providing the actual anti-aliasing attenuation and resampling filter lengthdds
@@ -129,6 +129,12 @@ void Resampler::setFilter(int32_t halfFiltLength,int32_t overSampling, float cut | |||
double Resampler::getStep() const { | |||
return _stepAdapted; | |||
} | |||
double Resampler::getAttenuation() const { | |||
return _attenuation; | |||
} | |||
int32_t Resampler::getHalfFilterLength() const{ | |||
return _halfFilterLength; | |||
} | |||
void Resampler::reset(){ | |||
_initialized=false; | |||
} | |||
@@ -136,6 +142,7 @@ void Resampler::configure(float fs, float newFs, float attenuation, int32_t minH | |||
// Serial.print("configure, fs: "); | |||
// Serial.println(fs); | |||
if (fs<=0. || newFs <=0.){ | |||
_attenuation=0; | |||
_initialized=false; | |||
return; | |||
} | |||
@@ -152,9 +159,10 @@ void Resampler::configure(float fs, float newFs, float attenuation, int32_t minH | |||
float cutOffFrequ, kaiserBeta; | |||
_overSamplingFactor=1024; | |||
if (fs <= newFs){ | |||
_attenuation=0; | |||
cutOffFrequ=1.; | |||
kaiserBeta=10; | |||
_halfFilterLength=minHalfFilterLength; | |||
_halfFilterLength=min(minHalfFilterLength,MAX_HALF_FILTER_LENGTH); | |||
} | |||
else{ | |||
cutOffFrequ=newFs/fs; | |||
@@ -204,6 +212,7 @@ 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 |
@@ -69,6 +69,8 @@ class Resampler { | |||
void addToPos(double val); | |||
void fixStep(); | |||
bool initialized() const; | |||
double getAttenuation() const; | |||
int32_t getHalfFilterLength() const; | |||
//resampling NOCHANNELS channels. Performance is increased a lot if the number of channels is known at compile time -> the number of channels is a template argument | |||
template <uint8_t NOCHANNELS> | |||
@@ -206,7 +208,7 @@ class Resampler { | |||
float* _endOfBuffer[MAX_NO_CHANNELS]; | |||
int32_t _overSamplingFactor; | |||
int32_t _halfFilterLength; | |||
int32_t _halfFilterLength=0; | |||
int32_t _filterLength; | |||
bool _initialized=false; | |||
@@ -218,6 +220,8 @@ class Resampler { | |||
double _cPos; | |||
double _sum; | |||
double _oldDiffs[2]; | |||
double _attenuation=0; | |||
}; | |||
#endif |
@@ -36,6 +36,7 @@ namespace { | |||
#define SPDIF_RX_BUFFER_LENGTH AUDIO_BLOCK_SAMPLES | |||
const int32_t bufferLength=8*AUDIO_BLOCK_SAMPLES; | |||
const uint16_t noSamplerPerIsr=SPDIF_RX_BUFFER_LENGTH/4; | |||
const float toFloatAudio= 1.f/pow(2., 23.); | |||
} | |||
volatile bool AsyncAudioInputSPDIF3::resetResampler=true; | |||
@@ -199,14 +200,13 @@ void AsyncAudioInputSPDIF3::isr(void) | |||
#endif | |||
float *destR = &(bufferR[buffer_offset]); | |||
float *destL = &(bufferL[buffer_offset]); | |||
const float factor= pow(2., 23.)+1; | |||
do { | |||
int32_t n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF; | |||
*destL++ = (float)(n)/factor; | |||
*destL++ = (float)(n)*toFloatAudio; | |||
++src; | |||
n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF; | |||
*destR++ = (float)(n)/factor; | |||
*destR++ = (float)(n)*toFloatAudio; | |||
++src; | |||
} while (src < end); | |||
buffer_offset=(buffer_offset+SPDIF_RX_BUFFER_LENGTH/4)%bufferLength; | |||
@@ -280,8 +280,9 @@ void AsyncAudioInputSPDIF3::configure(){ | |||
if (abs(frequDiff) > 0.01 || !_resampler.initialized()){ | |||
//the new sample frequency differs from the last one -> configure the _resampler again | |||
_inputFrequency=inputF; | |||
const int32_t targetLatency=round(_targetLatencyS*inputF); | |||
_targetLatencyS=max(0.001,(noSamplerPerIsr*3./2./_inputFrequency)); | |||
_maxLatency=max(2.*_blockDuration, 2*noSamplerPerIsr/_inputFrequency); | |||
const int32_t targetLatency=round(_targetLatencyS*inputF); | |||
__disable_irq(); | |||
resample_offset = targetLatency <= buffer_offset ? buffer_offset - targetLatency : bufferLength -(targetLatency-buffer_offset); | |||
__enable_irq(); | |||
@@ -402,8 +403,9 @@ void AsyncAudioInputSPDIF3::update(void) | |||
double AsyncAudioInputSPDIF3::getInputFrequency() const{ | |||
__disable_irq(); | |||
double f=_lastValidInputFrequ; | |||
bool l=locked; | |||
__enable_irq(); | |||
return f; | |||
return l ? f : 0.; | |||
} | |||
double AsyncAudioInputSPDIF3::getTargetLantency() const { | |||
__disable_irq(); | |||
@@ -411,6 +413,12 @@ double AsyncAudioInputSPDIF3::getTargetLantency() const { | |||
__enable_irq(); | |||
return l ; | |||
} | |||
double AsyncAudioInputSPDIF3::getAttenuation() const{ | |||
return _resampler.getAttenuation(); | |||
} | |||
int32_t AsyncAudioInputSPDIF3::getHalfFilterLength() const{ | |||
return _resampler.getHalfFilterLength(); | |||
} | |||
void AsyncAudioInputSPDIF3::config_spdifIn(){ | |||
//CCM Clock Gating Register 5, imxrt1060_rev1.pdf page 1145 | |||
CCM_CCGR5 |=CCM_CCGR5_SPDIF(CCM_CCGR_ON); //turn spdif clock on - necessary for receiver! |
@@ -51,6 +51,8 @@ public: | |||
double getInputFrequency() const; | |||
bool isLocked() const; | |||
double getTargetLantency() const; | |||
double getAttenuation() const; | |||
int32_t getHalfFilterLength() const; | |||
protected: | |||
static DMAChannel dma; | |||
static void isr(void); | |||
@@ -84,10 +86,10 @@ private: | |||
volatile double _bufferedTime; | |||
volatile double _lastValidInputFrequ; | |||
double _inputFrequency; | |||
double _inputFrequency=0.; | |||
double _targetLatencyS; //target latency [seconds] | |||
const double _blockDuration=AUDIO_BLOCK_SAMPLES/AUDIO_SAMPLE_RATE; //[seconds] | |||
const double _maxLatency=2.*_blockDuration; | |||
const double _blockDuration=AUDIO_BLOCK_SAMPLES/AUDIO_SAMPLE_RATE_EXACT; //[seconds] | |||
double _maxLatency=2.*_blockDuration; | |||
#ifdef DEBUG_SPDIF_IN | |||
static volatile bool bufferOverflow; |