update digital lab

This commit is contained in:
Charles J. Cliffe 2015-08-16 20:33:51 -04:00
commit 867174edf3
21 changed files with 377 additions and 188 deletions

View File

@ -263,6 +263,8 @@ SET (cubicsdr_sources
src/process/VisualProcessor.cpp src/process/VisualProcessor.cpp
src/process/ScopeVisualProcessor.cpp src/process/ScopeVisualProcessor.cpp
src/process/SpectrumVisualProcessor.cpp src/process/SpectrumVisualProcessor.cpp
src/process/FFTVisualDataThread.cpp
src/process/SpectrumVisualDataThread.cpp
src/ui/GLPanel.cpp src/ui/GLPanel.cpp
external/rtaudio/RtAudio.cpp external/rtaudio/RtAudio.cpp
external/lodepng/lodepng.cpp external/lodepng/lodepng.cpp
@ -316,6 +318,8 @@ SET (cubicsdr_headers
src/process/VisualProcessor.h src/process/VisualProcessor.h
src/process/ScopeVisualProcessor.h src/process/ScopeVisualProcessor.h
src/process/SpectrumVisualProcessor.h src/process/SpectrumVisualProcessor.h
src/process/FFTVisualDataThread.h
src/process/SpectrumVisualDataThread.h
src/ui/GLPanel.h src/ui/GLPanel.h
src/ui/UITestCanvas.cpp src/ui/UITestCanvas.cpp
src/ui/UITestCanvas.h src/ui/UITestCanvas.h

View File

@ -85,6 +85,7 @@ Features and Status:
- [ ] Undo / Redo action - [ ] Undo / Redo action
- I/Q Recording and playback - I/Q Recording and playback
- [ ] Recording - [ ] Recording
- [ ] Record waterfall output to PNG file chunks of desired height
- [ ] Record I/Q input data - [ ] Record I/Q input data
- [ ] Simultaneously record demod decimated I/Q and audio - [ ] Simultaneously record demod decimated I/Q and audio
- [ ] Playback - [ ] Playback

View File

@ -89,11 +89,11 @@ AppFrame::AppFrame() :
demodModeSelectorCons->setHelpTip("Choose number of constallations types."); demodModeSelectorCons->setHelpTip("Choose number of constallations types.");
demodTray->Add(demodModeSelectorCons, 2, wxEXPAND | wxALL, 0); demodTray->Add(demodModeSelectorCons, 2, wxEXPAND | wxALL, 0);
wxGetApp().getDemodSpectrumProcesor()->setup(1024); wxGetApp().getDemodSpectrumProcessor()->setup(1024);
demodSpectrumCanvas = new SpectrumCanvas(this, attribList); demodSpectrumCanvas = new SpectrumCanvas(this, attribList);
demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000); demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000);
demodVisuals->Add(demodSpectrumCanvas, 3, wxEXPAND | wxALL, 0); demodVisuals->Add(demodSpectrumCanvas, 3, wxEXPAND | wxALL, 0);
wxGetApp().getDemodSpectrumProcesor()->attachOutput(demodSpectrumCanvas->getVisualDataQueue()); wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodSpectrumCanvas->getVisualDataQueue());
demodVisuals->AddSpacer(1); demodVisuals->AddSpacer(1);
@ -103,7 +103,7 @@ AppFrame::AppFrame() :
demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas); demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas);
demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas); demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas);
demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0); demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0);
wxGetApp().getDemodSpectrumProcesor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue()); wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue());
demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0); demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);
@ -140,9 +140,9 @@ AppFrame::AppFrame() :
vbox->AddSpacer(1); vbox->AddSpacer(1);
wxBoxSizer *spectrumSizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *spectrumSizer = new wxBoxSizer(wxHORIZONTAL);
wxGetApp().getSpectrumProcesor()->setup(2048); wxGetApp().getSpectrumProcessor()->setup(2048);
spectrumCanvas = new SpectrumCanvas(this, attribList); spectrumCanvas = new SpectrumCanvas(this, attribList);
wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue()); wxGetApp().getSpectrumProcessor()->attachOutput(spectrumCanvas->getVisualDataQueue());
spectrumAvgMeter = new MeterCanvas(this, attribList); spectrumAvgMeter = new MeterCanvas(this, attribList);
spectrumAvgMeter->setHelpTip("Spectrum averaging speed, click or drag to adjust."); spectrumAvgMeter->setHelpTip("Spectrum averaging speed, click or drag to adjust.");
@ -160,15 +160,14 @@ AppFrame::AppFrame() :
wxBoxSizer *wfSizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *wfSizer = new wxBoxSizer(wxHORIZONTAL);
wxGetApp().getWaterfallProcesor()->setup(2048);
waterfallCanvas = new WaterfallCanvas(this, attribList); waterfallCanvas = new WaterfallCanvas(this, attribList);
waterfallCanvas->setup(2048, 512); waterfallCanvas->setup(2048, 512);
fftDistrib.setInput(wxGetApp().getWaterfallVisualQueue()); waterfallDataThread = new FFTVisualDataThread();
fftDistrib.attachOutput(&fftQueue); t_FFTData = new std::thread(&FFTVisualDataThread::threadMain, waterfallDataThread);
wxGetApp().getWaterfallProcesor()->setInput(&fftQueue); waterfallDataThread->setInputQueue("IQDataInput", wxGetApp().getWaterfallVisualQueue());
wxGetApp().getWaterfallProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); waterfallDataThread->setOutputQueue("FFTDataOutput", waterfallCanvas->getVisualDataQueue());
waterfallSpeedMeter = new MeterCanvas(this, attribList); waterfallSpeedMeter = new MeterCanvas(this, attribList);
waterfallSpeedMeter->setHelpTip("Waterfall speed, click or drag to adjust (max 1024 lines per second)"); waterfallSpeedMeter->setHelpTip("Waterfall speed, click or drag to adjust (max 1024 lines per second)");
@ -398,12 +397,12 @@ AppFrame::AppFrame() :
float spectrumAvg = wxGetApp().getConfig()->getSpectrumAvgSpeed(); float spectrumAvg = wxGetApp().getConfig()->getSpectrumAvgSpeed();
spectrumAvgMeter->setLevel(spectrumAvg); spectrumAvgMeter->setLevel(spectrumAvg);
wxGetApp().getSpectrumProcesor()->setFFTAverageRate(spectrumAvg); wxGetApp().getSpectrumProcessor()->setFFTAverageRate(spectrumAvg);
int wflps =wxGetApp().getConfig()->getWaterfallLinesPerSec(); int wflps =wxGetApp().getConfig()->getWaterfallLinesPerSec();
waterfallSpeedMeter->setLevel(sqrt(wflps)); waterfallSpeedMeter->setLevel(sqrt(wflps));
fftDistrib.setLinesPerSecond(wflps); waterfallDataThread->setLinesPerSecond(wflps);
ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme()); ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme());
@ -427,6 +426,8 @@ AppFrame::AppFrame() :
} }
AppFrame::~AppFrame() { AppFrame::~AppFrame() {
waterfallDataThread->terminate();
t_FFTData->join();
} }
@ -512,9 +513,9 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
waterfallCanvas->setCenterFrequency(wxGetApp().getFrequency()); waterfallCanvas->setCenterFrequency(wxGetApp().getFrequency());
spectrumCanvas->setBandwidth(wxGetApp().getSampleRate()); spectrumCanvas->setBandwidth(wxGetApp().getSampleRate());
spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency());
fftDistrib.setLinesPerSecond(DEFAULT_WATERFALL_LPS); waterfallDataThread->setLinesPerSecond(DEFAULT_WATERFALL_LPS);
waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS)); waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS));
wxGetApp().getSpectrumProcesor()->setFFTAverageRate(0.65); wxGetApp().getSpectrumProcessor()->setFFTAverageRate(0.65);
spectrumAvgMeter->setLevel(0.65); spectrumAvgMeter->setLevel(0.65);
demodModeSelector->Refresh(); demodModeSelector->Refresh();
demodTuner->Refresh(); demodTuner->Refresh();
@ -633,13 +634,17 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
} }
void AppFrame::OnClose(wxCloseEvent& event) { void AppFrame::OnClose(wxCloseEvent& event) {
wxGetApp().getDemodSpectrumProcessor()->removeOutput(demodSpectrumCanvas->getVisualDataQueue());
wxGetApp().getDemodSpectrumProcessor()->removeOutput(demodWaterfallCanvas->getVisualDataQueue());
wxGetApp().getSpectrumProcessor()->removeOutput(spectrumCanvas->getVisualDataQueue());
wxGetApp().getConfig()->setWindow(this->GetPosition(), this->GetClientSize()); wxGetApp().getConfig()->setWindow(this->GetPosition(), this->GetClientSize());
wxGetApp().getConfig()->setWindowMaximized(this->IsMaximized()); wxGetApp().getConfig()->setWindowMaximized(this->IsMaximized());
wxGetApp().getConfig()->setTheme(ThemeMgr::mgr.getTheme()); wxGetApp().getConfig()->setTheme(ThemeMgr::mgr.getTheme());
wxGetApp().getConfig()->setSnap(wxGetApp().getFrequencySnap()); wxGetApp().getConfig()->setSnap(wxGetApp().getFrequencySnap());
wxGetApp().getConfig()->setCenterFreq(wxGetApp().getFrequency()); wxGetApp().getConfig()->setCenterFreq(wxGetApp().getFrequency());
wxGetApp().getConfig()->setSpectrumAvgSpeed(wxGetApp().getSpectrumProcesor()->getFFTAverageRate()); wxGetApp().getConfig()->setSpectrumAvgSpeed(wxGetApp().getSpectrumProcessor()->getFFTAverageRate());
wxGetApp().getConfig()->setWaterfallLinesPerSec(fftDistrib.getLinesPerSecond()); wxGetApp().getConfig()->setWaterfallLinesPerSec(waterfallDataThread->getLinesPerSecond());
wxGetApp().getConfig()->save(); wxGetApp().getConfig()->save();
event.Skip(); event.Skip();
} }
@ -802,75 +807,47 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
wxGetApp().getScopeProcessor()->run(); wxGetApp().getScopeProcessor()->run();
wxGetApp().getSpectrumDistributor()->run(); wxGetApp().getSpectrumDistributor()->run();
SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor(); SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcessor();
if (spectrumAvgMeter->inputChanged()) { if (spectrumAvgMeter->inputChanged()) {
float val = spectrumAvgMeter->getInputValue(); float val = spectrumAvgMeter->getInputValue();
if (val < 0.01) {
val = 0.01;
}
spectrumAvgMeter->setLevel(val); spectrumAvgMeter->setLevel(val);
proc->setFFTAverageRate(val); proc->setFFTAverageRate(val);
GetStatusBar()->SetStatusText(wxString::Format(wxT("Spectrum averaging speed changed to %0.2f%%."),val*100.0)); GetStatusBar()->SetStatusText(wxString::Format(wxT("Spectrum averaging speed changed to %0.2f%%."),val*100.0));
} }
proc->setView(spectrumCanvas->getViewState()); proc->setView(waterfallCanvas->getViewState());
proc->setBandwidth(spectrumCanvas->getBandwidth()); proc->setBandwidth(waterfallCanvas->getBandwidth());
proc->setCenterFrequency(spectrumCanvas->getCenterFrequency()); proc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
proc->run(); SpectrumVisualProcessor *dproc = wxGetApp().getDemodSpectrumProcessor();
SpectrumVisualProcessor *dproc = wxGetApp().getDemodSpectrumProcesor();
dproc->setView(demodWaterfallCanvas->getViewState()); dproc->setView(demodWaterfallCanvas->getViewState());
dproc->setBandwidth(demodWaterfallCanvas->getBandwidth()); dproc->setBandwidth(demodWaterfallCanvas->getBandwidth());
dproc->setCenterFrequency(demodWaterfallCanvas->getCenterFrequency()); dproc->setCenterFrequency(demodWaterfallCanvas->getCenterFrequency());
dproc->run();
SpectrumVisualProcessor *wproc = wxGetApp().getWaterfallProcesor(); SpectrumVisualProcessor *wproc = waterfallDataThread->getProcessor();
int fftSize = wproc->getDesiredInputSize();
if (fftSize) {
fftDistrib.setFFTSize(fftSize);
} else {
fftDistrib.setFFTSize(DEFAULT_FFT_SIZE);
}
if (waterfallSpeedMeter->inputChanged()) { if (waterfallSpeedMeter->inputChanged()) {
float val = waterfallSpeedMeter->getInputValue(); float val = waterfallSpeedMeter->getInputValue();
waterfallSpeedMeter->setLevel(val); waterfallSpeedMeter->setLevel(val);
fftDistrib.setLinesPerSecond((int)ceil(val*val)); waterfallDataThread->setLinesPerSecond((int)ceil(val*val));
wxGetApp().getWaterfallVisualQueue()->set_max_num_items((int)ceil(val*val));
GetStatusBar()->SetStatusText(wxString::Format(wxT("Waterfall max speed changed to %d lines per second."),(int)ceil(val*val))); GetStatusBar()->SetStatusText(wxString::Format(wxT("Waterfall max speed changed to %d lines per second."),(int)ceil(val*val)));
} }
fftDistrib.run();
wproc->setView(waterfallCanvas->getViewState()); wproc->setView(waterfallCanvas->getViewState());
wproc->setBandwidth(waterfallCanvas->getBandwidth()); wproc->setBandwidth(waterfallCanvas->getBandwidth());
wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
while (!wproc->isInputEmpty()) {
wproc->run();
}
waterfallCanvas->processInputQueue(); waterfallCanvas->processInputQueue();
demodWaterfallCanvas->processInputQueue(); demodWaterfallCanvas->processInputQueue();
if (!this->IsActive()) {
if (this->IsVisible()) { std::this_thread::sleep_for(std::chrono::milliseconds(25));
waterfallCanvas->DoPaint();
demodWaterfallCanvas->DoPaint();
#ifdef __APPLE__
usleep(5000);
#endif
} else {
#ifndef _WIN32
usleep(15000);
#else
Sleep(15);
#endif
} }
event.RequestMore(); event.RequestMore();

View File

@ -9,7 +9,8 @@
#include "MeterCanvas.h" #include "MeterCanvas.h"
#include "TuningCanvas.h" #include "TuningCanvas.h"
#include "ModeSelectorCanvas.h" #include "ModeSelectorCanvas.h"
#include "UITestCanvas.h" #include "FFTVisualDataThread.h"
//#include "UITestCanvas.h"
#include <map> #include <map>
@ -97,8 +98,9 @@ private:
std::string currentSessionFile; std::string currentSessionFile;
FFTDataDistributor fftDistrib; FFTVisualDataThread *waterfallDataThread;
DemodulatorThreadInputQueue fftQueue;
std::thread *t_FFTData;
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };

View File

@ -12,7 +12,6 @@
#endif #endif
#include "CubicSDR.h" #include "CubicSDR.h"
#include "FrequencyDialog.h"
#ifdef _OSX_APP_ #ifdef _OSX_APP_
#include "CoreFoundation/CoreFoundation.h" #include "CoreFoundation/CoreFoundation.h"
@ -35,7 +34,7 @@ class outbuf : public std::streambuf {
CubicSDR::CubicSDR() : appframe(NULL), m_glContext(NULL), frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE), directSamplingMode(0), CubicSDR::CubicSDR() : appframe(NULL), m_glContext(NULL), frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE), directSamplingMode(0),
sdrThread(NULL), sdrPostThread(NULL), pipeSDRCommand(NULL), pipeSDRIQData(NULL), pipeIQVisualData(NULL), pipeAudioVisualData(NULL), t_SDR(NULL), t_PostSDR(NULL) { sdrThread(NULL), sdrPostThread(NULL), spectrumVisualThread(NULL), demodVisualThread(NULL), pipeSDRCommand(NULL), pipeSDRIQData(NULL), pipeIQVisualData(NULL), pipeAudioVisualData(NULL), t_SDR(NULL), t_PostSDR(NULL) {
} }
@ -75,6 +74,9 @@ bool CubicSDR::OnInit() {
directSamplingMode = 0; directSamplingMode = 0;
// Visual Data // Visual Data
spectrumVisualThread = new SpectrumVisualDataThread();
demodVisualThread = new SpectrumVisualDataThread();
pipeIQVisualData = new DemodulatorThreadInputQueue(); pipeIQVisualData = new DemodulatorThreadInputQueue();
pipeIQVisualData->set_max_num_items(1); pipeIQVisualData->set_max_num_items(1);
@ -92,8 +94,8 @@ bool CubicSDR::OnInit() {
spectrumDistributor.attachOutput(pipeDemodIQVisualData); spectrumDistributor.attachOutput(pipeDemodIQVisualData);
spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); spectrumDistributor.attachOutput(pipeSpectrumIQVisualData);
demodSpectrumProcessor.setInput(pipeDemodIQVisualData); getDemodSpectrumProcessor()->setInput(pipeDemodIQVisualData);
spectrumProcessor.setInput(pipeSpectrumIQVisualData); getSpectrumProcessor()->setInput(pipeSpectrumIQVisualData);
pipeAudioVisualData = new DemodulatorThreadOutputQueue(); pipeAudioVisualData = new DemodulatorThreadOutputQueue();
pipeAudioVisualData->set_max_num_items(1); pipeAudioVisualData->set_max_num_items(1);
@ -104,7 +106,7 @@ bool CubicSDR::OnInit() {
pipeSDRIQData = new SDRThreadIQDataQueue(); pipeSDRIQData = new SDRThreadIQDataQueue();
pipeSDRCommand = new SDRThreadCommandQueue(); pipeSDRCommand = new SDRThreadCommandQueue();
pipeSDRIQData->set_max_num_items(1); pipeSDRIQData->set_max_num_items(100);
sdrThread = new SDRThread(); sdrThread = new SDRThread();
sdrThread->setInputQueue("SDRCommandQueue",pipeSDRCommand); sdrThread->setInputQueue("SDRCommandQueue",pipeSDRCommand);
@ -158,6 +160,8 @@ bool CubicSDR::OnInit() {
t_PostSDR = new std::thread(&SDRPostThread::threadMain, sdrPostThread); t_PostSDR = new std::thread(&SDRPostThread::threadMain, sdrPostThread);
t_SDR = new std::thread(&SDRThread::threadMain, sdrThread); t_SDR = new std::thread(&SDRThread::threadMain, sdrThread);
t_SpectrumVisual = new std::thread(&SpectrumVisualDataThread::threadMain, spectrumVisualThread);
t_DemodVisual = new std::thread(&SpectrumVisualDataThread::threadMain, demodVisualThread);
appframe = new AppFrame(); appframe = new AppFrame();
if (dev != NULL) { if (dev != NULL) {
@ -191,6 +195,13 @@ int CubicSDR::OnExit() {
std::cout << "Terminating SDR post-processing thread.." << std::endl; std::cout << "Terminating SDR post-processing thread.." << std::endl;
sdrPostThread->terminate(); sdrPostThread->terminate();
t_PostSDR->join(); t_PostSDR->join();
std::cout << "Terminating Visual Processor threads.." << std::endl;
spectrumVisualThread->terminate();
t_SpectrumVisual->join();
demodVisualThread->terminate();
t_DemodVisual->join();
delete sdrThread; delete sdrThread;
delete t_SDR; delete t_SDR;
@ -198,6 +209,11 @@ int CubicSDR::OnExit() {
delete sdrPostThread; delete sdrPostThread;
delete t_PostSDR; delete t_PostSDR;
delete t_SpectrumVisual;
delete spectrumVisualThread;
delete t_DemodVisual;
delete demodVisualThread;
delete pipeSDRCommand; delete pipeSDRCommand;
delete pipeIQVisualData; delete pipeIQVisualData;
@ -297,16 +313,12 @@ ScopeVisualProcessor *CubicSDR::getScopeProcessor() {
return &scopeProcessor; return &scopeProcessor;
} }
SpectrumVisualProcessor *CubicSDR::getSpectrumProcesor() { SpectrumVisualProcessor *CubicSDR::getSpectrumProcessor() {
return &spectrumProcessor; return spectrumVisualThread->getProcessor();
} }
SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcesor() { SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcessor() {
return &demodSpectrumProcessor; return demodVisualThread->getProcessor();
}
SpectrumVisualProcessor *CubicSDR::getWaterfallProcesor() {
return &waterfallProcessor;
} }
VisualDataDistributor<DemodulatorThreadIQData> *CubicSDR::getSpectrumDistributor() { VisualDataDistributor<DemodulatorThreadIQData> *CubicSDR::getSpectrumDistributor() {
@ -416,8 +428,25 @@ int CubicSDR::getPPM() {
} }
void CubicSDR::showFrequencyInput() { void CubicSDR::showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetMode) {
FrequencyDialog fdialog(appframe, -1, demodMgr.getActiveDemodulator()?_("Set Demodulator Frequency"):_("Set Center Frequency"), demodMgr.getActiveDemodulator(), wxPoint(-100,-100), wxSize(320, 75 )); const wxString demodTitle("Set Demodulator Frequency");
const wxString freqTitle("Set Center Frequency");
const wxString bwTitle("Set Demodulator Bandwidth");
wxString title;
switch (targetMode) {
case FrequencyDialog::FDIALOG_TARGET_DEFAULT:
title = demodMgr.getActiveDemodulator()?demodTitle:freqTitle;
break;
case FrequencyDialog::FDIALOG_TARGET_BANDWIDTH:
title = bwTitle;
break;
default:
break;
}
FrequencyDialog fdialog(appframe, -1, title, demodMgr.getActiveDemodulator(), wxPoint(-100,-100), wxSize(320, 75 ), wxDEFAULT_DIALOG_STYLE, targetMode);
fdialog.ShowModal(); fdialog.ShowModal();
} }

View File

@ -16,9 +16,11 @@
#include "DemodulatorMgr.h" #include "DemodulatorMgr.h"
#include "AppConfig.h" #include "AppConfig.h"
#include "AppFrame.h" #include "AppFrame.h"
#include "FrequencyDialog.h"
#include "ScopeVisualProcessor.h" #include "ScopeVisualProcessor.h"
#include "SpectrumVisualProcessor.h" #include "SpectrumVisualProcessor.h"
#include "SpectrumVisualDataThread.h"
#include <wx/cmdline.h> #include <wx/cmdline.h>
@ -56,9 +58,8 @@ public:
int getDevice(); int getDevice();
ScopeVisualProcessor *getScopeProcessor(); ScopeVisualProcessor *getScopeProcessor();
SpectrumVisualProcessor *getSpectrumProcesor(); SpectrumVisualProcessor *getSpectrumProcessor();
SpectrumVisualProcessor *getDemodSpectrumProcesor(); SpectrumVisualProcessor *getDemodSpectrumProcessor();
SpectrumVisualProcessor *getWaterfallProcesor();
VisualDataDistributor<DemodulatorThreadIQData> *getSpectrumDistributor(); VisualDataDistributor<DemodulatorThreadIQData> *getSpectrumDistributor();
DemodulatorThreadOutputQueue* getAudioVisualQueue(); DemodulatorThreadOutputQueue* getAudioVisualQueue();
@ -78,7 +79,7 @@ public:
void setPPM(int ppm_in); void setPPM(int ppm_in);
int getPPM(); int getPPM();
void showFrequencyInput(); void showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetMode = FrequencyDialog::FDIALOG_TARGET_DEFAULT);
private: private:
AppFrame *appframe; AppFrame *appframe;
@ -96,6 +97,8 @@ private:
SDRThread *sdrThread; SDRThread *sdrThread;
SDRPostThread *sdrPostThread; SDRPostThread *sdrPostThread;
SpectrumVisualDataThread *spectrumVisualThread;
SpectrumVisualDataThread *demodVisualThread;
SDRThreadCommandQueue* pipeSDRCommand; SDRThreadCommandQueue* pipeSDRCommand;
SDRThreadIQDataQueue* pipeSDRIQData; SDRThreadIQDataQueue* pipeSDRIQData;
@ -106,14 +109,13 @@ private:
DemodulatorThreadInputQueue* pipeWaterfallIQVisualData; DemodulatorThreadInputQueue* pipeWaterfallIQVisualData;
ScopeVisualProcessor scopeProcessor; ScopeVisualProcessor scopeProcessor;
SpectrumVisualProcessor spectrumProcessor;
SpectrumVisualProcessor waterfallProcessor;
SpectrumVisualProcessor demodSpectrumProcessor;
VisualDataDistributor<DemodulatorThreadIQData> spectrumDistributor; VisualDataDistributor<DemodulatorThreadIQData> spectrumDistributor;
std::thread *t_SDR; std::thread *t_SDR;
std::thread *t_PostSDR; std::thread *t_PostSDR;
std::thread *t_SpectrumVisual;
std::thread *t_DemodVisual;
}; };
static const wxCmdLineEntryDesc commandLineInfo [] = static const wxCmdLineEntryDesc commandLineInfo [] =

View File

@ -10,15 +10,22 @@ EVT_CHAR_HOOK(FrequencyDialog::OnChar)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
FrequencyDialog::FrequencyDialog(wxWindow * parent, wxWindowID id, const wxString & title, DemodulatorInstance *demod, const wxPoint & position, FrequencyDialog::FrequencyDialog(wxWindow * parent, wxWindowID id, const wxString & title, DemodulatorInstance *demod, const wxPoint & position,
const wxSize & size, long style) : const wxSize & size, long style, FrequencyDialogTarget targetMode) :
wxDialog(parent, id, title, position, size, style) { wxDialog(parent, id, title, position, size, style) {
wxString freqStr; wxString freqStr;
activeDemod = demod; activeDemod = demod;
this->targetMode = targetMode;
if (activeDemod) { if (targetMode == FDIALOG_TARGET_DEFAULT) {
freqStr = frequencyToStr(activeDemod->getFrequency()); if (activeDemod) {
} else { freqStr = frequencyToStr(activeDemod->getFrequency());
freqStr = frequencyToStr(wxGetApp().getFrequency()); } else {
freqStr = frequencyToStr(wxGetApp().getFrequency());
}
}
if (targetMode == FDIALOG_TARGET_BANDWIDTH) {
freqStr = frequencyToStr(wxGetApp().getDemodMgr().getLastBandwidth());
} }
dialogText = new wxTextCtrl(this, wxID_FREQ_INPUT, freqStr, wxPoint(6, 1), wxSize(size.GetWidth() - 20, size.GetHeight() - 70), dialogText = new wxTextCtrl(this, wxID_FREQ_INPUT, freqStr, wxPoint(6, 1), wxSize(size.GetWidth() - 20, size.GetHeight() - 70),
@ -109,14 +116,23 @@ void FrequencyDialog::OnChar(wxKeyEvent& event) {
case WXK_NUMPAD_ENTER: case WXK_NUMPAD_ENTER:
// Do Stuff // Do Stuff
freq = strToFrequency(dialogText->GetValue().ToStdString()); freq = strToFrequency(dialogText->GetValue().ToStdString());
if (activeDemod) { if (targetMode == FDIALOG_TARGET_DEFAULT) {
activeDemod->setTracking(true); if (activeDemod) {
activeDemod->setFollow(true); activeDemod->setTracking(true);
activeDemod->setFrequency(freq); activeDemod->setFollow(true);
activeDemod->updateLabel(freq); activeDemod->setFrequency(freq);
} else { activeDemod->updateLabel(freq);
wxGetApp().setFrequency(freq); } else {
} wxGetApp().setFrequency(freq);
}
}
if (targetMode == FDIALOG_TARGET_BANDWIDTH) {
if (activeDemod) {
activeDemod->setBandwidth(freq);
} else {
wxGetApp().getDemodMgr().setLastBandwidth(freq);
}
}
Close(); Close();
break; break;
case WXK_ESCAPE: case WXK_ESCAPE:

View File

@ -11,12 +11,13 @@
class FrequencyDialog: public wxDialog class FrequencyDialog: public wxDialog
{ {
public: public:
typedef enum FrequencyDialogTarget { FDIALOG_TARGET_DEFAULT, FDIALOG_TARGET_CENTERFREQ, FDIALOG_TARGET_FREQ, FDIALOG_TARGET_BANDWIDTH } FrequencyDialogTarget;
FrequencyDialog ( wxWindow * parent, wxWindowID id, const wxString & title, FrequencyDialog ( wxWindow * parent, wxWindowID id, const wxString & title,
DemodulatorInstance *demod = NULL, DemodulatorInstance *demod = NULL,
const wxPoint & pos = wxDefaultPosition, const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize, const wxSize & size = wxDefaultSize,
long style = wxDEFAULT_DIALOG_STYLE ); long style = wxDEFAULT_DIALOG_STYLE,
FrequencyDialogTarget targetMode = FDIALOG_TARGET_DEFAULT);
wxTextCtrl * dialogText; wxTextCtrl * dialogText;
@ -28,5 +29,6 @@ private:
void OnEnter ( wxCommandEvent &event ); void OnEnter ( wxCommandEvent &event );
void OnChar ( wxKeyEvent &event ); void OnChar ( wxKeyEvent &event );
std::string& filterChars(std::string& s, const std::string& allowed); std::string& filterChars(std::string& s, const std::string& allowed);
FrequencyDialogTarget targetMode;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };

View File

@ -0,0 +1,64 @@
#include "FFTVisualDataThread.h"
#include "CubicSDR.h"
FFTVisualDataThread::FFTVisualDataThread() : linesPerSecond(DEFAULT_WATERFALL_LPS) {
lpsChanged.store(true);
}
FFTVisualDataThread::~FFTVisualDataThread() {
}
void FFTVisualDataThread::setLinesPerSecond(int lps) {
linesPerSecond.store(lps);
lpsChanged.store(true);
}
int FFTVisualDataThread::getLinesPerSecond() {
return linesPerSecond.load();
}
SpectrumVisualProcessor *FFTVisualDataThread::getProcessor() {
return &wproc;
}
void FFTVisualDataThread::run() {
DemodulatorThreadInputQueue *pipeIQDataIn = (DemodulatorThreadInputQueue *)getInputQueue("IQDataInput");
SpectrumVisualDataQueue *pipeFFTDataOut = (SpectrumVisualDataQueue *)getOutputQueue("FFTDataOutput");
fftDistrib.setInput(pipeIQDataIn);
fftDistrib.attachOutput(&fftQueue);
wproc.setInput(&fftQueue);
wproc.attachOutput(pipeFFTDataOut);
wproc.setup(2048);
std::cout << "FFT visual data thread started." << std::endl;
while(!terminated) {
std::this_thread::sleep_for(std::chrono::milliseconds(12));
int fftSize = wproc.getDesiredInputSize();
if (fftSize) {
fftDistrib.setFFTSize(fftSize);
} else {
fftDistrib.setFFTSize(DEFAULT_FFT_SIZE);
}
if (lpsChanged.load()) {
fftDistrib.setLinesPerSecond(linesPerSecond.load());
pipeIQDataIn->set_max_num_items(linesPerSecond.load());
lpsChanged.store(false);
}
fftDistrib.run();
while (!wproc.isInputEmpty()) {
wproc.run();
}
}
std::cout << "FFT visual data thread done." << std::endl;
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "IOThread.h"
#include "SpectrumVisualProcessor.h"
class FFTVisualDataThread : public IOThread {
public:
FFTVisualDataThread();
~FFTVisualDataThread();
void setLinesPerSecond(int lps);
int getLinesPerSecond();
SpectrumVisualProcessor *getProcessor();
void run();
protected:
FFTDataDistributor fftDistrib;
DemodulatorThreadInputQueue fftQueue;
SpectrumVisualProcessor wproc;
std::atomic_int linesPerSecond;
std::atomic_bool lpsChanged;
};

View File

@ -0,0 +1,25 @@
#include "SpectrumVisualDataThread.h"
#include "CubicSDR.h"
SpectrumVisualDataThread::SpectrumVisualDataThread() {
}
SpectrumVisualDataThread::~SpectrumVisualDataThread() {
}
SpectrumVisualProcessor *SpectrumVisualDataThread::getProcessor() {
return &sproc;
}
void SpectrumVisualDataThread::run() {
std::cout << "Spectrum visual data thread started." << std::endl;
while(!terminated) {
std::this_thread::sleep_for(std::chrono::milliseconds(12));
sproc.run();
}
std::cout << "Spectrum visual data thread done." << std::endl;
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "IOThread.h"
#include "SpectrumVisualProcessor.h"
class SpectrumVisualDataThread : public IOThread {
public:
SpectrumVisualDataThread();
~SpectrumVisualDataThread();
SpectrumVisualProcessor *getProcessor();
void run();
protected:
SpectrumVisualProcessor sproc;
};

View File

@ -111,7 +111,10 @@ protected:
if (inp) { if (inp) {
if (inp->data.size() >= fftSize) { if (inp->data.size() >= fftSize) {
for (int i = 0, iMax = inp->data.size()-fftSize; i <= iMax; i += 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; lineRateAccum += lineRateStep;
if (lineRateAccum >= 1.0) { if (lineRateAccum >= 1.0) {

View File

@ -221,14 +221,14 @@ void SDRPostThread::run() {
data_in->decRefCount(); data_in->decRefCount();
} }
buffers.purge(); // buffers.purge();
if (iqVisualQueue && !iqVisualQueue->empty()) { if (iqVisualQueue && !iqVisualQueue->empty()) {
DemodulatorThreadIQData *visualDataDummy; DemodulatorThreadIQData *visualDataDummy;
iqVisualQueue->pop(visualDataDummy); iqVisualQueue->pop(visualDataDummy);
} }
visualDataBuffers.purge(); // visualDataBuffers.purge();
std::cout << "SDR post-processing thread done." << std::endl; std::cout << "SDR post-processing thread done." << std::endl;
} }

View File

@ -295,7 +295,7 @@ void SDRThread::run() {
} }
} }
buffers.purge(); // buffers.purge();
std::cout << "SDR thread done." << std::endl; std::cout << "SDR thread done." << std::endl;
} }

View File

@ -32,9 +32,8 @@ void initGLExtensions() {
return; return;
} }
const GLubyte *extensions = glGetString(GL_EXTENSIONS); // const GLubyte *extensions = glGetString(GL_EXTENSIONS);
// std::cout << std::endl << "Supported GL Extensions: " << std::endl << extensions << std::endl << std::endl;
std::cout << std::endl << "Supported GL Extensions: " << std::endl << extensions << std::endl << std::endl;
#ifdef __linux__ #ifdef __linux__
const GLint interval = 2; const GLint interval = 2;

View File

@ -22,6 +22,7 @@ EVT_IDLE(SpectrumCanvas::OnIdle)
EVT_MOTION(SpectrumCanvas::OnMouseMoved) EVT_MOTION(SpectrumCanvas::OnMouseMoved)
EVT_LEFT_DOWN(SpectrumCanvas::OnMouseDown) EVT_LEFT_DOWN(SpectrumCanvas::OnMouseDown)
EVT_LEFT_UP(SpectrumCanvas::OnMouseReleased) EVT_LEFT_UP(SpectrumCanvas::OnMouseReleased)
EVT_ENTER_WINDOW(SpectrumCanvas::OnMouseEnterWindow)
EVT_LEAVE_WINDOW(SpectrumCanvas::OnMouseLeftWindow) EVT_LEAVE_WINDOW(SpectrumCanvas::OnMouseLeftWindow)
EVT_MOUSEWHEEL(SpectrumCanvas::OnMouseWheelMoved) EVT_MOUSEWHEEL(SpectrumCanvas::OnMouseWheelMoved)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
@ -152,6 +153,11 @@ void SpectrumCanvas::OnMouseReleased(wxMouseEvent& event) {
SetCursor(wxCURSOR_SIZEWE); SetCursor(wxCURSOR_SIZEWE);
} }
void SpectrumCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
InteractiveCanvas::OnMouseEnterWindow(event);
SetCursor(wxCURSOR_SIZEWE);
}
void SpectrumCanvas::OnMouseLeftWindow(wxMouseEvent& event) { void SpectrumCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
InteractiveCanvas::OnMouseLeftWindow(event); InteractiveCanvas::OnMouseLeftWindow(event);
SetCursor(wxCURSOR_SIZEWE); SetCursor(wxCURSOR_SIZEWE);
@ -163,4 +169,4 @@ void SpectrumCanvas::attachWaterfallCanvas(WaterfallCanvas* canvas_in) {
SpectrumVisualDataQueue *SpectrumCanvas::getVisualDataQueue() { SpectrumVisualDataQueue *SpectrumCanvas::getVisualDataQueue() {
return &visualDataQueue; return &visualDataQueue;
} }

View File

@ -30,6 +30,7 @@ private:
void OnMouseDown(wxMouseEvent& event); void OnMouseDown(wxMouseEvent& event);
void OnMouseWheelMoved(wxMouseEvent& event); void OnMouseWheelMoved(wxMouseEvent& event);
void OnMouseReleased(wxMouseEvent& event); void OnMouseReleased(wxMouseEvent& event);
void OnMouseEnterWindow(wxMouseEvent& event);
void OnMouseLeftWindow(wxMouseEvent& event); void OnMouseLeftWindow(wxMouseEvent& event);
PrimaryGLContext *glContext; PrimaryGLContext *glContext;

View File

@ -297,7 +297,7 @@ void TuningCanvas::OnMouseMoved(wxMouseEvent& event) {
setStatusText("Click, wheel or drag a digit to change frequency; SPACE for direct input. Right click to set/clear snap. Hold ALT to change PPM. Hold SHIFT to disable carry."); setStatusText("Click, wheel or drag a digit to change frequency; SPACE for direct input. Right click to set/clear snap. Hold ALT to change PPM. Hold SHIFT to disable carry.");
break; break;
case TUNING_HOVER_BW: case TUNING_HOVER_BW:
setStatusText("Click, wheel or drag a digit to change bandwidth. Hold SHIFT to disable carry."); setStatusText("Click, wheel or drag a digit to change bandwidth; SPACE for direct input. Hold SHIFT to disable carry.");
break; break;
case TUNING_HOVER_CENTER: case TUNING_HOVER_CENTER:
setStatusText("Click, wheel or drag a digit to change center frequency; SPACE for direct input. Hold SHIFT to disable carry."); setStatusText("Click, wheel or drag a digit to change center frequency; SPACE for direct input. Hold SHIFT to disable carry.");
@ -407,8 +407,12 @@ void TuningCanvas::setHelpTip(std::string tip) {
void TuningCanvas::OnKeyDown(wxKeyEvent& event) { void TuningCanvas::OnKeyDown(wxKeyEvent& event) {
InteractiveCanvas::OnKeyDown(event); InteractiveCanvas::OnKeyDown(event);
if (event.GetKeyCode() == WXK_SPACE && (hoverState == TUNING_HOVER_CENTER || hoverState == TUNING_HOVER_FREQ)) { if (event.GetKeyCode() == WXK_SPACE) {
wxGetApp().showFrequencyInput(); if (hoverState == TUNING_HOVER_CENTER || hoverState == TUNING_HOVER_FREQ) {
wxGetApp().showFrequencyInput(FrequencyDialog::FDIALOG_TARGET_DEFAULT);
} else if (hoverState == TUNING_HOVER_BW) {
wxGetApp().showFrequencyInput(FrequencyDialog::FDIALOG_TARGET_BANDWIDTH);
}
} }
} }

View File

@ -88,12 +88,8 @@ void WaterfallCanvas::processInputQueue() {
} }
void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
// event.Skip(); // wxClientDC dc(this);
} wxPaintDC dc(this);
void WaterfallCanvas::DoPaint() {
wxClientDC dc(this);
// wxPaintDC dc(this);
const wxSize ClientSize = GetClientSize(); const wxSize ClientSize = GetClientSize();
long double currentZoom = zoom; long double currentZoom = zoom;
@ -109,45 +105,49 @@ void WaterfallCanvas::DoPaint() {
long long bw; long long bw;
if (currentZoom != 1) { if (currentZoom != 1) {
long long freq = wxGetApp().getFrequency(); long long freq = wxGetApp().getFrequency();
bw = getBandwidth();
double mpos = 0;
float mouseInView = false;
if (mouseTracker.mouseInView()) {
mpos = mouseTracker.getMouseX();
mouseInView = true;
} else if (spectrumCanvas && spectrumCanvas->getMouseTracker()->mouseInView()) {
mpos = spectrumCanvas->getMouseTracker()->getMouseX();
mouseInView = true;
}
if (currentZoom < 1) { if (currentZoom < 1) {
centerFreq = getCenterFrequency();
bw = getBandwidth();
bw = (long long) ceil((long double) bw * currentZoom); bw = (long long) ceil((long double) bw * currentZoom);
if (bw < 30000) { if (bw < 30000) {
bw = 30000; bw = 30000;
} }
if (mouseTracker.mouseInView()) { if (mouseInView) {
long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); long long mfreqA = getFrequencyAt(mpos);
setBandwidth(bw); setBandwidth(bw);
long long mfreqB = getFrequencyAt(mouseTracker.getMouseX()); long long mfreqB = getFrequencyAt(mpos);
centerFreq += mfreqA - mfreqB; centerFreq += mfreqA - mfreqB;
} }
setView(centerFreq, bw); setView(centerFreq, bw);
if (spectrumCanvas) {
spectrumCanvas->setView(centerFreq, bw);
}
} else { } else {
if (isView) { if (isView) {
bw = getBandwidth();
bw = (long long) ceil((long double) bw * currentZoom); bw = (long long) ceil((long double) bw * currentZoom);
if (bw >= wxGetApp().getSampleRate()) { if (bw >= wxGetApp().getSampleRate()) {
disableView(); disableView();
if (spectrumCanvas) { if (spectrumCanvas) {
spectrumCanvas->disableView(); spectrumCanvas->disableView();
} }
} else { } else {
if (mouseTracker.mouseInView()) { if (mouseInView) {
long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); long long mfreqA = getFrequencyAt(mpos);
setBandwidth(bw); setBandwidth(bw);
long long mfreqB = getFrequencyAt(mouseTracker.getMouseX()); long long mfreqB = getFrequencyAt(mpos);
centerFreq += mfreqA - mfreqB; centerFreq += mfreqA - mfreqB;
} } else {
setBandwidth(bw);
setView(getCenterFrequency(), bw);
if (spectrumCanvas) {
spectrumCanvas->setView(centerFreq, bw);
} }
} }
} }
@ -158,8 +158,15 @@ void WaterfallCanvas::DoPaint() {
if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + wxGetApp().getSampleRate() / 2)) { if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + wxGetApp().getSampleRate() / 2)) {
centerFreq = (freq + wxGetApp().getSampleRate() / 2) - bandwidth / 2; centerFreq = (freq + wxGetApp().getSampleRate() / 2) - bandwidth / 2;
} }
if (spectrumCanvas) {
if ((spectrumCanvas->getCenterFrequency() != centerFreq) || (spectrumCanvas->getBandwidth() != bw)) {
spectrumCanvas->setView(centerFreq,bw);
}
}
} }
glContext->SetCurrent(*this); glContext->SetCurrent(*this);
initGLExtensions(); initGLExtensions();
glViewport(0, 0, ClientSize.x, ClientSize.y); glViewport(0, 0, ClientSize.x, ClientSize.y);
@ -256,10 +263,16 @@ void WaterfallCanvas::OnKeyUp(wxKeyEvent& event) {
ctrlDown = event.ControlDown(); ctrlDown = event.ControlDown();
switch (event.GetKeyCode()) { switch (event.GetKeyCode()) {
case 'A': case 'A':
zoom = 1.0; case WXK_UP:
case WXK_NUMPAD_UP:
zoom = 1.0;
mouseZoom = 0.95;
break; break;
case 'Z': case 'Z':
zoom = 1.0; case WXK_DOWN:
case WXK_NUMPAD_DOWN:
zoom = 1.0;
mouseZoom = 1.05;
break; break;
} }
} }
@ -269,68 +282,37 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator(); DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
long long freq; long long originalFreq = getCenterFrequency();
long long originalFreq; long long freq = originalFreq;
switch (event.GetKeyCode()) { switch (event.GetKeyCode()) {
case 'A': case 'A':
zoom = 0.95; case WXK_UP:
case WXK_NUMPAD_UP:
mouseZoom = 1.0;
zoom = 0.95;
break; break;
case 'Z': case 'Z':
zoom = 1.05; case WXK_DOWN:
case WXK_NUMPAD_DOWN:
mouseZoom = 1.0;
zoom = 1.05;
break; break;
case WXK_RIGHT: case WXK_RIGHT:
freq = wxGetApp().getFrequency(); case WXK_NUMPAD_RIGHT:
originalFreq = freq;
if (shiftDown) { if (shiftDown) {
freq += wxGetApp().getSampleRate() * 10; freq += getBandwidth() * 10;
if (isView) {
setView(centerFreq + (freq - originalFreq), getBandwidth());
if (spectrumCanvas) {
spectrumCanvas->setView(getCenterFrequency(), getBandwidth());
}
}
} else { } else {
freq += wxGetApp().getSampleRate() / 2; freq += getBandwidth() / 2;
if (isView) {
setView(centerFreq + (freq - originalFreq), getBandwidth());
if (spectrumCanvas) {
spectrumCanvas->setView(getCenterFrequency(), getBandwidth());
}
}
} }
wxGetApp().setFrequency(freq);
setStatusText("Set center frequency: %s", freq);
break; break;
case WXK_LEFT: case WXK_LEFT:
freq = wxGetApp().getFrequency(); case WXK_NUMPAD_LEFT:
originalFreq = freq;
if (shiftDown) { if (shiftDown) {
if ((freq - wxGetApp().getSampleRate() * 10) < wxGetApp().getSampleRate() / 2) { freq -= getBandwidth() * 10;
freq = wxGetApp().getSampleRate() / 2;
} else {
freq -= wxGetApp().getSampleRate() * 10;
}
if (isView) {
setView(centerFreq + (freq - originalFreq), getBandwidth());
if (spectrumCanvas) {
spectrumCanvas->setView(getCenterFrequency(), getBandwidth());
}
}
} else { } else {
if ((freq - wxGetApp().getSampleRate() / 2) < wxGetApp().getSampleRate() / 2) { freq -= getBandwidth() / 2;
freq = wxGetApp().getSampleRate() / 2;
} else {
freq -= wxGetApp().getSampleRate() / 2;
}
if (isView) {
setView(centerFreq + (freq - originalFreq), getBandwidth());
if (spectrumCanvas) {
spectrumCanvas->setView(getCenterFrequency(), getBandwidth());
}
}
} }
wxGetApp().setFrequency(freq);
setStatusText("Set center frequency: %s", freq);
break; break;
case 'D': case 'D':
case WXK_DELETE: case WXK_DELETE:
@ -357,11 +339,44 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
event.Skip(); event.Skip();
return; return;
} }
long long minFreq = wxGetApp().getSampleRate()/2;
if (freq < minFreq) {
freq = minFreq;
}
if (freq != originalFreq) {
if (isView) {
setView(freq, getBandwidth());
if (spectrumCanvas) {
spectrumCanvas->setView(freq, getBandwidth());
}
long long minFreq = wxGetApp().getFrequency()-(wxGetApp().getSampleRate()/2);
long long maxFreq = wxGetApp().getFrequency()+(wxGetApp().getSampleRate()/2);
if (freq < minFreq) {
wxGetApp().setFrequency(freq+(wxGetApp().getSampleRate()/2));
setStatusText("Set center frequency: %s", freq);
}
if (freq > maxFreq) {
wxGetApp().setFrequency(freq-(wxGetApp().getSampleRate()/2));
setStatusText("Set center frequency: %s", freq);
}
} else {
if (spectrumCanvas) {
spectrumCanvas->setCenterFrequency(freq);
}
wxGetApp().setFrequency(freq);
setStatusText("Set center frequency: %s", freq);
}
}
} }
void WaterfallCanvas::OnIdle(wxIdleEvent &event) { void WaterfallCanvas::OnIdle(wxIdleEvent &event) {
// Refresh(); Refresh();
// event.RequestMore(); event.RequestMore();
event.Skip(); // event.Skip();
} }
void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {

View File

@ -28,7 +28,6 @@ public:
void attachSpectrumCanvas(SpectrumCanvas *canvas_in); void attachSpectrumCanvas(SpectrumCanvas *canvas_in);
void processInputQueue(); void processInputQueue();
SpectrumVisualDataQueue *getVisualDataQueue(); SpectrumVisualDataQueue *getVisualDataQueue();
void DoPaint();
private: private:
void OnPaint(wxPaintEvent& event); void OnPaint(wxPaintEvent& event);