Merge pull request #137 from cjcliffe/audio_spectrum
Audio spectrum visuals + fixes
This commit is contained in:
commit
8dd46eb1ab
|
@ -74,13 +74,24 @@ namespace CubicVR {
|
||||||
|
|
||||||
return mOut;
|
return mOut;
|
||||||
}
|
}
|
||||||
|
static mat4 frustum(__float left, __float right, __float bottom, __float top, __float zNear, __float zFar) {
|
||||||
static mat4 perspective(__float fovy, __float aspect, __float znear, __float zfar) {
|
__float A = (right + left) / (right - left);
|
||||||
|
__float B = (top + bottom) / (top - bottom);
|
||||||
|
__float C = - (zFar + zNear) / (zFar - zNear);
|
||||||
|
__float D = - (-2.0 * zFar * zNear) / (zFar - zNear);
|
||||||
|
|
||||||
|
|
||||||
|
return mat4((2.0 * zNear) / (right - left), 0, A, 0,
|
||||||
|
0, (2.0 * zNear) / (top - bottom), B, 0,
|
||||||
|
0, 0, C, D,
|
||||||
|
0, 0, -1, 0);
|
||||||
|
};
|
||||||
|
static mat4 perspective(__float fovy, __float aspect, __float zNear, __float zFar) {
|
||||||
__float yFac = tan(fovy * (float)M_PI / 360.0f);
|
__float yFac = tan(fovy * (float)M_PI / 360.0f);
|
||||||
__float xFac = yFac * aspect;
|
__float xFac = yFac * aspect;
|
||||||
|
|
||||||
return mat4(
|
return mat4::frustum(-xFac, xFac, -yFac, yFac, zNear, zFar);
|
||||||
1.0f / xFac, 0, 0, 0, 0, 1.0f / yFac, 0, 0, 0, 0, -(zfar + znear) / (zfar - znear), -1, 0, 0, -(2.0f * zfar * znear) / (zfar - znear), 0);
|
|
||||||
};
|
};
|
||||||
static mat4 ortho(__float left,__float right,__float bottom,__float top,__float znear,__float zfar) {
|
static mat4 ortho(__float left,__float right,__float bottom,__float top,__float znear,__float zfar) {
|
||||||
return mat4(2.0f / (right - left), 0, 0, 0, 0, 2.0f / (top - bottom), 0, 0, 0, 0, -2.0f / (zfar - znear), 0, -(left + right) / (right - left), -(top + bottom) / (top - bottom), -(zfar + znear) / (zfar - znear), 1);
|
return mat4(2.0f / (right - left), 0, 0, 0, 0, 2.0f / (top - bottom), 0, 0, 0, 0, -2.0f / (zfar - znear), 0, -(left + right) / (right - left), -(top + bottom) / (top - bottom), -(zfar + znear) / (zfar - znear), 1);
|
||||||
|
@ -300,8 +311,18 @@ namespace CubicVR {
|
||||||
|
|
||||||
return mat4::translate(-eyex,-eyey,-eyez) * mat4( side[0], up[0], -forward[0], 0, side[1], up[1], -forward[1], 0, side[2], up[2], -forward[2], 0, 0, 0, 0, 1);
|
return mat4::translate(-eyex,-eyey,-eyez) * mat4( side[0], up[0], -forward[0], 0, side[1], up[1], -forward[1], 0, side[2], up[2], -forward[2], 0, 0, 0, 0, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static vec3 unProject(mat4 pMatrix, mat4 mvMatrix, float width, float height, float winx, float winy, float winz) {
|
||||||
|
vec4 p(((winx / width) * 2.0) - 1.0, -(((winy / height) * 2.0) - 1.0), 1.0, 1.0);
|
||||||
|
|
||||||
|
vec4 invp = mat4::vec4_multiply(mat4::vec4_multiply(p, mat4::inverse(pMatrix)), mat4::inverse(mvMatrix));
|
||||||
|
|
||||||
|
vec3 result(invp[0] / invp[3], invp[1] / invp[3], invp[2] / invp[3]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* defined(__CubicVR2__mat4__) */
|
#endif /* defined(__CubicVR2__mat4__) */
|
||||||
|
|
Binary file not shown.
|
@ -90,7 +90,9 @@ AppFrame::AppFrame() :
|
||||||
demodTray->AddSpacer(1);
|
demodTray->AddSpacer(1);
|
||||||
|
|
||||||
scopeCanvas = new ScopeCanvas(this, attribList);
|
scopeCanvas = new ScopeCanvas(this, attribList);
|
||||||
|
scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum.");
|
||||||
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
|
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
|
||||||
|
wxGetApp().getScopeProcessor()->setup(2048);
|
||||||
wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue());
|
wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue());
|
||||||
|
|
||||||
demodScopeTray->AddSpacer(1);
|
demodScopeTray->AddSpacer(1);
|
||||||
|
@ -153,11 +155,12 @@ AppFrame::AppFrame() :
|
||||||
waterfallCanvas->setup(2048, 512);
|
waterfallCanvas->setup(2048, 512);
|
||||||
|
|
||||||
waterfallDataThread = new FFTVisualDataThread();
|
waterfallDataThread = new FFTVisualDataThread();
|
||||||
t_FFTData = new std::thread(&FFTVisualDataThread::threadMain, waterfallDataThread);
|
|
||||||
|
|
||||||
waterfallDataThread->setInputQueue("IQDataInput", wxGetApp().getWaterfallVisualQueue());
|
waterfallDataThread->setInputQueue("IQDataInput", wxGetApp().getWaterfallVisualQueue());
|
||||||
waterfallDataThread->setOutputQueue("FFTDataOutput", waterfallCanvas->getVisualDataQueue());
|
waterfallDataThread->setOutputQueue("FFTDataOutput", waterfallCanvas->getVisualDataQueue());
|
||||||
|
|
||||||
|
t_FFTData = new std::thread(&FFTVisualDataThread::threadMain, waterfallDataThread);
|
||||||
|
|
||||||
waterfallSpeedMeter = new MeterCanvas(this, attribList);
|
waterfallSpeedMeter = new MeterCanvas(this, attribList);
|
||||||
waterfallSpeedMeter->setHelpTip("Waterfall speed, click or drag to adjust (max 1024 lines per second)");
|
waterfallSpeedMeter->setHelpTip("Waterfall speed, click or drag to adjust (max 1024 lines per second)");
|
||||||
waterfallSpeedMeter->setMax(sqrt(1024));
|
waterfallSpeedMeter->setMax(sqrt(1024));
|
||||||
|
@ -789,6 +792,11 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||||
|
|
||||||
scopeCanvas->setPPMMode(demodTuner->isAltDown());
|
scopeCanvas->setPPMMode(demodTuner->isAltDown());
|
||||||
|
|
||||||
|
scopeCanvas->setShowDb(spectrumCanvas->getShowDb());
|
||||||
|
wxGetApp().getScopeProcessor()->setScopeEnabled(scopeCanvas->scopeVisible());
|
||||||
|
wxGetApp().getScopeProcessor()->setSpectrumEnabled(scopeCanvas->spectrumVisible());
|
||||||
|
wxGetApp().getAudioVisualQueue()->set_max_num_items((scopeCanvas->scopeVisible()?1:0) + (scopeCanvas->spectrumVisible()?1:0));
|
||||||
|
|
||||||
wxGetApp().getScopeProcessor()->run();
|
wxGetApp().getScopeProcessor()->run();
|
||||||
wxGetApp().getSpectrumDistributor()->run();
|
wxGetApp().getSpectrumDistributor()->run();
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
class AudioThreadInput: public ReferenceCounter {
|
class AudioThreadInput: public ReferenceCounter {
|
||||||
public:
|
public:
|
||||||
long long frequency;
|
long long frequency;
|
||||||
|
int inputRate;
|
||||||
int sampleRate;
|
int sampleRate;
|
||||||
int channels;
|
int channels;
|
||||||
float peak;
|
float peak;
|
||||||
|
|
|
@ -72,9 +72,6 @@ void DemodulatorPreThread::initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
DemodulatorPreThread::~DemodulatorPreThread() {
|
DemodulatorPreThread::~DemodulatorPreThread() {
|
||||||
delete workerThread;
|
|
||||||
delete workerQueue;
|
|
||||||
delete workerResults;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemodulatorPreThread::run() {
|
void DemodulatorPreThread::run() {
|
||||||
|
@ -260,7 +257,7 @@ void DemodulatorPreThread::run() {
|
||||||
|
|
||||||
inp->decRefCount();
|
inp->decRefCount();
|
||||||
|
|
||||||
if (!workerResults->empty()) {
|
if (!terminated && !workerResults->empty()) {
|
||||||
while (!workerResults->empty()) {
|
while (!workerResults->empty()) {
|
||||||
DemodulatorWorkerThreadResult result;
|
DemodulatorWorkerThreadResult result;
|
||||||
workerResults->pop(result);
|
workerResults->pop(result);
|
||||||
|
@ -323,7 +320,12 @@ void DemodulatorPreThread::terminate() {
|
||||||
terminated = true;
|
terminated = true;
|
||||||
DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue
|
DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue
|
||||||
iqInputQueue->push(inp);
|
iqInputQueue->push(inp);
|
||||||
|
DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_NULL);
|
||||||
|
workerQueue->push(command);
|
||||||
workerThread->terminate();
|
workerThread->terminate();
|
||||||
t_Worker->detach();
|
t_Worker->join();
|
||||||
delete t_Worker;
|
delete t_Worker;
|
||||||
|
delete workerThread;
|
||||||
|
delete workerResults;
|
||||||
|
delete workerQueue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -310,6 +310,7 @@ void DemodulatorThread::run() {
|
||||||
ati = outputBuffers.getBuffer();
|
ati = outputBuffers.getBuffer();
|
||||||
|
|
||||||
ati->sampleRate = audioSampleRate;
|
ati->sampleRate = audioSampleRate;
|
||||||
|
ati->inputRate = inp->sampleRate;
|
||||||
ati->setRefCount(1);
|
ati->setRefCount(1);
|
||||||
|
|
||||||
if (demodulatorType == DEMOD_TYPE_RAW) {
|
if (demodulatorType == DEMOD_TYPE_RAW) {
|
||||||
|
@ -359,7 +360,9 @@ void DemodulatorThread::run() {
|
||||||
if (ati && audioVisOutputQueue != NULL && audioVisOutputQueue->empty()) {
|
if (ati && audioVisOutputQueue != NULL && audioVisOutputQueue->empty()) {
|
||||||
|
|
||||||
ati_vis->busy_update.lock();
|
ati_vis->busy_update.lock();
|
||||||
|
ati_vis->sampleRate = inp->sampleRate;
|
||||||
|
ati_vis->inputRate = inp->sampleRate;
|
||||||
|
|
||||||
int num_vis = DEMOD_VIS_SIZE;
|
int num_vis = DEMOD_VIS_SIZE;
|
||||||
if (demodulatorType == DEMOD_TYPE_RAW || (stereo && inp->sampleRate >= 100000)) {
|
if (demodulatorType == DEMOD_TYPE_RAW || (stereo && inp->sampleRate >= 100000)) {
|
||||||
ati_vis->channels = 2;
|
ati_vis->channels = 2;
|
||||||
|
@ -377,6 +380,8 @@ void DemodulatorThread::run() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < stereoSize / 2; i++) {
|
for (int i = 0; i < stereoSize / 2; i++) {
|
||||||
|
ati_vis->inputRate = audioSampleRate;
|
||||||
|
ati_vis->sampleRate = 36000;
|
||||||
ati_vis->data[i] = ati->data[i * 2];
|
ati_vis->data[i] = ati->data[i * 2];
|
||||||
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
|
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
|
||||||
}
|
}
|
||||||
|
@ -384,7 +389,7 @@ void DemodulatorThread::run() {
|
||||||
} else {
|
} else {
|
||||||
ati_vis->channels = 1;
|
ati_vis->channels = 1;
|
||||||
if (numAudioWritten > bufSize) {
|
if (numAudioWritten > bufSize) {
|
||||||
|
ati_vis->inputRate = audioSampleRate;
|
||||||
if (num_vis > numAudioWritten) {
|
if (num_vis > numAudioWritten) {
|
||||||
num_vis = numAudioWritten;
|
num_vis = numAudioWritten;
|
||||||
}
|
}
|
||||||
|
@ -399,9 +404,8 @@ void DemodulatorThread::run() {
|
||||||
// std::cout << "Signal: " << agc_crcf_get_signal_level(agc) << " -- " << agc_crcf_get_rssi(agc) << "dB " << std::endl;
|
// std::cout << "Signal: " << agc_crcf_get_signal_level(agc) << " -- " << agc_crcf_get_rssi(agc) << "dB " << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioVisOutputQueue->push(ati_vis);
|
|
||||||
|
|
||||||
ati_vis->busy_update.unlock();
|
ati_vis->busy_update.unlock();
|
||||||
|
audioVisOutputQueue->push(ati_vis);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ati != NULL) {
|
if (ati != NULL) {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
typedef ThreadQueue<AudioThreadInput *> DemodulatorThreadOutputQueue;
|
typedef ThreadQueue<AudioThreadInput *> DemodulatorThreadOutputQueue;
|
||||||
|
|
||||||
#define DEMOD_VIS_SIZE 1024
|
#define DEMOD_VIS_SIZE 2048
|
||||||
|
|
||||||
class DemodulatorThread : public IOThread {
|
class DemodulatorThread : public IOThread {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "ColorTheme.h"
|
#include "ColorTheme.h"
|
||||||
|
|
||||||
ScopePanel::ScopePanel() : GLPanel(), scopeMode(SCOPE_MODE_Y) {
|
ScopePanel::ScopePanel() : GLPanel(), scopeMode(SCOPE_MODE_Y) {
|
||||||
|
setFill(GLPanelFillType::GLPANEL_FILL_NONE);
|
||||||
bgPanel.setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
|
bgPanel.setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
|
||||||
bgPanelStereo[0].setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
|
bgPanelStereo[0].setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
|
||||||
bgPanelStereo[0].setPosition(0, 0.5);
|
bgPanelStereo[0].setPosition(0, 0.5);
|
||||||
|
@ -21,14 +22,13 @@ void ScopePanel::setPoints(std::vector<float> &points) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopePanel::drawPanelContents() {
|
void ScopePanel::drawPanelContents() {
|
||||||
|
|
||||||
glLineWidth(1.0);
|
|
||||||
|
|
||||||
if (scopeMode == SCOPE_MODE_Y) {
|
if (scopeMode == SCOPE_MODE_Y) {
|
||||||
bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground, ThemeMgr::mgr.currentTheme->scopeBackground * 2.0);
|
bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground, ThemeMgr::mgr.currentTheme->scopeBackground * 2.0);
|
||||||
bgPanel.calcTransform(transform);
|
bgPanel.calcTransform(transform);
|
||||||
bgPanel.draw();
|
bgPanel.draw();
|
||||||
|
glLineWidth(1.0);
|
||||||
|
glEnable(GL_LINE_SMOOTH);
|
||||||
glLoadMatrixf(transform);
|
glLoadMatrixf(transform);
|
||||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
|
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
|
||||||
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
|
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
|
||||||
|
@ -45,8 +45,10 @@ void ScopePanel::drawPanelContents() {
|
||||||
bgPanelStereo[1].calcTransform(transform);
|
bgPanelStereo[1].calcTransform(transform);
|
||||||
bgPanelStereo[1].draw();
|
bgPanelStereo[1].draw();
|
||||||
|
|
||||||
|
glLineWidth(1.0);
|
||||||
glLoadMatrixf(transform);
|
glLoadMatrixf(transform);
|
||||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b);
|
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b);
|
||||||
|
glEnable(GL_LINE_SMOOTH);
|
||||||
glBegin (GL_LINES);
|
glBegin (GL_LINES);
|
||||||
glVertex2f(-1.0, 0.0);
|
glVertex2f(-1.0, 0.0);
|
||||||
glVertex2f(1.0, 0.0);
|
glVertex2f(1.0, 0.0);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include "ColorTheme.h"
|
#include "ColorTheme.h"
|
||||||
|
|
||||||
SpectrumPanel::SpectrumPanel() : floorValue(0), ceilValue(1), showDb(false) {
|
SpectrumPanel::SpectrumPanel() : floorValue(0), ceilValue(1), showDb(false), fftSize(2048) {
|
||||||
setFill(GLPANEL_FILL_GRAD_Y);
|
setFill(GLPANEL_FILL_GRAD_Y);
|
||||||
setFillColor(ThemeMgr::mgr.currentTheme->fftBackground * 2.0, ThemeMgr::mgr.currentTheme->fftBackground);
|
setFillColor(ThemeMgr::mgr.currentTheme->fftBackground * 2.0, ThemeMgr::mgr.currentTheme->fftBackground);
|
||||||
|
|
||||||
|
@ -51,6 +51,14 @@ long long SpectrumPanel::getBandwidth() {
|
||||||
return bandwidth;
|
return bandwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpectrumPanel::setFFTSize(int fftSize_in) {
|
||||||
|
this->fftSize = fftSize_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SpectrumPanel::getFFTSize() {
|
||||||
|
return fftSize;
|
||||||
|
}
|
||||||
|
|
||||||
void SpectrumPanel::setShowDb(bool showDb) {
|
void SpectrumPanel::setShowDb(bool showDb) {
|
||||||
this->showDb = showDb;
|
this->showDb = showDb;
|
||||||
if (showDb) {
|
if (showDb) {
|
||||||
|
@ -132,27 +140,58 @@ void SpectrumPanel::drawPanelContents() {
|
||||||
|
|
||||||
long long leftFreq = (double) freq - ((double) bandwidth / 2.0);
|
long long leftFreq = (double) freq - ((double) bandwidth / 2.0);
|
||||||
long long rightFreq = leftFreq + (double) bandwidth;
|
long long rightFreq = leftFreq + (double) bandwidth;
|
||||||
|
|
||||||
long long firstMhz = (leftFreq / 1000000) * 1000000;
|
long long hzStep = 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;
|
long double mhzStep = (100000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
double mhzVisualStep = 0.1f;
|
double mhzVisualStep = 0.1;
|
||||||
|
|
||||||
|
std::stringstream label;
|
||||||
|
label.precision(1);
|
||||||
|
|
||||||
if (mhzStep * 0.5 * viewWidth < 40) {
|
if (mhzStep * 0.5 * viewWidth < 40) {
|
||||||
mhzStep = (250000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
mhzStep = (250000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
mhzVisualStep = 0.25f;
|
mhzVisualStep = 0.25;
|
||||||
}
|
|
||||||
|
|
||||||
if (mhzStep * 0.5 * viewWidth > 400) {
|
if (mhzStep * 0.5 * viewWidth < 40) {
|
||||||
|
mhzStep = (500000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
|
mhzVisualStep = 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mhzStep * 0.5 * viewWidth < 40) {
|
||||||
|
mhzStep = (1000000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
|
mhzVisualStep = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mhzStep * 0.5 * viewWidth < 40) {
|
||||||
|
mhzStep = (2500000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
|
mhzVisualStep = 2.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mhzStep * 0.5 * viewWidth < 40) {
|
||||||
|
mhzStep = (5000000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
|
mhzVisualStep = 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mhzStep * 0.5 * viewWidth < 40) {
|
||||||
|
mhzStep = (10000000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
|
mhzVisualStep = 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mhzStep * 0.5 * viewWidth < 40) {
|
||||||
|
mhzStep = (50000000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
|
mhzVisualStep = 50.0;
|
||||||
|
}
|
||||||
|
} else if (mhzStep * 0.5 * viewWidth > 350) {
|
||||||
mhzStep = (10000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
mhzStep = (10000.0 / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
mhzVisualStep = 0.01f;
|
mhzVisualStep = 0.01;
|
||||||
|
label.precision(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
long double currentMhz = trunc(floor(firstMhz / 1000000.0));
|
|
||||||
|
|
||||||
std::stringstream label;
|
long long firstMhz = (leftFreq / hzStep) * hzStep;
|
||||||
label.precision(2);
|
long double mhzStart = ((long double) (firstMhz - leftFreq) / (long double) (rightFreq - leftFreq)) * 2.0;
|
||||||
|
long double currentMhz = trunc(floor(firstMhz / (long double)1000000.0));
|
||||||
|
|
||||||
|
|
||||||
double hPos = 1.0 - (16.0 / viewHeight);
|
double hPos = 1.0 - (16.0 / viewHeight);
|
||||||
double lMhzPos = 1.0 - (5.0 / viewHeight);
|
double lMhzPos = 1.0 - (5.0 / viewHeight);
|
||||||
|
@ -189,21 +228,20 @@ void SpectrumPanel::drawPanelContents() {
|
||||||
|
|
||||||
glLineWidth(1.0);
|
glLineWidth(1.0);
|
||||||
|
|
||||||
|
|
||||||
if (showDb) {
|
if (showDb) {
|
||||||
float dbPanelWidth = (1.0/viewWidth)*75.0;
|
float dbPanelWidth = (1.0/viewWidth)*75.0;
|
||||||
float dbPanelHeight = (1.0/viewHeight)*14.0;
|
float dbPanelHeight = (1.0/viewHeight)*14.0;
|
||||||
|
|
||||||
|
|
||||||
std::stringstream ssLabel;
|
std::stringstream ssLabel;
|
||||||
ssLabel << std::fixed << std::setprecision(1) << (20.0 * log10(2.0*(getCeilValue())/2048.0)) << "dB";
|
ssLabel << std::fixed << std::setprecision(1) << (20.0 * log10(2.0*(getCeilValue())/(double)fftSize)) << "dB";
|
||||||
|
|
||||||
dbPanelCeil.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT);
|
dbPanelCeil.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT);
|
||||||
dbPanelCeil.setSize(dbPanelWidth, dbPanelHeight);
|
dbPanelCeil.setSize(dbPanelWidth, dbPanelHeight);
|
||||||
dbPanelCeil.setPosition(-1.0 + dbPanelWidth, 1.0 - dbPanelHeight);
|
dbPanelCeil.setPosition(-1.0 + dbPanelWidth, 1.0 - dbPanelHeight);
|
||||||
|
|
||||||
ssLabel.str("");
|
ssLabel.str("");
|
||||||
ssLabel << (20.0 * log10(2.0*(getFloorValue())/2048.0)) << "dB";
|
ssLabel << (20.0 * log10(2.0*(getFloorValue())/(double)fftSize)) << "dB";
|
||||||
|
|
||||||
dbPanelFloor.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT);
|
dbPanelFloor.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT);
|
||||||
dbPanelFloor.setSize(dbPanelWidth, dbPanelHeight);
|
dbPanelFloor.setSize(dbPanelWidth, dbPanelHeight);
|
||||||
|
|
|
@ -19,7 +19,10 @@ public:
|
||||||
|
|
||||||
void setBandwidth(long long bandwidth);
|
void setBandwidth(long long bandwidth);
|
||||||
long long getBandwidth();
|
long long getBandwidth();
|
||||||
|
|
||||||
|
void setFFTSize(int fftSize_in);
|
||||||
|
int getFFTSize();
|
||||||
|
|
||||||
void setShowDb(bool showDb);
|
void setShowDb(bool showDb);
|
||||||
bool getShowDb();
|
bool getShowDb();
|
||||||
|
|
||||||
|
@ -28,6 +31,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float floorValue, ceilValue;
|
float floorValue, ceilValue;
|
||||||
|
int fftSize;
|
||||||
long long freq;
|
long long freq;
|
||||||
long long bandwidth;
|
long long bandwidth;
|
||||||
std::vector<float> points;
|
std::vector<float> points;
|
||||||
|
|
|
@ -1,4 +1,54 @@
|
||||||
#include "ScopeVisualProcessor.h"
|
#include "ScopeVisualProcessor.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
ScopeVisualProcessor::ScopeVisualProcessor(): fftInData(NULL), fftwOutput(NULL), fftw_plan(NULL), maxScopeSamples(1024) {
|
||||||
|
scopeEnabled.store(true);
|
||||||
|
spectrumEnabled.store(true);
|
||||||
|
fft_average_rate = 0.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeVisualProcessor::~ScopeVisualProcessor() {
|
||||||
|
if (fftInData) {
|
||||||
|
free(fftInData);
|
||||||
|
}
|
||||||
|
if (fftwOutput) {
|
||||||
|
free(fftwOutput);
|
||||||
|
}
|
||||||
|
if (fftw_plan) {
|
||||||
|
fftwf_destroy_plan(fftw_plan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ScopeVisualProcessor::setup(int fftSize_in) {
|
||||||
|
fftSize = fftSize_in;
|
||||||
|
desiredInputSize = fftSize;
|
||||||
|
|
||||||
|
if (fftInData) {
|
||||||
|
free(fftInData);
|
||||||
|
}
|
||||||
|
fftInData = (float*) fftwf_malloc(sizeof(float) * 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_r2c_1d(fftSize, fftInData, fftwOutput, FFTW_ESTIMATE);
|
||||||
|
//(fftSize, fftInData, fftwOutput, 0);
|
||||||
|
//(fftSize, fftwInput, fftwOutput, FFTW_R2HC, FFTW_ESTIMATE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeVisualProcessor::setScopeEnabled(bool scopeEnable) {
|
||||||
|
scopeEnabled.store(scopeEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeVisualProcessor::setSpectrumEnabled(bool spectrumEnable) {
|
||||||
|
spectrumEnabled.store(spectrumEnable);
|
||||||
|
}
|
||||||
|
|
||||||
void ScopeVisualProcessor::process() {
|
void ScopeVisualProcessor::process() {
|
||||||
if (!isOutputEmpty()) {
|
if (!isOutputEmpty()) {
|
||||||
|
@ -11,42 +61,144 @@ void ScopeVisualProcessor::process() {
|
||||||
if (!audioInputData) {
|
if (!audioInputData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int iMax = audioInputData->data.size();
|
int i, iMax = audioInputData->data.size();
|
||||||
if (!iMax) {
|
if (!iMax) {
|
||||||
audioInputData->decRefCount();
|
audioInputData->decRefCount();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioInputData->busy_update.lock();
|
audioInputData->busy_update.lock();
|
||||||
ScopeRenderData *renderData = outputBuffers.getBuffer();
|
|
||||||
renderData->channels = audioInputData->channels;
|
|
||||||
|
|
||||||
if (renderData->waveform_points.size() != iMax * 2) {
|
ScopeRenderData *renderData = NULL;
|
||||||
renderData->waveform_points.resize(iMax * 2);
|
|
||||||
}
|
if (scopeEnabled) {
|
||||||
|
iMax = audioInputData->data.size();
|
||||||
|
if (iMax > maxScopeSamples) {
|
||||||
|
iMax = maxScopeSamples;
|
||||||
|
}
|
||||||
|
|
||||||
float peak = 1.0f;
|
renderData = outputBuffers.getBuffer();
|
||||||
|
renderData->channels = audioInputData->channels;
|
||||||
for (int i = 0; i < iMax; i++) {
|
renderData->inputRate = audioInputData->inputRate;
|
||||||
float p = fabs(audioInputData->data[i]);
|
renderData->sampleRate = audioInputData->sampleRate;
|
||||||
if (p > peak) {
|
|
||||||
peak = p;
|
if (renderData->waveform_points.size() != iMax * 2) {
|
||||||
|
renderData->waveform_points.resize(iMax * 2);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
float peak = 1.0f;
|
||||||
|
|
||||||
|
for (i = 0; i < iMax; i++) {
|
||||||
|
float p = fabs(audioInputData->data[i]);
|
||||||
|
if (p > peak) {
|
||||||
|
peak = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioInputData->channels == 2) {
|
||||||
|
iMax = audioInputData->data.size();
|
||||||
|
if (renderData->waveform_points.size() != iMax * 2) {
|
||||||
|
renderData->waveform_points.resize(iMax * 2);
|
||||||
|
}
|
||||||
|
for (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 (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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderData->spectrum = false;
|
||||||
|
|
||||||
|
distribute(renderData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spectrumEnabled) {
|
||||||
|
renderData = outputBuffers.getBuffer();
|
||||||
|
iMax = audioInputData->data.size();
|
||||||
|
|
||||||
|
if (audioInputData->channels==1) {
|
||||||
|
for (i = 0; i < fftSize; i++) {
|
||||||
|
if (i < iMax) {
|
||||||
|
fftInData[i] = audioInputData->data[i];
|
||||||
|
} else {
|
||||||
|
fftInData[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (audioInputData->channels==2) {
|
||||||
|
iMax = iMax/2;
|
||||||
|
for (i = 0; i < fftSize; i++) {
|
||||||
|
if (i < iMax) {
|
||||||
|
fftInData[i] = audioInputData->data[i] + audioInputData->data[iMax+i];
|
||||||
|
} else {
|
||||||
|
fftInData[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fftwf_execute(fftw_plan);
|
||||||
|
|
||||||
|
float fft_ceil = 0, fft_floor = 1;
|
||||||
|
|
||||||
|
if (fft_result.size() < (fftSize/2)) {
|
||||||
|
fft_result.resize((fftSize/2));
|
||||||
|
fft_result_ma.resize((fftSize/2));
|
||||||
|
fft_result_maa.resize((fftSize/2));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (fftSize/2); i++) {
|
||||||
|
float a = fftwOutput[i][0];
|
||||||
|
float b = fftwOutput[i][1];
|
||||||
|
fft_result[i] = sqrt( a * a + b * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (fftSize/2); i++) {
|
||||||
|
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
|
||||||
|
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
|
||||||
|
|
||||||
|
if (fft_result_maa[i] > fft_ceil) {
|
||||||
|
fft_ceil = fft_result_maa[i];
|
||||||
|
}
|
||||||
|
if (fft_result_maa[i] < fft_floor) {
|
||||||
|
fft_floor = fft_result_maa[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
int outSize = fftSize/2;
|
||||||
|
|
||||||
|
if (audioInputData->sampleRate != audioInputData->inputRate) {
|
||||||
|
outSize = (int)floor((float)outSize * ((float)audioInputData->sampleRate/(float)audioInputData->inputRate));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderData->waveform_points.size() != outSize*2) {
|
||||||
|
renderData->waveform_points.resize(outSize*2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < outSize; i++) {
|
||||||
|
float v = (log10(fft_result_maa[i]+0.25 - (fft_floor_maa-0.75)) / log10((fft_ceil_maa+0.25) - (fft_floor_maa-0.75)));
|
||||||
|
renderData->waveform_points[i * 2] = ((double) i / (double) (outSize));
|
||||||
|
renderData->waveform_points[i * 2 + 1] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderData->fft_floor = fft_floor_maa;
|
||||||
|
renderData->fft_ceil = fft_ceil_maa;
|
||||||
|
renderData->fft_size = fftSize/2;
|
||||||
|
renderData->inputRate = audioInputData->inputRate;
|
||||||
|
renderData->sampleRate = audioInputData->sampleRate;
|
||||||
|
renderData->spectrum = true;
|
||||||
|
distribute(renderData);
|
||||||
|
}
|
||||||
|
|
||||||
audioInputData->busy_update.unlock();
|
audioInputData->busy_update.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,47 @@
|
||||||
|
|
||||||
#include "VisualProcessor.h"
|
#include "VisualProcessor.h"
|
||||||
#include "AudioThread.h"
|
#include "AudioThread.h"
|
||||||
|
#include "fftw3.h"
|
||||||
|
|
||||||
class ScopeRenderData: public ReferenceCounter {
|
class ScopeRenderData: public ReferenceCounter {
|
||||||
public:
|
public:
|
||||||
std::vector<float> waveform_points;
|
std::vector<float> waveform_points;
|
||||||
|
int inputRate;
|
||||||
|
int sampleRate;
|
||||||
int channels;
|
int channels;
|
||||||
|
bool spectrum;
|
||||||
|
int fft_size;
|
||||||
|
double fft_floor, fft_ceil;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ThreadQueue<ScopeRenderData *> ScopeRenderDataQueue;
|
typedef ThreadQueue<ScopeRenderData *> ScopeRenderDataQueue;
|
||||||
|
|
||||||
class ScopeVisualProcessor : public VisualProcessor<AudioThreadInput, ScopeRenderData> {
|
class ScopeVisualProcessor : public VisualProcessor<AudioThreadInput, ScopeRenderData> {
|
||||||
|
public:
|
||||||
|
ScopeVisualProcessor();
|
||||||
|
~ScopeVisualProcessor();
|
||||||
|
void setup(int fftSize_in);
|
||||||
|
void setScopeEnabled(bool scopeEnable);
|
||||||
|
void setSpectrumEnabled(bool spectrumEnable);
|
||||||
protected:
|
protected:
|
||||||
void process();
|
void process();
|
||||||
ReBuffer<ScopeRenderData> outputBuffers;
|
ReBuffer<ScopeRenderData> outputBuffers;
|
||||||
|
|
||||||
|
std::atomic_bool scopeEnabled;
|
||||||
|
std::atomic_bool spectrumEnabled;
|
||||||
|
|
||||||
|
float *fftInData;
|
||||||
|
fftwf_complex *fftwOutput;
|
||||||
|
fftwf_plan fftw_plan;
|
||||||
|
int fftSize;
|
||||||
|
int desiredInputSize;
|
||||||
|
int maxScopeSamples;
|
||||||
|
|
||||||
|
double fft_ceil_ma, fft_ceil_maa;
|
||||||
|
double fft_floor_ma, fft_floor_maa;
|
||||||
|
float fft_average_rate;
|
||||||
|
|
||||||
|
std::vector<double> fft_result;
|
||||||
|
std::vector<double> fft_result_ma;
|
||||||
|
std::vector<double> fft_result_maa;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), last
|
||||||
|
|
||||||
fft_ceil_ma = fft_ceil_maa = 100.0;
|
fft_ceil_ma = fft_ceil_maa = 100.0;
|
||||||
fft_floor_ma = fft_floor_maa = 0.0;
|
fft_floor_ma = fft_floor_maa = 0.0;
|
||||||
desiredInputSize = 0;
|
desiredInputSize.store(0);
|
||||||
fft_average_rate = 0.65;
|
fft_average_rate = 0.65;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,19 +27,25 @@ bool SpectrumVisualProcessor::isView() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumVisualProcessor::setView(bool bView) {
|
void SpectrumVisualProcessor::setView(bool bView) {
|
||||||
|
busy_run.lock();
|
||||||
is_view.store(bView);
|
is_view.store(bView);
|
||||||
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) {
|
void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) {
|
||||||
this->fft_average_rate = fftAverageRate;
|
busy_run.lock();
|
||||||
|
this->fft_average_rate.store(fftAverageRate);
|
||||||
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
float SpectrumVisualProcessor::getFFTAverageRate() {
|
float SpectrumVisualProcessor::getFFTAverageRate() {
|
||||||
return this->fft_average_rate;
|
return this->fft_average_rate.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) {
|
void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) {
|
||||||
|
busy_run.lock();
|
||||||
centerFreq.store(centerFreq_in);
|
centerFreq.store(centerFreq_in);
|
||||||
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
long long SpectrumVisualProcessor::getCenterFrequency() {
|
long long SpectrumVisualProcessor::getCenterFrequency() {
|
||||||
|
@ -47,7 +53,9 @@ long long SpectrumVisualProcessor::getCenterFrequency() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumVisualProcessor::setBandwidth(long bandwidth_in) {
|
void SpectrumVisualProcessor::setBandwidth(long bandwidth_in) {
|
||||||
|
busy_run.lock();
|
||||||
bandwidth.store(bandwidth_in);
|
bandwidth.store(bandwidth_in);
|
||||||
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
long SpectrumVisualProcessor::getBandwidth() {
|
long SpectrumVisualProcessor::getBandwidth() {
|
||||||
|
@ -55,12 +63,14 @@ long SpectrumVisualProcessor::getBandwidth() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int SpectrumVisualProcessor::getDesiredInputSize() {
|
int SpectrumVisualProcessor::getDesiredInputSize() {
|
||||||
return desiredInputSize;
|
return desiredInputSize.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumVisualProcessor::setup(int fftSize_in) {
|
void SpectrumVisualProcessor::setup(int fftSize_in) {
|
||||||
|
busy_run.lock();
|
||||||
|
|
||||||
fftSize = fftSize_in;
|
fftSize = fftSize_in;
|
||||||
desiredInputSize = fftSize;
|
desiredInputSize.store(fftSize);
|
||||||
|
|
||||||
if (fftwInput) {
|
if (fftwInput) {
|
||||||
free(fftwInput);
|
free(fftwInput);
|
||||||
|
@ -82,7 +92,7 @@ void SpectrumVisualProcessor::setup(int fftSize_in) {
|
||||||
fftwf_destroy_plan(fftw_plan);
|
fftwf_destroy_plan(fftw_plan);
|
||||||
}
|
}
|
||||||
fftw_plan = fftwf_plan_dft_1d(fftSize, fftwInput, fftwOutput, FFTW_FORWARD, FFTW_ESTIMATE);
|
fftw_plan = fftwf_plan_dft_1d(fftSize, fftwInput, fftwOutput, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||||
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumVisualProcessor::process() {
|
void SpectrumVisualProcessor::process() {
|
||||||
|
@ -102,6 +112,7 @@ void SpectrumVisualProcessor::process() {
|
||||||
}
|
}
|
||||||
|
|
||||||
iqData->busy_rw.lock();
|
iqData->busy_rw.lock();
|
||||||
|
busy_run.lock();
|
||||||
|
|
||||||
std::vector<liquid_float_complex> *data = &iqData->data;
|
std::vector<liquid_float_complex> *data = &iqData->data;
|
||||||
|
|
||||||
|
@ -118,6 +129,7 @@ void SpectrumVisualProcessor::process() {
|
||||||
if (!iqData->frequency || !iqData->sampleRate) {
|
if (!iqData->frequency || !iqData->sampleRate) {
|
||||||
iqData->decRefCount();
|
iqData->decRefCount();
|
||||||
iqData->busy_rw.unlock();
|
iqData->busy_rw.unlock();
|
||||||
|
busy_run.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +137,7 @@ void SpectrumVisualProcessor::process() {
|
||||||
|
|
||||||
int desired_input_size = fftSize / resamplerRatio;
|
int desired_input_size = fftSize / resamplerRatio;
|
||||||
|
|
||||||
this->desiredInputSize = desired_input_size;
|
this->desiredInputSize.store(desired_input_size);
|
||||||
|
|
||||||
if (iqData->data.size() < desired_input_size) {
|
if (iqData->data.size() < desired_input_size) {
|
||||||
// std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
|
// std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
|
||||||
|
@ -304,5 +316,6 @@ void SpectrumVisualProcessor::process() {
|
||||||
|
|
||||||
iqData->decRefCount();
|
iqData->decRefCount();
|
||||||
iqData->busy_rw.unlock();
|
iqData->busy_rw.unlock();
|
||||||
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ private:
|
||||||
|
|
||||||
double fft_ceil_ma, fft_ceil_maa;
|
double fft_ceil_ma, fft_ceil_maa;
|
||||||
double fft_floor_ma, fft_floor_maa;
|
double fft_floor_ma, fft_floor_maa;
|
||||||
float fft_average_rate;
|
std::atomic<float> fft_average_rate;
|
||||||
|
|
||||||
std::vector<double> fft_result;
|
std::vector<double> fft_result;
|
||||||
std::vector<double> fft_result_ma;
|
std::vector<double> fft_result_ma;
|
||||||
|
@ -66,7 +66,8 @@ private:
|
||||||
|
|
||||||
std::vector<liquid_float_complex> shiftBuffer;
|
std::vector<liquid_float_complex> shiftBuffer;
|
||||||
std::vector<liquid_float_complex> resampleBuffer;
|
std::vector<liquid_float_complex> resampleBuffer;
|
||||||
int desiredInputSize;
|
std::atomic_int desiredInputSize;
|
||||||
|
std::mutex busy_run;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@ using namespace CubicVR;
|
||||||
GLPanel::GLPanel() : fillType(GLPANEL_FILL_SOLID), contentsVisible(true), transform(mat4::identity()) {
|
GLPanel::GLPanel() : fillType(GLPANEL_FILL_SOLID), contentsVisible(true), transform(mat4::identity()) {
|
||||||
pos[0] = 0.0f;
|
pos[0] = 0.0f;
|
||||||
pos[1] = 0.0f;
|
pos[1] = 0.0f;
|
||||||
|
rot[0] = 0.0f;
|
||||||
|
rot[1] = 0.0f;
|
||||||
|
rot[2] = 0.0f;
|
||||||
size[0] = 1.0f;
|
size[0] = 1.0f;
|
||||||
size[1] = 1.0f;
|
size[1] = 1.0f;
|
||||||
fill[0] = RGBA4f(0.5,0.5,0.5);
|
fill[0] = RGBA4f(0.5,0.5,0.5);
|
||||||
|
@ -241,6 +244,11 @@ void GLPanel::drawPanelContents() {
|
||||||
void GLPanel::calcTransform(mat4 transform_in) {
|
void GLPanel::calcTransform(mat4 transform_in) {
|
||||||
// compute local transform
|
// compute local transform
|
||||||
localTransform = mat4::translate(pos[0], pos[1], 0) * mat4::scale(size[0], size[1], 1);
|
localTransform = mat4::translate(pos[0], pos[1], 0) * mat4::scale(size[0], size[1], 1);
|
||||||
|
|
||||||
|
if (rot[0] || rot[1] || rot[2]) {
|
||||||
|
localTransform *= mat4::rotate(rot[0], rot[1], rot[2]);
|
||||||
|
}
|
||||||
|
|
||||||
// compute global transform
|
// compute global transform
|
||||||
transform = transform_in * localTransform;
|
transform = transform_in * localTransform;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ 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 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;
|
typedef enum GLPanelCoordinateSystem { GLPANEL_Y_DOWN_ZERO_ONE, GLPANEL_Y_UP_ZERO_ONE, GLPANEL_Y_UP, GLPANEL_Y_DOWN } GLPanelCoordinateSystem;
|
||||||
float pos[2];
|
float pos[2];
|
||||||
|
float rot[3];
|
||||||
float size[2];
|
float size[2];
|
||||||
float view[2];
|
float view[2];
|
||||||
GLPanelFillType fillType;
|
GLPanelFillType fillType;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
class ThreadQueueBase {
|
class ThreadQueueBase {
|
||||||
|
|
||||||
|
@ -30,13 +31,17 @@ class ThreadQueue : public ThreadQueueBase {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/*! Create safe queue. */
|
/*! Create safe queue. */
|
||||||
ThreadQueue() = default;
|
ThreadQueue() {
|
||||||
|
m_max_num_items.store(0);
|
||||||
|
};
|
||||||
ThreadQueue(ThreadQueue&& sq) {
|
ThreadQueue(ThreadQueue&& sq) {
|
||||||
m_queue = std::move(sq.m_queue);
|
m_queue = std::move(sq.m_queue);
|
||||||
|
m_max_num_items.store(0);
|
||||||
}
|
}
|
||||||
ThreadQueue(const ThreadQueue& sq) {
|
ThreadQueue(const ThreadQueue& sq) {
|
||||||
std::lock_guard < std::mutex > lock(sq.m_mutex);
|
std::lock_guard < std::mutex > lock(sq.m_mutex);
|
||||||
m_queue = sq.m_queue;
|
m_queue = sq.m_queue;
|
||||||
|
m_max_num_items.store(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Destroy safe queue. */
|
/*! Destroy safe queue. */
|
||||||
|
@ -49,7 +54,10 @@ public:
|
||||||
* \param[in] item An item.
|
* \param[in] item An item.
|
||||||
*/
|
*/
|
||||||
void set_max_num_items(unsigned int max_num_items) {
|
void set_max_num_items(unsigned int max_num_items) {
|
||||||
m_max_num_items = max_num_items;
|
std::lock_guard < std::mutex > lock(m_mutex);
|
||||||
|
if (m_max_num_items.load() != max_num_items) {
|
||||||
|
m_max_num_items.store(max_num_items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,7 +68,7 @@ public:
|
||||||
bool push(const value_type& item) {
|
bool push(const value_type& item) {
|
||||||
std::lock_guard < std::mutex > lock(m_mutex);
|
std::lock_guard < std::mutex > lock(m_mutex);
|
||||||
|
|
||||||
if (m_max_num_items > 0 && m_queue.size() > m_max_num_items)
|
if (m_max_num_items.load() > 0 && m_queue.size() > m_max_num_items.load())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_queue.push(item);
|
m_queue.push(item);
|
||||||
|
@ -76,7 +84,7 @@ public:
|
||||||
bool push(const value_type&& item) {
|
bool push(const value_type&& item) {
|
||||||
std::lock_guard < std::mutex > lock(m_mutex);
|
std::lock_guard < std::mutex > lock(m_mutex);
|
||||||
|
|
||||||
if (m_max_num_items > 0 && m_queue.size() > m_max_num_items)
|
if (m_max_num_items.load() > 0 && m_queue.size() > m_max_num_items.load())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_queue.push(item);
|
m_queue.push(item);
|
||||||
|
@ -217,7 +225,7 @@ public:
|
||||||
*/
|
*/
|
||||||
bool full() const {
|
bool full() const {
|
||||||
std::lock_guard < std::mutex > lock(m_mutex);
|
std::lock_guard < std::mutex > lock(m_mutex);
|
||||||
return (m_max_num_items != 0) && (m_queue.size() >= m_max_num_items);
|
return (m_max_num_items.load() != 0) && (m_queue.size() >= m_max_num_items.load());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -278,7 +286,7 @@ private:
|
||||||
std::queue<T, Container> m_queue;
|
std::queue<T, Container> m_queue;
|
||||||
mutable std::mutex m_mutex;
|
mutable std::mutex m_mutex;
|
||||||
std::condition_variable m_condition;
|
std::condition_variable m_condition;
|
||||||
unsigned int m_max_num_items = 0;
|
std::atomic_uint m_max_num_items;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! Swaps the contents of two ThreadQueue objects. */
|
/*! Swaps the contents of two ThreadQueue objects. */
|
||||||
|
|
|
@ -14,24 +14,65 @@
|
||||||
#include "CubicSDRDefs.h"
|
#include "CubicSDRDefs.h"
|
||||||
#include "AppFrame.h"
|
#include "AppFrame.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
wxBEGIN_EVENT_TABLE(ScopeCanvas, wxGLCanvas) EVT_PAINT(ScopeCanvas::OnPaint)
|
wxBEGIN_EVENT_TABLE(ScopeCanvas, wxGLCanvas) EVT_PAINT(ScopeCanvas::OnPaint)
|
||||||
EVT_IDLE(ScopeCanvas::OnIdle)
|
EVT_IDLE(ScopeCanvas::OnIdle)
|
||||||
|
EVT_MOTION(ScopeCanvas::OnMouseMoved)
|
||||||
|
EVT_LEFT_DOWN(ScopeCanvas::OnMouseDown)
|
||||||
|
EVT_LEFT_UP(ScopeCanvas::OnMouseReleased)
|
||||||
|
EVT_RIGHT_DOWN(ScopeCanvas::OnMouseRightDown)
|
||||||
|
EVT_RIGHT_UP(ScopeCanvas::OnMouseRightReleased)
|
||||||
|
EVT_LEAVE_WINDOW(ScopeCanvas::OnMouseLeftWindow)
|
||||||
|
EVT_ENTER_WINDOW(ScopeCanvas::OnMouseEnterWindow)
|
||||||
wxEND_EVENT_TABLE()
|
wxEND_EVENT_TABLE()
|
||||||
|
|
||||||
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) :
|
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), stereo(false), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") {
|
||||||
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
|
||||||
wxFULL_REPAINT_ON_RESIZE), stereo(false), ppmMode(false) {
|
|
||||||
|
|
||||||
glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
|
glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
|
||||||
inputData.set_max_num_items(1);
|
inputData.set_max_num_items(2);
|
||||||
|
bgPanel.setFill(GLPanel::GLPANEL_FILL_GRAD_Y);
|
||||||
|
bgPanel.setSize(1.0, 0.5);
|
||||||
|
bgPanel.setPosition(0.0, -0.5);
|
||||||
|
panelSpacing = 0.4;
|
||||||
|
|
||||||
|
parentPanel.addChild(&scopePanel);
|
||||||
|
parentPanel.addChild(&spectrumPanel);
|
||||||
|
parentPanel.setFill(GLPanel::GLPANEL_FILL_NONE);
|
||||||
|
scopePanel.setSize(1.0,-1.0);
|
||||||
|
spectrumPanel.setSize(1.0,-1.0);
|
||||||
|
spectrumPanel.setShowDb(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeCanvas::~ScopeCanvas() {
|
ScopeCanvas::~ScopeCanvas() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScopeCanvas::scopeVisible() {
|
||||||
|
float panelInterval = (2.0 + panelSpacing);
|
||||||
|
|
||||||
|
ctrTarget = abs(round(ctr / panelInterval));
|
||||||
|
|
||||||
|
if (ctrTarget == 0 || dragAccel || (ctr != ctrTarget)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScopeCanvas::spectrumVisible() {
|
||||||
|
float panelInterval = (2.0 + panelSpacing);
|
||||||
|
|
||||||
|
ctrTarget = abs(round(ctr / panelInterval));
|
||||||
|
|
||||||
|
if (ctrTarget == 1 || dragAccel || (ctr != ctrTarget)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void ScopeCanvas::setStereo(bool state) {
|
void ScopeCanvas::setStereo(bool state) {
|
||||||
stereo = state;
|
stereo = state;
|
||||||
}
|
}
|
||||||
|
@ -49,20 +90,40 @@ bool ScopeCanvas::getPPMMode() {
|
||||||
return ppmMode;
|
return ppmMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScopeCanvas::setShowDb(bool showDb) {
|
||||||
|
this->showDb = showDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScopeCanvas::getShowDb() {
|
||||||
|
return showDb;
|
||||||
|
}
|
||||||
|
|
||||||
void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||||
wxPaintDC dc(this);
|
wxPaintDC dc(this);
|
||||||
const wxSize ClientSize = GetClientSize();
|
const wxSize ClientSize = GetClientSize();
|
||||||
|
|
||||||
if (!inputData.empty()) {
|
while (!inputData.empty()) {
|
||||||
ScopeRenderData *avData;
|
ScopeRenderData *avData;
|
||||||
inputData.pop(avData);
|
inputData.pop(avData);
|
||||||
|
|
||||||
if (avData) {
|
if (!avData->spectrum) {
|
||||||
if (avData->waveform_points.size()) {
|
if (avData->waveform_points.size()) {
|
||||||
scopePanel.setPoints(avData->waveform_points);
|
scopePanel.setPoints(avData->waveform_points);
|
||||||
setStereo(avData->channels == 2);
|
setStereo(avData->channels == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avData->decRefCount();
|
||||||
|
} else {
|
||||||
|
if (avData->waveform_points.size()) {
|
||||||
|
spectrumPanel.setPoints(avData->waveform_points);
|
||||||
|
spectrumPanel.setFloorValue(avData->fft_floor);
|
||||||
|
spectrumPanel.setCeilValue(avData->fft_ceil);
|
||||||
|
spectrumPanel.setBandwidth((avData->sampleRate/2)*1000);
|
||||||
|
spectrumPanel.setFreq((avData->sampleRate/4)*1000);
|
||||||
|
spectrumPanel.setFFTSize(avData->fft_size);
|
||||||
|
spectrumPanel.setShowDb(showDb);
|
||||||
|
}
|
||||||
|
|
||||||
avData->decRefCount();
|
avData->decRefCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,21 +132,95 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||||
initGLExtensions();
|
initGLExtensions();
|
||||||
|
|
||||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||||
|
|
||||||
glContext->DrawBegin();
|
glContext->DrawBegin();
|
||||||
|
|
||||||
|
bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 3.0, RGBA4f(0,0,0,0));
|
||||||
|
bgPanel.calcTransform(CubicVR::mat4::identity());
|
||||||
|
bgPanel.draw();
|
||||||
|
|
||||||
scopePanel.setMode(stereo?ScopePanel::SCOPE_MODE_2Y:ScopePanel::SCOPE_MODE_Y);
|
scopePanel.setMode(stereo?ScopePanel::SCOPE_MODE_2Y:ScopePanel::SCOPE_MODE_Y);
|
||||||
scopePanel.calcTransform(CubicVR::mat4::identity());
|
|
||||||
scopePanel.draw();
|
glMatrixMode(GL_PROJECTION);
|
||||||
glContext->DrawTunerTitles(ppmMode);
|
glLoadIdentity();
|
||||||
|
glLoadMatrixf(CubicVR::mat4::perspective(45.0, 1.0, 1.0, 1000.0));
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
CubicVR::mat4 modelView = CubicVR::mat4::lookat(0, 0, -1.205, 0, 0, 0, 0, -1, 0);
|
||||||
|
|
||||||
|
float panelWidth = 1.0;
|
||||||
|
float panelInterval = (panelWidth * 2.0 + panelSpacing);
|
||||||
|
|
||||||
|
if (!mouseTracker.mouseDown()) {
|
||||||
|
ctrTarget = round(ctr / panelInterval);
|
||||||
|
if (ctrTarget < -1.0) {
|
||||||
|
ctrTarget = -1.0;
|
||||||
|
} else if (ctrTarget > 0.0) {
|
||||||
|
ctrTarget = 0.0;
|
||||||
|
}
|
||||||
|
ctrTarget *= panelInterval;
|
||||||
|
if (!dragAccel) {
|
||||||
|
if (ctr != ctrTarget) {
|
||||||
|
ctr += (ctrTarget-ctr)*0.2;
|
||||||
|
}
|
||||||
|
if (abs(ctr - ctrTarget) < 0.001) {
|
||||||
|
ctr=ctrTarget;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dragAccel -= dragAccel * 0.1;
|
||||||
|
if ((abs(dragAccel) < 0.2) || (ctr < (ctrTarget-panelInterval/2.0)) || (ctr > (ctrTarget+panelInterval/2.0)) ) {
|
||||||
|
dragAccel = 0;
|
||||||
|
} else {
|
||||||
|
ctr += dragAccel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float roty = 0;
|
||||||
|
|
||||||
|
scopePanel.setPosition(ctr, 0);
|
||||||
|
if (scopeVisible()) {
|
||||||
|
scopePanel.contentsVisible = true;
|
||||||
|
roty = atan2(scopePanel.pos[0],1.2);
|
||||||
|
scopePanel.rot[1] = -(roty * (180.0 / M_PI));
|
||||||
|
} else {
|
||||||
|
scopePanel.contentsVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
spectrumPanel.setPosition(panelInterval+ctr, 0);
|
||||||
|
if (spectrumVisible()) {
|
||||||
|
spectrumPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0, RGBA4f(0,0,0,0));
|
||||||
|
spectrumPanel.contentsVisible = true;
|
||||||
|
roty = atan2(spectrumPanel.pos[0],1.2);
|
||||||
|
spectrumPanel.rot[1] = -(roty * (180.0 / M_PI));
|
||||||
|
} else {
|
||||||
|
spectrumPanel.contentsVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentPanel.calcTransform(modelView);
|
||||||
|
parentPanel.draw();
|
||||||
|
|
||||||
|
if (spectrumVisible()) {
|
||||||
|
spectrumPanel.drawChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
glLoadMatrixf(scopePanel.transform);
|
||||||
if (!deviceName.empty()) {
|
if (!deviceName.empty()) {
|
||||||
glContext->DrawDeviceName(deviceName);
|
glContext->DrawDeviceName(deviceName);
|
||||||
}
|
}
|
||||||
glContext->DrawEnd();
|
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
glContext->DrawTunerTitles(ppmMode);
|
||||||
|
glContext->DrawEnd();
|
||||||
|
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ScopeCanvas::OnIdle(wxIdleEvent &event) {
|
void ScopeCanvas::OnIdle(wxIdleEvent &event) {
|
||||||
Refresh();
|
Refresh();
|
||||||
event.RequestMore();
|
event.RequestMore();
|
||||||
|
@ -94,3 +229,44 @@ void ScopeCanvas::OnIdle(wxIdleEvent &event) {
|
||||||
ScopeRenderDataQueue *ScopeCanvas::getInputQueue() {
|
ScopeRenderDataQueue *ScopeCanvas::getInputQueue() {
|
||||||
return &inputData;
|
return &inputData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScopeCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||||
|
InteractiveCanvas::OnMouseMoved(event);
|
||||||
|
if (mouseTracker.mouseDown()) {
|
||||||
|
dragAccel = 4.0*mouseTracker.getDeltaMouseX();
|
||||||
|
ctr += dragAccel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeCanvas::OnMouseWheelMoved(wxMouseEvent& event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeCanvas::OnMouseDown(wxMouseEvent& event) {
|
||||||
|
InteractiveCanvas::OnMouseDown(event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||||
|
InteractiveCanvas::OnMouseReleased(event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
||||||
|
InteractiveCanvas::OnMouseEnterWindow(event);
|
||||||
|
if (!helpTip.empty()) {
|
||||||
|
setStatusText(helpTip);
|
||||||
|
}
|
||||||
|
SetCursor(wxCURSOR_SIZEWE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopeCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
||||||
|
InteractiveCanvas::OnMouseLeftWindow(event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ScopeCanvas::setHelpTip(std::string tip) {
|
||||||
|
helpTip = tip;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
#include "ScopeContext.h"
|
#include "ScopeContext.h"
|
||||||
#include "ScopeVisualProcessor.h"
|
#include "ScopeVisualProcessor.h"
|
||||||
#include "ScopePanel.h"
|
#include "ScopePanel.h"
|
||||||
|
#include "SpectrumPanel.h"
|
||||||
#include "fftw3.h"
|
#include "fftw3.h"
|
||||||
|
#include "InteractiveCanvas.h"
|
||||||
|
|
||||||
class ScopeCanvas: public wxGLCanvas {
|
class ScopeCanvas: public InteractiveCanvas {
|
||||||
public:
|
public:
|
||||||
ScopeCanvas(wxWindow *parent, int *attribList = NULL);
|
ScopeCanvas(wxWindow *parent, int *attribList = NULL);
|
||||||
~ScopeCanvas();
|
~ScopeCanvas();
|
||||||
|
@ -21,18 +23,41 @@ public:
|
||||||
void setPPMMode(bool ppmMode);
|
void setPPMMode(bool ppmMode);
|
||||||
bool getPPMMode();
|
bool getPPMMode();
|
||||||
|
|
||||||
|
void setShowDb(bool showDb);
|
||||||
|
bool getShowDb();
|
||||||
|
|
||||||
|
bool scopeVisible();
|
||||||
|
bool spectrumVisible();
|
||||||
|
|
||||||
|
void setHelpTip(std::string tip);
|
||||||
|
|
||||||
ScopeRenderDataQueue *getInputQueue();
|
ScopeRenderDataQueue *getInputQueue();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnPaint(wxPaintEvent& event);
|
void OnPaint(wxPaintEvent& event);
|
||||||
void OnIdle(wxIdleEvent &event);
|
void OnIdle(wxIdleEvent &event);
|
||||||
|
void OnMouseMoved(wxMouseEvent& event);
|
||||||
|
void OnMouseWheelMoved(wxMouseEvent& event);
|
||||||
|
void OnMouseDown(wxMouseEvent& event);
|
||||||
|
void OnMouseReleased(wxMouseEvent& event);
|
||||||
|
void OnMouseEnterWindow(wxMouseEvent& event);
|
||||||
|
void OnMouseLeftWindow(wxMouseEvent& event);
|
||||||
|
|
||||||
ScopeRenderDataQueue inputData;
|
ScopeRenderDataQueue inputData;
|
||||||
ScopePanel scopePanel;
|
ScopePanel scopePanel;
|
||||||
|
GLPanel parentPanel;
|
||||||
|
SpectrumPanel spectrumPanel;
|
||||||
|
GLPanel bgPanel;
|
||||||
ScopeContext *glContext;
|
ScopeContext *glContext;
|
||||||
std::string deviceName;
|
std::string deviceName;
|
||||||
bool stereo;
|
bool stereo;
|
||||||
bool ppmMode;
|
bool ppmMode;
|
||||||
|
bool showDb;
|
||||||
|
float panelSpacing;
|
||||||
|
float ctr;
|
||||||
|
float ctrTarget;
|
||||||
|
float dragAccel;
|
||||||
|
std::string helpTip;
|
||||||
// event table
|
// event table
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue