CubicSDR/src/demod/DemodulatorPreThread.cpp

271 lines
9.2 KiB
C++
Raw Normal View History

2014-11-16 16:51:45 -05:00
#include "CubicSDRDefs.h"
#include <vector>
#ifdef __APPLE__
2014-12-11 19:07:21 -05:00
#include <pthread.h>
#endif
#include "DemodulatorPreThread.h"
2014-12-16 21:30:03 -05:00
DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* pQueueIn, DemodulatorThreadPostInputQueue* pQueueOut,
DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) :
inputQueue(pQueueIn), postInputQueue(pQueueOut), terminated(false), initialized(false), audio_resampler(NULL), resample_ratio(1), audio_resample_ratio(
2014-12-24 01:28:33 -05:00
1), resampler(NULL), commandQueue(NULL), fir_filter(NULL), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify), threadQueueControl(
threadQueueControl) {
2014-11-30 17:59:24 -05:00
float kf = 0.5; // modulation factor
fdem = freqdem_create(kf);
// freqdem_print(fdem);
nco_shift = nco_crcf_create(LIQUID_VCO);
shift_freq = 0;
2014-11-30 23:33:55 -05:00
workerQueue = new DemodulatorThreadWorkerCommandQueue;
workerResults = new DemodulatorThreadWorkerResultQueue;
workerThread = new DemodulatorWorkerThread(workerQueue, workerResults);
2014-11-30 23:33:55 -05:00
t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread);
}
void DemodulatorPreThread::initialize() {
initialized = false;
resample_ratio = (float) (params.bandwidth) / (float) params.inputRate;
audio_resample_ratio = (float) (params.audioSampleRate) / (float) params.bandwidth;
float fc = 0.5 * ((double) params.bandwidth / (double) params.inputRate); // filter cutoff frequency
if (fc <= 0) {
fc = 0;
}
if (fc >= 0.5) {
fc = 0.5;
}
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);
if (fir_filter) {
firfilt_crcf_recreate(fir_filter, h, h_len);
} else {
fir_filter = firfilt_crcf_create(h, h_len);
}
2014-11-16 16:51:45 -05:00
// create multi-stage arbitrary resampler object
if (resampler) {
msresamp_crcf_destroy(resampler);
}
2014-11-16 16:51:45 -05:00
resampler = msresamp_crcf_create(resample_ratio, As);
// msresamp_crcf_print(resampler);
2014-11-16 16:51:45 -05:00
if (audio_resampler) {
msresamp_rrrf_destroy(audio_resampler);
}
audio_resampler = msresamp_rrrf_create(audio_resample_ratio, As);
// msresamp_crcf_print(audio_resampler);
2014-11-16 16:51:45 -05:00
initialized = true;
// std::cout << "inputResampleRate " << params.bandwidth << std::endl;
last_params = params;
2014-11-16 16:51:45 -05:00
}
DemodulatorPreThread::~DemodulatorPreThread() {
2014-11-30 23:33:55 -05:00
delete workerThread;
delete workerQueue;
delete workerResults;
2014-11-16 16:51:45 -05:00
}
#ifdef __APPLE__
void *DemodulatorPreThread::threadMain() {
#else
void DemodulatorPreThread::threadMain() {
#endif
#ifdef __APPLE__
pthread_t tID = pthread_self(); // ID of this thread
int priority = sched_get_priority_max( SCHED_FIFO )-1;
2014-12-24 01:28:33 -05:00
sched_param prio = {priority}; // scheduling priority of thread
pthread_setschedparam(tID, SCHED_FIFO, &prio);
#endif
if (!initialized) {
initialize();
}
std::cout << "Demodulator preprocessor thread started.." << std::endl;
2014-12-24 01:28:33 -05:00
std::deque<DemodulatorThreadPostIQData *> buffers;
std::deque<DemodulatorThreadPostIQData *>::iterator buffers_i;
while (!terminated) {
2014-12-22 23:27:52 -05:00
DemodulatorThreadIQData *inp;
2014-11-22 22:33:32 -05:00
inputQueue->pop(inp);
2014-11-16 16:51:45 -05:00
2014-11-30 23:33:55 -05:00
bool bandwidthChanged = false;
DemodulatorThreadParameters bandwidthParams = params;
if (!commandQueue->empty()) {
bool paramsChanged = false;
while (!commandQueue->empty()) {
DemodulatorThreadCommand command;
commandQueue->pop(command);
switch (command.cmd) {
2014-11-30 23:33:55 -05:00
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH:
if (command.int_value < 3000) {
command.int_value = 3000;
}
if (command.int_value > SRATE) {
command.int_value = SRATE;
}
2014-11-30 23:33:55 -05:00
bandwidthParams.bandwidth = command.int_value;
bandwidthChanged = true;
break;
2014-11-30 23:33:55 -05:00
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY:
params.frequency = command.int_value;
break;
}
}
2014-11-30 23:33:55 -05:00
if (bandwidthChanged) {
2014-12-01 01:14:32 -05:00
DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS);
command.audioSampleRate = bandwidthParams.audioSampleRate;
command.bandwidth = bandwidthParams.bandwidth;
command.frequency = bandwidthParams.frequency;
command.inputRate = bandwidthParams.inputRate;
2014-11-30 23:33:55 -05:00
workerQueue->push(command);
}
}
if (!initialized) {
continue;
}
// Requested frequency is not center, shift it into the center!
2014-12-22 23:27:52 -05:00
if (inp->frequency != params.frequency) {
if ((params.frequency - inp->frequency) != shift_freq) {
shift_freq = params.frequency - inp->frequency;
2014-11-30 17:16:35 -05:00
if (abs(shift_freq) <= (int) ((float) (SRATE / 2) * 1.5)) {
nco_crcf_set_frequency(nco_shift, (2.0 * M_PI) * (((float) abs(shift_freq)) / ((float) SRATE)));
}
}
}
2014-11-30 17:16:35 -05:00
if (abs(shift_freq) > (int) ((float) (SRATE / 2) * 1.5)) {
continue;
}
2014-12-24 01:28:33 -05:00
// std::lock_guard < std::mutex > lock(inp->m_mutex);
2014-12-22 23:27:52 -05:00
std::vector<signed char> *data = &inp->data;
if (data->size()) {
2014-12-16 21:30:03 -05:00
int bufSize = data->size() / 2;
liquid_float_complex in_buf_data[bufSize];
liquid_float_complex out_buf_data[bufSize];
liquid_float_complex *in_buf = in_buf_data;
liquid_float_complex *out_buf = out_buf_data;
liquid_float_complex *temp_buf = NULL;
for (int i = 0; i < bufSize; i++) {
in_buf[i].real = (float) (*data)[i * 2] / 127.0f;
in_buf[i].imag = (float) (*data)[i * 2 + 1] / 127.0f;
}
2014-11-16 16:51:45 -05:00
if (shift_freq != 0) {
if (shift_freq < 0) {
nco_crcf_mix_block_up(nco_shift, in_buf, out_buf, bufSize);
} else {
nco_crcf_mix_block_down(nco_shift, in_buf, out_buf, bufSize);
}
temp_buf = in_buf;
in_buf = out_buf;
out_buf = temp_buf;
}
2014-11-16 16:51:45 -05:00
2014-12-24 01:28:33 -05:00
DemodulatorThreadPostIQData *resamp = NULL;
for (buffers_i = buffers.begin(); buffers_i != buffers.end(); buffers_i++) {
if ((*buffers_i)->getRefCount() <= 0) {
resamp = (*buffers_i);
break;
}
}
if (resamp == NULL) {
resamp = new DemodulatorThreadPostIQData;
buffers.push_back(resamp);
}
resamp->setRefCount(1);
resamp->data.assign(in_buf, in_buf + bufSize);
// firfilt_crcf_execute_block(fir_filter, in_buf, bufSize, &((*resamp.data)[0]));
2014-11-16 16:51:45 -05:00
2014-12-23 01:12:14 -05:00
resamp->audio_resample_ratio = audio_resample_ratio;
resamp->audio_resampler = audio_resampler;
resamp->resample_ratio = resample_ratio;
resamp->resampler = resampler;
2014-11-16 16:51:45 -05:00
postInputQueue->push(resamp);
2014-12-24 01:28:33 -05:00
inp->decRefCount();
} else {
2014-12-22 23:27:52 -05:00
inp->decRefCount();
2014-11-16 16:51:45 -05:00
}
if (!workerResults->empty()) {
while (!workerResults->empty()) {
DemodulatorWorkerThreadResult result;
workerResults->pop(result);
switch (result.cmd) {
case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS:
firfilt_crcf_destroy(fir_filter);
// msresamp_crcf_destroy(resampler);
// msresamp_crcf_destroy(audio_resampler);
fir_filter = result.fir_filter;
resampler = result.resampler;
audio_resampler = result.audio_resampler;
resample_ratio = result.resample_ratio;
audio_resample_ratio = result.audio_resample_ratio;
params.audioSampleRate = result.audioSampleRate;
params.bandwidth = result.bandwidth;
params.inputRate = result.inputRate;
break;
}
}
}
2014-11-16 16:51:45 -05:00
}
2014-12-24 01:28:33 -05:00
while (!buffers.empty()) {
DemodulatorThreadPostIQData *iqDataDel = buffers.front();
buffers.pop_front();
std::lock_guard < std::mutex > lock(iqDataDel->m_mutex);
delete iqDataDel;
}
std::cout << "Demodulator preprocessor thread done." << std::endl;
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED);
2014-12-11 19:07:21 -05:00
tCmd.context = this;
threadQueueNotify->push(tCmd);
2014-11-16 16:51:45 -05:00
}
void DemodulatorPreThread::terminate() {
terminated = true;
2014-12-22 23:27:52 -05:00
DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue
inputQueue->push(inp);
2014-11-30 23:33:55 -05:00
workerThread->terminate();
}