From e5b7f76b2a5ff5aa25b3071f460cb76abac9ca95 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 26 Aug 2015 20:45:10 -0400 Subject: [PATCH 01/25] Version bump to 0.1.4 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ddee92..4a20f53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 2.8) SET(CUBICSDR_VERSION_MAJOR "0") SET(CUBICSDR_VERSION_MINOR "1") -SET(CUBICSDR_VERSION_PATCH "3") +SET(CUBICSDR_VERSION_PATCH "4") SET(CUBICSDR_VERSION_REL "beta") SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}-${CUBICSDR_VERSION_REL}") From b549f9748e6ef89fcdc5e29d9d352ef6b856cc4f Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Fri, 28 Aug 2015 19:55:25 -0400 Subject: [PATCH 02/25] Other apps seem to want I/Q pipe in this format; going with the flow --- CMakeLists.txt | 7 ++++++- src/demod/DemodulatorThread.cpp | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a20f53..01f92a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -423,6 +423,12 @@ IF (MSVC) set(CMAKE_CREATE_WIN32_EXE "/SUBSYSTEM:WINDOWS /ENTRY:\"mainCRTStartup\"") ENDIF(MSVC) +IF (APPLE) + ADD_DEFINITIONS( + -DHAVE_TYPE_TRAITS=1 + ) +ENDIF(APPLE) + IF (APPLE AND BUNDLE_APP) PROJECT(CubicSDR) SET(MACOSX_BUNDLE_BUNDLE_NAME CubicSDR) @@ -431,7 +437,6 @@ IF (APPLE AND BUNDLE_APP) -std=c++0x -pthread -D_OSX_APP_ - -DHAVE_TYPE_TRAITS=1 -mmacosx-version-min=10.9 ) diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 2ed31b0..e1274e2 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -320,8 +320,8 @@ void DemodulatorThread::run() { } ati->data.resize(numAudioWritten * 2); for (int i = 0; i < numAudioWritten; i++) { - ati->data[i * 2] = (*inputData)[i].real; - ati->data[i * 2 + 1] = (*inputData)[i].imag; + ati->data[i * 2] = (*inputData)[i].imag; + ati->data[i * 2 + 1] = (*inputData)[i].real; } } else if (stereo && inp->sampleRate >= 100000) { ati->channels = 2; From c62ab63f4f8ef3afe4b4e50a6a829c915735bdbd Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Fri, 28 Aug 2015 20:28:11 -0400 Subject: [PATCH 03/25] OSX wx build tweak for static lib --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 01f92a3..ff832df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -426,6 +426,7 @@ ENDIF(MSVC) IF (APPLE) ADD_DEFINITIONS( -DHAVE_TYPE_TRAITS=1 + -mmacosx-version-min=10.9 ) ENDIF(APPLE) @@ -437,7 +438,6 @@ IF (APPLE AND BUNDLE_APP) -std=c++0x -pthread -D_OSX_APP_ - -mmacosx-version-min=10.9 ) ADD_EXECUTABLE(CubicSDR From 45c0eafa2e01d9c9dbfcdf8a9eb7934d9ecf77ea Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Fri, 28 Aug 2015 21:48:33 -0400 Subject: [PATCH 04/25] MSVC FFTVisualDataThread constructor fix --- src/process/FFTVisualDataThread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/process/FFTVisualDataThread.cpp b/src/process/FFTVisualDataThread.cpp index 0e92dbb..dd5ce72 100644 --- a/src/process/FFTVisualDataThread.cpp +++ b/src/process/FFTVisualDataThread.cpp @@ -1,7 +1,8 @@ #include "FFTVisualDataThread.h" #include "CubicSDR.h" -FFTVisualDataThread::FFTVisualDataThread() : linesPerSecond(DEFAULT_WATERFALL_LPS) { +FFTVisualDataThread::FFTVisualDataThread() { + linesPerSecond.store(DEFAULT_WATERFALL_LPS); lpsChanged.store(true); } From 7288912878ef73372f8e043bbea323379958aee9 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sat, 29 Aug 2015 07:46:11 -0400 Subject: [PATCH 05/25] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cba51ff..a541eda 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Features and Status: - [x] Spectrum - [x] Waterfall - [x] Add faint grid for sense of scale - - [ ] Audio Spectrum + - [x] Audio Spectrum - [ ] X/Y Scope - [ ] Indicate outer spectrum edges when zoomed - [ ] 3D visuals @@ -67,8 +67,8 @@ Features and Status: - [x] Display audio output selection - [x] Volume control - [x] Direct frequency input - - [ ] Mute - - [ ] Waterfall speed + - [x] Mute + - [x] Waterfall speed - [ ] RTL-SDR Gain - Basic Input Controls - [x] Drag spectrum to change center frequency From 3ce569f043d6e4627c9375a4ca84caaa724a7e4b Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 31 Aug 2015 20:26:17 -0400 Subject: [PATCH 06/25] MSVC / Win32 x86 fixes --- external/msvc/x86/libgcc_s_dw2-1.dll | Bin 108032 -> 112142 bytes src/AppFrame.cpp | 1 + src/demod/DemodulatorMgr.cpp | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/external/msvc/x86/libgcc_s_dw2-1.dll b/external/msvc/x86/libgcc_s_dw2-1.dll index 915896437453892ba6b3fb8561bd80e8622e9c6a..99a76cf3a253193acdbc93c280dc1e1022a24a3d 100644 GIT binary patch literal 112142 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 `uH%`Au>)DCad-C9v;iip57 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 literal 108032 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 diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 0a20f77..502ef31 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -121,6 +121,7 @@ AppFrame::AppFrame() : demodMuteButton->setHighlightColor(RGBA4f(0.8,0.2,0.2)); demodMuteButton->setHelpTip("Demodulator Mute Toggle"); demodMuteButton->setToggleMode(true); + demodMuteButton->setSelection(-1); demodGainTray->Add(demodMuteButton, 1, wxEXPAND | wxALL, 0); diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp index 4d0671e..1931d3e 100644 --- a/src/demod/DemodulatorMgr.cpp +++ b/src/demod/DemodulatorMgr.cpp @@ -7,7 +7,7 @@ DemodulatorMgr::DemodulatorMgr() : activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL), lastBandwidth(DEFAULT_DEMOD_BW), lastDemodType( - DEFAULT_DEMOD_TYPE), lastSquelchEnabled(false), lastSquelch(0), lastGain(1.0), lastStereo(false) { + DEFAULT_DEMOD_TYPE), lastSquelchEnabled(false), lastSquelch(0), lastGain(1.0), lastStereo(false), lastMuted(false) { } From 2e6b173fb1d615e403fa1ee293919f692e8dd9fb Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 7 Sep 2015 20:46:03 -0400 Subject: [PATCH 07/25] attempt to fix waterfall stutter working parts --- CMakeLists.txt | 2 + src/process/FFTDataDistributor.cpp | 81 +++++++++++++++++++++++++++++ src/process/FFTDataDistributor.h | 22 ++++++++ src/process/FFTVisualDataThread.cpp | 2 +- src/process/FFTVisualDataThread.h | 1 + src/sdr/SDRPostThread.cpp | 31 ++++------- src/sdr/SDRPostThread.h | 4 -- 7 files changed, 117 insertions(+), 26 deletions(-) create mode 100644 src/process/FFTDataDistributor.cpp create mode 100644 src/process/FFTDataDistributor.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ff832df..f10bbd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -264,6 +264,7 @@ SET (cubicsdr_sources src/process/ScopeVisualProcessor.cpp src/process/SpectrumVisualProcessor.cpp src/process/FFTVisualDataThread.cpp + src/process/FFTDataDistributor.cpp src/process/SpectrumVisualDataThread.cpp src/ui/GLPanel.cpp external/rtaudio/RtAudio.cpp @@ -319,6 +320,7 @@ SET (cubicsdr_headers src/process/ScopeVisualProcessor.h src/process/SpectrumVisualProcessor.h src/process/FFTVisualDataThread.h + src/process/FFTDataDistributor.h src/process/SpectrumVisualDataThread.h src/ui/GLPanel.h src/ui/UITestCanvas.cpp diff --git a/src/process/FFTDataDistributor.cpp b/src/process/FFTDataDistributor.cpp new file mode 100644 index 0000000..818c955 --- /dev/null +++ b/src/process/FFTDataDistributor.cpp @@ -0,0 +1,81 @@ +#include "FFTDataDistributor.h" + +FFTDataDistributor::FFTDataDistributor() : linesPerSecond(DEFAULT_WATERFALL_LPS), lineRateAccum(0.0), fftSize(DEFAULT_FFT_SIZE) { +} + +void FFTDataDistributor::setFFTSize(int fftSize) { + this->fftSize = fftSize; +} + +void FFTDataDistributor::setLinesPerSecond(int lines) { + this->linesPerSecond = lines; +} + +int FFTDataDistributor::getLinesPerSecond() { + return this->linesPerSecond; +} + +void FFTDataDistributor::process() { + while (!input->empty()) { + if (!isAnyOutputEmpty()) { + return; + } + DemodulatorThreadIQData *inp; + input->pop(inp); + + if (inp) { + if (inputBuffer.sampleRate != inp->sampleRate || inputBuffer.frequency != inp->frequency) { + inputBuffer.sampleRate = inp->sampleRate; + inputBuffer.frequency = inp->frequency; + inputBuffer.data.assign(inp->data.begin(), inp->data.end()); + } else { + inputBuffer.data.insert(inputBuffer.data.end(), inp->data.begin(), inp->data.end()); + } + inp->decRefCount(); + } else { + continue; + } + + // number of seconds contained in input + double inputTime = (double)inputBuffer.data.size() / (double)inputBuffer.sampleRate; + // number of lines in input + double inputLines = (double)inputBuffer.data.size()/(double)fftSize; + + // ratio required to achieve the desired rate + double lineRateStep = ((double)linesPerSecond * inputTime)/(double)inputLines; + + if (inputBuffer.data.size() >= fftSize) { + int numProcessed = 0; + +// if (lineRateAccum + (lineRateStep * floor((double)inputBuffer.data.size()/(double)fftSize)) < 1.0) { +// // move along, nothing to see here.. +// lineRateAccum += (lineRateStep * inputBuffer.data.size()/fftSize); +// numProcessed = inputBuffer.data.size()/fftSize; +// } else { + for (int i = 0, iMax = inputBuffer.data.size(); i < iMax; i += fftSize) { + if ((i + fftSize) > iMax) { + break; + } + lineRateAccum += lineRateStep; + + if (lineRateAccum >= 1.0) { + DemodulatorThreadIQData *outp = outputBuffers.getBuffer(); + outp->frequency = inputBuffer.frequency; + outp->sampleRate = inputBuffer.sampleRate; + outp->data.assign(inputBuffer.data.begin()+i,inputBuffer.data.begin()+i+fftSize); + distribute(outp); + + while (lineRateAccum >= 1.0) { + lineRateAccum -= 1.0; + } + } + + numProcessed += fftSize; + } +// } + if (numProcessed) { + inputBuffer.data.erase(inputBuffer.data.begin(), inputBuffer.data.begin() + numProcessed); + } + } + } +} diff --git a/src/process/FFTDataDistributor.h b/src/process/FFTDataDistributor.h new file mode 100644 index 0000000..561a0e7 --- /dev/null +++ b/src/process/FFTDataDistributor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "VisualProcessor.h" +#include "DemodDefs.h" +#include + +class FFTDataDistributor : public VisualProcessor { +public: + FFTDataDistributor(); + void setFFTSize(int fftSize); + void setLinesPerSecond(int lines); + int getLinesPerSecond(); + +protected: + void process(); + + DemodulatorThreadIQData inputBuffer, tempBuffer; + ReBuffer outputBuffers; + int fftSize; + int linesPerSecond; + double lineRateAccum; +}; diff --git a/src/process/FFTVisualDataThread.cpp b/src/process/FFTVisualDataThread.cpp index dd5ce72..fe27525 100644 --- a/src/process/FFTVisualDataThread.cpp +++ b/src/process/FFTVisualDataThread.cpp @@ -37,7 +37,7 @@ void FFTVisualDataThread::run() { while(!terminated) { - std::this_thread::sleep_for(std::chrono::milliseconds(12)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); int fftSize = wproc.getDesiredInputSize(); diff --git a/src/process/FFTVisualDataThread.h b/src/process/FFTVisualDataThread.h index a08cd4d..31eb971 100644 --- a/src/process/FFTVisualDataThread.h +++ b/src/process/FFTVisualDataThread.h @@ -2,6 +2,7 @@ #include "IOThread.h" #include "SpectrumVisualProcessor.h" +#include "FFTDataDistributor.h" class FFTVisualDataThread : public IOThread { public: diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index e19cc51..7e76654 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -6,7 +6,7 @@ #include SDRPostThread::SDRPostThread() : IOThread(), - iqDataInQueue(NULL), iqDataOutQueue(NULL), iqVisualQueue(NULL), dcFilter(NULL), num_vis_samples(16384*2) { + iqDataInQueue(NULL), iqDataOutQueue(NULL), iqVisualQueue(NULL), dcFilter(NULL){ swapIQ.store(false); @@ -50,14 +50,6 @@ void SDRPostThread::removeDemodulator(DemodulatorInstance *demod) { busy_demod.unlock(); } -void SDRPostThread::setNumVisSamples(int num_vis_samples_in) { - num_vis_samples = num_vis_samples_in; -} - -int SDRPostThread::getNumVisSamples() { - return num_vis_samples; -} - void SDRPostThread::setSwapIQ(bool swapIQ) { this->swapIQ.store(swapIQ); } @@ -93,7 +85,6 @@ 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; @@ -118,21 +109,19 @@ void SDRPostThread::run() { iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]); - if (iqVisualQueue != NULL && iqVisualQueue->empty()) { + if (iqVisualQueue != NULL && !iqVisualQueue->full()) { DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer(); visualDataOut->setRefCount(1); - if (num_vis_samples > dataOut.size()) { - num_vis_samples = dataOut.size(); - } + int num_vis_samples = dataOut.size(); - 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); - } - +// 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); diff --git a/src/sdr/SDRPostThread.h b/src/sdr/SDRPostThread.h index e08ab58..0162e7e 100644 --- a/src/sdr/SDRPostThread.h +++ b/src/sdr/SDRPostThread.h @@ -11,9 +11,6 @@ public: void bindDemodulator(DemodulatorInstance *demod); void removeDemodulator(DemodulatorInstance *demod); - void setNumVisSamples(int num_vis_samples_in); - int getNumVisSamples(); - void setSwapIQ(bool swapIQ); bool getSwapIQ(); @@ -28,7 +25,6 @@ protected: std::mutex busy_demod; std::vector demodulators; iirfilt_crcf dcFilter; - int num_vis_samples; std::atomic_bool swapIQ; ReBuffer visualDataBuffers; From 125a967ee33c624e853aee6fb72442aa9203b06f Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 7 Sep 2015 20:53:55 -0400 Subject: [PATCH 08/25] svp header update --- src/process/SpectrumVisualProcessor.h | 72 --------------------------- 1 file changed, 72 deletions(-) diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index 149c170..6b7d079 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -69,75 +69,3 @@ private: std::atomic_int desiredInputSize; std::mutex busy_run; }; - - -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) { - if (lineRateAccum + (lineRateStep * floor((double)inp->data.size()/(double)fftSize)) < 1.0) { - // move along, nothing to see here.. - lineRateAccum += (lineRateStep * inp->data.size()/fftSize); - } else 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; -}; From ed2dd5e5d4aacb95d8196991bba13fb445412070 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 7 Sep 2015 20:54:09 -0400 Subject: [PATCH 09/25] svp timing --- src/process/SpectrumVisualDataThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/process/SpectrumVisualDataThread.cpp b/src/process/SpectrumVisualDataThread.cpp index cd737f4..360c7e6 100644 --- a/src/process/SpectrumVisualDataThread.cpp +++ b/src/process/SpectrumVisualDataThread.cpp @@ -16,7 +16,7 @@ void SpectrumVisualDataThread::run() { std::cout << "Spectrum visual data thread started." << std::endl; while(!terminated) { - std::this_thread::sleep_for(std::chrono::milliseconds(12)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); sproc.run(); } From 11121d8a0e1269c9b07385f6c33c311e1faff6bc Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 8 Sep 2015 21:32:15 -0400 Subject: [PATCH 10/25] waterfall jitter and general refresh improvements --- src/AppFrame.cpp | 4 +++- src/CubicSDR.cpp | 6 +++++- src/CubicSDR.h | 3 ++- src/process/FFTVisualDataThread.cpp | 5 +++-- src/process/SpectrumVisualDataThread.cpp | 3 ++- src/visual/MeterCanvas.cpp | 12 ++++++++++-- src/visual/ModeSelectorCanvas.cpp | 9 +++++++-- src/visual/ScopeCanvas.cpp | 4 ++++ src/visual/SpectrumCanvas.cpp | 4 ++++ src/visual/WaterfallCanvas.cpp | 20 +++++++++++++++++--- 10 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 0a20f77..2942555 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -49,7 +49,7 @@ AppFrame::AppFrame() : wxBoxSizer *demodTray = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *demodScopeTray = new wxBoxSizer(wxVERTICAL); - int attribList[] = { WX_GL_RGBA, WX_GL_STENCIL_SIZE, 8, WX_GL_BUFFER_SIZE, 24, WX_GL_DOUBLEBUFFER, 0 }; + int attribList[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; demodModeSelector = new ModeSelectorCanvas(this, attribList); demodModeSelector->addChoice(DEMOD_TYPE_FM, "FM"); @@ -840,7 +840,9 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); waterfallCanvas->processInputQueue(); +// waterfallCanvas->Refresh(); demodWaterfallCanvas->processInputQueue(); +// demodWaterfallCanvas->Refresh(); if (!this->IsActive()) { std::this_thread::sleep_for(std::chrono::milliseconds(25)); diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 769f9c5..56fcf70 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -90,7 +90,7 @@ bool CubicSDR::OnInit() { sdrThread->setOutputQueue("IQDataOutput",pipeSDRIQData); sdrPostThread = new SDRPostThread(); - sdrPostThread->setNumVisSamples(BUF_SIZE); +// sdrPostThread->setNumVisSamples(BUF_SIZE); sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData); sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData); sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData); @@ -427,6 +427,10 @@ void CubicSDR::showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetM fdialog.ShowModal(); } +AppFrame *CubicSDR::getAppFrame() { + return appframe; +} + void CubicSDR::setFrequencySnap(int snap) { if (snap > 1000000) { snap = 1000000; diff --git a/src/CubicSDR.h b/src/CubicSDR.h index a1d4aec..51640bd 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -80,7 +80,8 @@ public: int getPPM(); void showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetMode = FrequencyDialog::FDIALOG_TARGET_DEFAULT); - + AppFrame *getAppFrame(); + private: AppFrame *appframe; AppConfig config; diff --git a/src/process/FFTVisualDataThread.cpp b/src/process/FFTVisualDataThread.cpp index fe27525..6ec7f36 100644 --- a/src/process/FFTVisualDataThread.cpp +++ b/src/process/FFTVisualDataThread.cpp @@ -37,7 +37,8 @@ void FFTVisualDataThread::run() { while(!terminated) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); +// std::this_thread::yield(); int fftSize = wproc.getDesiredInputSize(); @@ -49,7 +50,7 @@ void FFTVisualDataThread::run() { if (lpsChanged.load()) { fftDistrib.setLinesPerSecond(linesPerSecond.load()); - pipeIQDataIn->set_max_num_items(linesPerSecond.load()); +// pipeIQDataIn->set_max_num_items(linesPerSecond.load()); lpsChanged.store(false); } diff --git a/src/process/SpectrumVisualDataThread.cpp b/src/process/SpectrumVisualDataThread.cpp index 360c7e6..e6dc1ac 100644 --- a/src/process/SpectrumVisualDataThread.cpp +++ b/src/process/SpectrumVisualDataThread.cpp @@ -16,7 +16,8 @@ void SpectrumVisualDataThread::run() { std::cout << "Spectrum visual data thread started." << std::endl; while(!terminated) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); +// std::this_thread::yield(); sproc.run(); } diff --git a/src/visual/MeterCanvas.cpp b/src/visual/MeterCanvas.cpp index 46153a0..6986788 100644 --- a/src/visual/MeterCanvas.cpp +++ b/src/visual/MeterCanvas.cpp @@ -36,6 +36,7 @@ MeterCanvas::~MeterCanvas() { void MeterCanvas::setLevel(float level_in) { level = level_in; + Refresh(); } float MeterCanvas::getLevel() { return level; @@ -43,10 +44,12 @@ float MeterCanvas::getLevel() { void MeterCanvas::setMax(float max_in) { level_max = max_in; + Refresh(); } void MeterCanvas::setInputValue(float slider_in) { userInputValue = inputValue = slider_in; + Refresh(); } bool MeterCanvas::inputChanged() { @@ -60,6 +63,7 @@ float MeterCanvas::getInputValue() { void MeterCanvas::setShowUserInput(bool showUserInput) { this->showUserInput = showUserInput; + Refresh(); } void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { @@ -87,8 +91,7 @@ void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void MeterCanvas::OnIdle(wxIdleEvent &event) { - Refresh(); - event.RequestMore(); + event.Skip(); } void MeterCanvas::OnMouseMoved(wxMouseEvent& event) { @@ -101,21 +104,25 @@ void MeterCanvas::OnMouseMoved(wxMouseEvent& event) { setStatusText(helpTip); } } + Refresh(); } void MeterCanvas::OnMouseDown(wxMouseEvent& event) { InteractiveCanvas::OnMouseDown(event); userInputValue = mouseTracker.getMouseY() * level_max; mouseTracker.setHorizDragLock(true); + Refresh(); } void MeterCanvas::OnMouseWheelMoved(wxMouseEvent& event) { InteractiveCanvas::OnMouseWheelMoved(event); + Refresh(); } void MeterCanvas::OnMouseReleased(wxMouseEvent& event) { InteractiveCanvas::OnMouseReleased(event); userInputValue = mouseTracker.getMouseY() * level_max; + Refresh(); } void MeterCanvas::OnMouseLeftWindow(wxMouseEvent& event) { @@ -127,6 +134,7 @@ void MeterCanvas::OnMouseLeftWindow(wxMouseEvent& event) { void MeterCanvas::OnMouseEnterWindow(wxMouseEvent& event) { InteractiveCanvas::mouseTracker.OnMouseEnterWindow(event); SetCursor(wxCURSOR_CROSS); + Refresh(); } void MeterCanvas::setHelpTip(std::string tip) { diff --git a/src/visual/ModeSelectorCanvas.cpp b/src/visual/ModeSelectorCanvas.cpp index 425fad6..4364cf6 100644 --- a/src/visual/ModeSelectorCanvas.cpp +++ b/src/visual/ModeSelectorCanvas.cpp @@ -79,18 +79,19 @@ void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void ModeSelectorCanvas::OnIdle(wxIdleEvent &event) { - Refresh(); - event.RequestMore(); + event.Skip(); } void ModeSelectorCanvas::OnMouseMoved(wxMouseEvent& event) { InteractiveCanvas::OnMouseMoved(event); + Refresh(); } void ModeSelectorCanvas::OnMouseDown(wxMouseEvent& event) { InteractiveCanvas::OnMouseDown(event); mouseTracker.setHorizDragLock(true); mouseTracker.setVertDragLock(true); + Refresh(); } void ModeSelectorCanvas::OnMouseWheelMoved(wxMouseEvent& event) { @@ -120,6 +121,7 @@ void ModeSelectorCanvas::OnMouseReleased(wxMouseEvent& event) { currentSelection = selectedButton; SetCursor (wxCURSOR_HAND); + Refresh(); } void ModeSelectorCanvas::OnMouseLeftWindow(wxMouseEvent& event) { @@ -134,6 +136,7 @@ void ModeSelectorCanvas::OnMouseEnterWindow(wxMouseEvent& event) { if (!helpTip.empty()) { setStatusText(helpTip); } + Refresh(); } void ModeSelectorCanvas::setHelpTip(std::string tip) { @@ -142,6 +145,7 @@ void ModeSelectorCanvas::setHelpTip(std::string tip) { void ModeSelectorCanvas::setNumChoices(int numChoices_in) { numChoices = numChoices_in; + Refresh(); } void ModeSelectorCanvas::addChoice(int value, std::string label) { @@ -157,6 +161,7 @@ void ModeSelectorCanvas::setSelection(int value) { } } currentSelection = -1; + Refresh(); } int ModeSelectorCanvas::getSelection() { diff --git a/src/visual/ScopeCanvas.cpp b/src/visual/ScopeCanvas.cpp index 9dfaced..e6a8c99 100644 --- a/src/visual/ScopeCanvas.cpp +++ b/src/visual/ScopeCanvas.cpp @@ -102,6 +102,10 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); const wxSize ClientSize = GetClientSize(); +#ifdef __APPLE__ + glFinish(); +#endif + while (!inputData.empty()) { ScopeRenderData *avData; inputData.pop(avData); diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index adcc96c..220aa04 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -45,6 +45,10 @@ SpectrumCanvas::~SpectrumCanvas() { void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); const wxSize ClientSize = GetClientSize(); +#ifdef __APPLE__ + glFinish(); +#endif + if (!visualDataQueue.empty()) { SpectrumVisualData *vData; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 108a1e2..15299b9 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -74,6 +74,7 @@ void WaterfallCanvas::processInputQueue() { } glContext->SetCurrent(*this); + bool processed = false; while (!visualDataQueue.empty()) { SpectrumVisualData *vData; @@ -83,14 +84,24 @@ void WaterfallCanvas::processInputQueue() { waterfallPanel.setPoints(vData->spectrum_points); waterfallPanel.step(); vData->decRefCount(); + processed = true; } } + if (processed) { + Refresh(); + } } void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { // wxClientDC dc(this); wxPaintDC dc(this); +//#ifdef __APPLE__ +// glFinish(); +//#endif + +// processInputQueue(); + const wxSize ClientSize = GetClientSize(); long double currentZoom = zoom; @@ -272,6 +283,7 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->EndDraw(); + glFlush(); SwapBuffers(); } @@ -389,9 +401,11 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { - Refresh(); - event.RequestMore(); -// event.Skip(); +// Refresh(); +// processInputQueue(); +// Refresh(); +// event.RequestMore(); + event.Skip(); } void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { From 7163cd13f2e8ae2dd5bee7cd382dc7470d919a76 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 9 Sep 2015 17:31:55 -0400 Subject: [PATCH 11/25] Spectrum panel init fixes, more FFT distributor tweaks --- src/panel/SpectrumPanel.cpp | 21 ++++++++++++++++----- src/process/FFTDataDistributor.cpp | 4 ++-- src/visual/ScopeCanvas.cpp | 6 +++--- src/visual/SpectrumCanvas.cpp | 6 +++--- src/visual/WaterfallCanvas.cpp | 4 ++-- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/panel/SpectrumPanel.cpp b/src/panel/SpectrumPanel.cpp index 034d3c5..ac2ac3e 100644 --- a/src/panel/SpectrumPanel.cpp +++ b/src/panel/SpectrumPanel.cpp @@ -4,8 +4,16 @@ #include #include #include "ColorTheme.h" +#include "CubicSDRDefs.h" -SpectrumPanel::SpectrumPanel() : floorValue(0), ceilValue(1), showDb(false), fftSize(2048) { +SpectrumPanel::SpectrumPanel() { + floorValue = 0; + ceilValue = 1; + showDb = false; + fftSize = DEFAULT_FFT_SIZE; + bandwidth = DEFAULT_DEMOD_BW; + freq = 0; + setFill(GLPANEL_FILL_GRAD_Y); setFillColor(ThemeMgr::mgr.currentTheme->fftBackground * 2.0, ThemeMgr::mgr.currentTheme->fftBackground); @@ -233,15 +241,18 @@ void SpectrumPanel::drawPanelContents() { float dbPanelHeight = (1.0/viewHeight)*14.0; - std::stringstream ssLabel; - ssLabel << std::fixed << std::setprecision(1) << (20.0 * log10(2.0*(getCeilValue())/(double)fftSize)) << "dB"; - + std::stringstream ssLabel(""); + if (getCeilValue() != getFloorValue() && fftSize) { + ssLabel << std::fixed << std::setprecision(1) << (20.0 * log10(2.0*(getCeilValue())/(double)fftSize)) << "dB"; + } dbPanelCeil.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT); dbPanelCeil.setSize(dbPanelWidth, dbPanelHeight); dbPanelCeil.setPosition(-1.0 + dbPanelWidth, 1.0 - dbPanelHeight); ssLabel.str(""); - ssLabel << (20.0 * log10(2.0*(getFloorValue())/(double)fftSize)) << "dB"; + if (getCeilValue() != getFloorValue() && fftSize) { + ssLabel << (20.0 * log10(2.0*(getFloorValue())/(double)fftSize)) << "dB"; + } dbPanelFloor.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT); dbPanelFloor.setSize(dbPanelWidth, dbPanelHeight); diff --git a/src/process/FFTDataDistributor.cpp b/src/process/FFTDataDistributor.cpp index 818c955..aecb0cc 100644 --- a/src/process/FFTDataDistributor.cpp +++ b/src/process/FFTDataDistributor.cpp @@ -16,7 +16,7 @@ int FFTDataDistributor::getLinesPerSecond() { } void FFTDataDistributor::process() { - while (!input->empty()) { + if (!input->empty()) { if (!isAnyOutputEmpty()) { return; } @@ -33,7 +33,7 @@ void FFTDataDistributor::process() { } inp->decRefCount(); } else { - continue; + return; } // number of seconds contained in input diff --git a/src/visual/ScopeCanvas.cpp b/src/visual/ScopeCanvas.cpp index e6a8c99..6c22dc7 100644 --- a/src/visual/ScopeCanvas.cpp +++ b/src/visual/ScopeCanvas.cpp @@ -102,9 +102,9 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); const wxSize ClientSize = GetClientSize(); -#ifdef __APPLE__ - glFinish(); -#endif +//#ifdef __APPLE__ +// glFinish(); +//#endif while (!inputData.empty()) { ScopeRenderData *avData; diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index 220aa04..557398c 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -45,9 +45,9 @@ SpectrumCanvas::~SpectrumCanvas() { void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); const wxSize ClientSize = GetClientSize(); -#ifdef __APPLE__ - glFinish(); -#endif +//#ifdef __APPLE__ +// glFinish(); +//#endif if (!visualDataQueue.empty()) { diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 15299b9..bfd1bc6 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -75,9 +75,9 @@ void WaterfallCanvas::processInputQueue() { glContext->SetCurrent(*this); bool processed = false; - while (!visualDataQueue.empty()) { + int numVis = visualDataQueue.size(); + for (int i = 0; i < numVis; i++) { SpectrumVisualData *vData; - visualDataQueue.pop(vData); if (vData) { From a1bf5b839eb63ab3ffe382db8c5b8e80a2a38240 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 9 Sep 2015 23:29:38 -0400 Subject: [PATCH 12/25] Prototype waterfall rate smoothing / fps matching --- src/AppFrame.cpp | 3 ++ src/IOThread.h | 3 +- src/process/FFTDataDistributor.cpp | 12 +++--- src/util/Timer.cpp | 13 +++++++ src/util/Timer.h | 3 ++ src/visual/WaterfallCanvas.cpp | 61 ++++++++++++++++++++++-------- src/visual/WaterfallCanvas.h | 11 ++++-- 7 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 2942555..f2ec1e0 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -395,6 +395,7 @@ AppFrame::AppFrame() : waterfallSpeedMeter->setLevel(sqrt(wflps)); waterfallDataThread->setLinesPerSecond(wflps); + waterfallCanvas->setLinesPerSecond(wflps); ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme()); @@ -507,6 +508,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) { spectrumCanvas->setBandwidth(wxGetApp().getSampleRate()); spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); waterfallDataThread->setLinesPerSecond(DEFAULT_WATERFALL_LPS); + waterfallCanvas->setLinesPerSecond(DEFAULT_WATERFALL_LPS); waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS)); wxGetApp().getSpectrumProcessor()->setFFTAverageRate(0.65); spectrumAvgMeter->setLevel(0.65); @@ -832,6 +834,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { float val = waterfallSpeedMeter->getInputValue(); waterfallSpeedMeter->setLevel(val); waterfallDataThread->setLinesPerSecond((int)ceil(val*val)); + waterfallCanvas->setLinesPerSecond((int)ceil(val*val)); GetStatusBar()->SetStatusText(wxString::Format(wxT("Waterfall max speed changed to %d lines per second."),(int)ceil(val*val))); } diff --git a/src/IOThread.h b/src/IOThread.h index 743635c..ac3e36b 100644 --- a/src/IOThread.h +++ b/src/IOThread.h @@ -8,6 +8,7 @@ #include #include "ThreadQueue.h" +#include "Timer.h" struct map_string_less : public std::binary_function { @@ -112,9 +113,9 @@ public: void setOutputQueue(std::string qname, ThreadQueueBase *threadQueue); void *getOutputQueue(std::string qname); - protected: std::map input_queues; std::map output_queues; std::atomic_bool terminated; + Timer gTimer; }; diff --git a/src/process/FFTDataDistributor.cpp b/src/process/FFTDataDistributor.cpp index aecb0cc..2f78953 100644 --- a/src/process/FFTDataDistributor.cpp +++ b/src/process/FFTDataDistributor.cpp @@ -47,11 +47,11 @@ void FFTDataDistributor::process() { if (inputBuffer.data.size() >= fftSize) { int numProcessed = 0; -// if (lineRateAccum + (lineRateStep * floor((double)inputBuffer.data.size()/(double)fftSize)) < 1.0) { -// // move along, nothing to see here.. -// lineRateAccum += (lineRateStep * inputBuffer.data.size()/fftSize); -// numProcessed = inputBuffer.data.size()/fftSize; -// } else { + if (lineRateAccum + (lineRateStep * ((double)inputBuffer.data.size()/(double)fftSize)) < 1.0) { + // move along, nothing to see here.. + lineRateAccum += (lineRateStep * ((double)inputBuffer.data.size()/(double)fftSize)); + numProcessed = inputBuffer.data.size(); + } else { for (int i = 0, iMax = inputBuffer.data.size(); i < iMax; i += fftSize) { if ((i + fftSize) > iMax) { break; @@ -72,7 +72,7 @@ void FFTDataDistributor::process() { numProcessed += fftSize; } -// } + } if (numProcessed) { inputBuffer.data.erase(inputBuffer.data.begin(), inputBuffer.data.begin() + numProcessed); } diff --git a/src/util/Timer.cpp b/src/util/Timer.cpp index 99ca67a..b45812b 100644 --- a/src/util/Timer.cpp +++ b/src/util/Timer.cpp @@ -5,6 +5,8 @@ #include #endif +#include + Timer::Timer(void) : time_elapsed(0), system_milliseconds(0), start_time(0), end_time(0), last_update(0), num_updates(0), paused_time(0), offset(0), paused_state(false), lock_state(0), lock_rate(0) { } @@ -157,3 +159,14 @@ bool Timer::paused() { return paused_state; } + +void Timer::timerTestFunc() { + update(); + if (getNumUpdates() % 120 == 0) { + std::cout << getNumUpdates() << "," << getSeconds() << " Rate: " << ((double)getNumUpdates()/getSeconds()) << "/sec" << std::endl; + } + if (getNumUpdates() >= 600) { + reset(); + } +} + diff --git a/src/util/Timer.h b/src/util/Timer.h index 58589d6..554face 100644 --- a/src/util/Timer.h +++ b/src/util/Timer.h @@ -155,6 +155,9 @@ public: * \return Current pause state, true if paused, false otherwise */ bool paused(); + + + void timerTestFunc(); }; #endif diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index bfd1bc6..1ae983f 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -39,7 +39,9 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : dragOfs(0), mouseZoom(1), zoom(1), freqMove(0.0), freqMoving(false), hoverAlpha(1.0) { glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this)); - + linesPerSecond = 30; + lpsIndex = 0; + preBuf = false; SetCursor(wxCURSOR_CROSS); } @@ -54,6 +56,8 @@ void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) { waterfall_lines = waterfall_lines_in; waterfallPanel.setup(fft_size, waterfall_lines); + gTimer.start(); + testTimer.start(); } WaterfallCanvas::DragState WaterfallCanvas::getDragState() { @@ -75,25 +79,47 @@ void WaterfallCanvas::processInputQueue() { glContext->SetCurrent(*this); bool processed = false; - int numVis = visualDataQueue.size(); - for (int i = 0; i < numVis; i++) { - SpectrumVisualData *vData; - visualDataQueue.pop(vData); - - if (vData) { - waterfallPanel.setPoints(vData->spectrum_points); - waterfallPanel.step(); - vData->decRefCount(); - processed = true; +// int numVis = visualDataQueue.size(); + + gTimer.update(); +// if (visualDataQueue.size() < 10 && !preBuf) { +// return; +// } else { +// preBuf = true; +// if (visualDataQueue.size() < 2) { +// preBuf = false; +// } +// } +// + double targetVis = 1.0 / (double)linesPerSecond; + lpsIndex += gTimer.lastUpdateSeconds(); + + if (linesPerSecond) { + if (lpsIndex >= targetVis) { + while (lpsIndex >= targetVis) { + SpectrumVisualData *vData; + if (!visualDataQueue.empty()) { + visualDataQueue.pop(vData); + + if (vData) { + waterfallPanel.setPoints(vData->spectrum_points); + waterfallPanel.step(); + vData->decRefCount(); + processed = true; + } + } + lpsIndex-=targetVis; + } } } if (processed) { - Refresh(); +// Refresh(); } } void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { // wxClientDC dc(this); + testTimer.timerTestFunc(); wxPaintDC dc(this); //#ifdef __APPLE__ @@ -401,11 +427,11 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { -// Refresh(); + Refresh(); // processInputQueue(); // Refresh(); -// event.RequestMore(); - event.Skip(); + event.RequestMore(); +// event.Skip(); } void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { @@ -793,3 +819,8 @@ void WaterfallCanvas::updateCenterFrequency(long long freq) { } +void WaterfallCanvas::setLinesPerSecond(int lps) { + linesPerSecond = lps; +} + + diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 28d0070..7887618 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -10,7 +10,7 @@ #include "MouseTracker.h" #include "SpectrumCanvas.h" #include "WaterfallPanel.h" - +#include "Timer.h" class WaterfallCanvas: public InteractiveCanvas { public: @@ -29,6 +29,8 @@ public: void processInputQueue(); SpectrumVisualDataQueue *getVisualDataQueue(); + void setLinesPerSecond(int lps); + private: void OnPaint(wxPaintEvent& event); void OnKeyDown(wxKeyEvent& event); @@ -64,9 +66,12 @@ private: bool freqMoving; long double freqMove; float hoverAlpha; - + int linesPerSecond; + SpectrumVisualDataQueue visualDataQueue; - + Timer gTimer, testTimer; + double lpsIndex; + bool preBuf; // event table wxDECLARE_EVENT_TABLE(); }; From 43b30367d93547c751689c2713717a23e16891f5 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 9 Sep 2015 23:46:05 -0400 Subject: [PATCH 13/25] Visual queue smoothing tweak --- src/process/FFTDataDistributor.cpp | 4 ++-- src/visual/WaterfallCanvas.cpp | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/process/FFTDataDistributor.cpp b/src/process/FFTDataDistributor.cpp index 2f78953..99bb38f 100644 --- a/src/process/FFTDataDistributor.cpp +++ b/src/process/FFTDataDistributor.cpp @@ -16,7 +16,7 @@ int FFTDataDistributor::getLinesPerSecond() { } void FFTDataDistributor::process() { - if (!input->empty()) { + while (!input->empty()) { if (!isAnyOutputEmpty()) { return; } @@ -33,7 +33,7 @@ void FFTDataDistributor::process() { } inp->decRefCount(); } else { - return; + continue; } // number of seconds contained in input diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 1ae983f..84c450e 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -113,7 +113,7 @@ void WaterfallCanvas::processInputQueue() { } } if (processed) { -// Refresh(); + Refresh(); } } @@ -427,11 +427,11 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { - Refresh(); +// Refresh(); // processInputQueue(); // Refresh(); - event.RequestMore(); -// event.Skip(); +// event.RequestMore(); + event.Skip(); } void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { @@ -821,6 +821,15 @@ void WaterfallCanvas::updateCenterFrequency(long long freq) { void WaterfallCanvas::setLinesPerSecond(int lps) { linesPerSecond = lps; + while (!visualDataQueue.empty()) { + SpectrumVisualData *vData; + visualDataQueue.pop(vData); + + if (vData) { + vData->decRefCount(); + } + } + } From fc9ff9c8779c1810a2b949180789bea1f9503d30 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 9 Sep 2015 23:46:23 -0400 Subject: [PATCH 14/25] iq data operator --- src/demod/DemodDefs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/demod/DemodDefs.h b/src/demod/DemodDefs.h index 12a8dd4..0f49ccd 100644 --- a/src/demod/DemodDefs.h +++ b/src/demod/DemodDefs.h @@ -71,6 +71,13 @@ public: } + DemodulatorThreadIQData & operator=(const DemodulatorThreadIQData &other) { + frequency = other.frequency; + sampleRate = other.sampleRate; + data.assign(other.data.begin(), other.data.end()); + return *this; + } + ~DemodulatorThreadIQData() { } From 7b48a1f4557fb51f411d9d4e7a0d44f40533872a Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 10 Sep 2015 00:55:39 -0400 Subject: [PATCH 15/25] Windows Timer fixes --- src/util/Timer.cpp | 9 ++++++--- src/util/Timer.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/util/Timer.cpp b/src/util/Timer.cpp index b45812b..bc6de22 100644 --- a/src/util/Timer.cpp +++ b/src/util/Timer.cpp @@ -1,13 +1,14 @@ #include "Timer.h" -#ifdef WIN32 +#ifdef _WIN32 + #include #include #endif #include -Timer::Timer(void) : time_elapsed(0), system_milliseconds(0), start_time(0), end_time(0), last_update(0), num_updates(0), paused_time(0), offset(0), paused_state(false), lock_state(0), lock_rate(0) +Timer::Timer(void) : time_elapsed(0), system_milliseconds(0), start_time(0), end_time(0), last_update(0), num_updates(0), paused_time(0), offset(0), paused_state(false), lock_state(false), lock_rate(0) { } @@ -77,8 +78,10 @@ void Timer::update(void) } else { -#ifdef WIN32 +#ifdef _WIN32 + system_milliseconds = timeGetTime (); + #else gettimeofday(&time_val,&time_zone); diff --git a/src/util/Timer.h b/src/util/Timer.h index 554face..18ab841 100644 --- a/src/util/Timer.h +++ b/src/util/Timer.h @@ -24,7 +24,7 @@ private: unsigned long paused_time; unsigned long offset; -#ifndef WIN32 +#ifndef _WIN32 struct timeval time_val; struct timezone time_zone; #endif From 0b7cbbde35bb927f70c9bb9b8700f39cb77b32f4 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 10 Sep 2015 01:26:05 -0400 Subject: [PATCH 16/25] fix skewing lag offset, mouse hover issues --- src/AppFrame.cpp | 4 ++-- src/visual/MeterCanvas.cpp | 8 +++++--- src/visual/ModeSelectorCanvas.cpp | 8 +++++--- src/visual/WaterfallCanvas.cpp | 14 ++++++++------ 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index f2ec1e0..ee27f37 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -842,9 +842,9 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wproc->setBandwidth(waterfallCanvas->getBandwidth()); wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); - waterfallCanvas->processInputQueue(); +// waterfallCanvas->processInputQueue(); // waterfallCanvas->Refresh(); - demodWaterfallCanvas->processInputQueue(); +// demodWaterfallCanvas->processInputQueue(); // demodWaterfallCanvas->Refresh(); if (!this->IsActive()) { diff --git a/src/visual/MeterCanvas.cpp b/src/visual/MeterCanvas.cpp index 6986788..4fe5e14 100644 --- a/src/visual/MeterCanvas.cpp +++ b/src/visual/MeterCanvas.cpp @@ -63,7 +63,6 @@ float MeterCanvas::getInputValue() { void MeterCanvas::setShowUserInput(bool showUserInput) { this->showUserInput = showUserInput; - Refresh(); } void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { @@ -91,7 +90,11 @@ void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void MeterCanvas::OnIdle(wxIdleEvent &event) { - event.Skip(); + if (mouseTracker.mouseInView()) { + Refresh(); + } else { + event.Skip(); + } } void MeterCanvas::OnMouseMoved(wxMouseEvent& event) { @@ -104,7 +107,6 @@ void MeterCanvas::OnMouseMoved(wxMouseEvent& event) { setStatusText(helpTip); } } - Refresh(); } void MeterCanvas::OnMouseDown(wxMouseEvent& event) { diff --git a/src/visual/ModeSelectorCanvas.cpp b/src/visual/ModeSelectorCanvas.cpp index 4364cf6..f52f533 100644 --- a/src/visual/ModeSelectorCanvas.cpp +++ b/src/visual/ModeSelectorCanvas.cpp @@ -79,19 +79,21 @@ void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void ModeSelectorCanvas::OnIdle(wxIdleEvent &event) { - event.Skip(); + if (mouseTracker.mouseInView()) { + Refresh(); + } else { + event.Skip(); + } } void ModeSelectorCanvas::OnMouseMoved(wxMouseEvent& event) { InteractiveCanvas::OnMouseMoved(event); - Refresh(); } void ModeSelectorCanvas::OnMouseDown(wxMouseEvent& event) { InteractiveCanvas::OnMouseDown(event); mouseTracker.setHorizDragLock(true); mouseTracker.setVertDragLock(true); - Refresh(); } void ModeSelectorCanvas::OnMouseWheelMoved(wxMouseEvent& event) { diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 84c450e..e683e71 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -107,14 +107,16 @@ void WaterfallCanvas::processInputQueue() { vData->decRefCount(); processed = true; } + lpsIndex-=targetVis; + } else { + break; } - lpsIndex-=targetVis; } } } - if (processed) { +// if (processed) { Refresh(); - } +// } } void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { @@ -428,10 +430,10 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { // Refresh(); -// processInputQueue(); + processInputQueue(); // Refresh(); -// event.RequestMore(); - event.Skip(); + event.RequestMore(); +// event.Skip(); } void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { From 4301d0d4348a057c44c829be00da0de5723453fb Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 10 Sep 2015 19:56:15 -0400 Subject: [PATCH 17/25] fix missing processed check --- src/visual/WaterfallCanvas.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index e683e71..f4d4347 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -82,15 +82,18 @@ void WaterfallCanvas::processInputQueue() { // int numVis = visualDataQueue.size(); gTimer.update(); -// if (visualDataQueue.size() < 10 && !preBuf) { -// return; -// } else { -// preBuf = true; -// if (visualDataQueue.size() < 2) { -// preBuf = false; +// if (linesPerSecond >= 30) { +// if ((visualDataQueue.size() < (linesPerSecond/5)) && !preBuf) { +// return; +// } else { +// if (visualDataQueue.size() < (linesPerSecond/10)) { +// preBuf = false; +// } else { +// preBuf = true; +// } // } // } -// + double targetVis = 1.0 / (double)linesPerSecond; lpsIndex += gTimer.lastUpdateSeconds(); @@ -114,14 +117,14 @@ void WaterfallCanvas::processInputQueue() { } } } -// if (processed) { + if (processed) { Refresh(); -// } + } } void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { // wxClientDC dc(this); - testTimer.timerTestFunc(); +// testTimer.timerTestFunc(); wxPaintDC dc(this); //#ifdef __APPLE__ From 0a6d409065a4c33559c36be75eb72103c2a61110 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 10 Sep 2015 21:48:18 -0400 Subject: [PATCH 18/25] tex update lock, VisualData"Re"Distributor --- src/CubicSDR.cpp | 2 +- src/CubicSDR.h | 4 ++-- src/process/VisualProcessor.h | 22 ++++++++++++++++++++++ src/visual/WaterfallCanvas.cpp | 6 +++++- src/visual/WaterfallCanvas.h | 1 + 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 56fcf70..fcb3b52 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -298,7 +298,7 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcessor() { return demodVisualThread->getProcessor(); } -VisualDataDistributor *CubicSDR::getSpectrumDistributor() { +VisualDataReDistributor *CubicSDR::getSpectrumDistributor() { return &spectrumDistributor; } diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 51640bd..fb84e99 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -60,7 +60,7 @@ public: ScopeVisualProcessor *getScopeProcessor(); SpectrumVisualProcessor *getSpectrumProcessor(); SpectrumVisualProcessor *getDemodSpectrumProcessor(); - VisualDataDistributor *getSpectrumDistributor(); + VisualDataReDistributor *getSpectrumDistributor(); DemodulatorThreadOutputQueue* getAudioVisualQueue(); DemodulatorThreadInputQueue* getIQVisualQueue(); @@ -111,7 +111,7 @@ private: ScopeVisualProcessor scopeProcessor; - VisualDataDistributor spectrumDistributor; + VisualDataReDistributor spectrumDistributor; std::thread *t_SDR; std::thread *t_PostSDR; diff --git a/src/process/VisualProcessor.h b/src/process/VisualProcessor.h index b7662bf..345224b 100644 --- a/src/process/VisualProcessor.h +++ b/src/process/VisualProcessor.h @@ -107,3 +107,25 @@ protected: } }; + +template +class VisualDataReDistributor : public VisualProcessor { +protected: + void process() { + while (!VisualProcessor::input->empty()) { + if (!VisualProcessor::isAnyOutputEmpty()) { + return; + } + OutputDataType *inp; + VisualProcessor::input->pop(inp); + + if (inp) { + OutputDataType *outp = buffers.getBuffer(); + (*outp) = (*inp); + inp->decRefCount(); + VisualProcessor::distribute(outp); + } + } + } + ReBuffer buffers; +}; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index f4d4347..21d9e90 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -99,6 +99,7 @@ void WaterfallCanvas::processInputQueue() { if (linesPerSecond) { if (lpsIndex >= targetVis) { + tex_update.lock(); while (lpsIndex >= targetVis) { SpectrumVisualData *vData; if (!visualDataQueue.empty()) { @@ -115,6 +116,7 @@ void WaterfallCanvas::processInputQueue() { break; } } + tex_update.unlock(); } } if (processed) { @@ -235,7 +237,9 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->BeginDraw(0,0,0); waterfallPanel.calcTransform(CubicVR::mat4::identity()); + tex_update.lock(); waterfallPanel.draw(); + tex_update.unlock(); std::vector &demods = wxGetApp().getDemodMgr().getDemodulators(); @@ -314,7 +318,7 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->EndDraw(); - glFlush(); +// glFlush(); SwapBuffers(); } diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 7887618..d4154a6 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -72,6 +72,7 @@ private: Timer gTimer, testTimer; double lpsIndex; bool preBuf; + std::mutex tex_update; // event table wxDECLARE_EVENT_TABLE(); }; From eec1d7936f02f83a4c4adeb03e2e62b497163f74 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 10 Sep 2015 23:01:10 -0400 Subject: [PATCH 19/25] smoothest windows results so far --- src/visual/WaterfallCanvas.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 21d9e90..7b02d96 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -120,7 +120,7 @@ void WaterfallCanvas::processInputQueue() { } } if (processed) { - Refresh(); +// Refresh(); } } @@ -133,7 +133,7 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { // glFinish(); //#endif -// processInputQueue(); + processInputQueue(); const wxSize ClientSize = GetClientSize(); long double currentZoom = zoom; @@ -437,8 +437,8 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { // Refresh(); - processInputQueue(); -// Refresh(); +// processInputQueue(); + Refresh(); event.RequestMore(); // event.Skip(); } From aa5a162888787ee81b3d0db76d70d43ef9fdfb11 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 10 Sep 2015 23:42:22 -0400 Subject: [PATCH 20/25] Cleanup --- src/CubicSDR.cpp | 2 +- src/visual/ScopeCanvas.cpp | 4 ---- src/visual/SpectrumCanvas.cpp | 4 ---- src/visual/WaterfallCanvas.cpp | 34 ++++------------------------------ 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index fcb3b52..15d187f 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -66,7 +66,7 @@ bool CubicSDR::OnInit() { pipeSpectrumIQVisualData->set_max_num_items(1); pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue(); - pipeWaterfallIQVisualData->set_max_num_items(DEFAULT_WATERFALL_LPS); + pipeWaterfallIQVisualData->set_max_num_items(128); spectrumDistributor.attachOutput(pipeDemodIQVisualData); spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); diff --git a/src/visual/ScopeCanvas.cpp b/src/visual/ScopeCanvas.cpp index 6c22dc7..9dfaced 100644 --- a/src/visual/ScopeCanvas.cpp +++ b/src/visual/ScopeCanvas.cpp @@ -102,10 +102,6 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); const wxSize ClientSize = GetClientSize(); -//#ifdef __APPLE__ -// glFinish(); -//#endif - while (!inputData.empty()) { ScopeRenderData *avData; inputData.pop(avData); diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index 557398c..adcc96c 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -45,10 +45,6 @@ SpectrumCanvas::~SpectrumCanvas() { void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); const wxSize ClientSize = GetClientSize(); -//#ifdef __APPLE__ -// glFinish(); -//#endif - if (!visualDataQueue.empty()) { SpectrumVisualData *vData; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 7b02d96..c7d8dad 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -78,21 +78,7 @@ void WaterfallCanvas::processInputQueue() { } glContext->SetCurrent(*this); - bool processed = false; -// int numVis = visualDataQueue.size(); - gTimer.update(); -// if (linesPerSecond >= 30) { -// if ((visualDataQueue.size() < (linesPerSecond/5)) && !preBuf) { -// return; -// } else { -// if (visualDataQueue.size() < (linesPerSecond/10)) { -// preBuf = false; -// } else { -// preBuf = true; -// } -// } -// } double targetVis = 1.0 / (double)linesPerSecond; lpsIndex += gTimer.lastUpdateSeconds(); @@ -109,7 +95,6 @@ void WaterfallCanvas::processInputQueue() { waterfallPanel.setPoints(vData->spectrum_points); waterfallPanel.step(); vData->decRefCount(); - processed = true; } lpsIndex-=targetVis; } else { @@ -118,21 +103,11 @@ void WaterfallCanvas::processInputQueue() { } tex_update.unlock(); } - } - if (processed) { -// Refresh(); - } -} + }} void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { -// wxClientDC dc(this); -// testTimer.timerTestFunc(); wxPaintDC dc(this); -//#ifdef __APPLE__ -// glFinish(); -//#endif - processInputQueue(); const wxSize ClientSize = GetClientSize(); @@ -318,7 +293,6 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->EndDraw(); -// glFlush(); SwapBuffers(); } @@ -436,11 +410,11 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { } void WaterfallCanvas::OnIdle(wxIdleEvent &event) { -// Refresh(); -// processInputQueue(); Refresh(); event.RequestMore(); -// event.Skip(); + if (visualDataQueue.size() > linesPerSecond) { + processInputQueue(); + } } void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { From 9906816c197e38b788273af61313949996595dbe Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Fri, 11 Sep 2015 00:03:02 -0400 Subject: [PATCH 21/25] Remove test var --- src/visual/WaterfallCanvas.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index d4154a6..03fb07b 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -69,7 +69,7 @@ private: int linesPerSecond; SpectrumVisualDataQueue visualDataQueue; - Timer gTimer, testTimer; + Timer gTimer; double lpsIndex; bool preBuf; std::mutex tex_update; From 261c7c3579e6ec819b15c63cf4410004e2c69963 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Fri, 11 Sep 2015 00:04:22 -0400 Subject: [PATCH 22/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a541eda..1c07547 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Features and Status: - Optimization - [x] Eliminate large waterfall texture uploads - [ ] Update visuals to OpenGL 3.x / OpenGL ES - - [ ] Resolve constant refresh on visuals that don't change often + - [x] Resolve constant refresh on visuals that don't change often - [ ] Resolve all driver/platform vertical sync issues - [ ] Group and divide IQ data distribution workload instead of 100% distribution per instance From 3294b4c10bd659de22072262b72d0a523bdccb9f Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Fri, 11 Sep 2015 00:09:43 -0400 Subject: [PATCH 23/25] set patch release version --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f10bbd5..82f37c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,8 @@ cmake_minimum_required (VERSION 2.8) SET(CUBICSDR_VERSION_MAJOR "0") SET(CUBICSDR_VERSION_MINOR "1") -SET(CUBICSDR_VERSION_PATCH "4") -SET(CUBICSDR_VERSION_REL "beta") +SET(CUBICSDR_VERSION_PATCH "6") +SET(CUBICSDR_VERSION_REL "beta-issue140") SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}-${CUBICSDR_VERSION_REL}") SET(CPACK_PACKAGE_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}") From 45d6531b8279cb42b058e0bfb28867a9907ad436 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Fri, 11 Sep 2015 00:13:30 -0400 Subject: [PATCH 24/25] remove test var --- src/visual/WaterfallCanvas.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index c7d8dad..91e18d6 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -57,7 +57,6 @@ void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) { waterfallPanel.setup(fft_size, waterfall_lines); gTimer.start(); - testTimer.start(); } WaterfallCanvas::DragState WaterfallCanvas::getDragState() { From 7a01c436d64b6fcf36e6cf69ed21ccbe977d64eb Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Fri, 11 Sep 2015 00:42:09 -0400 Subject: [PATCH 25/25] memory leak fix --- src/AppFrame.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 45e5ed7..dd83269 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -77,6 +77,7 @@ AppFrame::AppFrame() : demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas); demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0); wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue()); + demodWaterfallCanvas->getVisualDataQueue()->set_max_num_items(3); demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);