diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp index c50fe14..7510cc6 100644 --- a/src/AppConfig.cpp +++ b/src/AppConfig.cpp @@ -123,6 +123,8 @@ AppConfig::AppConfig() : configName("") { themeId.store(0); snap.store(1); centerFreq.store(100000000); + waterfallLinesPerSec.store(DEFAULT_WATERFALL_LPS); + spectrumAvgSpeed.store(0.65f); } @@ -204,6 +206,23 @@ long long AppConfig::getCenterFreq() { return centerFreq.load(); } + +void AppConfig::setWaterfallLinesPerSec(int lps) { + waterfallLinesPerSec.store(lps); +} + +int AppConfig::getWaterfallLinesPerSec() { + return waterfallLinesPerSec.load(); +} + +void AppConfig::setSpectrumAvgSpeed(float avgSpeed) { + spectrumAvgSpeed.store(avgSpeed); +} + +float AppConfig::getSpectrumAvgSpeed() { + return spectrumAvgSpeed.load(); +} + void AppConfig::setConfigName(std::string configName) { this->configName = configName; } @@ -243,6 +262,8 @@ bool AppConfig::save() { *window_node->newChild("theme") = themeId.load(); *window_node->newChild("snap") = snap.load(); *window_node->newChild("center_freq") = centerFreq.load(); + *window_node->newChild("waterfall_lps") = waterfallLinesPerSec.load(); + *window_node->newChild("spectrum_avg") = spectrumAvgSpeed.load(); } DataNode *devices_node = cfg.rootNode()->newChild("devices"); @@ -339,7 +360,19 @@ bool AppConfig::load() { win_node->getNext("center_freq")->element()->get(freqVal); centerFreq.store(freqVal); } -} + + if (win_node->hasAnother("waterfall_lps")) { + int lpsVal; + win_node->getNext("waterfall_lps")->element()->get(lpsVal); + waterfallLinesPerSec.store(lpsVal); + } + + if (win_node->hasAnother("spectrum_avg")) { + float avgVal; + win_node->getNext("spectrum_avg")->element()->get(avgVal); + spectrumAvgSpeed.store(avgVal); + } + } if (cfg.rootNode()->hasAnother("devices")) { DataNode *devices_node = cfg.rootNode()->getNext("devices"); diff --git a/src/AppConfig.h b/src/AppConfig.h index 10f1774..60de0c7 100644 --- a/src/AppConfig.h +++ b/src/AppConfig.h @@ -61,7 +61,13 @@ public: void setCenterFreq(long long freqVal); long long getCenterFreq(); - + + void setWaterfallLinesPerSec(int lps); + int getWaterfallLinesPerSec(); + + void setSpectrumAvgSpeed(float avgSpeed); + float getSpectrumAvgSpeed(); + void setConfigName(std::string configName); std::string getConfigFileName(bool ignoreName=false); bool save(); @@ -76,4 +82,6 @@ private: std::atomic_int themeId; std::atomic_llong snap; std::atomic_llong centerFreq; + std::atomic_int waterfallLinesPerSec; + std::atomic spectrumAvgSpeed; }; diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 826e40a..957651e 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -35,11 +35,10 @@ EVT_CLOSE(AppFrame::OnClose) EVT_MENU(wxID_ANY, AppFrame::OnMenu) EVT_COMMAND(wxID_ANY, wxEVT_THREAD, AppFrame::OnThread) EVT_IDLE(AppFrame::OnIdle) -EVT_TIMER(FRAME_TIMER_ID, AppFrame::OnTimer) wxEND_EVENT_TABLE() AppFrame::AppFrame() : - wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL), frame_timer(this, FRAME_TIMER_ID) { + wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL) { #ifdef __linux__ SetIcon(wxICON(cubicsdr)); @@ -63,8 +62,6 @@ AppFrame::AppFrame() : demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation, Amplitude Modulation and Lower, Upper or Double Side-Band."); demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0); -// demodTray->AddSpacer(2); - wxGetApp().getDemodSpectrumProcesor()->setup(1024); demodSpectrumCanvas = new SpectrumCanvas(this, attribList); demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000); @@ -109,23 +106,59 @@ AppFrame::AppFrame() : demodGainMeter = new MeterCanvas(this, attribList); demodGainMeter->setMax(2.0); demodGainMeter->setHelpTip("Current Demodulator Gain Level. Click / Drag to set Gain level."); + demodGainMeter->setShowUserInput(false); demodTray->Add(demodGainMeter, 1, wxEXPAND | wxALL, 0); vbox->Add(demodTray, 12, wxEXPAND | wxALL, 0); vbox->AddSpacer(1); + wxBoxSizer *spectrumSizer = new wxBoxSizer(wxHORIZONTAL); wxGetApp().getSpectrumProcesor()->setup(2048); spectrumCanvas = new SpectrumCanvas(this, attribList); - vbox->Add(spectrumCanvas, 5, wxEXPAND | wxALL, 0); - vbox->AddSpacer(1); wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue()); + + spectrumAvgMeter = new MeterCanvas(this, attribList); + spectrumAvgMeter->setHelpTip("Spectrum averaging speed, click or drag to adjust."); + spectrumAvgMeter->setMax(1.0); + spectrumAvgMeter->setLevel(0.65); + spectrumAvgMeter->setShowUserInput(false); + spectrumSizer->Add(spectrumCanvas, 63, wxEXPAND | wxALL, 0); + spectrumSizer->AddSpacer(1); + spectrumSizer->Add(spectrumAvgMeter, 1, wxEXPAND | wxALL, 0); + + vbox->Add(spectrumSizer, 5, wxEXPAND | wxALL, 0); + + vbox->AddSpacer(1); + + wxBoxSizer *wfSizer = new wxBoxSizer(wxHORIZONTAL); + + wxGetApp().getWaterfallProcesor()->setup(2048); waterfallCanvas = new WaterfallCanvas(this, attribList); waterfallCanvas->setup(2048, 512); + + fftDistrib.setInput(wxGetApp().getWaterfallVisualQueue()); + fftDistrib.attachOutput(&fftQueue); + + wxGetApp().getWaterfallProcesor()->setInput(&fftQueue); + wxGetApp().getWaterfallProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); + + waterfallSpeedMeter = new MeterCanvas(this, attribList); + waterfallSpeedMeter->setHelpTip("Waterfall speed, click or drag to adjust (max 1024 lines per second)"); + waterfallSpeedMeter->setMax(sqrt(1024)); + waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS)); + waterfallSpeedMeter->setShowUserInput(false); + + wfSizer->Add(waterfallCanvas, 63, wxEXPAND | wxALL, 0); + wfSizer->AddSpacer(1); + wfSizer->Add(waterfallSpeedMeter, 1, wxEXPAND | wxALL, 0); + + vbox->Add(wfSizer, 20, wxEXPAND | wxALL, 0); + + // TODO: refactor these.. waterfallCanvas->attachSpectrumCanvas(spectrumCanvas); spectrumCanvas->attachWaterfallCanvas(waterfallCanvas); - vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0); - wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); + /* vbox->AddSpacer(1); testCanvas = new UITestCanvas(this, attribList); @@ -334,6 +367,16 @@ AppFrame::AppFrame() : long long freqSnap = wxGetApp().getConfig()->getSnap(); wxGetApp().setFrequencySnap(freqSnap); + + float spectrumAvg = wxGetApp().getConfig()->getSpectrumAvgSpeed(); + + spectrumAvgMeter->setLevel(spectrumAvg); + wxGetApp().getSpectrumProcesor()->setFFTAverageRate(spectrumAvg); + + int wflps =wxGetApp().getConfig()->getWaterfallLinesPerSec(); + + waterfallSpeedMeter->setLevel(sqrt(wflps)); + fftDistrib.setLinesPerSecond(wflps); ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme()); @@ -351,8 +394,6 @@ AppFrame::AppFrame() : wxAcceleratorTable accel(3, entries); SetAcceleratorTable(accel); - // frame rate = 1000 / 30 = 33ms - frame_timer.Start(33); // static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; // wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not"); // ShowFullScreen(true); @@ -435,7 +476,22 @@ void AppFrame::OnMenu(wxCommandEvent& event) { } else if (event.GetId() == wxID_RESET) { wxGetApp().getDemodMgr().terminateAll(); wxGetApp().setFrequency(100000000); - wxGetApp().setOffset(0); + wxGetApp().getDemodMgr().setLastDemodulatorType(DEMOD_TYPE_FM); + demodModeSelector->setSelection(1); + wxGetApp().getDemodMgr().setLastStereo(false); + wxGetApp().getDemodMgr().setLastBandwidth(DEFAULT_DEMOD_BW); + wxGetApp().getDemodMgr().setLastGain(1.0); + wxGetApp().getDemodMgr().setLastSquelchLevel(0); + waterfallCanvas->setBandwidth(wxGetApp().getSampleRate()); + waterfallCanvas->setCenterFrequency(wxGetApp().getFrequency()); + spectrumCanvas->setBandwidth(wxGetApp().getSampleRate()); + spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); + fftDistrib.setLinesPerSecond(DEFAULT_WATERFALL_LPS); + waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS)); + wxGetApp().getSpectrumProcesor()->setFFTAverageRate(0.65); + spectrumAvgMeter->setLevel(0.65); + demodModeSelector->Refresh(); + demodTuner->Refresh(); SetTitle(CUBICSDR_TITLE); currentSessionFile = ""; } else if (event.GetId() == wxID_EXIT) { @@ -556,6 +612,8 @@ void AppFrame::OnClose(wxCloseEvent& event) { wxGetApp().getConfig()->setTheme(ThemeMgr::mgr.getTheme()); wxGetApp().getConfig()->setSnap(wxGetApp().getFrequencySnap()); wxGetApp().getConfig()->setCenterFreq(wxGetApp().getFrequency()); + wxGetApp().getConfig()->setSpectrumAvgSpeed(wxGetApp().getSpectrumProcesor()->getFFTAverageRate()); + wxGetApp().getConfig()->setWaterfallLinesPerSec(fftDistrib.getLinesPerSecond()); wxGetApp().getConfig()->save(); event.Skip(); } @@ -569,10 +627,6 @@ void AppFrame::OnThread(wxCommandEvent& event) { } void AppFrame::OnIdle(wxIdleEvent& event) { - event.Skip(); -} - -void AppFrame::OnTimer(wxTimerEvent& event) { DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); @@ -687,12 +741,20 @@ void AppFrame::OnTimer(wxTimerEvent& event) { wxGetApp().getScopeProcessor()->run(); wxGetApp().getSpectrumDistributor()->run(); - + SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor(); - proc->setView(waterfallCanvas->getViewState()); - proc->setBandwidth(waterfallCanvas->getBandwidth()); - proc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); + if (spectrumAvgMeter->inputChanged()) { + float val = spectrumAvgMeter->getInputValue(); + spectrumAvgMeter->setLevel(val); + proc->setFFTAverageRate(val); + + GetStatusBar()->SetStatusText(wxString::Format(wxT("Spectrum averaging speed changed to %0.2f%%."),val*100.0)); + } + + proc->setView(spectrumCanvas->getViewState()); + proc->setBandwidth(spectrumCanvas->getBandwidth()); + proc->setCenterFrequency(spectrumCanvas->getCenterFrequency()); proc->run(); @@ -704,25 +766,54 @@ void AppFrame::OnTimer(wxTimerEvent& event) { dproc->run(); - scopeCanvas->Refresh(); - - waterfallCanvas->Refresh(); - spectrumCanvas->Refresh(); - - demodWaterfallCanvas->Refresh(); - demodSpectrumCanvas->Refresh(); - - demodSignalMeter->Refresh(); - demodGainMeter->Refresh(); + SpectrumVisualProcessor *wproc = wxGetApp().getWaterfallProcesor(); - if (demodTuner->getMouseTracker()->mouseInView() || demodTuner->changed()) { - demodTuner->Refresh(); - } - if (demodModeSelector->getMouseTracker()->mouseInView()) { - demodModeSelector->Refresh(); + int fftSize = wproc->getDesiredInputSize(); + + if (fftSize) { + fftDistrib.setFFTSize(fftSize); + } else { + fftDistrib.setFFTSize(DEFAULT_FFT_SIZE); } - event.Skip(); + if (waterfallSpeedMeter->inputChanged()) { + float val = waterfallSpeedMeter->getInputValue(); + waterfallSpeedMeter->setLevel(val); + fftDistrib.setLinesPerSecond((int)ceil(val*val)); + wxGetApp().getWaterfallVisualQueue()->set_max_num_items((int)ceil(val*val)); + + GetStatusBar()->SetStatusText(wxString::Format(wxT("Waterfall max speed changed to %d lines per second."),(int)ceil(val*val))); + } + + fftDistrib.run(); + + wproc->setView(waterfallCanvas->getViewState()); + wproc->setBandwidth(waterfallCanvas->getBandwidth()); + wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); + + while (!wproc->isInputEmpty()) { + wproc->run(); + } + + waterfallCanvas->processInputQueue(); + demodWaterfallCanvas->processInputQueue(); + + + if (this->IsVisible()) { + waterfallCanvas->DoPaint(); + demodWaterfallCanvas->DoPaint(); +#ifdef __APPLE__ + usleep(5000); +#endif + } else { +#ifndef _WIN32 + usleep(15000); +#else + Sleep(15); +#endif + } + + event.RequestMore(); } void AppFrame::saveSession(std::string fileName) { diff --git a/src/AppFrame.h b/src/AppFrame.h index de90215..3531de5 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -50,8 +50,6 @@ #define wxID_AUDIO_BANDWIDTH_BASE 9000 #define wxID_AUDIO_DEVICE_MULTIPLIER 50 -#define FRAME_TIMER_ID 1000 - // Define a new frame type class AppFrame: public wxFrame { public: @@ -69,7 +67,6 @@ private: void OnClose(wxCloseEvent& event); void OnNewWindow(wxCommandEvent& event); void OnIdle(wxIdleEvent& event); - void OnTimer(wxTimerEvent& event); ScopeCanvas *scopeCanvas; SpectrumCanvas *spectrumCanvas; @@ -80,7 +77,9 @@ private: MeterCanvas *demodSignalMeter; MeterCanvas *demodGainMeter; TuningCanvas *demodTuner; - UITestCanvas *testCanvas; +// UITestCanvas *testCanvas; + MeterCanvas *spectrumAvgMeter; + MeterCanvas *waterfallSpeedMeter; DemodulatorInstance *activeDemodulator; @@ -94,7 +93,9 @@ private: wxMenuItem *iqSwapMenuItem; std::string currentSessionFile; - wxTimer frame_timer; + + FFTDataDistributor fftDistrib; + DemodulatorThreadInputQueue fftQueue; wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 3033b6e..2283d57 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -58,10 +58,13 @@ bool CubicSDR::OnInit() { spectrumDistributor.setInput(pipeIQVisualData); pipeDemodIQVisualData = new DemodulatorThreadInputQueue(); - pipeIQVisualData->set_max_num_items(1); + pipeDemodIQVisualData->set_max_num_items(1); pipeSpectrumIQVisualData = new DemodulatorThreadInputQueue(); - pipeIQVisualData->set_max_num_items(1); + pipeSpectrumIQVisualData->set_max_num_items(1); + + pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue(); + pipeWaterfallIQVisualData->set_max_num_items(DEFAULT_WATERFALL_LPS); spectrumDistributor.attachOutput(pipeDemodIQVisualData); spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); @@ -75,18 +78,21 @@ bool CubicSDR::OnInit() { scopeProcessor.setInput(pipeAudioVisualData); // I/Q Data - pipeSDRIQData = new SDRThreadIQDataQueue; + pipeSDRIQData = new SDRThreadIQDataQueue(); pipeSDRCommand = new SDRThreadCommandQueue(); + pipeSDRIQData->set_max_num_items(1); + sdrThread = new SDRThread(); sdrThread->setInputQueue("SDRCommandQueue",pipeSDRCommand); sdrThread->setOutputQueue("IQDataOutput",pipeSDRIQData); sdrPostThread = new SDRPostThread(); - sdrPostThread->setNumVisSamples(16384 * 2); + sdrPostThread->setNumVisSamples(BUF_SIZE); sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData); - sdrPostThread->setOutputQueue("IQVisualDataOut", pipeIQVisualData); - + sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData); + sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData); + std::vector::iterator devs_i; SDRThread::enumerate_rtl(&devs); @@ -276,6 +282,10 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcesor() { return &demodSpectrumProcessor; } +SpectrumVisualProcessor *CubicSDR::getWaterfallProcesor() { + return &waterfallProcessor; +} + VisualDataDistributor *CubicSDR::getSpectrumDistributor() { return &spectrumDistributor; } @@ -289,6 +299,10 @@ DemodulatorThreadInputQueue* CubicSDR::getIQVisualQueue() { return pipeIQVisualData; } +DemodulatorThreadInputQueue* CubicSDR::getWaterfallVisualQueue() { + return pipeWaterfallIQVisualData; +} + DemodulatorMgr &CubicSDR::getDemodMgr() { return demodMgr; } diff --git a/src/CubicSDR.h b/src/CubicSDR.h index c20d522..77dba79 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -58,10 +58,12 @@ public: ScopeVisualProcessor *getScopeProcessor(); SpectrumVisualProcessor *getSpectrumProcesor(); SpectrumVisualProcessor *getDemodSpectrumProcesor(); + SpectrumVisualProcessor *getWaterfallProcesor(); VisualDataDistributor *getSpectrumDistributor(); DemodulatorThreadOutputQueue* getAudioVisualQueue(); DemodulatorThreadInputQueue* getIQVisualQueue(); + DemodulatorThreadInputQueue* getWaterfallVisualQueue(); DemodulatorMgr &getDemodMgr(); void bindDemodulator(DemodulatorInstance *demod); @@ -101,9 +103,11 @@ private: DemodulatorThreadOutputQueue* pipeAudioVisualData; DemodulatorThreadInputQueue* pipeDemodIQVisualData; DemodulatorThreadInputQueue* pipeSpectrumIQVisualData; + DemodulatorThreadInputQueue* pipeWaterfallIQVisualData; ScopeVisualProcessor scopeProcessor; SpectrumVisualProcessor spectrumProcessor; + SpectrumVisualProcessor waterfallProcessor; SpectrumVisualProcessor demodSpectrumProcessor; VisualDataDistributor spectrumDistributor; diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index b9191d2..49df312 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -33,3 +33,4 @@ const char filePathSeparator = #define DEFAULT_DEMOD_TYPE 1 #define DEFAULT_DEMOD_BW 200000 +#define DEFAULT_WATERFALL_LPS 30 diff --git a/src/IOThread.h b/src/IOThread.h index 0b06f0a..743635c 100644 --- a/src/IOThread.h +++ b/src/IOThread.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "ThreadQueue.h" @@ -37,6 +38,8 @@ protected: }; +#define REBUFFER_GC_LIMIT 100 + template class ReBuffer { @@ -44,11 +47,27 @@ public: BufferType *getBuffer() { BufferType* buf = NULL; for (outputBuffersI = outputBuffers.begin(); outputBuffersI != outputBuffers.end(); outputBuffersI++) { - if ((*outputBuffersI)->getRefCount() <= 0) { - return (*outputBuffersI); + if (!buf && (*outputBuffersI)->getRefCount() <= 0) { + buf = (*outputBuffersI); + (*outputBuffersI)->setRefCount(0); + } else if ((*outputBuffersI)->getRefCount() <= 0) { + (*outputBuffersI)->decRefCount(); } } + if (buf) { + if (outputBuffers.back()->getRefCount() < -REBUFFER_GC_LIMIT) { + BufferType *ref = outputBuffers.back(); + outputBuffers.pop_back(); + delete ref; + } + return buf; + } + +// if (outputBuffers.size() > 100) { +// std::cout << "Buffer over 100.." << std::endl; +// } + buf = new BufferType(); outputBuffers.push_back(buf); diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index d987a15..becc261 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -94,7 +94,7 @@ void DemodulatorThread::run() { while (!terminated) { DemodulatorThreadPostIQData *inp; iqInputQueue->pop(inp); - std::lock_guard < std::mutex > lock(inp->m_mutex); +// std::lock_guard < std::mutex > lock(inp->m_mutex); int bufSize = inp->data.size(); diff --git a/src/panel/SpectrumPanel.cpp b/src/panel/SpectrumPanel.cpp index 4e33087..81f62f6 100644 --- a/src/panel/SpectrumPanel.cpp +++ b/src/panel/SpectrumPanel.cpp @@ -58,18 +58,18 @@ void SpectrumPanel::drawPanelContents() { if (points.size()) { glBlendFunc(GL_SRC_ALPHA, GL_ONE); - float range = ceilValue-floorValue; - float ranges[3][4] = { { 90.0, 5000.0, 10.0, 100.0 }, { 20.0, 150.0, 10.0, 10.0 }, { -20.0, 30.0, 10.0, 1.0 } }; + double range = ceilValue-floorValue; + double ranges[3][4] = { { 90.0, 5000.0, 10.0, 100.0 }, { 20.0, 150.0, 10.0, 10.0 }, { -20.0, 30.0, 10.0, 1.0 } }; for (int i = 0; i < 3; i++) { - float p = 0; - float rangeMin = ranges[i][0]; - float rangeMax = ranges[i][1]; - float rangeTrans = ranges[i][2]; - float rangeStep = ranges[i][3]; + double p = 0; + double rangeMin = ranges[i][0]; + double rangeMax = ranges[i][1]; + double rangeTrans = ranges[i][2]; + double rangeStep = ranges[i][3]; if (range >= rangeMin && range <= rangeMax) { - float a = 1.0; + double a = 1.0; if (range <= rangeMin+rangeTrans) { a *= (range-rangeMin)/rangeTrans; @@ -80,7 +80,7 @@ void SpectrumPanel::drawPanelContents() { glColor4f(0.12, 0.12, 0.12, a); glBegin(GL_LINES); - for (float l = floorValue; l<=ceilValue+rangeStep; l+=rangeStep) { + for (double l = floorValue; l<=ceilValue+rangeStep; l+=rangeStep) { p += rangeStep/range; glVertex2f(0,p); glVertex2f(1,p); } @@ -104,29 +104,34 @@ void SpectrumPanel::drawPanelContents() { float viewHeight = (float) vp[3]; float viewWidth = (float) vp[2]; - long long leftFreq = (float) freq - ((float) bandwidth / 2.0); - long long rightFreq = leftFreq + (float) bandwidth; + long long leftFreq = (double) freq - ((double) bandwidth / 2.0); + long long rightFreq = leftFreq + (double) bandwidth; long long firstMhz = (leftFreq / 1000000) * 1000000; long double mhzStart = ((long double) (firstMhz - leftFreq) / (long double) (rightFreq - leftFreq)) * 2.0; long double mhzStep = (100000.0 / (long double) (rightFreq - leftFreq)) * 2.0; - float mhzVisualStep = 0.1f; + double mhzVisualStep = 0.1f; + if (mhzStep * 0.5 * viewWidth < 40) { + mhzStep = (250000.0 / (long double) (rightFreq - leftFreq)) * 2.0; + mhzVisualStep = 0.25f; + } + if (mhzStep * 0.5 * viewWidth > 400) { mhzStep = (10000.0 / (long double) (rightFreq - leftFreq)) * 2.0; mhzVisualStep = 0.01f; } - + long double currentMhz = trunc(floor(firstMhz / 1000000.0)); std::stringstream label; label.precision(2); - float hPos = 1.0 - (16.0 / viewHeight); - float lMhzPos = 1.0 - (5.0 / viewHeight); + double hPos = 1.0 - (16.0 / viewHeight); + double lMhzPos = 1.0 - (5.0 / viewHeight); - for (float m = -1.0 + mhzStart, mMax = 1.0 + ((mhzStart>0)?mhzStart:-mhzStart); m <= mMax; m += mhzStep) { + for (double m = -1.0 + mhzStart, mMax = 1.0 + ((mhzStart>0)?mhzStart:-mhzStart); m <= mMax; m += mhzStep) { label << std::fixed << currentMhz; double fractpart, intpart; diff --git a/src/process/ScopeVisualProcessor.cpp b/src/process/ScopeVisualProcessor.cpp index 7439977..15669da 100644 --- a/src/process/ScopeVisualProcessor.cpp +++ b/src/process/ScopeVisualProcessor.cpp @@ -17,6 +17,7 @@ void ScopeVisualProcessor::process() { return; } + audioInputData->busy_update.lock(); ScopeRenderData *renderData = outputBuffers.getBuffer(); renderData->channels = audioInputData->channels; @@ -44,6 +45,8 @@ void ScopeVisualProcessor::process() { renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak; } } + distribute(renderData); + audioInputData->busy_update.unlock(); } } diff --git a/src/process/SpectrumVisualProcessor.cpp b/src/process/SpectrumVisualProcessor.cpp index 8defddc..06c65c2 100644 --- a/src/process/SpectrumVisualProcessor.cpp +++ b/src/process/SpectrumVisualProcessor.cpp @@ -14,6 +14,8 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), last fft_ceil_ma = fft_ceil_maa = 100.0; fft_floor_ma = fft_floor_maa = 0.0; + desiredInputSize = 0; + fft_average_rate = 0.65; } SpectrumVisualProcessor::~SpectrumVisualProcessor() { @@ -28,6 +30,13 @@ void SpectrumVisualProcessor::setView(bool bView) { is_view.store(bView); } +void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) { + this->fft_average_rate = fftAverageRate; +} + +float SpectrumVisualProcessor::getFFTAverageRate() { + return this->fft_average_rate; +} void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) { centerFreq.store(centerFreq_in); @@ -45,8 +54,13 @@ long SpectrumVisualProcessor::getBandwidth() { return bandwidth.load(); } +int SpectrumVisualProcessor::getDesiredInputSize() { + return desiredInputSize; +} + void SpectrumVisualProcessor::setup(int fftSize_in) { fftSize = fftSize_in; + desiredInputSize = fftSize; if (fftwInput) { free(fftwInput); @@ -83,6 +97,12 @@ void SpectrumVisualProcessor::process() { input->pop(iqData); + if (!iqData) { + return; + } + + iqData->busy_rw.lock(); + std::vector *data = &iqData->data; if (data && data->size()) { @@ -96,6 +116,8 @@ void SpectrumVisualProcessor::process() { if (is_view.load()) { if (!iqData->frequency || !iqData->sampleRate) { + iqData->decRefCount(); + iqData->busy_rw.unlock(); return; } @@ -103,6 +125,8 @@ void SpectrumVisualProcessor::process() { int desired_input_size = fftSize / resamplerRatio; + this->desiredInputSize = desired_input_size; + if (iqData->data.size() < desired_input_size) { // std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl; desired_input_size = iqData->data.size(); @@ -244,11 +268,11 @@ void SpectrumVisualProcessor::process() { for (int i = 0, iMax = fftSize; i < iMax; i++) { if (is_view.load()) { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; + fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate; + fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate; } else { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; + fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate; + fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate; } if (fft_result_maa[i] > fft_ceil) { @@ -280,5 +304,8 @@ void SpectrumVisualProcessor::process() { distribute(output); } - + + iqData->decRefCount(); + iqData->busy_rw.unlock(); } + diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index 6ffe848..fd7f013 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -3,6 +3,7 @@ #include "VisualProcessor.h" #include "DemodDefs.h" #include "fftw3.h" +#include class SpectrumVisualData : public ReferenceCounter { public: @@ -20,12 +21,17 @@ public: bool isView(); void setView(bool bView); + void setFFTAverageRate(float fftAverageRate); + float getFFTAverageRate(); + void setCenterFrequency(long long centerFreq_in); long long getCenterFrequency(); void setBandwidth(long bandwidth_in); long getBandwidth(); + int getDesiredInputSize(); + void setup(int fftSize); protected: @@ -45,12 +51,13 @@ private: unsigned int lastDataSize; fftwf_plan fftw_plan; - float fft_ceil_ma, fft_ceil_maa; - float fft_floor_ma, fft_floor_maa; + double fft_ceil_ma, fft_ceil_maa; + double fft_floor_ma, fft_floor_maa; + float fft_average_rate; - std::vector fft_result; - std::vector fft_result_ma; - std::vector fft_result_maa; + std::vector fft_result; + std::vector fft_result_ma; + std::vector fft_result_maa; msresamp_crcf resampler; double resamplerRatio; @@ -59,4 +66,74 @@ private: std::vector shiftBuffer; std::vector resampleBuffer; + int desiredInputSize; +}; + + +class FFTDataDistributor : public VisualProcessor { +public: + FFTDataDistributor() : linesPerSecond(DEFAULT_WATERFALL_LPS), lineRateAccum(0.0) { + } + + void setFFTSize(int fftSize) { + this->fftSize = fftSize; + } + + void setLinesPerSecond(int lines) { + this->linesPerSecond = lines; + } + + int getLinesPerSecond() { + return this->linesPerSecond; + } +protected: + void process() { + while (!input->empty()) { + if (!isAnyOutputEmpty()) { + return; + } + DemodulatorThreadIQData *inp; + input->pop(inp); + + int fftSize = this->fftSize; + + if (fftSize > inp->data.size()) { + fftSize = inp->data.size(); + } + + // number of milliseconds contained in input + double inputTime = (double)inp->data.size() / (double)inp->sampleRate; + // number of lines in input + int inputLines = floor((double)inp->data.size()/(double)fftSize); + + // ratio required to achieve the desired rate + double lineRateStep = ((double)linesPerSecond * inputTime)/(double)inputLines; + + if (inp) { + if (inp->data.size() >= fftSize) { + for (int i = 0, iMax = inp->data.size()-fftSize; i <= iMax; i += fftSize) { + lineRateAccum += lineRateStep; + + if (lineRateAccum >= 1.0) { + DemodulatorThreadIQData *outp = outputBuffers.getBuffer(); + outp->frequency = inp->frequency; + outp->sampleRate = inp->sampleRate; + outp->data.assign(inp->data.begin()+i,inp->data.begin()+i+fftSize); + distribute(outp); + + while (lineRateAccum >= 1.0) { + lineRateAccum -= 1.0; + } + } + } + } + inp->decRefCount(); + } + } + } + + ReBuffer outputBuffers; + int fftSize; + int linesPerSecond; + double lineRateAccum; }; diff --git a/src/process/VisualProcessor.h b/src/process/VisualProcessor.h index 1f02bbe..b7662bf 100644 --- a/src/process/VisualProcessor.h +++ b/src/process/VisualProcessor.h @@ -11,6 +11,28 @@ public: virtual ~VisualProcessor() { } + + bool isInputEmpty() { + return input->empty(); + } + + bool isOutputEmpty() { + for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) { + if ((*outputs_i)->full()) { + return false; + } + } + return true; + } + + bool isAnyOutputEmpty() { + for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) { + if (!(*outputs_i)->full()) { + return true; + } + } + return false; + } void setInput(ThreadQueue *vis_in) { busy_update.lock(); @@ -60,24 +82,6 @@ protected: } } } - - bool isOutputEmpty() { - for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) { - if (!(*outputs_i)->empty()) { - return false; - } - } - return true; - } - - bool isAnyOutputEmpty() { - for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) { - if ((*outputs_i)->empty()) { - return true; - } - } - return false; - } ThreadQueue *input; std::vector *> outputs; @@ -90,10 +94,10 @@ template class VisualDataDistributor : public VisualProcessor { protected: void process() { - if (!VisualProcessor::isOutputEmpty()) { - return; - } while (!VisualProcessor::input->empty()) { + if (!VisualProcessor::isAnyOutputEmpty()) { + return; + } OutputDataType *inp; VisualProcessor::input->pop(inp); if (inp) { diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 3ceac05..e4a9d2b 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -76,24 +76,25 @@ void SDRPostThread::run() { dcFilter = iirfilt_crcf_create_dc_blocker(0.0005); - DemodulatorThreadIQData *visualDataOut = new DemodulatorThreadIQData; - std::cout << "SDR post-processing thread started.." << std::endl; iqDataInQueue = (SDRThreadIQDataQueue*)getInputQueue("IQDataInput"); iqDataOutQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQDataOutput"); - iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOut"); + iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOutput"); ReBuffer buffers; std::vector fpData; std::vector dataOut; - + + iqDataInQueue->set_max_num_items(0); + while (!terminated) { SDRThreadIQData *data_in; - + iqDataInQueue->pop(data_in); -// std::lock_guard < std::mutex > lock(data_in->m_mutex); - + // std::lock_guard < std::mutex > lock(data_in->m_mutex); + int num_vis_samples = this->num_vis_samples; + if (data_in && data_in->data.size()) { int dataSize = data_in->data.size()/2; if (dataSize > fpData.capacity()) { @@ -104,7 +105,7 @@ void SDRPostThread::run() { fpData.resize(dataSize); dataOut.resize(dataSize); } - + if (swapIQ) { for (int i = 0; i < dataSize; i++) { fpData[i] = _lut_swap[*((uint16_t*)&data_in->data[2*i])]; @@ -114,21 +115,16 @@ void SDRPostThread::run() { fpData[i] = _lut[*((uint16_t*)&data_in->data[2*i])]; } } - + iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]); - - if (iqDataOutQueue != NULL) { - DemodulatorThreadIQData *pipeDataOut = new DemodulatorThreadIQData; - - pipeDataOut->frequency = data_in->frequency; - pipeDataOut->sampleRate = data_in->sampleRate; - pipeDataOut->data.assign(dataOut.begin(), dataOut.end()); - iqDataOutQueue->push(pipeDataOut); - } - + if (iqVisualQueue != NULL && iqVisualQueue->empty()) { - - visualDataOut->busy_rw.lock(); + DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer(); + visualDataOut->setRefCount(1); + + if (num_vis_samples > dataOut.size()) { + num_vis_samples = dataOut.size(); + } if (visualDataOut->data.size() < num_vis_samples) { if (visualDataOut->data.capacity() < num_vis_samples) { @@ -136,84 +132,90 @@ void SDRPostThread::run() { } visualDataOut->data.resize(num_vis_samples); } - + visualDataOut->frequency = data_in->frequency; visualDataOut->sampleRate = data_in->sampleRate; visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples); - + iqVisualQueue->push(visualDataOut); - - visualDataOut->busy_rw.unlock(); } busy_demod.lock(); - + int activeDemods = 0; bool pushedData = false; - - if (demodulators.size()) { - - std::vector::iterator i; - for (i = demodulators.begin(); i != demodulators.end(); i++) { - DemodulatorInstance *demod = *i; + + if (demodulators.size() || iqDataOutQueue != NULL) { + std::vector::iterator demod_i; + for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) { + DemodulatorInstance *demod = *demod_i; if (demod->getFrequency() != data_in->frequency - && abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) { + && abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) { continue; } activeDemods++; } - - if (demodulators.size()) { - - DemodulatorThreadIQData *demodDataOut = buffers.getBuffer(); - -// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex); - demodDataOut->frequency = data_in->frequency; - demodDataOut->sampleRate = data_in->sampleRate; - demodDataOut->setRefCount(activeDemods); - demodDataOut->data.assign(dataOut.begin(), dataOut.end()); - - std::vector::iterator i; - for (i = demodulators.begin(); i != demodulators.end(); i++) { - DemodulatorInstance *demod = *i; - DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe(); - - if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) { - if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) { - demod->setActive(false); - DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData; - dummyDataOut->frequency = data_in->frequency; - dummyDataOut->sampleRate = data_in->sampleRate; - demodQueue->push(dummyDataOut); - } - - if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) { - wxGetApp().setFrequency(demod->getFrequency()); - } - } else if (!demod->isActive()) { - demod->setActive(true); - if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) { - wxGetApp().getDemodMgr().setActiveDemodulator(demod); - } + + if (iqDataOutQueue != NULL) { + activeDemods++; + } + + DemodulatorThreadIQData *demodDataOut = buffers.getBuffer(); + + // std::lock_guard < std::mutex > lock(demodDataOut->m_mutex); + demodDataOut->frequency = data_in->frequency; + demodDataOut->sampleRate = data_in->sampleRate; + demodDataOut->setRefCount(activeDemods); + demodDataOut->data.assign(dataOut.begin(), dataOut.end()); + + for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) { + DemodulatorInstance *demod = *demod_i; + DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe(); + + if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) { + if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) { + demod->setActive(false); + DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData; + dummyDataOut->frequency = data_in->frequency; + dummyDataOut->sampleRate = data_in->sampleRate; + demodQueue->push(dummyDataOut); } - - if (!demod->isActive()) { - continue; + + if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) { + wxGetApp().setFrequency(demod->getFrequency()); } - if (demod->isFollow()) { - demod->setFollow(false); + } else if (!demod->isActive()) { + demod->setActive(true); + if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) { + wxGetApp().getDemodMgr().setActiveDemodulator(demod); } - - demodQueue->push(demodDataOut); - pushedData = true; } - - if (!pushedData) { - demodDataOut->setRefCount(0); + + if (!demod->isActive()) { + continue; + } + if (demod->isFollow()) { + demod->setFollow(false); + } + + demodQueue->push(demodDataOut); + pushedData = true; + } + + if (iqDataOutQueue != NULL) { + if (!iqDataOutQueue->full()) { + iqDataOutQueue->push(demodDataOut); + pushedData = true; + } else { + demodDataOut->decRefCount(); } } + + if (!pushedData && iqDataOutQueue == NULL) { + demodDataOut->setRefCount(0); + } } - + busy_demod.unlock(); } data_in->decRefCount(); @@ -226,7 +228,7 @@ void SDRPostThread::run() { iqVisualQueue->pop(visualDataDummy); } - delete visualDataOut; + visualDataBuffers.purge(); std::cout << "SDR post-processing thread done." << std::endl; } diff --git a/src/sdr/SDRPostThread.h b/src/sdr/SDRPostThread.h index f97e24f..e08ab58 100644 --- a/src/sdr/SDRPostThread.h +++ b/src/sdr/SDRPostThread.h @@ -30,6 +30,8 @@ protected: iirfilt_crcf dcFilter; int num_vis_samples; std::atomic_bool swapIQ; + ReBuffer visualDataBuffers; + private: std::vector _lut; diff --git a/src/util/GLExt.cpp b/src/util/GLExt.cpp index 47ccfdf..eb1e7d6 100644 --- a/src/util/GLExt.cpp +++ b/src/util/GLExt.cpp @@ -36,7 +36,11 @@ void initGLExtensions() { std::cout << std::endl << "Supported GL Extensions: " << std::endl << extensions << std::endl << std::endl; +#ifdef __linux__ + const GLint interval = 2; +#else const GLint interval = 1; +#endif #ifdef _WIN32 if (GLExtSupported("WGL_EXT_swap_control")) { diff --git a/src/visual/MeterCanvas.cpp b/src/visual/MeterCanvas.cpp index 423fc20..46153a0 100644 --- a/src/visual/MeterCanvas.cpp +++ b/src/visual/MeterCanvas.cpp @@ -25,7 +25,7 @@ EVT_ENTER_WINDOW(MeterCanvas::OnMouseEnterWindow) wxEND_EVENT_TABLE() MeterCanvas::MeterCanvas(wxWindow *parent, int *attribList) : - InteractiveCanvas(parent, attribList), level(0), level_max(1), inputValue(0), userInputValue(0) { + InteractiveCanvas(parent, attribList), level(0), level_max(1), inputValue(0), userInputValue(0), showUserInput(true) { glContext = new MeterContext(this, &wxGetApp().GetContext(this)); } @@ -58,6 +58,10 @@ float MeterCanvas::getInputValue() { return userInputValue; } +void MeterCanvas::setShowUserInput(bool showUserInput) { + this->showUserInput = showUserInput; +} + void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); const wxSize ClientSize = GetClientSize(); @@ -68,18 +72,23 @@ void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glViewport(0, 0, ClientSize.x, ClientSize.y); glContext->DrawBegin(); + glContext->Draw(ThemeMgr::mgr.currentTheme->generalBackground.r, ThemeMgr::mgr.currentTheme->generalBackground.g, ThemeMgr::mgr.currentTheme->generalBackground.b, 0.5, 1.0); + if (mouseTracker.mouseInView()) { glContext->Draw(0.4, 0.4, 0.4, 0.5, mouseTracker.getMouseY()); } glContext->Draw(ThemeMgr::mgr.currentTheme->meterLevel.r, ThemeMgr::mgr.currentTheme->meterLevel.g, ThemeMgr::mgr.currentTheme->meterLevel.b, 0.5, level / level_max); - glContext->Draw(ThemeMgr::mgr.currentTheme->meterValue.r, ThemeMgr::mgr.currentTheme->meterValue.g, ThemeMgr::mgr.currentTheme->meterValue.b, 0.5, userInputValue / level_max); + if (showUserInput) { + glContext->Draw(ThemeMgr::mgr.currentTheme->meterValue.r, ThemeMgr::mgr.currentTheme->meterValue.g, ThemeMgr::mgr.currentTheme->meterValue.b, 0.5, userInputValue / level_max); + } glContext->DrawEnd(); SwapBuffers(); } void MeterCanvas::OnIdle(wxIdleEvent &event) { - event.Skip(); + Refresh(); + event.RequestMore(); } void MeterCanvas::OnMouseMoved(wxMouseEvent& event) { diff --git a/src/visual/MeterCanvas.h b/src/visual/MeterCanvas.h index a6968b1..0cc97cd 100644 --- a/src/visual/MeterCanvas.h +++ b/src/visual/MeterCanvas.h @@ -26,6 +26,7 @@ public: void setInputValue(float slider_in); bool inputChanged(); float getInputValue(); + void setShowUserInput(bool showUserInput); void setHelpTip(std::string tip); @@ -48,6 +49,8 @@ private: float inputValue; float userInputValue; + bool showUserInput; + std::string helpTip; // wxDECLARE_EVENT_TABLE(); diff --git a/src/visual/ModeSelectorCanvas.cpp b/src/visual/ModeSelectorCanvas.cpp index 98172b5..5058291 100644 --- a/src/visual/ModeSelectorCanvas.cpp +++ b/src/visual/ModeSelectorCanvas.cpp @@ -72,7 +72,8 @@ void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void ModeSelectorCanvas::OnIdle(wxIdleEvent &event) { - event.Skip(); + Refresh(); + event.RequestMore(); } void ModeSelectorCanvas::OnMouseMoved(wxMouseEvent& event) { diff --git a/src/visual/ScopeCanvas.cpp b/src/visual/ScopeCanvas.cpp index 1063c16..a4cd4be 100644 --- a/src/visual/ScopeCanvas.cpp +++ b/src/visual/ScopeCanvas.cpp @@ -87,7 +87,8 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void ScopeCanvas::OnIdle(wxIdleEvent &event) { - event.Skip(); + Refresh(); + event.RequestMore(); } ScopeRenderDataQueue *ScopeCanvas::getInputQueue() { diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index c9df1f0..f21a6a8 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -32,7 +32,8 @@ SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) : glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this)); mouseTracker.setVertDragLock(true); - + visualDataQueue.set_max_num_items(1); + SetCursor(wxCURSOR_SIZEWE); } @@ -84,7 +85,8 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { void SpectrumCanvas::OnIdle(wxIdleEvent &event) { - event.Skip(); + Refresh(); + event.RequestMore(); } diff --git a/src/visual/TuningCanvas.cpp b/src/visual/TuningCanvas.cpp index cb618f6..8a85ac4 100644 --- a/src/visual/TuningCanvas.cpp +++ b/src/visual/TuningCanvas.cpp @@ -252,6 +252,10 @@ void TuningCanvas::OnIdle(wxIdleEvent &event) { dragging = false; } } + if (mouseTracker.mouseInView() || changed()) { + Refresh(); + } + event.RequestMore(); } void TuningCanvas::OnMouseMoved(wxMouseEvent& event) { diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index a5269e2..00bc773 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -68,8 +68,32 @@ void WaterfallCanvas::attachSpectrumCanvas(SpectrumCanvas *canvas_in) { spectrumCanvas = canvas_in; } +void WaterfallCanvas::processInputQueue() { + if (!glContext) { + return; + } + glContext->SetCurrent(*this); + + while (!visualDataQueue.empty()) { + SpectrumVisualData *vData; + + visualDataQueue.pop(vData); + + if (vData) { + waterfallPanel.setPoints(vData->spectrum_points); + waterfallPanel.step(); + vData->decRefCount(); + } + } +} + void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { - wxPaintDC dc(this); +// event.Skip(); +} + +void WaterfallCanvas::DoPaint() { + wxClientDC dc(this); + // wxPaintDC dc(this); const wxSize ClientSize = GetClientSize(); long double currentZoom = zoom; @@ -90,8 +114,8 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { centerFreq = getCenterFrequency(); bw = getBandwidth(); bw = (long long) ceil((long double) bw * currentZoom); - if (bw < 100000) { - bw = 100000; + if (bw < 30000) { + bw = 30000; } if (mouseTracker.mouseInView()) { long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); @@ -139,18 +163,6 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->SetCurrent(*this); initGLExtensions(); glViewport(0, 0, ClientSize.x, ClientSize.y); - - if (!visualDataQueue.empty()) { - SpectrumVisualData *vData; - - visualDataQueue.pop(vData); - - if (vData) { - waterfallPanel.setPoints(vData->spectrum_points); - waterfallPanel.step(); - vData->decRefCount(); - } - } glContext->BeginDraw(0,0,0); @@ -347,6 +359,8 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { +// Refresh(); +// event.RequestMore(); event.Skip(); } diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index b570ffb..1b59e35 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -26,7 +26,9 @@ public: DragState getNextDragState(); void attachSpectrumCanvas(SpectrumCanvas *canvas_in); + void processInputQueue(); SpectrumVisualDataQueue *getVisualDataQueue(); + void DoPaint(); private: void OnPaint(wxPaintEvent& event);