diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 26b31e1..ac2f5d3 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -27,8 +27,9 @@ bool CubicSDR::OnInit() { threadAudio = new std::thread(&AudioThread::threadMain, audioThread); demodulatorTest = demodMgr.newThread(); - demodulatorTest->params.audioInputQueue = audioInputQueue; - demodulatorTest->init(); + demodulatorTest->getParams().audioInputQueue = audioInputQueue; + demodulatorTest->getParams().frequency = DEFAULT_FREQ; + demodulatorTest->run(); audioVisualQueue = new DemodulatorThreadOutputQueue(); demodulatorTest->setVisualOutputQueue(audioVisualQueue); @@ -87,6 +88,7 @@ PrimaryGLContext& CubicSDR::GetContext(wxGLCanvas *canvas) { void CubicSDR::setFrequency(unsigned int freq) { frequency = freq; +// demodulatorTest->getParams().frequency = freq; SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_TUNE); command.int_value = freq; threadCmdQueueSDR->push(command); diff --git a/src/CubicSDR.h b/src/CubicSDR.h index e767c7f..9f351d1 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -40,6 +40,10 @@ public: return demodulatorTest; } + DemodulatorMgr &getDemodMgr() { + return demodMgr; + } + private: PrimaryGLContext *m_glContext; diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp index 03a642c..a82fa4f 100644 --- a/src/demod/DemodulatorMgr.cpp +++ b/src/demod/DemodulatorMgr.cpp @@ -2,6 +2,12 @@ DemodulatorInstance::DemodulatorInstance() : t_Demod(NULL), threadQueueDemod(NULL), demodulatorThread(NULL) { + + threadQueueDemod = new DemodulatorThreadInputQueue; + threadQueueCommand = new DemodulatorThreadCommandQueue; + demodulatorThread = new DemodulatorThread(threadQueueDemod); + demodulatorThread->setCommandQueue(threadQueueCommand); + } DemodulatorInstance::~DemodulatorInstance() { @@ -14,20 +20,30 @@ void DemodulatorInstance::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQu demodulatorThread->setVisualOutputQueue(tQueue); } -void DemodulatorInstance::init() { - if (demodulatorThread) { +void DemodulatorInstance::run() { + if (t_Demod) { terminate(); delete threadQueueDemod; delete demodulatorThread; delete t_Demod; + + threadQueueDemod = new DemodulatorThreadInputQueue; + threadQueueCommand = new DemodulatorThreadCommandQueue; + demodulatorThread = new DemodulatorThread(threadQueueDemod); + demodulatorThread->setCommandQueue(threadQueueCommand); } - threadQueueDemod = new DemodulatorThreadInputQueue; - demodulatorThread = new DemodulatorThread(threadQueueDemod, ¶ms); - t_Demod = new std::thread(&DemodulatorThread::threadMain, demodulatorThread); } +DemodulatorThreadCommandQueue *DemodulatorInstance::getCommandQueue() { + return threadQueueCommand; +} + +DemodulatorThreadParameters &DemodulatorInstance::getParams() { + return demodulatorThread->getParams(); +} + void DemodulatorInstance::terminate() { demodulatorThread->terminate(); t_Demod->join(); @@ -55,3 +71,7 @@ void DemodulatorMgr::terminateAll() { delete d; } } + +std::vector &DemodulatorMgr::getDemodulators() { + return demods; +} diff --git a/src/demod/DemodulatorMgr.h b/src/demod/DemodulatorMgr.h index 5651ab6..4a2588f 100644 --- a/src/demod/DemodulatorMgr.h +++ b/src/demod/DemodulatorMgr.h @@ -11,12 +11,15 @@ public: std::thread *t_Demod; DemodulatorThreadInputQueue* threadQueueDemod; - DemodulatorThreadParameters params; + DemodulatorThreadCommandQueue* threadQueueCommand; DemodulatorInstance(); ~DemodulatorInstance(); void setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue); - void init(); + DemodulatorThreadCommandQueue *getCommandQueue(); + DemodulatorThreadParameters &getParams(); + + void run(); void terminate(); }; @@ -26,6 +29,7 @@ public: ~DemodulatorMgr(); DemodulatorInstance *newThread(); + std::vector &getDemodulators(); void terminateAll(); private: diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index b6be1d2..bfdb03d 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -2,21 +2,35 @@ #include "CubicSDRDefs.h" #include -DemodulatorThread::DemodulatorThread(DemodulatorThreadInputQueue* pQueue, DemodulatorThreadParameters *params_in) : - inputQueue(pQueue), visOutQueue(NULL), terminated(false) { +DemodulatorThread::DemodulatorThread(DemodulatorThreadInputQueue* pQueue) : + inputQueue(pQueue), visOutQueue(NULL), terminated(false), initialized(false), audio_resampler(NULL), resample_ratio(1), audio_resample_ratio( + 1), resampler(NULL), commandQueue(NULL), fir_filter(NULL) { - DemodulatorThreadParameters defaultParams; - if (!params_in) { - params = defaultParams; - } else { - params = *params_in; + float kf = 0.75; // modulation factor + fdem = freqdem_create(kf); +// freqdem_print(fdem); + + nco_shift = nco_crcf_create(LIQUID_VCO); + shift_freq = 0; + +} + +void DemodulatorThread::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; } - 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; + if (fc >= 0.5) { + fc = 0.5; + } - float fc = 0.5f * ((float) params.inputResampleRate / (float) params.inputRate) * 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 @@ -26,27 +40,29 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadInputQueue* pQueue, Demodu 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, (float) params.filterFrequency / (float) params.demodResampleRate, As, mu, h); - - fir_audio_filter = firfilt_crcf_create(h, h_len); + if (fir_filter) { + firfilt_crcf_recreate(fir_filter, h, h_len); + } else { + fir_filter = firfilt_crcf_create(h, h_len); + } // create multi-stage arbitrary resampler object + if (resampler) { + msresamp_crcf_destroy(resampler); + } resampler = msresamp_crcf_create(resample_ratio, As); - msresamp_crcf_print(resampler); - - second_resampler = msresamp_crcf_create(second_resampler_ratio, As); - msresamp_crcf_print(second_resampler); +// msresamp_crcf_print(resampler); + if (audio_resampler) { + msresamp_crcf_destroy(audio_resampler); + } audio_resampler = msresamp_crcf_create(audio_resample_ratio, As); - msresamp_crcf_print(audio_resampler); +// msresamp_crcf_print(audio_resampler); - float kf = 0.75; // modulation factor + initialized = true; +// std::cout << "inputResampleRate " << params.bandwidth << std::endl; - fdem = freqdem_create(kf); - freqdem_print(fdem); + last_params = params; } DemodulatorThread::~DemodulatorThread() { @@ -55,21 +71,84 @@ DemodulatorThread::~DemodulatorThread() { void DemodulatorThread::threadMain() { + if (!initialized) { + initialize(); + } + while (!terminated) { DemodulatorThreadIQData inp; inputQueue->pop(inp); + if (!commandQueue->empty()) { + bool paramsChanged = false; + while (!commandQueue->empty()) { + DemodulatorThreadCommand command; + commandQueue->pop(command); + switch (command.cmd) { + case DemodulatorThreadCommand::SDR_THREAD_CMD_SET_BANDWIDTH: + if (command.int_value < 3000) { + command.int_value = 3000; + } + if (command.int_value > SRATE) { + command.int_value = SRATE; + } + params.bandwidth = command.int_value; + paramsChanged = true; + break; + case DemodulatorThreadCommand::SDR_THREAD_CMD_SET_FREQUENCY: + params.frequency = command.int_value; + break; + } + } + + if (paramsChanged) { + initialize(); + while (!inputQueue->empty()) { // catch up + inputQueue->pop(inp); + } + } + } + + if (!initialized) { + continue; + } + + // Requested frequency is not center, shift it into the center! + if (inp.frequency != params.frequency) { + if ((params.frequency - inp.frequency) != shift_freq) { + shift_freq = params.frequency - inp.frequency; + 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))); + } + } + } + + if (abs(shift_freq) > (int)((float)(SRATE/2) * 1.5)) { + continue; + } + std::vector *data = &inp.data; if (data->size()) { liquid_float_complex filtered_input[BUF_SIZE / 2]; + liquid_float_complex x, y, z; + for (int i = 0; i < BUF_SIZE / 2; i++) { + if (shift_freq != 0) { + nco_crcf_step(nco_shift); - liquid_float_complex x; - liquid_float_complex y; + z.real = (float) (*data)[i * 2] / 127.0f; + z.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; + if (shift_freq < 0) { + nco_crcf_mix_up(nco_shift, z, &x); + } else { + nco_crcf_mix_down(nco_shift, z, &x); + } + } else { + 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 @@ -103,22 +182,11 @@ void DemodulatorThread::threadMain() { } } - int wbfm_out_size = ceil((float) (num_written) * second_resampler_ratio); - liquid_float_complex resampled_wbfm_output[wbfm_out_size]; - - unsigned int num_wbfm_written; - msresamp_crcf_execute(second_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); + 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_wbfm_output, num_wbfm_written, resampled_audio_output, &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); diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h index 3aed769..163ea26 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorThread.h @@ -16,9 +16,30 @@ #include "CubicSDRDefs.h" enum DemodulatorType { - DEMOD_TYPE_NULL, DEMOD_TYPE_AM, DEMOD_TYPE_FM, DEMOD_TYPE_LSB, DEMOD_TYPE_USB, DEMOD_TYPE_WFM + DEMOD_TYPE_NULL, DEMOD_TYPE_AM, DEMOD_TYPE_FM, DEMOD_TYPE_LSB, DEMOD_TYPE_USB }; +class DemodulatorThreadCommand { +public: + enum DemodulatorThreadCommandEnum { + SDR_THREAD_CMD_NULL, + SDR_THREAD_CMD_SET_BANDWIDTH, + SDR_THREAD_CMD_SET_FREQUENCY + }; + + DemodulatorThreadCommand() : cmd(cmd), int_value(SDR_THREAD_CMD_NULL) { + + } + + DemodulatorThreadCommand(DemodulatorThreadCommandEnum cmd) : cmd(cmd), int_value(0) { + + } + + DemodulatorThreadCommandEnum cmd; + int int_value; +}; + + class DemodulatorThreadIQData { public: unsigned int frequency; @@ -65,18 +86,16 @@ public: class DemodulatorThreadParameters { public: + unsigned int frequency; unsigned int inputRate; - unsigned int inputResampleRate; // set equal to disable second stage re-sampling? - unsigned int demodResampleRate; - unsigned int filterFrequency; + unsigned int bandwidth; // set equal to disable second stage re-sampling? unsigned int audioSampleRate; AudioThreadInputQueue *audioInputQueue; DemodulatorType demodType; DemodulatorThreadParameters() : - audioInputQueue(NULL), inputRate(SRATE), inputResampleRate(200000), demodResampleRate(100000), audioSampleRate(AUDIO_FREQUENCY), filterFrequency( - 32000), demodType(DEMOD_TYPE_WFM) { + frequency(0), audioInputQueue(NULL), inputRate(SRATE), bandwidth(200000), audioSampleRate(AUDIO_FREQUENCY), demodType(DEMOD_TYPE_FM) { } @@ -87,11 +106,12 @@ public: typedef ThreadQueue DemodulatorThreadInputQueue; typedef ThreadQueue DemodulatorThreadOutputQueue; +typedef ThreadQueue DemodulatorThreadCommandQueue; class DemodulatorThread { public: - DemodulatorThread(DemodulatorThreadInputQueue* pQueue, DemodulatorThreadParameters *params); + DemodulatorThread(DemodulatorThreadInputQueue* pQueue); ~DemodulatorThread(); void threadMain(); @@ -101,26 +121,39 @@ public: visOutQueue->set_max_num_items(1); } + void setCommandQueue(DemodulatorThreadCommandQueue *tQueue) { + commandQueue = tQueue; + } + + DemodulatorThreadParameters &getParams() { + return params; + } + + void initialize(); + void terminate(); protected: DemodulatorThreadInputQueue* inputQueue; DemodulatorThreadOutputQueue* visOutQueue; + DemodulatorThreadCommandQueue* commandQueue; firfilt_crcf fir_filter; - firfilt_crcf fir_audio_filter; msresamp_crcf resampler; float resample_ratio; - msresamp_crcf second_resampler; - float second_resampler_ratio; - msresamp_crcf audio_resampler; float audio_resample_ratio; DemodulatorThreadParameters params; + DemodulatorThreadParameters last_params; + freqdem fdem; + nco_crcf nco_shift; + int shift_freq; + std::atomic terminated; + std::atomic initialized; }; diff --git a/src/demod/DemodulatorThreadQueue.cpp b/src/demod/DemodulatorThreadQueue.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/demod/DemodulatorThreadQueue.h b/src/demod/DemodulatorThreadQueue.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/demod/DemodulatorThreadTask.cpp b/src/demod/DemodulatorThreadTask.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/demod/DemodulatorThreadTask.h b/src/demod/DemodulatorThreadTask.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/util/MouseTracker.cpp b/src/util/MouseTracker.cpp index 3c4a7a7..59819ed 100644 --- a/src/util/MouseTracker.cpp +++ b/src/util/MouseTracker.cpp @@ -15,17 +15,23 @@ void MouseTracker::OnMouseMoved(wxMouseEvent& event) { deltaMouseY = mouseY - lastMouseY; if (isMouseDown) { - lastMouseX = mouseX; - - if (vertDragLock && mouseY != lastMouseY) { - target->WarpPointer(event.m_x, lastMouseY * ClientSize.y); - } else { - lastMouseY = mouseY; +#ifndef __APPLE__ + if (horizDragLock && vertDragLock) { + target->WarpPointer(originMouseX * ClientSize.x, originMouseY * ClientSize.y); + mouseX = originMouseX; + mouseY = originMouseY; + } else if (vertDragLock && mouseY != lastMouseY) { + target->WarpPointer(event.m_x, originMouseY * ClientSize.y); + mouseY = originMouseY; + } else if (horizDragLock && mouseX != lastMouseX) { + target->WarpPointer(originMouseX * ClientSize.x, event.m_y); + mouseX = originMouseX; } - } else { - lastMouseY = mouseY; - lastMouseX = mouseX; +#endif } + + lastMouseX = mouseX; + lastMouseY = mouseY; } void MouseTracker::OnMouseDown(wxMouseEvent& event) { @@ -105,6 +111,10 @@ void MouseTracker::setVertDragLock(bool dragLock) { vertDragLock = dragLock; } +void MouseTracker::setHorizDragLock(bool dragLock) { + horizDragLock = dragLock; +} + bool MouseTracker::mouseDown() { return isMouseDown; } diff --git a/src/util/MouseTracker.h b/src/util/MouseTracker.h index 9e00b41..dad15a3 100644 --- a/src/util/MouseTracker.h +++ b/src/util/MouseTracker.h @@ -6,13 +6,13 @@ class MouseTracker { public: MouseTracker(wxWindow *target) : target(target), mouseX(0), mouseY(0), lastMouseX(0), lastMouseY(0), originMouseX(0), originMouseY(0), deltaMouseX(0), deltaMouseY(0), isMouseDown( - false), vertDragLock(false), isMouseInView(false) { + false), vertDragLock(false), horizDragLock(false), isMouseInView(false) { } MouseTracker() : target(NULL), mouseX(0), mouseY(0), lastMouseX(0), lastMouseY(0), originMouseX(0), originMouseY(0), deltaMouseX(0), deltaMouseY(0), isMouseDown( - false), vertDragLock(false), isMouseInView(false) { + false), vertDragLock(false), horizDragLock(false), isMouseInView(false) { } @@ -35,6 +35,7 @@ public: float getMouseY(); void setVertDragLock(bool dragLock); + void setHorizDragLock(bool dragLock); bool mouseDown(); bool mouseInView(); void setTarget(wxWindow *target_in); @@ -46,6 +47,6 @@ private: float originMouseX, originMouseY; bool isMouseDown, isMouseInView; - bool vertDragLock; + bool vertDragLock, horizDragLock; wxWindow *target; }; diff --git a/src/util/ThreadQueue.h b/src/util/ThreadQueue.h index 69b18d3..66dff2a 100644 --- a/src/util/ThreadQueue.h +++ b/src/util/ThreadQueue.h @@ -207,6 +207,15 @@ public: return m_queue.empty(); } + /** + * Remove any items in the queue. + */ + void flush() const { + std::lock_guard < std::mutex > lock(m_mutex); + std::queue emptyQueue; + std::swap(m_queue, emptyQueue); + } + /** * Swaps the contents. * \param[out] sq The ThreadQueue to swap with 'this'. diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 2b26167..cdf89ff 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -29,7 +29,7 @@ wxEND_EVENT_TABLE() WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, - wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0) { + wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0), bwChange(false), demodBW(0) { int in_block_size = BUF_SIZE / 2; int out_block_size = FFT_SIZE; @@ -45,7 +45,8 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : timer.start(); mTracker.setTarget(this); - + mTracker.setVertDragLock(true); + mTracker.setHorizDragLock(true); SetCursor(wxCURSOR_CROSS); } @@ -63,6 +64,12 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->BeginDraw(); glContext->Draw(spectrum_points); + std::vector *demods = &wxGetApp().getDemodMgr().getDemodulators(); + + for (int i = 0, iMax = demods->size(); i < iMax; i++) { + glContext->DrawDemod((*demods)[i]); + } + if (mTracker.mouseInView()) { glContext->DrawFreqSelector(mTracker.getMouseX()); } @@ -180,57 +187,90 @@ void WaterfallCanvas::OnIdle(wxIdleEvent &event) { void WaterfallCanvas::mouseMoved(wxMouseEvent& event) { mTracker.OnMouseMoved(event); + + DemodulatorInstance *demod = wxGetApp().getDemodTest(); + if (mTracker.mouseDown()) { - int freqChange = mTracker.getDeltaMouseX() * SRATE; + if (demod && mTracker.getDeltaMouseY()) { + int bwDiff = (int)(mTracker.getDeltaMouseY() * 100000.0); - if (freqChange != 0) { - int freq = wxGetApp().getFrequency(); - freq -= freqChange; - wxGetApp().setFrequency(freq); + if (!demodBW) { + demodBW = demod->getParams().bandwidth; + } - ((wxFrame*) parent)->GetStatusBar()->SetStatusText( - wxString::Format(wxT("Set center frequency: %s"), - wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep))); + DemodulatorThreadCommand command; + command.cmd = DemodulatorThreadCommand::SDR_THREAD_CMD_SET_BANDWIDTH; + demodBW = demodBW - bwDiff; + if (demodBW < 1000) { + demodBW = 1000; + } + if (demodBW > SRATE) { + demodBW = SRATE; + } + + command.int_value = demodBW; + demod->getCommandQueue()->push(command); + bwChange = true; } + +// int freqChange = mTracker.getDeltaMouseX() * SRATE; +// +// if (freqChange != 0) { +// int freq = wxGetApp().getFrequency(); +// freq -= freqChange; +// wxGetApp().setFrequency(freq); +// +// ((wxFrame*) parent)->GetStatusBar()->SetStatusText( +// wxString::Format(wxT("Set center frequency: %s"), +// wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep))); +// } } } void WaterfallCanvas::mouseDown(wxMouseEvent& event) { mTracker.OnMouseDown(event); - SetCursor(wxCURSOR_CROSS); + SetCursor(wxCURSOR_SIZENS); + bwChange = false; } void WaterfallCanvas::mouseWheelMoved(wxMouseEvent& event) { + DemodulatorInstance *demod = wxGetApp().getDemodTest(); mTracker.OnMouseWheelMoved(event); } void WaterfallCanvas::mouseReleased(wxMouseEvent& event) { mTracker.OnMouseReleased(event); - if (mTracker.getOriginDeltaMouseX() == 0 && mTracker.getOriginDeltaMouseX() == 0) { + if (mTracker.getOriginDeltaMouseX() == 0 && mTracker.getOriginDeltaMouseY() == 0 && !bwChange) { float pos = mTracker.getMouseX(); - int freq = wxGetApp().getFrequency(); + int center_freq = wxGetApp().getFrequency(); - freq += (pos - 0.5) * SRATE; + DemodulatorInstance *demod = wxGetApp().getDemodTest(); - wxGetApp().setFrequency(freq); + int freq = center_freq - (int)(0.5 * (float)SRATE) + (int)((float)pos * (float)SRATE); + + DemodulatorThreadCommand command; + command.cmd = DemodulatorThreadCommand::SDR_THREAD_CMD_SET_FREQUENCY; + command.int_value = freq; + + demod->getCommandQueue()->push(command); ((wxFrame*) parent)->GetStatusBar()->SetStatusText( wxString::Format(wxT("Set center frequency: %s"), wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep))); } - SetCursor(wxCURSOR_SIZEWE); + SetCursor(wxCURSOR_CROSS); } void WaterfallCanvas::mouseLeftWindow(wxMouseEvent& event) { mTracker.OnMouseLeftWindow(event); - SetCursor(wxCURSOR_SIZEWE); + SetCursor(wxCURSOR_CROSS); } void WaterfallCanvas::mouseEnterWindow(wxMouseEvent& event) { mTracker.OnMouseEnterWindow(event); - SetCursor(wxCURSOR_SIZEWE); + SetCursor(wxCURSOR_CROSS); } diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 7447be4..7d27f35 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -48,6 +48,8 @@ private: Timer timer; float frameTimer; MouseTracker mTracker; + bool bwChange; + int demodBW; // event table wxDECLARE_EVENT_TABLE(); diff --git a/src/visual/WaterfallContext.cpp b/src/visual/WaterfallContext.cpp index df10b1b..7c10522 100644 --- a/src/visual/WaterfallContext.cpp +++ b/src/visual/WaterfallContext.cpp @@ -82,14 +82,14 @@ void WaterfallContext::Draw(std::vector &points) { } -void WaterfallContext::DrawFreqSelector(float uxPos) { - DemodulatorInstance *demod = wxGetApp().getDemodTest(); - +void WaterfallContext::DrawDemod(DemodulatorInstance *demod) { if (!demod) { return; } - glClear(GL_DEPTH_BUFFER_BIT); + float uxPos = (float) (demod->getParams().frequency - (wxGetApp().getFrequency() - SRATE / 2)) / (float) SRATE; + + glDisable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); glColor3f(1.0, 1.0, 1.0); @@ -98,7 +98,7 @@ void WaterfallContext::DrawFreqSelector(float uxPos) { glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0); glVertex3f((uxPos - 0.5) * 2.0, -1.0, 0.0); - float ofs = ((float) demod->params.inputResampleRate) / (float) SRATE; + float ofs = ((float) demod->getParams().bandwidth) / (float) SRATE; glVertex3f((uxPos - 0.5) * 2.0 - ofs, 1.0, 0.0); glVertex3f((uxPos - 0.5) * 2.0 - ofs, -1.0, 0.0); @@ -107,6 +107,36 @@ void WaterfallContext::DrawFreqSelector(float uxPos) { glVertex3f((uxPos - 0.5) * 2.0 + ofs, -1.0, 0.0); glEnd(); + glEnable(GL_DEPTH_TEST); + +} + +void WaterfallContext::DrawFreqSelector(float uxPos) { + DemodulatorInstance *demod = wxGetApp().getDemodTest(); + + if (!demod) { + return; + } + + glDisable(GL_DEPTH_TEST); + glDisable(GL_TEXTURE_2D); + + glColor3f(1.0, 1.0, 1.0); + + glBegin(GL_LINES); + glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0, -1.0, 0.0); + + float ofs = ((float) demod->getParams().bandwidth) / (float) SRATE; + + glVertex3f((uxPos - 0.5) * 2.0 - ofs, 1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0 - ofs, -1.0, 0.0); + + glVertex3f((uxPos - 0.5) * 2.0 + ofs, 1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0 + ofs, -1.0, 0.0); + + glEnd(); + glEnable(GL_DEPTH_TEST); } diff --git a/src/visual/WaterfallContext.h b/src/visual/WaterfallContext.h index 0b8d0bb..176a420 100644 --- a/src/visual/WaterfallContext.h +++ b/src/visual/WaterfallContext.h @@ -2,6 +2,7 @@ #include "PrimaryGLContext.h" #include "Gradient.h" +#include "DemodulatorMgr.h" #define NUM_WATERFALL_LINES 512 @@ -14,6 +15,7 @@ public: void BeginDraw(); void Draw(std::vector &points); void DrawFreqSelector(float uxPos); + void DrawDemod(DemodulatorInstance *demod); void EndDraw(); private: