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/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

View File

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

View File

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

View File

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

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) {
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();

View File

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

View File

@ -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) {

View File

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

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"