Modem, ModemKit and initial ModemAnalog refactor
This commit is contained in:
parent
f1f2cb91eb
commit
a1a6a467e8
|
@ -234,6 +234,25 @@ SET (cubicsdr_sources
|
|||
src/demod/DemodulatorWorkerThread.cpp
|
||||
src/demod/DemodulatorInstance.cpp
|
||||
src/demod/DemodulatorMgr.cpp
|
||||
src/modules/modem/Modem.cpp
|
||||
src/modules/modem/ModemAnalog.cpp
|
||||
src/modules/modem/digital/ModemASK.cpp
|
||||
src/modules/modem/digital/ModemAPSK.cpp
|
||||
src/modules/modem/digital/ModemBPSK.cpp
|
||||
src/modules/modem/digital/ModemDPSK.cpp
|
||||
src/modules/modem/digital/ModemPSK.cpp
|
||||
src/modules/modem/digital/ModemOOK.cpp
|
||||
src/modules/modem/digital/ModemST.cpp
|
||||
src/modules/modem/digital/ModemSQAM.cpp
|
||||
src/modules/modem/digital/ModemQAM.cpp
|
||||
src/modules/modem/digital/ModemQPSK.cpp
|
||||
src/modules/modem/analog/ModemAM.cpp
|
||||
src/modules/modem/analog/ModemDSB.cpp
|
||||
src/modules/modem/analog/ModemFM.cpp
|
||||
src/modules/modem/analog/ModemFMStereo.cpp
|
||||
src/modules/modem/analog/ModemIQ.cpp
|
||||
src/modules/modem/analog/ModemLSB.cpp
|
||||
src/modules/modem/analog/ModemUSB.cpp
|
||||
src/audio/AudioThread.cpp
|
||||
src/util/Gradient.cpp
|
||||
src/util/Timer.cpp
|
||||
|
@ -293,6 +312,25 @@ SET (cubicsdr_headers
|
|||
src/demod/DemodulatorInstance.h
|
||||
src/demod/DemodulatorMgr.h
|
||||
src/demod/DemodDefs.h
|
||||
src/modules/modem/Modem.h
|
||||
src/modules/modem/ModemAnalog.h
|
||||
src/modules/modem/digital/ModemASK.h
|
||||
src/modules/modem/digital/ModemAPSK.h
|
||||
src/modules/modem/digital/ModemBPSK.h
|
||||
src/modules/modem/digital/ModemDPSK.h
|
||||
src/modules/modem/digital/ModemPSK.h
|
||||
src/modules/modem/digital/ModemOOK.h
|
||||
src/modules/modem/digital/ModemST.h
|
||||
src/modules/modem/digital/ModemSQAM.h
|
||||
src/modules/modem/digital/ModemQAM.h
|
||||
src/modules/modem/digital/ModemQPSK.h
|
||||
src/modules/modem/analog/ModemAM.h
|
||||
src/modules/modem/analog/ModemDSB.h
|
||||
src/modules/modem/analog/ModemFM.h
|
||||
src/modules/modem/analog/ModemFMStereo.h
|
||||
src/modules/modem/analog/ModemIQ.h
|
||||
src/modules/modem/analog/ModemLSB.h
|
||||
src/modules/modem/analog/ModemUSB.h
|
||||
src/audio/AudioThread.h
|
||||
src/util/Gradient.h
|
||||
src/util/Timer.h
|
||||
|
@ -372,6 +410,9 @@ SOURCE_GROUP("Base" REGULAR_EXPRESSION "src/${REG_EXT}")
|
|||
SOURCE_GROUP("Forms\\SDRDevices" REGULAR_EXPRESSION "src/forms/SDRDevices/${REG_EXT}")
|
||||
SOURCE_GROUP("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}")
|
||||
SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${REG_EXT}")
|
||||
SOURCE_GROUP("Modem" REGULAR_EXPRESSION "src/modules/modem/${REG_EXT}")
|
||||
SOURCE_GROUP("Modem-Analog" REGULAR_EXPRESSION "src/modules/modem/analog/${REG_EXT}")
|
||||
SOURCE_GROUP("Modem-Digital" REGULAR_EXPRESSION "src/modules/modem/digital/${REG_EXT}")
|
||||
SOURCE_GROUP("Audio" REGULAR_EXPRESSION "src/audio/${REG_EXT}")
|
||||
SOURCE_GROUP("Utility" REGULAR_EXPRESSION "src/util/${REG_EXT}")
|
||||
SOURCE_GROUP("Visual" REGULAR_EXPRESSION "src/visual/${REG_EXT}")
|
||||
|
@ -387,6 +428,10 @@ include_directories (
|
|||
${PROJECT_SOURCE_DIR}/src/forms/SDRDevices
|
||||
${PROJECT_SOURCE_DIR}/src/sdr
|
||||
${PROJECT_SOURCE_DIR}/src/demod
|
||||
${PROJECT_SOURCE_DIR}/src/modules
|
||||
${PROJECT_SOURCE_DIR}/src/modules/modem
|
||||
${PROJECT_SOURCE_DIR}/src/modules/modem/digital
|
||||
${PROJECT_SOURCE_DIR}/src/modules/modem/analog
|
||||
${PROJECT_SOURCE_DIR}/src/audio
|
||||
${PROJECT_SOURCE_DIR}/src/util
|
||||
${PROJECT_SOURCE_DIR}/src/panel
|
||||
|
|
|
@ -93,21 +93,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class DemodulatorThreadPostIQData: public ReferenceCounter {
|
||||
public:
|
||||
std::vector<liquid_float_complex> data;
|
||||
long long sampleRate;
|
||||
msresamp_rrrf audioResampler;
|
||||
msresamp_rrrf stereoResampler;
|
||||
double audioResampleRatio;
|
||||
int audioSampleRate;
|
||||
|
||||
firfilt_rrrf firStereoLeft;
|
||||
firfilt_rrrf firStereoRight;
|
||||
iirfilt_crcf iirStereoPilot;
|
||||
|
||||
DemodulatorThreadPostIQData() :
|
||||
sampleRate(0), audioResampler(NULL), stereoResampler(NULL), audioResampleRatio(0), audioSampleRate(0), firStereoLeft(NULL), firStereoRight(NULL), iirStereoPilot(NULL) {
|
||||
sampleRate(0) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -116,6 +109,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class DemodulatorThreadAudioData: public ReferenceCounter {
|
||||
public:
|
||||
long long frequency;
|
||||
|
|
|
@ -202,7 +202,7 @@ bool DemodulatorInstance::isStereo() {
|
|||
|
||||
void DemodulatorInstance::setStereo(bool state) {
|
||||
stereo = state;
|
||||
demodulatorThread->setStereo(state);
|
||||
// demodulatorThread->setStereo(state);
|
||||
}
|
||||
|
||||
void DemodulatorInstance::squelchAuto() {
|
||||
|
|
|
@ -27,45 +27,45 @@ void DemodulatorPreThread::initialize() {
|
|||
initialized = false;
|
||||
|
||||
iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate;
|
||||
audioResampleRatio = (double) (params.audioSampleRate) / (double) params.bandwidth;
|
||||
// audioResampleRatio = (double) (params.audioSampleRate) / (double) params.bandwidth;
|
||||
|
||||
float As = 120.0f; // stop-band attenuation [dB]
|
||||
float As = 60.0f; // stop-band attenuation [dB]
|
||||
|
||||
iqResampler = msresamp_crcf_create(iqResampleRatio, As);
|
||||
audioResampler = msresamp_rrrf_create(audioResampleRatio, As);
|
||||
stereoResampler = msresamp_rrrf_create(audioResampleRatio, As);
|
||||
// audioResampler = msresamp_rrrf_create(audioResampleRatio, As);
|
||||
// stereoResampler = msresamp_rrrf_create(audioResampleRatio, As);
|
||||
|
||||
// Stereo filters / shifters
|
||||
double firStereoCutoff = ((double) 16000 / (double) params.audioSampleRate);
|
||||
float ft = ((double) 1000 / (double) params.audioSampleRate); // filter transition
|
||||
float mu = 0.0f; // fractional timing offset
|
||||
// double firStereoCutoff = ((double) 16000 / (double) params.audioSampleRate);
|
||||
// float ft = ((double) 1000 / (double) params.audioSampleRate); // filter transition
|
||||
// float mu = 0.0f; // fractional timing offset
|
||||
//
|
||||
// if (firStereoCutoff < 0) {
|
||||
// firStereoCutoff = 0;
|
||||
// }
|
||||
//
|
||||
// if (firStereoCutoff > 0.5) {
|
||||
// firStereoCutoff = 0.5;
|
||||
// }
|
||||
|
||||
if (firStereoCutoff < 0) {
|
||||
firStereoCutoff = 0;
|
||||
}
|
||||
|
||||
if (firStereoCutoff > 0.5) {
|
||||
firStereoCutoff = 0.5;
|
||||
}
|
||||
|
||||
unsigned int h_len = estimate_req_filter_len(ft, As);
|
||||
float *h = new float[h_len];
|
||||
liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
|
||||
|
||||
firStereoLeft = firfilt_rrrf_create(h, h_len);
|
||||
firStereoRight = firfilt_rrrf_create(h, h_len);
|
||||
// unsigned int h_len = estimate_req_filter_len(ft, As);
|
||||
// float *h = new float[h_len];
|
||||
// liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
|
||||
//
|
||||
// firStereoLeft = firfilt_rrrf_create(h, h_len);
|
||||
// firStereoRight = firfilt_rrrf_create(h, h_len);
|
||||
|
||||
// stereo pilot filter
|
||||
float bw = params.bandwidth;
|
||||
if (bw < 100000.0) {
|
||||
bw = 100000.0;
|
||||
}
|
||||
unsigned int order = 5; // filter order
|
||||
float f0 = ((double) 19000 / bw);
|
||||
float fc = ((double) 19500 / bw);
|
||||
float Ap = 1.0f;
|
||||
As = 60.0f;
|
||||
iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);
|
||||
// float bw = params.bandwidth;
|
||||
// if (bw < 100000.0) {
|
||||
// bw = 100000.0;
|
||||
// }
|
||||
// unsigned int order = 5; // filter order
|
||||
// float f0 = ((double) 19000 / bw);
|
||||
// float fc = ((double) 19500 / bw);
|
||||
// float Ap = 1.0f;
|
||||
// As = 60.0f;
|
||||
// iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);
|
||||
|
||||
initialized = true;
|
||||
lastParams = params;
|
||||
|
@ -218,7 +218,6 @@ void DemodulatorPreThread::run() {
|
|||
msresamp_crcf_execute(iqResampler, in_buf, bufSize, &resampledData[0], &numWritten);
|
||||
|
||||
resamp->setRefCount(1);
|
||||
|
||||
resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten);
|
||||
|
||||
// bool uneven = (numWritten % 2 != 0);
|
||||
|
@ -245,13 +244,13 @@ void DemodulatorPreThread::run() {
|
|||
|
||||
|
||||
|
||||
resamp->audioResampleRatio = audioResampleRatio;
|
||||
resamp->audioResampler = audioResampler;
|
||||
resamp->audioSampleRate = params.audioSampleRate;
|
||||
resamp->stereoResampler = stereoResampler;
|
||||
resamp->firStereoLeft = firStereoLeft;
|
||||
resamp->firStereoRight = firStereoRight;
|
||||
resamp->iirStereoPilot = iirStereoPilot;
|
||||
// resamp->audioResampleRatio = audioResampleRatio;
|
||||
// resamp->audioResampler = audioResampler;
|
||||
// resamp->audioSampleRate = params.audioSampleRate;
|
||||
// resamp->stereoResampler = stereoResampler;
|
||||
// resamp->firStereoLeft = firStereoLeft;
|
||||
// resamp->firStereoRight = firStereoRight;
|
||||
// resamp->iirStereoPilot = iirStereoPilot;
|
||||
resamp->sampleRate = params.bandwidth;
|
||||
|
||||
iqOutputQueue->push(resamp);
|
||||
|
|
|
@ -13,21 +13,21 @@
|
|||
|
||||
DemodulatorThread::DemodulatorThread() : IOThread(), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(1), audioSampleRate(0), squelchLevel(0), signalLevel(0), squelchEnabled(false), iqInputQueue(NULL), audioOutputQueue(NULL), audioVisOutputQueue(NULL), threadQueueControl(NULL), threadQueueNotify(NULL) {
|
||||
|
||||
stereo.store(false);
|
||||
// stereo.store(false);
|
||||
muted.store(false);
|
||||
agcEnabled.store(false);
|
||||
demodulatorType.store(DEMOD_TYPE_FM);
|
||||
|
||||
demodFM = freqdem_create(0.5);
|
||||
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
|
||||
demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1);
|
||||
demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
|
||||
demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
|
||||
demodAM = demodAM_DSB_CSP;
|
||||
// demodFM = freqdem_create(0.5);
|
||||
// demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
|
||||
// demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1);
|
||||
// demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
|
||||
// demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
|
||||
// demodAM = demodAM_DSB_CSP;
|
||||
|
||||
// advanced demodulators
|
||||
|
||||
demodulatorCons.store(2);
|
||||
/* demodulatorCons.store(2);
|
||||
currentDemodCons = 0;
|
||||
|
||||
demodASK = demodASK2;
|
||||
|
@ -90,7 +90,7 @@ DemodulatorThread::DemodulatorThread() : IOThread(), iqAutoGain(NULL), amOutputC
|
|||
|
||||
demodQPSK = modem_create(LIQUID_MODEM_QPSK);
|
||||
|
||||
currentDemodLock = false;
|
||||
currentDemodLock = false; */
|
||||
|
||||
}
|
||||
DemodulatorThread::~DemodulatorThread() {
|
||||
|
@ -110,23 +110,23 @@ void DemodulatorThread::run() {
|
|||
pthread_setschedparam(tID, SCHED_FIFO, &prio);
|
||||
#endif
|
||||
|
||||
msresamp_rrrf audioResampler = NULL;
|
||||
msresamp_rrrf stereoResampler = NULL;
|
||||
firfilt_rrrf firStereoLeft = NULL;
|
||||
firfilt_rrrf firStereoRight = NULL;
|
||||
iirfilt_crcf iirStereoPilot = NULL;
|
||||
// msresamp_rrrf audioResampler = NULL;
|
||||
// msresamp_rrrf stereoResampler = NULL;
|
||||
// firfilt_rrrf firStereoLeft = NULL;
|
||||
// firfilt_rrrf firStereoRight = NULL;
|
||||
// iirfilt_crcf iirStereoPilot = NULL;
|
||||
|
||||
liquid_float_complex u, v, w, x, y;
|
||||
// liquid_float_complex u, v, w, x, y;
|
||||
|
||||
firhilbf firStereoR2C = firhilbf_create(5, 60.0f);
|
||||
firhilbf firStereoC2R = firhilbf_create(5, 60.0f);
|
||||
// firhilbf firStereoR2C = firhilbf_create(5, 60.0f);
|
||||
// firhilbf firStereoC2R = firhilbf_create(5, 60.0f);
|
||||
|
||||
nco_crcf stereoPilot = nco_crcf_create(LIQUID_VCO);
|
||||
nco_crcf_reset(stereoPilot);
|
||||
nco_crcf_pll_set_bandwidth(stereoPilot, 0.25f);
|
||||
// nco_crcf stereoPilot = nco_crcf_create(LIQUID_VCO);
|
||||
// nco_crcf_reset(stereoPilot);
|
||||
// nco_crcf_pll_set_bandwidth(stereoPilot, 0.25f);
|
||||
|
||||
// half band filter used for side-band elimination
|
||||
resamp2_crcf ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
|
||||
// resamp2_crcf ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
|
||||
|
||||
// Automatic IQ gain
|
||||
iqAutoGain = agc_crcf_create();
|
||||
|
@ -141,22 +141,22 @@ void DemodulatorThread::run() {
|
|||
threadQueueControl = (DemodulatorThreadControlCommandQueue *)getInputQueue("ControlQueue");
|
||||
threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue");
|
||||
|
||||
switch (demodulatorType.load()) {
|
||||
case DEMOD_TYPE_FM:
|
||||
break;
|
||||
case DEMOD_TYPE_LSB:
|
||||
demodAM = demodAM_LSB;
|
||||
break;
|
||||
case DEMOD_TYPE_USB:
|
||||
demodAM = demodAM_USB;
|
||||
break;
|
||||
case DEMOD_TYPE_DSB:
|
||||
demodAM = demodAM_DSB;
|
||||
break;
|
||||
case DEMOD_TYPE_AM:
|
||||
demodAM = demodAM_DSB_CSP;
|
||||
break;
|
||||
}
|
||||
// switch (demodulatorType.load()) {
|
||||
// case DEMOD_TYPE_FM:
|
||||
// break;
|
||||
// case DEMOD_TYPE_LSB:
|
||||
// demodAM = demodAM_LSB;
|
||||
// break;
|
||||
// case DEMOD_TYPE_USB:
|
||||
// demodAM = demodAM_USB;
|
||||
// break;
|
||||
// case DEMOD_TYPE_DSB:
|
||||
// demodAM = demodAM_DSB;
|
||||
// break;
|
||||
// case DEMOD_TYPE_AM:
|
||||
// demodAM = demodAM_DSB_CSP;
|
||||
// break;
|
||||
// }
|
||||
|
||||
while (!terminated) {
|
||||
DemodulatorThreadPostIQData *inp;
|
||||
|
@ -170,47 +170,47 @@ void DemodulatorThread::run() {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (audioResampler == NULL) {
|
||||
audioResampler = inp->audioResampler;
|
||||
stereoResampler = inp->stereoResampler;
|
||||
firStereoLeft = inp->firStereoLeft;
|
||||
firStereoRight = inp->firStereoRight;
|
||||
iirStereoPilot = inp->iirStereoPilot;
|
||||
audioSampleRate = inp->audioSampleRate;
|
||||
} else if (audioResampler != inp->audioResampler) {
|
||||
msresamp_rrrf_destroy(audioResampler);
|
||||
msresamp_rrrf_destroy(stereoResampler);
|
||||
audioResampler = inp->audioResampler;
|
||||
stereoResampler = inp->stereoResampler;
|
||||
audioSampleRate = inp->audioSampleRate;
|
||||
|
||||
if (demodAM) {
|
||||
ampmodem_reset(demodAM);
|
||||
}
|
||||
freqdem_reset(demodFM);
|
||||
nco_crcf_reset(stereoPilot);
|
||||
}
|
||||
|
||||
if (firStereoLeft != inp->firStereoLeft) {
|
||||
if (firStereoLeft != NULL) {
|
||||
firfilt_rrrf_destroy(firStereoLeft);
|
||||
}
|
||||
firStereoLeft = inp->firStereoLeft;
|
||||
}
|
||||
|
||||
if (firStereoRight != inp->firStereoRight) {
|
||||
if (firStereoRight != NULL) {
|
||||
firfilt_rrrf_destroy(firStereoRight);
|
||||
}
|
||||
firStereoRight = inp->firStereoRight;
|
||||
}
|
||||
|
||||
if (iirStereoPilot != inp->iirStereoPilot) {
|
||||
if (iirStereoPilot != NULL) {
|
||||
iirfilt_crcf_destroy(iirStereoPilot);
|
||||
}
|
||||
iirStereoPilot = inp->iirStereoPilot;
|
||||
}
|
||||
// if (audioResampler == NULL) {
|
||||
// audioResampler = inp->audioResampler;
|
||||
// stereoResampler = inp->stereoResampler;
|
||||
// firStereoLeft = inp->firStereoLeft;
|
||||
// firStereoRight = inp->firStereoRight;
|
||||
// iirStereoPilot = inp->iirStereoPilot;
|
||||
// audioSampleRate = inp->audioSampleRate;
|
||||
// } else if (audioResampler != inp->audioResampler) {
|
||||
// msresamp_rrrf_destroy(audioResampler);
|
||||
// msresamp_rrrf_destroy(stereoResampler);
|
||||
// audioResampler = inp->audioResampler;
|
||||
// stereoResampler = inp->stereoResampler;
|
||||
// audioSampleRate = inp->audioSampleRate;
|
||||
//
|
||||
// if (demodAM) {
|
||||
// ampmodem_reset(demodAM);
|
||||
// }
|
||||
// freqdem_reset(demodFM);
|
||||
// nco_crcf_reset(stereoPilot);
|
||||
// }
|
||||
//
|
||||
// if (firStereoLeft != inp->firStereoLeft) {
|
||||
// if (firStereoLeft != NULL) {
|
||||
// firfilt_rrrf_destroy(firStereoLeft);
|
||||
// }
|
||||
// firStereoLeft = inp->firStereoLeft;
|
||||
// }
|
||||
//
|
||||
// if (firStereoRight != inp->firStereoRight) {
|
||||
// if (firStereoRight != NULL) {
|
||||
// firfilt_rrrf_destroy(firStereoRight);
|
||||
// }
|
||||
// firStereoRight = inp->firStereoRight;
|
||||
// }
|
||||
//
|
||||
// if (iirStereoPilot != inp->iirStereoPilot) {
|
||||
// if (iirStereoPilot != NULL) {
|
||||
// iirfilt_crcf_destroy(iirStereoPilot);
|
||||
// }
|
||||
// iirStereoPilot = inp->iirStereoPilot;
|
||||
// }
|
||||
|
||||
if (agcData.size() != bufSize) {
|
||||
if (agcData.capacity() < bufSize) {
|
||||
|
@ -221,23 +221,24 @@ void DemodulatorThread::run() {
|
|||
agcAMData.resize(bufSize);
|
||||
}
|
||||
|
||||
double audio_resample_ratio = inp->audioResampleRatio;
|
||||
// double audio_resample_ratio = inp->audioResampleRatio;
|
||||
|
||||
if (demodOutputData.size() != bufSize) {
|
||||
if (demodOutputData.capacity() < bufSize) {
|
||||
demodOutputData.reserve(bufSize);
|
||||
}
|
||||
demodOutputData.resize(bufSize);
|
||||
}
|
||||
// if (demodOutputData.size() != bufSize) {
|
||||
// if (demodOutputData.capacity() < bufSize) {
|
||||
// demodOutputData.reserve(bufSize);
|
||||
// }
|
||||
// demodOutputData.resize(bufSize);
|
||||
// }
|
||||
|
||||
/*
|
||||
if (demodOutputDataDigital.size() != bufSize) {
|
||||
if (demodOutputDataDigital.capacity() < bufSize) {
|
||||
demodOutputDataDigital.reserve(bufSize);
|
||||
}
|
||||
demodOutputDataDigital.resize(bufSize);
|
||||
}
|
||||
|
||||
int audio_out_size = ceil((double) (bufSize) * audio_resample_ratio) + 512;
|
||||
*/
|
||||
// int audio_out_size = ceil((double) (bufSize) * audio_resample_ratio) + 512;
|
||||
|
||||
agc_crcf_execute_block(iqAutoGain, &(inp->data[0]), bufSize, &agcData[0]);
|
||||
|
||||
|
@ -258,8 +259,8 @@ void DemodulatorThread::run() {
|
|||
}
|
||||
|
||||
// Reset demodulator Constellations & Lock
|
||||
updateDemodulatorCons(0);
|
||||
|
||||
// updateDemodulatorCons(0);
|
||||
/*
|
||||
if (demodulatorType == DEMOD_TYPE_FM) {
|
||||
currentDemodLock = false;
|
||||
freqdem_demodulate_block(demodFM, &(*inputData)[0], bufSize, &demodOutputData[0]);
|
||||
|
@ -669,7 +670,7 @@ void DemodulatorThread::run() {
|
|||
|
||||
msresamp_rrrf_execute(stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (currentSignalLevel > signalLevel) {
|
||||
signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.5;
|
||||
|
@ -681,13 +682,14 @@ void DemodulatorThread::run() {
|
|||
|
||||
if (audioOutputQueue != NULL) {
|
||||
if (!squelchEnabled || (signalLevel >= squelchLevel)) {
|
||||
|
||||
ati = outputBuffers.getBuffer();
|
||||
|
||||
ati->sampleRate = audioSampleRate;
|
||||
ati->inputRate = inp->sampleRate;
|
||||
ati->setRefCount(1);
|
||||
|
||||
/*
|
||||
|
||||
if (demodulatorType == DEMOD_TYPE_RAW) {
|
||||
ati->channels = 2;
|
||||
if (ati->data.capacity() < (numAudioWritten * 2)) {
|
||||
|
@ -720,7 +722,7 @@ void DemodulatorThread::run() {
|
|||
ati->channels = 1;
|
||||
ati->data.assign(resampledOutputData.begin(), resampledOutputData.begin() + numAudioWritten);
|
||||
}
|
||||
|
||||
*/
|
||||
std::vector<float>::iterator data_i;
|
||||
ati->peak = 0;
|
||||
for (data_i = ati->data.begin(); data_i != ati->data.end(); data_i++) {
|
||||
|
@ -731,7 +733,7 @@ void DemodulatorThread::run() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (ati && audioVisOutputQueue != NULL && audioVisOutputQueue->empty()) {
|
||||
AudioThreadInput *ati_vis = audioVisBuffers.getBuffer();
|
||||
ati_vis->setRefCount(1);
|
||||
|
@ -762,6 +764,7 @@ void DemodulatorThread::run() {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
int numAudioWritten = ati->data.size();
|
||||
ati_vis->channels = 1;
|
||||
if (numAudioWritten > bufSize) {
|
||||
ati_vis->inputRate = audioSampleRate;
|
||||
|
@ -781,7 +784,8 @@ void DemodulatorThread::run() {
|
|||
|
||||
audioVisOutputQueue->push(ati_vis);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
if (ati != NULL) {
|
||||
if (!muted.load()) {
|
||||
audioOutputQueue->push(ati);
|
||||
|
@ -791,7 +795,7 @@ void DemodulatorThread::run() {
|
|||
}
|
||||
|
||||
if (!threadQueueControl->empty()) {
|
||||
int newDemodType = DEMOD_TYPE_NULL;
|
||||
// int newDemodType = DEMOD_TYPE_NULL;
|
||||
|
||||
while (!threadQueueControl->empty()) {
|
||||
DemodulatorThreadControlCommand command;
|
||||
|
@ -804,14 +808,14 @@ void DemodulatorThread::run() {
|
|||
case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_OFF:
|
||||
squelchEnabled = false;
|
||||
break;
|
||||
case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE:
|
||||
newDemodType = command.demodType;
|
||||
break;
|
||||
// case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE:
|
||||
// newDemodType = command.demodType;
|
||||
// break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (newDemodType != DEMOD_TYPE_NULL) {
|
||||
switch (newDemodType) {
|
||||
case DEMOD_TYPE_FM:
|
||||
|
@ -868,15 +872,15 @@ void DemodulatorThread::run() {
|
|||
break;
|
||||
}
|
||||
demodulatorType = newDemodType;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
demodOutputDataDigital.empty();
|
||||
// demodOutputDataDigital.empty();
|
||||
|
||||
inp->decRefCount();
|
||||
}
|
||||
// end while !terminated
|
||||
|
||||
/*
|
||||
if (audioResampler != NULL) {
|
||||
msresamp_rrrf_destroy(audioResampler);
|
||||
}
|
||||
|
@ -898,7 +902,7 @@ void DemodulatorThread::run() {
|
|||
firhilbf_destroy(firStereoC2R);
|
||||
nco_crcf_destroy(stereoPilot);
|
||||
resamp2_crcf_destroy(ssbFilt);
|
||||
|
||||
*/
|
||||
outputBuffers.purge();
|
||||
|
||||
if (audioVisOutputQueue && !audioVisOutputQueue->empty()) {
|
||||
|
@ -920,14 +924,14 @@ void DemodulatorThread::terminate() {
|
|||
iqInputQueue->push(inp);
|
||||
}
|
||||
|
||||
void DemodulatorThread::setStereo(bool state) {
|
||||
stereo.store(state);
|
||||
std::cout << "Stereo " << (state ? "Enabled" : "Disabled") << std::endl;
|
||||
}
|
||||
//void DemodulatorThread::setStereo(bool state) {
|
||||
// stereo.store(state);
|
||||
// std::cout << "Stereo " << (state ? "Enabled" : "Disabled") << std::endl;
|
||||
//}
|
||||
|
||||
bool DemodulatorThread::isStereo() {
|
||||
return stereo.load();
|
||||
}
|
||||
//bool DemodulatorThread::isStereo() {
|
||||
// return stereo.load();
|
||||
//}
|
||||
|
||||
bool DemodulatorThread::isMuted() {
|
||||
return muted.load();
|
||||
|
|
|
@ -21,8 +21,8 @@ public:
|
|||
void run();
|
||||
void terminate();
|
||||
|
||||
void setStereo(bool state);
|
||||
bool isStereo();
|
||||
// void setStereo(bool state);
|
||||
// bool isStereo();
|
||||
|
||||
void setAGC(bool state);
|
||||
bool getAGC();
|
||||
|
@ -42,35 +42,35 @@ public:
|
|||
|
||||
void setDemodulatorCons(int demod_cons_in);
|
||||
int getDemodulatorCons();
|
||||
|
||||
#ifdef __APPLE__
|
||||
static void *pthread_helper(void *context) {
|
||||
return ((DemodulatorThread *) context)->threadMain();
|
||||
}
|
||||
#endif
|
||||
//
|
||||
//#ifdef __APPLE__
|
||||
// static void *pthread_helper(void *context) {
|
||||
// return ((DemodulatorThread *) context)->threadMain();
|
||||
// }
|
||||
//#endif
|
||||
|
||||
protected:
|
||||
ReBuffer<AudioThreadInput> outputBuffers;
|
||||
|
||||
std::vector<liquid_float_complex> agcData;
|
||||
std::vector<float> agcAMData;
|
||||
std::vector<float> demodOutputData;
|
||||
std::vector<float> demodStereoData;
|
||||
std::vector<float> resampledOutputData;
|
||||
std::vector<float> resampledStereoData;
|
||||
// std::vector<float> demodOutputData;
|
||||
// std::vector<float> demodStereoData;
|
||||
// std::vector<float> resampledOutputData;
|
||||
// std::vector<float> resampledStereoData;
|
||||
std::vector<unsigned int> demodOutputDataDigital;
|
||||
//std::vector<unsigned int> demodOutputDataDigitalTest;
|
||||
|
||||
//std::vector<unsigned char> demodOutputSoftbits;
|
||||
//std::vector<unsigned char> demodOutputSoftbitsTest;
|
||||
|
||||
freqdem demodFM;
|
||||
ampmodem demodAM;
|
||||
ampmodem demodAM_DSB_CSP;
|
||||
ampmodem demodAM_DSB;
|
||||
ampmodem demodAM_LSB;
|
||||
ampmodem demodAM_USB;
|
||||
|
||||
// freqdem demodFM;
|
||||
// ampmodem demodAM;
|
||||
// ampmodem demodAM_DSB_CSP;
|
||||
// ampmodem demodAM_DSB;
|
||||
// ampmodem demodAM_LSB;
|
||||
// ampmodem demodAM_USB;
|
||||
/*
|
||||
modem demodASK;
|
||||
modem demodASK2;
|
||||
modem demodASK4;
|
||||
|
@ -130,14 +130,14 @@ protected:
|
|||
modem demodQAM256;
|
||||
|
||||
modem demodQPSK;
|
||||
|
||||
*/
|
||||
agc_crcf iqAutoGain;
|
||||
|
||||
float amOutputCeil;
|
||||
float amOutputCeilMA;
|
||||
float amOutputCeilMAA;
|
||||
|
||||
std::atomic_bool stereo;
|
||||
// std::atomic_bool stereo;
|
||||
std::atomic_bool muted;
|
||||
std::atomic_bool agcEnabled;
|
||||
std::atomic_int demodulatorType;
|
||||
|
|
|
@ -47,12 +47,12 @@ void DemodulatorWorkerThread::run() {
|
|||
}
|
||||
|
||||
if (filterCommand.bandwidth && filterCommand.audioSampleRate) {
|
||||
result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth;
|
||||
result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
|
||||
result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
|
||||
result.audioSampleRate = filterCommand.audioSampleRate;
|
||||
// result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth;
|
||||
// result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
|
||||
// result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
|
||||
// result.audioSampleRate = filterCommand.audioSampleRate;
|
||||
|
||||
// Stereo filters / shifters
|
||||
/* // Stereo filters / shifters
|
||||
double firStereoCutoff = ((double) 16000 / (double) filterCommand.audioSampleRate);
|
||||
float ft = ((double) 1000 / (double) filterCommand.audioSampleRate); // filter transition
|
||||
float mu = 0.0f; // fractional timing offset
|
||||
|
@ -83,7 +83,7 @@ void DemodulatorWorkerThread::run() {
|
|||
float Ap = 1.0f;
|
||||
As = 60.0f;
|
||||
|
||||
result.iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);
|
||||
result.iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As); */
|
||||
}
|
||||
|
||||
if (filterCommand.bandwidth) {
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
firfilt_rrrf firStereoLeft;
|
||||
firfilt_rrrf firStereoRight;
|
||||
iirfilt_crcf iirStereoPilot;
|
||||
|
||||
DemodulatorThread *demodThread;
|
||||
|
||||
long long sampleRate;
|
||||
unsigned int bandwidth;
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#include "Modem.h"
|
||||
|
||||
ModemFactoryList Modem::modemFactories;
|
||||
|
||||
void Modem::addModemFactory(std::string modemName, ModemFactoryFunc *factoryFunc) {
|
||||
modemFactories[modemName] = factoryFunc;
|
||||
}
|
||||
|
||||
ModemFactoryList Modem::getFactories() {
|
||||
return modemFactories;
|
||||
}
|
||||
|
||||
Modem *Modem::factory() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ModemKit *Modem::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Modem::disposeKit(ModemKit *kit) {
|
||||
return;
|
||||
}
|
||||
|
||||
void Modem::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include "liquid/liquid.h"
|
||||
#include "IOThread.h"
|
||||
#include "AudioThread.h"
|
||||
|
||||
class ModemKit {
|
||||
public:
|
||||
ModemKit() : sampleRate(0), audioSampleRate(0) {
|
||||
|
||||
}
|
||||
|
||||
long long sampleRate;
|
||||
int audioSampleRate;
|
||||
};
|
||||
|
||||
|
||||
class ModemIQData: public ReferenceCounter {
|
||||
public:
|
||||
std::vector<liquid_float_complex> data;
|
||||
long long sampleRate;
|
||||
|
||||
ModemIQData() : sampleRate(0) {
|
||||
|
||||
}
|
||||
|
||||
~ModemIQData() {
|
||||
std::lock_guard < std::mutex > lock(m_mutex);
|
||||
}
|
||||
};
|
||||
|
||||
class Modem;
|
||||
typedef Modem *(Modem::*ModemFactoryFunc)();
|
||||
typedef std::map<std::string,ModemFactoryFunc *> ModemFactoryList;
|
||||
|
||||
class Modem {
|
||||
public:
|
||||
static void addModemFactory(std::string modemName, ModemFactoryFunc *factoryFunc);
|
||||
static ModemFactoryList getFactories();
|
||||
|
||||
virtual Modem *factory();
|
||||
|
||||
virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
virtual void disposeKit(ModemKit *kit);
|
||||
virtual void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
private:
|
||||
static ModemFactoryList modemFactories;
|
||||
};
|
|
@ -0,0 +1,78 @@
|
|||
#include "ModemAnalog.h"
|
||||
|
||||
ModemAnalog::ModemAnalog() : aOutputCeil(1), aOutputCeilMA(1), aOutputCeilMAA(1) {
|
||||
|
||||
}
|
||||
|
||||
ModemKit *ModemAnalog::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
ModemKitAnalog *akit = new ModemKitAnalog;
|
||||
|
||||
// stop-band attenuation [dB]
|
||||
float As = 60.0f;
|
||||
|
||||
akit->sampleRate = sampleRate;
|
||||
akit->audioSampleRate = audioSampleRate;
|
||||
akit->audioResampleRatio = double(audioSampleRate) / double(sampleRate);
|
||||
akit->audioResampler = msresamp_rrrf_create(akit->audioResampleRatio, As);
|
||||
|
||||
return akit;
|
||||
}
|
||||
|
||||
void ModemAnalog::disposeKit(ModemKit *kit) {
|
||||
ModemKitAnalog *akit = (ModemKitAnalog *)kit;
|
||||
|
||||
msresamp_rrrf_destroy(akit->audioResampler);
|
||||
delete kit;
|
||||
}
|
||||
|
||||
void ModemAnalog::initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input) {
|
||||
bufSize = input->data.size();
|
||||
|
||||
if (!bufSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
double audio_resample_ratio = akit->audioResampleRatio;
|
||||
|
||||
int audio_out_size = ceil((double) (bufSize) * audio_resample_ratio) + 512;
|
||||
|
||||
if (demodOutputData.size() != bufSize) {
|
||||
if (demodOutputData.capacity() < bufSize) {
|
||||
demodOutputData.reserve(bufSize);
|
||||
}
|
||||
demodOutputData.resize(bufSize);
|
||||
}
|
||||
if (resampledOutputData.size() != audio_out_size) {
|
||||
if (resampledOutputData.capacity() < audio_out_size) {
|
||||
resampledOutputData.reserve(audio_out_size);
|
||||
}
|
||||
resampledOutputData.resize(audio_out_size);
|
||||
}
|
||||
}
|
||||
|
||||
void ModemAnalog::buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain) {
|
||||
unsigned int numAudioWritten;
|
||||
|
||||
if (autoGain) {
|
||||
aOutputCeilMA = aOutputCeilMA + (aOutputCeil - aOutputCeilMA) * 0.025;
|
||||
aOutputCeilMAA = aOutputCeilMAA + (aOutputCeilMA - aOutputCeilMAA) * 0.025;
|
||||
aOutputCeil = 0;
|
||||
|
||||
for (int i = 0; i < bufSize; i++) {
|
||||
if (demodOutputData[i] > aOutputCeil) {
|
||||
aOutputCeil = demodOutputData[i];
|
||||
}
|
||||
}
|
||||
|
||||
float gain = 0.5 / aOutputCeilMAA;
|
||||
|
||||
for (int i = 0; i < bufSize; i++) {
|
||||
demodOutputData[i] *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
msresamp_rrrf_execute(akit->audioResampler, &demodOutputData[0], demodOutputData.size(), &resampledOutputData[0], &numAudioWritten);
|
||||
|
||||
audioOut->channels = 1;
|
||||
audioOut->data.assign(resampledOutputData.begin(), resampledOutputData.begin() + numAudioWritten);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
||||
class ModemKitAnalog : public ModemKit {
|
||||
public:
|
||||
ModemKitAnalog() : ModemKit(), audioResampler(nullptr), audioResampleRatio(0) {
|
||||
|
||||
};
|
||||
|
||||
msresamp_rrrf audioResampler;
|
||||
double audioResampleRatio;
|
||||
};
|
||||
|
||||
|
||||
class ModemAnalog : public Modem {
|
||||
public:
|
||||
ModemAnalog();
|
||||
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
void disposeKit(ModemKit *kit);
|
||||
void initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input);
|
||||
void buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain);
|
||||
protected:
|
||||
int bufSize;
|
||||
std::vector<float> demodOutputData;
|
||||
std::vector<float> resampledOutputData;
|
||||
|
||||
float aOutputCeil;
|
||||
float aOutputCeilMA;
|
||||
float aOutputCeilMAA;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
#include "ModemAM.h"
|
||||
|
||||
ModemAM::ModemAM() {
|
||||
demodAM = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
|
||||
}
|
||||
|
||||
Modem *ModemAM::factory() {
|
||||
return new ModemAM;
|
||||
}
|
||||
|
||||
void ModemAM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *amkit = (ModemKitAnalog *)kit;
|
||||
|
||||
initOutputBuffers(amkit,input);
|
||||
|
||||
if (!bufSize) {
|
||||
input->decRefCount();
|
||||
return;
|
||||
}
|
||||
|
||||
ampmodem_demodulate_block(demodAM, &input->data[0], bufSize, &demodOutputData[0]);
|
||||
|
||||
buildAudioOutput(amkit,audioOut,true);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
#include "ModemAnalog.h"
|
||||
|
||||
class ModemAM : public ModemAnalog {
|
||||
public:
|
||||
ModemAM();
|
||||
Modem *factory();
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
ampmodem demodAM;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
#include "ModemDSB.h"
|
||||
|
||||
ModemDSB::ModemDSB() {
|
||||
demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
|
||||
}
|
||||
|
||||
Modem *ModemDSB::factory() {
|
||||
return new ModemDSB;
|
||||
}
|
||||
|
||||
void ModemDSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *amkit = (ModemKitAnalog *)kit;
|
||||
|
||||
initOutputBuffers(amkit, input);
|
||||
|
||||
if (!bufSize) {
|
||||
input->decRefCount();
|
||||
return;
|
||||
}
|
||||
|
||||
ampmodem_demodulate_block(demodAM_DSB, &input->data[0], bufSize, &demodOutputData[0]);
|
||||
|
||||
buildAudioOutput(amkit, audioOut, true);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
#include "ModemAnalog.h"
|
||||
|
||||
class ModemDSB : public ModemAnalog {
|
||||
public:
|
||||
ModemDSB();
|
||||
Modem *factory();
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
ampmodem demodAM_DSB;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
#include "ModemFM.h"
|
||||
|
||||
ModemFM::ModemFM() {
|
||||
demodFM = freqdem_create(0.5);
|
||||
}
|
||||
|
||||
Modem *ModemFM::factory() {
|
||||
return new ModemFM;
|
||||
}
|
||||
|
||||
void ModemFM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *fmkit = (ModemKitAnalog *)kit;
|
||||
|
||||
initOutputBuffers(fmkit, input);
|
||||
|
||||
if (!bufSize) {
|
||||
input->decRefCount();
|
||||
return;
|
||||
}
|
||||
|
||||
freqdem_demodulate_block(demodFM, &input->data[0], bufSize, &demodOutputData[0]);
|
||||
|
||||
buildAudioOutput(fmkit, audioOut, false);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
#include "ModemAnalog.h"
|
||||
|
||||
class ModemFM : public ModemAnalog {
|
||||
public:
|
||||
ModemFM();
|
||||
Modem *factory();
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
||||
freqdem demodFM;
|
||||
};
|
|
@ -0,0 +1,176 @@
|
|||
#include "ModemFMStereo.h"
|
||||
|
||||
ModemFMStereo::ModemFMStereo() {
|
||||
firStereoR2C = firhilbf_create(5, 60.0f);
|
||||
firStereoC2R = firhilbf_create(5, 60.0f);
|
||||
|
||||
stereoPilot = nco_crcf_create(LIQUID_VCO);
|
||||
nco_crcf_reset(stereoPilot);
|
||||
nco_crcf_pll_set_bandwidth(stereoPilot, 0.25f);
|
||||
}
|
||||
|
||||
ModemFMStereo::~ModemFMStereo() {
|
||||
firhilbf_destroy(firStereoR2C);
|
||||
firhilbf_destroy(firStereoC2R);
|
||||
|
||||
nco_crcf_destroy(stereoPilot);
|
||||
}
|
||||
|
||||
Modem *ModemFMStereo::factory() {
|
||||
return new ModemFMStereo;
|
||||
}
|
||||
|
||||
ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
ModemKitFMStereo *kit = new ModemKitFMStereo;
|
||||
|
||||
kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate);
|
||||
|
||||
float As = 60.0f; // stop-band attenuation [dB]
|
||||
|
||||
kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As);
|
||||
kit->stereoResampler = msresamp_rrrf_create(kit->audioResampleRatio, As);
|
||||
|
||||
// Stereo filters / shifters
|
||||
double firStereoCutoff = 16000.0 / double(audioSampleRate);
|
||||
// filter transition
|
||||
float ft = 1000.0 / double(audioSampleRate);
|
||||
// fractional timing offset
|
||||
float mu = 0.0f;
|
||||
|
||||
if (firStereoCutoff < 0) {
|
||||
firStereoCutoff = 0;
|
||||
}
|
||||
|
||||
if (firStereoCutoff > 0.5) {
|
||||
firStereoCutoff = 0.5;
|
||||
}
|
||||
|
||||
unsigned int h_len = estimate_req_filter_len(ft, As);
|
||||
float *h = new float[h_len];
|
||||
liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
|
||||
|
||||
kit->firStereoLeft = firfilt_rrrf_create(h, h_len);
|
||||
kit->firStereoRight = firfilt_rrrf_create(h, h_len);
|
||||
|
||||
// stereo pilot filter
|
||||
float bw = sampleRate;
|
||||
if (bw < 100000.0) {
|
||||
bw = 100000.0;
|
||||
}
|
||||
unsigned int order = 5; // filter order
|
||||
float f0 = ((double) 19000 / bw);
|
||||
float fc = ((double) 19500 / bw);
|
||||
float Ap = 1.0f;
|
||||
|
||||
kit->iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);
|
||||
|
||||
return kit;
|
||||
}
|
||||
|
||||
void ModemFMStereo::disposeKit(ModemKit *kit) {
|
||||
ModemKitFMStereo *fmkit = (ModemKitFMStereo *)kit;
|
||||
|
||||
msresamp_rrrf_destroy(fmkit->audioResampler);
|
||||
msresamp_rrrf_destroy(fmkit->stereoResampler);
|
||||
firfilt_rrrf_destroy(fmkit->firStereoLeft);
|
||||
firfilt_rrrf_destroy(fmkit->firStereoRight);
|
||||
}
|
||||
|
||||
|
||||
void ModemFMStereo::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitFMStereo *fmkit = (ModemKitFMStereo *)kit;
|
||||
int bufSize = input->data.size();
|
||||
liquid_float_complex u, v, w, x, y;
|
||||
|
||||
double audio_resample_ratio = fmkit->audioResampleRatio;
|
||||
|
||||
if (demodOutputData.size() != bufSize) {
|
||||
if (demodOutputData.capacity() < bufSize) {
|
||||
demodOutputData.reserve(bufSize);
|
||||
}
|
||||
demodOutputData.resize(bufSize);
|
||||
}
|
||||
|
||||
int audio_out_size = ceil((double) (bufSize) * audio_resample_ratio) + 512;
|
||||
|
||||
freqdem_demodulate_block(demodFM, &input->data[0], bufSize, &demodOutputData[0]);
|
||||
|
||||
if (resampledOutputData.size() != audio_out_size) {
|
||||
if (resampledOutputData.capacity() < audio_out_size) {
|
||||
resampledOutputData.reserve(audio_out_size);
|
||||
}
|
||||
resampledOutputData.resize(audio_out_size);
|
||||
}
|
||||
|
||||
unsigned int numAudioWritten;
|
||||
|
||||
msresamp_rrrf_execute(fmkit->audioResampler, &demodOutputData[0], bufSize, &resampledOutputData[0], &numAudioWritten);
|
||||
|
||||
if (demodStereoData.size() != bufSize) {
|
||||
if (demodStereoData.capacity() < bufSize) {
|
||||
demodStereoData.reserve(bufSize);
|
||||
}
|
||||
demodStereoData.resize(bufSize);
|
||||
}
|
||||
|
||||
float phase_error = 0;
|
||||
|
||||
for (int i = 0; i < bufSize; i++) {
|
||||
// real -> complex
|
||||
firhilbf_r2c_execute(firStereoR2C, demodOutputData[i], &x);
|
||||
|
||||
// 19khz pilot band-pass
|
||||
iirfilt_crcf_execute(fmkit->iirStereoPilot, x, &v);
|
||||
nco_crcf_cexpf(stereoPilot, &w);
|
||||
|
||||
w.imag = -w.imag; // conjf(w)
|
||||
|
||||
// multiply u = v * conjf(w)
|
||||
u.real = v.real * w.real - v.imag * w.imag;
|
||||
u.imag = v.real * w.imag + v.imag * w.real;
|
||||
|
||||
// cargf(u)
|
||||
phase_error = atan2f(u.imag,u.real);
|
||||
|
||||
// step pll
|
||||
nco_crcf_pll_step(stereoPilot, phase_error);
|
||||
nco_crcf_step(stereoPilot);
|
||||
|
||||
// 38khz down-mix
|
||||
nco_crcf_mix_down(stereoPilot, x, &y);
|
||||
nco_crcf_mix_down(stereoPilot, y, &x);
|
||||
|
||||
// complex -> real
|
||||
firhilbf_c2r_execute(firStereoC2R, x, &demodStereoData[i]);
|
||||
}
|
||||
|
||||
// std::cout << "[PLL] phase error: " << phase_error;
|
||||
// std::cout << " freq:" << (((nco_crcf_get_frequency(stereoPilot) / (2.0 * M_PI)) * inp->sampleRate)) << std::endl;
|
||||
|
||||
if (audio_out_size != resampledStereoData.size()) {
|
||||
if (resampledStereoData.capacity() < audio_out_size) {
|
||||
resampledStereoData.reserve(audio_out_size);
|
||||
}
|
||||
resampledStereoData.resize(audio_out_size);
|
||||
}
|
||||
|
||||
msresamp_rrrf_execute(fmkit->stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten);
|
||||
|
||||
audioOut->channels = 2;
|
||||
if (audioOut->data.capacity() < (numAudioWritten * 2)) {
|
||||
audioOut->data.reserve(numAudioWritten * 2);
|
||||
}
|
||||
audioOut->data.resize(numAudioWritten * 2);
|
||||
for (int i = 0; i < numAudioWritten; i++) {
|
||||
float l, r;
|
||||
|
||||
firfilt_rrrf_push(fmkit->firStereoLeft, 0.568 * (resampledOutputData[i] - (resampledStereoData[i])));
|
||||
firfilt_rrrf_execute(fmkit->firStereoLeft, &l);
|
||||
|
||||
firfilt_rrrf_push(fmkit->firStereoRight, 0.568 * (resampledOutputData[i] + (resampledStereoData[i])));
|
||||
firfilt_rrrf_execute(fmkit->firStereoRight, &r);
|
||||
|
||||
audioOut->data[i * 2] = l;
|
||||
audioOut->data[i * 2 + 1] = r;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
||||
class ModemKitFMStereo: public ModemKit {
|
||||
public:
|
||||
ModemKitFMStereo() : audioResampler(nullptr), stereoResampler(nullptr), audioResampleRatio(0), firStereoLeft(nullptr), firStereoRight(nullptr), iirStereoPilot(nullptr) {
|
||||
}
|
||||
|
||||
msresamp_rrrf audioResampler;
|
||||
msresamp_rrrf stereoResampler;
|
||||
double audioResampleRatio;
|
||||
|
||||
firfilt_rrrf firStereoLeft;
|
||||
firfilt_rrrf firStereoRight;
|
||||
iirfilt_crcf iirStereoPilot;
|
||||
};
|
||||
|
||||
|
||||
class ModemFMStereo : public Modem {
|
||||
public:
|
||||
ModemFMStereo();
|
||||
~ModemFMStereo();
|
||||
Modem *factory();
|
||||
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
void disposeKit(ModemKit *kit);
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
std::vector<float> demodOutputData;
|
||||
std::vector<float> demodStereoData;
|
||||
std::vector<float> resampledOutputData;
|
||||
std::vector<float> resampledStereoData;
|
||||
freqdem demodFM;
|
||||
|
||||
firhilbf firStereoR2C;
|
||||
firhilbf firStereoC2R;
|
||||
|
||||
nco_crcf stereoPilot;
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
#include "ModemIQ.h"
|
||||
|
||||
ModemIQ::ModemIQ() {
|
||||
|
||||
}
|
||||
|
||||
Modem *ModemIQ::factory() {
|
||||
return new ModemIQ;
|
||||
}
|
||||
|
||||
ModemKit *ModemIQ::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
ModemKit *kit = new ModemKit;
|
||||
return kit;
|
||||
}
|
||||
|
||||
void ModemIQ::disposeKit(ModemKit *kit) {
|
||||
delete kit;
|
||||
}
|
||||
|
||||
void ModemIQ::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
int bufSize = input->data.size();
|
||||
|
||||
if (!bufSize) {
|
||||
input->decRefCount();
|
||||
return;
|
||||
}
|
||||
|
||||
audioOut->channels = 2;
|
||||
if (audioOut->data.capacity() < (bufSize * 2)) {
|
||||
audioOut->data.reserve(bufSize * 2);
|
||||
}
|
||||
|
||||
audioOut->data.resize(bufSize * 2);
|
||||
for (int i = 0; i < bufSize; i++) {
|
||||
audioOut->data[i * 2] = input->data[i].imag;
|
||||
audioOut->data[i * 2 + 1] = input->data[i].real;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
||||
class ModemIQ : public Modem {
|
||||
public:
|
||||
ModemIQ();
|
||||
Modem *factory();
|
||||
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
void disposeKit(ModemKit *kit);
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
#include "ModemLSB.h"
|
||||
|
||||
ModemLSB::ModemLSB() {
|
||||
// half band filter used for side-band elimination
|
||||
ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
|
||||
demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1);
|
||||
}
|
||||
|
||||
Modem *ModemLSB::factory() {
|
||||
return new ModemLSB;
|
||||
}
|
||||
|
||||
ModemLSB::~ModemLSB() {
|
||||
resamp2_crcf_destroy(ssbFilt);
|
||||
ampmodem_destroy(demodAM_LSB);
|
||||
}
|
||||
|
||||
void ModemLSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *akit = (ModemKitAnalog *)kit;
|
||||
|
||||
initOutputBuffers(akit,input);
|
||||
|
||||
if (!bufSize) {
|
||||
input->decRefCount();
|
||||
return;
|
||||
}
|
||||
|
||||
liquid_float_complex x, y;
|
||||
for (int i = 0; i < bufSize; i++) { // Reject upper band
|
||||
resamp2_crcf_filter_execute(ssbFilt,input->data[i],&x,&y);
|
||||
ampmodem_demodulate(demodAM_LSB, x, &demodOutputData[i]);
|
||||
}
|
||||
|
||||
buildAudioOutput(akit, audioOut, true);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
#include "ModemAnalog.h"
|
||||
|
||||
class ModemLSB : public ModemAnalog {
|
||||
public:
|
||||
ModemLSB();
|
||||
~ModemLSB();
|
||||
Modem *factory();
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
resamp2_crcf ssbFilt;
|
||||
ampmodem demodAM_LSB;
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
#include "ModemUSB.h"
|
||||
|
||||
ModemUSB::ModemUSB() {
|
||||
// half band filter used for side-band elimination
|
||||
ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
|
||||
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
|
||||
}
|
||||
|
||||
Modem *ModemUSB::factory() {
|
||||
return new ModemUSB;
|
||||
}
|
||||
|
||||
ModemUSB::~ModemUSB() {
|
||||
resamp2_crcf_destroy(ssbFilt);
|
||||
ampmodem_destroy(demodAM_USB);
|
||||
}
|
||||
|
||||
void ModemUSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *akit = (ModemKitAnalog *)kit;
|
||||
|
||||
initOutputBuffers(akit,input);
|
||||
|
||||
if (!bufSize) {
|
||||
input->decRefCount();
|
||||
return;
|
||||
}
|
||||
|
||||
liquid_float_complex x, y;
|
||||
for (int i = 0; i < bufSize; i++) { // Reject lower band
|
||||
resamp2_crcf_filter_execute(ssbFilt,input->data[i],&x,&y);
|
||||
ampmodem_demodulate(demodAM_USB, y, &demodOutputData[i]);
|
||||
}
|
||||
|
||||
buildAudioOutput(akit, audioOut, true);
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include "ModemAnalog.h"
|
||||
|
||||
class ModemUSB : public ModemAnalog {
|
||||
public:
|
||||
ModemUSB();
|
||||
~ModemUSB();
|
||||
Modem *factory();
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
resamp2_crcf ssbFilt;
|
||||
ampmodem demodAM_USB;
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
#include "ModemAPSK.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "ModemASK.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "ModemBPSK.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "ModemDPSK.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "ModemOOK.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "ModemPSK.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "ModemQAM.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "ModemQPSK.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "ModemSQAM.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#include "ModemST.h"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#pragma once
|
||||
#include "Modem.h"
|
Loading…
Reference in New Issue