diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ddee92..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 "3") -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}") @@ -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 @@ -423,6 +425,13 @@ IF (MSVC) set(CMAKE_CREATE_WIN32_EXE "/SUBSYSTEM:WINDOWS /ENTRY:\"mainCRTStartup\"") ENDIF(MSVC) +IF (APPLE) + ADD_DEFINITIONS( + -DHAVE_TYPE_TRAITS=1 + -mmacosx-version-min=10.9 + ) +ENDIF(APPLE) + IF (APPLE AND BUNDLE_APP) PROJECT(CubicSDR) SET(MACOSX_BUNDLE_BUNDLE_NAME CubicSDR) @@ -431,8 +440,6 @@ IF (APPLE AND BUNDLE_APP) -std=c++0x -pthread -D_OSX_APP_ - -DHAVE_TYPE_TRAITS=1 - -mmacosx-version-min=10.9 ) ADD_EXECUTABLE(CubicSDR diff --git a/README.md b/README.md index cba51ff..1c07547 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 @@ -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 diff --git a/external/msvc/x86/libgcc_s_dw2-1.dll b/external/msvc/x86/libgcc_s_dw2-1.dll index 9158964..99a76cf 100644 Binary files a/external/msvc/x86/libgcc_s_dw2-1.dll and b/external/msvc/x86/libgcc_s_dw2-1.dll differ diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index a9d162a..dc3cf8d 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"); @@ -104,6 +104,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); @@ -148,6 +149,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); @@ -422,6 +424,7 @@ AppFrame::AppFrame() : waterfallSpeedMeter->setLevel(sqrt(wflps)); waterfallDataThread->setLinesPerSecond(wflps); + waterfallCanvas->setLinesPerSecond(wflps); ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme()); @@ -534,6 +537,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); @@ -893,6 +897,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))); } @@ -900,8 +905,10 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wproc->setBandwidth(waterfallCanvas->getBandwidth()); wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); - waterfallCanvas->processInputQueue(); - demodWaterfallCanvas->processInputQueue(); +// 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 dfbdd73..51344c4 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -89,7 +89,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); @@ -113,7 +113,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); @@ -321,7 +321,7 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcessor() { return demodVisualThread->getProcessor(); } -VisualDataDistributor *CubicSDR::getSpectrumDistributor() { +VisualDataReDistributor *CubicSDR::getSpectrumDistributor() { return &spectrumDistributor; } @@ -450,6 +450,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..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(); @@ -80,7 +80,8 @@ public: int getPPM(); void showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetMode = FrequencyDialog::FDIALOG_TARGET_DEFAULT); - + AppFrame *getAppFrame(); + private: AppFrame *appframe; AppConfig config; @@ -110,7 +111,7 @@ private: ScopeVisualProcessor scopeProcessor; - VisualDataDistributor spectrumDistributor; + VisualDataReDistributor spectrumDistributor; std::thread *t_SDR; std::thread *t_PostSDR; 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/demod/DemodDefs.h b/src/demod/DemodDefs.h index 1daa22f..a9a0d48 100644 --- a/src/demod/DemodDefs.h +++ b/src/demod/DemodDefs.h @@ -81,6 +81,13 @@ public: } + DemodulatorThreadIQData & operator=(const DemodulatorThreadIQData &other) { + frequency = other.frequency; + sampleRate = other.sampleRate; + data.assign(other.data.begin(), other.data.end()); + return *this; + } + ~DemodulatorThreadIQData() { } diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp index 60b65cf..fcc2c1b 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) { } diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 228ad3f..c9b831b 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -696,8 +696,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; 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 new file mode 100644 index 0000000..99bb38f --- /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 * ((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; + } + 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 0e92dbb..6ec7f36 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); } @@ -36,7 +37,8 @@ void FFTVisualDataThread::run() { while(!terminated) { - std::this_thread::sleep_for(std::chrono::milliseconds(12)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); +// std::this_thread::yield(); int fftSize = wproc.getDesiredInputSize(); @@ -48,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/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/process/SpectrumVisualDataThread.cpp b/src/process/SpectrumVisualDataThread.cpp index cd737f4..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(12)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); +// std::this_thread::yield(); sproc.run(); } 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; -}; 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/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; diff --git a/src/util/Timer.cpp b/src/util/Timer.cpp index 99ca67a..bc6de22 100644 --- a/src/util/Timer.cpp +++ b/src/util/Timer.cpp @@ -1,11 +1,14 @@ #include "Timer.h" -#ifdef WIN32 +#ifdef _WIN32 + #include #include #endif -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) +#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(false), lock_rate(0) { } @@ -75,8 +78,10 @@ void Timer::update(void) } else { -#ifdef WIN32 +#ifdef _WIN32 + system_milliseconds = timeGetTime (); + #else gettimeofday(&time_val,&time_zone); @@ -157,3 +162,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..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 @@ -155,6 +155,9 @@ public: * \return Current pause state, true if paused, false otherwise */ bool paused(); + + + void timerTestFunc(); }; #endif diff --git a/src/visual/MeterCanvas.cpp b/src/visual/MeterCanvas.cpp index 46153a0..4fe5e14 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() { @@ -87,8 +90,11 @@ void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void MeterCanvas::OnIdle(wxIdleEvent &event) { - Refresh(); - event.RequestMore(); + if (mouseTracker.mouseInView()) { + Refresh(); + } else { + event.Skip(); + } } void MeterCanvas::OnMouseMoved(wxMouseEvent& event) { @@ -107,15 +113,18 @@ 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 +136,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..f52f533 100644 --- a/src/visual/ModeSelectorCanvas.cpp +++ b/src/visual/ModeSelectorCanvas.cpp @@ -79,8 +79,11 @@ void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { } void ModeSelectorCanvas::OnIdle(wxIdleEvent &event) { - Refresh(); - event.RequestMore(); + if (mouseTracker.mouseInView()) { + Refresh(); + } else { + event.Skip(); + } } void ModeSelectorCanvas::OnMouseMoved(wxMouseEvent& event) { @@ -120,6 +123,7 @@ void ModeSelectorCanvas::OnMouseReleased(wxMouseEvent& event) { currentSelection = selectedButton; SetCursor (wxCURSOR_HAND); + Refresh(); } void ModeSelectorCanvas::OnMouseLeftWindow(wxMouseEvent& event) { @@ -134,6 +138,7 @@ void ModeSelectorCanvas::OnMouseEnterWindow(wxMouseEvent& event) { if (!helpTip.empty()) { setStatusText(helpTip); } + Refresh(); } void ModeSelectorCanvas::setHelpTip(std::string tip) { @@ -142,6 +147,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 +163,7 @@ void ModeSelectorCanvas::setSelection(int value) { } } currentSelection = -1; + Refresh(); } int ModeSelectorCanvas::getSelection() { diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 108a1e2..91e18d6 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,7 @@ void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) { waterfall_lines = waterfall_lines_in; waterfallPanel.setup(fft_size, waterfall_lines); + gTimer.start(); } WaterfallCanvas::DragState WaterfallCanvas::getDragState() { @@ -74,23 +77,38 @@ void WaterfallCanvas::processInputQueue() { } glContext->SetCurrent(*this); - while (!visualDataQueue.empty()) { - SpectrumVisualData *vData; - - visualDataQueue.pop(vData); - - if (vData) { - waterfallPanel.setPoints(vData->spectrum_points); - waterfallPanel.step(); - vData->decRefCount(); + gTimer.update(); + + double targetVis = 1.0 / (double)linesPerSecond; + lpsIndex += gTimer.lastUpdateSeconds(); + + if (linesPerSecond) { + if (lpsIndex >= targetVis) { + tex_update.lock(); + while (lpsIndex >= targetVis) { + SpectrumVisualData *vData; + if (!visualDataQueue.empty()) { + visualDataQueue.pop(vData); + + if (vData) { + waterfallPanel.setPoints(vData->spectrum_points); + waterfallPanel.step(); + vData->decRefCount(); + } + lpsIndex-=targetVis; + } else { + break; + } + } + tex_update.unlock(); } - } -} + }} void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { -// wxClientDC dc(this); wxPaintDC dc(this); + processInputQueue(); + const wxSize ClientSize = GetClientSize(); long double currentZoom = zoom; @@ -193,7 +211,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(); @@ -391,7 +411,9 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { void WaterfallCanvas::OnIdle(wxIdleEvent &event) { Refresh(); event.RequestMore(); -// event.Skip(); + if (visualDataQueue.size() > linesPerSecond) { + processInputQueue(); + } } void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { @@ -779,3 +801,17 @@ 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(); + } + } + +} + + diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 28d0070..03fb07b 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,13 @@ private: bool freqMoving; long double freqMove; float hoverAlpha; - + int linesPerSecond; + SpectrumVisualDataQueue visualDataQueue; - + Timer gTimer; + double lpsIndex; + bool preBuf; + std::mutex tex_update; // event table wxDECLARE_EVENT_TABLE(); };