| @@ -30,7 +30,10 @@ | |||
| #include "Resampler.h" | |||
| #include <math.h> | |||
| Resampler::Resampler(StepAdaptionParameters settings){ | |||
| Resampler::Resampler(float attenuation, int32_t minHalfFilterLength, int32_t maxHalfFilterLength, StepAdaptionParameters settings): _targetAttenuation(attenuation) | |||
| { | |||
| _maxHalfFilterLength=max(1, min(MAX_HALF_FILTER_LENGTH, maxHalfFilterLength)); | |||
| _minHalfFilterLength=max(1, min(maxHalfFilterLength, minHalfFilterLength)); | |||
| #ifdef DEBUG_RESAMPLER | |||
| while (!Serial); | |||
| #endif | |||
| @@ -138,7 +141,7 @@ int32_t Resampler::getHalfFilterLength() const{ | |||
| void Resampler::reset(){ | |||
| _initialized=false; | |||
| } | |||
| void Resampler::configure(float fs, float newFs, float attenuation, int32_t minHalfFilterLength){ | |||
| void Resampler::configure(float fs, float newFs){ | |||
| // Serial.print("configure, fs: "); | |||
| // Serial.println(fs); | |||
| if (fs<=0. || newFs <=0.){ | |||
| @@ -147,6 +150,7 @@ void Resampler::configure(float fs, float newFs, float attenuation, int32_t minH | |||
| _initialized=false; | |||
| return; | |||
| } | |||
| _attenuation=_targetAttenuation; | |||
| _step=(double)fs/newFs; | |||
| _configuredStep=_step; | |||
| _stepAdapted=_step; | |||
| @@ -154,7 +158,7 @@ void Resampler::configure(float fs, float newFs, float attenuation, int32_t minH | |||
| _oldDiffs[0]=0.; | |||
| _oldDiffs[1]=0.; | |||
| for (uint8_t i =0; i< MAX_NO_CHANNELS; i++){ | |||
| memset(_buffer[i], 0, sizeof(float)*MAX_HALF_FILTER_LENGTH*2); | |||
| memset(_buffer[i], 0, sizeof(float)*_maxHalfFilterLength*2); | |||
| } | |||
| float cutOffFrequ, kaiserBeta; | |||
| @@ -163,7 +167,7 @@ void Resampler::configure(float fs, float newFs, float attenuation, int32_t minH | |||
| _attenuation=0; | |||
| cutOffFrequ=1.; | |||
| kaiserBeta=10; | |||
| _halfFilterLength=min(minHalfFilterLength,MAX_HALF_FILTER_LENGTH); | |||
| _halfFilterLength=min(_minHalfFilterLength,_maxHalfFilterLength); | |||
| } | |||
| else{ | |||
| cutOffFrequ=newFs/fs; | |||
| @@ -172,38 +176,23 @@ void Resampler::configure(float fs, float newFs, float attenuation, int32_t minH | |||
| Serial.print("b: "); | |||
| Serial.println(b); | |||
| #endif | |||
| double hfl=(int32_t)((attenuation-8)/(2.*2.285*TWO_PI*b)+0.5); | |||
| if (hfl >= minHalfFilterLength && hfl <= MAX_HALF_FILTER_LENGTH){ | |||
| double hfl=(int32_t)((_attenuation-8)/(2.*2.285*TWO_PI*b)+0.5); | |||
| if (hfl >= _minHalfFilterLength && hfl <= _maxHalfFilterLength){ | |||
| _halfFilterLength=hfl; | |||
| #ifdef DEBUG_RESAMPLER | |||
| Serial.print("Attenuation: "); | |||
| #endif | |||
| } | |||
| else if (hfl < minHalfFilterLength){ | |||
| _halfFilterLength=minHalfFilterLength; | |||
| attenuation=((2*_halfFilterLength+1)-1)*(2.285*TWO_PI*b)+8; | |||
| #ifdef DEBUG_RESAMPLER | |||
| Serial.println("Resmapler: sinc filter length increased"); | |||
| Serial.print("Attenuation increased to "); | |||
| #endif | |||
| else if (hfl < _minHalfFilterLength){ | |||
| _halfFilterLength=_minHalfFilterLength; | |||
| _attenuation=((2*_halfFilterLength+1)-1)*(2.285*TWO_PI*b)+8; | |||
| } | |||
| else{ | |||
| _halfFilterLength=MAX_HALF_FILTER_LENGTH; | |||
| attenuation=((2*_halfFilterLength+1)-1)*(2.285*TWO_PI*b)+8; | |||
| #ifdef DEBUG_RESAMPLER | |||
| Serial.println("Resmapler: needed sinc filter length too long"); | |||
| Serial.print("Attenuation decreased to "); | |||
| #endif | |||
| _halfFilterLength=_maxHalfFilterLength; | |||
| _attenuation=((2*_halfFilterLength+1)-1)*(2.285*TWO_PI*b)+8; | |||
| } | |||
| #ifdef DEBUG_RESAMPLER | |||
| Serial.print(attenuation); | |||
| Serial.println("dB"); | |||
| #endif | |||
| if (attenuation>50.){ | |||
| kaiserBeta=0.1102*(attenuation-8.7); | |||
| if (_attenuation>50.){ | |||
| kaiserBeta=0.1102*(_attenuation-8.7); | |||
| } | |||
| else if (21<=attenuation && attenuation<=50){ | |||
| kaiserBeta=0.5842*(float)pow(attenuation-21.,0.4)+0.07886*(attenuation-21.); | |||
| else if (21<=_attenuation && _attenuation<=50){ | |||
| kaiserBeta=0.5842*(float)pow(_attenuation-21.,0.4)+0.07886*(_attenuation-21.); | |||
| } | |||
| else{ | |||
| kaiserBeta=0.; | |||
| @@ -213,7 +202,6 @@ void Resampler::configure(float fs, float newFs, float attenuation, int32_t minH | |||
| int32_t f = (noSamples-1)/(MAX_FILTER_SAMPLES-1)+1; | |||
| _overSamplingFactor/=f; | |||
| } | |||
| _attenuation=attenuation; | |||
| } | |||
| #ifdef DEBUG_RESAMPLER | |||
| @@ -49,11 +49,11 @@ class Resampler { | |||
| double ki=0.00012; | |||
| double kd= 1.8; | |||
| }; | |||
| Resampler(StepAdaptionParameters settings=StepAdaptionParameters()); | |||
| Resampler(float attenuation=100, int32_t minHalfFilterLength=20, int32_t maxHalfFilterLength=80, StepAdaptionParameters settings=StepAdaptionParameters()); | |||
| void reset(); | |||
| ///@param attenuation target attenuation [dB] of the anti-aliasing filter. Only used if newFs<fs. The attenuation can't be reached if the needed filter length exceeds 2*MAX_FILTER_SAMPLES+1 | |||
| ///@param minHalfFilterLength If newFs >= fs, the filter length of the resampling filter is 2*minHalfFilterLength+1. If fs y newFs the filter is maybe longer to reach the desired attenuation | |||
| void configure(float fs, float newFs, float attenuation=100, int32_t minHalfFilterLength=20); | |||
| void configure(float fs, float newFs); | |||
| ///@param input0 first input array/ channel | |||
| ///@param input1 second input array/ channel | |||
| ///@param inputLength length of each input array | |||
| @@ -207,6 +207,8 @@ class Resampler { | |||
| float _buffer[MAX_NO_CHANNELS][MAX_HALF_FILTER_LENGTH*2]; | |||
| float* _endOfBuffer[MAX_NO_CHANNELS]; | |||
| int32_t _minHalfFilterLength; | |||
| int32_t _maxHalfFilterLength; | |||
| int32_t _overSamplingFactor; | |||
| int32_t _halfFilterLength; | |||
| int32_t _filterLength; | |||
| @@ -222,6 +224,7 @@ class Resampler { | |||
| double _oldDiffs[2]; | |||
| double _attenuation=0; | |||
| float _targetAttenuation=100; | |||
| }; | |||
| #endif | |||
| @@ -65,9 +65,10 @@ AsyncAudioInputSPDIF3::~AsyncAudioInputSPDIF3(){ | |||
| } | |||
| PROGMEM | |||
| AsyncAudioInputSPDIF3::AsyncAudioInputSPDIF3(bool dither, bool noiseshaping,float attenuation, int32_t minHalfFilterLength) : AudioStream(0, NULL) { | |||
| _attenuation=attenuation; | |||
| _minHalfFilterLength=minHalfFilterLength; | |||
| AsyncAudioInputSPDIF3::AsyncAudioInputSPDIF3(bool dither, bool noiseshaping,float attenuation, int32_t minHalfFilterLength, int32_t maxHalfFilterLength): | |||
| AudioStream(0, NULL), | |||
| _resampler(attenuation, minHalfFilterLength, maxHalfFilterLength) | |||
| { | |||
| const float factor = powf(2, 15)-1.f; // to 16 bit audio | |||
| quantizer[0]=new Quantizer(AUDIO_SAMPLE_RATE_EXACT); | |||
| quantizer[0]->configure(noiseshaping, dither, factor); | |||
| @@ -251,7 +252,7 @@ void AsyncAudioInputSPDIF3::configure(){ | |||
| __disable_irq(); | |||
| resample_offset = targetLatency <= buffer_offset ? buffer_offset - targetLatency : bufferLength -(targetLatency-buffer_offset); | |||
| __enable_irq(); | |||
| _resampler.configure(inputF, AUDIO_SAMPLE_RATE_EXACT, _attenuation, _minHalfFilterLength); | |||
| _resampler.configure(inputF, AUDIO_SAMPLE_RATE_EXACT); | |||
| #ifdef DEBUG_SPDIF_IN | |||
| Serial.print("_maxLatency: "); | |||
| Serial.println(_maxLatency); | |||
| @@ -40,9 +40,10 @@ | |||
| class AsyncAudioInputSPDIF3 : public AudioStream | |||
| { | |||
| public: | |||
| ///@param attenuation target attenuation [dB] of the anti-aliasing filter. Only used if newFs<fs. The attenuation can't be reached if the needed filter length exceeds 2*MAX_FILTER_SAMPLES+1 | |||
| ///@param minHalfFilterLength If newFs >= fs, the filter length of the resampling filter is 2*minHalfFilterLength+1. If fs y newFs the filter is maybe longer to reach the desired attenuation | |||
| AsyncAudioInputSPDIF3(bool dither=true, bool noiseshaping=true,float attenuation=100, int32_t minHalfFilterLength=20); | |||
| ///@param attenuation target attenuation [dB] of the anti-aliasing filter. Only used if AUDIO_SAMPLE_RATE_EXACT < input sample rate (input fs). The attenuation can't be reached if the needed filter length exceeds 2*MAX_FILTER_SAMPLES+1 | |||
| ///@param minHalfFilterLength If AUDIO_SAMPLE_RATE_EXACT >= input fs), the filter length of the resampling filter is 2*minHalfFilterLength+1. If AUDIO_SAMPLE_RATE_EXACT < input fs the filter is maybe longer to reach the desired attenuation | |||
| ///@param maxHalfFilterLength Can be used to restrict the maximum filter length at the cost of a lower attenuation | |||
| AsyncAudioInputSPDIF3(bool dither=true, bool noiseshaping=true,float attenuation=100, int32_t minHalfFilterLength=20, int32_t maxHalfFilterLength=80); | |||
| ~AsyncAudioInputSPDIF3(); | |||
| virtual void update(void); | |||
| void begin(); | |||
| @@ -69,8 +70,6 @@ private: | |||
| static volatile uint32_t microsLast; | |||
| //==================== | |||
| float _attenuation; | |||
| int32_t _minHalfFilterLength; | |||
| Resampler _resampler; | |||
| Quantizer* quantizer[2]; | |||
| arm_biquad_cascade_df2T_instance_f32 _bufferLPFilter; | |||
| @@ -1,7 +1,7 @@ | |||
| #include <Audio.h> | |||
| AsyncAudioInputSPDIF3 spdifIn(false, false, 100, 20); //dither = false, noiseshaping = false, anti-aliasing attenuation=100dB, minimum resampling filter length=20 | |||
| AsyncAudioInputSPDIF3 spdifIn(false, false, 100, 20, 80); //dither = true, noiseshaping = true, anti-aliasing attenuation=100dB, minimum half resampling filter length=20, maximum half resampling filter length=80 | |||
| AudioOutputSPDIF3 spdifOut; | |||
| AudioConnection patchCord1(spdifIn, 0, spdifOut, 0); | |||
| @@ -30,7 +30,9 @@ void loop() { | |||
| Serial.print("resampling goup delay [milli seconds]: "); | |||
| Serial.println(spdifIn.getHalfFilterLength()/inputFrequency*1e3,2); | |||
| Serial.print("half filter length: "); | |||
| Serial.println(spdifIn.getHalfFilterLength()); | |||
| double pUsageIn=spdifIn.processorUsage(); | |||
| Serial.print("processor usage [%]: "); | |||