@@ -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 [%]: "); |