providing the actual anti-aliasing attenuation and resampling filter lengthdds
double Resampler::getStep() const { | double Resampler::getStep() const { | ||||
return _stepAdapted; | return _stepAdapted; | ||||
} | } | ||||
double Resampler::getAttenuation() const { | |||||
return _attenuation; | |||||
} | |||||
int32_t Resampler::getHalfFilterLength() const{ | |||||
return _halfFilterLength; | |||||
} | |||||
void Resampler::reset(){ | void Resampler::reset(){ | ||||
_initialized=false; | _initialized=false; | ||||
} | } | ||||
// Serial.print("configure, fs: "); | // Serial.print("configure, fs: "); | ||||
// Serial.println(fs); | // Serial.println(fs); | ||||
if (fs<=0. || newFs <=0.){ | if (fs<=0. || newFs <=0.){ | ||||
_attenuation=0; | |||||
_initialized=false; | _initialized=false; | ||||
return; | return; | ||||
} | } | ||||
float cutOffFrequ, kaiserBeta; | float cutOffFrequ, kaiserBeta; | ||||
_overSamplingFactor=1024; | _overSamplingFactor=1024; | ||||
if (fs <= newFs){ | if (fs <= newFs){ | ||||
_attenuation=0; | |||||
cutOffFrequ=1.; | cutOffFrequ=1.; | ||||
kaiserBeta=10; | kaiserBeta=10; | ||||
_halfFilterLength=minHalfFilterLength; | |||||
_halfFilterLength=min(minHalfFilterLength,MAX_HALF_FILTER_LENGTH); | |||||
} | } | ||||
else{ | else{ | ||||
cutOffFrequ=newFs/fs; | cutOffFrequ=newFs/fs; | ||||
int32_t f = (noSamples-1)/(MAX_FILTER_SAMPLES-1)+1; | int32_t f = (noSamples-1)/(MAX_FILTER_SAMPLES-1)+1; | ||||
_overSamplingFactor/=f; | _overSamplingFactor/=f; | ||||
} | } | ||||
_attenuation=attenuation; | |||||
} | } | ||||
#ifdef DEBUG_RESAMPLER | #ifdef DEBUG_RESAMPLER |
void addToPos(double val); | void addToPos(double val); | ||||
void fixStep(); | void fixStep(); | ||||
bool initialized() const; | 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 | //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> | template <uint8_t NOCHANNELS> | ||||
float* _endOfBuffer[MAX_NO_CHANNELS]; | float* _endOfBuffer[MAX_NO_CHANNELS]; | ||||
int32_t _overSamplingFactor; | int32_t _overSamplingFactor; | ||||
int32_t _halfFilterLength; | |||||
int32_t _halfFilterLength=0; | |||||
int32_t _filterLength; | int32_t _filterLength; | ||||
bool _initialized=false; | bool _initialized=false; | ||||
double _cPos; | double _cPos; | ||||
double _sum; | double _sum; | ||||
double _oldDiffs[2]; | double _oldDiffs[2]; | ||||
double _attenuation=0; | |||||
}; | }; | ||||
#endif | #endif |
#define SPDIF_RX_BUFFER_LENGTH AUDIO_BLOCK_SAMPLES | #define SPDIF_RX_BUFFER_LENGTH AUDIO_BLOCK_SAMPLES | ||||
const int32_t bufferLength=8*AUDIO_BLOCK_SAMPLES; | const int32_t bufferLength=8*AUDIO_BLOCK_SAMPLES; | ||||
const uint16_t noSamplerPerIsr=SPDIF_RX_BUFFER_LENGTH/4; | const uint16_t noSamplerPerIsr=SPDIF_RX_BUFFER_LENGTH/4; | ||||
const float toFloatAudio= 1.f/pow(2., 23.); | |||||
} | } | ||||
volatile bool AsyncAudioInputSPDIF3::resetResampler=true; | volatile bool AsyncAudioInputSPDIF3::resetResampler=true; | ||||
#endif | #endif | ||||
float *destR = &(bufferR[buffer_offset]); | float *destR = &(bufferR[buffer_offset]); | ||||
float *destL = &(bufferL[buffer_offset]); | float *destL = &(bufferL[buffer_offset]); | ||||
const float factor= pow(2., 23.)+1; | |||||
do { | do { | ||||
int32_t n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF; | int32_t n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF; | ||||
*destL++ = (float)(n)/factor; | |||||
*destL++ = (float)(n)*toFloatAudio; | |||||
++src; | ++src; | ||||
n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF; | n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF; | ||||
*destR++ = (float)(n)/factor; | |||||
*destR++ = (float)(n)*toFloatAudio; | |||||
++src; | ++src; | ||||
} while (src < end); | } while (src < end); | ||||
buffer_offset=(buffer_offset+SPDIF_RX_BUFFER_LENGTH/4)%bufferLength; | buffer_offset=(buffer_offset+SPDIF_RX_BUFFER_LENGTH/4)%bufferLength; | ||||
if (abs(frequDiff) > 0.01 || !_resampler.initialized()){ | if (abs(frequDiff) > 0.01 || !_resampler.initialized()){ | ||||
//the new sample frequency differs from the last one -> configure the _resampler again | //the new sample frequency differs from the last one -> configure the _resampler again | ||||
_inputFrequency=inputF; | _inputFrequency=inputF; | ||||
const int32_t targetLatency=round(_targetLatencyS*inputF); | |||||
_targetLatencyS=max(0.001,(noSamplerPerIsr*3./2./_inputFrequency)); | _targetLatencyS=max(0.001,(noSamplerPerIsr*3./2./_inputFrequency)); | ||||
_maxLatency=max(2.*_blockDuration, 2*noSamplerPerIsr/_inputFrequency); | |||||
const int32_t targetLatency=round(_targetLatencyS*inputF); | |||||
__disable_irq(); | __disable_irq(); | ||||
resample_offset = targetLatency <= buffer_offset ? buffer_offset - targetLatency : bufferLength -(targetLatency-buffer_offset); | resample_offset = targetLatency <= buffer_offset ? buffer_offset - targetLatency : bufferLength -(targetLatency-buffer_offset); | ||||
__enable_irq(); | __enable_irq(); | ||||
double AsyncAudioInputSPDIF3::getInputFrequency() const{ | double AsyncAudioInputSPDIF3::getInputFrequency() const{ | ||||
__disable_irq(); | __disable_irq(); | ||||
double f=_lastValidInputFrequ; | double f=_lastValidInputFrequ; | ||||
bool l=locked; | |||||
__enable_irq(); | __enable_irq(); | ||||
return f; | |||||
return l ? f : 0.; | |||||
} | } | ||||
double AsyncAudioInputSPDIF3::getTargetLantency() const { | double AsyncAudioInputSPDIF3::getTargetLantency() const { | ||||
__disable_irq(); | __disable_irq(); | ||||
__enable_irq(); | __enable_irq(); | ||||
return l ; | return l ; | ||||
} | } | ||||
double AsyncAudioInputSPDIF3::getAttenuation() const{ | |||||
return _resampler.getAttenuation(); | |||||
} | |||||
int32_t AsyncAudioInputSPDIF3::getHalfFilterLength() const{ | |||||
return _resampler.getHalfFilterLength(); | |||||
} | |||||
void AsyncAudioInputSPDIF3::config_spdifIn(){ | void AsyncAudioInputSPDIF3::config_spdifIn(){ | ||||
//CCM Clock Gating Register 5, imxrt1060_rev1.pdf page 1145 | //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! | CCM_CCGR5 |=CCM_CCGR5_SPDIF(CCM_CCGR_ON); //turn spdif clock on - necessary for receiver! |
double getInputFrequency() const; | double getInputFrequency() const; | ||||
bool isLocked() const; | bool isLocked() const; | ||||
double getTargetLantency() const; | double getTargetLantency() const; | ||||
double getAttenuation() const; | |||||
int32_t getHalfFilterLength() const; | |||||
protected: | protected: | ||||
static DMAChannel dma; | static DMAChannel dma; | ||||
static void isr(void); | static void isr(void); | ||||
volatile double _bufferedTime; | volatile double _bufferedTime; | ||||
volatile double _lastValidInputFrequ; | volatile double _lastValidInputFrequ; | ||||
double _inputFrequency; | |||||
double _inputFrequency=0.; | |||||
double _targetLatencyS; //target latency [seconds] | 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 | #ifdef DEBUG_SPDIF_IN | ||||
static volatile bool bufferOverflow; | static volatile bool bufferOverflow; |