2014-12-16 18:27:32 -05:00
|
|
|
#include "DemodulatorThread.h"
|
|
|
|
#include "CubicSDRDefs.h"
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <pthread.h>
|
|
|
|
#endif
|
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
|
2014-12-24 01:28:33 -05:00
|
|
|
DemodulatorThreadCommandQueue* threadQueueNotify) :
|
2015-01-03 17:07:39 -05:00
|
|
|
iqInputQueue(iqInputQueue), audioVisOutputQueue(NULL), audioOutputQueue(NULL), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(
|
|
|
|
1), stereo(false), terminated(
|
|
|
|
false), demodulatorType(DEMOD_TYPE_FM), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelchLevel(0), signalLevel(
|
|
|
|
0), squelchEnabled(false) {
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
demodFM = freqdem_create(0.5);
|
|
|
|
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1);
|
|
|
|
demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
|
2015-01-07 20:23:15 -05:00
|
|
|
demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
|
2015-01-03 17:07:39 -05:00
|
|
|
demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
|
|
|
|
demodAM = demodAM_DSB_CSP;
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2014-12-16 18:27:32 -05:00
|
|
|
}
|
|
|
|
DemodulatorThread::~DemodulatorThread() {
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
void *DemodulatorThread::threadMain() {
|
|
|
|
#else
|
2014-12-16 21:30:03 -05:00
|
|
|
void DemodulatorThread::threadMain() {
|
2014-12-16 18:27:32 -05:00
|
|
|
#endif
|
2014-12-16 20:33:44 -05:00
|
|
|
#ifdef __APPLE__
|
2014-12-18 20:11:25 -05:00
|
|
|
pthread_t tID = pthread_self(); // ID of this thread
|
|
|
|
int priority = sched_get_priority_max( SCHED_FIFO )-1;
|
2014-12-18 21:39:32 -05:00
|
|
|
sched_param prio = {priority}; // scheduling priority of thread
|
2014-12-18 20:11:25 -05:00
|
|
|
pthread_setschedparam(tID, SCHED_FIFO, &prio);
|
2014-12-16 20:33:44 -05:00
|
|
|
#endif
|
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
msresamp_rrrf audioResampler = NULL;
|
|
|
|
msresamp_rrrf stereoResampler = NULL;
|
|
|
|
firfilt_rrrf firStereoLeft = NULL;
|
|
|
|
firfilt_rrrf firStereoRight = NULL;
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
// Stereo filters / shifters
|
|
|
|
double firStereoCutoff = 0.5 * ((double) 36000 / (double) AUDIO_FREQUENCY); // filter cutoff frequency
|
2014-12-27 15:04:43 -05:00
|
|
|
float ft = 0.05f; // filter transition
|
2015-01-03 17:07:39 -05:00
|
|
|
float As = 120.0f; // stop-band attenuation [dB]
|
2014-12-27 15:04:43 -05:00
|
|
|
float mu = 0.0f; // fractional timing offset
|
2015-01-03 17:07:39 -05:00
|
|
|
|
|
|
|
if (firStereoCutoff < 0) {
|
|
|
|
firStereoCutoff = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (firStereoCutoff > 0.5) {
|
|
|
|
firStereoCutoff = 0.5;
|
|
|
|
}
|
|
|
|
|
2014-12-27 15:04:43 -05:00
|
|
|
unsigned int h_len = estimate_req_filter_len(ft, As);
|
|
|
|
float h[h_len];
|
2015-01-03 17:07:39 -05:00
|
|
|
liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
|
2014-12-27 15:04:43 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
firStereoLeft = firfilt_rrrf_create(h, h_len);
|
|
|
|
firStereoRight = firfilt_rrrf_create(h, h_len);
|
2014-12-27 12:23:09 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
liquid_float_complex x, y;
|
2014-12-27 12:23:09 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
firhilbf firStereoR2C = firhilbf_create(5, 60.0f);
|
|
|
|
firhilbf firStereoC2R = firhilbf_create(5, 60.0f);
|
2015-01-01 18:08:54 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
nco_crcf stereoShifter = nco_crcf_create(LIQUID_NCO);
|
|
|
|
double stereoShiftFrequency = 0;
|
2015-01-01 18:08:54 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
// SSB Half-band filter
|
|
|
|
nco_crcf ssbShifterUp = nco_crcf_create(LIQUID_NCO);
|
|
|
|
nco_crcf_set_frequency(ssbShifterUp, (2.0 * M_PI) * 0.25);
|
2015-01-01 18:08:54 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
nco_crcf ssbShifterDown = nco_crcf_create(LIQUID_NCO);
|
|
|
|
nco_crcf_set_frequency(ssbShifterDown, (2.0 * M_PI) * 0.25);
|
2015-01-01 18:08:54 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
float ssbFt = 0.001f; // filter transition
|
|
|
|
float ssbAs = 120.0f; // stop-band attenuation [dB]
|
2015-01-01 18:08:54 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
h_len = estimate_req_filter_len(ssbFt, ssbAs);
|
|
|
|
float ssb_h[h_len];
|
|
|
|
liquid_firdes_kaiser(h_len, 0.25, ssbAs, 0.0, ssb_h);
|
2015-01-01 18:08:54 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
firfilt_crcf firSSB = firfilt_crcf_create(ssb_h, h_len);
|
2014-12-27 12:23:09 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
// Automatic IQ gain
|
|
|
|
iqAutoGain = agc_crcf_create();
|
|
|
|
agc_crcf_set_bandwidth(iqAutoGain, 0.9);
|
2014-12-21 16:08:32 -05:00
|
|
|
|
2015-01-22 21:32:32 -05:00
|
|
|
AudioThreadInput *ati_vis = new AudioThreadInput;
|
|
|
|
ati_vis->data.reserve(DEMOD_VIS_SIZE);
|
|
|
|
|
2014-12-16 21:30:03 -05:00
|
|
|
std::cout << "Demodulator thread started.." << std::endl;
|
2014-12-24 01:28:33 -05:00
|
|
|
|
2015-01-08 21:12:49 -05:00
|
|
|
terminated = false;
|
|
|
|
|
2014-12-16 21:30:03 -05:00
|
|
|
while (!terminated) {
|
2014-12-23 01:12:14 -05:00
|
|
|
DemodulatorThreadPostIQData *inp;
|
2015-01-03 17:07:39 -05:00
|
|
|
iqInputQueue->pop(inp);
|
2014-12-24 01:28:33 -05:00
|
|
|
std::lock_guard < std::mutex > lock(inp->m_mutex);
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2014-12-23 01:12:14 -05:00
|
|
|
int bufSize = inp->data.size();
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2014-12-16 21:30:03 -05:00
|
|
|
if (!bufSize) {
|
2014-12-24 01:28:33 -05:00
|
|
|
inp->decRefCount();
|
2014-12-16 21:30:03 -05:00
|
|
|
continue;
|
|
|
|
}
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
if (audioResampler == NULL) {
|
2015-01-03 17:07:39 -05:00
|
|
|
audioResampler = inp->audioResampler;
|
|
|
|
stereoResampler = inp->stereoResampler;
|
2015-01-04 13:20:31 -05:00
|
|
|
} else if (audioResampler != inp->audioResampler) {
|
2015-01-03 17:07:39 -05:00
|
|
|
msresamp_rrrf_destroy(audioResampler);
|
|
|
|
msresamp_rrrf_destroy(stereoResampler);
|
|
|
|
audioResampler = inp->audioResampler;
|
|
|
|
stereoResampler = inp->stereoResampler;
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2015-01-07 21:25:35 -05:00
|
|
|
if (demodAM) {
|
|
|
|
ampmodem_reset(demodAM);
|
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
freqdem_reset(demodFM);
|
2014-12-16 21:30:03 -05:00
|
|
|
}
|
2014-12-16 20:33:44 -05:00
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
if (agcData.size() != bufSize) {
|
|
|
|
if (agcData.capacity() < bufSize) {
|
|
|
|
agcData.reserve(bufSize);
|
|
|
|
agcAMData.reserve(bufSize);
|
2014-12-24 03:03:34 -05:00
|
|
|
}
|
2015-01-04 13:20:31 -05:00
|
|
|
agcData.resize(bufSize);
|
|
|
|
agcAMData.resize(bufSize);
|
2014-12-24 03:03:34 -05:00
|
|
|
}
|
2014-12-16 21:30:03 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
double audio_resample_ratio = inp->audioResampleRatio;
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
if (demodOutputData.size() != bufSize) {
|
|
|
|
if (demodOutputData.capacity() < bufSize) {
|
|
|
|
demodOutputData.reserve(bufSize);
|
2014-12-24 03:03:34 -05:00
|
|
|
}
|
2015-01-04 13:20:31 -05:00
|
|
|
demodOutputData.resize(bufSize);
|
2014-12-24 03:03:34 -05:00
|
|
|
}
|
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
int audio_out_size = ceil((double) (bufSize) * audio_resample_ratio) + 512;
|
2014-12-27 12:45:21 -05:00
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
agc_crcf_execute_block(iqAutoGain, &(inp->data[0]), bufSize, &agcData[0]);
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
float currentSignalLevel = 0;
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
currentSignalLevel = ((60.0 / fabs(agc_crcf_get_rssi(iqAutoGain))) / 15.0 - signalLevel);
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (agc_crcf_get_signal_level(iqAutoGain) > currentSignalLevel) {
|
|
|
|
currentSignalLevel = agc_crcf_get_signal_level(iqAutoGain);
|
2015-01-01 03:48:32 -05:00
|
|
|
}
|
|
|
|
|
2015-01-01 18:08:54 -05:00
|
|
|
if (demodulatorType == DEMOD_TYPE_FM) {
|
2015-01-04 13:20:31 -05:00
|
|
|
freqdem_demodulate_block(demodFM, &agcData[0], bufSize, &demodOutputData[0]);
|
2015-01-01 18:08:54 -05:00
|
|
|
} else {
|
|
|
|
float p;
|
2015-01-03 19:03:16 -05:00
|
|
|
switch (demodulatorType.load()) {
|
2015-01-01 18:08:54 -05:00
|
|
|
case DEMOD_TYPE_LSB:
|
2015-01-04 13:20:31 -05:00
|
|
|
for (int i = 0; i < bufSize; i++) { // Reject upper band
|
|
|
|
nco_crcf_mix_up(ssbShifterUp, inp->data[i], &x);
|
2015-01-03 17:07:39 -05:00
|
|
|
nco_crcf_step(ssbShifterUp);
|
|
|
|
firfilt_crcf_push(firSSB, x);
|
|
|
|
firfilt_crcf_execute(firSSB, &x);
|
2015-01-04 13:20:31 -05:00
|
|
|
nco_crcf_mix_down(ssbShifterDown, x, &(inp->data[i]));
|
2015-01-03 17:07:39 -05:00
|
|
|
nco_crcf_step(ssbShifterDown);
|
2015-01-01 18:08:54 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DEMOD_TYPE_USB:
|
2015-01-04 13:20:31 -05:00
|
|
|
for (int i = 0; i < bufSize; i++) { // Reject lower band
|
|
|
|
nco_crcf_mix_down(ssbShifterDown, inp->data[i], &x);
|
2015-01-03 17:07:39 -05:00
|
|
|
nco_crcf_step(ssbShifterDown);
|
|
|
|
firfilt_crcf_push(firSSB, x);
|
|
|
|
firfilt_crcf_execute(firSSB, &x);
|
2015-01-04 13:20:31 -05:00
|
|
|
nco_crcf_mix_up(ssbShifterUp, x, &(inp->data[i]));
|
2015-01-03 17:07:39 -05:00
|
|
|
nco_crcf_step(ssbShifterUp);
|
2015-01-01 18:08:54 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DEMOD_TYPE_AM:
|
2015-01-07 20:23:15 -05:00
|
|
|
case DEMOD_TYPE_DSB:
|
2015-01-01 18:08:54 -05:00
|
|
|
break;
|
2015-01-01 03:48:32 -05:00
|
|
|
}
|
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
amOutputCeil = 0;
|
2015-01-01 18:08:54 -05:00
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
for (int i = 0; i < bufSize; i++) {
|
|
|
|
ampmodem_demodulate(demodAM, inp->data[i], &demodOutputData[i]);
|
2015-01-03 17:07:39 -05:00
|
|
|
if (demodOutputData[i] > amOutputCeil) {
|
|
|
|
amOutputCeil = demodOutputData[i];
|
2015-01-01 03:48:32 -05:00
|
|
|
}
|
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
amOutputCeilMA = amOutputCeilMA + (amOutputCeil - amOutputCeilMA) * 0.05;
|
|
|
|
amOutputCeilMAA = amOutputCeilMAA + (amOutputCeilMA - amOutputCeilMAA) * 0.05;
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
float gain = 0.95 / amOutputCeilMAA;
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
for (int i = 0; i < bufSize; i++) {
|
2015-01-03 17:07:39 -05:00
|
|
|
demodOutputData[i] *= gain;
|
2015-01-01 03:48:32 -05:00
|
|
|
}
|
|
|
|
}
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (audio_out_size != resampledOutputData.size()) {
|
|
|
|
if (resampledOutputData.capacity() < audio_out_size) {
|
|
|
|
resampledOutputData.reserve(audio_out_size);
|
2014-12-27 12:45:21 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
resampledOutputData.resize(audio_out_size);
|
2014-12-27 12:45:21 -05:00
|
|
|
}
|
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
unsigned int numAudioWritten;
|
2015-01-04 13:20:31 -05:00
|
|
|
msresamp_rrrf_execute(audioResampler, &demodOutputData[0], bufSize, &resampledOutputData[0], &numAudioWritten);
|
2014-12-27 12:45:21 -05:00
|
|
|
|
2014-12-26 20:58:42 -05:00
|
|
|
if (stereo) {
|
2015-01-04 13:20:31 -05:00
|
|
|
if (demodStereoData.size() != bufSize) {
|
|
|
|
if (demodStereoData.capacity() < bufSize) {
|
|
|
|
demodStereoData.reserve(bufSize);
|
2014-12-27 12:45:21 -05:00
|
|
|
}
|
2015-01-04 13:20:31 -05:00
|
|
|
demodStereoData.resize(bufSize);
|
2014-12-27 12:45:21 -05:00
|
|
|
}
|
2014-12-26 20:58:42 -05:00
|
|
|
|
2015-01-11 17:08:16 -05:00
|
|
|
double freq = (2.0 * M_PI) * (((double) abs(38000)) / ((double) inp->sampleRate));
|
2014-12-26 20:58:42 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (stereoShiftFrequency != freq) {
|
|
|
|
nco_crcf_set_frequency(stereoShifter, freq);
|
|
|
|
stereoShiftFrequency = freq;
|
2014-12-27 12:23:09 -05:00
|
|
|
}
|
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
for (int i = 0; i < bufSize; i++) {
|
2015-01-03 17:07:39 -05:00
|
|
|
firhilbf_r2c_execute(firStereoR2C, demodOutputData[i], &x);
|
|
|
|
nco_crcf_mix_down(stereoShifter, x, &y);
|
|
|
|
nco_crcf_step(stereoShifter);
|
|
|
|
firhilbf_c2r_execute(firStereoC2R, y, &demodStereoData[i]);
|
2014-12-26 20:58:42 -05:00
|
|
|
}
|
2014-12-24 03:03:34 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (audio_out_size != resampledStereoData.size()) {
|
|
|
|
if (resampledStereoData.capacity() < audio_out_size) {
|
|
|
|
resampledStereoData.reserve(audio_out_size);
|
2014-12-27 12:45:21 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
resampledStereoData.resize(audio_out_size);
|
2014-12-24 03:03:34 -05:00
|
|
|
}
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2015-01-04 13:20:31 -05:00
|
|
|
msresamp_rrrf_execute(stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten);
|
2014-12-26 20:58:42 -05:00
|
|
|
}
|
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (currentSignalLevel > signalLevel) {
|
|
|
|
signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.5;
|
2014-12-31 19:45:01 -05:00
|
|
|
} else {
|
2015-01-03 17:07:39 -05:00
|
|
|
signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.05;
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
|
|
|
|
2014-12-27 15:04:43 -05:00
|
|
|
AudioThreadInput *ati = NULL;
|
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (audioOutputQueue != NULL) {
|
|
|
|
if (!squelchEnabled || (signalLevel >= squelchLevel)) {
|
2014-12-24 01:28:33 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
for (outputBuffersI = outputBuffers.begin(); outputBuffersI != outputBuffers.end(); outputBuffersI++) {
|
|
|
|
if ((*outputBuffersI)->getRefCount() <= 0) {
|
|
|
|
ati = (*outputBuffersI);
|
2014-12-24 01:28:33 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ati == NULL) {
|
|
|
|
ati = new AudioThreadInput;
|
2015-01-03 17:07:39 -05:00
|
|
|
outputBuffers.push_back(ati);
|
2014-12-24 01:28:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ati->setRefCount(1);
|
2014-12-26 20:58:42 -05:00
|
|
|
|
|
|
|
if (stereo) {
|
|
|
|
ati->channels = 2;
|
2015-01-03 17:07:39 -05:00
|
|
|
if (ati->data.capacity() < (numAudioWritten * 2)) {
|
|
|
|
ati->data.reserve(numAudioWritten * 2);
|
2014-12-27 12:45:21 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
ati->data.resize(numAudioWritten * 2);
|
|
|
|
for (int i = 0; i < numAudioWritten; i++) {
|
2014-12-27 15:04:43 -05:00
|
|
|
float l, r;
|
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
firfilt_rrrf_push(firStereoLeft, (resampledOutputData[i] - (resampledStereoData[i])));
|
|
|
|
firfilt_rrrf_execute(firStereoLeft, &l);
|
2014-12-27 15:04:43 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
firfilt_rrrf_push(firStereoRight, (resampledOutputData[i] + (resampledStereoData[i])));
|
|
|
|
firfilt_rrrf_execute(firStereoRight, &r);
|
2014-12-27 15:04:43 -05:00
|
|
|
|
|
|
|
ati->data[i * 2] = l;
|
|
|
|
ati->data[i * 2 + 1] = r;
|
2014-12-26 20:58:42 -05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ati->channels = 1;
|
2015-01-03 17:07:39 -05:00
|
|
|
ati->data.assign(resampledOutputData.begin(), resampledOutputData.begin() + numAudioWritten);
|
2014-12-26 20:58:42 -05:00
|
|
|
}
|
2014-12-24 01:28:33 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
audioOutputQueue->push(ati);
|
2014-12-21 16:08:32 -05:00
|
|
|
}
|
2014-12-16 21:30:03 -05:00
|
|
|
}
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (ati && audioVisOutputQueue != NULL && audioVisOutputQueue->empty()) {
|
2014-12-21 17:37:41 -05:00
|
|
|
|
2014-12-21 16:08:32 -05:00
|
|
|
int num_vis = DEMOD_VIS_SIZE;
|
2014-12-26 22:20:50 -05:00
|
|
|
if (stereo) {
|
2014-12-27 15:04:43 -05:00
|
|
|
ati_vis->channels = 2;
|
|
|
|
int stereoSize = ati->data.size();
|
2014-12-26 22:20:50 -05:00
|
|
|
if (stereoSize > DEMOD_VIS_SIZE) {
|
|
|
|
stereoSize = DEMOD_VIS_SIZE;
|
|
|
|
}
|
2015-01-22 21:32:32 -05:00
|
|
|
|
2014-12-26 22:20:50 -05:00
|
|
|
ati_vis->data.resize(stereoSize);
|
|
|
|
|
|
|
|
for (int i = 0; i < stereoSize / 2; i++) {
|
2015-01-01 03:48:32 -05:00
|
|
|
ati_vis->data[i] = ati->data[i * 2];
|
|
|
|
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
|
2014-12-21 16:08:32 -05:00
|
|
|
}
|
2014-12-18 21:39:32 -05:00
|
|
|
} else {
|
2014-12-27 15:04:43 -05:00
|
|
|
ati_vis->channels = 1;
|
2015-01-04 13:20:31 -05:00
|
|
|
if (numAudioWritten > bufSize) {
|
2014-12-26 22:20:50 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (num_vis > numAudioWritten) {
|
|
|
|
num_vis = numAudioWritten;
|
2014-12-26 22:20:50 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
ati_vis->data.assign(resampledOutputData.begin(), resampledOutputData.begin() + num_vis);
|
2014-12-26 22:20:50 -05:00
|
|
|
} else {
|
2015-01-04 13:20:31 -05:00
|
|
|
if (num_vis > bufSize) {
|
|
|
|
num_vis = bufSize;
|
2014-12-26 22:20:50 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
ati_vis->data.assign(demodOutputData.begin(), demodOutputData.begin() + num_vis);
|
2014-12-21 16:08:32 -05:00
|
|
|
}
|
2014-12-26 22:20:50 -05:00
|
|
|
|
|
|
|
// std::cout << "Signal: " << agc_crcf_get_signal_level(agc) << " -- " << agc_crcf_get_rssi(agc) << "dB " << std::endl;
|
2014-12-21 16:08:32 -05:00
|
|
|
}
|
2014-12-21 17:37:41 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
audioVisOutputQueue->push(ati_vis);
|
2014-12-21 16:08:32 -05:00
|
|
|
}
|
|
|
|
if (!threadQueueControl->empty()) {
|
2015-01-01 18:08:54 -05:00
|
|
|
int newDemodType = DEMOD_TYPE_NULL;
|
|
|
|
|
2014-12-21 16:08:32 -05:00
|
|
|
while (!threadQueueControl->empty()) {
|
|
|
|
DemodulatorThreadControlCommand command;
|
|
|
|
threadQueueControl->pop(command);
|
|
|
|
|
|
|
|
switch (command.cmd) {
|
2015-01-03 17:07:39 -05:00
|
|
|
case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_ON:
|
|
|
|
squelchEnabled = true;
|
2014-12-21 16:08:32 -05:00
|
|
|
break;
|
|
|
|
case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_OFF:
|
2015-01-03 17:07:39 -05:00
|
|
|
squelchEnabled = false;
|
2014-12-21 16:08:32 -05:00
|
|
|
break;
|
2015-01-01 18:08:54 -05:00
|
|
|
case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE:
|
|
|
|
newDemodType = command.demodType;
|
|
|
|
break;
|
2014-12-21 16:08:32 -05:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2014-12-18 21:39:32 -05:00
|
|
|
}
|
2015-01-01 18:08:54 -05:00
|
|
|
|
|
|
|
if (newDemodType != DEMOD_TYPE_NULL) {
|
|
|
|
switch (newDemodType) {
|
|
|
|
case DEMOD_TYPE_FM:
|
2015-01-07 21:25:35 -05:00
|
|
|
freqdem_reset(demodFM);
|
2015-01-01 18:08:54 -05:00
|
|
|
break;
|
|
|
|
case DEMOD_TYPE_LSB:
|
2015-01-03 17:07:39 -05:00
|
|
|
demodAM = demodAM_USB;
|
2015-01-07 21:25:35 -05:00
|
|
|
ampmodem_reset(demodAM);
|
2015-01-01 18:08:54 -05:00
|
|
|
break;
|
|
|
|
case DEMOD_TYPE_USB:
|
2015-01-03 17:07:39 -05:00
|
|
|
demodAM = demodAM_LSB;
|
2015-01-07 21:25:35 -05:00
|
|
|
ampmodem_reset(demodAM);
|
2015-01-01 18:08:54 -05:00
|
|
|
break;
|
2015-01-07 20:23:15 -05:00
|
|
|
case DEMOD_TYPE_DSB:
|
|
|
|
demodAM = demodAM_DSB;
|
2015-01-07 21:25:35 -05:00
|
|
|
ampmodem_reset(demodAM);
|
2015-01-07 20:23:15 -05:00
|
|
|
break;
|
2015-01-01 18:08:54 -05:00
|
|
|
case DEMOD_TYPE_AM:
|
2015-01-03 17:07:39 -05:00
|
|
|
demodAM = demodAM_DSB_CSP;
|
2015-01-07 21:25:35 -05:00
|
|
|
ampmodem_reset(demodAM);
|
2015-01-01 18:08:54 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
demodulatorType = newDemodType;
|
|
|
|
}
|
2014-12-16 21:30:03 -05:00
|
|
|
}
|
2014-12-21 16:08:32 -05:00
|
|
|
|
2014-12-24 01:28:33 -05:00
|
|
|
inp->decRefCount();
|
2014-12-16 21:30:03 -05:00
|
|
|
}
|
2014-12-16 18:27:32 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
if (audioResampler != NULL) {
|
|
|
|
msresamp_rrrf_destroy(audioResampler);
|
2014-12-16 21:30:03 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
if (stereoResampler != NULL) {
|
|
|
|
msresamp_rrrf_destroy(stereoResampler);
|
2014-12-26 21:55:13 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
if (firStereoLeft != NULL) {
|
|
|
|
firfilt_rrrf_destroy(firStereoLeft);
|
2014-12-27 15:04:43 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
if (firStereoRight != NULL) {
|
|
|
|
firfilt_rrrf_destroy(firStereoRight);
|
2014-12-27 15:04:43 -05:00
|
|
|
}
|
2014-12-16 20:33:44 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
agc_crcf_destroy(iqAutoGain);
|
|
|
|
firhilbf_destroy(firStereoR2C);
|
|
|
|
firhilbf_destroy(firStereoC2R);
|
|
|
|
nco_crcf_destroy(stereoShifter);
|
|
|
|
nco_crcf_destroy(ssbShifterUp);
|
|
|
|
nco_crcf_destroy(ssbShifterDown);
|
|
|
|
|
|
|
|
while (!outputBuffers.empty()) {
|
|
|
|
AudioThreadInput *audioDataDel = outputBuffers.front();
|
|
|
|
outputBuffers.pop_front();
|
2014-12-24 01:28:33 -05:00
|
|
|
delete audioDataDel;
|
|
|
|
}
|
|
|
|
|
2015-01-22 21:32:32 -05:00
|
|
|
delete ati_vis;
|
|
|
|
|
2014-12-16 21:30:03 -05:00
|
|
|
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED);
|
|
|
|
tCmd.context = this;
|
|
|
|
threadQueueNotify->push(tCmd);
|
2015-01-11 20:26:51 -05:00
|
|
|
std::cout << "Demodulator thread done." << std::endl;
|
2015-01-20 19:13:49 -05:00
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
return this;
|
|
|
|
#endif
|
2014-12-16 18:27:32 -05:00
|
|
|
}
|
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
void DemodulatorThread::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) {
|
|
|
|
audioVisOutputQueue = tQueue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DemodulatorThread::setAudioOutputQueue(AudioThreadInputQueue *tQueue) {
|
|
|
|
audioOutputQueue = tQueue;
|
|
|
|
}
|
|
|
|
|
2014-12-16 18:27:32 -05:00
|
|
|
void DemodulatorThread::terminate() {
|
2014-12-16 21:30:03 -05:00
|
|
|
terminated = true;
|
2014-12-23 01:12:14 -05:00
|
|
|
DemodulatorThreadPostIQData *inp = new DemodulatorThreadPostIQData; // push dummy to nudge queue
|
2015-01-03 17:07:39 -05:00
|
|
|
iqInputQueue->push(inp);
|
2014-12-16 18:27:32 -05:00
|
|
|
}
|
2014-12-26 20:58:42 -05:00
|
|
|
|
|
|
|
void DemodulatorThread::setStereo(bool state) {
|
|
|
|
stereo = state;
|
2014-12-26 22:20:50 -05:00
|
|
|
std::cout << "Stereo " << (state ? "Enabled" : "Disabled") << std::endl;
|
2014-12-26 20:58:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DemodulatorThread::isStereo() {
|
|
|
|
return stereo;
|
|
|
|
}
|
2014-12-31 19:45:01 -05:00
|
|
|
|
|
|
|
float DemodulatorThread::getSignalLevel() {
|
2015-01-03 17:07:39 -05:00
|
|
|
return signalLevel;
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void DemodulatorThread::setSquelchLevel(float signal_level_in) {
|
2015-01-03 17:07:39 -05:00
|
|
|
if (!squelchEnabled) {
|
|
|
|
squelchEnabled = true;
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
squelchLevel = signal_level_in;
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
float DemodulatorThread::getSquelchLevel() {
|
2015-01-03 17:07:39 -05:00
|
|
|
return squelchLevel;
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2015-01-01 18:08:54 -05:00
|
|
|
void DemodulatorThread::setDemodulatorType(int demod_type_in) {
|
2015-01-01 03:48:32 -05:00
|
|
|
demodulatorType = demod_type_in;
|
|
|
|
}
|
|
|
|
|
2015-01-01 18:08:54 -05:00
|
|
|
int DemodulatorThread::getDemodulatorType() {
|
2015-01-01 03:48:32 -05:00
|
|
|
return demodulatorType;
|
|
|
|
}
|
2015-01-01 18:08:54 -05:00
|
|
|
|