Merge pull request #143 from cjcliffe/master

update lab
This commit is contained in:
Charles J. Cliffe 2015-09-12 14:11:55 -04:00
commit eaaf6cd02e
26 changed files with 310 additions and 152 deletions

View File

@ -2,8 +2,8 @@ cmake_minimum_required (VERSION 2.8)
SET(CUBICSDR_VERSION_MAJOR "0") SET(CUBICSDR_VERSION_MAJOR "0")
SET(CUBICSDR_VERSION_MINOR "1") SET(CUBICSDR_VERSION_MINOR "1")
SET(CUBICSDR_VERSION_PATCH "3") SET(CUBICSDR_VERSION_PATCH "6")
SET(CUBICSDR_VERSION_REL "beta") SET(CUBICSDR_VERSION_REL "beta-issue140")
SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}-${CUBICSDR_VERSION_REL}") 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}") 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/ScopeVisualProcessor.cpp
src/process/SpectrumVisualProcessor.cpp src/process/SpectrumVisualProcessor.cpp
src/process/FFTVisualDataThread.cpp src/process/FFTVisualDataThread.cpp
src/process/FFTDataDistributor.cpp
src/process/SpectrumVisualDataThread.cpp src/process/SpectrumVisualDataThread.cpp
src/ui/GLPanel.cpp src/ui/GLPanel.cpp
external/rtaudio/RtAudio.cpp external/rtaudio/RtAudio.cpp
@ -319,6 +320,7 @@ SET (cubicsdr_headers
src/process/ScopeVisualProcessor.h src/process/ScopeVisualProcessor.h
src/process/SpectrumVisualProcessor.h src/process/SpectrumVisualProcessor.h
src/process/FFTVisualDataThread.h src/process/FFTVisualDataThread.h
src/process/FFTDataDistributor.h
src/process/SpectrumVisualDataThread.h src/process/SpectrumVisualDataThread.h
src/ui/GLPanel.h src/ui/GLPanel.h
src/ui/UITestCanvas.cpp src/ui/UITestCanvas.cpp
@ -423,6 +425,13 @@ IF (MSVC)
set(CMAKE_CREATE_WIN32_EXE "/SUBSYSTEM:WINDOWS /ENTRY:\"mainCRTStartup\"") set(CMAKE_CREATE_WIN32_EXE "/SUBSYSTEM:WINDOWS /ENTRY:\"mainCRTStartup\"")
ENDIF(MSVC) ENDIF(MSVC)
IF (APPLE)
ADD_DEFINITIONS(
-DHAVE_TYPE_TRAITS=1
-mmacosx-version-min=10.9
)
ENDIF(APPLE)
IF (APPLE AND BUNDLE_APP) IF (APPLE AND BUNDLE_APP)
PROJECT(CubicSDR) PROJECT(CubicSDR)
SET(MACOSX_BUNDLE_BUNDLE_NAME CubicSDR) SET(MACOSX_BUNDLE_BUNDLE_NAME CubicSDR)
@ -431,8 +440,6 @@ IF (APPLE AND BUNDLE_APP)
-std=c++0x -std=c++0x
-pthread -pthread
-D_OSX_APP_ -D_OSX_APP_
-DHAVE_TYPE_TRAITS=1
-mmacosx-version-min=10.9
) )
ADD_EXECUTABLE(CubicSDR ADD_EXECUTABLE(CubicSDR

View File

@ -42,7 +42,7 @@ Features and Status:
- [x] Spectrum - [x] Spectrum
- [x] Waterfall - [x] Waterfall
- [x] Add faint grid for sense of scale - [x] Add faint grid for sense of scale
- [ ] Audio Spectrum - [x] Audio Spectrum
- [ ] X/Y Scope - [ ] X/Y Scope
- [ ] Indicate outer spectrum edges when zoomed - [ ] Indicate outer spectrum edges when zoomed
- [ ] 3D visuals - [ ] 3D visuals
@ -67,8 +67,8 @@ Features and Status:
- [x] Display audio output selection - [x] Display audio output selection
- [x] Volume control - [x] Volume control
- [x] Direct frequency input - [x] Direct frequency input
- [ ] Mute - [x] Mute
- [ ] Waterfall speed - [x] Waterfall speed
- [ ] RTL-SDR Gain - [ ] RTL-SDR Gain
- Basic Input Controls - Basic Input Controls
- [x] Drag spectrum to change center frequency - [x] Drag spectrum to change center frequency
@ -123,7 +123,7 @@ Features and Status:
- Optimization - Optimization
- [x] Eliminate large waterfall texture uploads - [x] Eliminate large waterfall texture uploads
- [ ] Update visuals to OpenGL 3.x / OpenGL ES - [ ] 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 - [ ] Resolve all driver/platform vertical sync issues
- [ ] Group and divide IQ data distribution workload instead of 100% distribution per instance - [ ] Group and divide IQ data distribution workload instead of 100% distribution per instance

Binary file not shown.

View File

@ -49,7 +49,7 @@ AppFrame::AppFrame() :
wxBoxSizer *demodTray = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *demodTray = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *demodScopeTray = new wxBoxSizer(wxVERTICAL); 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 = new ModeSelectorCanvas(this, attribList);
demodModeSelector->addChoice(DEMOD_TYPE_FM, "FM"); demodModeSelector->addChoice(DEMOD_TYPE_FM, "FM");
@ -104,6 +104,7 @@ AppFrame::AppFrame() :
demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas); demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas);
demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0); demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0);
wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue()); wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue());
demodWaterfallCanvas->getVisualDataQueue()->set_max_num_items(3);
demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0); demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);
@ -148,6 +149,7 @@ AppFrame::AppFrame() :
demodMuteButton->setHighlightColor(RGBA4f(0.8,0.2,0.2)); demodMuteButton->setHighlightColor(RGBA4f(0.8,0.2,0.2));
demodMuteButton->setHelpTip("Demodulator Mute Toggle"); demodMuteButton->setHelpTip("Demodulator Mute Toggle");
demodMuteButton->setToggleMode(true); demodMuteButton->setToggleMode(true);
demodMuteButton->setSelection(-1);
demodGainTray->Add(demodMuteButton, 1, wxEXPAND | wxALL, 0); demodGainTray->Add(demodMuteButton, 1, wxEXPAND | wxALL, 0);
@ -422,6 +424,7 @@ AppFrame::AppFrame() :
waterfallSpeedMeter->setLevel(sqrt(wflps)); waterfallSpeedMeter->setLevel(sqrt(wflps));
waterfallDataThread->setLinesPerSecond(wflps); waterfallDataThread->setLinesPerSecond(wflps);
waterfallCanvas->setLinesPerSecond(wflps);
ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme()); ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme());
@ -534,6 +537,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
spectrumCanvas->setBandwidth(wxGetApp().getSampleRate()); spectrumCanvas->setBandwidth(wxGetApp().getSampleRate());
spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency());
waterfallDataThread->setLinesPerSecond(DEFAULT_WATERFALL_LPS); waterfallDataThread->setLinesPerSecond(DEFAULT_WATERFALL_LPS);
waterfallCanvas->setLinesPerSecond(DEFAULT_WATERFALL_LPS);
waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS)); waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS));
wxGetApp().getSpectrumProcessor()->setFFTAverageRate(0.65); wxGetApp().getSpectrumProcessor()->setFFTAverageRate(0.65);
spectrumAvgMeter->setLevel(0.65); spectrumAvgMeter->setLevel(0.65);
@ -893,6 +897,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
float val = waterfallSpeedMeter->getInputValue(); float val = waterfallSpeedMeter->getInputValue();
waterfallSpeedMeter->setLevel(val); waterfallSpeedMeter->setLevel(val);
waterfallDataThread->setLinesPerSecond((int)ceil(val*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))); 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->setBandwidth(waterfallCanvas->getBandwidth());
wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
waterfallCanvas->processInputQueue(); // waterfallCanvas->processInputQueue();
demodWaterfallCanvas->processInputQueue(); // waterfallCanvas->Refresh();
// demodWaterfallCanvas->processInputQueue();
// demodWaterfallCanvas->Refresh();
if (!this->IsActive()) { if (!this->IsActive()) {
std::this_thread::sleep_for(std::chrono::milliseconds(25)); std::this_thread::sleep_for(std::chrono::milliseconds(25));

View File

@ -89,7 +89,7 @@ bool CubicSDR::OnInit() {
pipeSpectrumIQVisualData->set_max_num_items(1); pipeSpectrumIQVisualData->set_max_num_items(1);
pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue(); pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue();
pipeWaterfallIQVisualData->set_max_num_items(DEFAULT_WATERFALL_LPS); pipeWaterfallIQVisualData->set_max_num_items(128);
spectrumDistributor.attachOutput(pipeDemodIQVisualData); spectrumDistributor.attachOutput(pipeDemodIQVisualData);
spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); spectrumDistributor.attachOutput(pipeSpectrumIQVisualData);
@ -113,7 +113,7 @@ bool CubicSDR::OnInit() {
sdrThread->setOutputQueue("IQDataOutput",pipeSDRIQData); sdrThread->setOutputQueue("IQDataOutput",pipeSDRIQData);
sdrPostThread = new SDRPostThread(); sdrPostThread = new SDRPostThread();
sdrPostThread->setNumVisSamples(BUF_SIZE); // sdrPostThread->setNumVisSamples(BUF_SIZE);
sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData); sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData);
sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData); sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData);
sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData); sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData);
@ -321,7 +321,7 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcessor() {
return demodVisualThread->getProcessor(); return demodVisualThread->getProcessor();
} }
VisualDataDistributor<DemodulatorThreadIQData> *CubicSDR::getSpectrumDistributor() { VisualDataReDistributor<DemodulatorThreadIQData> *CubicSDR::getSpectrumDistributor() {
return &spectrumDistributor; return &spectrumDistributor;
} }
@ -450,6 +450,10 @@ void CubicSDR::showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetM
fdialog.ShowModal(); fdialog.ShowModal();
} }
AppFrame *CubicSDR::getAppFrame() {
return appframe;
}
void CubicSDR::setFrequencySnap(int snap) { void CubicSDR::setFrequencySnap(int snap) {
if (snap > 1000000) { if (snap > 1000000) {
snap = 1000000; snap = 1000000;

View File

@ -60,7 +60,7 @@ public:
ScopeVisualProcessor *getScopeProcessor(); ScopeVisualProcessor *getScopeProcessor();
SpectrumVisualProcessor *getSpectrumProcessor(); SpectrumVisualProcessor *getSpectrumProcessor();
SpectrumVisualProcessor *getDemodSpectrumProcessor(); SpectrumVisualProcessor *getDemodSpectrumProcessor();
VisualDataDistributor<DemodulatorThreadIQData> *getSpectrumDistributor(); VisualDataReDistributor<DemodulatorThreadIQData> *getSpectrumDistributor();
DemodulatorThreadOutputQueue* getAudioVisualQueue(); DemodulatorThreadOutputQueue* getAudioVisualQueue();
DemodulatorThreadInputQueue* getIQVisualQueue(); DemodulatorThreadInputQueue* getIQVisualQueue();
@ -80,7 +80,8 @@ public:
int getPPM(); int getPPM();
void showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetMode = FrequencyDialog::FDIALOG_TARGET_DEFAULT); void showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetMode = FrequencyDialog::FDIALOG_TARGET_DEFAULT);
AppFrame *getAppFrame();
private: private:
AppFrame *appframe; AppFrame *appframe;
AppConfig config; AppConfig config;
@ -110,7 +111,7 @@ private:
ScopeVisualProcessor scopeProcessor; ScopeVisualProcessor scopeProcessor;
VisualDataDistributor<DemodulatorThreadIQData> spectrumDistributor; VisualDataReDistributor<DemodulatorThreadIQData> spectrumDistributor;
std::thread *t_SDR; std::thread *t_SDR;
std::thread *t_PostSDR; std::thread *t_PostSDR;

View File

@ -8,6 +8,7 @@
#include <iostream> #include <iostream>
#include "ThreadQueue.h" #include "ThreadQueue.h"
#include "Timer.h"
struct map_string_less : public std::binary_function<std::string,std::string,bool> struct map_string_less : public std::binary_function<std::string,std::string,bool>
{ {
@ -112,9 +113,9 @@ public:
void setOutputQueue(std::string qname, ThreadQueueBase *threadQueue); void setOutputQueue(std::string qname, ThreadQueueBase *threadQueue);
void *getOutputQueue(std::string qname); void *getOutputQueue(std::string qname);
protected: protected:
std::map<std::string, ThreadQueueBase *, map_string_less> input_queues; std::map<std::string, ThreadQueueBase *, map_string_less> input_queues;
std::map<std::string, ThreadQueueBase *, map_string_less> output_queues; std::map<std::string, ThreadQueueBase *, map_string_less> output_queues;
std::atomic_bool terminated; std::atomic_bool terminated;
Timer gTimer;
}; };

View File

@ -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() { ~DemodulatorThreadIQData() {
} }

View File

@ -7,7 +7,7 @@
DemodulatorMgr::DemodulatorMgr() : DemodulatorMgr::DemodulatorMgr() :
activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL), lastBandwidth(DEFAULT_DEMOD_BW), lastDemodType( 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) {
} }

View File

@ -696,8 +696,8 @@ void DemodulatorThread::run() {
} }
ati->data.resize(numAudioWritten * 2); ati->data.resize(numAudioWritten * 2);
for (int i = 0; i < numAudioWritten; i++) { for (int i = 0; i < numAudioWritten; i++) {
ati->data[i * 2] = (*inputData)[i].real; ati->data[i * 2] = (*inputData)[i].imag;
ati->data[i * 2 + 1] = (*inputData)[i].imag; ati->data[i * 2 + 1] = (*inputData)[i].real;
} }
} else if (stereo && inp->sampleRate >= 100000) { } else if (stereo && inp->sampleRate >= 100000) {
ati->channels = 2; ati->channels = 2;

View File

@ -4,8 +4,16 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include "ColorTheme.h" #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); setFill(GLPANEL_FILL_GRAD_Y);
setFillColor(ThemeMgr::mgr.currentTheme->fftBackground * 2.0, ThemeMgr::mgr.currentTheme->fftBackground); 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; float dbPanelHeight = (1.0/viewHeight)*14.0;
std::stringstream ssLabel; std::stringstream ssLabel("");
ssLabel << std::fixed << std::setprecision(1) << (20.0 * log10(2.0*(getCeilValue())/(double)fftSize)) << "dB"; 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.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT);
dbPanelCeil.setSize(dbPanelWidth, dbPanelHeight); dbPanelCeil.setSize(dbPanelWidth, dbPanelHeight);
dbPanelCeil.setPosition(-1.0 + dbPanelWidth, 1.0 - dbPanelHeight); dbPanelCeil.setPosition(-1.0 + dbPanelWidth, 1.0 - dbPanelHeight);
ssLabel.str(""); 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.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT);
dbPanelFloor.setSize(dbPanelWidth, dbPanelHeight); dbPanelFloor.setSize(dbPanelWidth, dbPanelHeight);

View File

@ -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);
}
}
}
}

View File

@ -0,0 +1,22 @@
#pragma once
#include "VisualProcessor.h"
#include "DemodDefs.h"
#include <cmath>
class FFTDataDistributor : public VisualProcessor<DemodulatorThreadIQData, DemodulatorThreadIQData> {
public:
FFTDataDistributor();
void setFFTSize(int fftSize);
void setLinesPerSecond(int lines);
int getLinesPerSecond();
protected:
void process();
DemodulatorThreadIQData inputBuffer, tempBuffer;
ReBuffer<DemodulatorThreadIQData> outputBuffers;
int fftSize;
int linesPerSecond;
double lineRateAccum;
};

View File

@ -1,7 +1,8 @@
#include "FFTVisualDataThread.h" #include "FFTVisualDataThread.h"
#include "CubicSDR.h" #include "CubicSDR.h"
FFTVisualDataThread::FFTVisualDataThread() : linesPerSecond(DEFAULT_WATERFALL_LPS) { FFTVisualDataThread::FFTVisualDataThread() {
linesPerSecond.store(DEFAULT_WATERFALL_LPS);
lpsChanged.store(true); lpsChanged.store(true);
} }
@ -36,7 +37,8 @@ void FFTVisualDataThread::run() {
while(!terminated) { 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(); int fftSize = wproc.getDesiredInputSize();
@ -48,7 +50,7 @@ void FFTVisualDataThread::run() {
if (lpsChanged.load()) { if (lpsChanged.load()) {
fftDistrib.setLinesPerSecond(linesPerSecond.load()); fftDistrib.setLinesPerSecond(linesPerSecond.load());
pipeIQDataIn->set_max_num_items(linesPerSecond.load()); // pipeIQDataIn->set_max_num_items(linesPerSecond.load());
lpsChanged.store(false); lpsChanged.store(false);
} }

View File

@ -2,6 +2,7 @@
#include "IOThread.h" #include "IOThread.h"
#include "SpectrumVisualProcessor.h" #include "SpectrumVisualProcessor.h"
#include "FFTDataDistributor.h"
class FFTVisualDataThread : public IOThread { class FFTVisualDataThread : public IOThread {
public: public:

View File

@ -16,7 +16,8 @@ void SpectrumVisualDataThread::run() {
std::cout << "Spectrum visual data thread started." << std::endl; std::cout << "Spectrum visual data thread started." << std::endl;
while(!terminated) { 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(); sproc.run();
} }

View File

@ -69,75 +69,3 @@ private:
std::atomic_int desiredInputSize; std::atomic_int desiredInputSize;
std::mutex busy_run; std::mutex busy_run;
}; };
class FFTDataDistributor : public VisualProcessor<DemodulatorThreadIQData, DemodulatorThreadIQData> {
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<DemodulatorThreadIQData> outputBuffers;
int fftSize;
int linesPerSecond;
double lineRateAccum;
};

View File

@ -107,3 +107,25 @@ protected:
} }
}; };
template<class OutputDataType = ReferenceCounter>
class VisualDataReDistributor : public VisualProcessor<OutputDataType, OutputDataType> {
protected:
void process() {
while (!VisualProcessor<OutputDataType, OutputDataType>::input->empty()) {
if (!VisualProcessor<OutputDataType, OutputDataType>::isAnyOutputEmpty()) {
return;
}
OutputDataType *inp;
VisualProcessor<OutputDataType, OutputDataType>::input->pop(inp);
if (inp) {
OutputDataType *outp = buffers.getBuffer();
(*outp) = (*inp);
inp->decRefCount();
VisualProcessor<OutputDataType, OutputDataType>::distribute(outp);
}
}
}
ReBuffer<OutputDataType> buffers;
};

View File

@ -6,7 +6,7 @@
#include <deque> #include <deque>
SDRPostThread::SDRPostThread() : IOThread(), 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); swapIQ.store(false);
@ -50,14 +50,6 @@ void SDRPostThread::removeDemodulator(DemodulatorInstance *demod) {
busy_demod.unlock(); 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) { void SDRPostThread::setSwapIQ(bool swapIQ) {
this->swapIQ.store(swapIQ); this->swapIQ.store(swapIQ);
} }
@ -93,7 +85,6 @@ void SDRPostThread::run() {
iqDataInQueue->pop(data_in); iqDataInQueue->pop(data_in);
// std::lock_guard < std::mutex > lock(data_in->m_mutex); // std::lock_guard < std::mutex > lock(data_in->m_mutex);
int num_vis_samples = this->num_vis_samples;
if (data_in && data_in->data.size()) { if (data_in && data_in->data.size()) {
int dataSize = data_in->data.size()/2; int dataSize = data_in->data.size()/2;
@ -118,21 +109,19 @@ void SDRPostThread::run() {
iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]); iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]);
if (iqVisualQueue != NULL && iqVisualQueue->empty()) { if (iqVisualQueue != NULL && !iqVisualQueue->full()) {
DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer(); DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer();
visualDataOut->setRefCount(1); visualDataOut->setRefCount(1);
if (num_vis_samples > dataOut.size()) { int num_vis_samples = dataOut.size();
num_vis_samples = dataOut.size();
}
if (visualDataOut->data.size() < num_vis_samples) { // if (visualDataOut->data.size() < num_vis_samples) {
if (visualDataOut->data.capacity() < num_vis_samples) { // if (visualDataOut->data.capacity() < num_vis_samples) {
visualDataOut->data.reserve(num_vis_samples); // visualDataOut->data.reserve(num_vis_samples);
} // }
visualDataOut->data.resize(num_vis_samples); // visualDataOut->data.resize(num_vis_samples);
} // }
//
visualDataOut->frequency = data_in->frequency; visualDataOut->frequency = data_in->frequency;
visualDataOut->sampleRate = data_in->sampleRate; visualDataOut->sampleRate = data_in->sampleRate;
visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples); visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples);

View File

@ -11,9 +11,6 @@ public:
void bindDemodulator(DemodulatorInstance *demod); void bindDemodulator(DemodulatorInstance *demod);
void removeDemodulator(DemodulatorInstance *demod); void removeDemodulator(DemodulatorInstance *demod);
void setNumVisSamples(int num_vis_samples_in);
int getNumVisSamples();
void setSwapIQ(bool swapIQ); void setSwapIQ(bool swapIQ);
bool getSwapIQ(); bool getSwapIQ();
@ -28,7 +25,6 @@ protected:
std::mutex busy_demod; std::mutex busy_demod;
std::vector<DemodulatorInstance *> demodulators; std::vector<DemodulatorInstance *> demodulators;
iirfilt_crcf dcFilter; iirfilt_crcf dcFilter;
int num_vis_samples;
std::atomic_bool swapIQ; std::atomic_bool swapIQ;
ReBuffer<DemodulatorThreadIQData> visualDataBuffers; ReBuffer<DemodulatorThreadIQData> visualDataBuffers;

View File

@ -1,11 +1,14 @@
#include "Timer.h" #include "Timer.h"
#ifdef WIN32 #ifdef _WIN32
#include <windows.h>
#include <mmsystem.h> #include <mmsystem.h>
#endif #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 <iostream>
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 else
{ {
#ifdef WIN32 #ifdef _WIN32
system_milliseconds = timeGetTime (); system_milliseconds = timeGetTime ();
#else #else
gettimeofday(&time_val,&time_zone); gettimeofday(&time_val,&time_zone);
@ -157,3 +162,14 @@ bool Timer::paused()
{ {
return paused_state; 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();
}
}

View File

@ -24,7 +24,7 @@ private:
unsigned long paused_time; unsigned long paused_time;
unsigned long offset; unsigned long offset;
#ifndef WIN32 #ifndef _WIN32
struct timeval time_val; struct timeval time_val;
struct timezone time_zone; struct timezone time_zone;
#endif #endif
@ -155,6 +155,9 @@ public:
* \return Current pause state, true if paused, false otherwise * \return Current pause state, true if paused, false otherwise
*/ */
bool paused(); bool paused();
void timerTestFunc();
}; };
#endif #endif

View File

@ -36,6 +36,7 @@ MeterCanvas::~MeterCanvas() {
void MeterCanvas::setLevel(float level_in) { void MeterCanvas::setLevel(float level_in) {
level = level_in; level = level_in;
Refresh();
} }
float MeterCanvas::getLevel() { float MeterCanvas::getLevel() {
return level; return level;
@ -43,10 +44,12 @@ float MeterCanvas::getLevel() {
void MeterCanvas::setMax(float max_in) { void MeterCanvas::setMax(float max_in) {
level_max = max_in; level_max = max_in;
Refresh();
} }
void MeterCanvas::setInputValue(float slider_in) { void MeterCanvas::setInputValue(float slider_in) {
userInputValue = inputValue = slider_in; userInputValue = inputValue = slider_in;
Refresh();
} }
bool MeterCanvas::inputChanged() { bool MeterCanvas::inputChanged() {
@ -87,8 +90,11 @@ void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
} }
void MeterCanvas::OnIdle(wxIdleEvent &event) { void MeterCanvas::OnIdle(wxIdleEvent &event) {
Refresh(); if (mouseTracker.mouseInView()) {
event.RequestMore(); Refresh();
} else {
event.Skip();
}
} }
void MeterCanvas::OnMouseMoved(wxMouseEvent& event) { void MeterCanvas::OnMouseMoved(wxMouseEvent& event) {
@ -107,15 +113,18 @@ void MeterCanvas::OnMouseDown(wxMouseEvent& event) {
InteractiveCanvas::OnMouseDown(event); InteractiveCanvas::OnMouseDown(event);
userInputValue = mouseTracker.getMouseY() * level_max; userInputValue = mouseTracker.getMouseY() * level_max;
mouseTracker.setHorizDragLock(true); mouseTracker.setHorizDragLock(true);
Refresh();
} }
void MeterCanvas::OnMouseWheelMoved(wxMouseEvent& event) { void MeterCanvas::OnMouseWheelMoved(wxMouseEvent& event) {
InteractiveCanvas::OnMouseWheelMoved(event); InteractiveCanvas::OnMouseWheelMoved(event);
Refresh();
} }
void MeterCanvas::OnMouseReleased(wxMouseEvent& event) { void MeterCanvas::OnMouseReleased(wxMouseEvent& event) {
InteractiveCanvas::OnMouseReleased(event); InteractiveCanvas::OnMouseReleased(event);
userInputValue = mouseTracker.getMouseY() * level_max; userInputValue = mouseTracker.getMouseY() * level_max;
Refresh();
} }
void MeterCanvas::OnMouseLeftWindow(wxMouseEvent& event) { void MeterCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
@ -127,6 +136,7 @@ void MeterCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
void MeterCanvas::OnMouseEnterWindow(wxMouseEvent& event) { void MeterCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
InteractiveCanvas::mouseTracker.OnMouseEnterWindow(event); InteractiveCanvas::mouseTracker.OnMouseEnterWindow(event);
SetCursor(wxCURSOR_CROSS); SetCursor(wxCURSOR_CROSS);
Refresh();
} }
void MeterCanvas::setHelpTip(std::string tip) { void MeterCanvas::setHelpTip(std::string tip) {

View File

@ -79,8 +79,11 @@ void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
} }
void ModeSelectorCanvas::OnIdle(wxIdleEvent &event) { void ModeSelectorCanvas::OnIdle(wxIdleEvent &event) {
Refresh(); if (mouseTracker.mouseInView()) {
event.RequestMore(); Refresh();
} else {
event.Skip();
}
} }
void ModeSelectorCanvas::OnMouseMoved(wxMouseEvent& event) { void ModeSelectorCanvas::OnMouseMoved(wxMouseEvent& event) {
@ -120,6 +123,7 @@ void ModeSelectorCanvas::OnMouseReleased(wxMouseEvent& event) {
currentSelection = selectedButton; currentSelection = selectedButton;
SetCursor (wxCURSOR_HAND); SetCursor (wxCURSOR_HAND);
Refresh();
} }
void ModeSelectorCanvas::OnMouseLeftWindow(wxMouseEvent& event) { void ModeSelectorCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
@ -134,6 +138,7 @@ void ModeSelectorCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
if (!helpTip.empty()) { if (!helpTip.empty()) {
setStatusText(helpTip); setStatusText(helpTip);
} }
Refresh();
} }
void ModeSelectorCanvas::setHelpTip(std::string tip) { void ModeSelectorCanvas::setHelpTip(std::string tip) {
@ -142,6 +147,7 @@ void ModeSelectorCanvas::setHelpTip(std::string tip) {
void ModeSelectorCanvas::setNumChoices(int numChoices_in) { void ModeSelectorCanvas::setNumChoices(int numChoices_in) {
numChoices = numChoices_in; numChoices = numChoices_in;
Refresh();
} }
void ModeSelectorCanvas::addChoice(int value, std::string label) { void ModeSelectorCanvas::addChoice(int value, std::string label) {
@ -157,6 +163,7 @@ void ModeSelectorCanvas::setSelection(int value) {
} }
} }
currentSelection = -1; currentSelection = -1;
Refresh();
} }
int ModeSelectorCanvas::getSelection() { int ModeSelectorCanvas::getSelection() {

View File

@ -39,7 +39,9 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
dragOfs(0), mouseZoom(1), zoom(1), freqMove(0.0), freqMoving(false), hoverAlpha(1.0) { dragOfs(0), mouseZoom(1), zoom(1), freqMove(0.0), freqMoving(false), hoverAlpha(1.0) {
glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this)); glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this));
linesPerSecond = 30;
lpsIndex = 0;
preBuf = false;
SetCursor(wxCURSOR_CROSS); SetCursor(wxCURSOR_CROSS);
} }
@ -54,6 +56,7 @@ void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) {
waterfall_lines = waterfall_lines_in; waterfall_lines = waterfall_lines_in;
waterfallPanel.setup(fft_size, waterfall_lines); waterfallPanel.setup(fft_size, waterfall_lines);
gTimer.start();
} }
WaterfallCanvas::DragState WaterfallCanvas::getDragState() { WaterfallCanvas::DragState WaterfallCanvas::getDragState() {
@ -74,23 +77,38 @@ void WaterfallCanvas::processInputQueue() {
} }
glContext->SetCurrent(*this); glContext->SetCurrent(*this);
while (!visualDataQueue.empty()) { gTimer.update();
SpectrumVisualData *vData;
double targetVis = 1.0 / (double)linesPerSecond;
visualDataQueue.pop(vData); lpsIndex += gTimer.lastUpdateSeconds();
if (vData) { if (linesPerSecond) {
waterfallPanel.setPoints(vData->spectrum_points); if (lpsIndex >= targetVis) {
waterfallPanel.step(); tex_update.lock();
vData->decRefCount(); 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)) { void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
// wxClientDC dc(this);
wxPaintDC dc(this); wxPaintDC dc(this);
processInputQueue();
const wxSize ClientSize = GetClientSize(); const wxSize ClientSize = GetClientSize();
long double currentZoom = zoom; long double currentZoom = zoom;
@ -193,7 +211,9 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glContext->BeginDraw(0,0,0); glContext->BeginDraw(0,0,0);
waterfallPanel.calcTransform(CubicVR::mat4::identity()); waterfallPanel.calcTransform(CubicVR::mat4::identity());
tex_update.lock();
waterfallPanel.draw(); waterfallPanel.draw();
tex_update.unlock();
std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators(); std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
@ -391,7 +411,9 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
void WaterfallCanvas::OnIdle(wxIdleEvent &event) { void WaterfallCanvas::OnIdle(wxIdleEvent &event) {
Refresh(); Refresh();
event.RequestMore(); event.RequestMore();
// event.Skip(); if (visualDataQueue.size() > linesPerSecond) {
processInputQueue();
}
} }
void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { 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();
}
}
}

View File

@ -10,7 +10,7 @@
#include "MouseTracker.h" #include "MouseTracker.h"
#include "SpectrumCanvas.h" #include "SpectrumCanvas.h"
#include "WaterfallPanel.h" #include "WaterfallPanel.h"
#include "Timer.h"
class WaterfallCanvas: public InteractiveCanvas { class WaterfallCanvas: public InteractiveCanvas {
public: public:
@ -29,6 +29,8 @@ public:
void processInputQueue(); void processInputQueue();
SpectrumVisualDataQueue *getVisualDataQueue(); SpectrumVisualDataQueue *getVisualDataQueue();
void setLinesPerSecond(int lps);
private: private:
void OnPaint(wxPaintEvent& event); void OnPaint(wxPaintEvent& event);
void OnKeyDown(wxKeyEvent& event); void OnKeyDown(wxKeyEvent& event);
@ -64,9 +66,13 @@ private:
bool freqMoving; bool freqMoving;
long double freqMove; long double freqMove;
float hoverAlpha; float hoverAlpha;
int linesPerSecond;
SpectrumVisualDataQueue visualDataQueue; SpectrumVisualDataQueue visualDataQueue;
Timer gTimer;
double lpsIndex;
bool preBuf;
std::mutex tex_update;
// event table // event table
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };