mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 15:43:50 +02:00
Improved audio resampler
Added LQ mode (2x faster). Added HQ mode (2x slower), intended for offline resampling. Default (MQ) quality is slightly improved (512 filter phases in irrational mode).
This commit is contained in:
parent
c6be02dc40
commit
a2ea6bf36e
3 changed files with 3164 additions and 544 deletions
|
@ -99,18 +99,22 @@ static void cubicInterpolation(const float* input, float* output, int inputSize,
|
|||
}
|
||||
}
|
||||
|
||||
int AudioSRC::createRationalFilter(int upFactor, int downFactor, float gain) {
|
||||
int numTaps = PROTOTYPE_TAPS;
|
||||
int AudioSRC::createRationalFilter(int upFactor, int downFactor, float gain, Quality quality) {
|
||||
|
||||
int prototypeTaps = prototypeFilterTable[quality].taps;
|
||||
int prototypeCoefs = prototypeFilterTable[quality].coefs;
|
||||
const float* prototypeFilter = prototypeFilterTable[quality].filter;
|
||||
|
||||
int numTaps = prototypeTaps;
|
||||
int numPhases = upFactor;
|
||||
int numCoefs = numTaps * numPhases;
|
||||
int oldCoefs = numCoefs;
|
||||
int prototypeCoefs = PROTOTYPE_TAPS * PROTOTYPE_PHASES;
|
||||
|
||||
//
|
||||
// When downsampling, we can lower the filter cutoff by downFactor/upFactor using the
|
||||
// time-scaling property of the Fourier transform. The gain is adjusted accordingly.
|
||||
//
|
||||
if (downFactor > upFactor) {
|
||||
int oldCoefs = numCoefs;
|
||||
numCoefs = ((int64_t)oldCoefs * downFactor) / upFactor;
|
||||
numTaps = (numCoefs + upFactor - 1) / upFactor;
|
||||
gain *= (float)oldCoefs / numCoefs;
|
||||
|
@ -149,18 +153,22 @@ int AudioSRC::createRationalFilter(int upFactor, int downFactor, float gain) {
|
|||
return numTaps;
|
||||
}
|
||||
|
||||
int AudioSRC::createIrrationalFilter(int upFactor, int downFactor, float gain) {
|
||||
int numTaps = PROTOTYPE_TAPS;
|
||||
int AudioSRC::createIrrationalFilter(int upFactor, int downFactor, float gain, Quality quality) {
|
||||
|
||||
int prototypeTaps = prototypeFilterTable[quality].taps;
|
||||
int prototypeCoefs = prototypeFilterTable[quality].coefs;
|
||||
const float* prototypeFilter = prototypeFilterTable[quality].filter;
|
||||
|
||||
int numTaps = prototypeTaps;
|
||||
int numPhases = upFactor;
|
||||
int numCoefs = numTaps * numPhases;
|
||||
int oldCoefs = numCoefs;
|
||||
int prototypeCoefs = PROTOTYPE_TAPS * PROTOTYPE_PHASES;
|
||||
|
||||
//
|
||||
// When downsampling, we can lower the filter cutoff by downFactor/upFactor using the
|
||||
// time-scaling property of the Fourier transform. The gain is adjusted accordingly.
|
||||
//
|
||||
if (downFactor > upFactor) {
|
||||
int oldCoefs = numCoefs;
|
||||
numCoefs = ((int64_t)oldCoefs * downFactor) / upFactor;
|
||||
numTaps = (numCoefs + upFactor - 1) / upFactor;
|
||||
gain *= (float)oldCoefs / numCoefs;
|
||||
|
@ -1405,7 +1413,8 @@ int AudioSRC::render(float** inputs, float** outputs, int inputFrames) {
|
|||
return outputFrames;
|
||||
}
|
||||
|
||||
AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels) {
|
||||
AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels, Quality quality) {
|
||||
|
||||
assert(inputSampleRate > 0);
|
||||
assert(outputSampleRate > 0);
|
||||
assert(numChannels > 0);
|
||||
|
@ -1433,9 +1442,9 @@ AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels) {
|
|||
|
||||
// create the polyphase filter
|
||||
if (_step == 0) {
|
||||
_numTaps = createRationalFilter(_upFactor, _downFactor, 1.0f);
|
||||
_numTaps = createRationalFilter(_upFactor, _downFactor, 1.0f, quality);
|
||||
} else {
|
||||
_numTaps = createIrrationalFilter(_upFactor, _downFactor, 1.0f);
|
||||
_numTaps = createIrrationalFilter(_upFactor, _downFactor, 1.0f, quality);
|
||||
}
|
||||
|
||||
//printf("up=%d down=%.3f taps=%d\n", _upFactor, _downFactor + (LO32(_step)<<SRC_PHASEBITS) * Q32_TO_FLOAT, _numTaps);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
static const int SRC_MAX_CHANNELS = 4;
|
||||
|
||||
// polyphase filter
|
||||
static const int SRC_PHASEBITS = 8;
|
||||
static const int SRC_PHASEBITS = 9;
|
||||
static const int SRC_PHASES = (1 << SRC_PHASEBITS);
|
||||
static const int SRC_FRACBITS = 32 - SRC_PHASEBITS;
|
||||
static const uint32_t SRC_FRACMASK = (1 << SRC_FRACBITS) - 1;
|
||||
|
@ -31,7 +31,13 @@ static const int SRC_BLOCK = 256;
|
|||
class AudioSRC {
|
||||
|
||||
public:
|
||||
AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels);
|
||||
enum Quality {
|
||||
LOW_QUALITY,
|
||||
MEDIUM_QUALITY,
|
||||
HIGH_QUALITY
|
||||
};
|
||||
|
||||
AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels, Quality quality = MEDIUM_QUALITY);
|
||||
~AudioSRC();
|
||||
|
||||
// deinterleaved float input/output (native format)
|
||||
|
@ -70,8 +76,8 @@ private:
|
|||
int64_t _offset;
|
||||
int64_t _step;
|
||||
|
||||
int createRationalFilter(int upFactor, int downFactor, float gain);
|
||||
int createIrrationalFilter(int upFactor, int downFactor, float gain);
|
||||
int createRationalFilter(int upFactor, int downFactor, float gain, Quality quality);
|
||||
int createIrrationalFilter(int upFactor, int downFactor, float gain, Quality quality);
|
||||
|
||||
int multirateFilter1(const float* input0, float* output0, int inputFrames);
|
||||
int multirateFilter2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue