From c7a167a1d04dece52c67316a063d91d9ff4493b5 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 16 Dec 2014 18:27:02 -0500 Subject: [PATCH 1/4] Experimental demodulator preprocessor thread Demodulator becoming a CPU hotspot, trying to break up the workload between threads.. --- CMakeLists.txt | 2 + src/demod/DemodDefs.h | 41 ++++ src/demod/DemodulatorInstance.cpp | 144 ++++++++----- src/demod/DemodulatorInstance.h | 6 + src/demod/DemodulatorMgr.cpp | 193 ++++++++---------- ...torThread.cpp => DemodulatorPreThread.cpp} | 90 +++----- ...dulatorThread.h => DemodulatorPreThread.h} | 47 +---- 7 files changed, 267 insertions(+), 256 deletions(-) rename src/demod/{DemodulatorThread.cpp => DemodulatorPreThread.cpp} (72%) rename src/demod/{DemodulatorThread.h => DemodulatorPreThread.h} (55%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e86417a..3db72f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ SET (cubicsdr_sources src/AppFrame.cpp src/sdr/SDRThread.cpp src/sdr/SDRPostThread.cpp + src/demod/DemodulatorPreThread.cpp src/demod/DemodulatorThread.cpp src/demod/DemodulatorWorkerThread.cpp src/demod/DemodulatorInstance.cpp @@ -151,6 +152,7 @@ SET (cubicsdr_headers src/AppFrame.h src/sdr/SDRThread.h src/sdr/SDRPostThread.h + src/demod/DemodulatorPreThread.h src/demod/DemodulatorThread.h src/demod/DemodulatorWorkerThread.h src/demod/DemodulatorInstance.h diff --git a/src/demod/DemodDefs.h b/src/demod/DemodDefs.h index fb383a0..8f3c04f 100644 --- a/src/demod/DemodDefs.h +++ b/src/demod/DemodDefs.h @@ -1,6 +1,8 @@ #pragma once #include "ThreadQueue.h" +#include "CubicSDRDefs.h" +#include "liquid/liquid.h" enum DemodulatorType { DEMOD_TYPE_NULL, @@ -17,6 +19,7 @@ public: DEMOD_THREAD_CMD_NULL, DEMOD_THREAD_CMD_SET_BANDWIDTH, DEMOD_THREAD_CMD_SET_FREQUENCY, + DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED, DEMOD_THREAD_CMD_DEMOD_TERMINATED, DEMOD_THREAD_CMD_AUDIO_TERMINATED }; @@ -58,6 +61,22 @@ public: } }; +class DemodulatorThreadPostIQData { +public: + std::vector data; + float audio_resample_ratio; + msresamp_crcf audio_resampler; + + DemodulatorThreadPostIQData(): audio_resample_ratio(0), audio_resampler(NULL) { + + } + + ~DemodulatorThreadPostIQData() { + + } +}; + + class DemodulatorThreadAudioData { public: unsigned int frequency; @@ -84,4 +103,26 @@ public: }; typedef ThreadQueue DemodulatorThreadInputQueue; +typedef ThreadQueue DemodulatorThreadPostInputQueue; typedef ThreadQueue DemodulatorThreadCommandQueue; + + +class DemodulatorThreadParameters { +public: + unsigned int frequency; + unsigned int inputRate; + unsigned int bandwidth; // set equal to disable second stage re-sampling? + unsigned int audioSampleRate; + + DemodulatorType demodType; + + DemodulatorThreadParameters() : + frequency(0), inputRate(SRATE), bandwidth(200000), audioSampleRate( + AUDIO_FREQUENCY), demodType(DEMOD_TYPE_FM) { + + } + + ~DemodulatorThreadParameters() { + + } +}; diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 0daf081..c9a91c9 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -1,87 +1,137 @@ #include "DemodulatorInstance.h" DemodulatorInstance::DemodulatorInstance() : - t_Demod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), terminated(false), audioTerminated(false), demodTerminated( - false) { + t_Demod(NULL), t_PreDemod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), terminated(false), audioTerminated(false), demodTerminated( + false), preDemodTerminated(false) { - label = new std::string("Unnamed"); - threadQueueDemod = new DemodulatorThreadInputQueue; - threadQueueCommand = new DemodulatorThreadCommandQueue; - threadQueueNotify = new DemodulatorThreadCommandQueue; - demodulatorThread = new DemodulatorThread(threadQueueDemod, threadQueueNotify); - demodulatorThread->setCommandQueue(threadQueueCommand); - audioInputQueue = new AudioThreadInputQueue; - audioThread = new AudioThread(audioInputQueue, threadQueueNotify); - demodulatorThread->setAudioInputQueue(audioInputQueue); + label = new std::string("Unnamed"); + threadQueueDemod = new DemodulatorThreadInputQueue; + threadQueuePostDemod = new DemodulatorThreadPostInputQueue; + threadQueueCommand = new DemodulatorThreadCommandQueue; + threadQueueNotify = new DemodulatorThreadCommandQueue; + + demodulatorPreThread = new DemodulatorPreThread(threadQueueDemod, threadQueuePostDemod, threadQueueNotify); + demodulatorPreThread->setCommandQueue(threadQueueCommand); + demodulatorThread = new DemodulatorThread(threadQueuePostDemod, threadQueueNotify); + + audioInputQueue = new AudioThreadInputQueue; + audioThread = new AudioThread(audioInputQueue, threadQueueNotify); + + demodulatorThread->setAudioInputQueue(audioInputQueue); } DemodulatorInstance::~DemodulatorInstance() { - delete audioThread; - delete demodulatorThread; + delete audioThread; + delete demodulatorThread; - delete audioInputQueue; - delete threadQueueDemod; + delete audioInputQueue; + delete threadQueueDemod; } void DemodulatorInstance::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) { - demodulatorThread->setVisualOutputQueue(tQueue); + demodulatorThread->setVisualOutputQueue(tQueue); } void DemodulatorInstance::run() { - t_Audio = new std::thread(&AudioThread::threadMain, audioThread); + t_Audio = new std::thread(&AudioThread::threadMain, audioThread); #ifdef __APPLE__ // Already using pthreads, might as well do some custom init.. - pthread_attr_t attr; - size_t size; + pthread_attr_t attr; + size_t size; - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, 2048000); - pthread_attr_getstacksize(&attr, &size); - pthread_create(&t_Demod, &attr, &DemodulatorThread::pthread_helper, demodulatorThread); - pthread_attr_destroy(&attr); + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 2048000); + pthread_attr_getstacksize(&attr, &size); + pthread_create(&t_PreDemod, &attr, &DemodulatorPreThread::pthread_helper, demodulatorPreThread); + pthread_attr_destroy(&attr); - std::cout << "Initialized demodulator stack size of " << size << std::endl; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 2048000); + pthread_attr_getstacksize(&attr, &size); + pthread_create(&t_Demod, &attr, &DemodulatorThread::pthread_helper, demodulatorThread); + pthread_attr_destroy(&attr); + + std::cout << "Initialized demodulator stack size of " << size << std::endl; #else - t_Demod = new std::thread(&DemodulatorThread::threadMain, demodulatorThread); + t_PreDemod = new std::thread(&DemodulatorPreThread::threadMain, demodulatorPreThread); + t_Demod = new std::thread(&DemodulatorThread::threadMain, demodulatorThread); #endif } void DemodulatorInstance::updateLabel(int freq) { - std::stringstream newLabel; - newLabel.precision(3); - newLabel << std::fixed << ((float) freq / 1000000.0); - setLabel(newLabel.str()); + std::stringstream newLabel; + newLabel.precision(3); + newLabel << std::fixed << ((float) freq / 1000000.0); + setLabel(newLabel.str()); } DemodulatorThreadCommandQueue *DemodulatorInstance::getCommandQueue() { - return threadQueueCommand; + return threadQueueCommand; } DemodulatorThreadParameters &DemodulatorInstance::getParams() { - return demodulatorThread->getParams(); + return demodulatorPreThread->getParams(); } void DemodulatorInstance::terminate() { - std::cout << "Terminating demodulator thread.." << std::endl; - demodulatorThread->terminate(); -//#ifdef __APPLE__ -// pthread_join(t_Demod,NULL); -//#else -//#endif - std::cout << "Terminating demodulator audio thread.." << std::endl; - audioThread->terminate(); + std::cout << "Terminating demodulator preprocessor thread.." << std::endl; + demodulatorPreThread->terminate(); + std::cout << "Terminating demodulator thread.." << std::endl; + demodulatorThread->terminate(); + std::cout << "Terminating demodulator audio thread.." << std::endl; + audioThread->terminate(); } std::string DemodulatorInstance::getLabel() { - return *(label.load()); + return *(label.load()); } void DemodulatorInstance::setLabel(std::string labelStr) { - std::string *newLabel = new std::string; - newLabel->append(labelStr); - std::string *oldLabel; - oldLabel = label; - label = newLabel; - delete oldLabel; + std::string *newLabel = new std::string; + newLabel->append(labelStr); + std::string *oldLabel; + oldLabel = label; + label = newLabel; + delete oldLabel; } + +bool DemodulatorInstance::isTerminated() { + while (!threadQueueNotify->empty()) { + DemodulatorThreadCommand cmd; + threadQueueNotify->pop(cmd); + + switch (cmd.cmd) { + case DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED: + audioThread = NULL; + t_Audio->join(); + audioTerminated = true; + break; + case DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED: + demodulatorThread = NULL; +#ifdef __APPLE__ + pthread_join(t_Demod, NULL); +#else + t_Demod->join(); +#endif + demodTerminated = true; + break; + case DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED: + demodulatorPreThread = NULL; +#ifdef __APPLE__ + pthread_join(t_PreDemod, NULL); +#else + t_PreDemod->join(); +#endif + preDemodTerminated = true; + break; + default: + break; + } + } + + terminated = audioTerminated && demodTerminated && preDemodTerminated; + + return terminated; +} + diff --git a/src/demod/DemodulatorInstance.h b/src/demod/DemodulatorInstance.h index b636937..7df546d 100644 --- a/src/demod/DemodulatorInstance.h +++ b/src/demod/DemodulatorInstance.h @@ -5,17 +5,22 @@ #include #include "DemodulatorThread.h" +#include "DemodulatorPreThread.h" class DemodulatorInstance { public: DemodulatorThreadInputQueue* threadQueueDemod; + DemodulatorThreadPostInputQueue* threadQueuePostDemod; DemodulatorThreadCommandQueue* threadQueueCommand; DemodulatorThreadCommandQueue* threadQueueNotify; + DemodulatorPreThread *demodulatorPreThread; DemodulatorThread *demodulatorThread; #ifdef __APPLE__ + pthread_t t_PreDemod; pthread_t t_Demod; #else + std::thread *t_PreDemod; std::thread *t_Demod; #endif @@ -44,6 +49,7 @@ private: bool terminated; bool demodTerminated; bool audioTerminated; + bool preDemodTerminated; }; diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp index 7eafd6a..adc9e5c 100644 --- a/src/demod/DemodulatorMgr.cpp +++ b/src/demod/DemodulatorMgr.cpp @@ -5,169 +5,138 @@ #include #include - DemodulatorMgr::DemodulatorMgr() : - activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL) { + activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL) { } DemodulatorMgr::~DemodulatorMgr() { - terminateAll(); + terminateAll(); } DemodulatorInstance *DemodulatorMgr::newThread() { - DemodulatorInstance *newDemod = new DemodulatorInstance; + DemodulatorInstance *newDemod = new DemodulatorInstance; - demods.push_back(newDemod); + demods.push_back(newDemod); - std::stringstream label; - label << demods.size(); - newDemod->setLabel(label.str()); + std::stringstream label; + label << demods.size(); + newDemod->setLabel(label.str()); - return newDemod; + return newDemod; } void DemodulatorMgr::terminateAll() { - while (demods.size()) { - DemodulatorInstance *d = demods.back(); - deleteThread(d); - } + while (demods.size()) { + DemodulatorInstance *d = demods.back(); + deleteThread(d); + } } std::vector &DemodulatorMgr::getDemodulators() { - return demods; + return demods; } void DemodulatorMgr::deleteThread(DemodulatorInstance *demod) { - std::vector::iterator i; + std::vector::iterator i; - i = std::find(demods.begin(), demods.end(), demod); + i = std::find(demods.begin(), demods.end(), demod); - if (activeDemodulator == demod) { - activeDemodulator = NULL; - } - if (lastActiveDemodulator == demod) { - lastActiveDemodulator = NULL; - } - if (activeVisualDemodulator == demod) { - activeVisualDemodulator = NULL; - } + if (activeDemodulator == demod) { + activeDemodulator = NULL; + } + if (lastActiveDemodulator == demod) { + lastActiveDemodulator = NULL; + } + if (activeVisualDemodulator == demod) { + activeVisualDemodulator = NULL; + } - if (i != demods.end()) { - demods.erase(i); - demod->terminate(); - } + if (i != demods.end()) { + demods.erase(i); + demod->terminate(); + } - demods_deleted.push_back(demod); + demods_deleted.push_back(demod); - garbageCollect(); + garbageCollect(); } std::vector *DemodulatorMgr::getDemodulatorsAt(int freq, int bandwidth) { - std::vector *foundDemods = new std::vector(); + std::vector *foundDemods = new std::vector(); - for (int i = 0, iMax = demods.size(); i < iMax; i++) { - DemodulatorInstance *testDemod = demods[i]; + for (int i = 0, iMax = demods.size(); i < iMax; i++) { + DemodulatorInstance *testDemod = demods[i]; - int freqTest = testDemod->getParams().frequency; - int bandwidthTest = testDemod->getParams().bandwidth; - int halfBandwidthTest = bandwidthTest / 2; + int freqTest = testDemod->getParams().frequency; + int bandwidthTest = testDemod->getParams().bandwidth; + int halfBandwidthTest = bandwidthTest / 2; - int halfBuffer = bandwidth / 2; + int halfBuffer = bandwidth / 2; - if ((freq <= (freqTest + halfBandwidthTest + halfBuffer)) && (freq >= (freqTest - halfBandwidthTest - halfBuffer))) { - foundDemods->push_back(testDemod); - } - } + if ((freq <= (freqTest + halfBandwidthTest + halfBuffer)) && (freq >= (freqTest - halfBandwidthTest - halfBuffer))) { + foundDemods->push_back(testDemod); + } + } - return foundDemods; + return foundDemods; } void DemodulatorMgr::setActiveDemodulator(DemodulatorInstance *demod, bool temporary) { - if (!temporary) { - if (activeDemodulator != NULL) { - lastActiveDemodulator = activeDemodulator; - } else { - lastActiveDemodulator = demod; - } - } + if (!temporary) { + if (activeDemodulator != NULL) { + lastActiveDemodulator = activeDemodulator; + } else { + lastActiveDemodulator = demod; + } + } - if (activeVisualDemodulator) { - activeVisualDemodulator->setVisualOutputQueue(NULL); - } - if (demod) { - demod->setVisualOutputQueue(wxGetApp().getAudioVisualQueue()); - activeVisualDemodulator = demod; - } else { - DemodulatorInstance *last = getLastActiveDemodulator(); - if (last) { - last->setVisualOutputQueue(wxGetApp().getAudioVisualQueue()); - } - activeVisualDemodulator = last; - } + if (activeVisualDemodulator) { + activeVisualDemodulator->setVisualOutputQueue(NULL); + } + if (demod) { + demod->setVisualOutputQueue(wxGetApp().getAudioVisualQueue()); + activeVisualDemodulator = demod; + } else { + DemodulatorInstance *last = getLastActiveDemodulator(); + if (last) { + last->setVisualOutputQueue(wxGetApp().getAudioVisualQueue()); + } + activeVisualDemodulator = last; + } - activeDemodulator = demod; + activeDemodulator = demod; - garbageCollect(); + garbageCollect(); } DemodulatorInstance *DemodulatorMgr::getActiveDemodulator() { - return activeDemodulator; + return activeDemodulator; } DemodulatorInstance *DemodulatorMgr::getLastActiveDemodulator() { - if (std::find(demods.begin(), demods.end(), lastActiveDemodulator) == demods.end()) { - lastActiveDemodulator = activeDemodulator; - } + if (std::find(demods.begin(), demods.end(), lastActiveDemodulator) == demods.end()) { + lastActiveDemodulator = activeDemodulator; + } - return lastActiveDemodulator; + return lastActiveDemodulator; } void DemodulatorMgr::garbageCollect() { - if (demods_deleted.size()) { - std::vector::iterator i; + if (demods_deleted.size()) { + std::vector::iterator i; - for (i = demods_deleted.begin(); i != demods_deleted.end(); i++) { - if ((*i)->isTerminated()) { - DemodulatorInstance *deleted = (*i); - demods_deleted.erase(i); + for (i = demods_deleted.begin(); i != demods_deleted.end(); i++) { + if ((*i)->isTerminated()) { + DemodulatorInstance *deleted = (*i); + demods_deleted.erase(i); - std::cout << "Garbage collected demodulator instance " << deleted->getLabel() << std::endl; + std::cout << "Garbage collected demodulator instance " << deleted->getLabel() << std::endl; - delete deleted; - return; - } - } - } -} - -bool DemodulatorInstance::isTerminated() { - while (!threadQueueNotify->empty()) { - DemodulatorThreadCommand cmd; - threadQueueNotify->pop(cmd); - - switch (cmd.cmd) { - case DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED: - audioThread = NULL; - t_Audio->join(); - audioTerminated = true; - break; - case DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED: - demodulatorThread = NULL; -#ifdef __APPLE__ - pthread_join(t_Demod,NULL); -#else - t_Demod->join(); -#endif - demodTerminated = true; - break; - default: - break; - } - } - - terminated = audioTerminated && demodTerminated; - - return terminated; + delete deleted; + return; + } + } + } } diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorPreThread.cpp similarity index 72% rename from src/demod/DemodulatorThread.cpp rename to src/demod/DemodulatorPreThread.cpp index 03c31fa..76576fa 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorPreThread.cpp @@ -1,4 +1,4 @@ -#include "DemodulatorThread.h" + #include "CubicSDRDefs.h" #include @@ -6,8 +6,10 @@ #include #endif -DemodulatorThread::DemodulatorThread(DemodulatorThreadInputQueue* pQueue, DemodulatorThreadCommandQueue* threadQueueNotify) : - inputQueue(pQueue), visOutQueue(NULL), terminated(false), initialized(false), audio_resampler(NULL), resample_ratio(1), audio_resample_ratio( +#include "DemodulatorPreThread.h" + +DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* pQueueIn, DemodulatorThreadPostInputQueue* pQueueOut, DemodulatorThreadCommandQueue* threadQueueNotify) : + inputQueue(pQueueIn), postInputQueue(pQueueOut), terminated(false), initialized(false), audio_resampler(NULL), resample_ratio(1), audio_resample_ratio( 1), resampler(NULL), commandQueue(NULL), fir_filter(NULL), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify) { float kf = 0.5; // modulation factor @@ -24,7 +26,7 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadInputQueue* pQueue, Demodu t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread); } -void DemodulatorThread::initialize() { +void DemodulatorPreThread::initialize() { initialized = false; resample_ratio = (float) (params.bandwidth) / (float) params.inputRate; @@ -74,26 +76,24 @@ void DemodulatorThread::initialize() { last_params = params; } -DemodulatorThread::~DemodulatorThread() { +DemodulatorPreThread::~DemodulatorPreThread() { delete workerThread; delete workerQueue; delete workerResults; } #ifdef __APPLE__ -void *DemodulatorThread::threadMain() { +void *DemodulatorPreThread::threadMain() { #else -void DemodulatorThread::threadMain() { +void DemodulatorPreThread::threadMain() { #endif if (!initialized) { initialize(); } - liquid_float_complex *in_buf = new liquid_float_complex[BUF_SIZE / 2]; - liquid_float_complex *out_buf = new liquid_float_complex[BUF_SIZE / 2]; - std::cout << "Demodulator thread started.." << std::endl; + std::cout << "Demodulator preprocessor thread started.." << std::endl; while (!terminated) { DemodulatorThreadIQData inp; inputQueue->pop(inp); @@ -154,66 +154,47 @@ void DemodulatorThread::threadMain() { std::vector *data = &inp.data; if (data->size()) { - liquid_float_complex *temp_buf; + int bufSize = data->size() / 2; - for (int i = 0; i < BUF_SIZE / 2; i++) { + 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; } if (shift_freq != 0) { if (shift_freq < 0) { - nco_crcf_mix_block_up(nco_shift, in_buf, out_buf, BUF_SIZE / 2); + nco_crcf_mix_block_up(nco_shift, in_buf, out_buf, bufSize); } else { - nco_crcf_mix_block_down(nco_shift, in_buf, out_buf, BUF_SIZE / 2); + nco_crcf_mix_block_down(nco_shift, in_buf, out_buf, bufSize); } temp_buf = in_buf; in_buf = out_buf; out_buf = temp_buf; } - firfilt_crcf_execute_block(fir_filter, in_buf, BUF_SIZE / 2, out_buf); + firfilt_crcf_execute_block(fir_filter, in_buf, bufSize, out_buf); - int out_size = ceil((float) (BUF_SIZE / 2) * resample_ratio); + int out_size = ceil((float) (bufSize) * resample_ratio); - liquid_float_complex resampled_output[out_size]; - float demod_output[out_size]; + DemodulatorThreadPostIQData resamp; + + resamp.audio_resample_ratio = audio_resample_ratio; + resamp.audio_resampler = audio_resampler; + resamp.data.resize(out_size); unsigned int num_written; // number of values written to buffer - msresamp_crcf_execute(resampler, out_buf, (BUF_SIZE / 2), resampled_output, &num_written); + msresamp_crcf_execute(resampler, out_buf, (bufSize), &resamp.data[0], &num_written); - freqdem_demodulate_block(fdem, resampled_output, num_written, demod_output); + resamp.data.resize(num_written); - for (int i = 0; i < num_written; i++) { - resampled_output[i].real = demod_output[i]; - resampled_output[i].imag = 0; - } - - int audio_out_size = ceil((float) (num_written) * audio_resample_ratio); - liquid_float_complex resampled_audio_output[audio_out_size]; - - unsigned int num_audio_written; - msresamp_crcf_execute(audio_resampler, resampled_output, num_written, resampled_audio_output, &num_audio_written); - - std::vector newBuffer; - newBuffer.resize(num_audio_written * 2); - for (int i = 0; i < num_audio_written; i++) { - liquid_float_complex y = resampled_audio_output[i]; - - newBuffer[i * 2] = y.real; - newBuffer[i * 2 + 1] = y.real; - } - - AudioThreadInput ati; - ati.data = newBuffer; - - if (audioInputQueue != NULL) { - audioInputQueue->push(ati); - } - - if (visOutQueue != NULL) { - visOutQueue->push(ati); - } + postInputQueue->push(resamp); } if (!workerResults->empty()) { @@ -244,16 +225,13 @@ void DemodulatorThread::threadMain() { } } - delete in_buf; - delete out_buf; - - std::cout << "Demodulator thread done." << std::endl; - DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED); + std::cout << "Demodulator preprocessor thread done." << std::endl; + DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED); tCmd.context = this; threadQueueNotify->push(tCmd); } -void DemodulatorThread::terminate() { +void DemodulatorPreThread::terminate() { terminated = true; DemodulatorThreadIQData inp; // push dummy to nudge queue inputQueue->push(inp); diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorPreThread.h similarity index 55% rename from src/demod/DemodulatorThread.h rename to src/demod/DemodulatorPreThread.h index 850f188..72cbc89 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorPreThread.h @@ -2,46 +2,16 @@ #include #include -#include "wx/wxprec.h" -#ifndef WX_PRECOMP -#include "wx/wx.h" -#endif - -#include "wx/thread.h" - -#include "liquid/liquid.h" #include "CubicSDRDefs.h" -#include "DemodulatorWorkerThread.h" #include "DemodDefs.h" +#include "DemodulatorWorkerThread.h" -class DemodulatorThreadParameters { -public: - unsigned int frequency; - unsigned int inputRate; - unsigned int bandwidth; // set equal to disable second stage re-sampling? - unsigned int audioSampleRate; - - DemodulatorType demodType; - - DemodulatorThreadParameters() : - frequency(0), inputRate(SRATE), bandwidth(200000), audioSampleRate( - AUDIO_FREQUENCY), demodType(DEMOD_TYPE_FM) { - - } - - ~DemodulatorThreadParameters() { - - } -}; - -typedef ThreadQueue DemodulatorThreadOutputQueue; - -class DemodulatorThread { +class DemodulatorPreThread { public: - DemodulatorThread(DemodulatorThreadInputQueue* pQueue, DemodulatorThreadCommandQueue* threadQueueNotify); - ~DemodulatorThread(); + DemodulatorPreThread(DemodulatorThreadInputQueue* pQueueIn, DemodulatorThreadPostInputQueue* pQueueOut, DemodulatorThreadCommandQueue* threadQueueNotify); + ~DemodulatorPreThread(); #ifdef __APPLE__ void *threadMain(); @@ -49,10 +19,6 @@ public: void threadMain(); #endif - void setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) { - visOutQueue = tQueue; - } - void setCommandQueue(DemodulatorThreadCommandQueue *tQueue) { commandQueue = tQueue; } @@ -71,18 +37,17 @@ public: #ifdef __APPLE__ static void *pthread_helper(void *context) { - return ((DemodulatorThread *) context)->threadMain(); + return ((DemodulatorPreThread *) context)->threadMain(); } #endif protected: DemodulatorThreadInputQueue* inputQueue; - DemodulatorThreadOutputQueue* visOutQueue; + DemodulatorThreadPostInputQueue* postInputQueue; DemodulatorThreadCommandQueue* commandQueue; AudioThreadInputQueue *audioInputQueue; firfilt_crcf fir_filter; - msresamp_crcf resampler; float resample_ratio; From 62c5ab38e5afedca6ef8b136fba2ed034221022b Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 16 Dec 2014 18:27:32 -0500 Subject: [PATCH 2/4] Demodulator split --- src/demod/DemodulatorThread.cpp | 87 +++++++++++++++++++++++++++++++++ src/demod/DemodulatorThread.h | 51 +++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 src/demod/DemodulatorThread.cpp create mode 100644 src/demod/DemodulatorThread.h diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp new file mode 100644 index 0000000..93e73be --- /dev/null +++ b/src/demod/DemodulatorThread.cpp @@ -0,0 +1,87 @@ +#include "DemodulatorThread.h" +#include "CubicSDRDefs.h" +#include + +#ifdef __APPLE__ +#include +#endif + +DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadCommandQueue* threadQueueNotify) : + postInputQueue(pQueue), visOutQueue(NULL), terminated(false), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify) { + + float kf = 0.5; // modulation factor + fdem = freqdem_create(kf); +// freqdem_print(fdem); +} +DemodulatorThread::~DemodulatorThread() { +} + +#ifdef __APPLE__ +void *DemodulatorThread::threadMain() { +#else + void DemodulatorThread::threadMain() { +#endif + + std::cout << "Demodulator thread started.." << std::endl; + while (!terminated) { + DemodulatorThreadPostIQData inp; + postInputQueue->pop(inp); + + int out_size = inp.data.size(); + + if (!out_size) { + continue; + } + + msresamp_crcf audio_resampler = inp.audio_resampler; + float audio_resample_ratio = inp.audio_resample_ratio; + + float demod_output[out_size]; + + freqdem_demodulate_block(fdem, &inp.data[0], out_size, demod_output); + + liquid_float_complex demod_audio_data[out_size]; + + for (int i = 0; i < out_size; i++) { + demod_audio_data[i].real = demod_output[i]; + demod_audio_data[i].imag = 0; + } + + int audio_out_size = ceil((float) (out_size) * audio_resample_ratio); + liquid_float_complex resampled_audio_output[audio_out_size]; + + unsigned int num_audio_written; + msresamp_crcf_execute(audio_resampler, demod_audio_data, out_size, resampled_audio_output, &num_audio_written); + + std::vector newBuffer; + newBuffer.resize(num_audio_written * 2); + for (int i = 0; i < num_audio_written; i++) { + liquid_float_complex y = resampled_audio_output[i]; + + newBuffer[i * 2] = y.real; + newBuffer[i * 2 + 1] = y.real; + } + + AudioThreadInput ati; + ati.data = newBuffer; + + if (audioInputQueue != NULL) { + audioInputQueue->push(ati); + } + + if (visOutQueue != NULL) { + visOutQueue->push(ati); + } + } + + std::cout << "Demodulator thread done." << std::endl; + DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED); + tCmd.context = this; + threadQueueNotify->push(tCmd); +} + +void DemodulatorThread::terminate() { + terminated = true; + DemodulatorThreadPostIQData inp; // push dummy to nudge queue + postInputQueue->push(inp); +} diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h new file mode 100644 index 0000000..0713716 --- /dev/null +++ b/src/demod/DemodulatorThread.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#include "DemodDefs.h" +#include "AudioThread.h" + +typedef ThreadQueue DemodulatorThreadOutputQueue; + +class DemodulatorThread { +public: + + DemodulatorThread(DemodulatorThreadPostInputQueue* pQueueIn, DemodulatorThreadCommandQueue* threadQueueNotify); + ~DemodulatorThread(); + +#ifdef __APPLE__ + void *threadMain(); +#else + void threadMain(); +#endif + + void setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) { + visOutQueue = tQueue; + } + + void setAudioInputQueue(AudioThreadInputQueue *tQueue) { + audioInputQueue = tQueue; + } + + void initialize(); + + void terminate(); + +#ifdef __APPLE__ + static void *pthread_helper(void *context) { + return ((DemodulatorThread *) context)->threadMain(); + } +#endif + +protected: + DemodulatorThreadPostInputQueue* postInputQueue; + DemodulatorThreadOutputQueue* visOutQueue; + AudioThreadInputQueue *audioInputQueue; + + freqdem fdem; + + std::atomic terminated; + + DemodulatorThreadCommandQueue* threadQueueNotify; +}; From 02cf2099a9b0500af3f5ab42c2f928fe0b84e8e8 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 16 Dec 2014 20:33:44 -0500 Subject: [PATCH 3/4] Rebalance demodulator threads, tweak priorities --- src/AppFrame.cpp | 6 +++- src/CubicSDRDefs.h | 8 ++--- src/audio/AudioThread.cpp | 12 ++++++-- src/demod/DemodDefs.h | 2 ++ src/demod/DemodulatorInstance.cpp | 2 ++ src/demod/DemodulatorPreThread.cpp | 25 +++++++-------- src/demod/DemodulatorThread.cpp | 49 ++++++++++++++++++++++++------ src/sdr/SDRPostThread.cpp | 7 +++++ src/sdr/SDRThread.cpp | 6 ++++ 9 files changed, 87 insertions(+), 30 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index bbc2654..bb0a827 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -93,6 +93,10 @@ void AppFrame::OnThread(wxCommandEvent& event) { void AppFrame::OnIdle(wxIdleEvent& event) { bool work_done = false; +//#ifdef __APPLE__ +// std::this_thread::sleep_for(std::chrono::milliseconds(4)); +// std::this_thread::yield(); +//#endif if (!wxGetApp().getIQVisualQueue()->empty()) { SDRThreadIQData iqData; wxGetApp().getIQVisualQueue()->pop(iqData); @@ -127,6 +131,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) { } if (!work_done) { - event.Skip(); + event.Skip(); } } diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 1bf8f09..9951cd6 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -1,12 +1,8 @@ #pragma once -#ifdef __APPLE__ #define BUF_SIZE (16384*3) -#else -#define BUF_SIZE (16384*4) -#endif -#define SRATE 2000000 +#define SRATE 1500000 #define FFT_SIZE 2048 #define DEFAULT_FREQ 98900000 -#define AUDIO_FREQUENCY 48000 +#define AUDIO_FREQUENCY 44100 diff --git a/src/audio/AudioThread.cpp b/src/audio/AudioThread.cpp index 3c37055..b79c161 100644 --- a/src/audio/AudioThread.cpp +++ b/src/audio/AudioThread.cpp @@ -44,7 +44,14 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu } void AudioThread::threadMain() { - std::cout << "Audio thread initializing.." << std::endl; +#ifdef __APPLE__ + pthread_t tID = pthread_self(); // ID of this thread + int priority = sched_get_priority_min( SCHED_RR ); + sched_param prio = { priority }; // scheduling priority of thread + pthread_setschedparam( tID, SCHED_RR, &prio ); +#endif + + std::cout << "Audio thread initializing.." << std::endl; if (dac.getDeviceCount() < 1) { std::cout << "No audio devices found!" << std::endl; @@ -59,7 +66,8 @@ void AudioThread::threadMain() { unsigned int bufferFrames = 256; RtAudio::StreamOptions opts; -// opts.flags = RTAUDIO_SCHEDULE_REALTIME | RTAUDIO_MINIMIZE_LATENCY; + opts.flags = RTAUDIO_SCHEDULE_REALTIME; +// | RTAUDIO_MINIMIZE_LATENCY; // opts.flags = RTAUDIO_MINIMIZE_LATENCY; opts.streamName = "CubicSDR Audio Output"; // opts.priority = sched_get_priority_max(SCHED_FIFO); diff --git a/src/demod/DemodDefs.h b/src/demod/DemodDefs.h index 8f3c04f..9fb246f 100644 --- a/src/demod/DemodDefs.h +++ b/src/demod/DemodDefs.h @@ -66,6 +66,8 @@ public: std::vector data; float audio_resample_ratio; msresamp_crcf audio_resampler; + float resample_ratio; + msresamp_crcf resampler; DemodulatorThreadPostIQData(): audio_resample_ratio(0), audio_resampler(NULL) { diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index c9a91c9..e5aa33f 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -42,12 +42,14 @@ void DemodulatorInstance::run() { pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 2048000); pthread_attr_getstacksize(&attr, &size); + pthread_attr_setschedpolicy(&attr, SCHED_RR); pthread_create(&t_PreDemod, &attr, &DemodulatorPreThread::pthread_helper, demodulatorPreThread); pthread_attr_destroy(&attr); pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 2048000); pthread_attr_getstacksize(&attr, &size); + pthread_attr_setschedpolicy(&attr, SCHED_RR); pthread_create(&t_Demod, &attr, &DemodulatorThread::pthread_helper, demodulatorThread); pthread_attr_destroy(&attr); diff --git a/src/demod/DemodulatorPreThread.cpp b/src/demod/DemodulatorPreThread.cpp index 76576fa..1f76615 100644 --- a/src/demod/DemodulatorPreThread.cpp +++ b/src/demod/DemodulatorPreThread.cpp @@ -86,6 +86,12 @@ DemodulatorPreThread::~DemodulatorPreThread() { void *DemodulatorPreThread::threadMain() { #else void DemodulatorPreThread::threadMain() { +#endif +#ifdef __APPLE__ + pthread_t tID = pthread_self(); // ID of this thread + int priority = sched_get_priority_min( SCHED_RR ); + sched_param prio = { priority }; // scheduling priority of thread + pthread_setschedparam( tID, SCHED_RR, &prio ); #endif if (!initialized) { @@ -179,20 +185,15 @@ void DemodulatorPreThread::threadMain() { out_buf = temp_buf; } - firfilt_crcf_execute_block(fir_filter, in_buf, bufSize, out_buf); - - int out_size = ceil((float) (bufSize) * resample_ratio); - DemodulatorThreadPostIQData resamp; + resamp.data.resize(bufSize); + + firfilt_crcf_execute_block(fir_filter, in_buf, bufSize, &resamp.data[0]); resamp.audio_resample_ratio = audio_resample_ratio; resamp.audio_resampler = audio_resampler; - resamp.data.resize(out_size); - - unsigned int num_written; // number of values written to buffer - msresamp_crcf_execute(resampler, out_buf, (bufSize), &resamp.data[0], &num_written); - - resamp.data.resize(num_written); + resamp.resample_ratio = resample_ratio; + resamp.resampler = resampler; postInputQueue->push(resamp); } @@ -205,8 +206,8 @@ void DemodulatorPreThread::threadMain() { switch (result.cmd) { case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS: firfilt_crcf_destroy(fir_filter); - msresamp_crcf_destroy(resampler); - msresamp_crcf_destroy(audio_resampler); +// msresamp_crcf_destroy(resampler); +// msresamp_crcf_destroy(audio_resampler); fir_filter = result.fir_filter; resampler = result.resampler; diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 93e73be..58f4ca0 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -21,37 +21,61 @@ void *DemodulatorThread::threadMain() { #else void DemodulatorThread::threadMain() { #endif +#ifdef __APPLE__ + pthread_t tID = pthread_self(); // ID of this thread + int priority = sched_get_priority_min( SCHED_RR ); + sched_param prio = { priority }; // scheduling priority of thread + pthread_setschedparam( tID, SCHED_RR, &prio ); +#endif + + msresamp_crcf audio_resampler = NULL; + msresamp_crcf resampler = NULL; std::cout << "Demodulator thread started.." << std::endl; while (!terminated) { DemodulatorThreadPostIQData inp; postInputQueue->pop(inp); - int out_size = inp.data.size(); + int bufSize = inp.data.size(); - if (!out_size) { + if (!bufSize) { continue; } - msresamp_crcf audio_resampler = inp.audio_resampler; + if (resampler == NULL) { + resampler = inp.resampler; + audio_resampler = inp.audio_resampler; + } else if (resampler != inp.resampler) { + msresamp_crcf_destroy(resampler); + msresamp_crcf_destroy(audio_resampler); + resampler = inp.resampler; + audio_resampler = inp.audio_resampler; + } + + int out_size = ceil((float) (bufSize) * inp.resample_ratio); + liquid_float_complex resampled_data[out_size]; + + unsigned int num_written; + msresamp_crcf_execute(resampler, &inp.data[0], bufSize, resampled_data, &num_written); + float audio_resample_ratio = inp.audio_resample_ratio; - float demod_output[out_size]; + float demod_output[num_written]; - freqdem_demodulate_block(fdem, &inp.data[0], out_size, demod_output); + freqdem_demodulate_block(fdem, resampled_data, num_written, demod_output); - liquid_float_complex demod_audio_data[out_size]; + liquid_float_complex demod_audio_data[num_written]; - for (int i = 0; i < out_size; i++) { + for (int i = 0; i < num_written; i++) { demod_audio_data[i].real = demod_output[i]; demod_audio_data[i].imag = 0; } - int audio_out_size = ceil((float) (out_size) * audio_resample_ratio); + int audio_out_size = ceil((float) (num_written) * audio_resample_ratio); liquid_float_complex resampled_audio_output[audio_out_size]; unsigned int num_audio_written; - msresamp_crcf_execute(audio_resampler, demod_audio_data, out_size, resampled_audio_output, &num_audio_written); + msresamp_crcf_execute(audio_resampler, demod_audio_data, num_written, resampled_audio_output, &num_audio_written); std::vector newBuffer; newBuffer.resize(num_audio_written * 2); @@ -74,6 +98,13 @@ void *DemodulatorThread::threadMain() { } } + if (resampler != NULL) { + msresamp_crcf_destroy(resampler); + } + if (audio_resampler != NULL) { + msresamp_crcf_destroy(audio_resampler); + } + std::cout << "Demodulator thread done." << std::endl; DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED); tCmd.context = this; diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 02e7bdf..6868fab 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -42,6 +42,13 @@ void SDRPostThread::threadMain() { int n_read; double seconds = 0.0; +//#ifdef __APPLE__ +// pthread_t tID = pthread_self(); // ID of this thread +// int priority = sched_get_priority_min( SCHED_RR ); +// sched_param prio = { priority }; // scheduling priority of thread +// pthread_setschedparam( tID, SCHED_RR, &prio ); +//#endif + dcFilter = iirfilt_crcf_create_dc_blocker(0.0005); liquid_float_complex x, y; diff --git a/src/sdr/SDRThread.cpp b/src/sdr/SDRThread.cpp index e1c1475..a4b9d56 100644 --- a/src/sdr/SDRThread.cpp +++ b/src/sdr/SDRThread.cpp @@ -89,6 +89,12 @@ int SDRThread::enumerate_rtl() { } void SDRThread::threadMain() { +//#ifdef __APPLE__ +// pthread_t tID = pthread_self(); // ID of this thread +// int priority = sched_get_priority_min( SCHED_RR ); +// sched_param prio = { priority }; // scheduling priority of thread +// pthread_setschedparam( tID, SCHED_RR, &prio ); +//#endif std::cout << "SDR thread initializing.." << std::endl; From 912ef930a2aca7dba7c141faabb65f8ad915a468 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 16 Dec 2014 21:03:45 -0500 Subject: [PATCH 4/4] Font preloader, new demod no-move drag fix --- src/CubicSDRDefs.h | 4 ++-- src/visual/PrimaryGLContext.cpp | 5 ++++- src/visual/WaterfallCanvas.cpp | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 9951cd6..f1ec469 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -1,7 +1,7 @@ #pragma once -#define BUF_SIZE (16384*3) -#define SRATE 1500000 +#define BUF_SIZE (16384*4) +#define SRATE 2500000 #define FFT_SIZE 2048 #define DEFAULT_FREQ 98900000 diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp index 793132a..1876c47 100644 --- a/src/visual/PrimaryGLContext.cpp +++ b/src/visual/PrimaryGLContext.cpp @@ -54,7 +54,10 @@ void PrimaryGLContext::CheckGLError() { PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas, wxGLContext *sharedContext) : wxGLContext(canvas, sharedContext) { SetCurrent(*canvas); - + // Pre-load fonts + for (int i = 0; i < GLFONT_MAX; i++) { + getFont((GLFontSize)i); + } CheckGLError(); } diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 3c8e09f..5eeac20 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -444,7 +444,7 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) { demod->run(); wxGetApp().bindDemodulator(demod); - wxGetApp().getDemodMgr().setActiveDemodulator(demod); + wxGetApp().getDemodMgr().setActiveDemodulator(demod,false); } if (demod == NULL) { @@ -474,7 +474,7 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) { int freq = center_freq - (int) (0.5 * (float) SRATE) + (int) ((float) pos * (float) SRATE); wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false); - nextDragState = WF_DRAG_NONE; + nextDragState = WF_DRAG_FREQUENCY; } } else if (dragState == WF_DRAG_RANGE) { float width = mTracker.getOriginDeltaMouseX(); @@ -503,7 +503,7 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) { demod->run(); wxGetApp().bindDemodulator(demod); - wxGetApp().getDemodMgr().setActiveDemodulator(demod); + wxGetApp().getDemodMgr().setActiveDemodulator(demod,false); } if (demod == NULL) {