From 0802f7b756dd5c074bab576432140e274a1ea123 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Aug 2015 00:50:43 -0400 Subject: [PATCH 01/23] Experimenting with max speed waterfall (no dropped FFTs :) - FFT Detail from zoomed-in views is greatly improved with the additional data --- src/AppFrame.cpp | 35 +++++- src/AppFrame.h | 3 + src/CubicSDR.cpp | 15 ++- src/CubicSDR.h | 4 + src/process/SpectrumVisualProcessor.cpp | 12 +- src/process/SpectrumVisualProcessor.h | 37 ++++++ src/process/VisualProcessor.h | 46 ++++---- src/sdr/SDRPostThread.cpp | 145 ++++++++++++------------ src/visual/WaterfallCanvas.cpp | 2 +- 9 files changed, 195 insertions(+), 104 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 826e40a..9bc7183 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -120,12 +120,18 @@ AppFrame::AppFrame() : vbox->AddSpacer(1); wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue()); + wxGetApp().getWaterfallProcesor()->setup(2048); waterfallCanvas = new WaterfallCanvas(this, attribList); waterfallCanvas->setup(2048, 512); waterfallCanvas->attachSpectrumCanvas(spectrumCanvas); spectrumCanvas->attachWaterfallCanvas(waterfallCanvas); vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0); - wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); +// wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); + fftDistrib.setInput(wxGetApp().getWaterfallVisualQueue()); + fftDistrib.attachOutput(&fftQueue); + wxGetApp().getWaterfallProcesor()->setInput(&fftQueue); + wxGetApp().getWaterfallProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); + /* vbox->AddSpacer(1); testCanvas = new UITestCanvas(this, attribList); @@ -690,9 +696,9 @@ void AppFrame::OnTimer(wxTimerEvent& event) { SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor(); - proc->setView(waterfallCanvas->getViewState()); - proc->setBandwidth(waterfallCanvas->getBandwidth()); - proc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); + proc->setView(spectrumCanvas->getViewState()); + proc->setBandwidth(spectrumCanvas->getBandwidth()); + proc->setCenterFrequency(spectrumCanvas->getCenterFrequency()); proc->run(); @@ -704,6 +710,27 @@ void AppFrame::OnTimer(wxTimerEvent& event) { dproc->run(); + SpectrumVisualProcessor *wproc = wxGetApp().getWaterfallProcesor(); + + int fftSize = wproc->getDesiredInputSize(); + + if (fftSize) { + fftDistrib.setFFTSize(fftSize); + } else { + fftDistrib.setFFTSize(DEFAULT_FFT_SIZE); + } + + fftDistrib.run(); + + wproc->setView(waterfallCanvas->getViewState()); + wproc->setBandwidth(waterfallCanvas->getBandwidth()); + wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); + + while (!wproc->isInputEmpty()) { + wproc->run(); + } + + scopeCanvas->Refresh(); waterfallCanvas->Refresh(); diff --git a/src/AppFrame.h b/src/AppFrame.h index de90215..7397097 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -96,5 +96,8 @@ private: 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..8619b71 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -63,6 +63,8 @@ bool CubicSDR::OnInit() { pipeSpectrumIQVisualData = new DemodulatorThreadInputQueue(); pipeIQVisualData->set_max_num_items(1); + pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue(); + spectrumDistributor.attachOutput(pipeDemodIQVisualData); spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); @@ -85,8 +87,9 @@ bool CubicSDR::OnInit() { sdrPostThread = new SDRPostThread(); sdrPostThread->setNumVisSamples(16384 * 2); 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 +279,10 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcesor() { return &demodSpectrumProcessor; } +SpectrumVisualProcessor *CubicSDR::getWaterfallProcesor() { + return &waterfallProcessor; +} + VisualDataDistributor *CubicSDR::getSpectrumDistributor() { return &spectrumDistributor; } @@ -289,6 +296,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/process/SpectrumVisualProcessor.cpp b/src/process/SpectrumVisualProcessor.cpp index 8defddc..75f2ee4 100644 --- a/src/process/SpectrumVisualProcessor.cpp +++ b/src/process/SpectrumVisualProcessor.cpp @@ -14,6 +14,7 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), last fft_ceil_ma = fft_ceil_maa = 100.0; fft_floor_ma = fft_floor_maa = 0.0; + desiredInputSize = 0; } SpectrumVisualProcessor::~SpectrumVisualProcessor() { @@ -45,8 +46,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); @@ -103,6 +109,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(); @@ -280,5 +288,7 @@ void SpectrumVisualProcessor::process() { distribute(output); } - + + iqData->decRefCount(); } + diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index 6ffe848..cfbd7dd 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -26,6 +26,8 @@ public: void setBandwidth(long bandwidth_in); long getBandwidth(); + int getDesiredInputSize(); + void setup(int fftSize); protected: @@ -59,4 +61,39 @@ private: std::vector shiftBuffer; std::vector resampleBuffer; + int desiredInputSize; +}; + + +class FFTDataDistributor : public VisualProcessor { +public: + void setFFTSize(int fftSize) { + this->fftSize = fftSize; + } + +protected: + void process() { + while (!input->empty()) { + if (!isAnyOutputEmpty()) { + return; + } + DemodulatorThreadIQData *inp; + input->pop(inp); + if (inp) { + if (inp->data.size() >= fftSize) { + for (int i = 0, iMax = inp->data.size()-fftSize; i < iMax; i += fftSize) { + 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); + } + } + inp->decRefCount(); + } + } + } + + ReBuffer outputBuffers; + int fftSize; }; 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..5e68d90 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -82,18 +82,18 @@ void SDRPostThread::run() { iqDataInQueue = (SDRThreadIQDataQueue*)getInputQueue("IQDataInput"); iqDataOutQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQDataOutput"); - iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOut"); + iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOutput"); ReBuffer buffers; std::vector fpData; std::vector dataOut; - + 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); + if (data_in && data_in->data.size()) { int dataSize = data_in->data.size()/2; if (dataSize > fpData.capacity()) { @@ -104,7 +104,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,106 +114,101 @@ 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(); - + if (visualDataOut->data.size() < num_vis_samples) { if (visualDataOut->data.capacity() < num_vis_samples) { visualDataOut->data.reserve(num_vis_samples); } 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) { + iqDataOutQueue->push(demodDataOut); + pushedData = true; + } + + if (!pushedData && iqDataOutQueue == NULL) { + demodDataOut->setRefCount(0); } } - + busy_demod.unlock(); } data_in->decRefCount(); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index a5269e2..af56d8f 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -140,7 +140,7 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { initGLExtensions(); glViewport(0, 0, ClientSize.x, ClientSize.y); - if (!visualDataQueue.empty()) { + while (!visualDataQueue.empty()) { SpectrumVisualData *vData; visualDataQueue.pop(vData); From 8494ce3f18458547b86e9c6f434ee568bebb919c Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Aug 2015 19:03:46 -0400 Subject: [PATCH 02/23] FFTDataDistributor "lines per second" rate control --- src/AppFrame.cpp | 2 +- src/process/SpectrumVisualProcessor.h | 37 +++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 9bc7183..abc07dc 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -719,7 +719,7 @@ void AppFrame::OnTimer(wxTimerEvent& event) { } else { fftDistrib.setFFTSize(DEFAULT_FFT_SIZE); } - + fftDistrib.setLinesPerSecond(15); fftDistrib.run(); wproc->setView(waterfallCanvas->getViewState()); diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index cfbd7dd..a757a88 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: @@ -67,10 +68,17 @@ private: class FFTDataDistributor : public VisualProcessor { public: + FFTDataDistributor() : linesPerSecond(30) { + } + void setFFTSize(int fftSize) { this->fftSize = fftSize; } + void setLinesPerSecond(int lines) { + this->linesPerSecond = lines; + } + protected: void process() { while (!input->empty()) { @@ -79,14 +87,31 @@ protected: } DemodulatorThreadIQData *inp; input->pop(inp); + + // 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) { - 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); + 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(); @@ -96,4 +121,6 @@ protected: ReBuffer outputBuffers; int fftSize; + int linesPerSecond; + double lineRateAccum; }; From f4640094b8fba5458d765012f047662278edefef Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Aug 2015 20:37:46 -0400 Subject: [PATCH 03/23] Crank up the waterfall zoom limits for more detail :) --- src/AppFrame.cpp | 2 +- src/CubicSDR.cpp | 3 ++- src/process/SpectrumVisualProcessor.h | 12 +++++++++--- src/visual/SpectrumCanvas.cpp | 3 ++- src/visual/WaterfallCanvas.cpp | 4 ++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index abc07dc..03f02a5 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -719,7 +719,7 @@ void AppFrame::OnTimer(wxTimerEvent& event) { } else { fftDistrib.setFFTSize(DEFAULT_FFT_SIZE); } - fftDistrib.setLinesPerSecond(15); + fftDistrib.setLinesPerSecond(60); fftDistrib.run(); wproc->setView(waterfallCanvas->getViewState()); diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 8619b71..51deb24 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -64,6 +64,7 @@ bool CubicSDR::OnInit() { pipeIQVisualData->set_max_num_items(1); pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue(); + pipeWaterfallIQVisualData->set_max_num_items(512); spectrumDistributor.attachOutput(pipeDemodIQVisualData); spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); @@ -85,7 +86,7 @@ bool CubicSDR::OnInit() { sdrThread->setOutputQueue("IQDataOutput",pipeSDRIQData); sdrPostThread = new SDRPostThread(); - sdrPostThread->setNumVisSamples(16384 * 2); + sdrPostThread->setNumVisSamples(BUF_SIZE); sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData); sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData); sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData); diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index a757a88..bcbca01 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -68,7 +68,7 @@ private: class FFTDataDistributor : public VisualProcessor { public: - FFTDataDistributor() : linesPerSecond(30) { + FFTDataDistributor() : linesPerSecond(30), lineRateAccum(0.0) { } void setFFTSize(int fftSize) { @@ -87,7 +87,13 @@ protected: } 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 @@ -98,7 +104,7 @@ protected: if (inp) { if (inp->data.size() >= fftSize) { - for (int i = 0, iMax = inp->data.size()-fftSize; i < iMax; i += fftSize) { + for (int i = 0, iMax = inp->data.size()-fftSize; i <= iMax; i += fftSize) { lineRateAccum += lineRateStep; if (lineRateAccum >= 1.0) { @@ -108,7 +114,7 @@ protected: outp->data.assign(inp->data.begin()+i,inp->data.begin()+i+fftSize); distribute(outp); - while (lineRateAccum > 1.0) { + while (lineRateAccum >= 1.0) { lineRateAccum -= 1.0; } } diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index c9df1f0..f07ae9c 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); } diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index af56d8f..51d1723 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -90,8 +90,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()); From 847f7a7569f90052eec2335f1b666b01c8ed5f57 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Aug 2015 21:19:55 -0400 Subject: [PATCH 04/23] Automatic ReBuffer<> garbage collection of unused buffers --- src/IOThread.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/IOThread.h b/src/IOThread.h index 0b06f0a..734b37a 100644 --- a/src/IOThread.h +++ b/src/IOThread.h @@ -37,6 +37,8 @@ protected: }; +#define REBUFFER_GC_LIMIT 100 + template class ReBuffer { @@ -44,11 +46,23 @@ 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; + } + buf = new BufferType(); outputBuffers.push_back(buf); From 655e4da1dcf83bca38e9cfbe526b1215b459a9be Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Aug 2015 21:49:42 -0400 Subject: [PATCH 05/23] Update post-input IQ visual out queue to ReBuffer<> + float is no longer enough for FFT zoom resolution :D --- src/panel/SpectrumPanel.cpp | 37 +++++++++++++++++++++---------------- src/sdr/SDRPostThread.cpp | 10 +++------- src/sdr/SDRPostThread.h | 2 ++ 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/panel/SpectrumPanel.cpp b/src/panel/SpectrumPanel.cpp index 4e33087..99bf23c 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 > 400) { mhzStep = (10000.0 / (long double) (rightFreq - leftFreq)) * 2.0; mhzVisualStep = 0.01f; } - + + if (mhzStep * 0.5 * viewWidth < 40) { + mhzStep = (250000.0 / (long double) (rightFreq - leftFreq)) * 2.0; + mhzVisualStep = 0.25f; + } + 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/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 5e68d90..9baa1c7 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -76,8 +76,6 @@ 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"); @@ -118,8 +116,8 @@ void SDRPostThread::run() { iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]); if (iqVisualQueue != NULL && iqVisualQueue->empty()) { - - visualDataOut->busy_rw.lock(); + DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer(); + visualDataOut->setRefCount(1); if (visualDataOut->data.size() < num_vis_samples) { if (visualDataOut->data.capacity() < num_vis_samples) { @@ -133,8 +131,6 @@ void SDRPostThread::run() { visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples); iqVisualQueue->push(visualDataOut); - - visualDataOut->busy_rw.unlock(); } busy_demod.lock(); @@ -221,7 +217,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; From 0c1f3149aca9eca309d6c47d3aa63ab488a196ee Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Aug 2015 22:11:54 -0400 Subject: [PATCH 06/23] Whoops.. I can has memory leak? --- src/AppFrame.cpp | 8 ++++++-- src/CubicSDR.cpp | 4 ++-- src/sdr/SDRPostThread.cpp | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 03f02a5..5efd96d 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -358,7 +358,6 @@ AppFrame::AppFrame() : 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); @@ -381,6 +380,10 @@ void AppFrame::initDeviceParams(std::string deviceId) { if (devConfig->getIQSwap()) { iqSwapMenuItem->Check(); } + + if (!frame_timer.IsRunning()) { + frame_timer.Start(33); + } } @@ -719,7 +722,8 @@ void AppFrame::OnTimer(wxTimerEvent& event) { } else { fftDistrib.setFFTSize(DEFAULT_FFT_SIZE); } - fftDistrib.setLinesPerSecond(60); + fftDistrib.setLinesPerSecond(24); + wxGetApp().getWaterfallVisualQueue()->set_max_num_items(24); fftDistrib.run(); wproc->setView(waterfallCanvas->getViewState()); diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 51deb24..c6bbbe4 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -58,10 +58,10 @@ 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(512); diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 9baa1c7..4efc143 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -117,6 +117,7 @@ void SDRPostThread::run() { if (iqVisualQueue != NULL && iqVisualQueue->empty()) { DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer(); + visualDataOut->busy_rw.lock(); visualDataOut->setRefCount(1); if (visualDataOut->data.size() < num_vis_samples) { @@ -130,6 +131,7 @@ void SDRPostThread::run() { visualDataOut->sampleRate = data_in->sampleRate; visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples); + visualDataOut->busy_rw.unlock(); iqVisualQueue->push(visualDataOut); } From a9181594e2d4f39ca954fc0b499e04f3814dee45 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Aug 2015 22:25:49 -0400 Subject: [PATCH 07/23] Fixes a rare crash while testing.. --- src/process/SpectrumVisualProcessor.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/process/SpectrumVisualProcessor.cpp b/src/process/SpectrumVisualProcessor.cpp index 75f2ee4..932477b 100644 --- a/src/process/SpectrumVisualProcessor.cpp +++ b/src/process/SpectrumVisualProcessor.cpp @@ -89,6 +89,12 @@ void SpectrumVisualProcessor::process() { input->pop(iqData); + if (!iqData) { + return; + } + + iqData->busy_rw.lock(); + std::vector *data = &iqData->data; if (data && data->size()) { @@ -102,6 +108,8 @@ void SpectrumVisualProcessor::process() { if (is_view.load()) { if (!iqData->frequency || !iqData->sampleRate) { + iqData->decRefCount(); + iqData->busy_rw.unlock(); return; } @@ -290,5 +298,6 @@ void SpectrumVisualProcessor::process() { } iqData->decRefCount(); + iqData->busy_rw.unlock(); } From 706a113459ef879d3f7dc640359092c3ea239210 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Aug 2015 23:52:03 -0400 Subject: [PATCH 08/23] Functional waterfall speed control from 1->1024 lines per second --- src/AppFrame.cpp | 54 ++++++++++++++++++++++----- src/AppFrame.h | 4 +- src/CubicSDR.cpp | 2 +- src/CubicSDRDefs.h | 1 + src/panel/SpectrumPanel.cpp | 10 ++--- src/process/SpectrumVisualProcessor.h | 2 +- 6 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 5efd96d..e092ced 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -63,8 +63,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); @@ -114,24 +112,49 @@ AppFrame::AppFrame() : 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->setMax(3.0); + spectrumAvgMeter->setInputValue(1.0); + + 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); - waterfallCanvas->attachSpectrumCanvas(spectrumCanvas); - spectrumCanvas->attachWaterfallCanvas(waterfallCanvas); - vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0); -// wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); + fftDistrib.setInput(wxGetApp().getWaterfallVisualQueue()); fftDistrib.attachOutput(&fftQueue); + wxGetApp().getWaterfallProcesor()->setInput(&fftQueue); wxGetApp().getWaterfallProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); + waterfallSpeedMeter = new MeterCanvas(this, attribList); + waterfallSpeedMeter->setMax(sqrt(1024)); + waterfallSpeedMeter->setInputValue(sqrt(DEFAULT_WATERFALL_LPS)); + + 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->AddSpacer(1); testCanvas = new UITestCanvas(this, attribList); @@ -722,8 +745,13 @@ void AppFrame::OnTimer(wxTimerEvent& event) { } else { fftDistrib.setFFTSize(DEFAULT_FFT_SIZE); } - fftDistrib.setLinesPerSecond(24); - wxGetApp().getWaterfallVisualQueue()->set_max_num_items(24); + + if (waterfallSpeedMeter->inputChanged()) { + int val = (int)waterfallSpeedMeter->getInputValue(); + fftDistrib.setLinesPerSecond((int)ceil(val*val)); + wxGetApp().getWaterfallVisualQueue()->set_max_num_items((int)ceil(val*val)); + } + fftDistrib.run(); wproc->setView(waterfallCanvas->getViewState()); @@ -752,6 +780,12 @@ void AppFrame::OnTimer(wxTimerEvent& event) { if (demodModeSelector->getMouseTracker()->mouseInView()) { demodModeSelector->Refresh(); } + if (waterfallSpeedMeter->getMouseTracker()->mouseInView()) { + waterfallSpeedMeter->Refresh(); + } + if (spectrumAvgMeter->getMouseTracker()->mouseInView()) { + spectrumAvgMeter->Refresh(); + } event.Skip(); } diff --git a/src/AppFrame.h b/src/AppFrame.h index 7397097..7194068 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -80,7 +80,9 @@ private: MeterCanvas *demodSignalMeter; MeterCanvas *demodGainMeter; TuningCanvas *demodTuner; - UITestCanvas *testCanvas; +// UITestCanvas *testCanvas; + MeterCanvas *spectrumAvgMeter; + MeterCanvas *waterfallSpeedMeter; DemodulatorInstance *activeDemodulator; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index c6bbbe4..ca1eef3 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -64,7 +64,7 @@ bool CubicSDR::OnInit() { pipeSpectrumIQVisualData->set_max_num_items(1); pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue(); - pipeWaterfallIQVisualData->set_max_num_items(512); + pipeWaterfallIQVisualData->set_max_num_items(DEFAULT_WATERFALL_LPS); spectrumDistributor.attachOutput(pipeDemodIQVisualData); spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index b9191d2..fb96a68 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 24 \ No newline at end of file diff --git a/src/panel/SpectrumPanel.cpp b/src/panel/SpectrumPanel.cpp index 99bf23c..81f62f6 100644 --- a/src/panel/SpectrumPanel.cpp +++ b/src/panel/SpectrumPanel.cpp @@ -113,16 +113,16 @@ void SpectrumPanel::drawPanelContents() { long double mhzStep = (100000.0 / (long double) (rightFreq - leftFreq)) * 2.0; double mhzVisualStep = 0.1f; - if (mhzStep * 0.5 * viewWidth > 400) { - mhzStep = (10000.0 / (long double) (rightFreq - leftFreq)) * 2.0; - mhzVisualStep = 0.01f; - } - 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; diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index bcbca01..2ee8ba2 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -68,7 +68,7 @@ private: class FFTDataDistributor : public VisualProcessor { public: - FFTDataDistributor() : linesPerSecond(30), lineRateAccum(0.0) { + FFTDataDistributor() : linesPerSecond(DEFAULT_WATERFALL_LPS), lineRateAccum(0.0) { } void setFFTSize(int fftSize) { From acd856646fd09a855635dae8ed30f4e95106263c Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 00:33:42 -0400 Subject: [PATCH 09/23] Windows frame timing tweaks --- src/AppFrame.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index e092ced..9d59c67 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -380,7 +380,6 @@ AppFrame::AppFrame() : wxAcceleratorTable accel(3, entries); SetAcceleratorTable(accel); - // frame rate = 1000 / 30 = 33ms // static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; // wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not"); // ShowFullScreen(true); @@ -405,7 +404,8 @@ void AppFrame::initDeviceParams(std::string deviceId) { } if (!frame_timer.IsRunning()) { - frame_timer.Start(33); + // frame rate = 1000 / 30 = 33ms + frame_timer.Start(25); } } From d2dbb2ff11843c46b5f23e3bcc261d4e631703bb Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 16:47:35 -0400 Subject: [PATCH 10/23] OSX re-tweak, might need a more accurate frame timer for windows.. --- src/AppFrame.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 9d59c67..bf29cb6 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -405,7 +405,14 @@ void AppFrame::initDeviceParams(std::string deviceId) { if (!frame_timer.IsRunning()) { // frame rate = 1000 / 30 = 33ms + +// windows needs a bit more time or it lags? +#ifdef _WIN32 frame_timer.Start(25); +#else + frame_timer.Start(33); +#endif + } } From 6ae02bee9c1e52059e002e49bb5b6fd76f69c575 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 18:07:06 -0400 Subject: [PATCH 11/23] Frame timer too jittery for anything but OSX, back to throttling which looks nicer.. --- src/AppFrame.cpp | 27 +++++++++++++-------------- src/AppFrame.h | 2 +- src/CubicSDRDefs.h | 2 +- src/sdr/SDRPostThread.cpp | 5 +++++ src/visual/MeterCanvas.cpp | 3 ++- src/visual/ModeSelectorCanvas.cpp | 3 ++- src/visual/ScopeCanvas.cpp | 3 ++- src/visual/SpectrumCanvas.cpp | 3 ++- src/visual/TuningCanvas.cpp | 2 ++ src/visual/WaterfallCanvas.cpp | 3 ++- 10 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index bf29cb6..e0745ec 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -35,7 +35,7 @@ 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) +//EVT_TIMER(FRAME_TIMER_ID, AppFrame::OnTimer) wxEND_EVENT_TABLE() AppFrame::AppFrame() : @@ -407,11 +407,11 @@ void AppFrame::initDeviceParams(std::string deviceId) { // frame rate = 1000 / 30 = 33ms // windows needs a bit more time or it lags? -#ifdef _WIN32 - frame_timer.Start(25); -#else - frame_timer.Start(33); -#endif +//#ifdef _WIN32 +// frame_timer.Start(25); +//#else +// frame_timer.Start(15); +//#endif } } @@ -608,10 +608,10 @@ void AppFrame::OnThread(wxCommandEvent& event) { } void AppFrame::OnIdle(wxIdleEvent& event) { - event.Skip(); -} - -void AppFrame::OnTimer(wxTimerEvent& event) { +// event.Skip(); +//} +// +//void AppFrame::OnTimer(wxTimerEvent& event) { DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); @@ -768,9 +768,8 @@ void AppFrame::OnTimer(wxTimerEvent& event) { while (!wproc->isInputEmpty()) { wproc->run(); } - - scopeCanvas->Refresh(); + /* scopeCanvas->Refresh(); waterfallCanvas->Refresh(); spectrumCanvas->Refresh(); @@ -792,9 +791,9 @@ void AppFrame::OnTimer(wxTimerEvent& event) { } if (spectrumAvgMeter->getMouseTracker()->mouseInView()) { spectrumAvgMeter->Refresh(); - } + } */ - event.Skip(); + event.RequestMore(); } void AppFrame::saveSession(std::string fileName) { diff --git a/src/AppFrame.h b/src/AppFrame.h index 7194068..fd9eac6 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -69,7 +69,7 @@ private: void OnClose(wxCloseEvent& event); void OnNewWindow(wxCommandEvent& event); void OnIdle(wxIdleEvent& event); - void OnTimer(wxTimerEvent& event); +// void OnTimer(wxTimerEvent& event); ScopeCanvas *scopeCanvas; SpectrumCanvas *spectrumCanvas; diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index fb96a68..b2c326a 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -33,4 +33,4 @@ const char filePathSeparator = #define DEFAULT_DEMOD_TYPE 1 #define DEFAULT_DEMOD_BW 200000 -#define DEFAULT_WATERFALL_LPS 24 \ No newline at end of file +#define DEFAULT_WATERFALL_LPS 30 \ No newline at end of file diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 4efc143..5658615 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -91,6 +91,7 @@ void SDRPostThread::run() { iqDataInQueue->pop(data_in); // 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; @@ -120,6 +121,10 @@ void SDRPostThread::run() { visualDataOut->busy_rw.lock(); visualDataOut->setRefCount(1); + if (num_vis_samples > data_in->data.size()) { + num_vis_samples = data_in->data.size(); + } + if (visualDataOut->data.size() < num_vis_samples) { if (visualDataOut->data.capacity() < num_vis_samples) { visualDataOut->data.reserve(num_vis_samples); diff --git a/src/visual/MeterCanvas.cpp b/src/visual/MeterCanvas.cpp index 423fc20..07e7984 100644 --- a/src/visual/MeterCanvas.cpp +++ b/src/visual/MeterCanvas.cpp @@ -79,7 +79,8 @@ void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void MeterCanvas::OnIdle(wxIdleEvent &event) { - event.Skip(); + Refresh(); + event.RequestMore(); } void MeterCanvas::OnMouseMoved(wxMouseEvent& event) { 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 f07ae9c..f21a6a8 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -85,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..23f15a4 100644 --- a/src/visual/TuningCanvas.cpp +++ b/src/visual/TuningCanvas.cpp @@ -252,6 +252,8 @@ void TuningCanvas::OnIdle(wxIdleEvent &event) { dragging = false; } } + Refresh(); + event.RequestMore(); } void TuningCanvas::OnMouseMoved(wxMouseEvent& event) { diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 51d1723..892b17f 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -347,7 +347,8 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { - event.Skip(); + Refresh(); + event.RequestMore(); } void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { From 8bce6329820049ae27d39139ec905ab9f6dfc65d Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 18:16:53 -0400 Subject: [PATCH 12/23] Add some sleep to AppFrame idle to prevent it from chewing up too much CPU while minimized --- src/AppFrame.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index e0745ec..5930a5c 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -769,6 +769,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wproc->run(); } + usleep(5000); /* scopeCanvas->Refresh(); waterfallCanvas->Refresh(); From 33d51b2bff7b40fd7753edee1647ef2cdc3723c8 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 19:39:11 -0400 Subject: [PATCH 13/23] Improve input response time, balance visuals, fix a bug --- src/AppFrame.cpp | 24 +++++------------------- src/AppFrame.h | 4 ---- src/CubicSDRDefs.h | 2 +- src/sdr/SDRPostThread.cpp | 4 ++-- src/visual/WaterfallCanvas.cpp | 31 +++++++++++++++++++------------ src/visual/WaterfallCanvas.h | 1 + 6 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 5930a5c..614b2e5 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)); @@ -261,7 +260,7 @@ AppFrame::AppFrame() : // sampleRateMenuItems[wxID_BANDWIDTH_3000M] = menu->AppendRadioItem(wxID_BANDWIDTH_3000M, "3.0M"); sampleRateMenuItems[wxID_BANDWIDTH_3200M] = menu->AppendRadioItem(wxID_BANDWIDTH_3200M, "3.2M"); - sampleRateMenuItems[wxID_BANDWIDTH_2400M]->Check(true); + sampleRateMenuItems[wxID_BANDWIDTH_2048M]->Check(true); menuBar->Append(menu, wxT("&Input Bandwidth")); @@ -402,18 +401,6 @@ void AppFrame::initDeviceParams(std::string deviceId) { if (devConfig->getIQSwap()) { iqSwapMenuItem->Check(); } - - if (!frame_timer.IsRunning()) { - // frame rate = 1000 / 30 = 33ms - -// windows needs a bit more time or it lags? -//#ifdef _WIN32 -// frame_timer.Start(25); -//#else -// frame_timer.Start(15); -//#endif - - } } @@ -608,10 +595,6 @@ void AppFrame::OnThread(wxCommandEvent& event) { } void AppFrame::OnIdle(wxIdleEvent& event) { -// event.Skip(); -//} -// -//void AppFrame::OnTimer(wxTimerEvent& event) { DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); @@ -769,6 +752,9 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wproc->run(); } + waterfallCanvas->processInputQueue(); + demodWaterfallCanvas->processInputQueue(); + usleep(5000); /* scopeCanvas->Refresh(); diff --git a/src/AppFrame.h b/src/AppFrame.h index fd9eac6..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; @@ -96,7 +93,6 @@ private: wxMenuItem *iqSwapMenuItem; std::string currentSessionFile; - wxTimer frame_timer; FFTDataDistributor fftDistrib; DemodulatorThreadInputQueue fftQueue; diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index b2c326a..677e68b 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -27,7 +27,7 @@ const char filePathSeparator = #define BUF_SIZE (16384*6) -#define DEFAULT_SAMPLE_RATE 2400000 +#define DEFAULT_SAMPLE_RATE 2048000 #define DEFAULT_FFT_SIZE 2048 #define DEFAULT_DEMOD_TYPE 1 diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 5658615..7a999f9 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -121,8 +121,8 @@ void SDRPostThread::run() { visualDataOut->busy_rw.lock(); visualDataOut->setRefCount(1); - if (num_vis_samples > data_in->data.size()) { - num_vis_samples = data_in->data.size(); + if (num_vis_samples > dataOut.size()) { + num_vis_samples = dataOut.size(); } if (visualDataOut->data.size() < num_vis_samples) { diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 892b17f..2a52a11 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -68,6 +68,25 @@ 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); @@ -139,18 +158,6 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->SetCurrent(*this); initGLExtensions(); glViewport(0, 0, ClientSize.x, ClientSize.y); - - while (!visualDataQueue.empty()) { - SpectrumVisualData *vData; - - visualDataQueue.pop(vData); - - if (vData) { - waterfallPanel.setPoints(vData->spectrum_points); - waterfallPanel.step(); - vData->decRefCount(); - } - } glContext->BeginDraw(0,0,0); diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index b570ffb..2f51ec3 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -26,6 +26,7 @@ public: DragState getNextDragState(); void attachSpectrumCanvas(SpectrumCanvas *canvas_in); + void processInputQueue(); SpectrumVisualDataQueue *getVisualDataQueue(); private: From 9de7bc95fbae8abd0334b6a453c403fc9da0bef3 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 20:05:57 -0400 Subject: [PATCH 14/23] meter visual fix, tuner refresh fix --- src/AppFrame.cpp | 12 ++++++++---- src/visual/MeterCanvas.cpp | 12 ++++++++++-- src/visual/MeterCanvas.h | 3 +++ src/visual/TuningCanvas.cpp | 4 +++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 614b2e5..890aa25 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -106,6 +106,7 @@ 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); @@ -118,8 +119,9 @@ AppFrame::AppFrame() : spectrumAvgMeter = new MeterCanvas(this, attribList); spectrumAvgMeter->setMax(3.0); - spectrumAvgMeter->setInputValue(1.0); - + spectrumAvgMeter->setLevel(1.0); + spectrumAvgMeter->setShowUserInput(false); + spectrumSizer->Add(spectrumCanvas, 63, wxEXPAND | wxALL, 0); spectrumSizer->AddSpacer(1); spectrumSizer->Add(spectrumAvgMeter, 1, wxEXPAND | wxALL, 0); @@ -142,7 +144,8 @@ AppFrame::AppFrame() : waterfallSpeedMeter = new MeterCanvas(this, attribList); waterfallSpeedMeter->setMax(sqrt(1024)); - waterfallSpeedMeter->setInputValue(sqrt(DEFAULT_WATERFALL_LPS)); + waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS)); + waterfallSpeedMeter->setShowUserInput(false); wfSizer->Add(waterfallCanvas, 63, wxEXPAND | wxALL, 0); wfSizer->AddSpacer(1); @@ -737,7 +740,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) { } if (waterfallSpeedMeter->inputChanged()) { - int val = (int)waterfallSpeedMeter->getInputValue(); + float val = waterfallSpeedMeter->getInputValue(); + waterfallSpeedMeter->setLevel(val); fftDistrib.setLinesPerSecond((int)ceil(val*val)); wxGetApp().getWaterfallVisualQueue()->set_max_num_items((int)ceil(val*val)); } diff --git a/src/visual/MeterCanvas.cpp b/src/visual/MeterCanvas.cpp index 07e7984..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,11 +72,15 @@ 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(); 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/TuningCanvas.cpp b/src/visual/TuningCanvas.cpp index 23f15a4..8a85ac4 100644 --- a/src/visual/TuningCanvas.cpp +++ b/src/visual/TuningCanvas.cpp @@ -252,7 +252,9 @@ void TuningCanvas::OnIdle(wxIdleEvent &event) { dragging = false; } } - Refresh(); + if (mouseTracker.mouseInView() || changed()) { + Refresh(); + } event.RequestMore(); } From 1d5a2f1ac7b08d85387da962fb0e191c52f01405 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 21:45:02 -0400 Subject: [PATCH 15/23] Fix for an initial priming overload and visuals memory leak --- src/CubicSDR.cpp | 4 +++- src/IOThread.h | 5 +++++ src/demod/DemodulatorThread.cpp | 2 +- src/sdr/SDRPostThread.cpp | 10 ++++++++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index ca1eef3..2283d57 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -78,9 +78,11 @@ 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); diff --git a/src/IOThread.h b/src/IOThread.h index 734b37a..743635c 100644 --- a/src/IOThread.h +++ b/src/IOThread.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "ThreadQueue.h" @@ -63,6 +64,10 @@ public: 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/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 7a999f9..a9955cd 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -86,6 +86,8 @@ void SDRPostThread::run() { std::vector fpData; std::vector dataOut; + iqDataInQueue->set_max_num_items(30); + while (!terminated) { SDRThreadIQData *data_in; @@ -203,8 +205,12 @@ void SDRPostThread::run() { } if (iqDataOutQueue != NULL) { - iqDataOutQueue->push(demodDataOut); - pushedData = true; + if (!iqDataOutQueue->full()) { + iqDataOutQueue->push(demodDataOut); + pushedData = true; + } else { + demodDataOut->decRefCount(); + } } if (!pushedData && iqDataOutQueue == NULL) { From b345dc7516de0130021c8984a16a82bfef2bb2a8 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 22:14:14 -0400 Subject: [PATCH 16/23] Spectrum averaging control now functional --- src/AppFrame.cpp | 12 +++++++++--- src/process/SpectrumVisualProcessor.cpp | 12 ++++++++---- src/process/SpectrumVisualProcessor.h | 3 +++ src/sdr/SDRPostThread.cpp | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 890aa25..07c919b 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -118,8 +118,8 @@ AppFrame::AppFrame() : wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue()); spectrumAvgMeter = new MeterCanvas(this, attribList); - spectrumAvgMeter->setMax(3.0); - spectrumAvgMeter->setLevel(1.0); + spectrumAvgMeter->setMax(1.0); + spectrumAvgMeter->setLevel(0.65); spectrumAvgMeter->setShowUserInput(false); spectrumSizer->Add(spectrumCanvas, 63, wxEXPAND | wxALL, 0); @@ -712,9 +712,15 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wxGetApp().getScopeProcessor()->run(); wxGetApp().getSpectrumDistributor()->run(); - + SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor(); + if (spectrumAvgMeter->inputChanged()) { + float val = spectrumAvgMeter->getInputValue(); + spectrumAvgMeter->setLevel(val); + proc->setFFTAverageRate(val); + } + proc->setView(spectrumCanvas->getViewState()); proc->setBandwidth(spectrumCanvas->getBandwidth()); proc->setCenterFrequency(spectrumCanvas->getCenterFrequency()); diff --git a/src/process/SpectrumVisualProcessor.cpp b/src/process/SpectrumVisualProcessor.cpp index 932477b..34b2543 100644 --- a/src/process/SpectrumVisualProcessor.cpp +++ b/src/process/SpectrumVisualProcessor.cpp @@ -15,6 +15,7 @@ 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() { @@ -29,6 +30,9 @@ void SpectrumVisualProcessor::setView(bool bView) { is_view.store(bView); } +void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) { + this->fft_average_rate = fftAverageRate; +} void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) { centerFreq.store(centerFreq_in); @@ -260,11 +264,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) { diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index 2ee8ba2..134d61f 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -21,6 +21,8 @@ public: bool isView(); void setView(bool bView); + void setFFTAverageRate(float fftAverageRate); + void setCenterFrequency(long long centerFreq_in); long long getCenterFrequency(); @@ -50,6 +52,7 @@ private: float fft_ceil_ma, fft_ceil_maa; float fft_floor_ma, fft_floor_maa; + float fft_average_rate; std::vector fft_result; std::vector fft_result_ma; diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index a9955cd..30944cf 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -86,7 +86,7 @@ void SDRPostThread::run() { std::vector fpData; std::vector dataOut; - iqDataInQueue->set_max_num_items(30); + iqDataInQueue->set_max_num_items(0); while (!terminated) { SDRThreadIQData *data_in; From 7095993ba20ea581a1e3358e56e55a53df44b4dc Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 12 Aug 2015 22:28:39 -0400 Subject: [PATCH 17/23] fft avgeraging float->double to remove some jitter --- src/process/SpectrumVisualProcessor.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index 2ee8ba2..39f97ad 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -48,12 +48,12 @@ 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; - 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; From 8000e97a8c7a07253e83e6be645a87b725600487 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 13 Aug 2015 17:59:56 -0400 Subject: [PATCH 18/23] force waterfall to throttle by client dc paint from appframe idle - Attempting to improve waterfall jitter between platforms --- src/AppFrame.cpp | 6 +++++- src/visual/WaterfallCanvas.cpp | 12 +++++++++--- src/visual/WaterfallCanvas.h | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 1e621dd..42f7cf0 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -768,7 +768,11 @@ void AppFrame::OnIdle(wxIdleEvent& event) { #ifndef _WIN32 usleep(5000); #endif - + + if (this->IsVisible()) { + waterfallCanvas->DoPaint(); + demodWaterfallCanvas->DoPaint(); + } event.RequestMore(); } diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 2a52a11..00bc773 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -88,7 +88,12 @@ void WaterfallCanvas::processInputQueue() { } 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; @@ -354,8 +359,9 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { - Refresh(); - event.RequestMore(); +// Refresh(); +// event.RequestMore(); + event.Skip(); } void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 2f51ec3..1b59e35 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -28,6 +28,7 @@ public: void attachSpectrumCanvas(SpectrumCanvas *canvas_in); void processInputQueue(); SpectrumVisualDataQueue *getVisualDataQueue(); + void DoPaint(); private: void OnPaint(wxPaintEvent& event); From 1781188dfe06ad1cdd22f0e13810694510d9825d Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 13 Aug 2015 18:03:06 -0400 Subject: [PATCH 19/23] Sleep only when not visible.. --- src/AppFrame.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 42f7cf0..9e0e15f 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -765,14 +765,17 @@ void AppFrame::OnIdle(wxIdleEvent& event) { waterfallCanvas->processInputQueue(); demodWaterfallCanvas->processInputQueue(); -#ifndef _WIN32 - usleep(5000); -#endif if (this->IsVisible()) { waterfallCanvas->DoPaint(); demodWaterfallCanvas->DoPaint(); } +#ifndef _WIN32 + else { + usleep(15000); + } +#endif + event.RequestMore(); } From b1f20de0e95696cd5d6db7917c8cfa90da4793fb Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 13 Aug 2015 18:10:22 -0400 Subject: [PATCH 20/23] RefCounter should make this unnecessary? --- src/sdr/SDRPostThread.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 30944cf..e4a9d2b 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -120,7 +120,6 @@ void SDRPostThread::run() { if (iqVisualQueue != NULL && iqVisualQueue->empty()) { DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer(); - visualDataOut->busy_rw.lock(); visualDataOut->setRefCount(1); if (num_vis_samples > dataOut.size()) { @@ -138,7 +137,6 @@ void SDRPostThread::run() { visualDataOut->sampleRate = data_in->sampleRate; visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples); - visualDataOut->busy_rw.unlock(); iqVisualQueue->push(visualDataOut); } From e04b12662fc81ee5a61b14bfd484f90e7495a29f Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 13 Aug 2015 20:39:31 -0400 Subject: [PATCH 21/23] Linux re-tweak --- src/AppFrame.cpp | 15 +++++++++++---- src/CubicSDRDefs.h | 4 ++-- src/process/ScopeVisualProcessor.cpp | 3 +++ src/util/GLExt.cpp | 4 ++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 9e0e15f..27e6d22 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -118,6 +118,7 @@ AppFrame::AppFrame() : 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); @@ -143,6 +144,7 @@ AppFrame::AppFrame() : 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); @@ -263,7 +265,7 @@ AppFrame::AppFrame() : // sampleRateMenuItems[wxID_BANDWIDTH_3000M] = menu->AppendRadioItem(wxID_BANDWIDTH_3000M, "3.0M"); sampleRateMenuItems[wxID_BANDWIDTH_3200M] = menu->AppendRadioItem(wxID_BANDWIDTH_3200M, "3.2M"); - sampleRateMenuItems[wxID_BANDWIDTH_2048M]->Check(true); + sampleRateMenuItems[wxID_BANDWIDTH_2400M]->Check(true); menuBar->Append(menu, wxT("&Input Bandwidth")); @@ -719,6 +721,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) { 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()); @@ -750,6 +754,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) { 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(); @@ -769,12 +775,13 @@ void AppFrame::OnIdle(wxIdleEvent& event) { if (this->IsVisible()) { waterfallCanvas->DoPaint(); demodWaterfallCanvas->DoPaint(); - } + } else { #ifndef _WIN32 - else { usleep(15000); - } +#else + Sleep(15); #endif + } event.RequestMore(); } diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 677e68b..49df312 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -27,10 +27,10 @@ const char filePathSeparator = #define BUF_SIZE (16384*6) -#define DEFAULT_SAMPLE_RATE 2048000 +#define DEFAULT_SAMPLE_RATE 2400000 #define DEFAULT_FFT_SIZE 2048 #define DEFAULT_DEMOD_TYPE 1 #define DEFAULT_DEMOD_BW 200000 -#define DEFAULT_WATERFALL_LPS 30 \ No newline at end of file +#define DEFAULT_WATERFALL_LPS 30 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/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")) { From 709ab4b7d6c42a99662af52a7148a0c9bb70c3f7 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 13 Aug 2015 21:10:43 -0400 Subject: [PATCH 22/23] OSX idle throttle --- src/AppFrame.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 27e6d22..082ec99 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -775,6 +775,9 @@ void AppFrame::OnIdle(wxIdleEvent& event) { if (this->IsVisible()) { waterfallCanvas->DoPaint(); demodWaterfallCanvas->DoPaint(); +#ifdef __APPLE__ + usleep(5000); +#endif } else { #ifndef _WIN32 usleep(15000); From 1e493b2e2002525b90c94964416be2e81c815d02 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 13 Aug 2015 22:00:05 -0400 Subject: [PATCH 23/23] Save waterfall / spectrum settings, update session reset --- src/AppConfig.cpp | 35 ++++++++++++++++++++++++- src/AppConfig.h | 10 ++++++- src/AppFrame.cpp | 29 +++++++++++++++++++- src/process/SpectrumVisualProcessor.cpp | 4 +++ src/process/SpectrumVisualProcessor.h | 4 +++ 5 files changed, 79 insertions(+), 3 deletions(-) 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 082ec99..957651e 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -367,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()); @@ -466,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) { @@ -587,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(); } diff --git a/src/process/SpectrumVisualProcessor.cpp b/src/process/SpectrumVisualProcessor.cpp index 34b2543..06c65c2 100644 --- a/src/process/SpectrumVisualProcessor.cpp +++ b/src/process/SpectrumVisualProcessor.cpp @@ -34,6 +34,10 @@ 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); } diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index 4f6374d..fd7f013 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -22,6 +22,7 @@ public: void setView(bool bView); void setFFTAverageRate(float fftAverageRate); + float getFFTAverageRate(); void setCenterFrequency(long long centerFreq_in); long long getCenterFrequency(); @@ -82,6 +83,9 @@ public: this->linesPerSecond = lines; } + int getLinesPerSecond() { + return this->linesPerSecond; + } protected: void process() { while (!input->empty()) {