mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2026-06-03 06:24:49 -04:00
Merge pull request #126 from cjcliffe/ui_visuals_to_panels
Refactoring, clean-up, GLPanels
This commit is contained in:
+64
-10
@@ -35,10 +35,11 @@ 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) {
|
||||
wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL), frame_timer(this, FRAME_TIMER_ID) {
|
||||
|
||||
#ifdef __linux__
|
||||
SetIcon(wxICON(cubicsdr));
|
||||
@@ -64,10 +65,11 @@ AppFrame::AppFrame() :
|
||||
|
||||
// demodTray->AddSpacer(2);
|
||||
|
||||
wxGetApp().getDemodSpectrumProcesor()->setup(1024);
|
||||
demodSpectrumCanvas = new SpectrumCanvas(this, attribList);
|
||||
demodSpectrumCanvas->setup(1024);
|
||||
demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000);
|
||||
demodVisuals->Add(demodSpectrumCanvas, 3, wxEXPAND | wxALL, 0);
|
||||
wxGetApp().getDemodSpectrumProcesor()->attachOutput(demodSpectrumCanvas->getVisualDataQueue());
|
||||
|
||||
demodVisuals->AddSpacer(1);
|
||||
|
||||
@@ -77,6 +79,7 @@ AppFrame::AppFrame() :
|
||||
demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas);
|
||||
demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas);
|
||||
demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0);
|
||||
wxGetApp().getDemodSpectrumProcesor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue());
|
||||
|
||||
demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);
|
||||
|
||||
@@ -91,6 +94,7 @@ AppFrame::AppFrame() :
|
||||
|
||||
scopeCanvas = new ScopeCanvas(this, attribList);
|
||||
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
|
||||
wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue());
|
||||
|
||||
demodScopeTray->AddSpacer(1);
|
||||
|
||||
@@ -109,17 +113,25 @@ AppFrame::AppFrame() :
|
||||
|
||||
vbox->Add(demodTray, 12, wxEXPAND | wxALL, 0);
|
||||
vbox->AddSpacer(1);
|
||||
|
||||
wxGetApp().getSpectrumProcesor()->setup(2048);
|
||||
spectrumCanvas = new SpectrumCanvas(this, attribList);
|
||||
spectrumCanvas->setup(2048);
|
||||
vbox->Add(spectrumCanvas, 5, wxEXPAND | wxALL, 0);
|
||||
vbox->AddSpacer(1);
|
||||
wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue());
|
||||
|
||||
waterfallCanvas = new WaterfallCanvas(this, attribList);
|
||||
waterfallCanvas->setup(2048, 512);
|
||||
waterfallCanvas->attachSpectrumCanvas(spectrumCanvas);
|
||||
waterfallCanvas->attachWaterfallCanvas(demodWaterfallCanvas);
|
||||
spectrumCanvas->attachWaterfallCanvas(waterfallCanvas);
|
||||
vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0);
|
||||
|
||||
wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue());
|
||||
/*
|
||||
vbox->AddSpacer(1);
|
||||
testCanvas = new UITestCanvas(this, attribList);
|
||||
vbox->Add(testCanvas, 20, wxEXPAND | wxALL, 0);
|
||||
// */
|
||||
|
||||
this->SetSizer(vbox);
|
||||
|
||||
// waterfallCanvas->SetFocusFromKbd();
|
||||
@@ -339,6 +351,8 @@ 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);
|
||||
@@ -442,6 +456,11 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
|
||||
ThemeMgr::mgr.setTheme(COLOR_THEME_RADAR);
|
||||
}
|
||||
|
||||
if (event.GetId() >= wxID_THEME_DEFAULT && event.GetId() <= wxID_THEME_RADAR) {
|
||||
demodTuner->Refresh();
|
||||
demodModeSelector->Refresh();
|
||||
}
|
||||
|
||||
switch (event.GetId()) {
|
||||
case wxID_BANDWIDTH_250K:
|
||||
wxGetApp().setSampleRate(250000);
|
||||
@@ -550,12 +569,10 @@ void AppFrame::OnThread(wxCommandEvent& event) {
|
||||
}
|
||||
|
||||
void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
bool work_done = false;
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
//#ifdef __APPLE__
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(4));
|
||||
// std::this_thread::yield();
|
||||
//#endif
|
||||
void AppFrame::OnTimer(wxTimerEvent& event) {
|
||||
|
||||
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
|
||||
@@ -667,7 +684,44 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
}
|
||||
|
||||
scopeCanvas->setPPMMode(demodTuner->isAltDown());
|
||||
|
||||
wxGetApp().getScopeProcessor()->run();
|
||||
wxGetApp().getSpectrumDistributor()->run();
|
||||
|
||||
SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor();
|
||||
|
||||
proc->setView(waterfallCanvas->getViewState());
|
||||
proc->setBandwidth(waterfallCanvas->getBandwidth());
|
||||
proc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
|
||||
|
||||
proc->run();
|
||||
|
||||
SpectrumVisualProcessor *dproc = wxGetApp().getDemodSpectrumProcesor();
|
||||
|
||||
dproc->setView(demodWaterfallCanvas->getViewState());
|
||||
dproc->setBandwidth(demodWaterfallCanvas->getBandwidth());
|
||||
dproc->setCenterFrequency(demodWaterfallCanvas->getCenterFrequency());
|
||||
|
||||
dproc->run();
|
||||
|
||||
scopeCanvas->Refresh();
|
||||
|
||||
waterfallCanvas->Refresh();
|
||||
spectrumCanvas->Refresh();
|
||||
|
||||
demodWaterfallCanvas->Refresh();
|
||||
demodSpectrumCanvas->Refresh();
|
||||
|
||||
demodSignalMeter->Refresh();
|
||||
demodGainMeter->Refresh();
|
||||
|
||||
if (demodTuner->getMouseTracker()->mouseInView() || demodTuner->changed()) {
|
||||
demodTuner->Refresh();
|
||||
}
|
||||
if (demodModeSelector->getMouseTracker()->mouseInView()) {
|
||||
demodModeSelector->Refresh();
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
+6
-2
@@ -9,6 +9,7 @@
|
||||
#include "MeterCanvas.h"
|
||||
#include "TuningCanvas.h"
|
||||
#include "ModeSelectorCanvas.h"
|
||||
#include "UITestCanvas.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -49,7 +50,7 @@
|
||||
#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 {
|
||||
@@ -68,6 +69,7 @@ private:
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnNewWindow(wxCommandEvent& event);
|
||||
void OnIdle(wxIdleEvent& event);
|
||||
void OnTimer(wxTimerEvent& event);
|
||||
|
||||
ScopeCanvas *scopeCanvas;
|
||||
SpectrumCanvas *spectrumCanvas;
|
||||
@@ -78,6 +80,7 @@ private:
|
||||
MeterCanvas *demodSignalMeter;
|
||||
MeterCanvas *demodGainMeter;
|
||||
TuningCanvas *demodTuner;
|
||||
UITestCanvas *testCanvas;
|
||||
|
||||
DemodulatorInstance *activeDemodulator;
|
||||
|
||||
@@ -91,6 +94,7 @@ private:
|
||||
wxMenuItem *iqSwapMenuItem;
|
||||
|
||||
std::string currentSessionFile;
|
||||
|
||||
wxTimer frame_timer;
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
+66
-24
@@ -21,6 +21,12 @@
|
||||
|
||||
IMPLEMENT_APP(CubicSDR)
|
||||
|
||||
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) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool CubicSDR::OnInit() {
|
||||
#ifdef _OSX_APP_
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
@@ -45,22 +51,41 @@ bool CubicSDR::OnInit() {
|
||||
ppm = 0;
|
||||
directSamplingMode = 0;
|
||||
|
||||
audioVisualQueue = new DemodulatorThreadOutputQueue();
|
||||
audioVisualQueue->set_max_num_items(1);
|
||||
// Visual Data
|
||||
pipeIQVisualData = new DemodulatorThreadInputQueue();
|
||||
pipeIQVisualData->set_max_num_items(1);
|
||||
|
||||
threadCmdQueueSDR = new SDRThreadCommandQueue;
|
||||
sdrThread = new SDRThread(threadCmdQueueSDR);
|
||||
spectrumDistributor.setInput(pipeIQVisualData);
|
||||
|
||||
pipeDemodIQVisualData = new DemodulatorThreadInputQueue();
|
||||
pipeIQVisualData->set_max_num_items(1);
|
||||
|
||||
pipeSpectrumIQVisualData = new DemodulatorThreadInputQueue();
|
||||
pipeIQVisualData->set_max_num_items(1);
|
||||
|
||||
spectrumDistributor.attachOutput(pipeDemodIQVisualData);
|
||||
spectrumDistributor.attachOutput(pipeSpectrumIQVisualData);
|
||||
|
||||
demodSpectrumProcessor.setInput(pipeDemodIQVisualData);
|
||||
spectrumProcessor.setInput(pipeSpectrumIQVisualData);
|
||||
|
||||
pipeAudioVisualData = new DemodulatorThreadOutputQueue();
|
||||
pipeAudioVisualData->set_max_num_items(1);
|
||||
|
||||
scopeProcessor.setInput(pipeAudioVisualData);
|
||||
|
||||
// I/Q Data
|
||||
pipeSDRIQData = new SDRThreadIQDataQueue;
|
||||
pipeSDRCommand = new SDRThreadCommandQueue();
|
||||
|
||||
sdrThread = new SDRThread();
|
||||
sdrThread->setInputQueue("SDRCommandQueue",pipeSDRCommand);
|
||||
sdrThread->setOutputQueue("IQDataOutput",pipeSDRIQData);
|
||||
|
||||
sdrPostThread = new SDRPostThread();
|
||||
sdrPostThread->setNumVisSamples(16384 * 2);
|
||||
|
||||
iqPostDataQueue = new SDRThreadIQDataQueue;
|
||||
iqVisualQueue = new DemodulatorThreadInputQueue;
|
||||
iqVisualQueue->set_max_num_items(1);
|
||||
|
||||
sdrThread->setIQDataOutQueue(iqPostDataQueue);
|
||||
sdrPostThread->setIQDataInQueue(iqPostDataQueue);
|
||||
sdrPostThread->setIQVisualQueue(iqVisualQueue);
|
||||
sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData);
|
||||
sdrPostThread->setOutputQueue("IQVisualDataOut", pipeIQVisualData);
|
||||
|
||||
std::vector<SDRDeviceInfo *>::iterator devs_i;
|
||||
|
||||
@@ -144,11 +169,11 @@ int CubicSDR::OnExit() {
|
||||
delete sdrPostThread;
|
||||
delete t_PostSDR;
|
||||
|
||||
delete threadCmdQueueSDR;
|
||||
delete pipeSDRCommand;
|
||||
|
||||
delete iqVisualQueue;
|
||||
delete audioVisualQueue;
|
||||
delete iqPostDataQueue;
|
||||
delete pipeIQVisualData;
|
||||
delete pipeAudioVisualData;
|
||||
delete pipeSDRIQData;
|
||||
|
||||
delete m_glContext;
|
||||
|
||||
@@ -194,7 +219,7 @@ void CubicSDR::setFrequency(long long freq) {
|
||||
frequency = freq;
|
||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_TUNE);
|
||||
command.llong_value = freq;
|
||||
threadCmdQueueSDR->push(command);
|
||||
pipeSDRCommand->push(command);
|
||||
}
|
||||
|
||||
long long CubicSDR::getOffset() {
|
||||
@@ -205,7 +230,7 @@ void CubicSDR::setOffset(long long ofs) {
|
||||
offset = ofs;
|
||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_OFFSET);
|
||||
command.llong_value = ofs;
|
||||
threadCmdQueueSDR->push(command);
|
||||
pipeSDRCommand->push(command);
|
||||
|
||||
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||
config.getDevice(dev->getDeviceId())->setOffset(ofs);
|
||||
@@ -215,7 +240,7 @@ void CubicSDR::setDirectSampling(int mode) {
|
||||
directSamplingMode = mode;
|
||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DIRECT_SAMPLING);
|
||||
command.llong_value = mode;
|
||||
threadCmdQueueSDR->push(command);
|
||||
pipeSDRCommand->push(command);
|
||||
|
||||
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||
config.getDevice(dev->getDeviceId())->setDirectSampling(mode);
|
||||
@@ -239,12 +264,29 @@ long long CubicSDR::getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
ScopeVisualProcessor *CubicSDR::getScopeProcessor() {
|
||||
return &scopeProcessor;
|
||||
}
|
||||
|
||||
SpectrumVisualProcessor *CubicSDR::getSpectrumProcesor() {
|
||||
return &spectrumProcessor;
|
||||
}
|
||||
|
||||
SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcesor() {
|
||||
return &demodSpectrumProcessor;
|
||||
}
|
||||
|
||||
VisualDataDistributor<DemodulatorThreadIQData> *CubicSDR::getSpectrumDistributor() {
|
||||
return &spectrumDistributor;
|
||||
}
|
||||
|
||||
|
||||
DemodulatorThreadOutputQueue* CubicSDR::getAudioVisualQueue() {
|
||||
return audioVisualQueue;
|
||||
return pipeAudioVisualData;
|
||||
}
|
||||
|
||||
DemodulatorThreadInputQueue* CubicSDR::getIQVisualQueue() {
|
||||
return iqVisualQueue;
|
||||
return pipeIQVisualData;
|
||||
}
|
||||
|
||||
DemodulatorMgr &CubicSDR::getDemodMgr() {
|
||||
@@ -262,7 +304,7 @@ void CubicSDR::setSampleRate(long long rate_in) {
|
||||
sampleRate = rate_in;
|
||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_SAMPLERATE);
|
||||
command.llong_value = rate_in;
|
||||
threadCmdQueueSDR->push(command);
|
||||
pipeSDRCommand->push(command);
|
||||
setFrequency(frequency);
|
||||
}
|
||||
|
||||
@@ -286,7 +328,7 @@ void CubicSDR::setDevice(int deviceId) {
|
||||
sdrThread->setDeviceId(deviceId);
|
||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE);
|
||||
command.llong_value = deviceId;
|
||||
threadCmdQueueSDR->push(command);
|
||||
pipeSDRCommand->push(command);
|
||||
|
||||
SDRDeviceInfo *dev = (*getDevices())[deviceId];
|
||||
DeviceConfig *devConfig = config.getDevice(dev->getDeviceId());
|
||||
@@ -317,7 +359,7 @@ void CubicSDR::setPPM(int ppm_in) {
|
||||
|
||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_PPM);
|
||||
command.llong_value = ppm;
|
||||
threadCmdQueueSDR->push(command);
|
||||
pipeSDRCommand->push(command);
|
||||
|
||||
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||
|
||||
|
||||
+21
-8
@@ -17,16 +17,16 @@
|
||||
#include "AppConfig.h"
|
||||
#include "AppFrame.h"
|
||||
|
||||
#include "ScopeVisualProcessor.h"
|
||||
#include "SpectrumVisualProcessor.h"
|
||||
|
||||
#include <wx/cmdline.h>
|
||||
|
||||
#define NUM_DEMODULATORS 1
|
||||
|
||||
class CubicSDR: public wxApp {
|
||||
public:
|
||||
CubicSDR() :
|
||||
appframe(NULL), m_glContext(NULL), frequency(0), sdrThread(NULL), sdrPostThread(NULL), threadCmdQueueSDR(NULL), iqVisualQueue(NULL), iqPostDataQueue(NULL), audioVisualQueue(NULL), t_SDR(NULL), t_PostSDR(NULL), sampleRate(DEFAULT_SAMPLE_RATE), offset(0), snap(1), directSamplingMode(0), ppm(0) {
|
||||
|
||||
}
|
||||
CubicSDR();
|
||||
|
||||
PrimaryGLContext &GetContext(wxGLCanvas *canvas);
|
||||
|
||||
@@ -55,6 +55,11 @@ public:
|
||||
void setDevice(int deviceId);
|
||||
int getDevice();
|
||||
|
||||
ScopeVisualProcessor *getScopeProcessor();
|
||||
SpectrumVisualProcessor *getSpectrumProcesor();
|
||||
SpectrumVisualProcessor *getDemodSpectrumProcesor();
|
||||
VisualDataDistributor<DemodulatorThreadIQData> *getSpectrumDistributor();
|
||||
|
||||
DemodulatorThreadOutputQueue* getAudioVisualQueue();
|
||||
DemodulatorThreadInputQueue* getIQVisualQueue();
|
||||
DemodulatorMgr &getDemodMgr();
|
||||
@@ -90,11 +95,19 @@ private:
|
||||
SDRThread *sdrThread;
|
||||
SDRPostThread *sdrPostThread;
|
||||
|
||||
SDRThreadCommandQueue* threadCmdQueueSDR;
|
||||
SDRThreadIQDataQueue* iqPostDataQueue;
|
||||
DemodulatorThreadInputQueue* iqVisualQueue;
|
||||
DemodulatorThreadOutputQueue* audioVisualQueue;
|
||||
SDRThreadCommandQueue* pipeSDRCommand;
|
||||
SDRThreadIQDataQueue* pipeSDRIQData;
|
||||
DemodulatorThreadInputQueue* pipeIQVisualData;
|
||||
DemodulatorThreadOutputQueue* pipeAudioVisualData;
|
||||
DemodulatorThreadInputQueue* pipeDemodIQVisualData;
|
||||
DemodulatorThreadInputQueue* pipeSpectrumIQVisualData;
|
||||
|
||||
ScopeVisualProcessor scopeProcessor;
|
||||
SpectrumVisualProcessor spectrumProcessor;
|
||||
SpectrumVisualProcessor demodSpectrumProcessor;
|
||||
|
||||
VisualDataDistributor<DemodulatorThreadIQData> spectrumDistributor;
|
||||
|
||||
std::thread *t_SDR;
|
||||
std::thread *t_PostSDR;
|
||||
};
|
||||
|
||||
@@ -33,24 +33,3 @@ const char filePathSeparator =
|
||||
#define DEFAULT_DEMOD_TYPE 1
|
||||
#define DEFAULT_DEMOD_BW 200000
|
||||
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
class ReferenceCounter {
|
||||
public:
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
void setRefCount(int rc) {
|
||||
refCount.store(rc);
|
||||
}
|
||||
|
||||
void decRefCount() {
|
||||
refCount.store(refCount.load()-1);
|
||||
}
|
||||
|
||||
int getRefCount() {
|
||||
return refCount.load();
|
||||
}
|
||||
protected:
|
||||
std::atomic_int refCount;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "IOThread.h"
|
||||
|
||||
IOThread::IOThread() {
|
||||
terminated.store(false);
|
||||
}
|
||||
|
||||
IOThread::~IOThread() {
|
||||
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
void *IOThread::threadMain() {
|
||||
terminated.store(false);
|
||||
run();
|
||||
return this;
|
||||
};
|
||||
|
||||
void *IOThread::pthread_helper(void *context) {
|
||||
return ((IOThread *) context)->threadMain();
|
||||
};
|
||||
#else
|
||||
void IOThread::threadMain() {
|
||||
terminated.store(false);
|
||||
run();
|
||||
};
|
||||
#endif
|
||||
|
||||
void IOThread::setup() {
|
||||
|
||||
};
|
||||
|
||||
void IOThread::run() {
|
||||
|
||||
};
|
||||
|
||||
void IOThread::terminate() {
|
||||
terminated.store(true);
|
||||
};
|
||||
|
||||
void IOThread::onBindOutput(std::string name, ThreadQueueBase* threadQueue) {
|
||||
|
||||
};
|
||||
|
||||
void IOThread::onBindInput(std::string name, ThreadQueueBase* threadQueue) {
|
||||
|
||||
};
|
||||
|
||||
void IOThread::setInputQueue(std::string qname, ThreadQueueBase *threadQueue) {
|
||||
input_queues[qname] = threadQueue;
|
||||
this->onBindInput(qname, threadQueue);
|
||||
};
|
||||
|
||||
void *IOThread::getInputQueue(std::string qname) {
|
||||
return input_queues[qname];
|
||||
};
|
||||
|
||||
void IOThread::setOutputQueue(std::string qname, ThreadQueueBase *threadQueue) {
|
||||
output_queues[qname] = threadQueue;
|
||||
this->onBindOutput(qname, threadQueue);
|
||||
};
|
||||
|
||||
void *IOThread::getOutputQueue(std::string qname) {
|
||||
return output_queues[qname];
|
||||
};
|
||||
|
||||
bool IOThread::isTerminated() {
|
||||
return terminated.load();
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "ThreadQueue.h"
|
||||
|
||||
struct map_string_less : public std::binary_function<std::string,std::string,bool>
|
||||
{
|
||||
bool operator()(const std::string& a,const std::string& b) const
|
||||
{
|
||||
return a.compare(b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ReferenceCounter {
|
||||
public:
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
void setRefCount(int rc) {
|
||||
refCount.store(rc);
|
||||
}
|
||||
|
||||
void decRefCount() {
|
||||
refCount.store(refCount.load()-1);
|
||||
}
|
||||
|
||||
int getRefCount() {
|
||||
return refCount.load();
|
||||
}
|
||||
protected:
|
||||
std::atomic_int refCount;
|
||||
};
|
||||
|
||||
|
||||
template<class BufferType = ReferenceCounter>
|
||||
class ReBuffer {
|
||||
|
||||
public:
|
||||
BufferType *getBuffer() {
|
||||
BufferType* buf = NULL;
|
||||
for (outputBuffersI = outputBuffers.begin(); outputBuffersI != outputBuffers.end(); outputBuffersI++) {
|
||||
if ((*outputBuffersI)->getRefCount() <= 0) {
|
||||
return (*outputBuffersI);
|
||||
}
|
||||
}
|
||||
|
||||
buf = new BufferType();
|
||||
outputBuffers.push_back(buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void purge() {
|
||||
while (!outputBuffers.empty()) {
|
||||
BufferType *ref = outputBuffers.front();
|
||||
outputBuffers.pop_front();
|
||||
delete ref;
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::deque<BufferType*> outputBuffers;
|
||||
typename std::deque<BufferType*>::iterator outputBuffersI;
|
||||
};
|
||||
|
||||
|
||||
class IOThread {
|
||||
public:
|
||||
IOThread();
|
||||
virtual ~IOThread();
|
||||
|
||||
static void *pthread_helper(void *context);
|
||||
|
||||
#ifdef __APPLE__
|
||||
virtual void *threadMain();
|
||||
#else
|
||||
virtual void threadMain();
|
||||
#endif
|
||||
|
||||
virtual void setup();
|
||||
virtual void run();
|
||||
virtual void terminate();
|
||||
bool isTerminated();
|
||||
virtual void onBindOutput(std::string name, ThreadQueueBase* threadQueue);
|
||||
virtual void onBindInput(std::string name, ThreadQueueBase* threadQueue);
|
||||
|
||||
void setInputQueue(std::string qname, ThreadQueueBase *threadQueue);
|
||||
void *getInputQueue(std::string qname);
|
||||
void setOutputQueue(std::string qname, ThreadQueueBase *threadQueue);
|
||||
void *getOutputQueue(std::string qname);
|
||||
|
||||
|
||||
protected:
|
||||
std::map<std::string, ThreadQueueBase *, map_string_less> input_queues;
|
||||
std::map<std::string, ThreadQueueBase *, map_string_less> output_queues;
|
||||
std::atomic_bool terminated;
|
||||
};
|
||||
+18
-18
@@ -11,15 +11,14 @@ std::map<int, AudioThread *> AudioThread::deviceController;
|
||||
std::map<int, int> AudioThread::deviceSampleRate;
|
||||
std::map<int, std::thread *> AudioThread::deviceThread;
|
||||
|
||||
AudioThread::AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||
currentInput(NULL), inputQueue(inputQueue), gain(
|
||||
1.0), threadQueueNotify(threadQueueNotify), sampleRate(0), nBufferFrames(1024) {
|
||||
AudioThread::AudioThread() : IOThread(),
|
||||
currentInput(NULL), inputQueue(NULL), nBufferFrames(1024), threadQueueNotify(NULL), sampleRate(0) {
|
||||
|
||||
audioQueuePtr.store(0);
|
||||
underflowCount.store(0);
|
||||
terminated.store(false);
|
||||
active.store(false);
|
||||
outputDevice.store(-1);
|
||||
gain.store(1.0);
|
||||
|
||||
boundThreads = new std::vector<AudioThread *>;
|
||||
}
|
||||
@@ -56,7 +55,7 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
||||
float *out = (float*) outputBuffer;
|
||||
memset(out, 0, nBufferFrames * 2 * sizeof(float));
|
||||
|
||||
if (src->terminated) {
|
||||
if (src->isTerminated()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -72,17 +71,17 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
||||
|
||||
for (int j = 0; j < src->boundThreads.load()->size(); j++) {
|
||||
AudioThread *srcmix = (*(src->boundThreads.load()))[j];
|
||||
if (srcmix->terminated || !srcmix->inputQueue || srcmix->inputQueue->empty() || !srcmix->isActive()) {
|
||||
if (srcmix->isTerminated() || !srcmix->inputQueue || srcmix->inputQueue->empty() || !srcmix->isActive()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!srcmix->currentInput) {
|
||||
srcmix->audioQueuePtr = 0;
|
||||
if (srcmix->terminated || srcmix->inputQueue->empty()) {
|
||||
if (srcmix->isTerminated() || srcmix->inputQueue->empty()) {
|
||||
continue;
|
||||
}
|
||||
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||
if (srcmix->terminated) {
|
||||
if (srcmix->isTerminated()) {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
@@ -117,11 +116,11 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
||||
srcmix->currentInput->decRefCount();
|
||||
srcmix->currentInput = NULL;
|
||||
}
|
||||
if (srcmix->terminated || srcmix->inputQueue->empty()) {
|
||||
if (srcmix->isTerminated() || srcmix->inputQueue->empty()) {
|
||||
continue;
|
||||
}
|
||||
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||
if (srcmix->terminated) {
|
||||
if (srcmix->isTerminated()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -138,11 +137,11 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
||||
srcmix->currentInput->decRefCount();
|
||||
srcmix->currentInput = NULL;
|
||||
}
|
||||
if (srcmix->terminated || srcmix->inputQueue->empty()) {
|
||||
if (srcmix->isTerminated() || srcmix->inputQueue->empty()) {
|
||||
break;
|
||||
}
|
||||
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||
if (srcmix->terminated) {
|
||||
if (srcmix->isTerminated()) {
|
||||
break;
|
||||
}
|
||||
float srcPeak = srcmix->currentInput->peak * srcmix->gain;
|
||||
@@ -165,11 +164,11 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
||||
srcmix->currentInput->decRefCount();
|
||||
srcmix->currentInput = NULL;
|
||||
}
|
||||
if (srcmix->terminated || srcmix->inputQueue->empty()) {
|
||||
if (srcmix->isTerminated() || srcmix->inputQueue->empty()) {
|
||||
break;
|
||||
}
|
||||
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||
if (srcmix->terminated) {
|
||||
if (srcmix->isTerminated()) {
|
||||
break;
|
||||
}
|
||||
float srcPeak = srcmix->currentInput->peak * srcmix->gain;
|
||||
@@ -317,7 +316,7 @@ void AudioThread::setupDevice(int deviceId) {
|
||||
}
|
||||
|
||||
if (deviceController.find(parameters.deviceId) == deviceController.end()) {
|
||||
deviceController[parameters.deviceId] = new AudioThread(NULL, NULL);
|
||||
deviceController[parameters.deviceId] = new AudioThread();
|
||||
|
||||
deviceController[parameters.deviceId]->setInitOutputDevice(parameters.deviceId, sampleRate);
|
||||
deviceController[parameters.deviceId]->bindThread(this);
|
||||
@@ -359,7 +358,7 @@ void AudioThread::setInitOutputDevice(int deviceId, int sampleRate) {
|
||||
this->sampleRate = sampleRate;
|
||||
}
|
||||
|
||||
void AudioThread::threadMain() {
|
||||
void AudioThread::run() {
|
||||
#ifdef __APPLE__
|
||||
pthread_t tID = pthread_self(); // ID of this thread
|
||||
int priority = sched_get_priority_max( SCHED_RR) - 1;
|
||||
@@ -378,8 +377,9 @@ void AudioThread::threadMain() {
|
||||
|
||||
std::cout << "Audio thread started." << std::endl;
|
||||
|
||||
terminated = false;
|
||||
|
||||
inputQueue = (AudioThreadInputQueue *)getInputQueue("AudioDataInput");
|
||||
threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue");
|
||||
|
||||
while (!terminated) {
|
||||
AudioThreadCommand command;
|
||||
cmdQueue.pop(command);
|
||||
|
||||
@@ -47,20 +47,18 @@ public:
|
||||
typedef ThreadQueue<AudioThreadInput *> AudioThreadInputQueue;
|
||||
typedef ThreadQueue<AudioThreadCommand> AudioThreadCommandQueue;
|
||||
|
||||
class AudioThread {
|
||||
class AudioThread : public IOThread {
|
||||
public:
|
||||
|
||||
AudioThreadInput *currentInput;
|
||||
AudioThreadInputQueue *inputQueue;
|
||||
std::atomic_uint audioQueuePtr;
|
||||
std::atomic_uint underflowCount;
|
||||
std::atomic_bool terminated;
|
||||
std::atomic_bool initialized;
|
||||
std::atomic_bool active;
|
||||
std::atomic_int outputDevice;
|
||||
std::atomic<float> gain;
|
||||
|
||||
AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify);
|
||||
AudioThread();
|
||||
~AudioThread();
|
||||
|
||||
static void enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs);
|
||||
@@ -70,7 +68,7 @@ public:
|
||||
int getOutputDevice();
|
||||
void setSampleRate(int sampleRate);
|
||||
int getSampleRate();
|
||||
void threadMain();
|
||||
void run();
|
||||
void terminate();
|
||||
|
||||
bool isActive();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define DEMOD_TYPE_DSB 5
|
||||
#define DEMOD_TYPE_RAW 6
|
||||
|
||||
#include "IOThread.h"
|
||||
|
||||
class DemodulatorThread;
|
||||
class DemodulatorThreadCommand {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "DemodulatorInstance.h"
|
||||
|
||||
DemodulatorInstance::DemodulatorInstance() :
|
||||
t_Demod(NULL), t_PreDemod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), currentAudioGain(1.0) {
|
||||
t_PreDemod(NULL), t_Demod(NULL), t_Audio(NULL) {
|
||||
|
||||
terminated.store(true);
|
||||
audioTerminated.store(true);
|
||||
@@ -16,23 +16,32 @@ DemodulatorInstance::DemodulatorInstance() :
|
||||
currentFrequency.store(0);
|
||||
currentBandwidth.store(0);
|
||||
currentOutputDevice.store(-1);
|
||||
|
||||
currentAudioGain.store(1.0);
|
||||
|
||||
label = new std::string("Unnamed");
|
||||
threadQueueDemod = new DemodulatorThreadInputQueue;
|
||||
threadQueuePostDemod = new DemodulatorThreadPostInputQueue;
|
||||
threadQueueCommand = new DemodulatorThreadCommandQueue;
|
||||
threadQueueNotify = new DemodulatorThreadCommandQueue;
|
||||
pipeIQInputData = new DemodulatorThreadInputQueue;
|
||||
pipeIQDemodData = new DemodulatorThreadPostInputQueue;
|
||||
pipeDemodCommand = new DemodulatorThreadCommandQueue;
|
||||
pipeDemodNotify = new DemodulatorThreadCommandQueue;
|
||||
|
||||
demodulatorPreThread = new DemodulatorPreThread();
|
||||
demodulatorPreThread->setInputQueue("IQDataInput",pipeIQInputData);
|
||||
demodulatorPreThread->setOutputQueue("IQDataOutput",pipeIQDemodData);
|
||||
demodulatorPreThread->setOutputQueue("NotifyQueue",pipeDemodNotify);
|
||||
demodulatorPreThread->setInputQueue("CommandQueue",pipeDemodCommand);
|
||||
|
||||
pipeAudioData = new AudioThreadInputQueue;
|
||||
threadQueueControl = new DemodulatorThreadControlCommandQueue;
|
||||
|
||||
demodulatorPreThread = new DemodulatorPreThread(threadQueueDemod, threadQueuePostDemod, threadQueueControl, threadQueueNotify);
|
||||
demodulatorPreThread->setCommandQueue(threadQueueCommand);
|
||||
demodulatorThread = new DemodulatorThread(threadQueuePostDemod, threadQueueControl, threadQueueNotify);
|
||||
demodulatorThread = new DemodulatorThread();
|
||||
demodulatorThread->setInputQueue("IQDataInput",pipeIQDemodData);
|
||||
demodulatorThread->setInputQueue("ControlQueue",threadQueueControl);
|
||||
demodulatorThread->setOutputQueue("NotifyQueue",pipeDemodNotify);
|
||||
demodulatorThread->setOutputQueue("AudioDataOutput", pipeAudioData);
|
||||
|
||||
audioInputQueue = new AudioThreadInputQueue;
|
||||
audioThread = new AudioThread(audioInputQueue, threadQueueNotify);
|
||||
|
||||
demodulatorThread->setAudioOutputQueue(audioInputQueue);
|
||||
audioThread = new AudioThread();
|
||||
audioThread->setInputQueue("AudioDataInput", pipeAudioData);
|
||||
audioThread->setOutputQueue("NotifyQueue", pipeDemodNotify);
|
||||
|
||||
currentDemodType = demodulatorThread->getDemodulatorType();
|
||||
}
|
||||
@@ -41,16 +50,16 @@ DemodulatorInstance::~DemodulatorInstance() {
|
||||
delete audioThread;
|
||||
delete demodulatorThread;
|
||||
delete demodulatorPreThread;
|
||||
delete threadQueueDemod;
|
||||
delete threadQueuePostDemod;
|
||||
delete threadQueueCommand;
|
||||
delete threadQueueNotify;
|
||||
delete pipeIQInputData;
|
||||
delete pipeIQDemodData;
|
||||
delete pipeDemodCommand;
|
||||
delete pipeDemodNotify;
|
||||
delete threadQueueControl;
|
||||
delete audioInputQueue;
|
||||
delete pipeAudioData;
|
||||
}
|
||||
|
||||
void DemodulatorInstance::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) {
|
||||
demodulatorThread->setVisualOutputQueue(tQueue);
|
||||
demodulatorThread->setOutputQueue("AudioVisualOutput", tQueue);
|
||||
}
|
||||
|
||||
void DemodulatorInstance::run() {
|
||||
@@ -104,7 +113,7 @@ void DemodulatorInstance::updateLabel(long long freq) {
|
||||
}
|
||||
|
||||
DemodulatorThreadCommandQueue *DemodulatorInstance::getCommandQueue() {
|
||||
return threadQueueCommand;
|
||||
return pipeDemodCommand;
|
||||
}
|
||||
|
||||
void DemodulatorInstance::terminate() {
|
||||
@@ -130,9 +139,9 @@ void DemodulatorInstance::setLabel(std::string labelStr) {
|
||||
}
|
||||
|
||||
bool DemodulatorInstance::isTerminated() {
|
||||
while (!threadQueueNotify->empty()) {
|
||||
while (!pipeDemodNotify->empty()) {
|
||||
DemodulatorThreadCommand cmd;
|
||||
threadQueueNotify->pop(cmd);
|
||||
pipeDemodNotify->pop(cmd);
|
||||
|
||||
switch (cmd.cmd) {
|
||||
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED:
|
||||
@@ -302,13 +311,13 @@ void DemodulatorInstance::setBandwidth(int bw) {
|
||||
currentBandwidth = bw;
|
||||
checkBandwidth();
|
||||
demodulatorPreThread->getParams().bandwidth = currentBandwidth;
|
||||
} else if (demodulatorPreThread && threadQueueCommand) {
|
||||
} else if (demodulatorPreThread && pipeDemodCommand) {
|
||||
DemodulatorThreadCommand command;
|
||||
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH;
|
||||
currentBandwidth = bw;
|
||||
checkBandwidth();
|
||||
command.llong_value = currentBandwidth;
|
||||
threadQueueCommand->push(command);
|
||||
pipeDemodCommand->push(command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,12 +335,12 @@ void DemodulatorInstance::setFrequency(long long freq) {
|
||||
if (!active) {
|
||||
currentFrequency = freq;
|
||||
demodulatorPreThread->getParams().frequency = currentFrequency;
|
||||
} else if (demodulatorPreThread && threadQueueCommand) {
|
||||
} else if (demodulatorPreThread && pipeDemodCommand) {
|
||||
DemodulatorThreadCommand command;
|
||||
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY;
|
||||
currentFrequency = freq;
|
||||
command.llong_value = freq;
|
||||
threadQueueCommand->push(command);
|
||||
pipeDemodCommand->push(command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,12 +356,12 @@ void DemodulatorInstance::setAudioSampleRate(int sampleRate) {
|
||||
if (terminated) {
|
||||
currentAudioSampleRate = sampleRate;
|
||||
demodulatorPreThread->getParams().audioSampleRate = sampleRate;
|
||||
} else if (demodulatorPreThread && threadQueueCommand) {
|
||||
} else if (demodulatorPreThread && pipeDemodCommand) {
|
||||
DemodulatorThreadCommand command;
|
||||
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_AUDIO_RATE;
|
||||
currentAudioSampleRate = sampleRate;
|
||||
command.llong_value = sampleRate;
|
||||
threadQueueCommand->push(command);
|
||||
pipeDemodCommand->push(command);
|
||||
}
|
||||
if (currentDemodType == DEMOD_TYPE_RAW) {
|
||||
setBandwidth(currentAudioSampleRate);
|
||||
@@ -402,3 +411,7 @@ bool DemodulatorInstance::isTracking() {
|
||||
void DemodulatorInstance::setTracking(bool tracking) {
|
||||
this->tracking = tracking;
|
||||
}
|
||||
|
||||
DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() {
|
||||
return pipeIQInputData;
|
||||
}
|
||||
|
||||
@@ -10,14 +10,6 @@
|
||||
class DemodulatorInstance {
|
||||
public:
|
||||
|
||||
DemodulatorThreadInputQueue* threadQueueDemod;
|
||||
DemodulatorThreadPostInputQueue* threadQueuePostDemod;
|
||||
DemodulatorThreadCommandQueue* threadQueueCommand;
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||
DemodulatorPreThread *demodulatorPreThread;
|
||||
DemodulatorThread *demodulatorThread;
|
||||
DemodulatorThreadControlCommandQueue *threadQueueControl;
|
||||
|
||||
#ifdef __APPLE__
|
||||
pthread_t t_PreDemod;
|
||||
pthread_t t_Demod;
|
||||
@@ -26,7 +18,6 @@ public:
|
||||
std::thread *t_Demod;
|
||||
#endif
|
||||
|
||||
AudioThreadInputQueue *audioInputQueue;
|
||||
AudioThread *audioThread;
|
||||
std::thread *t_Audio;
|
||||
|
||||
@@ -82,6 +73,19 @@ public:
|
||||
|
||||
bool isTracking();
|
||||
void setTracking(bool tracking);
|
||||
|
||||
DemodulatorThreadInputQueue *getIQInputDataPipe();
|
||||
|
||||
protected:
|
||||
DemodulatorThreadInputQueue* pipeIQInputData;
|
||||
DemodulatorThreadPostInputQueue* pipeIQDemodData;
|
||||
AudioThreadInputQueue *pipeAudioData;
|
||||
DemodulatorThreadCommandQueue* pipeDemodCommand;
|
||||
DemodulatorThreadCommandQueue* pipeDemodNotify;
|
||||
DemodulatorPreThread *demodulatorPreThread;
|
||||
DemodulatorThread *demodulatorThread;
|
||||
DemodulatorThreadControlCommandQueue *threadQueueControl;
|
||||
|
||||
private:
|
||||
|
||||
void checkBandwidth();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
DemodulatorMgr::DemodulatorMgr() :
|
||||
activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL), lastBandwidth(DEFAULT_DEMOD_BW), lastDemodType(
|
||||
DEFAULT_DEMOD_TYPE), lastGain(1.0), lastSquelch(0), lastSquelchEnabled(false), lastStereo(false) {
|
||||
DEFAULT_DEMOD_TYPE), lastSquelchEnabled(false), lastSquelch(0), lastGain(1.0), lastStereo(false) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,8 @@
|
||||
#include "DemodulatorPreThread.h"
|
||||
#include "CubicSDR.h"
|
||||
|
||||
DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* iqInputQueue, DemodulatorThreadPostInputQueue* iqOutputQueue,
|
||||
DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||
iqInputQueue(iqInputQueue), iqOutputQueue(iqOutputQueue), audioResampler(NULL), stereoResampler(NULL), iqResampleRatio(
|
||||
1), audioResampleRatio(1), firStereoRight(NULL), firStereoLeft(NULL), iirStereoPilot(NULL), iqResampler(NULL), commandQueue(NULL), threadQueueNotify(threadQueueNotify), threadQueueControl(
|
||||
threadQueueControl) {
|
||||
terminated.store(false);
|
||||
DemodulatorPreThread::DemodulatorPreThread() : IOThread(), iqResampler(NULL), iqResampleRatio(1), audioResampler(NULL), stereoResampler(NULL), audioResampleRatio(1), firStereoLeft(NULL), firStereoRight(NULL), iirStereoPilot(NULL), iqInputQueue(NULL), iqOutputQueue(NULL), threadQueueNotify(NULL), commandQueue(NULL)
|
||||
{
|
||||
initialized.store(false);
|
||||
|
||||
freqShifter = nco_crcf_create(LIQUID_VCO);
|
||||
@@ -21,9 +17,10 @@ DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* iqInputQ
|
||||
|
||||
workerQueue = new DemodulatorThreadWorkerCommandQueue;
|
||||
workerResults = new DemodulatorThreadWorkerResultQueue;
|
||||
workerThread = new DemodulatorWorkerThread(workerQueue, workerResults);
|
||||
|
||||
t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread);
|
||||
|
||||
workerThread = new DemodulatorWorkerThread();
|
||||
workerThread->setInputQueue("WorkerCommandQueue",workerQueue);
|
||||
workerThread->setOutputQueue("WorkerResultQueue",workerResults);
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::initialize() {
|
||||
@@ -80,11 +77,7 @@ DemodulatorPreThread::~DemodulatorPreThread() {
|
||||
delete workerResults;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
void *DemodulatorPreThread::threadMain() {
|
||||
#else
|
||||
void DemodulatorPreThread::threadMain() {
|
||||
#endif
|
||||
void DemodulatorPreThread::run() {
|
||||
#ifdef __APPLE__
|
||||
pthread_t tID = pthread_self(); // ID of this thread
|
||||
int priority = sched_get_priority_max( SCHED_FIFO) - 1;
|
||||
@@ -98,16 +91,20 @@ void DemodulatorPreThread::threadMain() {
|
||||
|
||||
std::cout << "Demodulator preprocessor thread started.." << std::endl;
|
||||
|
||||
std::deque<DemodulatorThreadPostIQData *> buffers;
|
||||
std::deque<DemodulatorThreadPostIQData *>::iterator buffers_i;
|
||||
t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread);
|
||||
|
||||
ReBuffer<DemodulatorThreadPostIQData> buffers;
|
||||
|
||||
iqInputQueue = (DemodulatorThreadInputQueue*)getInputQueue("IQDataInput");
|
||||
iqOutputQueue = (DemodulatorThreadPostInputQueue*)getOutputQueue("IQDataOutput");
|
||||
threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue");
|
||||
commandQueue = ( DemodulatorThreadCommandQueue*)getInputQueue("CommandQueue");
|
||||
|
||||
std::vector<liquid_float_complex> in_buf_data;
|
||||
std::vector<liquid_float_complex> out_buf_data;
|
||||
// liquid_float_complex carrySample; // Keep the stream count even to simplify some demod operations
|
||||
// bool carrySampleFlag = false;
|
||||
|
||||
terminated = false;
|
||||
|
||||
while (!terminated) {
|
||||
DemodulatorThreadIQData *inp;
|
||||
iqInputQueue->pop(inp);
|
||||
@@ -207,19 +204,7 @@ void DemodulatorPreThread::threadMain() {
|
||||
out_buf = temp_buf;
|
||||
}
|
||||
|
||||
DemodulatorThreadPostIQData *resamp = NULL;
|
||||
|
||||
for (buffers_i = buffers.begin(); buffers_i != buffers.end(); buffers_i++) {
|
||||
if ((*buffers_i)->getRefCount() <= 0) {
|
||||
resamp = (*buffers_i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (resamp == NULL) {
|
||||
resamp = new DemodulatorThreadPostIQData;
|
||||
buffers.push_back(resamp);
|
||||
}
|
||||
DemodulatorThreadPostIQData *resamp = buffers.getBuffer();
|
||||
|
||||
int out_size = ceil((double) (bufSize) * iqResampleRatio) + 512;
|
||||
|
||||
@@ -326,20 +311,12 @@ void DemodulatorPreThread::threadMain() {
|
||||
}
|
||||
}
|
||||
|
||||
while (!buffers.empty()) {
|
||||
DemodulatorThreadPostIQData *iqDataDel = buffers.front();
|
||||
buffers.pop_front();
|
||||
delete iqDataDel;
|
||||
}
|
||||
buffers.purge();
|
||||
|
||||
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED);
|
||||
tCmd.context = this;
|
||||
threadQueueNotify->push(tCmd);
|
||||
std::cout << "Demodulator preprocessor thread done." << std::endl;
|
||||
|
||||
#ifdef __APPLE__
|
||||
return this;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::terminate() {
|
||||
|
||||
@@ -7,26 +7,13 @@
|
||||
#include "DemodDefs.h"
|
||||
#include "DemodulatorWorkerThread.h"
|
||||
|
||||
class DemodulatorPreThread {
|
||||
class DemodulatorPreThread : public IOThread {
|
||||
public:
|
||||
|
||||
DemodulatorPreThread(DemodulatorThreadInputQueue* iqInputQueue, DemodulatorThreadPostInputQueue* iqOutputQueue,
|
||||
DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify);
|
||||
DemodulatorPreThread();
|
||||
~DemodulatorPreThread();
|
||||
|
||||
#ifdef __APPLE__
|
||||
void *threadMain();
|
||||
#else
|
||||
void threadMain();
|
||||
#endif
|
||||
|
||||
void setCommandQueue(DemodulatorThreadCommandQueue *tQueue) {
|
||||
commandQueue = tQueue;
|
||||
}
|
||||
|
||||
void setDemodulatorControlQueue(DemodulatorThreadControlCommandQueue *tQueue) {
|
||||
threadQueueControl = tQueue;
|
||||
}
|
||||
void run();
|
||||
|
||||
DemodulatorThreadParameters &getParams() {
|
||||
return params;
|
||||
@@ -46,10 +33,6 @@ public:
|
||||
#endif
|
||||
|
||||
protected:
|
||||
DemodulatorThreadInputQueue* iqInputQueue;
|
||||
DemodulatorThreadPostInputQueue* iqOutputQueue;
|
||||
DemodulatorThreadCommandQueue* commandQueue;
|
||||
|
||||
msresamp_crcf iqResampler;
|
||||
double iqResampleRatio;
|
||||
std::vector<liquid_float_complex> resampledData;
|
||||
@@ -68,7 +51,6 @@ protected:
|
||||
nco_crcf freqShifter;
|
||||
int shiftFrequency;
|
||||
|
||||
std::atomic_bool terminated;
|
||||
std::atomic_bool initialized;
|
||||
|
||||
DemodulatorWorkerThread *workerThread;
|
||||
@@ -76,6 +58,9 @@ protected:
|
||||
|
||||
DemodulatorThreadWorkerCommandQueue *workerQueue;
|
||||
DemodulatorThreadWorkerResultQueue *workerResults;
|
||||
|
||||
DemodulatorThreadInputQueue* iqInputQueue;
|
||||
DemodulatorThreadPostInputQueue* iqOutputQueue;
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||
DemodulatorThreadControlCommandQueue *threadQueueControl;
|
||||
DemodulatorThreadCommandQueue* commandQueue;
|
||||
};
|
||||
|
||||
@@ -11,15 +11,10 @@
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||
iqInputQueue(iqInputQueue), audioVisOutputQueue(NULL), audioOutputQueue(NULL), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(
|
||||
1), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelchLevel(0), signalLevel(
|
||||
0), squelchEnabled(false), audioSampleRate(0) {
|
||||
DemodulatorThread::DemodulatorThread() : IOThread(), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(1), audioSampleRate(0), squelchLevel(0), signalLevel(0), squelchEnabled(false), iqInputQueue(NULL), audioOutputQueue(NULL), audioVisOutputQueue(NULL), threadQueueControl(NULL), threadQueueNotify(NULL) {
|
||||
|
||||
stereo.store(false);
|
||||
agcEnabled.store(false);
|
||||
terminated.store(false);
|
||||
demodulatorType.store(DEMOD_TYPE_FM);
|
||||
|
||||
demodFM = freqdem_create(0.5);
|
||||
@@ -33,11 +28,13 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQue
|
||||
DemodulatorThread::~DemodulatorThread() {
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
void *DemodulatorThread::threadMain() {
|
||||
#else
|
||||
void DemodulatorThread::threadMain() {
|
||||
#endif
|
||||
void DemodulatorThread::onBindOutput(std::string name, ThreadQueueBase *threadQueue) {
|
||||
if (name == "AudioVisualOutput") {
|
||||
audioVisOutputQueue = (DemodulatorThreadOutputQueue *)threadQueue;
|
||||
}
|
||||
}
|
||||
|
||||
void DemodulatorThread::run() {
|
||||
#ifdef __APPLE__
|
||||
pthread_t tID = pthread_self(); // ID of this thread
|
||||
int priority = sched_get_priority_max( SCHED_FIFO )-1;
|
||||
@@ -72,6 +69,11 @@ void DemodulatorThread::threadMain() {
|
||||
|
||||
std::cout << "Demodulator thread started.." << std::endl;
|
||||
|
||||
iqInputQueue = (DemodulatorThreadPostInputQueue*)getInputQueue("IQDataInput");
|
||||
audioOutputQueue = (AudioThreadInputQueue*)getOutputQueue("AudioDataOutput");
|
||||
threadQueueControl = (DemodulatorThreadControlCommandQueue *)getInputQueue("ControlQueue");
|
||||
threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue");
|
||||
|
||||
switch (demodulatorType.load()) {
|
||||
case DEMOD_TYPE_FM:
|
||||
break;
|
||||
@@ -89,8 +91,6 @@ void DemodulatorThread::threadMain() {
|
||||
break;
|
||||
}
|
||||
|
||||
terminated = false;
|
||||
|
||||
while (!terminated) {
|
||||
DemodulatorThreadPostIQData *inp;
|
||||
iqInputQueue->pop(inp);
|
||||
@@ -188,7 +188,6 @@ void DemodulatorThread::threadMain() {
|
||||
} else if (demodulatorType == DEMOD_TYPE_RAW) {
|
||||
// do nothing here..
|
||||
} else {
|
||||
float p;
|
||||
switch (demodulatorType.load()) {
|
||||
case DEMOD_TYPE_LSB:
|
||||
for (int i = 0; i < bufSize; i++) { // Reject upper band
|
||||
@@ -307,17 +306,7 @@ void DemodulatorThread::threadMain() {
|
||||
if (audioOutputQueue != NULL) {
|
||||
if (!squelchEnabled || (signalLevel >= squelchLevel)) {
|
||||
|
||||
for (outputBuffersI = outputBuffers.begin(); outputBuffersI != outputBuffers.end(); outputBuffersI++) {
|
||||
if ((*outputBuffersI)->getRefCount() <= 0) {
|
||||
ati = (*outputBuffersI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ati == NULL) {
|
||||
ati = new AudioThreadInput;
|
||||
outputBuffers.push_back(ati);
|
||||
}
|
||||
ati = outputBuffers.getBuffer();
|
||||
|
||||
ati->sampleRate = audioSampleRate;
|
||||
ati->setRefCount(1);
|
||||
@@ -491,11 +480,7 @@ void DemodulatorThread::threadMain() {
|
||||
nco_crcf_destroy(stereoPilot);
|
||||
resamp2_cccf_destroy(ssbFilt);
|
||||
|
||||
while (!outputBuffers.empty()) {
|
||||
AudioThreadInput *audioDataDel = outputBuffers.front();
|
||||
outputBuffers.pop_front();
|
||||
delete audioDataDel;
|
||||
}
|
||||
outputBuffers.purge();
|
||||
|
||||
if (audioVisOutputQueue && !audioVisOutputQueue->empty()) {
|
||||
AudioThreadInput *dummy_vis;
|
||||
@@ -506,19 +491,8 @@ void DemodulatorThread::threadMain() {
|
||||
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED);
|
||||
tCmd.context = this;
|
||||
threadQueueNotify->push(tCmd);
|
||||
|
||||
std::cout << "Demodulator thread done." << std::endl;
|
||||
|
||||
#ifdef __APPLE__
|
||||
return this;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DemodulatorThread::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) {
|
||||
audioVisOutputQueue = tQueue;
|
||||
}
|
||||
|
||||
void DemodulatorThread::setAudioOutputQueue(AudioThreadInputQueue *tQueue) {
|
||||
audioOutputQueue = tQueue;
|
||||
}
|
||||
|
||||
void DemodulatorThread::terminate() {
|
||||
|
||||
@@ -10,22 +10,15 @@ typedef ThreadQueue<AudioThreadInput *> DemodulatorThreadOutputQueue;
|
||||
|
||||
#define DEMOD_VIS_SIZE 1024
|
||||
|
||||
class DemodulatorThread {
|
||||
class DemodulatorThread : public IOThread {
|
||||
public:
|
||||
|
||||
DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify);
|
||||
DemodulatorThread();
|
||||
~DemodulatorThread();
|
||||
|
||||
#ifdef __APPLE__
|
||||
void *threadMain();
|
||||
#else
|
||||
void threadMain();
|
||||
#endif
|
||||
|
||||
void setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue);
|
||||
void setAudioOutputQueue(AudioThreadInputQueue *tQueue);
|
||||
|
||||
void onBindOutput(std::string name, ThreadQueueBase *threadQueue);
|
||||
|
||||
void run();
|
||||
void terminate();
|
||||
|
||||
void setStereo(bool state);
|
||||
@@ -48,8 +41,7 @@ public:
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::deque<AudioThreadInput *> outputBuffers;
|
||||
std::deque<AudioThreadInput *>::iterator outputBuffersI;
|
||||
ReBuffer<AudioThreadInput> outputBuffers;
|
||||
|
||||
std::vector<liquid_float_complex> agcData;
|
||||
std::vector<float> agcAMData;
|
||||
@@ -58,10 +50,6 @@ protected:
|
||||
std::vector<float> resampledOutputData;
|
||||
std::vector<float> resampledStereoData;
|
||||
|
||||
DemodulatorThreadPostInputQueue* iqInputQueue;
|
||||
DemodulatorThreadOutputQueue* audioVisOutputQueue;
|
||||
AudioThreadInputQueue *audioOutputQueue;
|
||||
|
||||
freqdem demodFM;
|
||||
ampmodem demodAM;
|
||||
ampmodem demodAM_DSB_CSP;
|
||||
@@ -77,13 +65,16 @@ protected:
|
||||
|
||||
std::atomic_bool stereo;
|
||||
std::atomic_bool agcEnabled;
|
||||
std::atomic_bool terminated;
|
||||
std::atomic_int demodulatorType;
|
||||
int audioSampleRate;
|
||||
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||
DemodulatorThreadControlCommandQueue *threadQueueControl;
|
||||
std::atomic<float> squelchLevel;
|
||||
std::atomic<float> signalLevel;
|
||||
bool squelchEnabled;
|
||||
|
||||
DemodulatorThreadPostInputQueue* iqInputQueue;
|
||||
AudioThreadInputQueue *audioOutputQueue;
|
||||
DemodulatorThreadOutputQueue* audioVisOutputQueue;
|
||||
DemodulatorThreadControlCommandQueue *threadQueueControl;
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||
};
|
||||
|
||||
@@ -2,18 +2,20 @@
|
||||
#include "CubicSDRDefs.h"
|
||||
#include <vector>
|
||||
|
||||
DemodulatorWorkerThread::DemodulatorWorkerThread(DemodulatorThreadWorkerCommandQueue* in, DemodulatorThreadWorkerResultQueue* out) :
|
||||
commandQueue(in), resultQueue(out) {
|
||||
terminated.store(false);
|
||||
DemodulatorWorkerThread::DemodulatorWorkerThread() : IOThread(),
|
||||
commandQueue(NULL), resultQueue(NULL) {
|
||||
}
|
||||
|
||||
DemodulatorWorkerThread::~DemodulatorWorkerThread() {
|
||||
}
|
||||
|
||||
void DemodulatorWorkerThread::threadMain() {
|
||||
void DemodulatorWorkerThread::run() {
|
||||
|
||||
std::cout << "Demodulator worker thread started.." << std::endl;
|
||||
|
||||
|
||||
commandQueue = (DemodulatorThreadWorkerCommandQueue *)getInputQueue("WorkerCommandQueue");
|
||||
resultQueue = (DemodulatorThreadWorkerResultQueue *)getOutputQueue("WorkerResultQueue");
|
||||
|
||||
while (!terminated) {
|
||||
bool filterChanged = false;
|
||||
DemodulatorWorkerThreadCommand filterCommand;
|
||||
|
||||
@@ -70,13 +70,13 @@ public:
|
||||
typedef ThreadQueue<DemodulatorWorkerThreadCommand> DemodulatorThreadWorkerCommandQueue;
|
||||
typedef ThreadQueue<DemodulatorWorkerThreadResult> DemodulatorThreadWorkerResultQueue;
|
||||
|
||||
class DemodulatorWorkerThread {
|
||||
class DemodulatorWorkerThread : public IOThread {
|
||||
public:
|
||||
|
||||
DemodulatorWorkerThread(DemodulatorThreadWorkerCommandQueue* in, DemodulatorThreadWorkerResultQueue* out);
|
||||
DemodulatorWorkerThread();
|
||||
~DemodulatorWorkerThread();
|
||||
|
||||
void threadMain();
|
||||
void run();
|
||||
|
||||
void setCommandQueue(DemodulatorThreadWorkerCommandQueue *tQueue) {
|
||||
commandQueue = tQueue;
|
||||
@@ -92,6 +92,4 @@ protected:
|
||||
|
||||
DemodulatorThreadWorkerCommandQueue *commandQueue;
|
||||
DemodulatorThreadWorkerResultQueue *resultQueue;
|
||||
|
||||
std::atomic_bool terminated;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "ScopePanel.h"
|
||||
#include "ColorTheme.h"
|
||||
|
||||
ScopePanel::ScopePanel() : GLPanel(), scopeMode(SCOPE_MODE_Y) {
|
||||
bgPanel.setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
|
||||
bgPanelStereo[0].setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
|
||||
bgPanelStereo[0].setPosition(0, 0.5);
|
||||
bgPanelStereo[0].setSize(1, 0.5);
|
||||
bgPanelStereo[1].setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
|
||||
bgPanelStereo[1].setPosition(0, -0.5);
|
||||
bgPanelStereo[1].setSize(1, 0.5);
|
||||
}
|
||||
|
||||
void ScopePanel::setMode(ScopeMode scopeMode) {
|
||||
this->scopeMode = scopeMode;
|
||||
}
|
||||
|
||||
|
||||
void ScopePanel::setPoints(std::vector<float> &points) {
|
||||
this->points.assign(points.begin(),points.end());
|
||||
}
|
||||
|
||||
void ScopePanel::drawPanelContents() {
|
||||
|
||||
glLineWidth(1.0);
|
||||
|
||||
if (scopeMode == SCOPE_MODE_Y) {
|
||||
bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground, ThemeMgr::mgr.currentTheme->scopeBackground * 2.0);
|
||||
bgPanel.calcTransform(transform);
|
||||
bgPanel.draw();
|
||||
|
||||
glLoadMatrixf(transform);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
|
||||
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
|
||||
glBegin (GL_LINES);
|
||||
glVertex2f(-1.0, 0.0);
|
||||
glVertex2f(1.0, 0.0);
|
||||
glEnd();
|
||||
} else if (scopeMode == SCOPE_MODE_2Y) {
|
||||
bgPanelStereo[0].setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground, ThemeMgr::mgr.currentTheme->scopeBackground * 2.0);
|
||||
bgPanelStereo[1].setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground, ThemeMgr::mgr.currentTheme->scopeBackground * 2.0);
|
||||
|
||||
bgPanelStereo[0].calcTransform(transform);
|
||||
bgPanelStereo[0].draw();
|
||||
bgPanelStereo[1].calcTransform(transform);
|
||||
bgPanelStereo[1].draw();
|
||||
|
||||
glLoadMatrixf(transform);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b);
|
||||
glBegin (GL_LINES);
|
||||
glVertex2f(-1.0, 0.0);
|
||||
glVertex2f(1.0, 0.0);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
|
||||
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
|
||||
glVertex2f(-1.0, 0.5);
|
||||
glVertex2f(1.0, 0.5);
|
||||
glVertex2f(-1.0, -0.5);
|
||||
glVertex2f(1.0, -0.5);
|
||||
glEnd();
|
||||
|
||||
} else if (scopeMode == SCOPE_MODE_XY) {
|
||||
// ...
|
||||
}
|
||||
|
||||
if (points.size()) {
|
||||
glEnable (GL_BLEND);
|
||||
glEnable (GL_LINE_SMOOTH);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColor4f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b, 1.0);
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
|
||||
glLineWidth(1.5);
|
||||
if (scopeMode == SCOPE_MODE_Y) {
|
||||
glLoadMatrixf(bgPanel.transform);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2);
|
||||
} else if (scopeMode == SCOPE_MODE_2Y) {
|
||||
glLoadMatrixf(bgPanelStereo[0].transform);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 4);
|
||||
|
||||
glLoadMatrixf(bgPanelStereo[1].transform);
|
||||
glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4);
|
||||
} else if (scopeMode == SCOPE_MODE_XY) {
|
||||
// ...
|
||||
}
|
||||
glLineWidth(1.0);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "GLPanel.h"
|
||||
|
||||
class ScopePanel : public GLPanel {
|
||||
|
||||
public:
|
||||
typedef enum ScopeMode { SCOPE_MODE_Y, SCOPE_MODE_2Y, SCOPE_MODE_XY } ScopeMode;
|
||||
|
||||
ScopePanel();
|
||||
|
||||
void setMode(ScopeMode scopeMode);
|
||||
void setPoints(std::vector<float> &points);
|
||||
|
||||
protected:
|
||||
void drawPanelContents();
|
||||
|
||||
private:
|
||||
std::vector<float> points;
|
||||
ScopeMode scopeMode;
|
||||
GLPanel bgPanel;
|
||||
GLPanel bgPanelStereo[2];
|
||||
};
|
||||
@@ -1,82 +1,83 @@
|
||||
#include "SpectrumContext.h"
|
||||
#include "SpectrumPanel.h"
|
||||
|
||||
#include "SpectrumCanvas.h"
|
||||
#include "CubicSDR.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include "ColorTheme.h"
|
||||
|
||||
SpectrumContext::SpectrumContext(SpectrumCanvas *canvas, wxGLContext *sharedContext) :
|
||||
PrimaryGLContext(canvas, sharedContext), fft_size(0), floorValue(0), ceilValue(1) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
SpectrumPanel::SpectrumPanel() : floorValue(0), ceilValue(1) {
|
||||
setFill(GLPANEL_FILL_GRAD_Y);
|
||||
setFillColor(ThemeMgr::mgr.currentTheme->fftBackground * 2.0, ThemeMgr::mgr.currentTheme->fftBackground);
|
||||
}
|
||||
|
||||
|
||||
float SpectrumContext::getFloorValue() const {
|
||||
float SpectrumPanel::getFloorValue() const {
|
||||
return floorValue;
|
||||
}
|
||||
|
||||
void SpectrumContext::setFloorValue(float floorValue) {
|
||||
void SpectrumPanel::setFloorValue(float floorValue) {
|
||||
this->floorValue = floorValue;
|
||||
}
|
||||
|
||||
float SpectrumContext::getCeilValue() const {
|
||||
float SpectrumPanel::getCeilValue() const {
|
||||
return ceilValue;
|
||||
}
|
||||
|
||||
void SpectrumContext::setCeilValue(float ceilValue) {
|
||||
void SpectrumPanel::setCeilValue(float ceilValue) {
|
||||
this->ceilValue = ceilValue;
|
||||
}
|
||||
|
||||
void SpectrumContext::Draw(std::vector<float> &points, long long freq, int bandwidth) {
|
||||
void SpectrumPanel::setFreq(long long freq) {
|
||||
this->freq = freq;
|
||||
}
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->fftBackground.r, ThemeMgr::mgr.currentTheme->fftBackground.g, ThemeMgr::mgr.currentTheme->fftBackground.b);
|
||||
glVertex2f(1, 0.5);
|
||||
glVertex2f(-1, 0.5);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->fftBackground.r*2.0, ThemeMgr::mgr.currentTheme->fftBackground.g*2.0, ThemeMgr::mgr.currentTheme->fftBackground.b*2.0);
|
||||
glVertex2f(-1, -1);
|
||||
glVertex2f(1, -1);
|
||||
glEnd();
|
||||
long long SpectrumPanel::getFreq() {
|
||||
return freq;
|
||||
}
|
||||
|
||||
void SpectrumPanel::setBandwidth(long long bandwidth) {
|
||||
this->bandwidth = bandwidth;
|
||||
}
|
||||
|
||||
long long SpectrumPanel::getBandwidth() {
|
||||
return bandwidth;
|
||||
}
|
||||
|
||||
void SpectrumPanel::setPoints(std::vector<float> &points) {
|
||||
this->points.assign(points.begin(), points.end());
|
||||
}
|
||||
|
||||
|
||||
void SpectrumPanel::drawPanelContents() {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
|
||||
|
||||
glLoadMatrixf(transform * (CubicVR::mat4::translate(-1.0f, -0.75f, 0.0f) * CubicVR::mat4::scale(2.0f, 1.5f, 1.0f)));
|
||||
|
||||
if (points.size()) {
|
||||
glPushMatrix();
|
||||
glTranslatef(-1.0f, -0.75f, 0.0f);
|
||||
glScalef(2.0f, 1.5f, 1.0f);
|
||||
|
||||
|
||||
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 } };
|
||||
|
||||
|
||||
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];
|
||||
|
||||
|
||||
if (range >= rangeMin && range <= rangeMax) {
|
||||
float a = 1.0;
|
||||
|
||||
|
||||
if (range <= rangeMin+rangeTrans) {
|
||||
a *= (range-rangeMin)/rangeTrans;
|
||||
}
|
||||
if (range >= rangeMax-rangeTrans) {
|
||||
a *= (rangeTrans-(range-(rangeMax-rangeTrans)))/rangeTrans;
|
||||
}
|
||||
|
||||
|
||||
glColor4f(0.12, 0.12, 0.12, a);
|
||||
glBegin(GL_LINES);
|
||||
for (float l = floorValue; l<=ceilValue+rangeStep; l+=rangeStep) {
|
||||
@@ -86,76 +87,74 @@ void SpectrumContext::Draw(std::vector<float> &points, long long freq, int bandw
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->fftLine.r, ThemeMgr::mgr.currentTheme->fftLine.g, ThemeMgr::mgr.currentTheme->fftLine.b);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glLoadMatrixf(transform);
|
||||
|
||||
GLint vp[4];
|
||||
glGetIntegerv( GL_VIEWPORT, vp);
|
||||
|
||||
|
||||
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 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;
|
||||
|
||||
|
||||
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);
|
||||
|
||||
for (float m = -1.0 + mhzStart, mMax = 1.0 + fabs(mhzStart); m <= mMax; m += mhzStep) {
|
||||
|
||||
for (float m = -1.0 + mhzStart, mMax = 1.0 + ((mhzStart>0)?mhzStart:-mhzStart); m <= mMax; m += mhzStep) {
|
||||
label << std::fixed << currentMhz;
|
||||
|
||||
|
||||
double fractpart, intpart;
|
||||
|
||||
|
||||
fractpart = modf(currentMhz, &intpart);
|
||||
|
||||
|
||||
if (fractpart < 0.001) {
|
||||
glLineWidth(4.0);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->freqLine.r, ThemeMgr::mgr.currentTheme->freqLine.g, ThemeMgr::mgr.currentTheme->freqLine.b);
|
||||
} else {
|
||||
glLineWidth(1.0);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->freqLine.r * 0.65, ThemeMgr::mgr.currentTheme->freqLine.g * 0.65,
|
||||
ThemeMgr::mgr.currentTheme->freqLine.b * 0.65);
|
||||
ThemeMgr::mgr.currentTheme->freqLine.b * 0.65);
|
||||
}
|
||||
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(m, lMhzPos);
|
||||
glVertex2f(m, 1);
|
||||
glEnd();
|
||||
|
||||
|
||||
glColor4f(ThemeMgr::mgr.currentTheme->text.r, ThemeMgr::mgr.currentTheme->text.g, ThemeMgr::mgr.currentTheme->text.b,1.0);
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString(label.str(), m, hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(label.str(), m, hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
|
||||
label.str(std::string());
|
||||
|
||||
|
||||
currentMhz += mhzVisualStep;
|
||||
}
|
||||
|
||||
|
||||
glLineWidth(1.0);
|
||||
|
||||
// getFont(PrimaryGLContext::GLFONT_SIZE16).drawString("Welcome to CubicSDR -- This is a test string. 01234567890!@#$%^&*()_[]",0.0,0.0,16,GLFont::GLFONT_ALIGN_CENTER,GLFont::GLFONT_ALIGN_CENTER);
|
||||
CheckGLError();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "GLPanel.h"
|
||||
|
||||
class SpectrumPanel : public GLPanel {
|
||||
public:
|
||||
SpectrumPanel();
|
||||
|
||||
void setPoints(std::vector<float> &points);
|
||||
|
||||
float getFloorValue() const;
|
||||
void setFloorValue(float floorValue);
|
||||
|
||||
float getCeilValue() const;
|
||||
void setCeilValue(float ceilValue);
|
||||
|
||||
void setFreq(long long freq);
|
||||
long long getFreq();
|
||||
|
||||
void setBandwidth(long long bandwidth);
|
||||
long long getBandwidth();
|
||||
|
||||
protected:
|
||||
void drawPanelContents();
|
||||
|
||||
private:
|
||||
float floorValue, ceilValue;
|
||||
long long freq;
|
||||
long long bandwidth;
|
||||
std::vector<float> points;
|
||||
};
|
||||
@@ -1,34 +1,36 @@
|
||||
#include "WaterfallContext.h"
|
||||
#include "WaterfallCanvas.h"
|
||||
#include "CubicSDR.h"
|
||||
#include "WaterfallPanel.h"
|
||||
|
||||
WaterfallContext::WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext) :
|
||||
PrimaryGLContext(canvas, sharedContext), waterfall_lines(0), waterfall_slice(NULL), fft_size(0), activeTheme(NULL) {
|
||||
WaterfallPanel::WaterfallPanel() : GLPanel(), fft_size(0), waterfall_lines(0), waterfall_slice(NULL), activeTheme(NULL) {
|
||||
setFillColor(RGB3f(0,0,0));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
waterfall[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallContext::Setup(int fft_size_in, int num_waterfall_lines_in) {
|
||||
void WaterfallPanel::setup(int fft_size_in, int num_waterfall_lines_in) {
|
||||
waterfall_lines = num_waterfall_lines_in;
|
||||
fft_size = fft_size_in;
|
||||
|
||||
|
||||
if (points.size() != fft_size) {
|
||||
points.resize(fft_size);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (waterfall[i]) {
|
||||
glDeleteTextures(1, &waterfall[i]);
|
||||
waterfall[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
waterfall_ofs[i] = waterfall_lines - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallContext::refreshTheme() {
|
||||
void WaterfallPanel::refreshTheme() {
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
glBindTexture(GL_TEXTURE_2D, waterfall[i]);
|
||||
|
||||
|
||||
glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
|
||||
glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, &(ThemeMgr::mgr.currentTheme->waterfallGradient.getRed())[0]);
|
||||
glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, &(ThemeMgr::mgr.currentTheme->waterfallGradient.getGreen())[0]);
|
||||
@@ -36,81 +38,100 @@ void WaterfallContext::refreshTheme() {
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallContext::Draw(std::vector<float> &points) {
|
||||
void WaterfallPanel::setPoints(std::vector<float> &points) {
|
||||
int halfPts = points.size()/2;
|
||||
if (halfPts == fft_size) {
|
||||
for (int i = 0; i < fft_size; i++) {
|
||||
this->points[i] = points[i*2+1];
|
||||
}
|
||||
} else {
|
||||
this->points.assign(points.begin(), points.end());
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallPanel::step() {
|
||||
int half_fft_size = fft_size / 2;
|
||||
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||||
|
||||
if (!waterfall[0]) {
|
||||
glGenTextures(2, waterfall);
|
||||
|
||||
|
||||
unsigned char *waterfall_tex;
|
||||
|
||||
|
||||
waterfall_tex = new unsigned char[half_fft_size * waterfall_lines];
|
||||
memset(waterfall_tex, 0, half_fft_size * waterfall_lines);
|
||||
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
glBindTexture(GL_TEXTURE_2D, waterfall[i]);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, waterfall[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, half_fft_size, waterfall_lines, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_tex);
|
||||
}
|
||||
|
||||
if (waterfall_slice != NULL) {
|
||||
delete waterfall_slice;
|
||||
}
|
||||
waterfall_slice = new unsigned char[half_fft_size];
|
||||
|
||||
|
||||
if (waterfall_slice != NULL) {
|
||||
delete waterfall_slice;
|
||||
}
|
||||
waterfall_slice = new unsigned char[half_fft_size];
|
||||
|
||||
delete[] waterfall_tex;
|
||||
}
|
||||
|
||||
if (points.size()) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int i = 0, iMax = half_fft_size; i < iMax; i++) {
|
||||
float v = points[j * half_fft_size + i];
|
||||
|
||||
float wv = v < 0 ? 0 : (v > 0.99 ? 0.99 : v);
|
||||
|
||||
waterfall_slice[i] = (unsigned char) floor(wv * 255.0);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, waterfall[j]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, waterfall_ofs[j], half_fft_size, 1, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_slice);
|
||||
|
||||
if (waterfall_ofs[j] == 0) {
|
||||
waterfall_ofs[j] = waterfall_lines;
|
||||
}
|
||||
|
||||
waterfall_ofs[j]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallPanel::drawPanelContents() {
|
||||
if (!waterfall[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
int half_fft_size = fft_size / 2;
|
||||
|
||||
glLoadMatrixf(transform);
|
||||
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||||
|
||||
if (activeTheme != ThemeMgr::mgr.currentTheme) {
|
||||
refreshTheme();
|
||||
activeTheme = ThemeMgr::mgr.currentTheme;
|
||||
}
|
||||
|
||||
if (points.size()) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int i = 0, iMax = half_fft_size; i < iMax; i++) {
|
||||
float v = points[(j * half_fft_size + i) * 2 + 1];
|
||||
|
||||
float wv = v < 0 ? 0 : (v > 0.99 ? 0.99 : v);
|
||||
|
||||
waterfall_slice[i] = (unsigned char) floor(wv * 255.0);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, waterfall[j]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, waterfall_ofs[j], half_fft_size, 1, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_slice);
|
||||
|
||||
if (waterfall_ofs[j] == 0) {
|
||||
waterfall_ofs[j] = waterfall_lines;
|
||||
}
|
||||
|
||||
waterfall_ofs[j]--;
|
||||
}
|
||||
}
|
||||
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
|
||||
|
||||
GLint vp[4];
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
|
||||
|
||||
float viewWidth = (float) vp[2];
|
||||
|
||||
|
||||
// some bias to prevent seams at odd scales
|
||||
float half_pixel = 1.0 / viewWidth;
|
||||
float half_texel = 1.0 / (float) half_fft_size;
|
||||
float vtexel = 1.0 / (float) waterfall_lines;
|
||||
float vofs = (float) (waterfall_ofs[0] + 1) * vtexel;
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, waterfall[0]);
|
||||
glBegin (GL_QUADS);
|
||||
glTexCoord2f(0.0 + half_texel, 1.0 + vofs);
|
||||
@@ -122,7 +143,7 @@ void WaterfallContext::Draw(std::vector<float> &points) {
|
||||
glTexCoord2f(0.0 + half_texel, 0.0 + vofs);
|
||||
glVertex3f(-1.0, 1.0, 0.0);
|
||||
glEnd();
|
||||
|
||||
|
||||
vofs = (float) (waterfall_ofs[1] + 1) * vtexel;
|
||||
glBindTexture(GL_TEXTURE_2D, waterfall[1]);
|
||||
glBegin(GL_QUADS);
|
||||
@@ -135,9 +156,9 @@ void WaterfallContext::Draw(std::vector<float> &points) {
|
||||
glTexCoord2f(0.0 + half_texel, 0.0 + vofs);
|
||||
glVertex3f(0.0 - half_pixel, 1.0, 0.0);
|
||||
glEnd();
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "GLPanel.h"
|
||||
|
||||
class WaterfallPanel : public GLPanel {
|
||||
public:
|
||||
WaterfallPanel();
|
||||
void setup(int fft_size_in, int num_waterfall_lines_in);
|
||||
void refreshTheme();
|
||||
void setPoints(std::vector<float> &points);
|
||||
void step();
|
||||
|
||||
protected:
|
||||
void drawPanelContents();
|
||||
|
||||
private:
|
||||
std::vector<float> points;
|
||||
|
||||
GLuint waterfall[2];
|
||||
int waterfall_ofs[2];
|
||||
int fft_size;
|
||||
int waterfall_lines;
|
||||
unsigned char *waterfall_slice;
|
||||
|
||||
ColorTheme *activeTheme;
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "ScopeVisualProcessor.h"
|
||||
|
||||
void ScopeVisualProcessor::process() {
|
||||
if (!isOutputEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!input->empty()) {
|
||||
AudioThreadInput *audioInputData;
|
||||
input->pop(audioInputData);
|
||||
|
||||
if (!audioInputData) {
|
||||
return;
|
||||
}
|
||||
int iMax = audioInputData->data.size();
|
||||
if (!iMax) {
|
||||
audioInputData->decRefCount();
|
||||
return;
|
||||
}
|
||||
|
||||
ScopeRenderData *renderData = outputBuffers.getBuffer();
|
||||
renderData->channels = audioInputData->channels;
|
||||
|
||||
if (renderData->waveform_points.size() != iMax * 2) {
|
||||
renderData->waveform_points.resize(iMax * 2);
|
||||
}
|
||||
|
||||
float peak = 1.0f;
|
||||
|
||||
for (int i = 0; i < iMax; i++) {
|
||||
float p = fabs(audioInputData->data[i]);
|
||||
if (p > peak) {
|
||||
peak = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (audioInputData->channels == 2) {
|
||||
for (int i = 0; i < iMax; i++) {
|
||||
renderData->waveform_points[i * 2] = (((double) (i % (iMax/2)) / (double) iMax) * 2.0 - 0.5) * 2.0;
|
||||
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < iMax; i++) {
|
||||
renderData->waveform_points[i * 2] = (((double) i / (double) iMax) - 0.5) * 2.0;
|
||||
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak;
|
||||
}
|
||||
}
|
||||
distribute(renderData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "VisualProcessor.h"
|
||||
#include "AudioThread.h"
|
||||
|
||||
class ScopeRenderData: public ReferenceCounter {
|
||||
public:
|
||||
std::vector<float> waveform_points;
|
||||
int channels;
|
||||
};
|
||||
|
||||
typedef ThreadQueue<ScopeRenderData *> ScopeRenderDataQueue;
|
||||
|
||||
class ScopeVisualProcessor : public VisualProcessor<AudioThreadInput, ScopeRenderData> {
|
||||
protected:
|
||||
void process();
|
||||
ReBuffer<ScopeRenderData> outputBuffers;
|
||||
};
|
||||
@@ -0,0 +1,284 @@
|
||||
#include "SpectrumVisualProcessor.h"
|
||||
#include "CubicSDR.h"
|
||||
|
||||
|
||||
SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), lastBandwidth(0), fftwInput(NULL), fftwOutput(NULL), fftInData(NULL), fftLastData(NULL), lastDataSize(0), fftw_plan(NULL), resampler(NULL), resamplerRatio(0) {
|
||||
|
||||
is_view.store(false);
|
||||
fftSize.store(0);
|
||||
centerFreq.store(0);
|
||||
bandwidth.store(0);
|
||||
|
||||
freqShifter = nco_crcf_create(LIQUID_NCO);
|
||||
shiftFrequency = 0;
|
||||
|
||||
fft_ceil_ma = fft_ceil_maa = 100.0;
|
||||
fft_floor_ma = fft_floor_maa = 0.0;
|
||||
}
|
||||
|
||||
SpectrumVisualProcessor::~SpectrumVisualProcessor() {
|
||||
nco_crcf_destroy(freqShifter);
|
||||
}
|
||||
|
||||
bool SpectrumVisualProcessor::isView() {
|
||||
return is_view.load();
|
||||
}
|
||||
|
||||
void SpectrumVisualProcessor::setView(bool bView) {
|
||||
is_view.store(bView);
|
||||
}
|
||||
|
||||
|
||||
void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) {
|
||||
centerFreq.store(centerFreq_in);
|
||||
}
|
||||
|
||||
long long SpectrumVisualProcessor::getCenterFrequency() {
|
||||
return centerFreq.load();
|
||||
}
|
||||
|
||||
void SpectrumVisualProcessor::setBandwidth(long bandwidth_in) {
|
||||
bandwidth.store(bandwidth_in);
|
||||
}
|
||||
|
||||
long SpectrumVisualProcessor::getBandwidth() {
|
||||
return bandwidth.load();
|
||||
}
|
||||
|
||||
void SpectrumVisualProcessor::setup(int fftSize_in) {
|
||||
fftSize = fftSize_in;
|
||||
|
||||
if (fftwInput) {
|
||||
free(fftwInput);
|
||||
}
|
||||
fftwInput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
if (fftInData) {
|
||||
free(fftInData);
|
||||
}
|
||||
fftInData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
if (fftLastData) {
|
||||
free(fftLastData);
|
||||
}
|
||||
fftLastData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
if (fftwOutput) {
|
||||
free(fftwOutput);
|
||||
}
|
||||
fftwOutput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
if (fftw_plan) {
|
||||
fftwf_destroy_plan(fftw_plan);
|
||||
}
|
||||
fftw_plan = fftwf_plan_dft_1d(fftSize, fftwInput, fftwOutput, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
|
||||
}
|
||||
|
||||
void SpectrumVisualProcessor::process() {
|
||||
if (!isOutputEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!input || input->empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DemodulatorThreadIQData *iqData;
|
||||
|
||||
input->pop(iqData);
|
||||
|
||||
std::vector<liquid_float_complex> *data = &iqData->data;
|
||||
|
||||
if (data && data->size()) {
|
||||
SpectrumVisualData *output = outputBuffers.getBuffer();
|
||||
|
||||
if (output->spectrum_points.size() < fftSize * 2) {
|
||||
output->spectrum_points.resize(fftSize * 2);
|
||||
}
|
||||
|
||||
unsigned int num_written;
|
||||
|
||||
if (is_view.load()) {
|
||||
if (!iqData->frequency || !iqData->sampleRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
resamplerRatio = (double) (bandwidth) / (double) iqData->sampleRate;
|
||||
|
||||
int desired_input_size = fftSize / resamplerRatio;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
if (centerFreq != iqData->frequency) {
|
||||
if ((centerFreq - iqData->frequency) != shiftFrequency || lastInputBandwidth != iqData->sampleRate) {
|
||||
if (abs(iqData->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) {
|
||||
shiftFrequency = centerFreq - iqData->frequency;
|
||||
nco_crcf_reset(freqShifter);
|
||||
nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) iqData->sampleRate)));
|
||||
}
|
||||
}
|
||||
|
||||
if (shiftBuffer.size() != desired_input_size) {
|
||||
if (shiftBuffer.capacity() < desired_input_size) {
|
||||
shiftBuffer.reserve(desired_input_size);
|
||||
}
|
||||
shiftBuffer.resize(desired_input_size);
|
||||
}
|
||||
|
||||
if (shiftFrequency < 0) {
|
||||
nco_crcf_mix_block_up(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
|
||||
} else {
|
||||
nco_crcf_mix_block_down(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
|
||||
}
|
||||
} else {
|
||||
shiftBuffer.assign(iqData->data.begin(), iqData->data.end());
|
||||
}
|
||||
|
||||
if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != iqData->sampleRate) {
|
||||
float As = 60.0f;
|
||||
|
||||
if (resampler) {
|
||||
msresamp_crcf_destroy(resampler);
|
||||
}
|
||||
resampler = msresamp_crcf_create(resamplerRatio, As);
|
||||
|
||||
lastBandwidth = bandwidth;
|
||||
lastInputBandwidth = iqData->sampleRate;
|
||||
}
|
||||
|
||||
|
||||
int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512;
|
||||
|
||||
if (resampleBuffer.size() != out_size) {
|
||||
if (resampleBuffer.capacity() < out_size) {
|
||||
resampleBuffer.reserve(out_size);
|
||||
}
|
||||
resampleBuffer.resize(out_size);
|
||||
}
|
||||
|
||||
|
||||
msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written);
|
||||
|
||||
resampleBuffer.resize(fftSize);
|
||||
|
||||
if (num_written < fftSize) {
|
||||
for (int i = 0; i < num_written; i++) {
|
||||
fftInData[i][0] = resampleBuffer[i].real;
|
||||
fftInData[i][1] = resampleBuffer[i].imag;
|
||||
}
|
||||
for (int i = num_written; i < fftSize; i++) {
|
||||
fftInData[i][0] = 0;
|
||||
fftInData[i][1] = 0;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < fftSize; i++) {
|
||||
fftInData[i][0] = resampleBuffer[i].real;
|
||||
fftInData[i][1] = resampleBuffer[i].imag;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
num_written = data->size();
|
||||
if (data->size() < fftSize) {
|
||||
for (int i = 0, iMax = data->size(); i < iMax; i++) {
|
||||
fftInData[i][0] = (*data)[i].real;
|
||||
fftInData[i][1] = (*data)[i].imag;
|
||||
}
|
||||
for (int i = data->size(); i < fftSize; i++) {
|
||||
fftInData[i][0] = 0;
|
||||
fftInData[i][1] = 0;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < fftSize; i++) {
|
||||
fftInData[i][0] = (*data)[i].real;
|
||||
fftInData[i][1] = (*data)[i].imag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool execute = false;
|
||||
|
||||
if (num_written >= fftSize) {
|
||||
execute = true;
|
||||
memcpy(fftwInput, fftInData, fftSize * sizeof(fftwf_complex));
|
||||
memcpy(fftLastData, fftwInput, fftSize * sizeof(fftwf_complex));
|
||||
|
||||
} else {
|
||||
if (lastDataSize + num_written < fftSize) { // priming
|
||||
unsigned int num_copy = fftSize - lastDataSize;
|
||||
if (num_written > num_copy) {
|
||||
num_copy = num_written;
|
||||
}
|
||||
memcpy(fftLastData, fftInData, num_copy * sizeof(fftwf_complex));
|
||||
lastDataSize += num_copy;
|
||||
} else {
|
||||
unsigned int num_last = (fftSize - num_written);
|
||||
memcpy(fftwInput, fftLastData + (lastDataSize - num_last), num_last * sizeof(fftwf_complex));
|
||||
memcpy(fftwInput + num_last, fftInData, num_written * sizeof(fftwf_complex));
|
||||
memcpy(fftLastData, fftwInput, fftSize * sizeof(fftwf_complex));
|
||||
execute = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (execute) {
|
||||
fftwf_execute(fftw_plan);
|
||||
|
||||
float fft_ceil = 0, fft_floor = 1;
|
||||
|
||||
if (fft_result.size() < fftSize) {
|
||||
fft_result.resize(fftSize);
|
||||
fft_result_ma.resize(fftSize);
|
||||
fft_result_maa.resize(fftSize);
|
||||
}
|
||||
|
||||
for (int i = 0, iMax = fftSize / 2; i < iMax; i++) {
|
||||
float a = fftwOutput[i][0];
|
||||
float b = fftwOutput[i][1];
|
||||
float c = sqrt(a * a + b * b);
|
||||
|
||||
float x = fftwOutput[fftSize / 2 + i][0];
|
||||
float y = fftwOutput[fftSize / 2 + i][1];
|
||||
float z = sqrt(x * x + y * y);
|
||||
|
||||
fft_result[i] = (z);
|
||||
fft_result[fftSize / 2 + i] = (c);
|
||||
}
|
||||
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
if (fft_result_maa[i] > fft_ceil) {
|
||||
fft_ceil = fft_result_maa[i];
|
||||
}
|
||||
if (fft_result_maa[i] < fft_floor) {
|
||||
fft_floor = fft_result_maa[i];
|
||||
}
|
||||
}
|
||||
|
||||
fft_ceil += 0.25;
|
||||
fft_floor -= 1;
|
||||
|
||||
fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05;
|
||||
fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05;
|
||||
|
||||
fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05;
|
||||
fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05;
|
||||
|
||||
for (int i = 0, iMax = fftSize; i < iMax; i++) {
|
||||
float v = (log10(fft_result_maa[i] - fft_floor_maa) / log10(fft_ceil_maa - fft_floor_maa));
|
||||
output->spectrum_points[i * 2] = ((float) i / (float) iMax);
|
||||
output->spectrum_points[i * 2 + 1] = v;
|
||||
}
|
||||
|
||||
output->fft_ceiling = fft_ceil_maa;
|
||||
output->fft_floor = fft_floor_maa;
|
||||
}
|
||||
|
||||
distribute(output);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "VisualProcessor.h"
|
||||
#include "DemodDefs.h"
|
||||
#include "fftw3.h"
|
||||
|
||||
class SpectrumVisualData : public ReferenceCounter {
|
||||
public:
|
||||
std::vector<float> spectrum_points;
|
||||
double fft_ceiling, fft_floor;
|
||||
};
|
||||
|
||||
typedef ThreadQueue<SpectrumVisualData *> SpectrumVisualDataQueue;
|
||||
|
||||
class SpectrumVisualProcessor : public VisualProcessor<DemodulatorThreadIQData, SpectrumVisualData> {
|
||||
public:
|
||||
SpectrumVisualProcessor();
|
||||
~SpectrumVisualProcessor();
|
||||
|
||||
bool isView();
|
||||
void setView(bool bView);
|
||||
|
||||
void setCenterFrequency(long long centerFreq_in);
|
||||
long long getCenterFrequency();
|
||||
|
||||
void setBandwidth(long bandwidth_in);
|
||||
long getBandwidth();
|
||||
|
||||
void setup(int fftSize);
|
||||
|
||||
protected:
|
||||
void process();
|
||||
|
||||
ReBuffer<SpectrumVisualData> outputBuffers;
|
||||
std::atomic_bool is_view;
|
||||
std::atomic_int fftSize;
|
||||
std::atomic_llong centerFreq;
|
||||
std::atomic_long bandwidth;
|
||||
|
||||
private:
|
||||
long lastInputBandwidth;
|
||||
long lastBandwidth;
|
||||
|
||||
fftwf_complex *fftwInput, *fftwOutput, *fftInData, *fftLastData;
|
||||
unsigned int lastDataSize;
|
||||
fftwf_plan fftw_plan;
|
||||
|
||||
float fft_ceil_ma, fft_ceil_maa;
|
||||
float fft_floor_ma, fft_floor_maa;
|
||||
|
||||
std::vector<float> fft_result;
|
||||
std::vector<float> fft_result_ma;
|
||||
std::vector<float> fft_result_maa;
|
||||
|
||||
msresamp_crcf resampler;
|
||||
double resamplerRatio;
|
||||
nco_crcf freqShifter;
|
||||
long shiftFrequency;
|
||||
|
||||
std::vector<liquid_float_complex> shiftBuffer;
|
||||
std::vector<liquid_float_complex> resampleBuffer;
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
#include "VisualProcessor.h"
|
||||
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include "CubicSDRDefs.h"
|
||||
#include "ThreadQueue.h"
|
||||
#include "IOThread.h"
|
||||
#include <algorithm>
|
||||
|
||||
template<class InputDataType = ReferenceCounter, class OutputDataType = ReferenceCounter>
|
||||
class VisualProcessor {
|
||||
public:
|
||||
virtual ~VisualProcessor() {
|
||||
|
||||
}
|
||||
|
||||
void setInput(ThreadQueue<InputDataType *> *vis_in) {
|
||||
busy_update.lock();
|
||||
input = vis_in;
|
||||
busy_update.unlock();
|
||||
}
|
||||
|
||||
void attachOutput(ThreadQueue<OutputDataType *> *vis_out) {
|
||||
// attach an output queue
|
||||
busy_update.lock();
|
||||
outputs.push_back(vis_out);
|
||||
busy_update.unlock();
|
||||
}
|
||||
|
||||
void removeOutput(ThreadQueue<OutputDataType *> *vis_out) {
|
||||
// remove an output queue
|
||||
busy_update.lock();
|
||||
typename std::vector<ThreadQueue<OutputDataType *> *>::iterator i = std::find(outputs.begin(), outputs.end(), vis_out);
|
||||
if (i != outputs.end()) {
|
||||
outputs.erase(i);
|
||||
}
|
||||
busy_update.unlock();
|
||||
}
|
||||
|
||||
void run() {
|
||||
busy_update.lock();
|
||||
if (input && !input->empty()) {
|
||||
process();
|
||||
}
|
||||
busy_update.unlock();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void process() {
|
||||
// process inputs to output
|
||||
// distribute(output);
|
||||
}
|
||||
|
||||
void distribute(OutputDataType *output) {
|
||||
// distribute outputs
|
||||
output->setRefCount(outputs.size());
|
||||
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
|
||||
if ((*outputs_i)->full()) {
|
||||
output->decRefCount();
|
||||
} else {
|
||||
(*outputs_i)->push(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
typename std::vector<ThreadQueue<OutputDataType *> *>::iterator outputs_i;
|
||||
std::mutex busy_update;
|
||||
};
|
||||
|
||||
|
||||
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()) {
|
||||
OutputDataType *inp;
|
||||
VisualProcessor<OutputDataType, OutputDataType>::input->pop(inp);
|
||||
if (inp) {
|
||||
VisualProcessor<OutputDataType, OutputDataType>::distribute(inp);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "SDRDeviceInfo.h"
|
||||
|
||||
|
||||
SDRDeviceInfo::SDRDeviceInfo() : name(""), serial(""), available(false) {
|
||||
|
||||
}
|
||||
|
||||
std::string SDRDeviceInfo::getDeviceId() {
|
||||
std::string deviceId;
|
||||
|
||||
deviceId.append(getName());
|
||||
deviceId.append(" :: ");
|
||||
deviceId.append(getSerial());
|
||||
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
bool SDRDeviceInfo::isAvailable() const {
|
||||
return available;
|
||||
}
|
||||
|
||||
void SDRDeviceInfo::setAvailable(bool available) {
|
||||
this->available = available;
|
||||
}
|
||||
|
||||
const std::string& SDRDeviceInfo::getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
void SDRDeviceInfo::setName(const std::string& name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
const std::string& SDRDeviceInfo::getSerial() const {
|
||||
return serial;
|
||||
}
|
||||
|
||||
void SDRDeviceInfo::setSerial(const std::string& serial) {
|
||||
this->serial = serial;
|
||||
}
|
||||
|
||||
const std::string& SDRDeviceInfo::getTuner() const {
|
||||
return tuner;
|
||||
}
|
||||
|
||||
void SDRDeviceInfo::setTuner(const std::string& tuner) {
|
||||
this->tuner = tuner;
|
||||
}
|
||||
|
||||
const std::string& SDRDeviceInfo::getManufacturer() const {
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
void SDRDeviceInfo::setManufacturer(const std::string& manufacturer) {
|
||||
this->manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
const std::string& SDRDeviceInfo::getProduct() const {
|
||||
return product;
|
||||
}
|
||||
|
||||
void SDRDeviceInfo::setProduct(const std::string& product) {
|
||||
this->product = product;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class SDRDeviceInfo {
|
||||
public:
|
||||
SDRDeviceInfo();
|
||||
|
||||
std::string getDeviceId();
|
||||
|
||||
bool isAvailable() const;
|
||||
void setAvailable(bool available);
|
||||
|
||||
const std::string& getName() const;
|
||||
void setName(const std::string& name);
|
||||
|
||||
const std::string& getSerial() const;
|
||||
void setSerial(const std::string& serial);
|
||||
|
||||
const std::string& getTuner() const;
|
||||
void setTuner(const std::string& tuner);
|
||||
|
||||
const std::string& getManufacturer() const;
|
||||
void setManufacturer(const std::string& manufacturer);
|
||||
|
||||
const std::string& getProduct() const;
|
||||
void setProduct(const std::string& product);
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::string serial;
|
||||
std::string product;
|
||||
std::string manufacturer;
|
||||
std::string tuner;
|
||||
bool available;
|
||||
};
|
||||
+19
-46
@@ -5,10 +5,9 @@
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
SDRPostThread::SDRPostThread() :
|
||||
SDRPostThread::SDRPostThread() : IOThread(),
|
||||
iqDataInQueue(NULL), iqDataOutQueue(NULL), iqVisualQueue(NULL), dcFilter(NULL), num_vis_samples(16384*2) {
|
||||
|
||||
terminated.store(false);
|
||||
swapIQ.store(false);
|
||||
|
||||
// create a lookup table
|
||||
@@ -51,16 +50,6 @@ void SDRPostThread::removeDemodulator(DemodulatorInstance *demod) {
|
||||
busy_demod.unlock();
|
||||
}
|
||||
|
||||
void SDRPostThread::setIQDataInQueue(SDRThreadIQDataQueue* iqDataQueue) {
|
||||
iqDataInQueue = iqDataQueue;
|
||||
}
|
||||
void SDRPostThread::setIQDataOutQueue(DemodulatorThreadInputQueue* iqDataQueue) {
|
||||
iqDataOutQueue = iqDataQueue;
|
||||
}
|
||||
void SDRPostThread::setIQVisualQueue(DemodulatorThreadInputQueue *iqVisQueue) {
|
||||
iqVisualQueue = iqVisQueue;
|
||||
}
|
||||
|
||||
void SDRPostThread::setNumVisSamples(int num_vis_samples_in) {
|
||||
num_vis_samples = num_vis_samples_in;
|
||||
}
|
||||
@@ -77,10 +66,7 @@ bool SDRPostThread::getSwapIQ() {
|
||||
return this->swapIQ.load();
|
||||
}
|
||||
|
||||
void SDRPostThread::threadMain() {
|
||||
int n_read;
|
||||
double seconds = 0.0;
|
||||
|
||||
void SDRPostThread::run() {
|
||||
#ifdef __APPLE__
|
||||
pthread_t tID = pthread_self(); // ID of this thread
|
||||
int priority = sched_get_priority_max( SCHED_FIFO) - 1;
|
||||
@@ -94,15 +80,18 @@ void SDRPostThread::threadMain() {
|
||||
|
||||
std::cout << "SDR post-processing thread started.." << std::endl;
|
||||
|
||||
std::deque<DemodulatorThreadIQData *> buffers;
|
||||
std::deque<DemodulatorThreadIQData *>::iterator buffers_i;
|
||||
iqDataInQueue = (SDRThreadIQDataQueue*)getInputQueue("IQDataInput");
|
||||
iqDataOutQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQDataOutput");
|
||||
iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOut");
|
||||
|
||||
ReBuffer<DemodulatorThreadIQData> buffers;
|
||||
std::vector<liquid_float_complex> fpData;
|
||||
std::vector<liquid_float_complex> dataOut;
|
||||
|
||||
while (!terminated) {
|
||||
SDRThreadIQData *data_in;
|
||||
|
||||
iqDataInQueue.load()->pop(data_in);
|
||||
iqDataInQueue->pop(data_in);
|
||||
// std::lock_guard < std::mutex > lock(data_in->m_mutex);
|
||||
|
||||
if (data_in && data_in->data.size()) {
|
||||
@@ -128,16 +117,16 @@ void SDRPostThread::threadMain() {
|
||||
|
||||
iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]);
|
||||
|
||||
if (iqDataOutQueue.load() != NULL) {
|
||||
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.load()->push(pipeDataOut);
|
||||
iqDataOutQueue->push(pipeDataOut);
|
||||
}
|
||||
|
||||
if (iqVisualQueue.load() != NULL && iqVisualQueue.load()->empty()) {
|
||||
if (iqVisualQueue != NULL && iqVisualQueue->empty()) {
|
||||
|
||||
visualDataOut->busy_rw.lock();
|
||||
|
||||
@@ -152,7 +141,7 @@ void SDRPostThread::threadMain() {
|
||||
visualDataOut->sampleRate = data_in->sampleRate;
|
||||
visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples);
|
||||
|
||||
iqVisualQueue.load()->push(visualDataOut);
|
||||
iqVisualQueue->push(visualDataOut);
|
||||
|
||||
visualDataOut->busy_rw.unlock();
|
||||
}
|
||||
@@ -176,19 +165,7 @@ void SDRPostThread::threadMain() {
|
||||
|
||||
if (demodulators.size()) {
|
||||
|
||||
DemodulatorThreadIQData *demodDataOut = NULL;
|
||||
|
||||
for (buffers_i = buffers.begin(); buffers_i != buffers.end(); buffers_i++) {
|
||||
if ((*buffers_i)->getRefCount() <= 0) {
|
||||
demodDataOut = (*buffers_i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (demodDataOut == NULL) {
|
||||
demodDataOut = new DemodulatorThreadIQData;
|
||||
buffers.push_back(demodDataOut);
|
||||
}
|
||||
DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
|
||||
|
||||
// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex);
|
||||
demodDataOut->frequency = data_in->frequency;
|
||||
@@ -199,7 +176,7 @@ void SDRPostThread::threadMain() {
|
||||
std::vector<DemodulatorInstance *>::iterator i;
|
||||
for (i = demodulators.begin(); i != demodulators.end(); i++) {
|
||||
DemodulatorInstance *demod = *i;
|
||||
DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod;
|
||||
DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe();
|
||||
|
||||
if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
||||
if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
|
||||
@@ -242,15 +219,11 @@ void SDRPostThread::threadMain() {
|
||||
data_in->decRefCount();
|
||||
}
|
||||
|
||||
while (!buffers.empty()) {
|
||||
DemodulatorThreadIQData *demodDataDel = buffers.front();
|
||||
buffers.pop_front();
|
||||
// std::lock_guard < std::mutex > lock(demodDataDel->m_mutex);
|
||||
// delete demodDataDel;
|
||||
}
|
||||
if (iqVisualQueue.load() && !iqVisualQueue.load()->empty()) {
|
||||
buffers.purge();
|
||||
|
||||
if (iqVisualQueue && !iqVisualQueue->empty()) {
|
||||
DemodulatorThreadIQData *visualDataDummy;
|
||||
iqVisualQueue.load()->pop(visualDataDummy);
|
||||
iqVisualQueue->pop(visualDataDummy);
|
||||
}
|
||||
|
||||
delete visualDataOut;
|
||||
@@ -261,5 +234,5 @@ void SDRPostThread::threadMain() {
|
||||
void SDRPostThread::terminate() {
|
||||
terminated = true;
|
||||
SDRThreadIQData *dummy = new SDRThreadIQData;
|
||||
iqDataInQueue.load()->push(dummy);
|
||||
iqDataInQueue->push(dummy);
|
||||
}
|
||||
|
||||
+5
-10
@@ -3,7 +3,7 @@
|
||||
#include "SDRThread.h"
|
||||
#include <algorithm>
|
||||
|
||||
class SDRPostThread {
|
||||
class SDRPostThread : public IOThread {
|
||||
public:
|
||||
SDRPostThread();
|
||||
~SDRPostThread();
|
||||
@@ -11,27 +11,22 @@ public:
|
||||
void bindDemodulator(DemodulatorInstance *demod);
|
||||
void removeDemodulator(DemodulatorInstance *demod);
|
||||
|
||||
void setIQDataInQueue(SDRThreadIQDataQueue* iqDataQueue);
|
||||
void setIQDataOutQueue(DemodulatorThreadInputQueue* iqDataQueue);
|
||||
void setIQVisualQueue(DemodulatorThreadInputQueue* iqVisQueue);
|
||||
|
||||
void setNumVisSamples(int num_vis_samples_in);
|
||||
int getNumVisSamples();
|
||||
|
||||
void setSwapIQ(bool swapIQ);
|
||||
bool getSwapIQ();
|
||||
|
||||
void threadMain();
|
||||
void run();
|
||||
void terminate();
|
||||
|
||||
protected:
|
||||
std::atomic<SDRThreadIQDataQueue *> iqDataInQueue;
|
||||
std::atomic<DemodulatorThreadInputQueue *> iqDataOutQueue;
|
||||
std::atomic<DemodulatorThreadInputQueue *> iqVisualQueue;
|
||||
SDRThreadIQDataQueue *iqDataInQueue;
|
||||
DemodulatorThreadInputQueue *iqDataOutQueue;
|
||||
DemodulatorThreadInputQueue *iqVisualQueue;
|
||||
|
||||
std::mutex busy_demod;
|
||||
std::vector<DemodulatorInstance *> demodulators;
|
||||
std::atomic_bool terminated;
|
||||
iirfilt_crcf dcFilter;
|
||||
int num_vis_samples;
|
||||
std::atomic_bool swapIQ;
|
||||
|
||||
+18
-34
@@ -3,9 +3,7 @@
|
||||
#include <vector>
|
||||
#include "CubicSDR.h"
|
||||
|
||||
SDRThread::SDRThread(SDRThreadCommandQueue* pQueue) :
|
||||
commandQueue(pQueue), iqDataOutQueue(NULL) {
|
||||
terminated.store(false);
|
||||
SDRThread::SDRThread() : IOThread() {
|
||||
offset.store(0);
|
||||
deviceId.store(-1);
|
||||
dev = NULL;
|
||||
@@ -114,7 +112,7 @@ int SDRThread::enumerate_rtl(std::vector<SDRDeviceInfo *> *devs) {
|
||||
|
||||
}
|
||||
|
||||
void SDRThread::threadMain() {
|
||||
void SDRThread::run() {
|
||||
#ifdef __APPLE__
|
||||
pthread_t tID = pthread_self(); // ID of this thread
|
||||
int priority = sched_get_priority_max( SCHED_FIFO) - 1;
|
||||
@@ -124,8 +122,6 @@ void SDRThread::threadMain() {
|
||||
|
||||
std::cout << "SDR thread initializing.." << std::endl;
|
||||
|
||||
int devCount = rtlsdr_get_device_count();
|
||||
|
||||
std::vector<SDRDeviceInfo *> devs;
|
||||
if (deviceId == -1) {
|
||||
deviceId = enumerate_rtl(&devs);
|
||||
@@ -168,12 +164,12 @@ void SDRThread::threadMain() {
|
||||
|
||||
std::cout << "SDR thread started.." << std::endl;
|
||||
|
||||
std::deque<SDRThreadIQData *> buffers;
|
||||
std::deque<SDRThreadIQData *>::iterator buffers_i;
|
||||
ReBuffer<SDRThreadIQData> buffers;
|
||||
|
||||
SDRThreadIQDataQueue* iqDataOutQueue = (SDRThreadIQDataQueue*) getOutputQueue("IQDataOutput");
|
||||
SDRThreadCommandQueue* cmdQueue = (SDRThreadCommandQueue*) getInputQueue("SDRCommandQueue");
|
||||
|
||||
while (!terminated) {
|
||||
SDRThreadCommandQueue *cmdQueue = commandQueue.load();
|
||||
|
||||
if (!cmdQueue->empty()) {
|
||||
bool freq_changed = false;
|
||||
bool offset_changed = false;
|
||||
@@ -274,19 +270,7 @@ void SDRThread::threadMain() {
|
||||
|
||||
rtlsdr_read_sync(dev, buf, buf_size, &n_read);
|
||||
|
||||
SDRThreadIQData *dataOut = NULL;
|
||||
|
||||
for (buffers_i = buffers.begin(); buffers_i != buffers.end(); buffers_i++) {
|
||||
if ((*buffers_i)->getRefCount() <= 0) {
|
||||
dataOut = (*buffers_i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataOut == NULL) {
|
||||
dataOut = new SDRThreadIQData;
|
||||
buffers.push_back(dataOut);
|
||||
}
|
||||
SDRThreadIQData *dataOut = buffers.getBuffer();
|
||||
|
||||
// std::lock_guard < std::mutex > lock(dataOut->m_mutex);
|
||||
dataOut->setRefCount(1);
|
||||
@@ -306,21 +290,21 @@ void SDRThread::threadMain() {
|
||||
double time_slice = (double) n_read / (double) sampleRate.load();
|
||||
seconds += time_slice;
|
||||
|
||||
if (iqDataOutQueue.load() != NULL) {
|
||||
iqDataOutQueue.load()->push(dataOut);
|
||||
if (iqDataOutQueue != NULL) {
|
||||
iqDataOutQueue->push(dataOut);
|
||||
}
|
||||
}
|
||||
|
||||
while (!buffers.empty()) {
|
||||
SDRThreadIQData *iqDataDel = buffers.front();
|
||||
buffers.pop_front();
|
||||
// std::lock_guard < std::mutex > lock(iqDataDel->m_mutex);
|
||||
// delete iqDataDel;
|
||||
}
|
||||
|
||||
buffers.purge();
|
||||
|
||||
std::cout << "SDR thread done." << std::endl;
|
||||
}
|
||||
|
||||
void SDRThread::terminate() {
|
||||
terminated = true;
|
||||
|
||||
int SDRThread::getDeviceId() const {
|
||||
return deviceId.load();
|
||||
}
|
||||
|
||||
void SDRThread::setDeviceId(int deviceId) {
|
||||
this->deviceId.store(deviceId);
|
||||
}
|
||||
|
||||
+7
-92
@@ -6,77 +6,7 @@
|
||||
|
||||
#include "ThreadQueue.h"
|
||||
#include "DemodulatorMgr.h"
|
||||
|
||||
class SDRDeviceInfo {
|
||||
public:
|
||||
SDRDeviceInfo() : name(""), serial(""), available(false) { }
|
||||
|
||||
std::string getDeviceId() {
|
||||
std::string deviceId;
|
||||
|
||||
deviceId.append(getName());
|
||||
deviceId.append(" :: ");
|
||||
deviceId.append(getSerial());
|
||||
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
bool isAvailable() const {
|
||||
return available;
|
||||
}
|
||||
|
||||
void setAvailable(bool available) {
|
||||
this->available = available;
|
||||
}
|
||||
|
||||
const std::string& getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
void setName(const std::string& name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
const std::string& getSerial() const {
|
||||
return serial;
|
||||
}
|
||||
|
||||
void setSerial(const std::string& serial) {
|
||||
this->serial = serial;
|
||||
}
|
||||
|
||||
const std::string& getTuner() const {
|
||||
return tuner;
|
||||
}
|
||||
|
||||
void setTuner(const std::string& tuner) {
|
||||
this->tuner = tuner;
|
||||
}
|
||||
|
||||
const std::string& getManufacturer() const {
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
void setManufacturer(const std::string& manufacturer) {
|
||||
this->manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
const std::string& getProduct() const {
|
||||
return product;
|
||||
}
|
||||
|
||||
void setProduct(const std::string& product) {
|
||||
this->product = product;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::string serial;
|
||||
std::string product;
|
||||
std::string manufacturer;
|
||||
std::string tuner;
|
||||
bool available;
|
||||
};
|
||||
#include "SDRDeviceInfo.h"
|
||||
|
||||
class SDRThreadCommand {
|
||||
public:
|
||||
@@ -122,37 +52,22 @@ public:
|
||||
typedef ThreadQueue<SDRThreadCommand> SDRThreadCommandQueue;
|
||||
typedef ThreadQueue<SDRThreadIQData *> SDRThreadIQDataQueue;
|
||||
|
||||
class SDRThread {
|
||||
class SDRThread : public IOThread {
|
||||
public:
|
||||
rtlsdr_dev_t *dev;
|
||||
|
||||
SDRThread(SDRThreadCommandQueue* pQueue);
|
||||
SDRThread();
|
||||
~SDRThread();
|
||||
|
||||
static int enumerate_rtl(std::vector<SDRDeviceInfo *> *devs);
|
||||
|
||||
void threadMain();
|
||||
|
||||
void setIQDataOutQueue(SDRThreadIQDataQueue* iqDataQueue) {
|
||||
iqDataOutQueue = iqDataQueue;
|
||||
}
|
||||
|
||||
void terminate();
|
||||
|
||||
int getDeviceId() const {
|
||||
return deviceId.load();
|
||||
}
|
||||
|
||||
void setDeviceId(int deviceId) {
|
||||
this->deviceId.store(deviceId);
|
||||
}
|
||||
void run();
|
||||
|
||||
int getDeviceId() const;
|
||||
void setDeviceId(int deviceId);
|
||||
|
||||
protected:
|
||||
std::atomic<uint32_t> sampleRate;
|
||||
std::atomic_llong offset;
|
||||
std::atomic<SDRThreadCommandQueue*> commandQueue;
|
||||
std::atomic<SDRThreadIQDataQueue*> iqDataOutQueue;
|
||||
|
||||
std::atomic_bool terminated;
|
||||
std::atomic_int deviceId;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
|
||||
#include "GLPanel.h"
|
||||
#include "cubic_math.h"
|
||||
|
||||
using namespace CubicVR;
|
||||
|
||||
GLPanel::GLPanel() : fillType(GLPANEL_FILL_SOLID), contentsVisible(true), transform(mat4::identity()) {
|
||||
pos[0] = 0.0f;
|
||||
pos[1] = 0.0f;
|
||||
size[0] = 1.0f;
|
||||
size[1] = 1.0f;
|
||||
fill[0] = RGB3f(0.5,0.5,0.5);
|
||||
fill[1] = RGB3f(0.1,0.1,0.1);
|
||||
borderColor = RGB3f(0.8, 0.8, 0.8);
|
||||
setCoordinateSystem(GLPANEL_Y_UP);
|
||||
setMarginPx(0);
|
||||
setBorderPx(0);
|
||||
}
|
||||
|
||||
void GLPanel::genArrays() {
|
||||
float min = -1.0, mid = 0, max = 1.0;
|
||||
|
||||
if (fillType == GLPANEL_FILL_SOLID || fillType == GLPANEL_FILL_GRAD_X || fillType == GLPANEL_FILL_GRAD_Y) {
|
||||
glPoints.reserve(2 * 4);
|
||||
glPoints.resize(2 * 4);
|
||||
glColors.reserve(3 * 4);
|
||||
glColors.resize(3 * 4);
|
||||
|
||||
float pts[2 * 4] = {
|
||||
min, min,
|
||||
min, max,
|
||||
max, max,
|
||||
max, min
|
||||
};
|
||||
|
||||
RGB3f c[4];
|
||||
|
||||
if (fillType == GLPANEL_FILL_SOLID) {
|
||||
c[0] = c[1] = c[2] = c[3] = fill[0];
|
||||
} else if (fillType == GLPANEL_FILL_GRAD_X) {
|
||||
c[0] = c[1] = fill[0];
|
||||
c[2] = c[3] = fill[1];
|
||||
} else if (fillType == GLPANEL_FILL_GRAD_Y) {
|
||||
c[0] = c[3] = fill[0];
|
||||
c[1] = c[2] = fill[1];
|
||||
}
|
||||
|
||||
float clr[3 * 4] = {
|
||||
c[0].r, c[0].g, c[0].b,
|
||||
c[1].r, c[1].g, c[1].b,
|
||||
c[2].r, c[2].g, c[2].b,
|
||||
c[3].r, c[3].g, c[3].b
|
||||
};
|
||||
|
||||
glPoints.assign(pts, pts + (2 * 4));
|
||||
glColors.assign(clr, clr + (3 * 4));
|
||||
} else {
|
||||
glPoints.reserve(2 * 8);
|
||||
glPoints.resize(2 * 8);
|
||||
glColors.reserve(3 * 8);
|
||||
glColors.resize(3 * 8);
|
||||
|
||||
RGB3f c[8];
|
||||
|
||||
if (fillType == GLPANEL_FILL_GRAD_BAR_X) {
|
||||
float pts[2 * 8] = {
|
||||
min, min,
|
||||
min, max,
|
||||
mid, max,
|
||||
mid, min,
|
||||
|
||||
mid, min,
|
||||
mid, max,
|
||||
max, max,
|
||||
max, min
|
||||
};
|
||||
glPoints.assign(pts, pts + (2 * 8));
|
||||
|
||||
c[0] = c[1] = fill[0];
|
||||
c[2] = c[3] = fill[1];
|
||||
|
||||
c[4] = c[5] = fill[1];
|
||||
c[6] = c[7] = fill[0];
|
||||
|
||||
} else if (fillType == GLPANEL_FILL_GRAD_BAR_Y) {
|
||||
float pts[2 * 8] = {
|
||||
min, min,
|
||||
min, mid,
|
||||
max, mid,
|
||||
max, min,
|
||||
|
||||
min, mid,
|
||||
min, max,
|
||||
max, max,
|
||||
max, mid
|
||||
};
|
||||
glPoints.assign(pts, pts + (2 * 8));
|
||||
|
||||
c[0] = c[3] = fill[0];
|
||||
c[1] = c[2] = fill[1];
|
||||
|
||||
c[4] = c[7] = fill[1];
|
||||
c[5] = c[6] = fill[0];
|
||||
}
|
||||
|
||||
float clr[3 * 8] = {
|
||||
c[0].r, c[0].g, c[0].b,
|
||||
c[1].r, c[1].g, c[1].b,
|
||||
c[2].r, c[2].g, c[2].b,
|
||||
c[3].r, c[3].g, c[3].b,
|
||||
c[4].r, c[4].g, c[4].b,
|
||||
c[5].r, c[5].g, c[5].b,
|
||||
c[6].r, c[6].g, c[6].b,
|
||||
c[7].r, c[7].g, c[7].b
|
||||
};
|
||||
|
||||
glColors.assign(clr, clr + (3 * 8));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLPanel::setViewport() {
|
||||
GLint vp[4];
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
|
||||
view[0] = vp[2];
|
||||
view[1] = vp[3];
|
||||
}
|
||||
|
||||
void GLPanel::setPosition(float x, float y) {
|
||||
pos[0] = x;
|
||||
pos[1] = y;
|
||||
}
|
||||
|
||||
void GLPanel::setSize(float w, float h) {
|
||||
size[0] = w;
|
||||
size[1] = h;
|
||||
}
|
||||
|
||||
float GLPanel::getWidth() {
|
||||
return size[0];
|
||||
}
|
||||
|
||||
float GLPanel::getHeight() {
|
||||
return size[1];
|
||||
}
|
||||
|
||||
float GLPanel::getWidthPx() {
|
||||
return pdim.x;
|
||||
}
|
||||
|
||||
float GLPanel::getHeightPx() {
|
||||
return pdim.y;
|
||||
}
|
||||
|
||||
|
||||
void GLPanel::setCoordinateSystem(GLPanelCoordinateSystem coord_in) {
|
||||
coord = coord_in;
|
||||
|
||||
if (coord == GLPANEL_Y_DOWN || coord == GLPANEL_Y_UP) {
|
||||
min = -1;
|
||||
mid = 0;
|
||||
max = 1;
|
||||
} else {
|
||||
min = 0;
|
||||
mid = 0.5;
|
||||
max = 1;
|
||||
}
|
||||
|
||||
genArrays();
|
||||
}
|
||||
|
||||
void GLPanel::setFill(GLPanelFillType fill_mode) {
|
||||
fillType = fill_mode;
|
||||
genArrays();
|
||||
}
|
||||
|
||||
void GLPanel::setFillColor(RGB3f color1) {
|
||||
fill[0] = color1;
|
||||
genArrays();
|
||||
}
|
||||
|
||||
void GLPanel::setFillColor(RGB3f color1, RGB3f color2) {
|
||||
fill[0] = color1;
|
||||
fill[1] = color2;
|
||||
genArrays();
|
||||
}
|
||||
|
||||
void GLPanel::setMarginPx(float marg) {
|
||||
marginPx = marg;
|
||||
}
|
||||
|
||||
|
||||
void GLPanel::setBorderColor(RGB3f clr) {
|
||||
borderColor = clr;
|
||||
}
|
||||
|
||||
void GLPanel::setBorderPx(float bord) {
|
||||
borderPx.left = borderPx.right = borderPx.top = borderPx.bottom = bord;
|
||||
}
|
||||
|
||||
void GLPanel::setBorderPx(float bordl, float bordr, float bordt, float bordb) {
|
||||
borderPx.left = bordl;
|
||||
borderPx.right = bordr;
|
||||
borderPx.top = bordt;
|
||||
borderPx.bottom = bordb;
|
||||
}
|
||||
|
||||
void GLPanel::addChild(GLPanel *childPanel) {
|
||||
children.push_back(childPanel);
|
||||
}
|
||||
|
||||
void GLPanel::drawChildren() {
|
||||
if (children.size()) {
|
||||
std::vector<GLPanel *>::iterator panel_i;
|
||||
|
||||
for (panel_i = children.begin(); panel_i != children.end(); panel_i++) {
|
||||
(*panel_i)->calcTransform(transform);
|
||||
(*panel_i)->draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLPanel::drawPanelContents() {
|
||||
drawChildren();
|
||||
}
|
||||
|
||||
void GLPanel::calcTransform(mat4 transform_in) {
|
||||
// compute local transform
|
||||
localTransform = mat4::translate(pos[0], pos[1], 0) * mat4::scale(size[0], size[1], 1);
|
||||
// compute global transform
|
||||
transform = transform_in * localTransform;
|
||||
|
||||
// init view[]
|
||||
setViewport();
|
||||
|
||||
// get min/max transform
|
||||
vec4 vmin_t = mat4::vec4_multiply(vec4(min, min, 0, 1), transform);
|
||||
vec4 vmax_t = mat4::vec4_multiply(vec4(max, max, 0, 1), transform);
|
||||
|
||||
// screen dimensions
|
||||
vmin = vec2((vmin_t.x > vmax_t.x)?vmax_t.x:vmin_t.x, (vmin_t.y > vmax_t.y)?vmax_t.y:vmin_t.y);
|
||||
vmax = vec2((vmin_t.x > vmax_t.x)?vmin_t.x:vmax_t.x, (vmin_t.y > vmax_t.y)?vmin_t.y:vmax_t.y);
|
||||
|
||||
// unit dimensions
|
||||
umin = (vmin * 0.5) + vec2(1,1);
|
||||
umax = (vmax * 0.5) + vec2(1,1);
|
||||
|
||||
ucenter = vec2((umin + umax) * 0.5);
|
||||
|
||||
// pixel dimensions
|
||||
pdim = vec2((vmax.x - vmin.x) / 2.0 * view[0], (vmax.y - vmin.y) / 2.0 * view[1]);
|
||||
pvec = vec2(((vmax.x - vmin.x) / 2.0) / pdim.x, ((vmax.y - vmin.y) / 2.0) / pdim.y);
|
||||
|
||||
// std::cout << umin << " :: " << ucenter << " :: " << pdim << " :: " << pvec << std::endl;
|
||||
|
||||
if (marginPx) {
|
||||
transform *= mat4::scale(1.0 - marginPx * 2.0 * pvec.x / size[0], 1.0 - marginPx * 2.0 * pvec.y / size[1], 1);
|
||||
}
|
||||
}
|
||||
|
||||
void GLPanel::draw() {
|
||||
float min = -1.0, max = 1.0;
|
||||
|
||||
glLoadMatrixf(transform);
|
||||
|
||||
if (fillType != GLPANEL_FILL_NONE) {
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, &glPoints[0]);
|
||||
glColorPointer(3, GL_FLOAT, 0, &glColors[0]);
|
||||
|
||||
glDrawArrays(GL_QUADS, 0, glPoints.size() / 2);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
if (borderPx.left || borderPx.right || borderPx.top || borderPx.bottom) {
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glColor3f(borderColor.r, borderColor.g, borderColor.b);
|
||||
|
||||
if (borderPx.left) {
|
||||
glLineWidth(borderPx.left);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(min, min);
|
||||
glVertex2f(min, max);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if (borderPx.right) {
|
||||
glLineWidth(borderPx.right);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(max, min);
|
||||
glVertex2f(max, max);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if (borderPx.top) {
|
||||
glLineWidth(borderPx.top);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(min, min);
|
||||
glVertex2f(max, min);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if (borderPx.bottom) {
|
||||
glLineWidth(borderPx.bottom);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(min, max);
|
||||
glVertex2f(max, max);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
}
|
||||
}
|
||||
|
||||
if (contentsVisible) {
|
||||
mat4 mCoord = mat4::identity();
|
||||
|
||||
if (coord == GLPANEL_Y_DOWN_ZERO_ONE) {
|
||||
mCoord *= mat4::translate(-1.0f, 1.0f, 0.0f) * mat4::scale(2.0f, -2.0f, 2.0f);
|
||||
}
|
||||
if (coord == GLPANEL_Y_UP_ZERO_ONE) {
|
||||
mCoord = mat4::translate(-1.0f, -1.0f, 0.0f) * mat4::scale(2.0f, 2.0f, 2.0f);
|
||||
}
|
||||
if (coord == GLPANEL_Y_DOWN) {
|
||||
mCoord = mat4::scale(1.0f, -1.0f, 1.0f);
|
||||
}
|
||||
// if (coord == GLPANEL_Y_UP) {
|
||||
// }
|
||||
glLoadMatrixf(transform * mCoord);
|
||||
drawPanelContents();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLTextPanel::GLTextPanel() : GLPanel() {
|
||||
coord = GLPANEL_Y_UP;
|
||||
}
|
||||
|
||||
void GLTextPanel::drawPanelContents() {
|
||||
glColor4f(1, 1, 1, 1.0);
|
||||
|
||||
GLFont::GLFontSize sz;
|
||||
float size;
|
||||
|
||||
|
||||
if (pdim.y < 16) {
|
||||
sz = GLFont::GLFONT_SIZE12;
|
||||
size = 12;
|
||||
} else if (pdim.y < 18) {
|
||||
sz = GLFont::GLFONT_SIZE16;
|
||||
size = 16;
|
||||
} else if(pdim.y < 24) {
|
||||
sz = GLFont::GLFONT_SIZE18;
|
||||
size = 18;
|
||||
} else if(pdim.y < 32) {
|
||||
sz = GLFont::GLFONT_SIZE24;
|
||||
size = 24;
|
||||
} else if(pdim.y < 48) {
|
||||
sz = GLFont::GLFONT_SIZE32;
|
||||
size = 32;
|
||||
} else {
|
||||
sz = GLFont::GLFONT_SIZE48;
|
||||
size = 48;
|
||||
}
|
||||
|
||||
|
||||
GLFont::getFont(sz).drawString(textVal, mid, mid, size, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, (int)pdim.x, (int)pdim.y);
|
||||
}
|
||||
|
||||
void GLTextPanel::setText(std::string text) {
|
||||
textVal = text;
|
||||
}
|
||||
|
||||
std::string GLTextPanel::getText() {
|
||||
return textVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLTestPanel::drawPanelContents() {
|
||||
glColor3f(1.0,1.0,1.0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(min, mid);
|
||||
glVertex2f(max, mid);
|
||||
glVertex2f(mid, min);
|
||||
glVertex2f(mid, max);
|
||||
|
||||
glVertex2f(mid, max);
|
||||
glVertex2f(mid - 0.02, max - 0.2);
|
||||
glVertex2f(mid, 1);
|
||||
glVertex2f(mid + 0.02, max - 0.2);
|
||||
|
||||
glVertex2f(max, mid);
|
||||
glVertex2f(max - 0.1, mid + max * 0.25);
|
||||
glVertex2f(max, mid);
|
||||
glVertex2f(max - 0.1, mid - max * 0.25);
|
||||
|
||||
glEnd();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GLExt.h"
|
||||
#include "GLFont.h"
|
||||
#include "ColorTheme.h"
|
||||
#include "cubic_math.h"
|
||||
|
||||
class GLPanelEdges {
|
||||
public:
|
||||
float left;
|
||||
float right;
|
||||
float top;
|
||||
float bottom;
|
||||
|
||||
GLPanelEdges(): left(0), right(0), top(0), bottom(0) {
|
||||
}
|
||||
|
||||
GLPanelEdges(float l, float r, float t, float b) {
|
||||
left = l;
|
||||
right = r;
|
||||
top = t;
|
||||
bottom = b;
|
||||
}
|
||||
};
|
||||
|
||||
class GLPanel {
|
||||
private:
|
||||
std::vector<float> glPoints;
|
||||
std::vector<float> glColors;
|
||||
|
||||
void genArrays();
|
||||
void setViewport();
|
||||
|
||||
public:
|
||||
typedef enum GLPanelFillType { GLPANEL_FILL_NONE, GLPANEL_FILL_SOLID, GLPANEL_FILL_GRAD_X, GLPANEL_FILL_GRAD_Y, GLPANEL_FILL_GRAD_BAR_X, GLPANEL_FILL_GRAD_BAR_Y } GLPanelFillType;
|
||||
typedef enum GLPanelCoordinateSystem { GLPANEL_Y_DOWN_ZERO_ONE, GLPANEL_Y_UP_ZERO_ONE, GLPANEL_Y_UP, GLPANEL_Y_DOWN } GLPanelCoordinateSystem;
|
||||
float pos[2];
|
||||
float size[2];
|
||||
float view[2];
|
||||
GLPanelFillType fillType;
|
||||
GLPanelCoordinateSystem coord;
|
||||
float marginPx;
|
||||
GLPanelEdges borderPx;
|
||||
RGB3f fill[2];
|
||||
RGB3f borderColor;
|
||||
bool contentsVisible;
|
||||
CubicVR::mat4 transform;
|
||||
CubicVR::mat4 localTransform;
|
||||
float min, mid, max;
|
||||
// screen dimensions
|
||||
CubicVR::vec2 vmin, vmax;
|
||||
// unit dimensions
|
||||
CubicVR::vec2 umin, umax, ucenter;
|
||||
// pixel dimensions
|
||||
CubicVR::vec2 pdim, pvec;
|
||||
|
||||
std::vector<GLPanel *> children;
|
||||
|
||||
GLPanel();
|
||||
|
||||
void setPosition(float x, float y);
|
||||
void setSize(float w, float h);
|
||||
float getWidth();
|
||||
float getHeight();
|
||||
float getWidthPx();
|
||||
float getHeightPx();
|
||||
void setCoordinateSystem(GLPanelCoordinateSystem coord);
|
||||
|
||||
void setFill(GLPanelFillType fill_mode);
|
||||
void setFillColor(RGB3f color1);
|
||||
void setFillColor(RGB3f color1, RGB3f color2);
|
||||
void setMarginPx(float marg);
|
||||
|
||||
void setBorderColor(RGB3f clr);
|
||||
void setBorderPx(float bord);
|
||||
void setBorderPx(float bordl, float bordr, float bordt, float bordb);
|
||||
|
||||
void addChild(GLPanel *childPanel);
|
||||
|
||||
void drawChildren();
|
||||
virtual void drawPanelContents();
|
||||
void calcTransform(CubicVR::mat4 transform);
|
||||
void draw();
|
||||
};
|
||||
|
||||
|
||||
class GLTextPanel : public GLPanel {
|
||||
private:
|
||||
std::string textVal;
|
||||
public:
|
||||
GLTextPanel();
|
||||
|
||||
void drawPanelContents();
|
||||
void setText(std::string text);
|
||||
std::string getText();
|
||||
};
|
||||
|
||||
class GLTestPanel : public GLPanel {
|
||||
public:
|
||||
GLTestPanel() : GLPanel() {
|
||||
|
||||
}
|
||||
|
||||
void drawPanelContents();
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "UITestCanvas.h"
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/wx.h"
|
||||
#endif
|
||||
|
||||
#if !wxUSE_GLCANVAS
|
||||
#error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
|
||||
#endif
|
||||
|
||||
#include "CubicSDR.h"
|
||||
#include "CubicSDRDefs.h"
|
||||
#include "AppFrame.h"
|
||||
#include <algorithm>
|
||||
|
||||
wxBEGIN_EVENT_TABLE(UITestCanvas, wxGLCanvas) EVT_PAINT(UITestCanvas::OnPaint)
|
||||
EVT_IDLE(UITestCanvas::OnIdle)
|
||||
EVT_MOTION(UITestCanvas::OnMouseMoved)
|
||||
EVT_LEFT_DOWN(UITestCanvas::OnMouseDown)
|
||||
EVT_LEFT_UP(UITestCanvas::OnMouseReleased)
|
||||
EVT_LEAVE_WINDOW(UITestCanvas::OnMouseLeftWindow)
|
||||
EVT_ENTER_WINDOW(UITestCanvas::OnMouseEnterWindow)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
UITestCanvas::UITestCanvas(wxWindow *parent, int *attribList) :
|
||||
InteractiveCanvas(parent, attribList) {
|
||||
|
||||
glContext = new UITestContext(this, &wxGetApp().GetContext(this));
|
||||
}
|
||||
|
||||
UITestCanvas::~UITestCanvas() {
|
||||
|
||||
}
|
||||
|
||||
void UITestCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
|
||||
glContext->SetCurrent(*this);
|
||||
initGLExtensions();
|
||||
|
||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||
|
||||
glContext->DrawBegin();
|
||||
|
||||
glContext->Draw();
|
||||
|
||||
glContext->DrawEnd();
|
||||
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
void UITestCanvas::OnIdle(wxIdleEvent &event) {
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
void UITestCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseMoved(event);
|
||||
|
||||
}
|
||||
|
||||
void UITestCanvas::OnMouseDown(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseDown(event);
|
||||
}
|
||||
|
||||
void UITestCanvas::OnMouseWheelMoved(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseWheelMoved(event);
|
||||
}
|
||||
|
||||
void UITestCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseReleased(event);
|
||||
}
|
||||
|
||||
void UITestCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseLeftWindow(event);
|
||||
}
|
||||
|
||||
void UITestCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
||||
InteractiveCanvas::mouseTracker.OnMouseEnterWindow(event);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "wx/glcanvas.h"
|
||||
#include "wx/timer.h"
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include "InteractiveCanvas.h"
|
||||
#include "UITestContext.h"
|
||||
#include "MouseTracker.h"
|
||||
|
||||
#include "fftw3.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class UITestCanvas: public InteractiveCanvas {
|
||||
public:
|
||||
UITestCanvas(wxWindow *parent, int *attribList = NULL);
|
||||
~UITestCanvas();
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnIdle(wxIdleEvent &event);
|
||||
|
||||
void OnMouseMoved(wxMouseEvent& event);
|
||||
void OnMouseDown(wxMouseEvent& event);
|
||||
void OnMouseWheelMoved(wxMouseEvent& event);
|
||||
void OnMouseReleased(wxMouseEvent& event);
|
||||
void OnMouseEnterWindow(wxMouseEvent& event);
|
||||
void OnMouseLeftWindow(wxMouseEvent& event);
|
||||
|
||||
UITestContext *glContext;
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "UITestContext.h"
|
||||
#include "UITestCanvas.h"
|
||||
#include "ColorTheme.h"
|
||||
|
||||
UITestContext::UITestContext(UITestCanvas *canvas, wxGLContext *sharedContext) :
|
||||
PrimaryGLContext(canvas, sharedContext) {
|
||||
|
||||
testPanel.setPosition(0.0, 0.0);
|
||||
testPanel.setSize(1.0, 1.0);
|
||||
testPanel.setMarginPx(10);
|
||||
testPanel.setFill(GLPanel::GLPANEL_FILL_GRAD_BAR_Y);
|
||||
testPanel.setFillColor(RGB3f(0.0,0.0,1.0), RGB3f(0.0,1.0,0.0));
|
||||
|
||||
testChildPanel.setPosition(0.0, 0.0);
|
||||
testChildPanel.setMarginPx(5);
|
||||
testChildPanel.setSize(1.0, 0.33);
|
||||
testChildPanel.setCoordinateSystem(GLPanel::GLPANEL_Y_DOWN_ZERO_ONE);
|
||||
testChildPanel.setFill(GLPanel::GLPANEL_FILL_GRAD_BAR_X);
|
||||
testChildPanel.setFillColor(RGB3f(0.0,0.0,1.0), RGB3f(0.0,1.0,0.0));
|
||||
testChildPanel.setBorderPx(1);
|
||||
|
||||
testChildPanel2.setPosition(0.0, -0.66);
|
||||
testChildPanel2.setSize(1.0, 0.33);
|
||||
testChildPanel2.setMarginPx(5);
|
||||
testChildPanel2.setFill(GLPanel::GLPANEL_FILL_GRAD_X);
|
||||
testChildPanel2.setFillColor(RGB3f(0.0,0.0,1.0), RGB3f(0.0,1.0,0.0));
|
||||
testChildPanel2.setBorderColor(RGB3f(1.0,0.0,0.0));
|
||||
testChildPanel2.setBorderPx(1);
|
||||
|
||||
testChildPanel3.setPosition(0.0, 0.66);
|
||||
testChildPanel3.setSize(1.0, 0.33);
|
||||
testChildPanel3.setMarginPx(5);
|
||||
testChildPanel3.setFill(GLPanel::GLPANEL_FILL_GRAD_X);
|
||||
testChildPanel3.setFillColor(RGB3f(0.0,0.0,1.0), RGB3f(0.0,1.0,0.0));
|
||||
testChildPanel3.setBorderColor(RGB3f(1.0,0.0,0.0));
|
||||
testChildPanel3.setBorderPx(1);
|
||||
|
||||
testText1.setText("Testing 123..");
|
||||
testText1.setFill(GLPanel::GLPANEL_FILL_NONE);
|
||||
testChildPanel2.addChild(&testText1);
|
||||
|
||||
testPanel.addChild(&testChildPanel);
|
||||
testPanel.addChild(&testChildPanel2);
|
||||
testPanel.addChild(&testChildPanel3);
|
||||
}
|
||||
|
||||
void UITestContext::DrawBegin() {
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glClearColor(ThemeMgr::mgr.currentTheme->generalBackground.r, ThemeMgr::mgr.currentTheme->generalBackground.g, ThemeMgr::mgr.currentTheme->generalBackground.b, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void UITestContext::Draw() {
|
||||
testPanel.calcTransform(CubicVR::mat4::identity());
|
||||
testPanel.draw();
|
||||
}
|
||||
|
||||
void UITestContext::DrawEnd() {
|
||||
glFlush();
|
||||
|
||||
CheckGLError();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "PrimaryGLContext.h"
|
||||
#include "GLPanel.h"
|
||||
|
||||
class UITestCanvas;
|
||||
|
||||
class UITestContext: public PrimaryGLContext {
|
||||
public:
|
||||
UITestContext(UITestCanvas *canvas, wxGLContext *sharedContext);
|
||||
|
||||
void DrawBegin();
|
||||
void Draw();
|
||||
void DrawEnd();
|
||||
|
||||
private:
|
||||
GLPanel testPanel;
|
||||
GLTestPanel testChildPanel;
|
||||
GLPanel testChildPanel2;
|
||||
GLPanel testChildPanel3;
|
||||
GLTextPanel testText1;
|
||||
};
|
||||
@@ -1598,8 +1598,8 @@ bool DataTree::LoadFromFile(const std::string& filename) {
|
||||
string compressionType(*header->getNext("compression"));
|
||||
dataSize = *header->getNext("uncompressed_size");
|
||||
|
||||
bool uncompress = false;
|
||||
#if USE_FASTLZ
|
||||
bool uncompress = false;
|
||||
if (compressionType == "FastLZ") {
|
||||
uncompress = true;
|
||||
}
|
||||
|
||||
+2
-3
@@ -36,7 +36,7 @@ void initGLExtensions() {
|
||||
|
||||
std::cout << std::endl << "Supported GL Extensions: " << std::endl << extensions << std::endl << std::endl;
|
||||
|
||||
int interval = 2;
|
||||
const GLint interval = 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (GLExtSupported("WGL_EXT_swap_control")) {
|
||||
@@ -50,8 +50,7 @@ void initGLExtensions() {
|
||||
|
||||
#ifdef __APPLE__
|
||||
// OSX is just ON / OFF
|
||||
const GLint gl_interval = 1;
|
||||
CGLSetParameter (CGLGetCurrentContext(), kCGLCPSwapInterval, &gl_interval);
|
||||
CGLSetParameter (CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
+49
-7
@@ -8,6 +8,9 @@
|
||||
#define RES_FOLDER ""
|
||||
#endif
|
||||
|
||||
|
||||
GLFont GLFont::fonts[GLFONT_MAX];
|
||||
|
||||
GLFontChar::GLFontChar() :
|
||||
id(0), x(0), y(0), width(0), height(0), xoffset(0), yoffset(0), xadvance(0), aspect(1), index(0) {
|
||||
|
||||
@@ -100,7 +103,7 @@ int GLFontChar::getIndex() {
|
||||
}
|
||||
|
||||
GLFont::GLFont() :
|
||||
numCharacters(0), lineHeight(0), base(0), imageWidth(0), imageHeight(0), loaded(false), texId(0) {
|
||||
lineHeight(0), base(0), imageWidth(0), imageHeight(0), loaded(false), texId(0) {
|
||||
|
||||
}
|
||||
|
||||
@@ -394,16 +397,20 @@ float GLFont::getStringWidth(std::string str, float size, float viewAspect) {
|
||||
return width;
|
||||
}
|
||||
|
||||
void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign, Align vAlign) {
|
||||
void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign, Align vAlign, int vpx, int vpy) {
|
||||
|
||||
GLint vp[4];
|
||||
|
||||
pxHeight *= 2;
|
||||
|
||||
glGetIntegerv( GL_VIEWPORT, vp);
|
||||
|
||||
float size = (float) pxHeight / (float) vp[3];
|
||||
float viewAspect = (float) vp[2] / (float) vp[3];
|
||||
if (!vpx || !vpy) {
|
||||
GLint vp[4];
|
||||
glGetIntegerv( GL_VIEWPORT, vp);
|
||||
vpx = vp[2];
|
||||
vpy = vp[3];
|
||||
}
|
||||
|
||||
float size = (float) pxHeight / (float) vpy;
|
||||
float viewAspect = (float) vpx / (float) vpy;
|
||||
float msgWidth = getStringWidth(str, size, viewAspect);
|
||||
|
||||
glPushMatrix();
|
||||
@@ -475,3 +482,38 @@ void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, A
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLFont &GLFont::getFont(GLFontSize esize) {
|
||||
if (!fonts[esize].isLoaded()) {
|
||||
|
||||
std::string fontName;
|
||||
switch (esize) {
|
||||
case GLFONT_SIZE12:
|
||||
fontName = "vera_sans_mono12.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE16:
|
||||
fontName = "vera_sans_mono16.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE18:
|
||||
fontName = "vera_sans_mono18.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE24:
|
||||
fontName = "vera_sans_mono24.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE32:
|
||||
fontName = "vera_sans_mono32.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE48:
|
||||
fontName = "vera_sans_mono48.fnt";
|
||||
break;
|
||||
default:
|
||||
fontName = "vera_sans_mono12.fnt";
|
||||
break;
|
||||
}
|
||||
|
||||
fonts[esize].loadFont(fontName);
|
||||
}
|
||||
|
||||
return fonts[esize];
|
||||
}
|
||||
|
||||
+7
-2
@@ -56,6 +56,9 @@ public:
|
||||
enum Align {
|
||||
GLFONT_ALIGN_LEFT, GLFONT_ALIGN_RIGHT, GLFONT_ALIGN_CENTER, GLFONT_ALIGN_TOP, GLFONT_ALIGN_BOTTOM
|
||||
};
|
||||
enum GLFontSize {
|
||||
GLFONT_SIZE12, GLFONT_SIZE16, GLFONT_SIZE18, GLFONT_SIZE24, GLFONT_SIZE32, GLFONT_SIZE48, GLFONT_MAX
|
||||
};
|
||||
|
||||
GLFont();
|
||||
~GLFont();
|
||||
@@ -63,14 +66,16 @@ public:
|
||||
bool isLoaded();
|
||||
|
||||
float getStringWidth(std::string str, float size, float viewAspect);
|
||||
void drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP);
|
||||
void drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx=0, int vpy=0);
|
||||
|
||||
static GLFont fonts[GLFONT_MAX];
|
||||
static GLFont &getFont(GLFontSize esize);
|
||||
|
||||
private:
|
||||
std::string nextParam(std::istringstream &str);
|
||||
std::string getParamKey(std::string param_str);
|
||||
std::string getParamValue(std::string param_str);
|
||||
|
||||
int numCharacters;
|
||||
int lineHeight;
|
||||
int base;
|
||||
int imageWidth, imageHeight;
|
||||
|
||||
+14
-1
@@ -15,9 +15,13 @@
|
||||
#include <cstdint>
|
||||
#include <condition_variable>
|
||||
|
||||
class ThreadQueueBase {
|
||||
|
||||
};
|
||||
|
||||
/** A thread-safe asynchronous queue */
|
||||
template<class T, class Container = std::list<T>>
|
||||
class ThreadQueue {
|
||||
class ThreadQueue : public ThreadQueueBase {
|
||||
|
||||
typedef typename Container::value_type value_type;
|
||||
typedef typename Container::size_type size_type;
|
||||
@@ -207,6 +211,15 @@ public:
|
||||
return m_queue.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the queue is full.
|
||||
* \return true if queue is full.
|
||||
*/
|
||||
bool full() const {
|
||||
std::lock_guard < std::mutex > lock(m_mutex);
|
||||
return (m_max_num_items != 0) && (m_queue.size() >= m_max_num_items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any items in the queue.
|
||||
*/
|
||||
|
||||
+140
-140
@@ -41,27 +41,27 @@ DefaultColorTheme::DefaultColorTheme() {
|
||||
waterfallGradient.addColor(GradientColor(1.0, 1.0, 0));
|
||||
waterfallGradient.addColor(GradientColor(1.0, 0.2, 0.0));
|
||||
waterfallGradient.generate(256);
|
||||
waterfallHighlight = RGBColor(1, 1, 1);
|
||||
waterfallNew = RGBColor(0, 1, 0);
|
||||
waterfallHover = RGBColor(1, 1, 0);
|
||||
waterfallDestroy = RGBColor(1, 0, 0);
|
||||
fftLine = RGBColor(0.9, 0.9, 0.9);
|
||||
fftHighlight = RGBColor(1, 1, 1);
|
||||
scopeLine = RGBColor(0.9, 0.9, 0.9);
|
||||
tuningBarLight = RGBColor(0.2, 0.2, 0.9);
|
||||
tuningBarDark = RGBColor(0.0, 0.0, 0.35);
|
||||
tuningBarUp = RGBColor(1.0, 139.0/255.0, 96.0/255.0);
|
||||
tuningBarDown = RGBColor(148.0/255.0, 148.0/255.0, 1.0);
|
||||
meterLevel = RGBColor(0.1, 0.75, 0.1);
|
||||
meterValue = RGBColor(0.75, 0.1, 0.1);
|
||||
text = RGBColor(1, 1, 1);
|
||||
freqLine = RGBColor(1, 1, 1);
|
||||
button = RGBColor(0.65, 0.65, 0.65);
|
||||
buttonHighlight = RGBColor(1, 1, 0);
|
||||
waterfallHighlight = RGB3f(1, 1, 1);
|
||||
waterfallNew = RGB3f(0, 1, 0);
|
||||
waterfallHover = RGB3f(1, 1, 0);
|
||||
waterfallDestroy = RGB3f(1, 0, 0);
|
||||
fftLine = RGB3f(0.9, 0.9, 0.9);
|
||||
fftHighlight = RGB3f(1, 1, 1);
|
||||
scopeLine = RGB3f(0.9, 0.9, 0.9);
|
||||
tuningBarLight = RGB3f(0.2, 0.2, 0.9);
|
||||
tuningBarDark = RGB3f(0.0, 0.0, 0.35);
|
||||
tuningBarUp = RGB3f(1.0, 139.0/255.0, 96.0/255.0);
|
||||
tuningBarDown = RGB3f(148.0/255.0, 148.0/255.0, 1.0);
|
||||
meterLevel = RGB3f(0.1, 0.75, 0.1);
|
||||
meterValue = RGB3f(0.75, 0.1, 0.1);
|
||||
text = RGB3f(1, 1, 1);
|
||||
freqLine = RGB3f(1, 1, 1);
|
||||
button = RGB3f(0.65, 0.65, 0.65);
|
||||
buttonHighlight = RGB3f(1, 1, 0);
|
||||
|
||||
scopeBackground = RGBColor(0.1, 0.1, 0.1);
|
||||
fftBackground = RGBColor(0.1, 0.1, 0.1);
|
||||
generalBackground = RGBColor(0.1, 0.1, 0.1);
|
||||
scopeBackground = RGB3f(0.1, 0.1, 0.1);
|
||||
fftBackground = RGB3f(0.1, 0.1, 0.1);
|
||||
generalBackground = RGB3f(0.1, 0.1, 0.1);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,27 +72,27 @@ RadarColorTheme::RadarColorTheme() {
|
||||
waterfallGradient.addColor(GradientColor(40.0 / 255.0, 240.0 / 255.0, 60.0 / 255.0));
|
||||
waterfallGradient.addColor(GradientColor(250.0 / 255.0, 250.0 / 255.0, 250.0 / 255.0));
|
||||
waterfallGradient.generate(256);
|
||||
waterfallHighlight = RGBColor(1, 1, 1);
|
||||
waterfallNew = RGBColor(0, 1, 0);
|
||||
waterfallHover = RGBColor(1, 1, 0);
|
||||
waterfallDestroy = RGBColor(1, 0, 0);
|
||||
fftLine = RGBColor(0.8, 1.0, 0.8);
|
||||
fftHighlight = RGBColor(1, 1, 1);
|
||||
scopeLine = RGBColor(0.8, 1.0, 0.8);
|
||||
tuningBarLight = RGBColor(0.0, 0.45, 0.0);
|
||||
tuningBarDark = RGBColor(0.0, 0.1, 0.0);
|
||||
tuningBarUp = RGBColor(1.0, 139.0/255.0, 96.0/255.0);
|
||||
tuningBarDown = RGBColor(148.0/255.0, 0.0, 0.0);
|
||||
meterLevel = RGBColor(0, 0.5, 0);
|
||||
meterValue = RGBColor(0, 0.5, 0);
|
||||
text = RGBColor(0.8, 1.0, 0.8);
|
||||
freqLine = RGBColor(1, 1, 1);
|
||||
button = RGBColor(0.65, 0.75, 0.65);
|
||||
buttonHighlight = RGBColor(0.65, 1.0, 0.65);
|
||||
waterfallHighlight = RGB3f(1, 1, 1);
|
||||
waterfallNew = RGB3f(0, 1, 0);
|
||||
waterfallHover = RGB3f(1, 1, 0);
|
||||
waterfallDestroy = RGB3f(1, 0, 0);
|
||||
fftLine = RGB3f(0.8, 1.0, 0.8);
|
||||
fftHighlight = RGB3f(1, 1, 1);
|
||||
scopeLine = RGB3f(0.8, 1.0, 0.8);
|
||||
tuningBarLight = RGB3f(0.0, 0.45, 0.0);
|
||||
tuningBarDark = RGB3f(0.0, 0.1, 0.0);
|
||||
tuningBarUp = RGB3f(1.0, 139.0/255.0, 96.0/255.0);
|
||||
tuningBarDown = RGB3f(148.0/255.0, 0.0, 0.0);
|
||||
meterLevel = RGB3f(0, 0.5, 0);
|
||||
meterValue = RGB3f(0, 0.5, 0);
|
||||
text = RGB3f(0.8, 1.0, 0.8);
|
||||
freqLine = RGB3f(1, 1, 1);
|
||||
button = RGB3f(0.65, 0.75, 0.65);
|
||||
buttonHighlight = RGB3f(0.65, 1.0, 0.65);
|
||||
|
||||
scopeBackground = RGBColor(0.05, 0.1, 0.05);
|
||||
fftBackground = RGBColor(0.05, 0.1, 0.05);
|
||||
generalBackground = RGBColor(0.05, 0.1, 0.05);
|
||||
scopeBackground = RGB3f(0.05, 0.1, 0.05);
|
||||
fftBackground = RGB3f(0.05, 0.1, 0.05);
|
||||
generalBackground = RGB3f(0.05, 0.1, 0.05);
|
||||
}
|
||||
|
||||
BlackAndWhiteColorTheme::BlackAndWhiteColorTheme() {
|
||||
@@ -101,27 +101,27 @@ BlackAndWhiteColorTheme::BlackAndWhiteColorTheme() {
|
||||
waterfallGradient.addColor(GradientColor(0.75, 0.75, 0.75));
|
||||
waterfallGradient.addColor(GradientColor(1.0, 1.0, 1.0));
|
||||
waterfallGradient.generate(256);
|
||||
waterfallHighlight = RGBColor(1, 1, 0.9);
|
||||
waterfallNew = RGBColor(0, 1, 0);
|
||||
waterfallHover = RGBColor(1, 1, 0);
|
||||
waterfallDestroy = RGBColor(1, 0, 0);
|
||||
fftLine = RGBColor(0.9, 0.9, 0.9);
|
||||
fftHighlight = RGBColor(1, 1, 0.9);
|
||||
scopeLine = RGBColor(0.9, 0.9, 0.9);
|
||||
tuningBarLight = RGBColor(0.4, 0.4, 0.4);
|
||||
tuningBarDark = RGBColor(0.1, 0.1, 0.1);
|
||||
tuningBarUp = RGBColor(0.8, 0.8, 0.8);
|
||||
tuningBarDown = RGBColor(0.4, 0.4, 0.4);
|
||||
meterLevel = RGBColor(0.5, 0.5, 0.5);
|
||||
meterValue = RGBColor(0.5, 0.5, 0.5);
|
||||
text = RGBColor(1, 1, 1);
|
||||
freqLine = RGBColor(1, 1, 1);
|
||||
button = RGBColor(0.65, 0.65, 0.65);
|
||||
buttonHighlight = RGBColor(1, 1, 1);
|
||||
waterfallHighlight = RGB3f(1, 1, 0.9);
|
||||
waterfallNew = RGB3f(0, 1, 0);
|
||||
waterfallHover = RGB3f(1, 1, 0);
|
||||
waterfallDestroy = RGB3f(1, 0, 0);
|
||||
fftLine = RGB3f(0.9, 0.9, 0.9);
|
||||
fftHighlight = RGB3f(1, 1, 0.9);
|
||||
scopeLine = RGB3f(0.9, 0.9, 0.9);
|
||||
tuningBarLight = RGB3f(0.4, 0.4, 0.4);
|
||||
tuningBarDark = RGB3f(0.1, 0.1, 0.1);
|
||||
tuningBarUp = RGB3f(0.8, 0.8, 0.8);
|
||||
tuningBarDown = RGB3f(0.4, 0.4, 0.4);
|
||||
meterLevel = RGB3f(0.5, 0.5, 0.5);
|
||||
meterValue = RGB3f(0.5, 0.5, 0.5);
|
||||
text = RGB3f(1, 1, 1);
|
||||
freqLine = RGB3f(1, 1, 1);
|
||||
button = RGB3f(0.65, 0.65, 0.65);
|
||||
buttonHighlight = RGB3f(1, 1, 1);
|
||||
|
||||
scopeBackground = RGBColor(0.1, 0.1, 0.1);
|
||||
fftBackground = RGBColor(0.1, 0.1, 0.1);
|
||||
generalBackground = RGBColor(0.1, 0.1, 0.1);
|
||||
scopeBackground = RGB3f(0.1, 0.1, 0.1);
|
||||
fftBackground = RGB3f(0.1, 0.1, 0.1);
|
||||
generalBackground = RGB3f(0.1, 0.1, 0.1);
|
||||
|
||||
}
|
||||
|
||||
@@ -139,27 +139,27 @@ SharpColorTheme::SharpColorTheme() {
|
||||
waterfallGradient.addColor(GradientColor(1.0, 0.25, 0.0));
|
||||
waterfallGradient.addColor(GradientColor(0.5, 0.1, 0.0));
|
||||
waterfallGradient.generate(256);
|
||||
waterfallHighlight = RGBColor(0.9, 0.9, 1.0);
|
||||
waterfallNew = RGBColor(0, 1, 0);
|
||||
waterfallHover = RGBColor(1, 1, 0);
|
||||
waterfallDestroy = RGBColor(1, 0, 0);
|
||||
fftLine = RGBColor(0.9, 0.9, 1.0);
|
||||
fftHighlight = RGBColor(0.9, 0.9, 1.0);
|
||||
scopeLine = RGBColor(0.85, 0.85, 1.0);
|
||||
tuningBarLight = RGBColor(28.0 / 255.0, 106.0 / 255.0, 179.0 / 255.0);
|
||||
tuningBarDark = RGBColor(14.0 / 255.0, 53.0 / 255.0, 89.5 / 255.0);
|
||||
tuningBarUp = RGBColor(0.7, 0.7, 0.7);
|
||||
tuningBarDown = RGBColor(1.0, 0.0, 0.0);
|
||||
meterLevel = RGBColor(28.0 / 255.0, 106.0 / 255.0, 179.0 / 255.0);
|
||||
meterValue = RGBColor(190.0 / 255.0, 190.0 / 255.0, 60.0 / 255.0);
|
||||
text = RGBColor(0.9, 0.9, 1);
|
||||
freqLine = RGBColor(0.85, 0.85, 1.0);
|
||||
button = RGBColor(217.0 / 255.0, 218.0 / 255.0, 228.0 / 255.0);
|
||||
buttonHighlight = RGBColor(208.0 / 255.0, 249.0 / 255.0, 255.0 / 255.0);
|
||||
waterfallHighlight = RGB3f(0.9, 0.9, 1.0);
|
||||
waterfallNew = RGB3f(0, 1, 0);
|
||||
waterfallHover = RGB3f(1, 1, 0);
|
||||
waterfallDestroy = RGB3f(1, 0, 0);
|
||||
fftLine = RGB3f(0.9, 0.9, 1.0);
|
||||
fftHighlight = RGB3f(0.9, 0.9, 1.0);
|
||||
scopeLine = RGB3f(0.85, 0.85, 1.0);
|
||||
tuningBarLight = RGB3f(28.0 / 255.0, 106.0 / 255.0, 179.0 / 255.0);
|
||||
tuningBarDark = RGB3f(14.0 / 255.0, 53.0 / 255.0, 89.5 / 255.0);
|
||||
tuningBarUp = RGB3f(0.7, 0.7, 0.7);
|
||||
tuningBarDown = RGB3f(1.0, 0.0, 0.0);
|
||||
meterLevel = RGB3f(28.0 / 255.0, 106.0 / 255.0, 179.0 / 255.0);
|
||||
meterValue = RGB3f(190.0 / 255.0, 190.0 / 255.0, 60.0 / 255.0);
|
||||
text = RGB3f(0.9, 0.9, 1);
|
||||
freqLine = RGB3f(0.85, 0.85, 1.0);
|
||||
button = RGB3f(217.0 / 255.0, 218.0 / 255.0, 228.0 / 255.0);
|
||||
buttonHighlight = RGB3f(208.0 / 255.0, 249.0 / 255.0, 255.0 / 255.0);
|
||||
|
||||
scopeBackground = RGBColor(0.05, 0.05, 0.15);
|
||||
fftBackground = RGBColor(0.05, 0.05, 0.15);
|
||||
generalBackground = RGBColor(0.05, 0.05, 0.15);
|
||||
scopeBackground = RGB3f(0.05, 0.05, 0.15);
|
||||
fftBackground = RGB3f(0.05, 0.05, 0.15);
|
||||
generalBackground = RGB3f(0.05, 0.05, 0.15);
|
||||
}
|
||||
|
||||
RadColorTheme::RadColorTheme() {
|
||||
@@ -170,27 +170,27 @@ RadColorTheme::RadColorTheme() {
|
||||
waterfallGradient.addColor(GradientColor(1.0, 40.0 / 255.0, 40.0 / 255.0));
|
||||
waterfallGradient.addColor(GradientColor(1.0, 1.0, 1.0));
|
||||
waterfallGradient.generate(256);
|
||||
waterfallHighlight = RGBColor(1, 1, 1);
|
||||
waterfallNew = RGBColor(0, 1, 0);
|
||||
waterfallHover = RGBColor(1, 1, 0);
|
||||
waterfallDestroy = RGBColor(1, 0, 0);
|
||||
fftLine = RGBColor(1.0, 0.9, 0.9);
|
||||
fftHighlight = RGBColor(1, 1, 1);
|
||||
scopeLine = RGBColor(1.0, 0.9, 0.9);
|
||||
tuningBarLight = RGBColor(0.0, 0.45, 0.0);
|
||||
tuningBarDark = RGBColor(0.0, 0.1, 0.0);
|
||||
tuningBarUp = RGBColor(1.0, 0.0, 0.0);
|
||||
tuningBarDown = RGBColor(0.0, 0.5, 1.0);
|
||||
meterLevel = RGBColor(0, 0.5, 0);
|
||||
meterValue = RGBColor(0.5, 0, 0);
|
||||
text = RGBColor(1, 1, 1);
|
||||
freqLine = RGBColor(1, 1, 1);
|
||||
button = RGBColor(0.65, 0.65, 0.65);
|
||||
buttonHighlight = RGBColor(0.76, 0.65, 0);
|
||||
waterfallHighlight = RGB3f(1, 1, 1);
|
||||
waterfallNew = RGB3f(0, 1, 0);
|
||||
waterfallHover = RGB3f(1, 1, 0);
|
||||
waterfallDestroy = RGB3f(1, 0, 0);
|
||||
fftLine = RGB3f(1.0, 0.9, 0.9);
|
||||
fftHighlight = RGB3f(1, 1, 1);
|
||||
scopeLine = RGB3f(1.0, 0.9, 0.9);
|
||||
tuningBarLight = RGB3f(0.0, 0.45, 0.0);
|
||||
tuningBarDark = RGB3f(0.0, 0.1, 0.0);
|
||||
tuningBarUp = RGB3f(1.0, 0.0, 0.0);
|
||||
tuningBarDown = RGB3f(0.0, 0.5, 1.0);
|
||||
meterLevel = RGB3f(0, 0.5, 0);
|
||||
meterValue = RGB3f(0.5, 0, 0);
|
||||
text = RGB3f(1, 1, 1);
|
||||
freqLine = RGB3f(1, 1, 1);
|
||||
button = RGB3f(0.65, 0.65, 0.65);
|
||||
buttonHighlight = RGB3f(0.76, 0.65, 0);
|
||||
|
||||
scopeBackground = RGBColor(13.0 / 255.0, 47.0 / 255.0, 9.0 / 255.0);
|
||||
fftBackground = RGBColor(0, 0, 50.0 / 255.0);
|
||||
generalBackground = RGBColor(13.0 / 255.0, 47.0 / 255.0, 9.0 / 255.0);
|
||||
scopeBackground = RGB3f(13.0 / 255.0, 47.0 / 255.0, 9.0 / 255.0);
|
||||
fftBackground = RGB3f(0, 0, 50.0 / 255.0);
|
||||
generalBackground = RGB3f(13.0 / 255.0, 47.0 / 255.0, 9.0 / 255.0);
|
||||
}
|
||||
|
||||
TouchColorTheme::TouchColorTheme() {
|
||||
@@ -204,27 +204,27 @@ TouchColorTheme::TouchColorTheme() {
|
||||
waterfallGradient.addColor(GradientColor(255.0 / 255.0, 0.0 / 255.0, 0.0 / 255.0));
|
||||
waterfallGradient.addColor(GradientColor(255.0 / 255.0, 255.0 / 255.0, 255.0 / 255.0));
|
||||
waterfallGradient.generate(256);
|
||||
waterfallHighlight = RGBColor(1, 1, 1);
|
||||
waterfallNew = RGBColor(0, 1, 0);
|
||||
waterfallHover = RGBColor(1, 1, 0);
|
||||
waterfallDestroy = RGBColor(1, 0, 0);
|
||||
fftLine = RGBColor(234.0 / 255.0, 232.0 / 255.0, 247.0 / 255.0);
|
||||
fftHighlight = RGBColor(1.0, 1.0, 1.0);
|
||||
scopeLine = RGBColor(234.0 / 255.0, 232.0 / 255.0, 247.0 / 255.0);
|
||||
tuningBarLight = RGBColor(0.2, 0.2, 0.7);
|
||||
tuningBarDark = RGBColor(0.1, 0.1, 0.45);
|
||||
tuningBarUp = RGBColor(0.5, 139.0/255.0, 96.0/255.0);
|
||||
tuningBarDown = RGBColor(0.6, 108.0/255.0, 1.0);
|
||||
meterLevel = RGBColor(61.0 / 255.0, 57.0 / 255.0, 88.0 / 255.0);
|
||||
meterValue = RGBColor(61.0 / 255.0, 57.0 / 255.0, 88.0 / 255.0);
|
||||
text = RGBColor(1, 1, 1);
|
||||
freqLine = RGBColor(1, 1, 1);
|
||||
button = RGBColor(1.0, 1.0, 1.0);
|
||||
buttonHighlight = RGBColor(208.0 / 255.0, 202.0 / 255.0, 247.0 / 255.0);
|
||||
waterfallHighlight = RGB3f(1, 1, 1);
|
||||
waterfallNew = RGB3f(0, 1, 0);
|
||||
waterfallHover = RGB3f(1, 1, 0);
|
||||
waterfallDestroy = RGB3f(1, 0, 0);
|
||||
fftLine = RGB3f(234.0 / 255.0, 232.0 / 255.0, 247.0 / 255.0);
|
||||
fftHighlight = RGB3f(1.0, 1.0, 1.0);
|
||||
scopeLine = RGB3f(234.0 / 255.0, 232.0 / 255.0, 247.0 / 255.0);
|
||||
tuningBarLight = RGB3f(0.2, 0.2, 0.7);
|
||||
tuningBarDark = RGB3f(0.1, 0.1, 0.45);
|
||||
tuningBarUp = RGB3f(0.5, 139.0/255.0, 96.0/255.0);
|
||||
tuningBarDown = RGB3f(0.6, 108.0/255.0, 1.0);
|
||||
meterLevel = RGB3f(61.0 / 255.0, 57.0 / 255.0, 88.0 / 255.0);
|
||||
meterValue = RGB3f(61.0 / 255.0, 57.0 / 255.0, 88.0 / 255.0);
|
||||
text = RGB3f(1, 1, 1);
|
||||
freqLine = RGB3f(1, 1, 1);
|
||||
button = RGB3f(1.0, 1.0, 1.0);
|
||||
buttonHighlight = RGB3f(208.0 / 255.0, 202.0 / 255.0, 247.0 / 255.0);
|
||||
|
||||
scopeBackground = RGBColor(39.0 / 255.0, 36.0 / 255.0, 56.0 / 255.0);
|
||||
fftBackground = RGBColor(39.0 / 255.0, 36.0 / 255.0, 56.0 / 255.0);
|
||||
generalBackground = RGBColor(61.0 / 255.0, 57.0 / 255.0, 88.0 / 255.0);
|
||||
scopeBackground = RGB3f(39.0 / 255.0, 36.0 / 255.0, 56.0 / 255.0);
|
||||
fftBackground = RGB3f(39.0 / 255.0, 36.0 / 255.0, 56.0 / 255.0);
|
||||
generalBackground = RGB3f(61.0 / 255.0, 57.0 / 255.0, 88.0 / 255.0);
|
||||
|
||||
}
|
||||
|
||||
@@ -239,27 +239,27 @@ HDColorTheme::HDColorTheme() {
|
||||
waterfallGradient.addColor(GradientColor(255.0 / 255.0, 235.0 / 255.0, 100.0 / 255.0));
|
||||
waterfallGradient.addColor(GradientColor(250.0 / 255.0, 250.0 / 255.0, 250.0 / 255.0));
|
||||
waterfallGradient.generate(256);
|
||||
waterfallHighlight = RGBColor(1, 1, 1);
|
||||
waterfallNew = RGBColor(0, 1, 0);
|
||||
waterfallHover = RGBColor(1, 1, 0);
|
||||
waterfallDestroy = RGBColor(1, 0, 0);
|
||||
fftLine = RGBColor(0.9, 0.9, 0.9);
|
||||
fftHighlight = RGBColor(1, 1, 1);
|
||||
scopeLine = RGBColor(0.9, 0.9, 0.9);
|
||||
tuningBarLight = RGBColor(0.4, 0.4, 1.0);
|
||||
tuningBarDark = RGBColor(0.1, 0.1, 0.45);
|
||||
tuningBarUp = RGBColor(1.0, 139.0/255.0, 96.0/255.0);
|
||||
tuningBarDown = RGBColor(148.0/255.0, 148.0/255.0, 1.0);
|
||||
meterLevel = RGBColor(0, 0.5, 0);
|
||||
meterValue = RGBColor(0.0, 0.0, 1.0);
|
||||
text = RGBColor(1, 1, 1);
|
||||
freqLine = RGBColor(1, 1, 1);
|
||||
button = RGBColor(0, 0.7, 0.7);
|
||||
buttonHighlight = RGBColor(1, 1, 1);
|
||||
waterfallHighlight = RGB3f(1, 1, 1);
|
||||
waterfallNew = RGB3f(0, 1, 0);
|
||||
waterfallHover = RGB3f(1, 1, 0);
|
||||
waterfallDestroy = RGB3f(1, 0, 0);
|
||||
fftLine = RGB3f(0.9, 0.9, 0.9);
|
||||
fftHighlight = RGB3f(1, 1, 1);
|
||||
scopeLine = RGB3f(0.9, 0.9, 0.9);
|
||||
tuningBarLight = RGB3f(0.4, 0.4, 1.0);
|
||||
tuningBarDark = RGB3f(0.1, 0.1, 0.45);
|
||||
tuningBarUp = RGB3f(1.0, 139.0/255.0, 96.0/255.0);
|
||||
tuningBarDown = RGB3f(148.0/255.0, 148.0/255.0, 1.0);
|
||||
meterLevel = RGB3f(0, 0.5, 0);
|
||||
meterValue = RGB3f(0.0, 0.0, 1.0);
|
||||
text = RGB3f(1, 1, 1);
|
||||
freqLine = RGB3f(1, 1, 1);
|
||||
button = RGB3f(0, 0.7, 0.7);
|
||||
buttonHighlight = RGB3f(1, 1, 1);
|
||||
|
||||
scopeBackground = RGBColor(0.0, 0.0, 48.0 / 255.0);
|
||||
fftBackground = RGBColor(0.0, 0.0, 48.0 / 255.0);
|
||||
generalBackground = RGBColor(0.0, 0.0, 0.0);
|
||||
scopeBackground = RGB3f(0.0, 0.0, 48.0 / 255.0);
|
||||
fftBackground = RGB3f(0.0, 0.0, 48.0 / 255.0);
|
||||
generalBackground = RGB3f(0.0, 0.0, 0.0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+30
-27
@@ -15,52 +15,55 @@
|
||||
#define COLOR_THEME_RADAR 6
|
||||
#define COLOR_THEME_MAX 7
|
||||
|
||||
class RGBColor {
|
||||
class RGB3f {
|
||||
public:
|
||||
float r, g, b;
|
||||
RGBColor(float r, float g, float b) :
|
||||
RGB3f(float r, float g, float b) :
|
||||
r(r), g(g), b(b) {
|
||||
}
|
||||
|
||||
RGBColor() :
|
||||
RGBColor(0, 0, 0) {
|
||||
RGB3f() :
|
||||
RGB3f(0, 0, 0) {
|
||||
}
|
||||
|
||||
~RGBColor() {
|
||||
~RGB3f() {
|
||||
}
|
||||
|
||||
RGBColor & operator=(const RGBColor &other) {
|
||||
RGB3f & operator=(const RGB3f &other) {
|
||||
r = other.r;
|
||||
g = other.g;
|
||||
b = other.b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGB3f operator*(float v) { return RGB3f(r*v, g*v, b*v); }
|
||||
|
||||
};
|
||||
|
||||
class ColorTheme {
|
||||
public:
|
||||
RGBColor waterfallHighlight;
|
||||
RGBColor waterfallNew;
|
||||
RGBColor wfHighlight;
|
||||
RGBColor waterfallHover;
|
||||
RGBColor waterfallDestroy;
|
||||
RGBColor fftLine;
|
||||
RGBColor fftHighlight;
|
||||
RGBColor scopeLine;
|
||||
RGBColor tuningBarLight;
|
||||
RGBColor tuningBarDark;
|
||||
RGBColor tuningBarUp;
|
||||
RGBColor tuningBarDown;
|
||||
RGBColor meterLevel;
|
||||
RGBColor meterValue;
|
||||
RGBColor text;
|
||||
RGBColor freqLine;
|
||||
RGBColor button;
|
||||
RGBColor buttonHighlight;
|
||||
RGB3f waterfallHighlight;
|
||||
RGB3f waterfallNew;
|
||||
RGB3f wfHighlight;
|
||||
RGB3f waterfallHover;
|
||||
RGB3f waterfallDestroy;
|
||||
RGB3f fftLine;
|
||||
RGB3f fftHighlight;
|
||||
RGB3f scopeLine;
|
||||
RGB3f tuningBarLight;
|
||||
RGB3f tuningBarDark;
|
||||
RGB3f tuningBarUp;
|
||||
RGB3f tuningBarDown;
|
||||
RGB3f meterLevel;
|
||||
RGB3f meterValue;
|
||||
RGB3f text;
|
||||
RGB3f freqLine;
|
||||
RGB3f button;
|
||||
RGB3f buttonHighlight;
|
||||
|
||||
RGBColor scopeBackground;
|
||||
RGBColor fftBackground;
|
||||
RGBColor generalBackground;
|
||||
RGB3f scopeBackground;
|
||||
RGB3f fftBackground;
|
||||
RGB3f generalBackground;
|
||||
|
||||
Gradient waterfallGradient;
|
||||
|
||||
|
||||
@@ -60,9 +60,6 @@ float MeterCanvas::getInputValue() {
|
||||
|
||||
void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
#ifdef __APPLE__ // force half-rate?
|
||||
glFinish();
|
||||
#endif
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
|
||||
glContext->SetCurrent(*this);
|
||||
@@ -82,7 +79,7 @@ void MeterCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
}
|
||||
|
||||
void MeterCanvas::OnIdle(wxIdleEvent &event) {
|
||||
Refresh(false);
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void MeterCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
@@ -115,6 +112,7 @@ void MeterCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
void MeterCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseLeftWindow(event);
|
||||
SetCursor(wxCURSOR_CROSS);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void MeterCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
||||
|
||||
@@ -25,7 +25,7 @@ EVT_ENTER_WINDOW(ModeSelectorCanvas::OnMouseEnterWindow)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
ModeSelectorCanvas::ModeSelectorCanvas(wxWindow *parent, int *attribList) :
|
||||
InteractiveCanvas(parent, attribList), currentSelection(-1), numChoices(0) {
|
||||
InteractiveCanvas(parent, attribList), numChoices(0), currentSelection(-1) {
|
||||
|
||||
glContext = new ModeSelectorContext(this, &wxGetApp().GetContext(this));
|
||||
}
|
||||
@@ -47,10 +47,7 @@ int ModeSelectorCanvas::getHoveredSelection() {
|
||||
|
||||
void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
#ifdef __APPLE__ // force half-rate?
|
||||
glFinish();
|
||||
#endif
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
|
||||
glContext->SetCurrent(*this);
|
||||
initGLExtensions();
|
||||
@@ -75,7 +72,7 @@ void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
}
|
||||
|
||||
void ModeSelectorCanvas::OnIdle(wxIdleEvent &event) {
|
||||
Refresh(false);
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void ModeSelectorCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
@@ -109,6 +106,7 @@ void ModeSelectorCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
void ModeSelectorCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseLeftWindow(event);
|
||||
SetCursor (wxCURSOR_CROSS);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void ModeSelectorCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
||||
|
||||
@@ -29,12 +29,12 @@ void ModeSelectorContext::DrawSelector(std::string label, int c, int cMax, bool
|
||||
float viewHeight = (float) vp[3];
|
||||
float viewWidth = (float) vp[2];
|
||||
|
||||
PrimaryGLContext::GLFontSize fontSize = GLFONT_SIZE16;
|
||||
GLFont::GLFontSize fontSize = GLFont::GLFONT_SIZE16;
|
||||
|
||||
int fontHeight = 16;
|
||||
|
||||
if (viewWidth < 30) {
|
||||
fontSize = GLFONT_SIZE12;
|
||||
fontSize = GLFont::GLFONT_SIZE12;
|
||||
fontHeight = 12;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ void ModeSelectorContext::DrawSelector(std::string label, int c, int cMax, bool
|
||||
glColor4f(0, 0, 0, a);
|
||||
}
|
||||
|
||||
getFont(fontSize).drawString(label, 0.0, y + height / 2.0, fontHeight, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(fontSize).drawString(label, 0.0, y + height / 2.0, fontHeight, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
}
|
||||
|
||||
void ModeSelectorContext::DrawEnd() {
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#include "AppFrame.h"
|
||||
#include <algorithm>
|
||||
|
||||
GLFont PrimaryGLContext::fonts[GLFONT_MAX];
|
||||
|
||||
wxString PrimaryGLContext::glGetwxString(GLenum name) {
|
||||
const GLubyte *v = glGetString(name);
|
||||
if (v == 0) {
|
||||
@@ -61,41 +59,7 @@ PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas, wxGLContext *sharedContex
|
||||
//#endif
|
||||
}
|
||||
|
||||
GLFont &PrimaryGLContext::getFont(GLFontSize esize) {
|
||||
if (!fonts[esize].isLoaded()) {
|
||||
|
||||
std::string fontName;
|
||||
switch (esize) {
|
||||
case GLFONT_SIZE12:
|
||||
fontName = "vera_sans_mono12.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE16:
|
||||
fontName = "vera_sans_mono16.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE18:
|
||||
fontName = "vera_sans_mono18.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE24:
|
||||
fontName = "vera_sans_mono24.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE32:
|
||||
fontName = "vera_sans_mono32.fnt";
|
||||
break;
|
||||
case GLFONT_SIZE48:
|
||||
fontName = "vera_sans_mono48.fnt";
|
||||
break;
|
||||
default:
|
||||
fontName = "vera_sans_mono12.fnt";
|
||||
break;
|
||||
}
|
||||
|
||||
fonts[esize].loadFont(fontName);
|
||||
}
|
||||
|
||||
return fonts[esize];
|
||||
}
|
||||
|
||||
void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBColor color, long long center_freq, long long srate) {
|
||||
void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, long long center_freq, long long srate) {
|
||||
if (!demod) {
|
||||
return;
|
||||
}
|
||||
@@ -165,18 +129,18 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBColor color,
|
||||
glColor4f(1.0, 1.0, 1.0, 0.8);
|
||||
|
||||
if (demod->getDemodulatorType() == DEMOD_TYPE_USB) {
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER);
|
||||
} else if (demod->getDemodulatorType() == DEMOD_TYPE_LSB) {
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER);
|
||||
} else {
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
}
|
||||
|
||||
void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBColor color, long long center_freq, long long srate) {
|
||||
void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGB3f color, long long center_freq, long long srate) {
|
||||
if (!demod) {
|
||||
return;
|
||||
}
|
||||
@@ -264,16 +228,16 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBColor color, lon
|
||||
}
|
||||
|
||||
glColor3f(0, 0, 0);
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5) + xOfs, -1.0 + hPos - yOfs, 16, demodAlign,
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5) + xOfs, -1.0 + hPos - yOfs, 16, demodAlign,
|
||||
GLFont::GLFONT_ALIGN_CENTER);
|
||||
glColor3f(0.8, 0.8, 0.8);
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
}
|
||||
|
||||
void PrimaryGLContext::DrawFreqSelector(float uxPos, RGBColor color, float w, long long center_freq, long long srate) {
|
||||
void PrimaryGLContext::DrawFreqSelector(float uxPos, RGB3f color, float w, long long center_freq, long long srate) {
|
||||
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
|
||||
long long bw = 0;
|
||||
@@ -324,7 +288,7 @@ void PrimaryGLContext::DrawFreqSelector(float uxPos, RGBColor color, float w, lo
|
||||
|
||||
}
|
||||
|
||||
void PrimaryGLContext::DrawRangeSelector(float uxPos1, float uxPos2, RGBColor color) {
|
||||
void PrimaryGLContext::DrawRangeSelector(float uxPos1, float uxPos2, RGB3f color) {
|
||||
if (uxPos2 < uxPos1) {
|
||||
float temp = uxPos2;
|
||||
uxPos2=uxPos1;
|
||||
|
||||
@@ -13,9 +13,6 @@
|
||||
|
||||
class PrimaryGLContext: public wxGLContext {
|
||||
public:
|
||||
enum GLFontSize {
|
||||
GLFONT_SIZE12, GLFONT_SIZE16, GLFONT_SIZE18, GLFONT_SIZE24, GLFONT_SIZE32, GLFONT_SIZE48, GLFONT_MAX
|
||||
};
|
||||
PrimaryGLContext(wxGLCanvas *canvas, wxGLContext *sharedContext);
|
||||
|
||||
static wxString glGetwxString(GLenum name);
|
||||
@@ -24,17 +21,14 @@ public:
|
||||
void BeginDraw(float r, float g, float b);
|
||||
void EndDraw();
|
||||
|
||||
void DrawFreqSelector(float uxPos, RGBColor color, float w = 0, long long center_freq = -1, long long srate = 0);
|
||||
void DrawRangeSelector(float uxPos1, float uxPos2, RGBColor color);
|
||||
void DrawDemod(DemodulatorInstance *demod, RGBColor color, long long center_freq = -1, long long srate = 0);
|
||||
void DrawDemodInfo(DemodulatorInstance *demod, RGBColor color, long long center_freq = -1, long long srate = 0);
|
||||
|
||||
static GLFont &getFont(GLFontSize esize);
|
||||
void DrawFreqSelector(float uxPos, RGB3f color, float w = 0, long long center_freq = -1, long long srate = 0);
|
||||
void DrawRangeSelector(float uxPos1, float uxPos2, RGB3f color);
|
||||
void DrawDemod(DemodulatorInstance *demod, RGB3f color, long long center_freq = -1, long long srate = 0);
|
||||
void DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, long long center_freq = -1, long long srate = 0);
|
||||
|
||||
void setHoverAlpha(float hoverAlpha);
|
||||
|
||||
private:
|
||||
static GLFont fonts[GLFONT_MAX];
|
||||
DemodulatorThreadParameters defaultDemodParams;
|
||||
float hoverAlpha;
|
||||
};
|
||||
|
||||
+21
-31
@@ -15,25 +15,23 @@
|
||||
#include "AppFrame.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
wxBEGIN_EVENT_TABLE(ScopeCanvas, wxGLCanvas) EVT_PAINT(ScopeCanvas::OnPaint)
|
||||
EVT_IDLE(ScopeCanvas::OnIdle)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) :
|
||||
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
||||
wxFULL_REPAINT_ON_RESIZE), parent(parent), stereo(false), ppmMode(false) {
|
||||
wxFULL_REPAINT_ON_RESIZE), stereo(false), ppmMode(false) {
|
||||
|
||||
glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
|
||||
inputData.set_max_num_items(1);
|
||||
}
|
||||
|
||||
ScopeCanvas::~ScopeCanvas() {
|
||||
|
||||
}
|
||||
|
||||
void ScopeCanvas::setWaveformPoints(std::vector<float> &waveform_points_in) {
|
||||
waveform_points = waveform_points_in;
|
||||
}
|
||||
|
||||
void ScopeCanvas::setStereo(bool state) {
|
||||
stereo = state;
|
||||
}
|
||||
@@ -53,34 +51,19 @@ bool ScopeCanvas::getPPMMode() {
|
||||
|
||||
void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
#ifdef __APPLE__ // force half-rate?
|
||||
glFinish();
|
||||
#endif
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
|
||||
if (!wxGetApp().getAudioVisualQueue()->empty()) {
|
||||
AudioThreadInput *demodAudioData;
|
||||
wxGetApp().getAudioVisualQueue()->pop(demodAudioData);
|
||||
if (!inputData.empty()) {
|
||||
ScopeRenderData *avData;
|
||||
inputData.pop(avData);
|
||||
|
||||
int iMax = demodAudioData?demodAudioData->data.size():0;
|
||||
|
||||
if (demodAudioData && iMax) {
|
||||
if (waveform_points.size() != iMax * 2) {
|
||||
waveform_points.resize(iMax * 2);
|
||||
if (avData) {
|
||||
if (avData->waveform_points.size()) {
|
||||
scopePanel.setPoints(avData->waveform_points);
|
||||
setStereo(avData->channels == 2);
|
||||
}
|
||||
|
||||
demodAudioData->busy_update.lock();
|
||||
|
||||
for (int i = 0; i < iMax; i++) {
|
||||
waveform_points[i * 2 + 1] = demodAudioData->data[i] * 0.5f;
|
||||
waveform_points[i * 2] = ((double) i / (double) iMax);
|
||||
}
|
||||
|
||||
demodAudioData->busy_update.unlock();
|
||||
|
||||
setStereo(demodAudioData->channels == 2);
|
||||
} else {
|
||||
std::cout << "Incoming Demodulator data empty?" << std::endl;
|
||||
|
||||
avData->decRefCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +73,10 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||
|
||||
glContext->DrawBegin();
|
||||
glContext->Plot(waveform_points, stereo, ppmMode);
|
||||
scopePanel.setMode(stereo?ScopePanel::SCOPE_MODE_2Y:ScopePanel::SCOPE_MODE_Y);
|
||||
scopePanel.calcTransform(CubicVR::mat4::identity());
|
||||
scopePanel.draw();
|
||||
glContext->DrawTunerTitles(ppmMode);
|
||||
if (!deviceName.empty()) {
|
||||
glContext->DrawDeviceName(deviceName);
|
||||
}
|
||||
@@ -101,5 +87,9 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
}
|
||||
|
||||
void ScopeCanvas::OnIdle(wxIdleEvent &event) {
|
||||
Refresh(false);
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
ScopeRenderDataQueue *ScopeCanvas::getInputQueue() {
|
||||
return &inputData;
|
||||
}
|
||||
|
||||
@@ -7,28 +7,28 @@
|
||||
#include <queue>
|
||||
|
||||
#include "ScopeContext.h"
|
||||
#include "ScopeVisualProcessor.h"
|
||||
#include "ScopePanel.h"
|
||||
#include "fftw3.h"
|
||||
|
||||
class ScopeCanvas: public wxGLCanvas {
|
||||
public:
|
||||
std::vector<float> waveform_points;
|
||||
|
||||
ScopeCanvas(wxWindow *parent, int *attribList = NULL);
|
||||
~ScopeCanvas();
|
||||
|
||||
void setWaveformPoints(std::vector<float> &waveform_points_in);
|
||||
void setStereo(bool state);
|
||||
void setDeviceName(std::string device_name);
|
||||
void setPPMMode(bool ppmMode);
|
||||
bool getPPMMode();
|
||||
|
||||
ScopeRenderDataQueue *getInputQueue();
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
|
||||
void OnIdle(wxIdleEvent &event);
|
||||
|
||||
wxWindow *parent;
|
||||
|
||||
ScopeRenderDataQueue inputData;
|
||||
ScopePanel scopePanel;
|
||||
ScopeContext *glContext;
|
||||
std::string deviceName;
|
||||
bool stereo;
|
||||
|
||||
+6
-112
@@ -23,56 +23,8 @@ void ScopeContext::DrawBegin() {
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void ScopeContext::Plot(std::vector<float> &points, bool stereo, bool ppmMode) {
|
||||
if (stereo) {
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, ThemeMgr::mgr.currentTheme->scopeBackground.b);
|
||||
glVertex2f(1, 1);
|
||||
glVertex2f(-1, 1);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r*2.0, ThemeMgr::mgr.currentTheme->scopeBackground.g*2.0, ThemeMgr::mgr.currentTheme->scopeBackground.b*2.0);
|
||||
glVertex2f(-1, 0.5);
|
||||
glVertex2f(1, 0.5);
|
||||
|
||||
glVertex2f(-1, 0.5);
|
||||
glVertex2f(1, 0.5);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, ThemeMgr::mgr.currentTheme->scopeBackground.b);
|
||||
glVertex2f(1, 0.0);
|
||||
glVertex2f(-1, 0.0);
|
||||
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, ThemeMgr::mgr.currentTheme->scopeBackground.b);
|
||||
glVertex2f(1, 0);
|
||||
glVertex2f(-1, 0);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r*2.0, ThemeMgr::mgr.currentTheme->scopeBackground.g*2.0, ThemeMgr::mgr.currentTheme->scopeBackground.b*2.0);
|
||||
glVertex2f(-1, -0.5);
|
||||
glVertex2f(1, -0.5);
|
||||
|
||||
glVertex2f(-1, -0.5);
|
||||
glVertex2f(1, -0.5);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, ThemeMgr::mgr.currentTheme->scopeBackground.b);
|
||||
glVertex2f(1, -1.0);
|
||||
glVertex2f(-1, -1.0);
|
||||
glEnd();
|
||||
} else {
|
||||
glBegin (GL_QUADS);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g,
|
||||
ThemeMgr::mgr.currentTheme->scopeBackground.b);
|
||||
glVertex2f(1, 1);
|
||||
glVertex2f(-1, 1);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r * 2.0, ThemeMgr::mgr.currentTheme->scopeBackground.g * 2.0,
|
||||
ThemeMgr::mgr.currentTheme->scopeBackground.b * 2.0);
|
||||
glVertex2f(-1, 0);
|
||||
glVertex2f(1, 0);
|
||||
|
||||
glVertex2f(-1, 0);
|
||||
glVertex2f(1, 0);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g,
|
||||
ThemeMgr::mgr.currentTheme->scopeBackground.b);
|
||||
glVertex2f(1, -1);
|
||||
glVertex2f(-1, -1);
|
||||
glEnd();
|
||||
}
|
||||
glLineWidth(1.0);
|
||||
|
||||
void ScopeContext::DrawTunerTitles(bool ppmMode) {
|
||||
glLoadIdentity();
|
||||
|
||||
GLint vp[4];
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
@@ -81,67 +33,9 @@ void ScopeContext::Plot(std::vector<float> &points, bool stereo, bool ppmMode) {
|
||||
|
||||
glColor3f(0.65, 0.65, 0.65);
|
||||
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString(ppmMode?"Device PPM":"Frequency", -0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString("Bandwidth", 0.0, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString("Center Frequency", 0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
|
||||
|
||||
if (stereo) {
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b);
|
||||
glBegin (GL_LINES);
|
||||
glVertex2f(-1.0, 0.0);
|
||||
glVertex2f(1.0, 0.0);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
|
||||
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
|
||||
glVertex2f(-1.0, 0.5);
|
||||
glVertex2f(1.0, 0.5);
|
||||
glVertex2f(-1.0, -0.5);
|
||||
glVertex2f(1.0, -0.5);
|
||||
glEnd();
|
||||
} else {
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
|
||||
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
|
||||
glBegin (GL_LINES);
|
||||
glVertex2f(-1.0, 0.0);
|
||||
glVertex2f(1.0, 0.0);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if (points.size()) {
|
||||
glEnable (GL_BLEND);
|
||||
glEnable (GL_LINE_SMOOTH);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColor4f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b, 1.0);
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
|
||||
if (stereo) {
|
||||
glLineWidth(1.5);
|
||||
glPushMatrix();
|
||||
glTranslatef(-1.0f, 0.5f, 0.0f);
|
||||
glScalef(4.0f, 0.92f, 1.0f);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 4);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-3.0f, -0.5f, 0.0f);
|
||||
glPushMatrix();
|
||||
glScalef(4.0f, 0.92f, 1.0f);
|
||||
glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
} else {
|
||||
glLineWidth(1.5);
|
||||
glPushMatrix();
|
||||
glTranslatef(-1.0f, 0.0f, 0.0f);
|
||||
glScalef(2.0f, 2.0f, 1.0f);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2);
|
||||
glPopMatrix();
|
||||
}
|
||||
glLineWidth(1.0);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(ppmMode?"Device PPM":"Frequency", -0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Bandwidth", 0.0, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Center Frequency", 0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
}
|
||||
|
||||
void ScopeContext::DrawDeviceName(std::string deviceName) {
|
||||
@@ -151,7 +45,7 @@ void ScopeContext::DrawDeviceName(std::string deviceName) {
|
||||
float hPos = (float) (viewHeight - 20) / viewHeight;
|
||||
|
||||
glColor3f(0.65, 0.65, 0.65);
|
||||
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString(deviceName.c_str(), 1.0, hPos, 12, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(deviceName.c_str(), 1.0, hPos, 12, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER);
|
||||
}
|
||||
|
||||
void ScopeContext::DrawEnd() {
|
||||
|
||||
@@ -12,7 +12,7 @@ public:
|
||||
ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext);
|
||||
|
||||
void DrawBegin();
|
||||
void Plot(std::vector<float> &points, bool stereo=false, bool ppmMode=false);
|
||||
void DrawTunerTitles(bool ppmMode=false);
|
||||
void DrawDeviceName(std::string deviceName);
|
||||
void DrawDivider();
|
||||
void DrawEnd();
|
||||
|
||||
+28
-116
@@ -27,59 +27,50 @@ EVT_MOUSEWHEEL(SpectrumCanvas::OnMouseWheelMoved)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
||||
InteractiveCanvas(parent, attribList), fft_size(0), in(NULL), out(NULL), plan(NULL), fft_ceil_ma(1), fft_ceil_maa(1), fft_floor_ma(0), fft_floor_maa(
|
||||
0), waterfallCanvas(NULL), trackingRate(0) {
|
||||
InteractiveCanvas(parent, attribList), waterfallCanvas(NULL) {
|
||||
|
||||
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
|
||||
glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this));
|
||||
|
||||
mouseTracker.setVertDragLock(true);
|
||||
|
||||
SetCursor(wxCURSOR_SIZEWE);
|
||||
}
|
||||
|
||||
void SpectrumCanvas::setup(int fft_size_in) {
|
||||
if (fft_size == fft_size_in) {
|
||||
return;
|
||||
}
|
||||
|
||||
fft_size = fft_size_in;
|
||||
|
||||
if (in) {
|
||||
free(in);
|
||||
}
|
||||
in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size);
|
||||
if (out) {
|
||||
free(out);
|
||||
}
|
||||
out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size);
|
||||
if (plan) {
|
||||
fftwf_destroy_plan(plan);
|
||||
}
|
||||
plan = fftwf_plan_dft_1d(fft_size, in, out, FFTW_FORWARD, FFTW_MEASURE);
|
||||
|
||||
fft_ceil_ma = fft_ceil_maa = 100.0;
|
||||
fft_floor_ma = fft_floor_maa = 0.0;
|
||||
}
|
||||
|
||||
SpectrumCanvas::~SpectrumCanvas() {
|
||||
|
||||
}
|
||||
|
||||
void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
#ifdef __APPLE__ // force half-rate?
|
||||
glFinish();
|
||||
#endif
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
|
||||
|
||||
if (!visualDataQueue.empty()) {
|
||||
SpectrumVisualData *vData;
|
||||
|
||||
visualDataQueue.pop(vData);
|
||||
|
||||
if (vData) {
|
||||
spectrumPanel.setPoints(vData->spectrum_points);
|
||||
spectrumPanel.setFloorValue(vData->fft_floor);
|
||||
spectrumPanel.setCeilValue(vData->fft_ceiling);
|
||||
vData->decRefCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
glContext->SetCurrent(*this);
|
||||
initGLExtensions();
|
||||
|
||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||
|
||||
glContext->BeginDraw(ThemeMgr::mgr.currentTheme->fftBackground.r, ThemeMgr::mgr.currentTheme->fftBackground.g, ThemeMgr::mgr.currentTheme->fftBackground.b);
|
||||
glContext->Draw(spectrum_points, getCenterFrequency(), getBandwidth());
|
||||
glContext->BeginDraw(0,0,0);
|
||||
|
||||
spectrumPanel.setFreq(getCenterFrequency());
|
||||
spectrumPanel.setBandwidth(getBandwidth());
|
||||
|
||||
spectrumPanel.calcTransform(CubicVR::mat4::identity());
|
||||
spectrumPanel.draw();
|
||||
|
||||
std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
|
||||
|
||||
for (int i = 0, iMax = demods.size(); i < iMax; i++) {
|
||||
@@ -91,88 +82,9 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
void SpectrumCanvas::setData(DemodulatorThreadIQData *input) {
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
std::vector<liquid_float_complex> *data = &input->data;
|
||||
if (data && data->size()) {
|
||||
if (fft_size != data->size()) {
|
||||
setup(data->size());
|
||||
}
|
||||
if (spectrum_points.size() < fft_size * 2) {
|
||||
if (spectrum_points.capacity() < fft_size * 2) {
|
||||
spectrum_points.reserve(fft_size * 2);
|
||||
}
|
||||
spectrum_points.resize(fft_size * 2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < fft_size; i++) {
|
||||
in[i][0] = (*data)[i].real;
|
||||
in[i][1] = (*data)[i].imag;
|
||||
}
|
||||
|
||||
fftwf_execute(plan);
|
||||
|
||||
float fft_ceil = 0, fft_floor = 1;
|
||||
|
||||
if (fft_result.size() != fft_size) {
|
||||
if (fft_result.capacity() < fft_size) {
|
||||
fft_result.reserve(fft_size);
|
||||
fft_result_ma.reserve(fft_size);
|
||||
fft_result_maa.reserve(fft_size);
|
||||
}
|
||||
fft_result.resize(fft_size);
|
||||
fft_result_ma.resize(fft_size);
|
||||
fft_result_maa.resize(fft_size);
|
||||
}
|
||||
|
||||
int n;
|
||||
for (int i = 0, iMax = fft_size / 2; i < iMax; i++) {
|
||||
float a = out[i][0];
|
||||
float b = out[i][1];
|
||||
float c = sqrt(a * a + b * b);
|
||||
|
||||
float x = out[fft_size / 2 + i][0];
|
||||
float y = out[fft_size / 2 + i][1];
|
||||
float z = sqrt(x * x + y * y);
|
||||
|
||||
fft_result[i] = (z);
|
||||
fft_result[fft_size / 2 + i] = (c);
|
||||
}
|
||||
|
||||
for (int i = 0, iMax = fft_size; i < iMax; i++) {
|
||||
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;
|
||||
|
||||
if (fft_result_maa[i] > fft_ceil) {
|
||||
fft_ceil = fft_result_maa[i];
|
||||
}
|
||||
if (fft_result_maa[i] < fft_floor) {
|
||||
fft_floor = fft_result_maa[i];
|
||||
}
|
||||
}
|
||||
|
||||
fft_ceil += 1;
|
||||
fft_floor -= 1;
|
||||
|
||||
fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.01;
|
||||
fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.01;
|
||||
|
||||
fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.01;
|
||||
fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.01;
|
||||
|
||||
for (int i = 0, iMax = fft_size; i < iMax; i++) {
|
||||
float v = (log10(fft_result_maa[i] - fft_floor_maa) / log10(fft_ceil_maa - fft_floor_maa));
|
||||
spectrum_points[i * 2] = ((float) i / (float) iMax);
|
||||
spectrum_points[i * 2 + 1] = v;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SpectrumCanvas::OnIdle(wxIdleEvent &event) {
|
||||
Refresh(false);
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
@@ -247,6 +159,6 @@ void SpectrumCanvas::attachWaterfallCanvas(WaterfallCanvas* canvas_in) {
|
||||
waterfallCanvas = canvas_in;
|
||||
}
|
||||
|
||||
SpectrumContext* SpectrumCanvas::getSpectrumContext() {
|
||||
return glContext;
|
||||
}
|
||||
SpectrumVisualDataQueue *SpectrumCanvas::getVisualDataQueue() {
|
||||
return &visualDataQueue;
|
||||
}
|
||||
+10
-25
@@ -1,33 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "wx/glcanvas.h"
|
||||
#include "wx/timer.h"
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include "InteractiveCanvas.h"
|
||||
#include "SpectrumContext.h"
|
||||
|
||||
#include "fftw3.h"
|
||||
#include "PrimaryGLContext.h"
|
||||
#include "MouseTracker.h"
|
||||
#include "SpectrumVisualProcessor.h"
|
||||
#include "SpectrumPanel.h"
|
||||
|
||||
class WaterfallCanvas;
|
||||
|
||||
class SpectrumCanvas: public InteractiveCanvas {
|
||||
public:
|
||||
std::vector<float> spectrum_points;
|
||||
|
||||
SpectrumCanvas(wxWindow *parent, int *attribList = NULL);
|
||||
void setup(int fft_size_in);
|
||||
~SpectrumCanvas();
|
||||
|
||||
void setData(DemodulatorThreadIQData *input);
|
||||
void attachWaterfallCanvas(WaterfallCanvas *canvas_in);
|
||||
void moveCenterFrequency(long long freqChange);
|
||||
|
||||
SpectrumContext* getSpectrumContext();
|
||||
|
||||
SpectrumVisualDataQueue *getVisualDataQueue();
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
|
||||
@@ -39,20 +32,12 @@ private:
|
||||
void OnMouseReleased(wxMouseEvent& event);
|
||||
void OnMouseLeftWindow(wxMouseEvent& event);
|
||||
|
||||
fftwf_complex *in, *out;
|
||||
fftwf_plan plan;
|
||||
|
||||
float fft_ceil_ma, fft_ceil_maa;
|
||||
float fft_floor_ma, fft_floor_maa;
|
||||
|
||||
std::vector<float> fft_result;
|
||||
std::vector<float> fft_result_ma;
|
||||
std::vector<float> fft_result_maa;
|
||||
|
||||
SpectrumContext *glContext;
|
||||
PrimaryGLContext *glContext;
|
||||
WaterfallCanvas *waterfallCanvas;
|
||||
int fft_size;
|
||||
int trackingRate;
|
||||
SpectrumPanel spectrumPanel;
|
||||
|
||||
SpectrumVisualDataQueue visualDataQueue;
|
||||
|
||||
// event table
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "PrimaryGLContext.h"
|
||||
#include "Gradient.h"
|
||||
|
||||
#define NUM_WATERFALL_LINES 512
|
||||
|
||||
class SpectrumCanvas;
|
||||
|
||||
class SpectrumContext: public PrimaryGLContext {
|
||||
public:
|
||||
SpectrumContext(SpectrumCanvas *canvas, wxGLContext *sharedContext);
|
||||
|
||||
void Draw(std::vector<float> &points, long long freq, int bandwidth);
|
||||
|
||||
float getFloorValue() const;
|
||||
void setFloorValue(float floorValue);
|
||||
float getCeilValue() const;
|
||||
void setCeilValue(float ceilValue);
|
||||
|
||||
private:
|
||||
int fft_size;
|
||||
float floorValue, ceilValue;
|
||||
};
|
||||
+28
-15
@@ -31,7 +31,7 @@ EVT_KEY_UP(TuningCanvas::OnKeyUp)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
TuningCanvas::TuningCanvas(wxWindow *parent, int *attribList) :
|
||||
InteractiveCanvas(parent, attribList), dragAccum(0), top(false), bottom(false), uxDown(0) {
|
||||
InteractiveCanvas(parent, attribList), dragAccum(0), uxDown(0), top(false), bottom(false), freq(-1), bw(-1), center(-1) {
|
||||
|
||||
glContext = new TuningContext(this, &wxGetApp().GetContext(this));
|
||||
|
||||
@@ -57,13 +57,27 @@ TuningCanvas::~TuningCanvas() {
|
||||
|
||||
}
|
||||
|
||||
bool TuningCanvas::changed() {
|
||||
DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
|
||||
long long current_freq = 0;
|
||||
if (activeDemod != NULL) {
|
||||
freq = activeDemod->getFrequency();
|
||||
}
|
||||
long long current_bw = wxGetApp().getDemodMgr().getLastBandwidth();
|
||||
long long current_center = wxGetApp().getFrequency();
|
||||
|
||||
if (current_freq != freq || current_bw != bw || current_center != center) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TuningCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
#ifdef __APPLE__ // force half-rate?
|
||||
glFinish();
|
||||
#endif
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
|
||||
|
||||
glContext->SetCurrent(*this);
|
||||
initGLExtensions();
|
||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||
@@ -71,23 +85,23 @@ void TuningCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
glContext->DrawBegin();
|
||||
|
||||
DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
|
||||
long long freq = 0;
|
||||
|
||||
freq = 0;
|
||||
if (activeDemod != NULL) {
|
||||
freq = activeDemod->getFrequency();
|
||||
}
|
||||
long long bw = wxGetApp().getDemodMgr().getLastBandwidth();
|
||||
long long center = wxGetApp().getFrequency();
|
||||
bw = wxGetApp().getDemodMgr().getLastBandwidth();
|
||||
center = wxGetApp().getFrequency();
|
||||
|
||||
if (mouseTracker.mouseDown()) {
|
||||
glContext->Draw(ThemeMgr::mgr.currentTheme->tuningBarDark.r, ThemeMgr::mgr.currentTheme->tuningBarDark.g, ThemeMgr::mgr.currentTheme->tuningBarDark.b,
|
||||
0.75, mouseTracker.getOriginMouseX(), mouseTracker.getMouseX());
|
||||
}
|
||||
|
||||
RGBColor clr = top ? ThemeMgr::mgr.currentTheme->tuningBarUp : ThemeMgr::mgr.currentTheme->tuningBarDown;
|
||||
RGB3f clr = top ? ThemeMgr::mgr.currentTheme->tuningBarUp : ThemeMgr::mgr.currentTheme->tuningBarDown;
|
||||
|
||||
RGBColor clrDark = ThemeMgr::mgr.currentTheme->tuningBarDark;
|
||||
RGBColor clrMid = ThemeMgr::mgr.currentTheme->tuningBarLight;
|
||||
RGB3f clrDark = ThemeMgr::mgr.currentTheme->tuningBarDark;
|
||||
RGB3f clrMid = ThemeMgr::mgr.currentTheme->tuningBarLight;
|
||||
|
||||
glContext->DrawTunerBarIndexed(1, 3, 11, freqDP, freqW, clrMid, 0.25, true, true); // freq
|
||||
glContext->DrawTunerBarIndexed(4, 6, 11, freqDP, freqW, clrDark, 0.25, true, true);
|
||||
@@ -129,7 +143,7 @@ void TuningCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
glContext->DrawTuner(freq, 11, freqDP, freqW);
|
||||
int snap = wxGetApp().getFrequencySnap();
|
||||
if (snap != 1) {
|
||||
glContext->DrawTunerDigitBox((int)log10(snap), 11, freqDP, freqW, RGBColor(1.0,0.0,0.0));
|
||||
glContext->DrawTunerDigitBox((int)log10(snap), 11, freqDP, freqW, RGB3f(1.0,0.0,0.0));
|
||||
}
|
||||
}
|
||||
glContext->DrawTuner(bw, 7, bwDP, bwW);
|
||||
@@ -238,8 +252,6 @@ void TuningCanvas::OnIdle(wxIdleEvent &event) {
|
||||
dragging = false;
|
||||
}
|
||||
}
|
||||
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
void TuningCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
@@ -373,6 +385,7 @@ void TuningCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
||||
if (currentPPM != lastPPM) {
|
||||
wxGetApp().saveConfig();
|
||||
}
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void TuningCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
||||
|
||||
@@ -22,7 +22,8 @@ public:
|
||||
~TuningCanvas();
|
||||
|
||||
void setHelpTip(std::string tip);
|
||||
|
||||
bool changed();
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnIdle(wxIdleEvent &event);
|
||||
@@ -66,6 +67,7 @@ private:
|
||||
int currentPPM;
|
||||
int lastPPM;
|
||||
|
||||
long long freq, bw, center;
|
||||
//
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
@@ -74,19 +74,19 @@ void TuningContext::DrawTuner(long long freq, int count, float displayPos, float
|
||||
freqStr << freq;
|
||||
std::string freqChars = freqStr.str();
|
||||
|
||||
PrimaryGLContext::GLFontSize fontSize = GLFONT_SIZE24;
|
||||
GLFont::GLFontSize fontSize = GLFont::GLFONT_SIZE24;
|
||||
int fontHeight = 24;
|
||||
|
||||
if (viewHeight < 28) {
|
||||
fontSize = GLFONT_SIZE18;
|
||||
fontSize = GLFont::GLFONT_SIZE18;
|
||||
fontHeight = 18;
|
||||
}
|
||||
if (viewHeight < 24) {
|
||||
fontSize = GLFONT_SIZE16;
|
||||
fontSize = GLFont::GLFONT_SIZE16;
|
||||
fontHeight = 16;
|
||||
}
|
||||
if (viewHeight < 18) {
|
||||
fontSize = GLFONT_SIZE12;
|
||||
fontSize = GLFont::GLFONT_SIZE12;
|
||||
fontHeight = 12;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ void TuningContext::DrawTuner(long long freq, int count, float displayPos, float
|
||||
int ofs = count - numChars;
|
||||
for (int i = ofs; i < count; i++) {
|
||||
float xpos = displayPos + (displayWidth / (float) count) * (float) i + ((displayWidth / 2.0) / (float) count);
|
||||
getFont(fontSize).drawString(freqStr.str().substr(i - ofs, 1), xpos, 0, fontHeight, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
GLFont::getFont(fontSize).drawString(freqStr.str().substr(i - ofs, 1), xpos, 0, fontHeight, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||
}
|
||||
|
||||
glColor4f(0.65, 0.65, 0.65, 0.25);
|
||||
@@ -112,7 +112,7 @@ void TuningContext::DrawTuner(long long freq, int count, float displayPos, float
|
||||
}
|
||||
|
||||
|
||||
void TuningContext::DrawTunerDigitBox(int index, int count, float displayPos, float displayWidth, RGBColor c) {
|
||||
void TuningContext::DrawTunerDigitBox(int index, int count, float displayPos, float displayWidth, RGB3f c) {
|
||||
GLint vp[4];
|
||||
glGetIntegerv( GL_VIEWPORT, vp);
|
||||
|
||||
@@ -152,7 +152,7 @@ int TuningContext::GetTunerDigitIndex(float mPos, int count, float displayPos, f
|
||||
return count - index;
|
||||
}
|
||||
|
||||
void TuningContext::DrawTunerBarIndexed(int start, int end, int count, float displayPos, float displayWidth, RGBColor color, float alpha, bool top,
|
||||
void TuningContext::DrawTunerBarIndexed(int start, int end, int count, float displayPos, float displayWidth, RGB3f color, float alpha, bool top,
|
||||
bool bottom) {
|
||||
float ofs = (displayWidth / (float) count);
|
||||
float p2 = displayPos + ofs * (float) (count - start + 1);
|
||||
|
||||
@@ -14,9 +14,9 @@ public:
|
||||
void DrawBegin();
|
||||
void Draw(float r, float g, float b, float a, float p1, float p2);
|
||||
void DrawTuner(long long freq, int count, float displayPos, float displayWidth);
|
||||
void DrawTunerDigitBox(int index, int count, float displayPos, float displayWidth, RGBColor c);
|
||||
void DrawTunerDigitBox(int index, int count, float displayPos, float displayWidth, RGB3f c);
|
||||
int GetTunerDigitIndex(float mPos, int count, float displayPos, float displayWidth);
|
||||
void DrawTunerBarIndexed(int start, int end, int count, float displayPos, float displayWidth, RGBColor color, float alpha, bool top, bool bottom);
|
||||
void DrawTunerBarIndexed(int start, int end, int count, float displayPos, float displayWidth, RGB3f color, float alpha, bool top, bool bottom);
|
||||
|
||||
void DrawDemodFreqBw(long long freq, unsigned int bw, long long center);
|
||||
void DrawEnd();
|
||||
|
||||
+83
-348
@@ -35,23 +35,15 @@ EVT_MOUSEWHEEL(WaterfallCanvas::OnMouseWheelMoved)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
|
||||
InteractiveCanvas(parent, attribList), spectrumCanvas(NULL), dragState(WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), fft_size(0), waterfall_lines(
|
||||
0), plan(
|
||||
NULL), in(NULL), out(NULL), resampler(NULL), resamplerRatio(0), lastInputBandwidth(0), zoom(1), mouseZoom(1), otherWaterfallCanvas(NULL), polling(true), last_data_size(0), fft_in_data(NULL), fft_last_data(NULL), hoverAlpha(1.0), dragOfs(0) {
|
||||
InteractiveCanvas(parent, attribList), dragState(WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), fft_size(0), waterfall_lines(0),
|
||||
dragOfs(0), mouseZoom(1), zoom(1), hoverAlpha(1.0) {
|
||||
|
||||
glContext = new WaterfallContext(this, &wxGetApp().GetContext(this));
|
||||
|
||||
freqShifter = nco_crcf_create(LIQUID_NCO);
|
||||
shiftFrequency = 0;
|
||||
|
||||
fft_ceil_ma = fft_ceil_maa = 100.0;
|
||||
fft_floor_ma = fft_floor_maa = 0.0;
|
||||
glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this));
|
||||
|
||||
SetCursor(wxCURSOR_CROSS);
|
||||
}
|
||||
|
||||
WaterfallCanvas::~WaterfallCanvas() {
|
||||
nco_crcf_destroy(freqShifter);
|
||||
}
|
||||
|
||||
void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) {
|
||||
@@ -61,28 +53,7 @@ void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) {
|
||||
fft_size = fft_size_in;
|
||||
waterfall_lines = waterfall_lines_in;
|
||||
|
||||
if (in) {
|
||||
free(in);
|
||||
}
|
||||
in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size);
|
||||
if (fft_in_data) {
|
||||
free(fft_in_data);
|
||||
}
|
||||
fft_in_data = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size);
|
||||
if (fft_last_data) {
|
||||
free(fft_last_data);
|
||||
}
|
||||
fft_last_data = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size);
|
||||
if (out) {
|
||||
free(out);
|
||||
}
|
||||
out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size);
|
||||
if (plan) {
|
||||
fftwf_destroy_plan(plan);
|
||||
}
|
||||
plan = fftwf_plan_dft_1d(fft_size, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
|
||||
glContext->Setup(fft_size, waterfall_lines);
|
||||
waterfallPanel.setup(fft_size, waterfall_lines);
|
||||
}
|
||||
|
||||
WaterfallCanvas::DragState WaterfallCanvas::getDragState() {
|
||||
@@ -99,37 +70,92 @@ void WaterfallCanvas::attachSpectrumCanvas(SpectrumCanvas *canvas_in) {
|
||||
|
||||
void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
wxPaintDC dc(this);
|
||||
#ifdef __APPLE__ // force half-rate?
|
||||
glFinish();
|
||||
#endif
|
||||
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
|
||||
|
||||
if (polling && !wxGetApp().getIQVisualQueue()->empty()) {
|
||||
DemodulatorThreadIQData *iqData;
|
||||
wxGetApp().getIQVisualQueue()->pop(iqData);
|
||||
|
||||
iqData->busy_rw.lock();
|
||||
|
||||
if (iqData && iqData->data.size()) {
|
||||
setData(iqData);
|
||||
if (otherWaterfallCanvas) {
|
||||
otherWaterfallCanvas->setData(iqData);
|
||||
long double currentZoom = zoom;
|
||||
|
||||
if (mouseZoom != 1) {
|
||||
currentZoom = mouseZoom;
|
||||
mouseZoom = mouseZoom + (1.0 - mouseZoom) * 0.2;
|
||||
if (fabs(mouseZoom-1.0)<0.01) {
|
||||
mouseZoom = 1;
|
||||
}
|
||||
}
|
||||
|
||||
long long bw;
|
||||
if (currentZoom != 1) {
|
||||
long long freq = wxGetApp().getFrequency();
|
||||
|
||||
if (currentZoom < 1) {
|
||||
centerFreq = getCenterFrequency();
|
||||
bw = getBandwidth();
|
||||
bw = (long long) ceil((long double) bw * currentZoom);
|
||||
if (bw < 100000) {
|
||||
bw = 100000;
|
||||
}
|
||||
if (mouseTracker.mouseInView()) {
|
||||
long long mfreqA = getFrequencyAt(mouseTracker.getMouseX());
|
||||
setBandwidth(bw);
|
||||
long long mfreqB = getFrequencyAt(mouseTracker.getMouseX());
|
||||
centerFreq += mfreqA - mfreqB;
|
||||
}
|
||||
|
||||
setView(centerFreq, bw);
|
||||
if (spectrumCanvas) {
|
||||
spectrumCanvas->setView(centerFreq, bw);
|
||||
}
|
||||
} else {
|
||||
std::cout << "Incoming IQ data empty?" << std::endl;
|
||||
if (isView) {
|
||||
bw = getBandwidth();
|
||||
bw = (long long) ceil((long double) bw * currentZoom);
|
||||
if (bw >= wxGetApp().getSampleRate()) {
|
||||
disableView();
|
||||
if (spectrumCanvas) {
|
||||
spectrumCanvas->disableView();
|
||||
}
|
||||
} else {
|
||||
if (mouseTracker.mouseInView()) {
|
||||
long long mfreqA = getFrequencyAt(mouseTracker.getMouseX());
|
||||
setBandwidth(bw);
|
||||
long long mfreqB = getFrequencyAt(mouseTracker.getMouseX());
|
||||
centerFreq += mfreqA - mfreqB;
|
||||
}
|
||||
|
||||
setView(getCenterFrequency(), bw);
|
||||
if (spectrumCanvas) {
|
||||
spectrumCanvas->setView(centerFreq, bw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (centerFreq < freq && (centerFreq - bandwidth / 2) < (freq - wxGetApp().getSampleRate() / 2)) {
|
||||
centerFreq = (freq - wxGetApp().getSampleRate() / 2) + bandwidth / 2;
|
||||
}
|
||||
if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + wxGetApp().getSampleRate() / 2)) {
|
||||
centerFreq = (freq + wxGetApp().getSampleRate() / 2) - bandwidth / 2;
|
||||
}
|
||||
|
||||
iqData->busy_rw.unlock();
|
||||
}
|
||||
|
||||
|
||||
glContext->SetCurrent(*this);
|
||||
initGLExtensions();
|
||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||
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);
|
||||
glContext->Draw(spectrum_points);
|
||||
|
||||
waterfallPanel.calcTransform(CubicVR::mat4::identity());
|
||||
waterfallPanel.draw();
|
||||
|
||||
std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
|
||||
|
||||
@@ -142,7 +168,6 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
int currentBandwidth = getBandwidth();
|
||||
long long currentCenterFreq = getCenterFrequency();
|
||||
|
||||
float demodColor, selectorColor;
|
||||
ColorTheme *currentTheme = ThemeMgr::mgr.currentTheme;
|
||||
int last_type = wxGetApp().getDemodMgr().getLastDemodulatorType();
|
||||
|
||||
@@ -229,13 +254,11 @@ void WaterfallCanvas::OnKeyUp(wxKeyEvent& event) {
|
||||
|
||||
void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
||||
InteractiveCanvas::OnKeyDown(event);
|
||||
float angle = 5.0;
|
||||
|
||||
DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
|
||||
|
||||
long long freq;
|
||||
long long originalFreq;
|
||||
unsigned int bw;
|
||||
switch (event.GetKeyCode()) {
|
||||
case 'A':
|
||||
zoom = 0.95;
|
||||
@@ -323,285 +346,8 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
|
||||
long double currentZoom = zoom;
|
||||
|
||||
if (mouseZoom != 1) {
|
||||
currentZoom = mouseZoom;
|
||||
mouseZoom = mouseZoom + (1.0 - mouseZoom) * 0.2;
|
||||
if (fabs(mouseZoom-1.0)<0.01) {
|
||||
mouseZoom = 1;
|
||||
}
|
||||
}
|
||||
|
||||
long long bw;
|
||||
if (currentZoom != 1) {
|
||||
long long freq = wxGetApp().getFrequency();
|
||||
|
||||
if (currentZoom < 1) {
|
||||
centerFreq = getCenterFrequency();
|
||||
bw = getBandwidth();
|
||||
bw = (long long) ceil((long double) bw * currentZoom);
|
||||
if (bw < 100000) {
|
||||
bw = 100000;
|
||||
}
|
||||
if (mouseTracker.mouseInView()) {
|
||||
long long mfreqA = getFrequencyAt(mouseTracker.getMouseX());
|
||||
setBandwidth(bw);
|
||||
long long mfreqB = getFrequencyAt(mouseTracker.getMouseX());
|
||||
centerFreq += mfreqA - mfreqB;
|
||||
}
|
||||
|
||||
setView(centerFreq, bw);
|
||||
if (spectrumCanvas) {
|
||||
spectrumCanvas->setView(centerFreq, bw);
|
||||
}
|
||||
} else {
|
||||
if (isView) {
|
||||
bw = getBandwidth();
|
||||
bw = (long long) ceil((long double) bw * currentZoom);
|
||||
if (bw >= wxGetApp().getSampleRate()) {
|
||||
disableView();
|
||||
if (spectrumCanvas) {
|
||||
spectrumCanvas->disableView();
|
||||
}
|
||||
} else {
|
||||
if (mouseTracker.mouseInView()) {
|
||||
long long mfreqA = getFrequencyAt(mouseTracker.getMouseX());
|
||||
setBandwidth(bw);
|
||||
long long mfreqB = getFrequencyAt(mouseTracker.getMouseX());
|
||||
centerFreq += mfreqA - mfreqB;
|
||||
}
|
||||
|
||||
setView(getCenterFrequency(), bw);
|
||||
if (spectrumCanvas) {
|
||||
spectrumCanvas->setView(centerFreq, bw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (centerFreq < freq && (centerFreq - bandwidth / 2) < (freq - wxGetApp().getSampleRate() / 2)) {
|
||||
centerFreq = (freq - wxGetApp().getSampleRate() / 2) + bandwidth / 2;
|
||||
}
|
||||
if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + wxGetApp().getSampleRate() / 2)) {
|
||||
centerFreq = (freq + wxGetApp().getSampleRate() / 2) - bandwidth / 2;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<liquid_float_complex> *data = &input->data;
|
||||
|
||||
if (data && data->size()) {
|
||||
// if (fft_size != data->size() && !isView) {
|
||||
// Setup(data->size(), waterfall_lines);
|
||||
// }
|
||||
|
||||
// if (last_bandwidth != bandwidth && !isView) {
|
||||
// Setup(bandwidth, waterfall_lines);
|
||||
// }
|
||||
|
||||
if (spectrum_points.size() < fft_size * 2) {
|
||||
spectrum_points.resize(fft_size * 2);
|
||||
}
|
||||
|
||||
unsigned int num_written;
|
||||
|
||||
if (isView) {
|
||||
if (!input->frequency || !input->sampleRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
resamplerRatio = (double) (bandwidth) / (double) input->sampleRate;
|
||||
|
||||
int desired_input_size = fft_size / resamplerRatio;
|
||||
|
||||
if (input->data.size() < desired_input_size) {
|
||||
// std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
|
||||
desired_input_size = input->data.size();
|
||||
}
|
||||
|
||||
if (centerFreq != input->frequency) {
|
||||
if ((centerFreq - input->frequency) != shiftFrequency || lastInputBandwidth != input->sampleRate) {
|
||||
if (abs(input->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) {
|
||||
shiftFrequency = centerFreq - input->frequency;
|
||||
nco_crcf_reset(freqShifter);
|
||||
nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) input->sampleRate)));
|
||||
}
|
||||
}
|
||||
|
||||
if (shiftBuffer.size() != desired_input_size) {
|
||||
if (shiftBuffer.capacity() < desired_input_size) {
|
||||
shiftBuffer.reserve(desired_input_size);
|
||||
}
|
||||
shiftBuffer.resize(desired_input_size);
|
||||
}
|
||||
|
||||
if (shiftFrequency < 0) {
|
||||
nco_crcf_mix_block_up(freqShifter, &input->data[0], &shiftBuffer[0], desired_input_size);
|
||||
} else {
|
||||
nco_crcf_mix_block_down(freqShifter, &input->data[0], &shiftBuffer[0], desired_input_size);
|
||||
}
|
||||
} else {
|
||||
shiftBuffer.assign(input->data.begin(), input->data.end());
|
||||
}
|
||||
|
||||
if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != input->sampleRate) {
|
||||
float As = 60.0f;
|
||||
|
||||
if (resampler) {
|
||||
msresamp_crcf_destroy(resampler);
|
||||
}
|
||||
resampler = msresamp_crcf_create(resamplerRatio, As);
|
||||
|
||||
lastBandwidth = bandwidth;
|
||||
lastInputBandwidth = input->sampleRate;
|
||||
}
|
||||
|
||||
|
||||
int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512;
|
||||
|
||||
if (resampleBuffer.size() != out_size) {
|
||||
if (resampleBuffer.capacity() < out_size) {
|
||||
resampleBuffer.reserve(out_size);
|
||||
}
|
||||
resampleBuffer.resize(out_size);
|
||||
}
|
||||
|
||||
|
||||
msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written);
|
||||
|
||||
resampleBuffer.resize(fft_size);
|
||||
|
||||
if (num_written < fft_size) {
|
||||
for (int i = 0; i < num_written; i++) {
|
||||
fft_in_data[i][0] = resampleBuffer[i].real;
|
||||
fft_in_data[i][1] = resampleBuffer[i].imag;
|
||||
}
|
||||
for (int i = num_written; i < fft_size; i++) {
|
||||
fft_in_data[i][0] = 0;
|
||||
fft_in_data[i][1] = 0;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < fft_size; i++) {
|
||||
fft_in_data[i][0] = resampleBuffer[i].real;
|
||||
fft_in_data[i][1] = resampleBuffer[i].imag;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
num_written = data->size();
|
||||
if (data->size() < fft_size) {
|
||||
for (int i = 0, iMax = data->size(); i < iMax; i++) {
|
||||
fft_in_data[i][0] = (*data)[i].real;
|
||||
fft_in_data[i][1] = (*data)[i].imag;
|
||||
}
|
||||
for (int i = data->size(); i < fft_size; i++) {
|
||||
fft_in_data[i][0] = 0;
|
||||
fft_in_data[i][1] = 0;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < fft_size; i++) {
|
||||
fft_in_data[i][0] = (*data)[i].real;
|
||||
fft_in_data[i][1] = (*data)[i].imag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool execute = false;
|
||||
|
||||
if (num_written >= fft_size) {
|
||||
execute = true;
|
||||
memcpy(in, fft_in_data, fft_size * sizeof(fftwf_complex));
|
||||
memcpy(fft_last_data, in, fft_size * sizeof(fftwf_complex));
|
||||
|
||||
} else {
|
||||
if (last_data_size + num_written < fft_size) { // priming
|
||||
unsigned int num_copy = fft_size - last_data_size;
|
||||
if (num_written > num_copy) {
|
||||
num_copy = num_written;
|
||||
}
|
||||
memcpy(fft_last_data, fft_in_data, num_copy * sizeof(fftwf_complex));
|
||||
last_data_size += num_copy;
|
||||
} else {
|
||||
unsigned int num_last = (fft_size - num_written);
|
||||
memcpy(in, fft_last_data + (last_data_size - num_last), num_last * sizeof(fftwf_complex));
|
||||
memcpy(in + num_last, fft_in_data, num_written * sizeof(fftwf_complex));
|
||||
memcpy(fft_last_data, in, fft_size * sizeof(fftwf_complex));
|
||||
execute = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (execute) {
|
||||
fftwf_execute(plan);
|
||||
|
||||
float fft_ceil = 0, fft_floor = 1;
|
||||
|
||||
if (fft_result.size() < fft_size) {
|
||||
fft_result.resize(fft_size);
|
||||
fft_result_ma.resize(fft_size);
|
||||
fft_result_maa.resize(fft_size);
|
||||
}
|
||||
|
||||
int n;
|
||||
for (int i = 0, iMax = fft_size / 2; i < iMax; i++) {
|
||||
float a = out[i][0];
|
||||
float b = out[i][1];
|
||||
float c = sqrt(a * a + b * b);
|
||||
|
||||
float x = out[fft_size / 2 + i][0];
|
||||
float y = out[fft_size / 2 + i][1];
|
||||
float z = sqrt(x * x + y * y);
|
||||
|
||||
fft_result[i] = (z);
|
||||
fft_result[fft_size / 2 + i] = (c);
|
||||
}
|
||||
|
||||
for (int i = 0, iMax = fft_size; i < iMax; i++) {
|
||||
if (isView) {
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
if (fft_result_maa[i] > fft_ceil) {
|
||||
fft_ceil = fft_result_maa[i];
|
||||
}
|
||||
if (fft_result_maa[i] < fft_floor) {
|
||||
fft_floor = fft_result_maa[i];
|
||||
}
|
||||
}
|
||||
|
||||
fft_ceil += 0.25;
|
||||
fft_floor -= 1;
|
||||
|
||||
fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05;
|
||||
fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05;
|
||||
|
||||
fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05;
|
||||
fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05;
|
||||
|
||||
for (int i = 0, iMax = fft_size; i < iMax; i++) {
|
||||
float v = (log10(fft_result_maa[i] - fft_floor_maa) / log10(fft_ceil_maa - fft_floor_maa));
|
||||
spectrum_points[i * 2] = ((float) i / (float) iMax);
|
||||
spectrum_points[i * 2 + 1] = v;
|
||||
}
|
||||
|
||||
if (spectrumCanvas) {
|
||||
spectrumCanvas->spectrum_points.assign(spectrum_points.begin(), spectrum_points.end());
|
||||
spectrumCanvas->getSpectrumContext()->setCeilValue(fft_ceil_maa);
|
||||
spectrumCanvas->getSpectrumContext()->setFloorValue(fft_floor_maa);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallCanvas::OnIdle(wxIdleEvent &event) {
|
||||
Refresh(false);
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
@@ -671,7 +417,6 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
setStatusText("Click and drag to set the current demodulator range.");
|
||||
}
|
||||
} else if (demodsHover->size() && !shiftDown) {
|
||||
int hovered = -1;
|
||||
long near_dist = getBandwidth();
|
||||
|
||||
DemodulatorInstance *activeDemodulator = NULL;
|
||||
@@ -963,16 +708,6 @@ void WaterfallCanvas::OnMouseRightReleased(wxMouseEvent& event) {
|
||||
mouseZoom = 1.0;
|
||||
}
|
||||
|
||||
void WaterfallCanvas::attachWaterfallCanvas(WaterfallCanvas* canvas_in) {
|
||||
otherWaterfallCanvas = canvas_in;
|
||||
otherWaterfallCanvas->setPolling(false);
|
||||
}
|
||||
|
||||
|
||||
bool WaterfallCanvas::isPolling() {
|
||||
return polling;
|
||||
}
|
||||
|
||||
void WaterfallCanvas::setPolling(bool polling) {
|
||||
this->polling = polling;
|
||||
SpectrumVisualDataQueue *WaterfallCanvas::getVisualDataQueue() {
|
||||
return &visualDataQueue;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
#include <queue>
|
||||
|
||||
#include "InteractiveCanvas.h"
|
||||
#include "WaterfallContext.h"
|
||||
#include "MouseTracker.h"
|
||||
#include "SpectrumCanvas.h"
|
||||
#include "WaterfallPanel.h"
|
||||
|
||||
#include "fftw3.h"
|
||||
|
||||
class WaterfallCanvas: public InteractiveCanvas {
|
||||
public:
|
||||
@@ -23,16 +22,11 @@ public:
|
||||
void setup(int fft_size_in, int waterfall_lines_in);
|
||||
~WaterfallCanvas();
|
||||
|
||||
void setData(DemodulatorThreadIQData *input);
|
||||
|
||||
DragState getDragState();
|
||||
DragState getNextDragState();
|
||||
|
||||
|
||||
void attachSpectrumCanvas(SpectrumCanvas *canvas_in);
|
||||
void attachWaterfallCanvas(WaterfallCanvas *canvas_in);
|
||||
|
||||
bool isPolling();
|
||||
void setPolling(bool polling);
|
||||
SpectrumVisualDataQueue *getVisualDataQueue();
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
@@ -53,21 +47,8 @@ private:
|
||||
std::vector<float> spectrum_points;
|
||||
|
||||
SpectrumCanvas *spectrumCanvas;
|
||||
WaterfallCanvas *otherWaterfallCanvas;
|
||||
bool polling;
|
||||
|
||||
fftwf_complex *in, *out, *fft_in_data, *fft_last_data;
|
||||
unsigned int last_data_size;
|
||||
fftwf_plan plan;
|
||||
|
||||
float fft_ceil_ma, fft_ceil_maa;
|
||||
float fft_floor_ma, fft_floor_maa;
|
||||
|
||||
std::vector<float> fft_result;
|
||||
std::vector<float> fft_result_ma;
|
||||
std::vector<float> fft_result_maa;
|
||||
|
||||
WaterfallContext *glContext;
|
||||
PrimaryGLContext *glContext;
|
||||
WaterfallPanel waterfallPanel;
|
||||
|
||||
DragState dragState;
|
||||
DragState nextDragState;
|
||||
@@ -76,18 +57,10 @@ private:
|
||||
int waterfall_lines;
|
||||
int dragOfs;
|
||||
|
||||
msresamp_crcf resampler;
|
||||
double resamplerRatio;
|
||||
nco_crcf freqShifter;
|
||||
long shiftFrequency;
|
||||
|
||||
int lastInputBandwidth;
|
||||
float mouseZoom, zoom;
|
||||
float hoverAlpha;
|
||||
|
||||
std::vector<liquid_float_complex> shiftBuffer;
|
||||
std::vector<liquid_float_complex> resampleBuffer;
|
||||
|
||||
SpectrumVisualDataQueue visualDataQueue;
|
||||
|
||||
// event table
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "PrimaryGLContext.h"
|
||||
#include "Gradient.h"
|
||||
#include "ColorTheme.h"
|
||||
|
||||
class WaterfallCanvas;
|
||||
|
||||
class WaterfallContext: public PrimaryGLContext {
|
||||
public:
|
||||
WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext);
|
||||
|
||||
void Draw(std::vector<float> &points);
|
||||
void Setup(int fft_size_in, int num_waterfall_lines_in);
|
||||
void refreshTheme();
|
||||
|
||||
private:
|
||||
GLuint waterfall[2];
|
||||
int waterfall_ofs[2];
|
||||
int fft_size;
|
||||
int waterfall_lines;
|
||||
unsigned char *waterfall_slice;
|
||||
|
||||
ColorTheme *activeTheme;
|
||||
};
|
||||
Reference in New Issue
Block a user