mirror of https://github.com/g4klx/MMDVM.git
Merge pull request #362 from n0mjs710/link-audio-fidelity
FM link-mode network audio: anti-alias/reconstruction filtering
This commit is contained in:
commit
046e1df161
29
FM.cpp
29
FM.cpp
|
|
@ -68,6 +68,12 @@ m_needReverse(false),
|
||||||
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz
|
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz
|
||||||
m_filterStage2(32768, 0,-32768, 32768, -50339, 19052),
|
m_filterStage2(32768, 0,-32768, 32768, -50339, 19052),
|
||||||
m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460),
|
m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460),
|
||||||
|
m_dsFilterStage1(m_filterStage1),//same coefficients, separate state
|
||||||
|
m_dsFilterStage2(m_filterStage2),
|
||||||
|
m_dsFilterStage3(m_filterStage3),
|
||||||
|
m_usFilterStage1(m_filterStage1),//same coefficients, separate state
|
||||||
|
m_usFilterStage2(m_filterStage2),
|
||||||
|
m_usFilterStage3(m_filterStage3),
|
||||||
m_blanking(),
|
m_blanking(),
|
||||||
m_accessMode(1U),
|
m_accessMode(1U),
|
||||||
m_linkMode(false),
|
m_linkMode(false),
|
||||||
|
|
@ -122,6 +128,7 @@ void CFM::repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_
|
||||||
|
|
||||||
q15_t currentExtSample;
|
q15_t currentExtSample;
|
||||||
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
|
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
|
||||||
|
currentExtSample = m_usFilterStage3.filter(m_usFilterStage2.filter(m_usFilterStage1.filter(currentExtSample)));
|
||||||
inputExt = inputExt && m_extEnabled;
|
inputExt = inputExt && m_extEnabled;
|
||||||
|
|
||||||
switch (m_accessMode) {
|
switch (m_accessMode) {
|
||||||
|
|
@ -203,8 +210,10 @@ void CFM::repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
||||||
currentSample = m_blanking.process(currentSample);
|
currentSample = m_blanking.process(currentSample);
|
||||||
if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF))
|
if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) {
|
||||||
m_downSampler.addSample(currentSample);
|
q15_t dsSample = m_dsFilterStage3.filter(m_dsFilterStage2.filter(m_dsFilterStage1.filter(currentSample)));
|
||||||
|
m_downSampler.addSample(dsSample);
|
||||||
|
}
|
||||||
|
|
||||||
currentSample *= currentBoost;
|
currentSample *= currentBoost;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -214,8 +223,10 @@ void CFM::repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_
|
||||||
if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
||||||
currentSample *= currentBoost;
|
currentSample *= currentBoost;
|
||||||
} else {
|
} else {
|
||||||
if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF))
|
if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) {
|
||||||
m_downSampler.addSample(currentSample);
|
q15_t dsSample = m_dsFilterStage3.filter(m_dsFilterStage2.filter(m_dsFilterStage1.filter(currentSample)));
|
||||||
|
m_downSampler.addSample(dsSample);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -263,6 +274,7 @@ void CFM::linkSamples(bool cos, q15_t* samples, uint8_t length)
|
||||||
// few samples past that point
|
// few samples past that point
|
||||||
q15_t currentExtSample = 0;
|
q15_t currentExtSample = 0;
|
||||||
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
|
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
|
||||||
|
currentExtSample = m_usFilterStage3.filter(m_usFilterStage2.filter(m_usFilterStage1.filter(currentExtSample)));
|
||||||
inputExt = inputExt && m_extEnabled;
|
inputExt = inputExt && m_extEnabled;
|
||||||
|
|
||||||
switch (m_accessMode) {
|
switch (m_accessMode) {
|
||||||
|
|
@ -332,7 +344,8 @@ void CFM::linkSamples(bool cos, q15_t* samples, uint8_t length)
|
||||||
|
|
||||||
if (m_rfSignal && m_extEnabled) {
|
if (m_rfSignal && m_extEnabled) {
|
||||||
q15_t currentSample = m_blanking.process(currentRFSample);
|
q15_t currentSample = m_blanking.process(currentRFSample);
|
||||||
m_downSampler.addSample(currentSample);
|
q15_t dsSample = m_dsFilterStage3.filter(m_dsFilterStage2.filter(m_dsFilterStage1.filter(currentSample)));
|
||||||
|
m_downSampler.addSample(dsSample);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_extSignal)
|
if (!m_extSignal)
|
||||||
|
|
@ -412,6 +425,12 @@ void CFM::reset()
|
||||||
m_inputExtRB.reset();
|
m_inputExtRB.reset();
|
||||||
|
|
||||||
m_downSampler.reset();
|
m_downSampler.reset();
|
||||||
|
m_dsFilterStage1.reset();
|
||||||
|
m_dsFilterStage2.reset();
|
||||||
|
m_dsFilterStage3.reset();
|
||||||
|
m_usFilterStage1.reset();
|
||||||
|
m_usFilterStage2.reset();
|
||||||
|
m_usFilterStage3.reset();
|
||||||
m_squelch.reset();
|
m_squelch.reset();
|
||||||
|
|
||||||
m_needReverse = false;
|
m_needReverse = false;
|
||||||
|
|
|
||||||
6
FM.h
6
FM.h
|
|
@ -80,6 +80,12 @@ private:
|
||||||
CFMDirectFormI m_filterStage1;
|
CFMDirectFormI m_filterStage1;
|
||||||
CFMDirectFormI m_filterStage2;
|
CFMDirectFormI m_filterStage2;
|
||||||
CFMDirectFormI m_filterStage3;
|
CFMDirectFormI m_filterStage3;
|
||||||
|
CFMDirectFormI m_dsFilterStage1; // anti-alias filter for the downsampler, own state
|
||||||
|
CFMDirectFormI m_dsFilterStage2;
|
||||||
|
CFMDirectFormI m_dsFilterStage3;
|
||||||
|
CFMDirectFormI m_usFilterStage1; // reconstruction filter for the upsampler, own state
|
||||||
|
CFMDirectFormI m_usFilterStage2;
|
||||||
|
CFMDirectFormI m_usFilterStage3;
|
||||||
CFMBlanking m_blanking;
|
CFMBlanking m_blanking;
|
||||||
uint8_t m_accessMode;
|
uint8_t m_accessMode;
|
||||||
bool m_linkMode;
|
bool m_linkMode;
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ m_sampleIndex(0U)
|
||||||
|
|
||||||
void CFMDownSampler::addSample(q15_t sample)
|
void CFMDownSampler::addSample(q15_t sample)
|
||||||
{
|
{
|
||||||
|
sample = __SSAT(sample, 12);//clamp before packing to 12 bits
|
||||||
uint32_t usample = uint32_t(int32_t(sample) + 2048);
|
uint32_t usample = uint32_t(int32_t(sample) + 2048);
|
||||||
//only take one of three samples
|
//only take one of three samples
|
||||||
switch(m_sampleIndex){
|
switch(m_sampleIndex){
|
||||||
|
|
@ -74,6 +75,8 @@ uint16_t CFMDownSampler::getData()
|
||||||
void CFMDownSampler::reset()
|
void CFMDownSampler::reset()
|
||||||
{
|
{
|
||||||
m_sampleIndex = 0U;
|
m_sampleIndex = 0U;
|
||||||
|
m_samplePack = 0U;
|
||||||
|
m_ringBuffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue