Modem, ModemKit and initial ModemAnalog refactor

This commit is contained in:
Charles J. Cliffe 2015-11-16 23:49:54 -05:00
parent f1f2cb91eb
commit a1a6a467e8
46 changed files with 932 additions and 186 deletions

View File

@ -234,6 +234,25 @@ SET (cubicsdr_sources
src/demod/DemodulatorWorkerThread.cpp src/demod/DemodulatorWorkerThread.cpp
src/demod/DemodulatorInstance.cpp src/demod/DemodulatorInstance.cpp
src/demod/DemodulatorMgr.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/audio/AudioThread.cpp
src/util/Gradient.cpp src/util/Gradient.cpp
src/util/Timer.cpp src/util/Timer.cpp
@ -293,6 +312,25 @@ SET (cubicsdr_headers
src/demod/DemodulatorInstance.h src/demod/DemodulatorInstance.h
src/demod/DemodulatorMgr.h src/demod/DemodulatorMgr.h
src/demod/DemodDefs.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/audio/AudioThread.h
src/util/Gradient.h src/util/Gradient.h
src/util/Timer.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("Forms\\SDRDevices" REGULAR_EXPRESSION "src/forms/SDRDevices/${REG_EXT}")
SOURCE_GROUP("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}") SOURCE_GROUP("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}")
SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${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("Audio" REGULAR_EXPRESSION "src/audio/${REG_EXT}")
SOURCE_GROUP("Utility" REGULAR_EXPRESSION "src/util/${REG_EXT}") SOURCE_GROUP("Utility" REGULAR_EXPRESSION "src/util/${REG_EXT}")
SOURCE_GROUP("Visual" REGULAR_EXPRESSION "src/visual/${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/forms/SDRDevices
${PROJECT_SOURCE_DIR}/src/sdr ${PROJECT_SOURCE_DIR}/src/sdr
${PROJECT_SOURCE_DIR}/src/demod ${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/audio
${PROJECT_SOURCE_DIR}/src/util ${PROJECT_SOURCE_DIR}/src/util
${PROJECT_SOURCE_DIR}/src/panel ${PROJECT_SOURCE_DIR}/src/panel

View File

@ -93,21 +93,14 @@ public:
} }
}; };
class DemodulatorThreadPostIQData: public ReferenceCounter { class DemodulatorThreadPostIQData: public ReferenceCounter {
public: public:
std::vector<liquid_float_complex> data; std::vector<liquid_float_complex> data;
long long sampleRate; long long sampleRate;
msresamp_rrrf audioResampler;
msresamp_rrrf stereoResampler;
double audioResampleRatio;
int audioSampleRate;
firfilt_rrrf firStereoLeft;
firfilt_rrrf firStereoRight;
iirfilt_crcf iirStereoPilot;
DemodulatorThreadPostIQData() : 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 { class DemodulatorThreadAudioData: public ReferenceCounter {
public: public:
long long frequency; long long frequency;

View File

@ -202,7 +202,7 @@ bool DemodulatorInstance::isStereo() {
void DemodulatorInstance::setStereo(bool state) { void DemodulatorInstance::setStereo(bool state) {
stereo = state; stereo = state;
demodulatorThread->setStereo(state); // demodulatorThread->setStereo(state);
} }
void DemodulatorInstance::squelchAuto() { void DemodulatorInstance::squelchAuto() {

View File

@ -27,45 +27,45 @@ void DemodulatorPreThread::initialize() {
initialized = false; initialized = false;
iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate; 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); iqResampler = msresamp_crcf_create(iqResampleRatio, As);
audioResampler = msresamp_rrrf_create(audioResampleRatio, As); // audioResampler = msresamp_rrrf_create(audioResampleRatio, As);
stereoResampler = msresamp_rrrf_create(audioResampleRatio, As); // stereoResampler = msresamp_rrrf_create(audioResampleRatio, As);
// Stereo filters / shifters // Stereo filters / shifters
double firStereoCutoff = ((double) 16000 / (double) params.audioSampleRate); // double firStereoCutoff = ((double) 16000 / (double) params.audioSampleRate);
float ft = ((double) 1000 / (double) params.audioSampleRate); // filter transition // float ft = ((double) 1000 / (double) params.audioSampleRate); // filter transition
float mu = 0.0f; // fractional timing offset // float mu = 0.0f; // fractional timing offset
//
// if (firStereoCutoff < 0) {
// firStereoCutoff = 0;
// }
//
// if (firStereoCutoff > 0.5) {
// firStereoCutoff = 0.5;
// }
if (firStereoCutoff < 0) { // unsigned int h_len = estimate_req_filter_len(ft, As);
firStereoCutoff = 0; // float *h = new float[h_len];
} // liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
//
if (firStereoCutoff > 0.5) { // firStereoLeft = firfilt_rrrf_create(h, h_len);
firStereoCutoff = 0.5; // 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 // stereo pilot filter
float bw = params.bandwidth; // float bw = params.bandwidth;
if (bw < 100000.0) { // if (bw < 100000.0) {
bw = 100000.0; // bw = 100000.0;
} // }
unsigned int order = 5; // filter order // unsigned int order = 5; // filter order
float f0 = ((double) 19000 / bw); // float f0 = ((double) 19000 / bw);
float fc = ((double) 19500 / bw); // float fc = ((double) 19500 / bw);
float Ap = 1.0f; // float Ap = 1.0f;
As = 60.0f; // As = 60.0f;
iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As); // iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);
initialized = true; initialized = true;
lastParams = params; lastParams = params;
@ -218,7 +218,6 @@ void DemodulatorPreThread::run() {
msresamp_crcf_execute(iqResampler, in_buf, bufSize, &resampledData[0], &numWritten); msresamp_crcf_execute(iqResampler, in_buf, bufSize, &resampledData[0], &numWritten);
resamp->setRefCount(1); resamp->setRefCount(1);
resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten); resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten);
// bool uneven = (numWritten % 2 != 0); // bool uneven = (numWritten % 2 != 0);
@ -245,13 +244,13 @@ void DemodulatorPreThread::run() {
resamp->audioResampleRatio = audioResampleRatio; // resamp->audioResampleRatio = audioResampleRatio;
resamp->audioResampler = audioResampler; // resamp->audioResampler = audioResampler;
resamp->audioSampleRate = params.audioSampleRate; // resamp->audioSampleRate = params.audioSampleRate;
resamp->stereoResampler = stereoResampler; // resamp->stereoResampler = stereoResampler;
resamp->firStereoLeft = firStereoLeft; // resamp->firStereoLeft = firStereoLeft;
resamp->firStereoRight = firStereoRight; // resamp->firStereoRight = firStereoRight;
resamp->iirStereoPilot = iirStereoPilot; // resamp->iirStereoPilot = iirStereoPilot;
resamp->sampleRate = params.bandwidth; resamp->sampleRate = params.bandwidth;
iqOutputQueue->push(resamp); iqOutputQueue->push(resamp);

View File

@ -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) { 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); muted.store(false);
agcEnabled.store(false); agcEnabled.store(false);
demodulatorType.store(DEMOD_TYPE_FM); demodulatorType.store(DEMOD_TYPE_FM);
demodFM = freqdem_create(0.5); // demodFM = freqdem_create(0.5);
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1); // 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_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 = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0); // demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
demodAM = demodAM_DSB_CSP; // demodAM = demodAM_DSB_CSP;
// advanced demodulators // advanced demodulators
demodulatorCons.store(2); /* demodulatorCons.store(2);
currentDemodCons = 0; currentDemodCons = 0;
demodASK = demodASK2; demodASK = demodASK2;
@ -90,7 +90,7 @@ DemodulatorThread::DemodulatorThread() : IOThread(), iqAutoGain(NULL), amOutputC
demodQPSK = modem_create(LIQUID_MODEM_QPSK); demodQPSK = modem_create(LIQUID_MODEM_QPSK);
currentDemodLock = false; currentDemodLock = false; */
} }
DemodulatorThread::~DemodulatorThread() { DemodulatorThread::~DemodulatorThread() {
@ -110,23 +110,23 @@ void DemodulatorThread::run() {
pthread_setschedparam(tID, SCHED_FIFO, &prio); pthread_setschedparam(tID, SCHED_FIFO, &prio);
#endif #endif
msresamp_rrrf audioResampler = NULL; // msresamp_rrrf audioResampler = NULL;
msresamp_rrrf stereoResampler = NULL; // msresamp_rrrf stereoResampler = NULL;
firfilt_rrrf firStereoLeft = NULL; // firfilt_rrrf firStereoLeft = NULL;
firfilt_rrrf firStereoRight = NULL; // firfilt_rrrf firStereoRight = NULL;
iirfilt_crcf iirStereoPilot = 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 firStereoR2C = firhilbf_create(5, 60.0f);
firhilbf firStereoC2R = firhilbf_create(5, 60.0f); // firhilbf firStereoC2R = firhilbf_create(5, 60.0f);
nco_crcf stereoPilot = nco_crcf_create(LIQUID_VCO); // nco_crcf stereoPilot = nco_crcf_create(LIQUID_VCO);
nco_crcf_reset(stereoPilot); // nco_crcf_reset(stereoPilot);
nco_crcf_pll_set_bandwidth(stereoPilot, 0.25f); // nco_crcf_pll_set_bandwidth(stereoPilot, 0.25f);
// half band filter used for side-band elimination // 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 // Automatic IQ gain
iqAutoGain = agc_crcf_create(); iqAutoGain = agc_crcf_create();
@ -141,22 +141,22 @@ void DemodulatorThread::run() {
threadQueueControl = (DemodulatorThreadControlCommandQueue *)getInputQueue("ControlQueue"); threadQueueControl = (DemodulatorThreadControlCommandQueue *)getInputQueue("ControlQueue");
threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue"); threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue");
switch (demodulatorType.load()) { // switch (demodulatorType.load()) {
case DEMOD_TYPE_FM: // case DEMOD_TYPE_FM:
break; // break;
case DEMOD_TYPE_LSB: // case DEMOD_TYPE_LSB:
demodAM = demodAM_LSB; // demodAM = demodAM_LSB;
break; // break;
case DEMOD_TYPE_USB: // case DEMOD_TYPE_USB:
demodAM = demodAM_USB; // demodAM = demodAM_USB;
break; // break;
case DEMOD_TYPE_DSB: // case DEMOD_TYPE_DSB:
demodAM = demodAM_DSB; // demodAM = demodAM_DSB;
break; // break;
case DEMOD_TYPE_AM: // case DEMOD_TYPE_AM:
demodAM = demodAM_DSB_CSP; // demodAM = demodAM_DSB_CSP;
break; // break;
} // }
while (!terminated) { while (!terminated) {
DemodulatorThreadPostIQData *inp; DemodulatorThreadPostIQData *inp;
@ -170,47 +170,47 @@ void DemodulatorThread::run() {
continue; continue;
} }
if (audioResampler == NULL) { // if (audioResampler == NULL) {
audioResampler = inp->audioResampler; // audioResampler = inp->audioResampler;
stereoResampler = inp->stereoResampler; // stereoResampler = inp->stereoResampler;
firStereoLeft = inp->firStereoLeft; // firStereoLeft = inp->firStereoLeft;
firStereoRight = inp->firStereoRight; // firStereoRight = inp->firStereoRight;
iirStereoPilot = inp->iirStereoPilot; // iirStereoPilot = inp->iirStereoPilot;
audioSampleRate = inp->audioSampleRate; // audioSampleRate = inp->audioSampleRate;
} else if (audioResampler != inp->audioResampler) { // } else if (audioResampler != inp->audioResampler) {
msresamp_rrrf_destroy(audioResampler); // msresamp_rrrf_destroy(audioResampler);
msresamp_rrrf_destroy(stereoResampler); // msresamp_rrrf_destroy(stereoResampler);
audioResampler = inp->audioResampler; // audioResampler = inp->audioResampler;
stereoResampler = inp->stereoResampler; // stereoResampler = inp->stereoResampler;
audioSampleRate = inp->audioSampleRate; // audioSampleRate = inp->audioSampleRate;
//
if (demodAM) { // if (demodAM) {
ampmodem_reset(demodAM); // ampmodem_reset(demodAM);
} // }
freqdem_reset(demodFM); // freqdem_reset(demodFM);
nco_crcf_reset(stereoPilot); // nco_crcf_reset(stereoPilot);
} // }
//
if (firStereoLeft != inp->firStereoLeft) { // if (firStereoLeft != inp->firStereoLeft) {
if (firStereoLeft != NULL) { // if (firStereoLeft != NULL) {
firfilt_rrrf_destroy(firStereoLeft); // firfilt_rrrf_destroy(firStereoLeft);
} // }
firStereoLeft = inp->firStereoLeft; // firStereoLeft = inp->firStereoLeft;
} // }
//
if (firStereoRight != inp->firStereoRight) { // if (firStereoRight != inp->firStereoRight) {
if (firStereoRight != NULL) { // if (firStereoRight != NULL) {
firfilt_rrrf_destroy(firStereoRight); // firfilt_rrrf_destroy(firStereoRight);
} // }
firStereoRight = inp->firStereoRight; // firStereoRight = inp->firStereoRight;
} // }
//
if (iirStereoPilot != inp->iirStereoPilot) { // if (iirStereoPilot != inp->iirStereoPilot) {
if (iirStereoPilot != NULL) { // if (iirStereoPilot != NULL) {
iirfilt_crcf_destroy(iirStereoPilot); // iirfilt_crcf_destroy(iirStereoPilot);
} // }
iirStereoPilot = inp->iirStereoPilot; // iirStereoPilot = inp->iirStereoPilot;
} // }
if (agcData.size() != bufSize) { if (agcData.size() != bufSize) {
if (agcData.capacity() < bufSize) { if (agcData.capacity() < bufSize) {
@ -221,23 +221,24 @@ void DemodulatorThread::run() {
agcAMData.resize(bufSize); agcAMData.resize(bufSize);
} }
double audio_resample_ratio = inp->audioResampleRatio; // double audio_resample_ratio = inp->audioResampleRatio;
if (demodOutputData.size() != bufSize) { // if (demodOutputData.size() != bufSize) {
if (demodOutputData.capacity() < bufSize) { // if (demodOutputData.capacity() < bufSize) {
demodOutputData.reserve(bufSize); // demodOutputData.reserve(bufSize);
} // }
demodOutputData.resize(bufSize); // demodOutputData.resize(bufSize);
} // }
/*
if (demodOutputDataDigital.size() != bufSize) { if (demodOutputDataDigital.size() != bufSize) {
if (demodOutputDataDigital.capacity() < bufSize) { if (demodOutputDataDigital.capacity() < bufSize) {
demodOutputDataDigital.reserve(bufSize); demodOutputDataDigital.reserve(bufSize);
} }
demodOutputDataDigital.resize(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]); agc_crcf_execute_block(iqAutoGain, &(inp->data[0]), bufSize, &agcData[0]);
@ -258,8 +259,8 @@ void DemodulatorThread::run() {
} }
// Reset demodulator Constellations & Lock // Reset demodulator Constellations & Lock
updateDemodulatorCons(0); // updateDemodulatorCons(0);
/*
if (demodulatorType == DEMOD_TYPE_FM) { if (demodulatorType == DEMOD_TYPE_FM) {
currentDemodLock = false; currentDemodLock = false;
freqdem_demodulate_block(demodFM, &(*inputData)[0], bufSize, &demodOutputData[0]); 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); msresamp_rrrf_execute(stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten);
} }
} }*/
if (currentSignalLevel > signalLevel) { if (currentSignalLevel > signalLevel) {
signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.5; signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.5;
@ -681,13 +682,14 @@ void DemodulatorThread::run() {
if (audioOutputQueue != NULL) { if (audioOutputQueue != NULL) {
if (!squelchEnabled || (signalLevel >= squelchLevel)) { if (!squelchEnabled || (signalLevel >= squelchLevel)) {
ati = outputBuffers.getBuffer(); ati = outputBuffers.getBuffer();
ati->sampleRate = audioSampleRate; ati->sampleRate = audioSampleRate;
ati->inputRate = inp->sampleRate; ati->inputRate = inp->sampleRate;
ati->setRefCount(1); ati->setRefCount(1);
/*
if (demodulatorType == DEMOD_TYPE_RAW) { if (demodulatorType == DEMOD_TYPE_RAW) {
ati->channels = 2; ati->channels = 2;
if (ati->data.capacity() < (numAudioWritten * 2)) { if (ati->data.capacity() < (numAudioWritten * 2)) {
@ -720,7 +722,7 @@ void DemodulatorThread::run() {
ati->channels = 1; ati->channels = 1;
ati->data.assign(resampledOutputData.begin(), resampledOutputData.begin() + numAudioWritten); ati->data.assign(resampledOutputData.begin(), resampledOutputData.begin() + numAudioWritten);
} }
*/
std::vector<float>::iterator data_i; std::vector<float>::iterator data_i;
ati->peak = 0; ati->peak = 0;
for (data_i = ati->data.begin(); data_i != ati->data.end(); data_i++) { 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()) { if (ati && audioVisOutputQueue != NULL && audioVisOutputQueue->empty()) {
AudioThreadInput *ati_vis = audioVisBuffers.getBuffer(); AudioThreadInput *ati_vis = audioVisBuffers.getBuffer();
ati_vis->setRefCount(1); ati_vis->setRefCount(1);
@ -762,6 +764,7 @@ void DemodulatorThread::run() {
} }
} }
} else { } else {
int numAudioWritten = ati->data.size();
ati_vis->channels = 1; ati_vis->channels = 1;
if (numAudioWritten > bufSize) { if (numAudioWritten > bufSize) {
ati_vis->inputRate = audioSampleRate; ati_vis->inputRate = audioSampleRate;
@ -781,6 +784,7 @@ void DemodulatorThread::run() {
audioVisOutputQueue->push(ati_vis); audioVisOutputQueue->push(ati_vis);
} }
*/
if (ati != NULL) { if (ati != NULL) {
if (!muted.load()) { if (!muted.load()) {
@ -791,7 +795,7 @@ void DemodulatorThread::run() {
} }
if (!threadQueueControl->empty()) { if (!threadQueueControl->empty()) {
int newDemodType = DEMOD_TYPE_NULL; // int newDemodType = DEMOD_TYPE_NULL;
while (!threadQueueControl->empty()) { while (!threadQueueControl->empty()) {
DemodulatorThreadControlCommand command; DemodulatorThreadControlCommand command;
@ -804,14 +808,14 @@ void DemodulatorThread::run() {
case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_OFF: case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_OFF:
squelchEnabled = false; squelchEnabled = false;
break; break;
case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE: // case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE:
newDemodType = command.demodType; // newDemodType = command.demodType;
break; // break;
default: default:
break; break;
} }
} }
/*
if (newDemodType != DEMOD_TYPE_NULL) { if (newDemodType != DEMOD_TYPE_NULL) {
switch (newDemodType) { switch (newDemodType) {
case DEMOD_TYPE_FM: case DEMOD_TYPE_FM:
@ -868,15 +872,15 @@ void DemodulatorThread::run() {
break; break;
} }
demodulatorType = newDemodType; demodulatorType = newDemodType;
} }*/
} }
demodOutputDataDigital.empty(); // demodOutputDataDigital.empty();
inp->decRefCount(); inp->decRefCount();
} }
// end while !terminated // end while !terminated
/*
if (audioResampler != NULL) { if (audioResampler != NULL) {
msresamp_rrrf_destroy(audioResampler); msresamp_rrrf_destroy(audioResampler);
} }
@ -898,7 +902,7 @@ void DemodulatorThread::run() {
firhilbf_destroy(firStereoC2R); firhilbf_destroy(firStereoC2R);
nco_crcf_destroy(stereoPilot); nco_crcf_destroy(stereoPilot);
resamp2_crcf_destroy(ssbFilt); resamp2_crcf_destroy(ssbFilt);
*/
outputBuffers.purge(); outputBuffers.purge();
if (audioVisOutputQueue && !audioVisOutputQueue->empty()) { if (audioVisOutputQueue && !audioVisOutputQueue->empty()) {
@ -920,14 +924,14 @@ void DemodulatorThread::terminate() {
iqInputQueue->push(inp); iqInputQueue->push(inp);
} }
void DemodulatorThread::setStereo(bool state) { //void DemodulatorThread::setStereo(bool state) {
stereo.store(state); // stereo.store(state);
std::cout << "Stereo " << (state ? "Enabled" : "Disabled") << std::endl; // std::cout << "Stereo " << (state ? "Enabled" : "Disabled") << std::endl;
} //}
bool DemodulatorThread::isStereo() { //bool DemodulatorThread::isStereo() {
return stereo.load(); // return stereo.load();
} //}
bool DemodulatorThread::isMuted() { bool DemodulatorThread::isMuted() {
return muted.load(); return muted.load();

View File

@ -21,8 +21,8 @@ public:
void run(); void run();
void terminate(); void terminate();
void setStereo(bool state); // void setStereo(bool state);
bool isStereo(); // bool isStereo();
void setAGC(bool state); void setAGC(bool state);
bool getAGC(); bool getAGC();
@ -42,35 +42,35 @@ public:
void setDemodulatorCons(int demod_cons_in); void setDemodulatorCons(int demod_cons_in);
int getDemodulatorCons(); int getDemodulatorCons();
//
#ifdef __APPLE__ //#ifdef __APPLE__
static void *pthread_helper(void *context) { // static void *pthread_helper(void *context) {
return ((DemodulatorThread *) context)->threadMain(); // return ((DemodulatorThread *) context)->threadMain();
} // }
#endif //#endif
protected: protected:
ReBuffer<AudioThreadInput> outputBuffers; ReBuffer<AudioThreadInput> outputBuffers;
std::vector<liquid_float_complex> agcData; std::vector<liquid_float_complex> agcData;
std::vector<float> agcAMData; std::vector<float> agcAMData;
std::vector<float> demodOutputData; // std::vector<float> demodOutputData;
std::vector<float> demodStereoData; // std::vector<float> demodStereoData;
std::vector<float> resampledOutputData; // std::vector<float> resampledOutputData;
std::vector<float> resampledStereoData; // std::vector<float> resampledStereoData;
std::vector<unsigned int> demodOutputDataDigital; std::vector<unsigned int> demodOutputDataDigital;
//std::vector<unsigned int> demodOutputDataDigitalTest; //std::vector<unsigned int> demodOutputDataDigitalTest;
//std::vector<unsigned char> demodOutputSoftbits; //std::vector<unsigned char> demodOutputSoftbits;
//std::vector<unsigned char> demodOutputSoftbitsTest; //std::vector<unsigned char> demodOutputSoftbitsTest;
freqdem demodFM; // freqdem demodFM;
ampmodem demodAM; // ampmodem demodAM;
ampmodem demodAM_DSB_CSP; // ampmodem demodAM_DSB_CSP;
ampmodem demodAM_DSB; // ampmodem demodAM_DSB;
ampmodem demodAM_LSB; // ampmodem demodAM_LSB;
ampmodem demodAM_USB; // ampmodem demodAM_USB;
/*
modem demodASK; modem demodASK;
modem demodASK2; modem demodASK2;
modem demodASK4; modem demodASK4;
@ -130,14 +130,14 @@ protected:
modem demodQAM256; modem demodQAM256;
modem demodQPSK; modem demodQPSK;
*/
agc_crcf iqAutoGain; agc_crcf iqAutoGain;
float amOutputCeil; float amOutputCeil;
float amOutputCeilMA; float amOutputCeilMA;
float amOutputCeilMAA; float amOutputCeilMAA;
std::atomic_bool stereo; // std::atomic_bool stereo;
std::atomic_bool muted; std::atomic_bool muted;
std::atomic_bool agcEnabled; std::atomic_bool agcEnabled;
std::atomic_int demodulatorType; std::atomic_int demodulatorType;

View File

@ -47,12 +47,12 @@ void DemodulatorWorkerThread::run() {
} }
if (filterCommand.bandwidth && filterCommand.audioSampleRate) { if (filterCommand.bandwidth && filterCommand.audioSampleRate) {
result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth; // result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth;
result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As); // result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As); // result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
result.audioSampleRate = filterCommand.audioSampleRate; // result.audioSampleRate = filterCommand.audioSampleRate;
// Stereo filters / shifters /* // Stereo filters / shifters
double firStereoCutoff = ((double) 16000 / (double) filterCommand.audioSampleRate); double firStereoCutoff = ((double) 16000 / (double) filterCommand.audioSampleRate);
float ft = ((double) 1000 / (double) filterCommand.audioSampleRate); // filter transition float ft = ((double) 1000 / (double) filterCommand.audioSampleRate); // filter transition
float mu = 0.0f; // fractional timing offset float mu = 0.0f; // fractional timing offset
@ -83,7 +83,7 @@ void DemodulatorWorkerThread::run() {
float Ap = 1.0f; float Ap = 1.0f;
As = 60.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) { if (filterCommand.bandwidth) {

View File

@ -37,6 +37,8 @@ public:
firfilt_rrrf firStereoRight; firfilt_rrrf firStereoRight;
iirfilt_crcf iirStereoPilot; iirfilt_crcf iirStereoPilot;
DemodulatorThread *demodThread;
long long sampleRate; long long sampleRate;
unsigned int bandwidth; unsigned int bandwidth;
unsigned int audioSampleRate; unsigned int audioSampleRate;

View File

@ -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;
}

48
src/modules/modem/Modem.h Normal file
View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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:
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -0,0 +1 @@
#include "ModemAPSK.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1 @@
#include "ModemASK.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1 @@
#include "ModemBPSK.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1 @@
#include "ModemDPSK.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1 @@
#include "ModemOOK.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1 @@
#include "ModemPSK.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1 @@
#include "ModemQAM.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1 @@
#include "ModemQPSK.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1 @@
#include "ModemSQAM.h"

View File

@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"

View File

@ -0,0 +1,2 @@
#include "ModemST.h"

View File

@ -0,0 +1,2 @@
#pragma once
#include "Modem.h"