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:
Ken Cooke 2016-12-24 11:10:35 -08:00
parent c6be02dc40
commit a2ea6bf36e
3 changed files with 3164 additions and 544 deletions

View file

@ -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);

View file

@ -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