From 2a34fc9cf9e23b148a011346782a04f1a798e55f Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sun, 16 Nov 2014 16:51:45 -0500 Subject: [PATCH] New demodulator thread code --- src/AppFrame.cpp | 84 ++++++++++--- src/AppFrame.h | 16 ++- src/CubicSDRDefs.h | 2 +- src/Demodulator.cpp | 207 ++++++++++----------------------- src/Demodulator.h | 11 -- src/DemodulatorThread.cpp | 173 +++++++++++++++++++++++++++ src/DemodulatorThread.h | 57 +++++++++ src/DemodulatorThreadQueue.cpp | 43 +++++++ src/DemodulatorThreadQueue.h | 28 +++++ src/DemodulatorThreadTask.cpp | 8 ++ src/DemodulatorThreadTask.h | 26 +++++ 11 files changed, 483 insertions(+), 172 deletions(-) create mode 100644 src/DemodulatorThread.cpp create mode 100644 src/DemodulatorThread.h create mode 100644 src/DemodulatorThreadQueue.cpp create mode 100644 src/DemodulatorThreadQueue.h create mode 100644 src/DemodulatorThreadTask.cpp create mode 100644 src/DemodulatorThreadTask.h diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index f9665e0..a725433 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -12,11 +12,15 @@ #include #include "SDRThread.h" +#include "DemodulatorThread.h" +#include "AudioThread.h" wxBEGIN_EVENT_TABLE(AppFrame, wxFrame) //EVT_MENU(wxID_NEW, AppFrame::OnNewWindow) EVT_MENU(wxID_CLOSE, AppFrame::OnClose) EVT_THREAD(EVENT_SDR_INPUT, AppFrame::OnEventInput) +EVT_THREAD(EVENT_DEMOD_INPUT, AppFrame::OnDemodInput) +EVT_THREAD(EVENT_AUDIO_INPUT, AppFrame::OnAudioInput) EVT_IDLE(AppFrame::OnIdle) wxEND_EVENT_TABLE() @@ -53,22 +57,39 @@ AppFrame::AppFrame() : Centre(); Show(); - m_pQueue = new SDRThreadQueue(this); - - t_SDR = new SDRThread(m_pQueue); + threadQueueSDR = new SDRThreadQueue(this); + t_SDR = new SDRThread(threadQueueSDR); if (t_SDR->Run() != wxTHREAD_NO_ERROR) { wxLogError - ("Can't create the thread!"); + ("Can't create the SDR thread!"); delete t_SDR; t_SDR = NULL; } + threadQueueDemod = new DemodulatorThreadQueue(this); + t_Demod = new DemodulatorThread(threadQueueDemod); + if (t_Demod->Run() != wxTHREAD_NO_ERROR) { + wxLogError + ("Can't create the Demodulator thread!"); + delete t_Demod; + t_Demod = NULL; + } + + threadQueueAudio = new AudioThreadQueue(this); + t_Audio = new AudioThread(threadQueueAudio); + if (t_Audio->Run() != wxTHREAD_NO_ERROR) { + wxLogError + ("Can't create the Audio thread!"); + delete t_Audio; + t_Audio = NULL; + } + // t_IQBuffer = new IQBufferThread(this); // if (t_IQBuffer->Run() != wxTHREAD_NO_ERROR) { // wxLogError // ("Can't create the thread!"); // delete t_IQBuffer; - t_IQBuffer = NULL; +// t_IQBuffer = NULL; // } // static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; @@ -99,9 +120,11 @@ AppFrame::~AppFrame() { // } // } - delete t_SDR; +// delete t_SDR; // delete t_IQBuffer; - delete m_pQueue; + delete threadQueueAudio; + delete threadQueueDemod; + delete threadQueueSDR; } void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { @@ -114,17 +137,50 @@ void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) { new AppFrame(); } +// SDR IQ -> Demodulator void AppFrame::OnEventInput(wxThreadEvent& event) { std::vector *new_buffer = event.GetPayload *>(); - - test_demod.writeBuffer(new_buffer); - scopeCanvas->setWaveformPoints(test_demod.waveform_points); - spectrumCanvas->setData(new_buffer); - waterfallCanvas->setData(new_buffer); - +// std::cout << new_buffer->size() << std::endl; + if (new_buffer->size()) { + test_demod.writeBuffer(new_buffer); + scopeCanvas->setWaveformPoints(test_demod.waveform_points); + spectrumCanvas->setData(new_buffer); + waterfallCanvas->setData(new_buffer); + } else { + std::cout << "Incoming IQ data empty?" << std::endl; + } delete new_buffer; } + +// Demodulator -> Audio +void AppFrame::OnDemodInput(wxThreadEvent& event) { + std::vector *new_buffer = event.GetPayload *>(); + + if (new_buffer->size()) { + AudioThreadTask task = AudioThreadTask(AudioThreadTask::AUDIO_THREAD_DATA); + task.setData(*new_buffer); + threadQueueAudio->addTask(task, AudioThreadQueue::AUDIO_PRIORITY_HIGHEST); + } else { + std::cout << "Incoming Demod data empty?" << std::endl; + } + delete new_buffer; +} + +// Audio -> Visual +void AppFrame::OnAudioInput(wxThreadEvent& event) { +// std::vector *new_buffer = event.GetPayload *>(); +// +// if (new_buffer->size()) { +// AudioThreadTask task = AudioThreadTask(AudioThreadTask::AUDIO_THREAD_DATA); +// task.setData(*new_buffer); +// threadQueueAudio->addTask(task, AudioThreadQueue::AUDIO_PRIORITY_HIGHEST); +// } else { +// std::cout << "Incoming Demod data empty?" << std::endl; +// } +// delete new_buffer; +} + void AppFrame::OnIdle(wxIdleEvent& event) { event.Skip(); @@ -134,7 +190,7 @@ void AppFrame::setFrequency(unsigned int freq) { frequency = freq; SDRThreadTask task = SDRThreadTask(SDRThreadTask::SDR_THREAD_TUNING); task.setUInt(freq); - m_pQueue->addTask(task, SDRThreadQueue::SDR_PRIORITY_HIGHEST); + threadQueueSDR->addTask(task, SDRThreadQueue::SDR_PRIORITY_HIGHEST); } int AppFrame::getFrequency() { diff --git a/src/AppFrame.h b/src/AppFrame.h index 5fb80bc..765bcaa 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -3,6 +3,9 @@ #include "wx/frame.h" #include "PrimaryGLContext.h" #include "SDRThread.h" +#include "AudioThread.h" +#include "DemodulatorThread.h" + #include "ScopeCanvas.h" #include "SpectrumCanvas.h" #include "WaterfallCanvas.h" @@ -14,6 +17,9 @@ public: AppFrame(); ~AppFrame(); void OnEventInput(wxThreadEvent& event); + void OnDemodInput(wxThreadEvent& event); + void OnAudioInput(wxThreadEvent& event); + void setFrequency(unsigned int freq); int getFrequency(); @@ -26,10 +32,16 @@ private: ScopeCanvas *scopeCanvas; SpectrumCanvas *spectrumCanvas; WaterfallCanvas *waterfallCanvas; + SDRThread *t_SDR; - IQBufferThread *t_IQBuffer; + SDRThreadQueue* threadQueueSDR; + AudioThread *t_Audio; + AudioThreadQueue* threadQueueAudio; + DemodulatorThread *t_Demod; + DemodulatorThreadQueue* threadQueueDemod; + + // IQBufferThread *t_IQBuffer; wxCriticalSection m_pThreadCS; - SDRThreadQueue* m_pQueue; unsigned int frequency; Demodulator test_demod; diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index d772066..014245a 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -5,4 +5,4 @@ #define FFT_SIZE 2048 #define DEFAULT_FREQ 98900000 - +#define AUDIO_FREQUENCY 48000 diff --git a/src/Demodulator.cpp b/src/Demodulator.cpp index c2af8f3..1b586d6 100644 --- a/src/Demodulator.cpp +++ b/src/Demodulator.cpp @@ -4,40 +4,6 @@ #include #endif -static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, void *userData) { - - Demodulator *src = (Demodulator *) userData; - - float *out = (float*) outputBuffer; - - if (!src->audio_queue.size()) { - for (int i = 0; i < framesPerBuffer * 2; i++) { - out[i] = 0; - } - return paContinue; - } - - std::vector *nextBuffer = src->audio_queue.front(); - - for (int i = 0; i < framesPerBuffer * 2; i++) { - out[i] = (*nextBuffer)[src->audio_queue_ptr]; - - src->audio_queue_ptr++; - - if (src->audio_queue_ptr == nextBuffer->size()) { - src->audio_queue.pop(); - delete nextBuffer; - src->audio_queue_ptr = 0; - if (!src->audio_queue.size()) { - break; - } - nextBuffer = src->audio_queue.front(); - } - } - - return paContinue; -} Demodulator::Demodulator() { @@ -45,53 +11,9 @@ Demodulator::Demodulator() { resample_ratio = (float) (bandwidth) / (float) SRATE; wbfm_frequency = 100000; wbfm_resample_ratio = (float) (wbfm_frequency) / (float) bandwidth; - audio_frequency = 48000; + audio_frequency = AUDIO_FREQUENCY; audio_resample_ratio = (float) (audio_frequency) / (float) wbfm_frequency; - PaError err; - err = Pa_Initialize(); - if (err != paNoError) { - std::cout << "Error starting :(\n"; - } - - int preferred_device = -1; - -#ifdef WIN32 - wchar_t dev_str[255]; - memset(dev_str, 0, sizeof(wchar_t) * 255); - std::wstring env_name(L"PA_RECOMMENDED_OUTPUT_DEVICE"); - GetEnvironmentVariable(env_name.c_str(), dev_str, 255); - std::wstring env_result(dev_str); - - int env_dev = _wtoi(env_result.c_str()); - - if (env_dev || env_result.length()) { - std::cout << "Using preferred PortAudio device PA_RECOMMENDED_OUTPUT_DEVICE=" << env_result.c_str() << std::endl; - preferred_device = env_dev; - } else { - std::cout << "Environment variable PA_RECOMMENDED_OUTPUT_DEVICE not set, using PortAudio defaults." << std::endl; - } -#endif - - outputParameters.device = (preferred_device != -1) ? preferred_device : Pa_GetDefaultOutputDevice(); - if (outputParameters.device == paNoDevice) { - std::cout << "Error: No default output device.\n"; - } - - outputParameters.channelCount = 2; /* Stereo output, most likely supported. */ - outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */ - outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - - stream = NULL; - - err = Pa_OpenStream(&stream, NULL, &outputParameters, audio_frequency, 1024, paClipOff, &patestCallback, this); - - err = Pa_StartStream(stream); - if (err != paNoError) { - std::cout << "Error starting stream: " << Pa_GetErrorText(err) << std::endl; - std::cout << "\tPortAudio error: " << Pa_GetErrorText(err) << std::endl; - } float fc = 0.5f * ((float)bandwidth / (float)SRATE) * 0.75; // filter cutoff frequency float ft = 0.05f; // filter transition @@ -127,91 +49,88 @@ Demodulator::Demodulator() { } Demodulator::~Demodulator() { - PaError err; - err = Pa_StopStream(stream); - err = Pa_CloseStream(stream); - Pa_Terminate(); + } void Demodulator::writeBuffer(std::vector *data) { - liquid_float_complex filtered_input[BUF_SIZE / 2]; + if (data->size()) { + liquid_float_complex filtered_input[BUF_SIZE / 2]; - for (int i = 0; i < BUF_SIZE / 2; i++) { + for (int i = 0; i < BUF_SIZE / 2; i++) { - liquid_float_complex x; - liquid_float_complex y; + liquid_float_complex x; + liquid_float_complex y; - x.real = (float) (*data)[i * 2] / 127.0f; - x.imag = (float) (*data)[i * 2 + 1] / 127.0f; + x.real = (float) (*data)[i * 2] / 127.0f; + x.imag = (float) (*data)[i * 2 + 1] / 127.0f; - firfilt_crcf_push(fir_filter, x); // push input sample - firfilt_crcf_execute(fir_filter, &y); // compute output + firfilt_crcf_push(fir_filter, x); // push input sample + firfilt_crcf_execute(fir_filter, &y); // compute output - filtered_input[i] = y; - } - - int out_size = ceil((float) (BUF_SIZE / 2) * resample_ratio); - - liquid_float_complex resampled_output[out_size]; - - unsigned int num_written; // number of values written to buffer - msresamp_crcf_execute(resampler, filtered_input, (BUF_SIZE / 2), resampled_output, &num_written); - - float waveform_ceil = 0, waveform_floor = 0; - - float pcm = 0; - - for (int i = 0; i < num_written; i++) { - freqdem_demodulate(fdem, resampled_output[i], &pcm); - - resampled_output[i].real = (float) pcm; - resampled_output[i].imag = 0; - - if (waveform_ceil < resampled_output[i].real) { - waveform_ceil = resampled_output[i].real; + filtered_input[i] = y; } - if (waveform_floor > resampled_output[i].real) { - waveform_floor = resampled_output[i].real; + int out_size = ceil((float) (BUF_SIZE / 2) * resample_ratio); + + liquid_float_complex resampled_output[out_size]; + + unsigned int num_written; // number of values written to buffer + msresamp_crcf_execute(resampler, filtered_input, (BUF_SIZE / 2), resampled_output, &num_written); + + float waveform_ceil = 0, waveform_floor = 0; + + float pcm = 0; + + for (int i = 0; i < num_written; i++) { + freqdem_demodulate(fdem, resampled_output[i], &pcm); + + resampled_output[i].real = (float) pcm; + resampled_output[i].imag = 0; + + if (waveform_ceil < resampled_output[i].real) { + waveform_ceil = resampled_output[i].real; + } + + if (waveform_floor > resampled_output[i].real) { + waveform_floor = resampled_output[i].real; + } } - } - int wbfm_out_size = ceil((float) (num_written) * wbfm_resample_ratio); - liquid_float_complex resampled_wbfm_output[wbfm_out_size]; + int wbfm_out_size = ceil((float) (num_written) * wbfm_resample_ratio); + liquid_float_complex resampled_wbfm_output[wbfm_out_size]; - unsigned int num_wbfm_written; - msresamp_crcf_execute(wbfm_resampler, resampled_output, num_written, resampled_wbfm_output, &num_wbfm_written); + unsigned int num_wbfm_written; + msresamp_crcf_execute(wbfm_resampler, resampled_output, num_written, resampled_wbfm_output, &num_wbfm_written); - 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]); - } + 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]); + } - int audio_out_size = ceil((float) (num_wbfm_written) * audio_resample_ratio); - liquid_float_complex resampled_audio_output[audio_out_size]; + int audio_out_size = ceil((float) (num_wbfm_written) * audio_resample_ratio); + liquid_float_complex resampled_audio_output[audio_out_size]; - unsigned int num_audio_written; - msresamp_crcf_execute(audio_resampler, resampled_wbfm_output, num_wbfm_written, resampled_audio_output, &num_audio_written); + unsigned int num_audio_written; + msresamp_crcf_execute(audio_resampler, resampled_wbfm_output, num_wbfm_written, resampled_audio_output, &num_audio_written); - std::vector *newBuffer = new std::vector; - newBuffer->resize(num_audio_written * 2); - for (int i = 0; i < num_audio_written; i++) { - liquid_float_complex y = resampled_audio_output[i]; +// std::vector *newBuffer = new std::vector; +// 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; +// } - (*newBuffer)[i * 2] = y.real; - (*newBuffer)[i * 2 + 1] = y.real; - } + if (waveform_points.size() != num_audio_written * 2) { + waveform_points.resize(num_audio_written * 2); + } - audio_queue.push(newBuffer); - - if (waveform_points.size() != num_audio_written * 2) { - waveform_points.resize(num_audio_written * 2); - } - - for (int i = 0, iMax = waveform_points.size() / 2; i < iMax; i++) { - waveform_points[i * 2 + 1] = resampled_audio_output[i].real * 0.5f; - waveform_points[i * 2] = ((double) i / (double) iMax); + for (int i = 0, iMax = waveform_points.size() / 2; i < iMax; i++) { + waveform_points[i * 2 + 1] = resampled_audio_output[i].real * 0.5f; + waveform_points[i * 2] = ((double) i / (double) iMax); + } } } diff --git a/src/Demodulator.h b/src/Demodulator.h index cbf483e..46efb02 100644 --- a/src/Demodulator.h +++ b/src/Demodulator.h @@ -9,19 +9,10 @@ #include "CubicSDRDefs.h" #include "liquid/liquid.h" -#include "portaudio.h" -#ifdef WIN32 -#include "pa_stream.h" -#include "pa_debugprint.h" -#endif -static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, void *userData); class Demodulator { public: - std::queue *> audio_queue; - unsigned int audio_queue_ptr; std::vector waveform_points; Demodulator(); @@ -47,7 +38,5 @@ private: unsigned int audio_frequency; - PaStreamParameters outputParameters; - PaStream *stream; freqdem fdem; }; diff --git a/src/DemodulatorThread.cpp b/src/DemodulatorThread.cpp new file mode 100644 index 0000000..43decdc --- /dev/null +++ b/src/DemodulatorThread.cpp @@ -0,0 +1,173 @@ +#include "DemodulatorThread.h" +#include "CubicSDRDefs.h" +#include + +//wxDEFINE_EVENT(wxEVT_COMMAND_DemodulatorThread_INPUT, wxThreadEvent); + +DemodulatorThread::DemodulatorThread(DemodulatorThreadQueue* pQueue, int id) : + wxThread(wxTHREAD_DETACHED), m_pQueue(pQueue), m_ID(id) { + + bandwidth = 200000; + resample_ratio = (float) (bandwidth) / (float) SRATE; + wbfm_frequency = 100000; + wbfm_resample_ratio = (float) (wbfm_frequency) / (float) bandwidth; + audio_frequency = AUDIO_FREQUENCY; + audio_resample_ratio = (float) (audio_frequency) / (float) wbfm_frequency; + + float fc = 0.5f * ((float) bandwidth / (float) SRATE) * 0.75; // filter cutoff frequency + 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); + liquid_firdes_kaiser(h_len, 32000.0 / (float) wbfm_frequency, As, mu, h); + + 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); + + wbfm_resampler = msresamp_crcf_create(wbfm_resample_ratio, As); + msresamp_crcf_print(wbfm_resampler); + + 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() { + +} + +wxThread::ExitCode DemodulatorThread::Entry() { + + while (!TestDestroy()) { + + if (m_pQueue->stackSize()) { + + while (m_pQueue->stackSize()) { + DemodulatorThreadTask task = m_pQueue->pop(); // pop a task from the queue. this will block the worker thread if queue is empty + switch (task.m_cmd) { + case DemodulatorThreadTask::DEMOD_THREAD_DATA: + std::vector *data = &task.getData(); + if (data->size()) { + liquid_float_complex filtered_input[BUF_SIZE / 2]; + + for (int i = 0; i < BUF_SIZE / 2; i++) { + + liquid_float_complex x; + liquid_float_complex y; + + x.real = (float) (*data)[i * 2] / 127.0f; + x.imag = (float) (*data)[i * 2 + 1] / 127.0f; + + firfilt_crcf_push(fir_filter, x); // push input sample + firfilt_crcf_execute(fir_filter, &y); // compute output + + filtered_input[i] = y; + } + + int out_size = ceil((float) (BUF_SIZE / 2) * resample_ratio); + + liquid_float_complex resampled_output[out_size]; + + unsigned int num_written; // number of values written to buffer + msresamp_crcf_execute(resampler, filtered_input, (BUF_SIZE / 2), resampled_output, &num_written); + + float waveform_ceil = 0, waveform_floor = 0; + + float pcm = 0; + + for (int i = 0; i < num_written; i++) { + freqdem_demodulate(fdem, resampled_output[i], &pcm); + + resampled_output[i].real = (float) pcm; + resampled_output[i].imag = 0; + + if (waveform_ceil < resampled_output[i].real) { + waveform_ceil = resampled_output[i].real; + } + + if (waveform_floor > resampled_output[i].real) { + waveform_floor = resampled_output[i].real; + } + } + + int wbfm_out_size = ceil((float) (num_written) * wbfm_resample_ratio); + liquid_float_complex resampled_wbfm_output[wbfm_out_size]; + + unsigned int num_wbfm_written; + msresamp_crcf_execute(wbfm_resampler, resampled_output, num_written, resampled_wbfm_output, &num_wbfm_written); + + 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]); + } + + int audio_out_size = ceil((float) (num_wbfm_written) * audio_resample_ratio); + liquid_float_complex resampled_audio_output[audio_out_size]; + + unsigned int num_audio_written; + msresamp_crcf_execute(audio_resampler, resampled_wbfm_output, num_wbfm_written, resampled_audio_output, &num_audio_written); + + std::vector *newBuffer = new std::vector; + 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; + } + + + if (!TestDestroy()) { + wxThreadEvent event(wxEVT_THREAD, EVENT_DEMOD_INPUT); + event.SetPayload(newBuffer); + wxQueueEvent(m_pQueue->getHandler(), event.Clone()); + } else { + delete newBuffer; + } + + // std::vector *newBuffer = new std::vector; + // 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; + // } + +// if (waveform_points.size() != num_audio_written * 2) { +// waveform_points.resize(num_audio_written * 2); +// } +// +// for (int i = 0, iMax = waveform_points.size() / 2; i < iMax; i++) { +// waveform_points[i * 2 + 1] = resampled_audio_output[i].real * 0.5f; +// waveform_points[i * 2] = ((double) i / (double) iMax); +// } + } + // audio_queue.push(newBuffer); + break; + } + } + } + + Sleep(1000); + } + std::cout << std::endl << "Demodulator Thread Done." << std::endl << std::endl; + + return (wxThread::ExitCode) 0; +} + diff --git a/src/DemodulatorThread.h b/src/DemodulatorThread.h new file mode 100644 index 0000000..bff7638 --- /dev/null +++ b/src/DemodulatorThread.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/thread.h" + +#include "DemodulatorThreadQueue.h" + +#include "liquid/liquid.h" + +// declare a new type of event, to be used by our DemodulatorThread class: +//wxDECLARE_EVENT(wxEVT_COMMAND_DemodulatorThread_COMPLETED, wxThreadEvent); +//wxDECLARE_EVENT(wxEVT_COMMAND_DemodulatorThread_UPDATE, wxThreadEvent); +//wxDECLARE_EVENT(wxEVT_COMMAND_DemodulatorThread_INPUT, wxThreadEvent); + +enum { + EVENT_DEMOD_INPUT = wxID_HIGHEST + 1 +}; + +class DemodulatorThread: public wxThread { +public: + std::queue *> audio_queue; + unsigned int audio_queue_ptr; + + DemodulatorThread(DemodulatorThreadQueue* pQueue, int id = 0); + ~DemodulatorThread(); + +protected: + virtual ExitCode Entry(); + DemodulatorThreadQueue* m_pQueue; + int m_ID; + + firfilt_crcf fir_filter; + firfilt_crcf fir_audio_filter; + + unsigned int bandwidth; + + msresamp_crcf resampler; + float resample_ratio; + + msresamp_crcf wbfm_resampler; + float wbfm_resample_ratio; + unsigned int wbfm_frequency; + + msresamp_crcf audio_resampler; + float audio_resample_ratio; + + unsigned int audio_frequency; + + freqdem fdem; +}; diff --git a/src/DemodulatorThreadQueue.cpp b/src/DemodulatorThreadQueue.cpp new file mode 100644 index 0000000..a6f6f5b --- /dev/null +++ b/src/DemodulatorThreadQueue.cpp @@ -0,0 +1,43 @@ +#include "DemodulatorThreadQueue.h" + +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +DemodulatorThreadQueue::DemodulatorThreadQueue(wxEvtHandler* pParent) : + m_pParent(pParent) { +} + +void DemodulatorThreadQueue::addTask(const DemodulatorThreadTask& task, const DEMOD_PRIORITY& priority) { + wxMutexLocker lock(m_MutexQueue); + m_Tasks.insert(std::make_pair(priority, task)); + m_QueueCount.Post(); +} + +DemodulatorThreadTask DemodulatorThreadQueue::pop() { + DemodulatorThreadTask element; + m_QueueCount.Wait(); + m_MutexQueue.Lock(); + element = (m_Tasks.begin())->second; + m_Tasks.erase(m_Tasks.begin()); + m_MutexQueue.Unlock(); + return element; +} + +void DemodulatorThreadQueue::report(const DemodulatorThreadTask::DEMOD_THREAD_COMMAND& cmd, const wxString& sArg, int iArg) { + wxCommandEvent evt(wxEVT_THREAD, cmd); + evt.SetString(sArg); + evt.SetInt(iArg); + m_pParent->AddPendingEvent(evt); +} + +size_t DemodulatorThreadQueue::stackSize() { + wxMutexLocker lock(m_MutexQueue); + return m_Tasks.size(); +} + +wxEvtHandler* DemodulatorThreadQueue::getHandler() { + return m_pParent; +} diff --git a/src/DemodulatorThreadQueue.h b/src/DemodulatorThreadQueue.h new file mode 100644 index 0000000..3920c11 --- /dev/null +++ b/src/DemodulatorThreadQueue.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include "DemodulatorThreadTask.h" + +#include "wx/event.h" + +class DemodulatorThreadQueue { +public: + enum DEMOD_PRIORITY { + DEMOD_PRIORITY_HIGHEST, DEMOD_PRIORITY_HIGHER, DEMOD_PRIORITY_NORMAL, DEMOD_PRIORITY_BELOW_NORMAL, DEMOD_PRIORITY_LOW, DEMOD_PRIORITY_IDLE + }; + DemodulatorThreadQueue(wxEvtHandler* pParent); + + void addTask(const DemodulatorThreadTask& task, const DEMOD_PRIORITY& priority = DEMOD_PRIORITY_NORMAL); + void report(const DemodulatorThreadTask::DEMOD_THREAD_COMMAND& cmd, const wxString& sArg = wxEmptyString, int iArg = 0); + + DemodulatorThreadTask pop(); + size_t stackSize(); + + wxEvtHandler* getHandler(); + +private: + wxEvtHandler* m_pParent; + std::multimap m_Tasks; + wxMutex m_MutexQueue; + wxSemaphore m_QueueCount; +}; diff --git a/src/DemodulatorThreadTask.cpp b/src/DemodulatorThreadTask.cpp new file mode 100644 index 0000000..4728df0 --- /dev/null +++ b/src/DemodulatorThreadTask.cpp @@ -0,0 +1,8 @@ +#include "DemodulatorThreadTask.h" + +void DemodulatorThreadTask::setData(std::vector &data_in) { + data = data_in; +} +std::vector &DemodulatorThreadTask::getData() { + return data; +} diff --git a/src/DemodulatorThreadTask.h b/src/DemodulatorThreadTask.h new file mode 100644 index 0000000..03f2efd --- /dev/null +++ b/src/DemodulatorThreadTask.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include "wx/defs.h" +#include "wx/string.h" + +class DemodulatorThreadTask { +public: + enum DEMOD_THREAD_COMMAND { + DEMOD_THREAD_EXIT = wxID_EXIT, DEMOD_THREAD_NULL = wxID_HIGHEST + 1, DEMOD_THREAD_STARTED, DEMOD_THREAD_PROCESS, DEMOD_THREAD_ERROR, DEMOD_THREAD_DATA + }; + + DemodulatorThreadTask() : + m_cmd(DEMOD_THREAD_NULL) { + } + DemodulatorThreadTask(DEMOD_THREAD_COMMAND cmd) : + m_cmd(cmd) { + } + + void setData(std::vector &data_in); + std::vector &getData(); + + DEMOD_THREAD_COMMAND m_cmd; + + std::vector data; +};