2014-11-16 16:51:45 -05:00
|
|
|
#include "DemodulatorThread.h"
|
|
|
|
#include "CubicSDRDefs.h"
|
|
|
|
#include <vector>
|
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
DemodulatorThread::DemodulatorThread(DemodulatorThreadInputQueue* pQueue, DemodulatorThreadParameters *params_in) :
|
2014-11-22 22:33:32 -05:00
|
|
|
inputQueue(pQueue), visOutQueue(NULL) {
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-17 22:58:56 -05:00
|
|
|
DemodulatorThreadParameters defaultParams;
|
|
|
|
if (!params_in) {
|
|
|
|
params = defaultParams;
|
|
|
|
} else {
|
|
|
|
params = *params_in;
|
|
|
|
}
|
|
|
|
|
|
|
|
resample_ratio = (float) (params.inputResampleRate) / (float) params.inputRate;
|
|
|
|
second_resampler_ratio = (float) (params.demodResampleRate) / (float) params.inputResampleRate;
|
|
|
|
audio_resample_ratio = (float) (params.audioSampleRate) / (float) params.demodResampleRate;
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-17 22:58:56 -05:00
|
|
|
float fc = 0.5f * ((float) params.inputResampleRate / (float) params.inputRate) * 0.75; // filter cutoff frequency
|
2014-11-16 16:51:45 -05:00
|
|
|
float ft = 0.05f; // filter transition
|
|
|
|
float As = 60.0f; // stop-band attenuation [dB]
|
|
|
|
float mu = 0.0f; // fractional timing offset
|
|
|
|
|
|
|
|
// estimate required filter length and generate filter
|
|
|
|
unsigned int h_len = estimate_req_filter_len(ft, As);
|
|
|
|
float h[h_len];
|
|
|
|
liquid_firdes_kaiser(h_len, fc, As, mu, h);
|
|
|
|
|
|
|
|
fir_filter = firfilt_crcf_create(h, h_len);
|
|
|
|
|
|
|
|
h_len = estimate_req_filter_len(ft, As);
|
2014-11-22 22:17:33 -05:00
|
|
|
liquid_firdes_kaiser(h_len, (float) params.filterFrequency / (float) params.demodResampleRate, As, mu, h);
|
2014-11-16 16:51:45 -05:00
|
|
|
|
|
|
|
fir_audio_filter = firfilt_crcf_create(h, h_len);
|
|
|
|
|
|
|
|
// create multi-stage arbitrary resampler object
|
|
|
|
resampler = msresamp_crcf_create(resample_ratio, As);
|
|
|
|
msresamp_crcf_print(resampler);
|
|
|
|
|
2014-11-17 22:58:56 -05:00
|
|
|
second_resampler = msresamp_crcf_create(second_resampler_ratio, As);
|
|
|
|
msresamp_crcf_print(second_resampler);
|
2014-11-16 16:51:45 -05:00
|
|
|
|
|
|
|
audio_resampler = msresamp_crcf_create(audio_resample_ratio, As);
|
|
|
|
msresamp_crcf_print(audio_resampler);
|
|
|
|
|
|
|
|
float kf = 0.75; // modulation factor
|
|
|
|
|
|
|
|
fdem = freqdem_create(kf);
|
|
|
|
freqdem_print(fdem);
|
|
|
|
}
|
|
|
|
|
|
|
|
DemodulatorThread::~DemodulatorThread() {
|
2014-11-22 22:17:33 -05:00
|
|
|
std::cout << std::endl << "Demodulator Thread Done." << std::endl << std::endl;
|
2014-11-16 16:51:45 -05:00
|
|
|
}
|
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
void DemodulatorThread::threadMain() {
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
DemodulatorThreadIQData inp;
|
2014-11-22 22:33:32 -05:00
|
|
|
inputQueue->pop(inp);
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
std::vector<signed char> *data = &inp.data;
|
|
|
|
if (data->size()) {
|
|
|
|
liquid_float_complex filtered_input[BUF_SIZE / 2];
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
for (int i = 0; i < BUF_SIZE / 2; i++) {
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
liquid_float_complex x;
|
|
|
|
liquid_float_complex y;
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
x.real = (float) (*data)[i * 2] / 127.0f;
|
|
|
|
x.imag = (float) (*data)[i * 2 + 1] / 127.0f;
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
firfilt_crcf_push(fir_filter, x); // push input sample
|
|
|
|
firfilt_crcf_execute(fir_filter, &y); // compute output
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
filtered_input[i] = y;
|
|
|
|
}
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
int out_size = ceil((float) (BUF_SIZE / 2) * resample_ratio);
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
liquid_float_complex resampled_output[out_size];
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
unsigned int num_written; // number of values written to buffer
|
|
|
|
msresamp_crcf_execute(resampler, filtered_input, (BUF_SIZE / 2), resampled_output, &num_written);
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
float waveform_ceil = 0, waveform_floor = 0;
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
float pcm = 0;
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
for (int i = 0; i < num_written; i++) {
|
|
|
|
freqdem_demodulate(fdem, resampled_output[i], &pcm);
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
resampled_output[i].real = (float) pcm;
|
|
|
|
resampled_output[i].imag = 0;
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
if (waveform_ceil < resampled_output[i].real) {
|
|
|
|
waveform_ceil = resampled_output[i].real;
|
|
|
|
}
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
if (waveform_floor > resampled_output[i].real) {
|
|
|
|
waveform_floor = resampled_output[i].real;
|
|
|
|
}
|
|
|
|
}
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
int wbfm_out_size = ceil((float) (num_written) * second_resampler_ratio);
|
|
|
|
liquid_float_complex resampled_wbfm_output[wbfm_out_size];
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
unsigned int num_wbfm_written;
|
|
|
|
msresamp_crcf_execute(second_resampler, resampled_output, num_written, resampled_wbfm_output, &num_wbfm_written);
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
for (int i = 0; i < num_wbfm_written; i++) {
|
|
|
|
firfilt_crcf_push(fir_audio_filter, resampled_wbfm_output[i]);
|
|
|
|
firfilt_crcf_execute(fir_audio_filter, &resampled_wbfm_output[i]);
|
|
|
|
}
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
int audio_out_size = ceil((float) (num_wbfm_written) * audio_resample_ratio);
|
|
|
|
liquid_float_complex resampled_audio_output[audio_out_size];
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
unsigned int num_audio_written;
|
|
|
|
msresamp_crcf_execute(audio_resampler, resampled_wbfm_output, num_wbfm_written, resampled_audio_output, &num_audio_written);
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
std::vector<float> newBuffer;
|
|
|
|
newBuffer.resize(num_audio_written * 2);
|
|
|
|
for (int i = 0; i < num_audio_written; i++) {
|
|
|
|
liquid_float_complex y = resampled_audio_output[i];
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
newBuffer[i * 2] = y.real;
|
|
|
|
newBuffer[i * 2 + 1] = y.real;
|
|
|
|
}
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
AudioThreadInput ati;
|
|
|
|
ati.data = newBuffer;
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
if (params.audioInputQueue != NULL) {
|
|
|
|
params.audioInputQueue->push(ati);
|
|
|
|
}
|
2014-11-16 16:51:45 -05:00
|
|
|
|
2014-11-22 22:17:33 -05:00
|
|
|
if (visOutQueue != NULL) {
|
|
|
|
visOutQueue->push(ati);
|
|
|
|
}
|
2014-11-16 16:51:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|