mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-23 04:08:36 -05:00
Merge pull request #129 from cjcliffe/waterfall_speed_avg
Waterfall speed and Spectrum Averaging control
This commit is contained in:
commit
b73f264d6b
@ -123,6 +123,8 @@ AppConfig::AppConfig() : configName("") {
|
||||
themeId.store(0);
|
||||
snap.store(1);
|
||||
centerFreq.store(100000000);
|
||||
waterfallLinesPerSec.store(DEFAULT_WATERFALL_LPS);
|
||||
spectrumAvgSpeed.store(0.65f);
|
||||
}
|
||||
|
||||
|
||||
@ -204,6 +206,23 @@ long long AppConfig::getCenterFreq() {
|
||||
return centerFreq.load();
|
||||
}
|
||||
|
||||
|
||||
void AppConfig::setWaterfallLinesPerSec(int lps) {
|
||||
waterfallLinesPerSec.store(lps);
|
||||
}
|
||||
|
||||
int AppConfig::getWaterfallLinesPerSec() {
|
||||
return waterfallLinesPerSec.load();
|
||||
}
|
||||
|
||||
void AppConfig::setSpectrumAvgSpeed(float avgSpeed) {
|
||||
spectrumAvgSpeed.store(avgSpeed);
|
||||
}
|
||||
|
||||
float AppConfig::getSpectrumAvgSpeed() {
|
||||
return spectrumAvgSpeed.load();
|
||||
}
|
||||
|
||||
void AppConfig::setConfigName(std::string configName) {
|
||||
this->configName = configName;
|
||||
}
|
||||
@ -243,6 +262,8 @@ bool AppConfig::save() {
|
||||
*window_node->newChild("theme") = themeId.load();
|
||||
*window_node->newChild("snap") = snap.load();
|
||||
*window_node->newChild("center_freq") = centerFreq.load();
|
||||
*window_node->newChild("waterfall_lps") = waterfallLinesPerSec.load();
|
||||
*window_node->newChild("spectrum_avg") = spectrumAvgSpeed.load();
|
||||
}
|
||||
|
||||
DataNode *devices_node = cfg.rootNode()->newChild("devices");
|
||||
@ -339,7 +360,19 @@ bool AppConfig::load() {
|
||||
win_node->getNext("center_freq")->element()->get(freqVal);
|
||||
centerFreq.store(freqVal);
|
||||
}
|
||||
}
|
||||
|
||||
if (win_node->hasAnother("waterfall_lps")) {
|
||||
int lpsVal;
|
||||
win_node->getNext("waterfall_lps")->element()->get(lpsVal);
|
||||
waterfallLinesPerSec.store(lpsVal);
|
||||
}
|
||||
|
||||
if (win_node->hasAnother("spectrum_avg")) {
|
||||
float avgVal;
|
||||
win_node->getNext("spectrum_avg")->element()->get(avgVal);
|
||||
spectrumAvgSpeed.store(avgVal);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.rootNode()->hasAnother("devices")) {
|
||||
DataNode *devices_node = cfg.rootNode()->getNext("devices");
|
||||
|
@ -61,7 +61,13 @@ public:
|
||||
|
||||
void setCenterFreq(long long freqVal);
|
||||
long long getCenterFreq();
|
||||
|
||||
|
||||
void setWaterfallLinesPerSec(int lps);
|
||||
int getWaterfallLinesPerSec();
|
||||
|
||||
void setSpectrumAvgSpeed(float avgSpeed);
|
||||
float getSpectrumAvgSpeed();
|
||||
|
||||
void setConfigName(std::string configName);
|
||||
std::string getConfigFileName(bool ignoreName=false);
|
||||
bool save();
|
||||
@ -76,4 +82,6 @@ private:
|
||||
std::atomic_int themeId;
|
||||
std::atomic_llong snap;
|
||||
std::atomic_llong centerFreq;
|
||||
std::atomic_int waterfallLinesPerSec;
|
||||
std::atomic<float> spectrumAvgSpeed;
|
||||
};
|
||||
|
161
src/AppFrame.cpp
161
src/AppFrame.cpp
@ -35,11 +35,10 @@ EVT_CLOSE(AppFrame::OnClose)
|
||||
EVT_MENU(wxID_ANY, AppFrame::OnMenu)
|
||||
EVT_COMMAND(wxID_ANY, wxEVT_THREAD, AppFrame::OnThread)
|
||||
EVT_IDLE(AppFrame::OnIdle)
|
||||
EVT_TIMER(FRAME_TIMER_ID, AppFrame::OnTimer)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
AppFrame::AppFrame() :
|
||||
wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL), frame_timer(this, FRAME_TIMER_ID) {
|
||||
wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL) {
|
||||
|
||||
#ifdef __linux__
|
||||
SetIcon(wxICON(cubicsdr));
|
||||
@ -63,8 +62,6 @@ AppFrame::AppFrame() :
|
||||
demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation, Amplitude Modulation and Lower, Upper or Double Side-Band.");
|
||||
demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0);
|
||||
|
||||
// demodTray->AddSpacer(2);
|
||||
|
||||
wxGetApp().getDemodSpectrumProcesor()->setup(1024);
|
||||
demodSpectrumCanvas = new SpectrumCanvas(this, attribList);
|
||||
demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000);
|
||||
@ -109,23 +106,59 @@ AppFrame::AppFrame() :
|
||||
demodGainMeter = new MeterCanvas(this, attribList);
|
||||
demodGainMeter->setMax(2.0);
|
||||
demodGainMeter->setHelpTip("Current Demodulator Gain Level. Click / Drag to set Gain level.");
|
||||
demodGainMeter->setShowUserInput(false);
|
||||
demodTray->Add(demodGainMeter, 1, wxEXPAND | wxALL, 0);
|
||||
|
||||
vbox->Add(demodTray, 12, wxEXPAND | wxALL, 0);
|
||||
vbox->AddSpacer(1);
|
||||
|
||||
wxBoxSizer *spectrumSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxGetApp().getSpectrumProcesor()->setup(2048);
|
||||
spectrumCanvas = new SpectrumCanvas(this, attribList);
|
||||
vbox->Add(spectrumCanvas, 5, wxEXPAND | wxALL, 0);
|
||||
vbox->AddSpacer(1);
|
||||
wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue());
|
||||
|
||||
spectrumAvgMeter = new MeterCanvas(this, attribList);
|
||||
spectrumAvgMeter->setHelpTip("Spectrum averaging speed, click or drag to adjust.");
|
||||
spectrumAvgMeter->setMax(1.0);
|
||||
spectrumAvgMeter->setLevel(0.65);
|
||||
spectrumAvgMeter->setShowUserInput(false);
|
||||
|
||||
spectrumSizer->Add(spectrumCanvas, 63, wxEXPAND | wxALL, 0);
|
||||
spectrumSizer->AddSpacer(1);
|
||||
spectrumSizer->Add(spectrumAvgMeter, 1, wxEXPAND | wxALL, 0);
|
||||
|
||||
vbox->Add(spectrumSizer, 5, wxEXPAND | wxALL, 0);
|
||||
|
||||
vbox->AddSpacer(1);
|
||||
|
||||
wxBoxSizer *wfSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxGetApp().getWaterfallProcesor()->setup(2048);
|
||||
waterfallCanvas = new WaterfallCanvas(this, attribList);
|
||||
waterfallCanvas->setup(2048, 512);
|
||||
|
||||
fftDistrib.setInput(wxGetApp().getWaterfallVisualQueue());
|
||||
fftDistrib.attachOutput(&fftQueue);
|
||||
|
||||
wxGetApp().getWaterfallProcesor()->setInput(&fftQueue);
|
||||
wxGetApp().getWaterfallProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue());
|
||||
|
||||
waterfallSpeedMeter = new MeterCanvas(this, attribList);
|
||||
waterfallSpeedMeter->setHelpTip("Waterfall speed, click or drag to adjust (max 1024 lines per second)");
|
||||
waterfallSpeedMeter->setMax(sqrt(1024));
|
||||
waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS));
|
||||
waterfallSpeedMeter->setShowUserInput(false);
|
||||
|
||||
wfSizer->Add(waterfallCanvas, 63, wxEXPAND | wxALL, 0);
|
||||
wfSizer->AddSpacer(1);
|
||||
wfSizer->Add(waterfallSpeedMeter, 1, wxEXPAND | wxALL, 0);
|
||||
|
||||
vbox->Add(wfSizer, 20, wxEXPAND | wxALL, 0);
|
||||
|
||||
// TODO: refactor these..
|
||||
waterfallCanvas->attachSpectrumCanvas(spectrumCanvas);
|
||||
spectrumCanvas->attachWaterfallCanvas(waterfallCanvas);
|
||||
vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0);
|
||||
wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue());
|
||||
|
||||
/*
|
||||
vbox->AddSpacer(1);
|
||||
testCanvas = new UITestCanvas(this, attribList);
|
||||
@ -334,6 +367,16 @@ AppFrame::AppFrame() :
|
||||
|
||||
long long freqSnap = wxGetApp().getConfig()->getSnap();
|
||||
wxGetApp().setFrequencySnap(freqSnap);
|
||||
|
||||
float spectrumAvg = wxGetApp().getConfig()->getSpectrumAvgSpeed();
|
||||
|
||||
spectrumAvgMeter->setLevel(spectrumAvg);
|
||||
wxGetApp().getSpectrumProcesor()->setFFTAverageRate(spectrumAvg);
|
||||
|
||||
int wflps =wxGetApp().getConfig()->getWaterfallLinesPerSec();
|
||||
|
||||
waterfallSpeedMeter->setLevel(sqrt(wflps));
|
||||
fftDistrib.setLinesPerSecond(wflps);
|
||||
|
||||
ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme());
|
||||
|
||||
@ -351,8 +394,6 @@ AppFrame::AppFrame() :
|
||||
wxAcceleratorTable accel(3, entries);
|
||||
SetAcceleratorTable(accel);
|
||||
|
||||
// frame rate = 1000 / 30 = 33ms
|
||||
frame_timer.Start(33);
|
||||
// static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 };
|
||||
// wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not");
|
||||
// ShowFullScreen(true);
|
||||
@ -435,7 +476,22 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
|
||||
} else if (event.GetId() == wxID_RESET) {
|
||||
wxGetApp().getDemodMgr().terminateAll();
|
||||
wxGetApp().setFrequency(100000000);
|
||||
wxGetApp().setOffset(0);
|
||||
wxGetApp().getDemodMgr().setLastDemodulatorType(DEMOD_TYPE_FM);
|
||||
demodModeSelector->setSelection(1);
|
||||
wxGetApp().getDemodMgr().setLastStereo(false);
|
||||
wxGetApp().getDemodMgr().setLastBandwidth(DEFAULT_DEMOD_BW);
|
||||
wxGetApp().getDemodMgr().setLastGain(1.0);
|
||||
wxGetApp().getDemodMgr().setLastSquelchLevel(0);
|
||||
waterfallCanvas->setBandwidth(wxGetApp().getSampleRate());
|
||||
waterfallCanvas->setCenterFrequency(wxGetApp().getFrequency());
|
||||
spectrumCanvas->setBandwidth(wxGetApp().getSampleRate());
|
||||
spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency());
|
||||
fftDistrib.setLinesPerSecond(DEFAULT_WATERFALL_LPS);
|
||||
waterfallSpeedMeter->setLevel(sqrt(DEFAULT_WATERFALL_LPS));
|
||||
wxGetApp().getSpectrumProcesor()->setFFTAverageRate(0.65);
|
||||
spectrumAvgMeter->setLevel(0.65);
|
||||
demodModeSelector->Refresh();
|
||||
demodTuner->Refresh();
|
||||
SetTitle(CUBICSDR_TITLE);
|
||||
currentSessionFile = "";
|
||||
} else if (event.GetId() == wxID_EXIT) {
|
||||
@ -556,6 +612,8 @@ void AppFrame::OnClose(wxCloseEvent& event) {
|
||||
wxGetApp().getConfig()->setTheme(ThemeMgr::mgr.getTheme());
|
||||
wxGetApp().getConfig()->setSnap(wxGetApp().getFrequencySnap());
|
||||
wxGetApp().getConfig()->setCenterFreq(wxGetApp().getFrequency());
|
||||
wxGetApp().getConfig()->setSpectrumAvgSpeed(wxGetApp().getSpectrumProcesor()->getFFTAverageRate());
|
||||
wxGetApp().getConfig()->setWaterfallLinesPerSec(fftDistrib.getLinesPerSecond());
|
||||
wxGetApp().getConfig()->save();
|
||||
event.Skip();
|
||||
}
|
||||
@ -569,10 +627,6 @@ void AppFrame::OnThread(wxCommandEvent& event) {
|
||||
}
|
||||
|
||||
void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void AppFrame::OnTimer(wxTimerEvent& event) {
|
||||
|
||||
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
|
||||
@ -687,12 +741,20 @@ void AppFrame::OnTimer(wxTimerEvent& event) {
|
||||
|
||||
wxGetApp().getScopeProcessor()->run();
|
||||
wxGetApp().getSpectrumDistributor()->run();
|
||||
|
||||
|
||||
SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor();
|
||||
|
||||
proc->setView(waterfallCanvas->getViewState());
|
||||
proc->setBandwidth(waterfallCanvas->getBandwidth());
|
||||
proc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
|
||||
if (spectrumAvgMeter->inputChanged()) {
|
||||
float val = spectrumAvgMeter->getInputValue();
|
||||
spectrumAvgMeter->setLevel(val);
|
||||
proc->setFFTAverageRate(val);
|
||||
|
||||
GetStatusBar()->SetStatusText(wxString::Format(wxT("Spectrum averaging speed changed to %0.2f%%."),val*100.0));
|
||||
}
|
||||
|
||||
proc->setView(spectrumCanvas->getViewState());
|
||||
proc->setBandwidth(spectrumCanvas->getBandwidth());
|
||||
proc->setCenterFrequency(spectrumCanvas->getCenterFrequency());
|
||||
|
||||
proc->run();
|
||||
|
||||
@ -704,25 +766,54 @@ void AppFrame::OnTimer(wxTimerEvent& event) {
|
||||
|
||||
dproc->run();
|
||||
|
||||
scopeCanvas->Refresh();
|
||||
|
||||
waterfallCanvas->Refresh();
|
||||
spectrumCanvas->Refresh();
|
||||
|
||||
demodWaterfallCanvas->Refresh();
|
||||
demodSpectrumCanvas->Refresh();
|
||||
|
||||
demodSignalMeter->Refresh();
|
||||
demodGainMeter->Refresh();
|
||||
SpectrumVisualProcessor *wproc = wxGetApp().getWaterfallProcesor();
|
||||
|
||||
if (demodTuner->getMouseTracker()->mouseInView() || demodTuner->changed()) {
|
||||
demodTuner->Refresh();
|
||||
}
|
||||
if (demodModeSelector->getMouseTracker()->mouseInView()) {
|
||||
demodModeSelector->Refresh();
|
||||
int fftSize = wproc->getDesiredInputSize();
|
||||
|
||||
if (fftSize) {
|
||||
fftDistrib.setFFTSize(fftSize);
|
||||
} else {
|
||||
fftDistrib.setFFTSize(DEFAULT_FFT_SIZE);
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
if (waterfallSpeedMeter->inputChanged()) {
|
||||
float val = waterfallSpeedMeter->getInputValue();
|
||||
waterfallSpeedMeter->setLevel(val);
|
||||
fftDistrib.setLinesPerSecond((int)ceil(val*val));
|
||||
wxGetApp().getWaterfallVisualQueue()->set_max_num_items((int)ceil(val*val));
|
||||
|
||||
GetStatusBar()->SetStatusText(wxString::Format(wxT("Waterfall max speed changed to %d lines per second."),(int)ceil(val*val)));
|
||||
}
|
||||
|
||||
fftDistrib.run();
|
||||
|
||||
wproc->setView(waterfallCanvas->getViewState());
|
||||
wproc->setBandwidth(waterfallCanvas->getBandwidth());
|
||||
wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
|
||||
|
||||
while (!wproc->isInputEmpty()) {
|
||||
wproc->run();
|
||||
}
|
||||
|
||||
waterfallCanvas->processInputQueue();
|
||||
demodWaterfallCanvas->processInputQueue();
|
||||
|
||||
|
||||
if (this->IsVisible()) {
|
||||
waterfallCanvas->DoPaint();
|
||||
demodWaterfallCanvas->DoPaint();
|
||||
#ifdef __APPLE__
|
||||
usleep(5000);
|
||||
#endif
|
||||
} else {
|
||||
#ifndef _WIN32
|
||||
usleep(15000);
|
||||
#else
|
||||
Sleep(15);
|
||||
#endif
|
||||
}
|
||||
|
||||
event.RequestMore();
|
||||
}
|
||||
|
||||
void AppFrame::saveSession(std::string fileName) {
|
||||
|
@ -50,8 +50,6 @@
|
||||
#define wxID_AUDIO_BANDWIDTH_BASE 9000
|
||||
#define wxID_AUDIO_DEVICE_MULTIPLIER 50
|
||||
|
||||
#define FRAME_TIMER_ID 1000
|
||||
|
||||
// Define a new frame type
|
||||
class AppFrame: public wxFrame {
|
||||
public:
|
||||
@ -69,7 +67,6 @@ private:
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnNewWindow(wxCommandEvent& event);
|
||||
void OnIdle(wxIdleEvent& event);
|
||||
void OnTimer(wxTimerEvent& event);
|
||||
|
||||
ScopeCanvas *scopeCanvas;
|
||||
SpectrumCanvas *spectrumCanvas;
|
||||
@ -80,7 +77,9 @@ private:
|
||||
MeterCanvas *demodSignalMeter;
|
||||
MeterCanvas *demodGainMeter;
|
||||
TuningCanvas *demodTuner;
|
||||
UITestCanvas *testCanvas;
|
||||
// UITestCanvas *testCanvas;
|
||||
MeterCanvas *spectrumAvgMeter;
|
||||
MeterCanvas *waterfallSpeedMeter;
|
||||
|
||||
DemodulatorInstance *activeDemodulator;
|
||||
|
||||
@ -94,7 +93,9 @@ private:
|
||||
wxMenuItem *iqSwapMenuItem;
|
||||
|
||||
std::string currentSessionFile;
|
||||
wxTimer frame_timer;
|
||||
|
||||
FFTDataDistributor fftDistrib;
|
||||
DemodulatorThreadInputQueue fftQueue;
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
@ -58,10 +58,13 @@ bool CubicSDR::OnInit() {
|
||||
spectrumDistributor.setInput(pipeIQVisualData);
|
||||
|
||||
pipeDemodIQVisualData = new DemodulatorThreadInputQueue();
|
||||
pipeIQVisualData->set_max_num_items(1);
|
||||
pipeDemodIQVisualData->set_max_num_items(1);
|
||||
|
||||
pipeSpectrumIQVisualData = new DemodulatorThreadInputQueue();
|
||||
pipeIQVisualData->set_max_num_items(1);
|
||||
pipeSpectrumIQVisualData->set_max_num_items(1);
|
||||
|
||||
pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue();
|
||||
pipeWaterfallIQVisualData->set_max_num_items(DEFAULT_WATERFALL_LPS);
|
||||
|
||||
spectrumDistributor.attachOutput(pipeDemodIQVisualData);
|
||||
spectrumDistributor.attachOutput(pipeSpectrumIQVisualData);
|
||||
@ -75,18 +78,21 @@ bool CubicSDR::OnInit() {
|
||||
scopeProcessor.setInput(pipeAudioVisualData);
|
||||
|
||||
// I/Q Data
|
||||
pipeSDRIQData = new SDRThreadIQDataQueue;
|
||||
pipeSDRIQData = new SDRThreadIQDataQueue();
|
||||
pipeSDRCommand = new SDRThreadCommandQueue();
|
||||
|
||||
pipeSDRIQData->set_max_num_items(1);
|
||||
|
||||
sdrThread = new SDRThread();
|
||||
sdrThread->setInputQueue("SDRCommandQueue",pipeSDRCommand);
|
||||
sdrThread->setOutputQueue("IQDataOutput",pipeSDRIQData);
|
||||
|
||||
sdrPostThread = new SDRPostThread();
|
||||
sdrPostThread->setNumVisSamples(16384 * 2);
|
||||
sdrPostThread->setNumVisSamples(BUF_SIZE);
|
||||
sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData);
|
||||
sdrPostThread->setOutputQueue("IQVisualDataOut", pipeIQVisualData);
|
||||
|
||||
sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData);
|
||||
sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData);
|
||||
|
||||
std::vector<SDRDeviceInfo *>::iterator devs_i;
|
||||
|
||||
SDRThread::enumerate_rtl(&devs);
|
||||
@ -276,6 +282,10 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcesor() {
|
||||
return &demodSpectrumProcessor;
|
||||
}
|
||||
|
||||
SpectrumVisualProcessor *CubicSDR::getWaterfallProcesor() {
|
||||
return &waterfallProcessor;
|
||||
}
|
||||
|
||||
VisualDataDistributor<DemodulatorThreadIQData> *CubicSDR::getSpectrumDistributor() {
|
||||
return &spectrumDistributor;
|
||||
}
|
||||
@ -289,6 +299,10 @@ DemodulatorThreadInputQueue* CubicSDR::getIQVisualQueue() {
|
||||
return pipeIQVisualData;
|
||||
}
|
||||
|
||||
DemodulatorThreadInputQueue* CubicSDR::getWaterfallVisualQueue() {
|
||||
return pipeWaterfallIQVisualData;
|
||||
}
|
||||
|
||||
DemodulatorMgr &CubicSDR::getDemodMgr() {
|
||||
return demodMgr;
|
||||
}
|
||||
|
@ -58,10 +58,12 @@ public:
|
||||
ScopeVisualProcessor *getScopeProcessor();
|
||||
SpectrumVisualProcessor *getSpectrumProcesor();
|
||||
SpectrumVisualProcessor *getDemodSpectrumProcesor();
|
||||
SpectrumVisualProcessor *getWaterfallProcesor();
|
||||
VisualDataDistributor<DemodulatorThreadIQData> *getSpectrumDistributor();
|
||||
|
||||
DemodulatorThreadOutputQueue* getAudioVisualQueue();
|
||||
DemodulatorThreadInputQueue* getIQVisualQueue();
|
||||
DemodulatorThreadInputQueue* getWaterfallVisualQueue();
|
||||
DemodulatorMgr &getDemodMgr();
|
||||
|
||||
void bindDemodulator(DemodulatorInstance *demod);
|
||||
@ -101,9 +103,11 @@ private:
|
||||
DemodulatorThreadOutputQueue* pipeAudioVisualData;
|
||||
DemodulatorThreadInputQueue* pipeDemodIQVisualData;
|
||||
DemodulatorThreadInputQueue* pipeSpectrumIQVisualData;
|
||||
DemodulatorThreadInputQueue* pipeWaterfallIQVisualData;
|
||||
|
||||
ScopeVisualProcessor scopeProcessor;
|
||||
SpectrumVisualProcessor spectrumProcessor;
|
||||
SpectrumVisualProcessor waterfallProcessor;
|
||||
SpectrumVisualProcessor demodSpectrumProcessor;
|
||||
|
||||
VisualDataDistributor<DemodulatorThreadIQData> spectrumDistributor;
|
||||
|
@ -33,3 +33,4 @@ const char filePathSeparator =
|
||||
#define DEFAULT_DEMOD_TYPE 1
|
||||
#define DEFAULT_DEMOD_BW 200000
|
||||
|
||||
#define DEFAULT_WATERFALL_LPS 30
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "ThreadQueue.h"
|
||||
|
||||
@ -37,6 +38,8 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
#define REBUFFER_GC_LIMIT 100
|
||||
|
||||
template<class BufferType = ReferenceCounter>
|
||||
class ReBuffer {
|
||||
|
||||
@ -44,11 +47,27 @@ public:
|
||||
BufferType *getBuffer() {
|
||||
BufferType* buf = NULL;
|
||||
for (outputBuffersI = outputBuffers.begin(); outputBuffersI != outputBuffers.end(); outputBuffersI++) {
|
||||
if ((*outputBuffersI)->getRefCount() <= 0) {
|
||||
return (*outputBuffersI);
|
||||
if (!buf && (*outputBuffersI)->getRefCount() <= 0) {
|
||||
buf = (*outputBuffersI);
|
||||
(*outputBuffersI)->setRefCount(0);
|
||||
} else if ((*outputBuffersI)->getRefCount() <= 0) {
|
||||
(*outputBuffersI)->decRefCount();
|
||||
}
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
if (outputBuffers.back()->getRefCount() < -REBUFFER_GC_LIMIT) {
|
||||
BufferType *ref = outputBuffers.back();
|
||||
outputBuffers.pop_back();
|
||||
delete ref;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
// if (outputBuffers.size() > 100) {
|
||||
// std::cout << "Buffer over 100.." << std::endl;
|
||||
// }
|
||||
|
||||
buf = new BufferType();
|
||||
outputBuffers.push_back(buf);
|
||||
|
||||
|
@ -94,7 +94,7 @@ void DemodulatorThread::run() {
|
||||
while (!terminated) {
|
||||
DemodulatorThreadPostIQData *inp;
|
||||
iqInputQueue->pop(inp);
|
||||
std::lock_guard < std::mutex > lock(inp->m_mutex);
|
||||
// std::lock_guard < std::mutex > lock(inp->m_mutex);
|
||||
|
||||
int bufSize = inp->data.size();
|
||||
|
||||
|
@ -58,18 +58,18 @@ void SpectrumPanel::drawPanelContents() {
|
||||
|
||||
if (points.size()) {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
float range = ceilValue-floorValue;
|
||||
float ranges[3][4] = { { 90.0, 5000.0, 10.0, 100.0 }, { 20.0, 150.0, 10.0, 10.0 }, { -20.0, 30.0, 10.0, 1.0 } };
|
||||
double range = ceilValue-floorValue;
|
||||
double ranges[3][4] = { { 90.0, 5000.0, 10.0, 100.0 }, { 20.0, 150.0, 10.0, 10.0 }, { -20.0, 30.0, 10.0, 1.0 } };
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float p = 0;
|
||||
float rangeMin = ranges[i][0];
|
||||
float rangeMax = ranges[i][1];
|
||||
float rangeTrans = ranges[i][2];
|
||||
float rangeStep = ranges[i][3];
|
||||
double p = 0;
|
||||
double rangeMin = ranges[i][0];
|
||||
double rangeMax = ranges[i][1];
|
||||
double rangeTrans = ranges[i][2];
|
||||
double rangeStep = ranges[i][3];
|
||||
|
||||
if (range >= rangeMin && range <= rangeMax) {
|
||||
float a = 1.0;
|
||||
double a = 1.0;
|
||||
|
||||
if (range <= rangeMin+rangeTrans) {
|
||||
a *= (range-rangeMin)/rangeTrans;
|
||||
@ -80,7 +80,7 @@ void SpectrumPanel::drawPanelContents() {
|
||||
|
||||
glColor4f(0.12, 0.12, 0.12, a);
|
||||
glBegin(GL_LINES);
|
||||
for (float l = floorValue; l<=ceilValue+rangeStep; l+=rangeStep) {
|
||||
for (double l = floorValue; l<=ceilValue+rangeStep; l+=rangeStep) {
|
||||
p += rangeStep/range;
|
||||
glVertex2f(0,p); glVertex2f(1,p);
|
||||
}
|
||||
@ -104,29 +104,34 @@ void SpectrumPanel::drawPanelContents() {
|
||||
float viewHeight = (float) vp[3];
|
||||
float viewWidth = (float) vp[2];
|
||||
|
||||
long long leftFreq = (float) freq - ((float) bandwidth / 2.0);
|
||||
long long rightFreq = leftFreq + (float) bandwidth;
|
||||
long long leftFreq = (double) freq - ((double) bandwidth / 2.0);
|
||||
long long rightFreq = leftFreq + (double) bandwidth;
|
||||
|
||||
long long firstMhz = (leftFreq / 1000000) * 1000000;
|
||||
long double mhzStart = ((long double) (firstMhz - leftFreq) / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||
|
||||
long double mhzStep = (100000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||
float mhzVisualStep = 0.1f;
|
||||
double mhzVisualStep = 0.1f;
|
||||
|
||||
if (mhzStep * 0.5 * viewWidth < 40) {
|
||||
mhzStep = (250000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||
mhzVisualStep = 0.25f;
|
||||
}
|
||||
|
||||
if (mhzStep * 0.5 * viewWidth > 400) {
|
||||
mhzStep = (10000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||
mhzVisualStep = 0.01f;
|
||||
}
|
||||
|
||||
|
||||
long double currentMhz = trunc(floor(firstMhz / 1000000.0));
|
||||
|
||||
std::stringstream label;
|
||||
label.precision(2);
|
||||
|
||||
float hPos = 1.0 - (16.0 / viewHeight);
|
||||
float lMhzPos = 1.0 - (5.0 / viewHeight);
|
||||
double hPos = 1.0 - (16.0 / viewHeight);
|
||||
double lMhzPos = 1.0 - (5.0 / viewHeight);
|
||||
|
||||
for (float m = -1.0 + mhzStart, mMax = 1.0 + ((mhzStart>0)?mhzStart:-mhzStart); m <= mMax; m += mhzStep) {
|
||||
for (double m = -1.0 + mhzStart, mMax = 1.0 + ((mhzStart>0)?mhzStart:-mhzStart); m <= mMax; m += mhzStep) {
|
||||
label << std::fixed << currentMhz;
|
||||
|
||||
double fractpart, intpart;
|
||||
|
@ -17,6 +17,7 @@ void ScopeVisualProcessor::process() {
|
||||
return;
|
||||
}
|
||||
|
||||
audioInputData->busy_update.lock();
|
||||
ScopeRenderData *renderData = outputBuffers.getBuffer();
|
||||
renderData->channels = audioInputData->channels;
|
||||
|
||||
@ -44,6 +45,8 @@ void ScopeVisualProcessor::process() {
|
||||
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak;
|
||||
}
|
||||
}
|
||||
|
||||
distribute(renderData);
|
||||
audioInputData->busy_update.unlock();
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), last
|
||||
|
||||
fft_ceil_ma = fft_ceil_maa = 100.0;
|
||||
fft_floor_ma = fft_floor_maa = 0.0;
|
||||
desiredInputSize = 0;
|
||||
fft_average_rate = 0.65;
|
||||
}
|
||||
|
||||
SpectrumVisualProcessor::~SpectrumVisualProcessor() {
|
||||
@ -28,6 +30,13 @@ void SpectrumVisualProcessor::setView(bool bView) {
|
||||
is_view.store(bView);
|
||||
}
|
||||
|
||||
void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) {
|
||||
this->fft_average_rate = fftAverageRate;
|
||||
}
|
||||
|
||||
float SpectrumVisualProcessor::getFFTAverageRate() {
|
||||
return this->fft_average_rate;
|
||||
}
|
||||
|
||||
void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) {
|
||||
centerFreq.store(centerFreq_in);
|
||||
@ -45,8 +54,13 @@ long SpectrumVisualProcessor::getBandwidth() {
|
||||
return bandwidth.load();
|
||||
}
|
||||
|
||||
int SpectrumVisualProcessor::getDesiredInputSize() {
|
||||
return desiredInputSize;
|
||||
}
|
||||
|
||||
void SpectrumVisualProcessor::setup(int fftSize_in) {
|
||||
fftSize = fftSize_in;
|
||||
desiredInputSize = fftSize;
|
||||
|
||||
if (fftwInput) {
|
||||
free(fftwInput);
|
||||
@ -83,6 +97,12 @@ void SpectrumVisualProcessor::process() {
|
||||
|
||||
input->pop(iqData);
|
||||
|
||||
if (!iqData) {
|
||||
return;
|
||||
}
|
||||
|
||||
iqData->busy_rw.lock();
|
||||
|
||||
std::vector<liquid_float_complex> *data = &iqData->data;
|
||||
|
||||
if (data && data->size()) {
|
||||
@ -96,6 +116,8 @@ void SpectrumVisualProcessor::process() {
|
||||
|
||||
if (is_view.load()) {
|
||||
if (!iqData->frequency || !iqData->sampleRate) {
|
||||
iqData->decRefCount();
|
||||
iqData->busy_rw.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -103,6 +125,8 @@ void SpectrumVisualProcessor::process() {
|
||||
|
||||
int desired_input_size = fftSize / resamplerRatio;
|
||||
|
||||
this->desiredInputSize = desired_input_size;
|
||||
|
||||
if (iqData->data.size() < desired_input_size) {
|
||||
// std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
|
||||
desired_input_size = iqData->data.size();
|
||||
@ -244,11 +268,11 @@ void SpectrumVisualProcessor::process() {
|
||||
|
||||
for (int i = 0, iMax = fftSize; i < iMax; i++) {
|
||||
if (is_view.load()) {
|
||||
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65;
|
||||
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65;
|
||||
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
|
||||
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
|
||||
} else {
|
||||
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65;
|
||||
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65;
|
||||
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
|
||||
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
|
||||
}
|
||||
|
||||
if (fft_result_maa[i] > fft_ceil) {
|
||||
@ -280,5 +304,8 @@ void SpectrumVisualProcessor::process() {
|
||||
|
||||
distribute(output);
|
||||
}
|
||||
|
||||
|
||||
iqData->decRefCount();
|
||||
iqData->busy_rw.unlock();
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "VisualProcessor.h"
|
||||
#include "DemodDefs.h"
|
||||
#include "fftw3.h"
|
||||
#include <cmath>
|
||||
|
||||
class SpectrumVisualData : public ReferenceCounter {
|
||||
public:
|
||||
@ -20,12 +21,17 @@ public:
|
||||
bool isView();
|
||||
void setView(bool bView);
|
||||
|
||||
void setFFTAverageRate(float fftAverageRate);
|
||||
float getFFTAverageRate();
|
||||
|
||||
void setCenterFrequency(long long centerFreq_in);
|
||||
long long getCenterFrequency();
|
||||
|
||||
void setBandwidth(long bandwidth_in);
|
||||
long getBandwidth();
|
||||
|
||||
int getDesiredInputSize();
|
||||
|
||||
void setup(int fftSize);
|
||||
|
||||
protected:
|
||||
@ -45,12 +51,13 @@ private:
|
||||
unsigned int lastDataSize;
|
||||
fftwf_plan fftw_plan;
|
||||
|
||||
float fft_ceil_ma, fft_ceil_maa;
|
||||
float fft_floor_ma, fft_floor_maa;
|
||||
double fft_ceil_ma, fft_ceil_maa;
|
||||
double fft_floor_ma, fft_floor_maa;
|
||||
float fft_average_rate;
|
||||
|
||||
std::vector<float> fft_result;
|
||||
std::vector<float> fft_result_ma;
|
||||
std::vector<float> fft_result_maa;
|
||||
std::vector<double> fft_result;
|
||||
std::vector<double> fft_result_ma;
|
||||
std::vector<double> fft_result_maa;
|
||||
|
||||
msresamp_crcf resampler;
|
||||
double resamplerRatio;
|
||||
@ -59,4 +66,74 @@ private:
|
||||
|
||||
std::vector<liquid_float_complex> shiftBuffer;
|
||||
std::vector<liquid_float_complex> resampleBuffer;
|
||||
int desiredInputSize;
|
||||
};
|
||||
|
||||
|
||||
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) {
|
||||
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;
|
||||
};
|
||||
|
@ -11,6 +11,28 @@ public:
|
||||
virtual ~VisualProcessor() {
|
||||
|
||||
}
|
||||
|
||||
bool isInputEmpty() {
|
||||
return input->empty();
|
||||
}
|
||||
|
||||
bool isOutputEmpty() {
|
||||
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
|
||||
if ((*outputs_i)->full()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isAnyOutputEmpty() {
|
||||
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
|
||||
if (!(*outputs_i)->full()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setInput(ThreadQueue<InputDataType *> *vis_in) {
|
||||
busy_update.lock();
|
||||
@ -60,24 +82,6 @@ protected:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isOutputEmpty() {
|
||||
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
|
||||
if (!(*outputs_i)->empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isAnyOutputEmpty() {
|
||||
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
|
||||
if ((*outputs_i)->empty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ThreadQueue<InputDataType *> *input;
|
||||
std::vector<ThreadQueue<OutputDataType *> *> outputs;
|
||||
@ -90,10 +94,10 @@ template<class OutputDataType = ReferenceCounter>
|
||||
class VisualDataDistributor : public VisualProcessor<OutputDataType, OutputDataType> {
|
||||
protected:
|
||||
void process() {
|
||||
if (!VisualProcessor<OutputDataType, OutputDataType>::isOutputEmpty()) {
|
||||
return;
|
||||
}
|
||||
while (!VisualProcessor<OutputDataType, OutputDataType>::input->empty()) {
|
||||
if (!VisualProcessor<OutputDataType, OutputDataType>::isAnyOutputEmpty()) {
|
||||
return;
|
||||
}
|
||||
OutputDataType *inp;
|
||||
VisualProcessor<OutputDataType, OutputDataType>::input->pop(inp);
|
||||
if (inp) {
|
||||
|
@ -76,24 +76,25 @@ void SDRPostThread::run() {
|
||||
|
||||
dcFilter = iirfilt_crcf_create_dc_blocker(0.0005);
|
||||
|
||||
DemodulatorThreadIQData *visualDataOut = new DemodulatorThreadIQData;
|
||||
|
||||
std::cout << "SDR post-processing thread started.." << std::endl;
|
||||
|
||||
iqDataInQueue = (SDRThreadIQDataQueue*)getInputQueue("IQDataInput");
|
||||
iqDataOutQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQDataOutput");
|
||||
iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOut");
|
||||
iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOutput");
|
||||
|
||||
ReBuffer<DemodulatorThreadIQData> buffers;
|
||||
std::vector<liquid_float_complex> fpData;
|
||||
std::vector<liquid_float_complex> dataOut;
|
||||
|
||||
|
||||
iqDataInQueue->set_max_num_items(0);
|
||||
|
||||
while (!terminated) {
|
||||
SDRThreadIQData *data_in;
|
||||
|
||||
|
||||
iqDataInQueue->pop(data_in);
|
||||
// std::lock_guard < std::mutex > lock(data_in->m_mutex);
|
||||
|
||||
// std::lock_guard < std::mutex > lock(data_in->m_mutex);
|
||||
int num_vis_samples = this->num_vis_samples;
|
||||
|
||||
if (data_in && data_in->data.size()) {
|
||||
int dataSize = data_in->data.size()/2;
|
||||
if (dataSize > fpData.capacity()) {
|
||||
@ -104,7 +105,7 @@ void SDRPostThread::run() {
|
||||
fpData.resize(dataSize);
|
||||
dataOut.resize(dataSize);
|
||||
}
|
||||
|
||||
|
||||
if (swapIQ) {
|
||||
for (int i = 0; i < dataSize; i++) {
|
||||
fpData[i] = _lut_swap[*((uint16_t*)&data_in->data[2*i])];
|
||||
@ -114,21 +115,16 @@ void SDRPostThread::run() {
|
||||
fpData[i] = _lut[*((uint16_t*)&data_in->data[2*i])];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]);
|
||||
|
||||
if (iqDataOutQueue != NULL) {
|
||||
DemodulatorThreadIQData *pipeDataOut = new DemodulatorThreadIQData;
|
||||
|
||||
pipeDataOut->frequency = data_in->frequency;
|
||||
pipeDataOut->sampleRate = data_in->sampleRate;
|
||||
pipeDataOut->data.assign(dataOut.begin(), dataOut.end());
|
||||
iqDataOutQueue->push(pipeDataOut);
|
||||
}
|
||||
|
||||
|
||||
if (iqVisualQueue != NULL && iqVisualQueue->empty()) {
|
||||
|
||||
visualDataOut->busy_rw.lock();
|
||||
DemodulatorThreadIQData *visualDataOut = visualDataBuffers.getBuffer();
|
||||
visualDataOut->setRefCount(1);
|
||||
|
||||
if (num_vis_samples > dataOut.size()) {
|
||||
num_vis_samples = dataOut.size();
|
||||
}
|
||||
|
||||
if (visualDataOut->data.size() < num_vis_samples) {
|
||||
if (visualDataOut->data.capacity() < num_vis_samples) {
|
||||
@ -136,84 +132,90 @@ void SDRPostThread::run() {
|
||||
}
|
||||
visualDataOut->data.resize(num_vis_samples);
|
||||
}
|
||||
|
||||
|
||||
visualDataOut->frequency = data_in->frequency;
|
||||
visualDataOut->sampleRate = data_in->sampleRate;
|
||||
visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples);
|
||||
|
||||
|
||||
iqVisualQueue->push(visualDataOut);
|
||||
|
||||
visualDataOut->busy_rw.unlock();
|
||||
}
|
||||
|
||||
busy_demod.lock();
|
||||
|
||||
|
||||
int activeDemods = 0;
|
||||
bool pushedData = false;
|
||||
|
||||
if (demodulators.size()) {
|
||||
|
||||
std::vector<DemodulatorInstance *>::iterator i;
|
||||
for (i = demodulators.begin(); i != demodulators.end(); i++) {
|
||||
DemodulatorInstance *demod = *i;
|
||||
|
||||
if (demodulators.size() || iqDataOutQueue != NULL) {
|
||||
std::vector<DemodulatorInstance *>::iterator demod_i;
|
||||
for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) {
|
||||
DemodulatorInstance *demod = *demod_i;
|
||||
if (demod->getFrequency() != data_in->frequency
|
||||
&& abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
||||
&& abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
||||
continue;
|
||||
}
|
||||
activeDemods++;
|
||||
}
|
||||
|
||||
if (demodulators.size()) {
|
||||
|
||||
DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
|
||||
|
||||
// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex);
|
||||
demodDataOut->frequency = data_in->frequency;
|
||||
demodDataOut->sampleRate = data_in->sampleRate;
|
||||
demodDataOut->setRefCount(activeDemods);
|
||||
demodDataOut->data.assign(dataOut.begin(), dataOut.end());
|
||||
|
||||
std::vector<DemodulatorInstance *>::iterator i;
|
||||
for (i = demodulators.begin(); i != demodulators.end(); i++) {
|
||||
DemodulatorInstance *demod = *i;
|
||||
DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe();
|
||||
|
||||
if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
||||
if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
|
||||
demod->setActive(false);
|
||||
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
|
||||
dummyDataOut->frequency = data_in->frequency;
|
||||
dummyDataOut->sampleRate = data_in->sampleRate;
|
||||
demodQueue->push(dummyDataOut);
|
||||
}
|
||||
|
||||
if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) {
|
||||
wxGetApp().setFrequency(demod->getFrequency());
|
||||
}
|
||||
} else if (!demod->isActive()) {
|
||||
demod->setActive(true);
|
||||
if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) {
|
||||
wxGetApp().getDemodMgr().setActiveDemodulator(demod);
|
||||
}
|
||||
|
||||
if (iqDataOutQueue != NULL) {
|
||||
activeDemods++;
|
||||
}
|
||||
|
||||
DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
|
||||
|
||||
// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex);
|
||||
demodDataOut->frequency = data_in->frequency;
|
||||
demodDataOut->sampleRate = data_in->sampleRate;
|
||||
demodDataOut->setRefCount(activeDemods);
|
||||
demodDataOut->data.assign(dataOut.begin(), dataOut.end());
|
||||
|
||||
for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) {
|
||||
DemodulatorInstance *demod = *demod_i;
|
||||
DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe();
|
||||
|
||||
if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
||||
if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
|
||||
demod->setActive(false);
|
||||
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
|
||||
dummyDataOut->frequency = data_in->frequency;
|
||||
dummyDataOut->sampleRate = data_in->sampleRate;
|
||||
demodQueue->push(dummyDataOut);
|
||||
}
|
||||
|
||||
if (!demod->isActive()) {
|
||||
continue;
|
||||
|
||||
if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) {
|
||||
wxGetApp().setFrequency(demod->getFrequency());
|
||||
}
|
||||
if (demod->isFollow()) {
|
||||
demod->setFollow(false);
|
||||
} else if (!demod->isActive()) {
|
||||
demod->setActive(true);
|
||||
if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) {
|
||||
wxGetApp().getDemodMgr().setActiveDemodulator(demod);
|
||||
}
|
||||
|
||||
demodQueue->push(demodDataOut);
|
||||
pushedData = true;
|
||||
}
|
||||
|
||||
if (!pushedData) {
|
||||
demodDataOut->setRefCount(0);
|
||||
|
||||
if (!demod->isActive()) {
|
||||
continue;
|
||||
}
|
||||
if (demod->isFollow()) {
|
||||
demod->setFollow(false);
|
||||
}
|
||||
|
||||
demodQueue->push(demodDataOut);
|
||||
pushedData = true;
|
||||
}
|
||||
|
||||
if (iqDataOutQueue != NULL) {
|
||||
if (!iqDataOutQueue->full()) {
|
||||
iqDataOutQueue->push(demodDataOut);
|
||||
pushedData = true;
|
||||
} else {
|
||||
demodDataOut->decRefCount();
|
||||
}
|
||||
}
|
||||
|
||||
if (!pushedData && iqDataOutQueue == NULL) {
|
||||
demodDataOut->setRefCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
busy_demod.unlock();
|
||||
}
|
||||
data_in->decRefCount();
|
||||
@ -226,7 +228,7 @@ void SDRPostThread::run() {
|
||||
iqVisualQueue->pop(visualDataDummy);
|
||||
}
|
||||
|
||||
delete visualDataOut;
|
||||
visualDataBuffers.purge();
|
||||
|
||||
std::cout << "SDR post-processing thread done." << std::endl;
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ protected:
|
||||
iirfilt_crcf dcFilter;
|
||||
int num_vis_samples;
|
||||
std::atomic_bool swapIQ;
|
||||
ReBuffer<DemodulatorThreadIQData> visualDataBuffers;
|
||||
|
||||
|
||||
private:
|
||||
std::vector<liquid_float_complex> _lut;
|
||||
|
@ -36,7 +36,11 @@ void initGLExtensions() {
|
||||
|
||||
std::cout << std::endl << "Supported GL Extensions: " << std::endl << extensions << std::endl << std::endl;
|
||||
|
||||
#ifdef __linux__
|
||||
const GLint interval = 2;
|
||||
#else
|
||||
const GLint interval = 1;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (GLExtSupported("WGL_EXT_swap_control")) {
|
||||
|
@ -25,7 +25,7 @@ EVT_ENTER_WINDOW(MeterCanvas::OnMouseEnterWindow)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
MeterCanvas::MeterCanvas(wxWindow *parent, int *attribList) :
|
||||
InteractiveCanvas(parent, attribList), level(0), level_max(1), inputValue(0), userInputValue(0) {
|
||||
InteractiveCanvas(parent, attribList), level(0), level_max(1), inputValue(0), userInputValue(0), showUserInput(true) {
|
||||
|
||||
glContext = new MeterContext(this, &wxGetApp().GetContext(this));
|
||||
}
|
||||
@ -58,6 +58,10 @@ float MeterCanvas::getInputValue() {
|
||||
return userInputValue;
|
||||
}
|
||||
|
||||
void MeterCanvas::setShowUserInput(bool showUserInput) {
|
||||
this->showUserInput = showUserInput;
|
||||
}
|
||||
|
||||
void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
@ -68,18 +72,23 @@ void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||
|
||||
glContext->DrawBegin();
|
||||
glContext->Draw(ThemeMgr::mgr.currentTheme->generalBackground.r, ThemeMgr::mgr.currentTheme->generalBackground.g, ThemeMgr::mgr.currentTheme->generalBackground.b, 0.5, 1.0);
|
||||
|
||||
if (mouseTracker.mouseInView()) {
|
||||
glContext->Draw(0.4, 0.4, 0.4, 0.5, mouseTracker.getMouseY());
|
||||
}
|
||||
glContext->Draw(ThemeMgr::mgr.currentTheme->meterLevel.r, ThemeMgr::mgr.currentTheme->meterLevel.g, ThemeMgr::mgr.currentTheme->meterLevel.b, 0.5, level / level_max);
|
||||
glContext->Draw(ThemeMgr::mgr.currentTheme->meterValue.r, ThemeMgr::mgr.currentTheme->meterValue.g, ThemeMgr::mgr.currentTheme->meterValue.b, 0.5, userInputValue / level_max);
|
||||
if (showUserInput) {
|
||||
glContext->Draw(ThemeMgr::mgr.currentTheme->meterValue.r, ThemeMgr::mgr.currentTheme->meterValue.g, ThemeMgr::mgr.currentTheme->meterValue.b, 0.5, userInputValue / level_max);
|
||||
}
|
||||
glContext->DrawEnd();
|
||||
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
void MeterCanvas::OnIdle(wxIdleEvent &event) {
|
||||
event.Skip();
|
||||
Refresh();
|
||||
event.RequestMore();
|
||||
}
|
||||
|
||||
void MeterCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
|
@ -26,6 +26,7 @@ public:
|
||||
void setInputValue(float slider_in);
|
||||
bool inputChanged();
|
||||
float getInputValue();
|
||||
void setShowUserInput(bool showUserInput);
|
||||
|
||||
void setHelpTip(std::string tip);
|
||||
|
||||
@ -48,6 +49,8 @@ private:
|
||||
float inputValue;
|
||||
float userInputValue;
|
||||
|
||||
bool showUserInput;
|
||||
|
||||
std::string helpTip;
|
||||
//
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
|
@ -72,7 +72,8 @@ void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
}
|
||||
|
||||
void ModeSelectorCanvas::OnIdle(wxIdleEvent &event) {
|
||||
event.Skip();
|
||||
Refresh();
|
||||
event.RequestMore();
|
||||
}
|
||||
|
||||
void ModeSelectorCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
|
@ -87,7 +87,8 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
}
|
||||
|
||||
void ScopeCanvas::OnIdle(wxIdleEvent &event) {
|
||||
event.Skip();
|
||||
Refresh();
|
||||
event.RequestMore();
|
||||
}
|
||||
|
||||
ScopeRenderDataQueue *ScopeCanvas::getInputQueue() {
|
||||
|
@ -32,7 +32,8 @@ SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
||||
glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this));
|
||||
|
||||
mouseTracker.setVertDragLock(true);
|
||||
|
||||
visualDataQueue.set_max_num_items(1);
|
||||
|
||||
SetCursor(wxCURSOR_SIZEWE);
|
||||
}
|
||||
|
||||
@ -84,7 +85,8 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
|
||||
|
||||
void SpectrumCanvas::OnIdle(wxIdleEvent &event) {
|
||||
event.Skip();
|
||||
Refresh();
|
||||
event.RequestMore();
|
||||
}
|
||||
|
||||
|
||||
|
@ -252,6 +252,10 @@ void TuningCanvas::OnIdle(wxIdleEvent &event) {
|
||||
dragging = false;
|
||||
}
|
||||
}
|
||||
if (mouseTracker.mouseInView() || changed()) {
|
||||
Refresh();
|
||||
}
|
||||
event.RequestMore();
|
||||
}
|
||||
|
||||
void TuningCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
|
@ -68,8 +68,32 @@ void WaterfallCanvas::attachSpectrumCanvas(SpectrumCanvas *canvas_in) {
|
||||
spectrumCanvas = canvas_in;
|
||||
}
|
||||
|
||||
void WaterfallCanvas::processInputQueue() {
|
||||
if (!glContext) {
|
||||
return;
|
||||
}
|
||||
glContext->SetCurrent(*this);
|
||||
|
||||
while (!visualDataQueue.empty()) {
|
||||
SpectrumVisualData *vData;
|
||||
|
||||
visualDataQueue.pop(vData);
|
||||
|
||||
if (vData) {
|
||||
waterfallPanel.setPoints(vData->spectrum_points);
|
||||
waterfallPanel.step();
|
||||
vData->decRefCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
// event.Skip();
|
||||
}
|
||||
|
||||
void WaterfallCanvas::DoPaint() {
|
||||
wxClientDC dc(this);
|
||||
// wxPaintDC dc(this);
|
||||
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
long double currentZoom = zoom;
|
||||
@ -90,8 +114,8 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
centerFreq = getCenterFrequency();
|
||||
bw = getBandwidth();
|
||||
bw = (long long) ceil((long double) bw * currentZoom);
|
||||
if (bw < 100000) {
|
||||
bw = 100000;
|
||||
if (bw < 30000) {
|
||||
bw = 30000;
|
||||
}
|
||||
if (mouseTracker.mouseInView()) {
|
||||
long long mfreqA = getFrequencyAt(mouseTracker.getMouseX());
|
||||
@ -139,18 +163,6 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
glContext->SetCurrent(*this);
|
||||
initGLExtensions();
|
||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||
|
||||
if (!visualDataQueue.empty()) {
|
||||
SpectrumVisualData *vData;
|
||||
|
||||
visualDataQueue.pop(vData);
|
||||
|
||||
if (vData) {
|
||||
waterfallPanel.setPoints(vData->spectrum_points);
|
||||
waterfallPanel.step();
|
||||
vData->decRefCount();
|
||||
}
|
||||
}
|
||||
|
||||
glContext->BeginDraw(0,0,0);
|
||||
|
||||
@ -347,6 +359,8 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
||||
}
|
||||
}
|
||||
void WaterfallCanvas::OnIdle(wxIdleEvent &event) {
|
||||
// Refresh();
|
||||
// event.RequestMore();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,9 @@ public:
|
||||
DragState getNextDragState();
|
||||
|
||||
void attachSpectrumCanvas(SpectrumCanvas *canvas_in);
|
||||
void processInputQueue();
|
||||
SpectrumVisualDataQueue *getVisualDataQueue();
|
||||
void DoPaint();
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
|
Loading…
Reference in New Issue
Block a user