update digital_lab

This commit is contained in:
Charles J. Cliffe 2015-08-26 20:32:53 -04:00
commit 2974546436
42 changed files with 1200 additions and 396 deletions

View File

@ -74,13 +74,24 @@ namespace CubicVR {
return mOut;
}
static mat4 perspective(__float fovy, __float aspect, __float znear, __float zfar) {
static mat4 frustum(__float left, __float right, __float bottom, __float top, __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 xFac = yFac * aspect;
return mat4(
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);
return mat4::frustum(-xFac, xFac, -yFac, yFac, zNear, 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);
@ -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);
};
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__) */

Binary file not shown.

View File

@ -2,6 +2,7 @@
#include "CubicSDR.h"
DeviceConfig::DeviceConfig() : deviceId("") {
iqSwap.store(0);
ppm.store(0);
directSampling.store(false);
offset.store(0);

View File

@ -117,7 +117,9 @@ AppFrame::AppFrame() :
demodTray->AddSpacer(1);
scopeCanvas = new ScopeCanvas(this, attribList);
scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum.");
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
wxGetApp().getScopeProcessor()->setup(2048);
wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue());
demodScopeTray->AddSpacer(1);
@ -130,18 +132,34 @@ AppFrame::AppFrame() :
demodTray->AddSpacer(1);
wxBoxSizer *demodGainTray = new wxBoxSizer(wxVERTICAL);
demodGainMeter = new MeterCanvas(this, attribList);
demodGainMeter->setMax(2.0);
demodGainMeter->setHelpTip("Current Demodulator Gain Level. Click / Drag to set Gain level.");
demodGainMeter->setShowUserInput(false);
demodTray->Add(demodGainMeter, 1, wxEXPAND | wxALL, 0);
demodGainTray->Add(demodGainMeter, 8, wxEXPAND | wxALL, 0);
demodGainTray->AddSpacer(1);
demodMuteButton = new ModeSelectorCanvas(this, attribList);
demodMuteButton->addChoice(1, "M");
demodMuteButton->setPadding(-1,-1);
demodMuteButton->setHighlightColor(RGBA4f(0.8,0.2,0.2));
demodMuteButton->setHelpTip("Demodulator Mute Toggle");
demodMuteButton->setToggleMode(true);
demodGainTray->Add(demodMuteButton, 1, wxEXPAND | wxALL, 0);
demodTray->Add(demodGainTray, 1, wxEXPAND | wxALL, 0);
vbox->Add(demodTray, 12, wxEXPAND | wxALL, 0);
vbox->AddSpacer(1);
wxBoxSizer *spectrumSizer = new wxBoxSizer(wxHORIZONTAL);
wxGetApp().getSpectrumProcessor()->setup(2048);
spectrumCanvas = new SpectrumCanvas(this, attribList);
spectrumCanvas->setShowDb(true);
wxGetApp().getSpectrumProcessor()->attachOutput(spectrumCanvas->getVisualDataQueue());
spectrumAvgMeter = new MeterCanvas(this, attribList);
@ -164,11 +182,12 @@ AppFrame::AppFrame() :
waterfallCanvas->setup(2048, 512);
waterfallDataThread = new FFTVisualDataThread();
t_FFTData = new std::thread(&FFTVisualDataThread::threadMain, waterfallDataThread);
waterfallDataThread->setInputQueue("IQDataInput", wxGetApp().getWaterfallVisualQueue());
waterfallDataThread->setOutputQueue("FFTDataOutput", waterfallCanvas->getVisualDataQueue());
t_FFTData = new std::thread(&FFTVisualDataThread::threadMain, waterfallDataThread);
waterfallSpeedMeter = new MeterCanvas(this, attribList);
waterfallSpeedMeter->setHelpTip("Waterfall speed, click or drag to adjust (max 1024 lines per second)");
waterfallSpeedMeter->setMax(sqrt(1024));
@ -505,6 +524,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
wxGetApp().setFrequency(100000000);
wxGetApp().getDemodMgr().setLastDemodulatorType(DEMOD_TYPE_FM);
demodModeSelector->setSelection(1);
wxGetApp().getDemodMgr().setLastMuted(false);
wxGetApp().getDemodMgr().setLastStereo(false);
wxGetApp().getDemodMgr().setLastBandwidth(DEFAULT_DEMOD_BW);
wxGetApp().getDemodMgr().setLastGain(1.0);
@ -693,6 +713,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
demodModeSelector->setSelection(dType);
demodModeSelectorAdv->setSelection(dType);
demodModeSelectorCons->setSelection(dCons);
demodMuteButton->setSelection(demod->isMuted()?1:-1);
}
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
long long centerFreq = demod->getFrequency();
@ -739,6 +760,25 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
demod->setDemodulatorCons(dSelectionCons);
}
int muteMode = demodMuteButton->getSelection();
if (demodMuteButton->modeChanged()) {
if (demod->isMuted() && muteMode == -1) {
demod->setMuted(false);
} else if (!demod->isMuted() && muteMode == 1) {
demod->setMuted(true);
}
wxGetApp().getDemodMgr().setLastMuted(demod->isMuted());
demodMuteButton->clearModeChanged();
} else {
if (demod->isMuted() && muteMode == -1) {
demodMuteButton->setSelection(1);
wxGetApp().getDemodMgr().setLastMuted(demod->isMuted());
} else if (!demod->isMuted() && muteMode == 1) {
demodMuteButton->setSelection(-1);
wxGetApp().getDemodMgr().setLastMuted(demod->isMuted());
}
}
demodWaterfallCanvas->setBandwidth(demodBw);
demodSpectrumCanvas->setBandwidth(demodBw);
}
@ -792,6 +832,15 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency());
waterfallCanvas->setCenterFrequency(wxGetApp().getFrequency());
}
if (demodMuteButton->modeChanged()) {
int muteMode = demodMuteButton->getSelection();
if (muteMode == -1) {
wxGetApp().getDemodMgr().setLastMuted(false);
} else if (muteMode == 1) {
wxGetApp().getDemodMgr().setLastMuted(true);
}
demodMuteButton->clearModeChanged();
}
}
if (demodTuner->getMouseTracker()->mouseInView()) {
@ -804,6 +853,11 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
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().getSpectrumDistributor()->run();
@ -814,6 +868,9 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
if (val < 0.01) {
val = 0.01;
}
if (val > 0.99) {
val = 0.99;
}
spectrumAvgMeter->setLevel(val);
proc->setFFTAverageRate(val);
@ -873,6 +930,7 @@ void AppFrame::saveSession(std::string fileName) {
*demod->newChild("stereo") = (*instance_i)->isStereo() ? 1 : 0;
*demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name;
*demod->newChild("gain") = (*instance_i)->getGain();
*demod->newChild("muted") = (*instance_i)->isMuted() ? 1 : 0;
}
s.SaveToFileXML(fileName);
@ -904,6 +962,9 @@ bool AppFrame::loadSession(std::string fileName) {
DataNode *demodulators = l.rootNode()->getNext("demodulators");
int numDemodulators = 0;
DemodulatorInstance *loadedDemod = NULL;
while (demodulators->hasAnother("demodulator")) {
DataNode *demod = demodulators->getNext("demodulator");
@ -917,15 +978,19 @@ bool AppFrame::loadSession(std::string fileName) {
float squelch_level = demod->hasAnother("squelch_level") ? (float) *demod->getNext("squelch_level") : 0;
int squelch_enabled = demod->hasAnother("squelch_enabled") ? (int) *demod->getNext("squelch_enabled") : 0;
int stereo = demod->hasAnother("stereo") ? (int) *demod->getNext("stereo") : 0;
int muted = demod->hasAnother("muted") ? (int) *demod->getNext("muted") : 0;
std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : "";
float gain = demod->hasAnother("gain") ? (float) *demod->getNext("gain") : 1.0;
DemodulatorInstance *newDemod = wxGetApp().getDemodMgr().newThread();
loadedDemod = newDemod;
numDemodulators++;
newDemod->setDemodulatorType(type);
newDemod->setBandwidth(bandwidth);
newDemod->setFrequency(freq);
newDemod->setGain(gain);
newDemod->updateLabel(freq);
newDemod->setMuted(muted?true:false);
if (squelch_enabled) {
newDemod->setSquelchEnabled(true);
newDemod->setSquelchLevel(squelch_level);
@ -958,6 +1023,13 @@ bool AppFrame::loadSession(std::string fileName) {
std::cout << "\t\tStereo: " << (stereo ? "true" : "false") << std::endl;
std::cout << "\t\tOutput Device: " << output_device << std::endl;
}
if ((numDemodulators == 1) && loadedDemod) {
loadedDemod->setActive(true);
loadedDemod->setFollow(true);
loadedDemod->setTracking(true);
wxGetApp().getDemodMgr().setActiveDemodulator(loadedDemod);
}
} catch (DataInvalidChildException &e) {
std::cout << e.what() << std::endl;
return false;

View File

@ -84,6 +84,7 @@ private:
// UITestCanvas *testCanvas;
MeterCanvas *spectrumAvgMeter;
MeterCanvas *waterfallSpeedMeter;
ModeSelectorCanvas *demodMuteButton;
DemodulatorInstance *activeDemodulator;

View File

@ -14,6 +14,7 @@
class AudioThreadInput: public ReferenceCounter {
public:
long long frequency;
int inputRate;
int sampleRate;
int channels;
float peak;

View File

@ -10,6 +10,7 @@ DemodulatorInstance::DemodulatorInstance() :
active.store(false);
squelch.store(false);
stereo.store(false);
muted.store(false);
tracking.store(false);
follow.store(false);
currentAudioSampleRate.store(0);
@ -430,6 +431,15 @@ void DemodulatorInstance::setTracking(bool tracking) {
this->tracking = tracking;
}
bool DemodulatorInstance::isMuted() {
return demodulatorThread->isMuted();
}
void DemodulatorInstance::setMuted(bool muted) {
this->muted = muted;
demodulatorThread->setMuted(muted);
}
DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() {
return pipeIQInputData;
}

View File

@ -79,6 +79,9 @@ public:
bool isTracking();
void setTracking(bool tracking);
bool isMuted();
void setMuted(bool muted);
DemodulatorThreadInputQueue *getIQInputDataPipe();
@ -104,6 +107,7 @@ private:
std::atomic_bool active;
std::atomic_bool squelch;
std::atomic_bool stereo;
std::atomic_bool muted;
std::atomic_llong currentFrequency;
std::atomic_int currentBandwidth;

View File

@ -232,3 +232,12 @@ void DemodulatorMgr::setLastStereo(bool lastStereo) {
this->lastStereo = lastStereo;
}
bool DemodulatorMgr::isLastMuted() const {
return lastMuted;
}
void DemodulatorMgr::setLastMuted(bool lastMuted) {
this->lastMuted = lastMuted;
}

View File

@ -43,6 +43,9 @@ public:
bool isLastStereo() const;
void setLastStereo(bool lastStereo);
bool isLastMuted() const;
void setLastMuted(bool lastMuted);
private:
void garbageCollect();
void updateLastState();
@ -60,5 +63,5 @@ private:
bool lastSquelchEnabled;
float lastSquelch;
float lastGain;
bool lastStereo;
bool lastStereo, lastMuted;
};

View File

@ -72,9 +72,6 @@ void DemodulatorPreThread::initialize() {
}
DemodulatorPreThread::~DemodulatorPreThread() {
delete workerThread;
delete workerQueue;
delete workerResults;
}
void DemodulatorPreThread::run() {
@ -260,7 +257,7 @@ void DemodulatorPreThread::run() {
inp->decRefCount();
if (!workerResults->empty()) {
if (!terminated && !workerResults->empty()) {
while (!workerResults->empty()) {
DemodulatorWorkerThreadResult result;
workerResults->pop(result);
@ -323,7 +320,12 @@ void DemodulatorPreThread::terminate() {
terminated = true;
DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue
iqInputQueue->push(inp);
DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_NULL);
workerQueue->push(command);
workerThread->terminate();
t_Worker->detach();
t_Worker->join();
delete t_Worker;
delete workerThread;
delete workerResults;
delete workerQueue;
}

View File

@ -14,6 +14,7 @@
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);
muted.store(false);
agcEnabled.store(false);
demodulatorType.store(DEMOD_TYPE_FM);
@ -685,6 +686,7 @@ void DemodulatorThread::run() {
ati = outputBuffers.getBuffer();
ati->sampleRate = audioSampleRate;
ati->inputRate = inp->sampleRate;
ati->setRefCount(1);
if (demodulatorType == DEMOD_TYPE_RAW) {
@ -734,7 +736,9 @@ void DemodulatorThread::run() {
if (ati && audioVisOutputQueue != NULL && audioVisOutputQueue->empty()) {
ati_vis->busy_update.lock();
ati_vis->sampleRate = inp->sampleRate;
ati_vis->inputRate = inp->sampleRate;
int num_vis = DEMOD_VIS_SIZE;
if (demodulatorType == DEMOD_TYPE_RAW || (stereo && inp->sampleRate >= 100000)) {
ati_vis->channels = 2;
@ -752,6 +756,8 @@ void DemodulatorThread::run() {
}
} else {
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 + stereoSize / 2] = ati->data[i * 2 + 1];
}
@ -759,7 +765,7 @@ void DemodulatorThread::run() {
} else {
ati_vis->channels = 1;
if (numAudioWritten > bufSize) {
ati_vis->inputRate = audioSampleRate;
if (num_vis > numAudioWritten) {
num_vis = numAudioWritten;
}
@ -774,13 +780,16 @@ void DemodulatorThread::run() {
// 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();
audioVisOutputQueue->push(ati_vis);
}
if (ati != NULL) {
audioOutputQueue->push(ati);
if (!muted.load()) {
audioOutputQueue->push(ati);
} else {
ati->setRefCount(0);
}
}
if (!threadQueueControl->empty()) {
@ -922,6 +931,14 @@ bool DemodulatorThread::isStereo() {
return stereo.load();
}
bool DemodulatorThread::isMuted() {
return muted.load();
}
void DemodulatorThread::setMuted(bool muted) {
this->muted.store(muted);
}
void DemodulatorThread::setAGC(bool state) {
agcEnabled.store(state);
}

View File

@ -8,7 +8,7 @@
typedef ThreadQueue<AudioThreadInput *> DemodulatorThreadOutputQueue;
#define DEMOD_VIS_SIZE 1024
#define DEMOD_VIS_SIZE 2048
class DemodulatorThread : public IOThread {
public:
@ -27,6 +27,9 @@ public:
void setAGC(bool state);
bool getAGC();
void setMuted(bool state);
bool isMuted();
float getSignalLevel();
void setSquelchLevel(float signal_level_in);
float getSquelchLevel();
@ -135,6 +138,7 @@ protected:
float amOutputCeilMAA;
std::atomic_bool stereo;
std::atomic_bool muted;
std::atomic_bool agcEnabled;
std::atomic_int demodulatorType;
std::atomic_int demodulatorCons;

View File

@ -2,6 +2,7 @@
#include "ColorTheme.h"
ScopePanel::ScopePanel() : GLPanel(), scopeMode(SCOPE_MODE_Y) {
setFill(GLPanelFillType::GLPANEL_FILL_NONE);
bgPanel.setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
bgPanelStereo[0].setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y);
bgPanelStereo[0].setPosition(0, 0.5);
@ -21,14 +22,13 @@ void ScopePanel::setPoints(std::vector<float> &points) {
}
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();
glLineWidth(1.0);
glEnable(GL_LINE_SMOOTH);
glLoadMatrixf(transform);
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
@ -45,8 +45,10 @@ void ScopePanel::drawPanelContents() {
bgPanelStereo[1].calcTransform(transform);
bgPanelStereo[1].draw();
glLineWidth(1.0);
glLoadMatrixf(transform);
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b);
glEnable(GL_LINE_SMOOTH);
glBegin (GL_LINES);
glVertex2f(-1.0, 0.0);
glVertex2f(1.0, 0.0);

View File

@ -2,15 +2,24 @@
#include <sstream>
#include <iostream>
#include <iomanip>
#include "ColorTheme.h"
SpectrumPanel::SpectrumPanel() : floorValue(0), ceilValue(1) {
SpectrumPanel::SpectrumPanel() : floorValue(0), ceilValue(1), showDb(false), fftSize(2048) {
setFill(GLPANEL_FILL_GRAD_Y);
setFillColor(ThemeMgr::mgr.currentTheme->fftBackground * 2.0, ThemeMgr::mgr.currentTheme->fftBackground);
dbPanelCeil.setMarginPx(0);
dbPanelCeil.setFill(GLPanel::GLPANEL_FILL_GRAD_X);
dbPanelCeil.setFillColor(RGBA4f(0.2,0.2,0.2,5.0), RGBA4f(0.2,0.2,0.2,0.0));
dbPanelFloor.setMarginPx(0);
dbPanelFloor.setFill(GLPanel::GLPANEL_FILL_GRAD_X);
dbPanelFloor.setFillColor(RGBA4f(0.2,0.2,0.2,5.), RGBA4f(0.2,0.2,0.2,0.0));
}
float SpectrumPanel::getFloorValue() const {
float SpectrumPanel::getFloorValue() {
return floorValue;
}
@ -18,7 +27,7 @@ void SpectrumPanel::setFloorValue(float floorValue) {
this->floorValue = floorValue;
}
float SpectrumPanel::getCeilValue() const {
float SpectrumPanel::getCeilValue() {
return ceilValue;
}
@ -42,6 +51,31 @@ long long SpectrumPanel::getBandwidth() {
return bandwidth;
}
void SpectrumPanel::setFFTSize(int fftSize_in) {
this->fftSize = fftSize_in;
}
int SpectrumPanel::getFFTSize() {
return fftSize;
}
void SpectrumPanel::setShowDb(bool showDb) {
this->showDb = showDb;
if (showDb) {
addChild(&dbPanelCeil);
addChild(&dbPanelFloor);
} else {
removeChild(&dbPanelCeil);
removeChild(&dbPanelFloor);
}
}
bool SpectrumPanel::getShowDb() {
return showDb;
}
void SpectrumPanel::setPoints(std::vector<float> &points) {
this->points.assign(points.begin(), points.end());
}
@ -95,38 +129,69 @@ void SpectrumPanel::drawPanelContents() {
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2);
glDisableClientState(GL_VERTEX_ARRAY);
}
glLoadMatrixf(transform);
GLint vp[4];
glGetIntegerv( GL_VIEWPORT, vp);
float viewHeight = (float) vp[3];
float viewWidth = (float) vp[2];
glLoadMatrixf(transform);
long long leftFreq = (double) freq - ((double) bandwidth / 2.0);
long long rightFreq = leftFreq + (double) bandwidth;
long long firstMhz = (leftFreq / 1000000) * 1000000;
long double mhzStart = ((long double) (firstMhz - leftFreq) / (long double) (rightFreq - leftFreq)) * 2.0;
long long hzStep = 1000000;
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) {
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;
mhzVisualStep = 0.01f;
mhzVisualStep = 0.01;
label.precision(2);
}
long double currentMhz = trunc(floor(firstMhz / 1000000.0));
std::stringstream label;
label.precision(2);
long long firstMhz = (leftFreq / hzStep) * hzStep;
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 lMhzPos = 1.0 - (5.0 / viewHeight);
@ -162,4 +227,24 @@ void SpectrumPanel::drawPanelContents() {
}
glLineWidth(1.0);
if (showDb) {
float dbPanelWidth = (1.0/viewWidth)*75.0;
float dbPanelHeight = (1.0/viewHeight)*14.0;
std::stringstream ssLabel;
ssLabel << std::fixed << std::setprecision(1) << (20.0 * log10(2.0*(getCeilValue())/(double)fftSize)) << "dB";
dbPanelCeil.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT);
dbPanelCeil.setSize(dbPanelWidth, dbPanelHeight);
dbPanelCeil.setPosition(-1.0 + dbPanelWidth, 1.0 - dbPanelHeight);
ssLabel.str("");
ssLabel << (20.0 * log10(2.0*(getFloorValue())/(double)fftSize)) << "dB";
dbPanelFloor.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT);
dbPanelFloor.setSize(dbPanelWidth, dbPanelHeight);
dbPanelFloor.setPosition(-1.0 + dbPanelWidth, - 1.0 + dbPanelHeight);
}
}

View File

@ -8,10 +8,10 @@ public:
void setPoints(std::vector<float> &points);
float getFloorValue() const;
float getFloorValue();
void setFloorValue(float floorValue);
float getCeilValue() const;
float getCeilValue();
void setCeilValue(float ceilValue);
void setFreq(long long freq);
@ -19,13 +19,24 @@ public:
void setBandwidth(long long bandwidth);
long long getBandwidth();
void setFFTSize(int fftSize_in);
int getFFTSize();
void setShowDb(bool showDb);
bool getShowDb();
protected:
void drawPanelContents();
private:
float floorValue, ceilValue;
int fftSize;
long long freq;
long long bandwidth;
std::vector<float> points;
GLTextPanel dbPanelCeil;
GLTextPanel dbPanelFloor;
bool showDb;
};

View File

@ -1,7 +1,7 @@
#include "WaterfallPanel.h"
WaterfallPanel::WaterfallPanel() : GLPanel(), fft_size(0), waterfall_lines(0), waterfall_slice(NULL), activeTheme(NULL) {
setFillColor(RGB3f(0,0,0));
setFillColor(RGBA4f(0,0,0));
for (int i = 0; i < 2; i++) {
waterfall[i] = 0;
}

View File

@ -1,4 +1,54 @@
#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() {
if (!isOutputEmpty()) {
@ -11,42 +61,144 @@ void ScopeVisualProcessor::process() {
if (!audioInputData) {
return;
}
int iMax = audioInputData->data.size();
int i, iMax = audioInputData->data.size();
if (!iMax) {
audioInputData->decRefCount();
return;
}
audioInputData->busy_update.lock();
ScopeRenderData *renderData = outputBuffers.getBuffer();
renderData->channels = audioInputData->channels;
if (renderData->waveform_points.size() != iMax * 2) {
renderData->waveform_points.resize(iMax * 2);
}
ScopeRenderData *renderData = NULL;
if (scopeEnabled) {
iMax = audioInputData->data.size();
if (iMax > maxScopeSamples) {
iMax = maxScopeSamples;
}
float peak = 1.0f;
for (int i = 0; i < iMax; i++) {
float p = fabs(audioInputData->data[i]);
if (p > peak) {
peak = p;
renderData = outputBuffers.getBuffer();
renderData->channels = audioInputData->channels;
renderData->inputRate = audioInputData->inputRate;
renderData->sampleRate = audioInputData->sampleRate;
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();
}
}

View File

@ -2,17 +2,47 @@
#include "VisualProcessor.h"
#include "AudioThread.h"
#include "fftw3.h"
class ScopeRenderData: public ReferenceCounter {
public:
std::vector<float> waveform_points;
int inputRate;
int sampleRate;
int channels;
bool spectrum;
int fft_size;
double fft_floor, fft_ceil;
};
typedef ThreadQueue<ScopeRenderData *> ScopeRenderDataQueue;
class ScopeVisualProcessor : public VisualProcessor<AudioThreadInput, ScopeRenderData> {
public:
ScopeVisualProcessor();
~ScopeVisualProcessor();
void setup(int fftSize_in);
void setScopeEnabled(bool scopeEnable);
void setSpectrumEnabled(bool spectrumEnable);
protected:
void process();
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;
};

View File

@ -14,7 +14,7 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), last
fft_ceil_ma = fft_ceil_maa = 100.0;
fft_floor_ma = fft_floor_maa = 0.0;
desiredInputSize = 0;
desiredInputSize.store(0);
fft_average_rate = 0.65;
}
@ -27,19 +27,25 @@ bool SpectrumVisualProcessor::isView() {
}
void SpectrumVisualProcessor::setView(bool bView) {
busy_run.lock();
is_view.store(bView);
busy_run.unlock();
}
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() {
return this->fft_average_rate;
return this->fft_average_rate.load();
}
void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) {
busy_run.lock();
centerFreq.store(centerFreq_in);
busy_run.unlock();
}
long long SpectrumVisualProcessor::getCenterFrequency() {
@ -47,7 +53,9 @@ long long SpectrumVisualProcessor::getCenterFrequency() {
}
void SpectrumVisualProcessor::setBandwidth(long bandwidth_in) {
busy_run.lock();
bandwidth.store(bandwidth_in);
busy_run.unlock();
}
long SpectrumVisualProcessor::getBandwidth() {
@ -55,12 +63,14 @@ long SpectrumVisualProcessor::getBandwidth() {
}
int SpectrumVisualProcessor::getDesiredInputSize() {
return desiredInputSize;
return desiredInputSize.load();
}
void SpectrumVisualProcessor::setup(int fftSize_in) {
busy_run.lock();
fftSize = fftSize_in;
desiredInputSize = fftSize;
desiredInputSize.store(fftSize);
if (fftwInput) {
free(fftwInput);
@ -82,7 +92,7 @@ void SpectrumVisualProcessor::setup(int fftSize_in) {
fftwf_destroy_plan(fftw_plan);
}
fftw_plan = fftwf_plan_dft_1d(fftSize, fftwInput, fftwOutput, FFTW_FORWARD, FFTW_ESTIMATE);
busy_run.unlock();
}
void SpectrumVisualProcessor::process() {
@ -102,6 +112,7 @@ void SpectrumVisualProcessor::process() {
}
iqData->busy_rw.lock();
busy_run.lock();
std::vector<liquid_float_complex> *data = &iqData->data;
@ -118,6 +129,7 @@ void SpectrumVisualProcessor::process() {
if (!iqData->frequency || !iqData->sampleRate) {
iqData->decRefCount();
iqData->busy_rw.unlock();
busy_run.unlock();
return;
}
@ -125,7 +137,7 @@ void SpectrumVisualProcessor::process() {
int desired_input_size = fftSize / resamplerRatio;
this->desiredInputSize = desired_input_size;
this->desiredInputSize.store(desired_input_size);
if (iqData->data.size() < desired_input_size) {
// std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
@ -283,9 +295,6 @@ void SpectrumVisualProcessor::process() {
}
}
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;
@ -293,7 +302,7 @@ void SpectrumVisualProcessor::process() {
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));
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)));
output->spectrum_points[i * 2] = ((float) i / (float) iMax);
output->spectrum_points[i * 2 + 1] = v;
}
@ -307,5 +316,6 @@ void SpectrumVisualProcessor::process() {
iqData->decRefCount();
iqData->busy_rw.unlock();
busy_run.unlock();
}

View File

@ -53,7 +53,7 @@ private:
double fft_ceil_ma, fft_ceil_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_ma;
@ -66,7 +66,8 @@ private:
std::vector<liquid_float_complex> shiftBuffer;
std::vector<liquid_float_complex> resampleBuffer;
int desiredInputSize;
std::atomic_int desiredInputSize;
std::mutex busy_run;
};

View File

@ -1,17 +1,21 @@
#include "GLPanel.h"
#include "cubic_math.h"
#include <algorithm>
using namespace CubicVR;
GLPanel::GLPanel() : fillType(GLPANEL_FILL_SOLID), contentsVisible(true), transform(mat4::identity()) {
pos[0] = 0.0f;
pos[1] = 0.0f;
rot[0] = 0.0f;
rot[1] = 0.0f;
rot[2] = 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);
fill[0] = RGBA4f(0.5,0.5,0.5);
fill[1] = RGBA4f(0.1,0.1,0.1);
borderColor = RGBA4f(0.8, 0.8, 0.8);
setCoordinateSystem(GLPANEL_Y_UP);
setMarginPx(0);
setBorderPx(0);
@ -23,8 +27,8 @@ void GLPanel::genArrays() {
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);
glColors.reserve(4 * 4);
glColors.resize(4 * 4);
float pts[2 * 4] = {
min, min,
@ -33,7 +37,7 @@ void GLPanel::genArrays() {
max, min
};
RGB3f c[4];
RGBA4f c[4];
if (fillType == GLPANEL_FILL_SOLID) {
c[0] = c[1] = c[2] = c[3] = fill[0];
@ -45,22 +49,22 @@ void GLPanel::genArrays() {
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
};
float clr[4 * 4] = {
c[0].r, c[0].g, c[0].b, c[0].a,
c[1].r, c[1].g, c[1].b, c[1].a,
c[2].r, c[2].g, c[2].b, c[2].a,
c[3].r, c[3].g, c[3].b, c[3].a
};
glPoints.assign(pts, pts + (2 * 4));
glColors.assign(clr, clr + (3 * 4));
glColors.assign(clr, clr + (4 * 4));
} else {
glPoints.reserve(2 * 8);
glPoints.resize(2 * 8);
glColors.reserve(3 * 8);
glColors.resize(3 * 8);
glColors.reserve(4 * 8);
glColors.resize(4 * 8);
RGB3f c[8];
RGBA4f c[8];
if (fillType == GLPANEL_FILL_GRAD_BAR_X) {
float pts[2 * 8] = {
@ -103,18 +107,18 @@ void GLPanel::genArrays() {
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
float clr[4 * 8] = {
c[0].r, c[0].g, c[0].b, c[0].a,
c[1].r, c[1].g, c[1].b, c[1].a,
c[2].r, c[2].g, c[2].b, c[2].a,
c[3].r, c[3].g, c[3].b, c[3].a,
c[4].r, c[4].g, c[4].b, c[4].a,
c[5].r, c[5].g, c[5].b, c[5].a,
c[6].r, c[6].g, c[6].b, c[6].a,
c[7].r, c[7].g, c[7].b, c[7].a
};
glColors.assign(clr, clr + (3 * 8));
glColors.assign(clr, clr + (4 * 8));
}
}
@ -175,12 +179,12 @@ void GLPanel::setFill(GLPanelFillType fill_mode) {
genArrays();
}
void GLPanel::setFillColor(RGB3f color1) {
void GLPanel::setFillColor(RGBA4f color1) {
fill[0] = color1;
genArrays();
}
void GLPanel::setFillColor(RGB3f color1, RGB3f color2) {
void GLPanel::setFillColor(RGBA4f color1, RGBA4f color2) {
fill[0] = color1;
fill[1] = color2;
genArrays();
@ -191,7 +195,7 @@ void GLPanel::setMarginPx(float marg) {
}
void GLPanel::setBorderColor(RGB3f clr) {
void GLPanel::setBorderColor(RGBA4f clr) {
borderColor = clr;
}
@ -207,7 +211,19 @@ void GLPanel::setBorderPx(float bordl, float bordr, float bordt, float bordb) {
}
void GLPanel::addChild(GLPanel *childPanel) {
children.push_back(childPanel);
std::vector<GLPanel *>::iterator i = std::find(children.begin(), children.end(), childPanel);
if (i == children.end()) {
children.push_back(childPanel);
}
}
void GLPanel::removeChild(GLPanel *childPanel) {
std::vector<GLPanel *>::iterator i = std::find(children.begin(), children.end(), childPanel);
if (i != children.end()) {
children.erase(i);
}
}
void GLPanel::drawChildren() {
@ -228,6 +244,11 @@ void GLPanel::drawPanelContents() {
void GLPanel::calcTransform(mat4 transform_in) {
// compute local transform
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
transform = transform_in * localTransform;
@ -265,10 +286,12 @@ void GLPanel::draw() {
glLoadMatrixf(transform);
if (fillType != GLPANEL_FILL_NONE) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, &glPoints[0]);
glColorPointer(3, GL_FLOAT, 0, &glColors[0]);
glColorPointer(4, GL_FLOAT, 0, &glColors[0]);
glDrawArrays(GL_QUADS, 0, glPoints.size() / 2);
@ -277,7 +300,7 @@ void GLPanel::draw() {
if (borderPx.left || borderPx.right || borderPx.top || borderPx.bottom) {
glEnable(GL_LINE_SMOOTH);
glColor3f(borderColor.r, borderColor.g, borderColor.b);
glColor4f(borderColor.r, borderColor.g, borderColor.b, borderColor.a);
if (borderPx.left) {
glLineWidth(borderPx.left);
@ -313,6 +336,7 @@ void GLPanel::draw() {
glDisable(GL_LINE_SMOOTH);
}
glDisable(GL_BLEND);
}
if (contentsVisible) {
@ -337,6 +361,8 @@ void GLPanel::draw() {
GLTextPanel::GLTextPanel() : GLPanel() {
coord = GLPANEL_Y_UP;
horizAlign = GLFont::GLFONT_ALIGN_CENTER;
vertAlign = GLFont::GLFONT_ALIGN_CENTER;
}
void GLTextPanel::drawPanelContents() {
@ -346,19 +372,19 @@ void GLTextPanel::drawPanelContents() {
float size;
if (pdim.y < 16) {
if (pdim.y <= 16) {
sz = GLFont::GLFONT_SIZE12;
size = 12;
} else if (pdim.y < 18) {
} else if (pdim.y <= 18) {
sz = GLFont::GLFONT_SIZE16;
size = 16;
} else if(pdim.y < 24) {
} else if(pdim.y <= 24) {
sz = GLFont::GLFONT_SIZE18;
size = 18;
} else if(pdim.y < 32) {
} else if(pdim.y <= 32) {
sz = GLFont::GLFONT_SIZE24;
size = 24;
} else if(pdim.y < 48) {
} else if(pdim.y <= 48) {
sz = GLFont::GLFONT_SIZE32;
size = 32;
} else {
@ -367,11 +393,13 @@ void GLTextPanel::drawPanelContents() {
}
GLFont::getFont(sz).drawString(textVal, mid, mid, size, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, (int)pdim.x, (int)pdim.y);
GLFont::getFont(sz).drawString(textVal, mid, mid, size, horizAlign, vertAlign, (int)pdim.x, (int)pdim.y);
}
void GLTextPanel::setText(std::string text) {
void GLTextPanel::setText(std::string text, GLFont::Align hAlign, GLFont::Align vAlign) {
textVal = text;
horizAlign = hAlign;
vertAlign = vAlign;
}
std::string GLTextPanel::getText() {

View File

@ -36,14 +36,15 @@ 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 rot[3];
float size[2];
float view[2];
GLPanelFillType fillType;
GLPanelCoordinateSystem coord;
float marginPx;
GLPanelEdges borderPx;
RGB3f fill[2];
RGB3f borderColor;
RGBA4f fill[2];
RGBA4f borderColor;
bool contentsVisible;
CubicVR::mat4 transform;
CubicVR::mat4 localTransform;
@ -68,15 +69,16 @@ public:
void setCoordinateSystem(GLPanelCoordinateSystem coord);
void setFill(GLPanelFillType fill_mode);
void setFillColor(RGB3f color1);
void setFillColor(RGB3f color1, RGB3f color2);
void setFillColor(RGBA4f color1);
void setFillColor(RGBA4f color1, RGBA4f color2);
void setMarginPx(float marg);
void setBorderColor(RGB3f clr);
void setBorderColor(RGBA4f clr);
void setBorderPx(float bord);
void setBorderPx(float bordl, float bordr, float bordt, float bordb);
void addChild(GLPanel *childPanel);
void removeChild(GLPanel *childPanel);
void drawChildren();
virtual void drawPanelContents();
@ -88,11 +90,13 @@ public:
class GLTextPanel : public GLPanel {
private:
std::string textVal;
GLFont::Align horizAlign;
GLFont::Align vertAlign;
public:
GLTextPanel();
void drawPanelContents();
void setText(std::string text);
void setText(std::string text, GLFont::Align hAlign = GLFont::GLFONT_ALIGN_CENTER, GLFont::Align vAlign = GLFont::GLFONT_ALIGN_CENTER);
std::string getText();
};

View File

@ -9,30 +9,30 @@ PrimaryGLContext(canvas, sharedContext) {
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));
testPanel.setFillColor(RGBA4f(0.0,0.0,1.0), RGBA4f(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.setFillColor(RGBA4f(0.0,0.0,1.0), RGBA4f(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.setFillColor(RGBA4f(0.0,0.0,1.0), RGBA4f(0.0,1.0,0.0));
testChildPanel2.setBorderColor(RGBA4f(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.setFillColor(RGBA4f(0.0,0.0,1.0), RGBA4f(0.0,1.0,0.0));
testChildPanel3.setBorderColor(RGBA4f(1.0,0.0,0.0));
testChildPanel3.setBorderPx(1);
testText1.setText("Testing 123..");

View File

@ -14,6 +14,7 @@
#include <thread>
#include <cstdint>
#include <condition_variable>
#include <atomic>
class ThreadQueueBase {
@ -30,13 +31,17 @@ class ThreadQueue : public ThreadQueueBase {
public:
/*! Create safe queue. */
ThreadQueue() = default;
ThreadQueue() {
m_max_num_items.store(0);
};
ThreadQueue(ThreadQueue&& sq) {
m_queue = std::move(sq.m_queue);
m_max_num_items.store(0);
}
ThreadQueue(const ThreadQueue& sq) {
std::lock_guard < std::mutex > lock(sq.m_mutex);
m_queue = sq.m_queue;
m_max_num_items.store(0);
}
/*! Destroy safe queue. */
@ -49,7 +54,10 @@ public:
* \param[in] item An item.
*/
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) {
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;
m_queue.push(item);
@ -76,7 +84,7 @@ public:
bool push(const value_type&& item) {
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;
m_queue.push(item);
@ -217,7 +225,7 @@ public:
*/
bool full() const {
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;
mutable std::mutex m_mutex;
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. */

View File

@ -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 = 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);
waterfallHighlight = RGBA4f(1, 1, 1);
waterfallNew = RGBA4f(0, 1, 0);
waterfallHover = RGBA4f(1, 1, 0);
waterfallDestroy = RGBA4f(1, 0, 0);
fftLine = RGBA4f(0.9, 0.9, 0.9);
fftHighlight = RGBA4f(1, 1, 1);
scopeLine = RGBA4f(0.9, 0.9, 0.9);
tuningBarLight = RGBA4f(0.2, 0.2, 0.9);
tuningBarDark = RGBA4f(0.0, 0.0, 0.35);
tuningBarUp = RGBA4f(1.0, 139.0/255.0, 96.0/255.0);
tuningBarDown = RGBA4f(148.0/255.0, 148.0/255.0, 1.0);
meterLevel = RGBA4f(0.1, 0.75, 0.1);
meterValue = RGBA4f(0.75, 0.1, 0.1);
text = RGBA4f(1, 1, 1);
freqLine = RGBA4f(1, 1, 1);
button = RGBA4f(0.65, 0.65, 0.65);
buttonHighlight = RGBA4f(1, 1, 0);
scopeBackground = RGB3f(0.1, 0.1, 0.1);
fftBackground = RGB3f(0.1, 0.1, 0.1);
generalBackground = RGB3f(0.1, 0.1, 0.1);
scopeBackground = RGBA4f(0.1, 0.1, 0.1);
fftBackground = RGBA4f(0.1, 0.1, 0.1);
generalBackground = RGBA4f(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 = 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);
waterfallHighlight = RGBA4f(1, 1, 1);
waterfallNew = RGBA4f(0, 1, 0);
waterfallHover = RGBA4f(1, 1, 0);
waterfallDestroy = RGBA4f(1, 0, 0);
fftLine = RGBA4f(0.8, 1.0, 0.8);
fftHighlight = RGBA4f(1, 1, 1);
scopeLine = RGBA4f(0.8, 1.0, 0.8);
tuningBarLight = RGBA4f(0.0, 0.45, 0.0);
tuningBarDark = RGBA4f(0.0, 0.1, 0.0);
tuningBarUp = RGBA4f(1.0, 139.0/255.0, 96.0/255.0);
tuningBarDown = RGBA4f(148.0/255.0, 0.0, 0.0);
meterLevel = RGBA4f(0, 0.5, 0);
meterValue = RGBA4f(0, 0.5, 0);
text = RGBA4f(0.8, 1.0, 0.8);
freqLine = RGBA4f(1, 1, 1);
button = RGBA4f(0.65, 0.75, 0.65);
buttonHighlight = RGBA4f(0.65, 1.0, 0.65);
scopeBackground = RGB3f(0.05, 0.1, 0.05);
fftBackground = RGB3f(0.05, 0.1, 0.05);
generalBackground = RGB3f(0.05, 0.1, 0.05);
scopeBackground = RGBA4f(0.05, 0.1, 0.05);
fftBackground = RGBA4f(0.05, 0.1, 0.05);
generalBackground = RGBA4f(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 = 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);
waterfallHighlight = RGBA4f(1, 1, 0.9);
waterfallNew = RGBA4f(0, 1, 0);
waterfallHover = RGBA4f(1, 1, 0);
waterfallDestroy = RGBA4f(1, 0, 0);
fftLine = RGBA4f(0.9, 0.9, 0.9);
fftHighlight = RGBA4f(1, 1, 0.9);
scopeLine = RGBA4f(0.9, 0.9, 0.9);
tuningBarLight = RGBA4f(0.4, 0.4, 0.4);
tuningBarDark = RGBA4f(0.1, 0.1, 0.1);
tuningBarUp = RGBA4f(0.8, 0.8, 0.8);
tuningBarDown = RGBA4f(0.4, 0.4, 0.4);
meterLevel = RGBA4f(0.5, 0.5, 0.5);
meterValue = RGBA4f(0.5, 0.5, 0.5);
text = RGBA4f(1, 1, 1);
freqLine = RGBA4f(1, 1, 1);
button = RGBA4f(0.65, 0.65, 0.65);
buttonHighlight = RGBA4f(1, 1, 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);
scopeBackground = RGBA4f(0.1, 0.1, 0.1);
fftBackground = RGBA4f(0.1, 0.1, 0.1);
generalBackground = RGBA4f(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 = 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);
waterfallHighlight = RGBA4f(0.9, 0.9, 1.0);
waterfallNew = RGBA4f(0, 1, 0);
waterfallHover = RGBA4f(1, 1, 0);
waterfallDestroy = RGBA4f(1, 0, 0);
fftLine = RGBA4f(0.9, 0.9, 1.0);
fftHighlight = RGBA4f(0.9, 0.9, 1.0);
scopeLine = RGBA4f(0.85, 0.85, 1.0);
tuningBarLight = RGBA4f(28.0 / 255.0, 106.0 / 255.0, 179.0 / 255.0);
tuningBarDark = RGBA4f(14.0 / 255.0, 53.0 / 255.0, 89.5 / 255.0);
tuningBarUp = RGBA4f(0.7, 0.7, 0.7);
tuningBarDown = RGBA4f(1.0, 0.0, 0.0);
meterLevel = RGBA4f(28.0 / 255.0, 106.0 / 255.0, 179.0 / 255.0);
meterValue = RGBA4f(190.0 / 255.0, 190.0 / 255.0, 60.0 / 255.0);
text = RGBA4f(0.9, 0.9, 1);
freqLine = RGBA4f(0.85, 0.85, 1.0);
button = RGBA4f(217.0 / 255.0, 218.0 / 255.0, 228.0 / 255.0);
buttonHighlight = RGBA4f(208.0 / 255.0, 249.0 / 255.0, 255.0 / 255.0);
scopeBackground = RGB3f(0.05, 0.05, 0.15);
fftBackground = RGB3f(0.05, 0.05, 0.15);
generalBackground = RGB3f(0.05, 0.05, 0.15);
scopeBackground = RGBA4f(0.05, 0.05, 0.15);
fftBackground = RGBA4f(0.05, 0.05, 0.15);
generalBackground = RGBA4f(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 = 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);
waterfallHighlight = RGBA4f(1, 1, 1);
waterfallNew = RGBA4f(0, 1, 0);
waterfallHover = RGBA4f(1, 1, 0);
waterfallDestroy = RGBA4f(1, 0, 0);
fftLine = RGBA4f(1.0, 0.9, 0.9);
fftHighlight = RGBA4f(1, 1, 1);
scopeLine = RGBA4f(1.0, 0.9, 0.9);
tuningBarLight = RGBA4f(0.0, 0.45, 0.0);
tuningBarDark = RGBA4f(0.0, 0.1, 0.0);
tuningBarUp = RGBA4f(1.0, 0.0, 0.0);
tuningBarDown = RGBA4f(0.0, 0.5, 1.0);
meterLevel = RGBA4f(0, 0.5, 0);
meterValue = RGBA4f(0.5, 0, 0);
text = RGBA4f(1, 1, 1);
freqLine = RGBA4f(1, 1, 1);
button = RGBA4f(0.65, 0.65, 0.65);
buttonHighlight = RGBA4f(0.76, 0.65, 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);
scopeBackground = RGBA4f(13.0 / 255.0, 47.0 / 255.0, 9.0 / 255.0);
fftBackground = RGBA4f(0, 0, 50.0 / 255.0);
generalBackground = RGBA4f(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 = 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);
waterfallHighlight = RGBA4f(1, 1, 1);
waterfallNew = RGBA4f(0, 1, 0);
waterfallHover = RGBA4f(1, 1, 0);
waterfallDestroy = RGBA4f(1, 0, 0);
fftLine = RGBA4f(234.0 / 255.0, 232.0 / 255.0, 247.0 / 255.0);
fftHighlight = RGBA4f(1.0, 1.0, 1.0);
scopeLine = RGBA4f(234.0 / 255.0, 232.0 / 255.0, 247.0 / 255.0);
tuningBarLight = RGBA4f(0.2, 0.2, 0.7);
tuningBarDark = RGBA4f(0.1, 0.1, 0.45);
tuningBarUp = RGBA4f(0.5, 139.0/255.0, 96.0/255.0);
tuningBarDown = RGBA4f(0.6, 108.0/255.0, 1.0);
meterLevel = RGBA4f(61.0 / 255.0, 57.0 / 255.0, 88.0 / 255.0);
meterValue = RGBA4f(61.0 / 255.0, 57.0 / 255.0, 88.0 / 255.0);
text = RGBA4f(1, 1, 1);
freqLine = RGBA4f(1, 1, 1);
button = RGBA4f(1.0, 1.0, 1.0);
buttonHighlight = RGBA4f(208.0 / 255.0, 202.0 / 255.0, 247.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);
scopeBackground = RGBA4f(39.0 / 255.0, 36.0 / 255.0, 56.0 / 255.0);
fftBackground = RGBA4f(39.0 / 255.0, 36.0 / 255.0, 56.0 / 255.0);
generalBackground = RGBA4f(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 = 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);
waterfallHighlight = RGBA4f(1, 1, 1);
waterfallNew = RGBA4f(0, 1, 0);
waterfallHover = RGBA4f(1, 1, 0);
waterfallDestroy = RGBA4f(1, 0, 0);
fftLine = RGBA4f(0.9, 0.9, 0.9);
fftHighlight = RGBA4f(1, 1, 1);
scopeLine = RGBA4f(0.9, 0.9, 0.9);
tuningBarLight = RGBA4f(0.4, 0.4, 1.0);
tuningBarDark = RGBA4f(0.1, 0.1, 0.45);
tuningBarUp = RGBA4f(1.0, 139.0/255.0, 96.0/255.0);
tuningBarDown = RGBA4f(148.0/255.0, 148.0/255.0, 1.0);
meterLevel = RGBA4f(0, 0.5, 0);
meterValue = RGBA4f(0.0, 0.0, 1.0);
text = RGBA4f(1, 1, 1);
freqLine = RGBA4f(1, 1, 1);
button = RGBA4f(0, 0.7, 0.7);
buttonHighlight = RGBA4f(1, 1, 1);
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);
scopeBackground = RGBA4f(0.0, 0.0, 48.0 / 255.0);
fftBackground = RGBA4f(0.0, 0.0, 48.0 / 255.0);
generalBackground = RGBA4f(0.0, 0.0, 0.0);
}

View File

@ -15,55 +15,56 @@
#define COLOR_THEME_RADAR 6
#define COLOR_THEME_MAX 7
class RGB3f {
class RGBA4f {
public:
float r, g, b;
RGB3f(float r, float g, float b) :
r(r), g(g), b(b) {
float r, g, b, a;
RGBA4f(float r, float g, float b, float a = 1.0) :
r(r), g(g), b(b), a(a) {
}
RGB3f() :
RGB3f(0, 0, 0) {
RGBA4f() :
RGBA4f(0, 0, 0) {
}
~RGB3f() {
~RGBA4f() {
}
RGB3f & operator=(const RGB3f &other) {
RGBA4f & operator=(const RGBA4f &other) {
r = other.r;
g = other.g;
b = other.b;
a = other.a;
return *this;
}
RGB3f operator*(float v) { return RGB3f(r*v, g*v, b*v); }
RGBA4f operator*(float v) { return RGBA4f(r*v, g*v, b*v); }
};
class ColorTheme {
public:
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;
RGBA4f waterfallHighlight;
RGBA4f waterfallNew;
RGBA4f wfHighlight;
RGBA4f waterfallHover;
RGBA4f waterfallDestroy;
RGBA4f fftLine;
RGBA4f fftHighlight;
RGBA4f scopeLine;
RGBA4f tuningBarLight;
RGBA4f tuningBarDark;
RGBA4f tuningBarUp;
RGBA4f tuningBarDown;
RGBA4f meterLevel;
RGBA4f meterValue;
RGBA4f text;
RGBA4f freqLine;
RGBA4f button;
RGBA4f buttonHighlight;
RGB3f scopeBackground;
RGB3f fftBackground;
RGB3f generalBackground;
RGBA4f scopeBackground;
RGBA4f fftBackground;
RGBA4f generalBackground;
Gradient waterfallGradient;

View File

@ -25,9 +25,11 @@ EVT_ENTER_WINDOW(ModeSelectorCanvas::OnMouseEnterWindow)
wxEND_EVENT_TABLE()
ModeSelectorCanvas::ModeSelectorCanvas(wxWindow *parent, int *attribList) :
InteractiveCanvas(parent, attribList), numChoices(0), currentSelection(-1) {
InteractiveCanvas(parent, attribList), numChoices(0), currentSelection(-1), toggleMode(false), inputChanged(false), padX(4.0), padY(4.0), highlightOverride(false) {
glContext = new ModeSelectorContext(this, &wxGetApp().GetContext(this));
highlightColor = RGBA4f(1.0,1.0,1.0,1.0);
}
ModeSelectorCanvas::~ModeSelectorCanvas() {
@ -59,10 +61,15 @@ void ModeSelectorCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
int yval = getHoveredSelection();
for (int i = 0; i < numChoices; i++) {
if (yval == i) {
glContext->DrawSelector(selections[i].label, i, numChoices, true, ThemeMgr::mgr.currentTheme->buttonHighlight.r, ThemeMgr::mgr.currentTheme->buttonHighlight.g, ThemeMgr::mgr.currentTheme->buttonHighlight.b, 1.0);
if (yval == i && !highlightOverride) {
RGBA4f hc = ThemeMgr::mgr.currentTheme->buttonHighlight;
glContext->DrawSelector(selections[i].label, i, numChoices, true, hc.r, hc.g, hc.b, 1.0, padX, padY);
} else {
glContext->DrawSelector(selections[i].label, i, numChoices, i == currentSelection, ThemeMgr::mgr.currentTheme->button.r, ThemeMgr::mgr.currentTheme->button.g, ThemeMgr::mgr.currentTheme->button.b, 1.0);
RGBA4f hc = ThemeMgr::mgr.currentTheme->button;
if (highlightOverride) {
hc = highlightColor;
}
glContext->DrawSelector(selections[i].label, i, numChoices, i == currentSelection, hc.r, hc.g, hc.b, 1.0, padX, padY);
}
}
@ -97,11 +104,22 @@ void ModeSelectorCanvas::OnMouseReleased(wxMouseEvent& event) {
const wxSize ClientSize = GetClientSize();
int selectedButton = currentSelection;
if (mouseTracker.getOriginDeltaMouseX() < 2.0 / ClientSize.y) {
currentSelection = getHoveredSelection();
selectedButton = getHoveredSelection();
}
SetCursor (wxCURSOR_ARROW);
if (toggleMode && (currentSelection == selectedButton)) {
selectedButton = -1;
}
if (currentSelection != selectedButton) {
inputChanged = true;
}
currentSelection = selectedButton;
SetCursor (wxCURSOR_HAND);
}
void ModeSelectorCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
@ -112,7 +130,7 @@ void ModeSelectorCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
void ModeSelectorCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
InteractiveCanvas::mouseTracker.OnMouseEnterWindow(event);
SetCursor (wxCURSOR_ARROW);
SetCursor (wxCURSOR_HAND);
if (!helpTip.empty()) {
setStatusText(helpTip);
}
@ -148,4 +166,24 @@ int ModeSelectorCanvas::getSelection() {
return selections[currentSelection].value;
}
void ModeSelectorCanvas::setToggleMode(bool toggleMode) {
this->toggleMode = toggleMode;
}
bool ModeSelectorCanvas::modeChanged() {
return inputChanged;
}
void ModeSelectorCanvas::clearModeChanged() {
inputChanged = false;
}
void ModeSelectorCanvas::setPadding(float padX, float padY) {
this->padX = padX;
this->padY = padY;
}
void ModeSelectorCanvas::setHighlightColor(RGBA4f hc) {
this->highlightColor = hc;
this->highlightOverride = true;
}

View File

@ -35,6 +35,14 @@ public:
void setSelection(int value);
int getSelection();
void setToggleMode(bool toggleMode);
bool modeChanged();
void clearModeChanged();
void setPadding(float padX, float padY);
void setHighlightColor(RGBA4f hc);
private:
void setNumChoices(int numChoices_in);
@ -53,7 +61,12 @@ private:
std::string helpTip;
int numChoices;
int currentSelection;
bool toggleMode;
bool inputChanged;
std::vector<ModeSelectorMode> selections;
float padX, padY;
RGBA4f highlightColor;
bool highlightOverride;
//
wxDECLARE_EVENT_TABLE();
};

View File

@ -22,7 +22,7 @@ void ModeSelectorContext::DrawBegin() {
glDisable(GL_TEXTURE_2D);
}
void ModeSelectorContext::DrawSelector(std::string label, int c, int cMax, bool on, float r, float g, float b, float a) {
void ModeSelectorContext::DrawSelector(std::string label, int c, int cMax, bool on, float r, float g, float b, float a, float px, float py) {
GLint vp[4];
glGetIntegerv( GL_VIEWPORT, vp);
@ -42,15 +42,21 @@ void ModeSelectorContext::DrawSelector(std::string label, int c, int cMax, bool
float y = 1.0 - ((float) (c+1) / (float) cMax * 2.0);
float height = (2.0 / (float) cMax);
float padX = (4.0 / viewWidth);
float padY = (4.0 / viewHeight);
float padX = (px / viewWidth);
float padY = (py / viewHeight);
if (a < 1.0) {
glEnable(GL_BLEND);
}
glBegin(on?GL_QUADS:GL_LINE_LOOP);
glVertex2f(-1.0 + padX, y + padY);
glVertex2f(1.0 - padX, y + padY);
glVertex2f(1.0 - padX, y + height - padY);
glVertex2f(-1.0 + padX, y + height - padY);
glEnd();
if (a < 1.0) {
glDisable(GL_BLEND);
}
if (on) {
glColor4f(0, 0, 0, a);

View File

@ -12,6 +12,6 @@ public:
ModeSelectorContext(ModeSelectorCanvas *canvas, wxGLContext *sharedContext);
void DrawBegin();
void DrawSelector(std::string label, int c, int cMax, bool on, float r, float g, float b, float a);
void DrawSelector(std::string label, int c, int cMax, bool on, float r, float g, float b, float a, float padx, float pady);
void DrawEnd();
};

View File

@ -59,7 +59,7 @@ PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas, wxGLContext *sharedContex
//#endif
}
void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, long long center_freq, long long srate) {
void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBA4f color, long long center_freq, long long srate) {
if (!demod) {
return;
}
@ -94,7 +94,12 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, lo
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0, 0, 0, 0.35);
if (demod->isMuted()) {
glColor4f(0.8, 0, 0, 0.35);
} else {
glColor4f(0, 0, 0, 0.35);
}
glBegin(GL_QUADS);
glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0);
glVertex3f(uxPos - ofsLeft, -1.0, 0.0);
@ -128,19 +133,25 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, lo
glColor4f(1.0, 1.0, 1.0, 0.8);
std::string demodLabel = demod->getLabel();
if (demod->isMuted()) {
demodLabel = std::string("[M] ") + demodLabel;
}
if (demod->getDemodulatorType() == DEMOD_TYPE_USB) {
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER);
} else if (demod->getDemodulatorType() == DEMOD_TYPE_LSB) {
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER);
} else {
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
}
glDisable(GL_BLEND);
}
void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGB3f color, long long center_freq, long long srate) {
void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBA4f color, long long center_freq, long long srate) {
if (!demod) {
return;
}
@ -283,14 +294,14 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGB3f color, long l
glColor3f(0, 0, 0);
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);
glColor3f(1, 1, 1);
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, RGB3f color, float w, long long center_freq, long long srate) {
void PrimaryGLContext::DrawFreqSelector(float uxPos, RGBA4f color, float w, long long center_freq, long long srate) {
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
long long bw = 0;
@ -341,7 +352,7 @@ void PrimaryGLContext::DrawFreqSelector(float uxPos, RGB3f color, float w, long
}
void PrimaryGLContext::DrawRangeSelector(float uxPos1, float uxPos2, RGB3f color) {
void PrimaryGLContext::DrawRangeSelector(float uxPos1, float uxPos2, RGBA4f color) {
if (uxPos2 < uxPos1) {
float temp = uxPos2;
uxPos2=uxPos1;

View File

@ -21,10 +21,10 @@ public:
void BeginDraw(float r, float g, float b);
void EndDraw();
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 DrawFreqSelector(float uxPos, RGBA4f color, float w = 0, long long center_freq = -1, long long srate = 0);
void DrawRangeSelector(float uxPos1, float uxPos2, RGBA4f color);
void DrawDemod(DemodulatorInstance *demod, RGBA4f color, long long center_freq = -1, long long srate = 0);
void DrawDemodInfo(DemodulatorInstance *demod, RGBA4f color, long long center_freq = -1, long long srate = 0);
void setHoverAlpha(float hoverAlpha);

View File

@ -14,24 +14,65 @@
#include "CubicSDRDefs.h"
#include "AppFrame.h"
#include <algorithm>
#include <cmath>
wxBEGIN_EVENT_TABLE(ScopeCanvas, wxGLCanvas) EVT_PAINT(ScopeCanvas::OnPaint)
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()
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) :
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE), stereo(false), ppmMode(false) {
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), stereo(false), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") {
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() {
}
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) {
stereo = state;
}
@ -49,20 +90,40 @@ bool ScopeCanvas::getPPMMode() {
return ppmMode;
}
void ScopeCanvas::setShowDb(bool showDb) {
this->showDb = showDb;
}
bool ScopeCanvas::getShowDb() {
return showDb;
}
void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
wxPaintDC dc(this);
const wxSize ClientSize = GetClientSize();
if (!inputData.empty()) {
while (!inputData.empty()) {
ScopeRenderData *avData;
inputData.pop(avData);
if (avData) {
if (!avData->spectrum) {
if (avData->waveform_points.size()) {
scopePanel.setPoints(avData->waveform_points);
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();
}
}
@ -71,21 +132,95 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
initGLExtensions();
glViewport(0, 0, ClientSize.x, ClientSize.y);
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.calcTransform(CubicVR::mat4::identity());
scopePanel.draw();
glContext->DrawTunerTitles(ppmMode);
glMatrixMode(GL_PROJECTION);
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()) {
glContext->DrawDeviceName(deviceName);
}
glContext->DrawEnd();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glContext->DrawTunerTitles(ppmMode);
glContext->DrawEnd();
SwapBuffers();
}
void ScopeCanvas::OnIdle(wxIdleEvent &event) {
Refresh();
event.RequestMore();
@ -94,3 +229,44 @@ void ScopeCanvas::OnIdle(wxIdleEvent &event) {
ScopeRenderDataQueue *ScopeCanvas::getInputQueue() {
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;
}

View File

@ -9,9 +9,11 @@
#include "ScopeContext.h"
#include "ScopeVisualProcessor.h"
#include "ScopePanel.h"
#include "SpectrumPanel.h"
#include "fftw3.h"
#include "InteractiveCanvas.h"
class ScopeCanvas: public wxGLCanvas {
class ScopeCanvas: public InteractiveCanvas {
public:
ScopeCanvas(wxWindow *parent, int *attribList = NULL);
~ScopeCanvas();
@ -21,18 +23,41 @@ public:
void setPPMMode(bool ppmMode);
bool getPPMMode();
void setShowDb(bool showDb);
bool getShowDb();
bool scopeVisible();
bool spectrumVisible();
void setHelpTip(std::string tip);
ScopeRenderDataQueue *getInputQueue();
private:
void OnPaint(wxPaintEvent& 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;
ScopePanel scopePanel;
GLPanel parentPanel;
SpectrumPanel spectrumPanel;
GLPanel bgPanel;
ScopeContext *glContext;
std::string deviceName;
bool stereo;
bool ppmMode;
bool showDb;
float panelSpacing;
float ctr;
float ctrTarget;
float dragAccel;
std::string helpTip;
// event table
wxDECLARE_EVENT_TABLE();
};

View File

@ -73,6 +73,8 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
spectrumPanel.calcTransform(CubicVR::mat4::identity());
spectrumPanel.draw();
glLoadIdentity();
std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
for (int i = 0, iMax = demods.size(); i < iMax; i++) {
@ -81,6 +83,8 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glContext->EndDraw();
spectrumPanel.drawChildren();
SwapBuffers();
}
@ -122,10 +126,18 @@ void SpectrumCanvas::moveCenterFrequency(long long freqChange) {
freq -= freqChange;
}
wxGetApp().setFrequency(freq);
setStatusText("Set center frequency: %s", freq);
}
}
void SpectrumCanvas::setShowDb(bool showDb) {
spectrumPanel.setShowDb(showDb);
}
bool SpectrumCanvas::getShowDb() {
return spectrumPanel.getShowDb();
}
void SpectrumCanvas::OnMouseMoved(wxMouseEvent& event) {
InteractiveCanvas::OnMouseMoved(event);
if (mouseTracker.mouseDown()) {
@ -135,7 +147,7 @@ void SpectrumCanvas::OnMouseMoved(wxMouseEvent& event) {
moveCenterFrequency(freqChange);
}
} else {
setStatusText("Click and drag to adjust center frequency.");
setStatusText("Click and drag to adjust center frequency. 'B' to toggle decibels display.");
}
}

View File

@ -19,6 +19,9 @@ public:
void attachWaterfallCanvas(WaterfallCanvas *canvas_in);
void moveCenterFrequency(long long freqChange);
void setShowDb(bool showDb);
bool getShowDb();
SpectrumVisualDataQueue *getVisualDataQueue();
private:

View File

@ -98,10 +98,10 @@ void TuningCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
0.75, mouseTracker.getOriginMouseX(), mouseTracker.getMouseX());
}
RGB3f clr = top ? ThemeMgr::mgr.currentTheme->tuningBarUp : ThemeMgr::mgr.currentTheme->tuningBarDown;
RGBA4f clr = top ? ThemeMgr::mgr.currentTheme->tuningBarUp : ThemeMgr::mgr.currentTheme->tuningBarDown;
RGB3f clrDark = ThemeMgr::mgr.currentTheme->tuningBarDark;
RGB3f clrMid = ThemeMgr::mgr.currentTheme->tuningBarLight;
RGBA4f clrDark = ThemeMgr::mgr.currentTheme->tuningBarDark;
RGBA4f 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);
@ -143,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, RGB3f(1.0,0.0,0.0));
glContext->DrawTunerDigitBox((int)log10(snap), 11, freqDP, freqW, RGBA4f(1.0,0.0,0.0));
}
}
glContext->DrawTuner(bw, 7, bwDP, bwW);

View File

@ -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, RGB3f c) {
void TuningContext::DrawTunerDigitBox(int index, int count, float displayPos, float displayWidth, RGBA4f 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, RGB3f color, float alpha, bool top,
void TuningContext::DrawTunerBarIndexed(int start, int end, int count, float displayPos, float displayWidth, RGBA4f color, float alpha, bool top,
bool bottom) {
float ofs = (displayWidth / (float) count);
float p2 = displayPos + ofs * (float) (count - start + 1);

View File

@ -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, RGB3f c);
void DrawTunerDigitBox(int index, int count, float displayPos, float displayWidth, RGBA4f c);
int GetTunerDigitIndex(float mPos, int count, float displayPos, float displayWidth);
void DrawTunerBarIndexed(int start, int end, int count, float displayPos, float displayWidth, RGB3f color, float alpha, bool top, bool bottom);
void DrawTunerBarIndexed(int start, int end, int count, float displayPos, float displayWidth, RGBA4f color, float alpha, bool top, bool bottom);
void DrawDemodFreqBw(long long freq, unsigned int bw, long long center);
void DrawEnd();

View File

@ -36,7 +36,7 @@ wxEND_EVENT_TABLE()
WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
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) {
dragOfs(0), mouseZoom(1), zoom(1), freqMove(0.0), freqMoving(false), hoverAlpha(1.0) {
glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this));
@ -102,6 +102,19 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
}
}
if (freqMove != 0.0) {
long long newFreq = getCenterFrequency() + (long long)((long double)getBandwidth()*freqMove) * 0.01;
updateCenterFrequency(newFreq);
if (!freqMoving) {
freqMove -= (freqMove * 0.2);
if (fabs(freqMove) < 0.01) {
freqMove = 0.0;
}
}
}
long long bw;
if (currentZoom != 1) {
long long freq = wxGetApp().getFrequency();
@ -161,7 +174,13 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
if (spectrumCanvas) {
if ((spectrumCanvas->getCenterFrequency() != centerFreq) || (spectrumCanvas->getBandwidth() != bw)) {
spectrumCanvas->setView(centerFreq,bw);
if (getViewState()) {
spectrumCanvas->setView(centerFreq,bw);
} else {
spectrumCanvas->disableView();
spectrumCanvas->setCenterFrequency(centerFreq);
spectrumCanvas->setBandwidth(bw);
}
}
}
}
@ -274,6 +293,12 @@ void WaterfallCanvas::OnKeyUp(wxKeyEvent& event) {
zoom = 1.0;
mouseZoom = 1.05;
break;
case WXK_LEFT:
case WXK_NUMPAD_LEFT:
case WXK_RIGHT:
case WXK_NUMPAD_RIGHT:
freqMoving = false;
break;
}
}
@ -300,18 +325,20 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
break;
case WXK_RIGHT:
case WXK_NUMPAD_RIGHT:
if (shiftDown) {
freq += getBandwidth() * 10;
if (isView) {
freqMove = shiftDown?5.0:1.0;
freqMoving = true;
} else {
freq += getBandwidth() / 2;
freq += shiftDown?(getBandwidth() * 10):(getBandwidth() / 2);
}
break;
case WXK_LEFT:
case WXK_NUMPAD_LEFT:
if (shiftDown) {
freq -= getBandwidth() * 10;
if (isView) {
freqMove = shiftDown?-5.0:-1.0;
freqMoving = true;
} else {
freq -= getBandwidth() / 2;
freq -= shiftDown?(getBandwidth() * 10):(getBandwidth() / 2);
}
break;
case 'D':
@ -322,6 +349,12 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
wxGetApp().removeDemodulator(activeDemod);
wxGetApp().getDemodMgr().deleteThread(activeDemod);
break;
case 'M':
if (!activeDemod) {
break;
}
activeDemod->setMuted(!activeDemod->isMuted());
break;
case 'S':
if (!activeDemod) {
break;
@ -332,6 +365,11 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
activeDemod->setStereo(true);
}
break;
case 'B':
if (spectrumCanvas) {
spectrumCanvas->setShowDb(!spectrumCanvas->getShowDb());
}
break;
case WXK_SPACE:
wxGetApp().showFrequencyInput();
break;
@ -346,30 +384,7 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
}
if (freq != originalFreq) {
if (isView) {
setView(freq, getBandwidth());
if (spectrumCanvas) {
spectrumCanvas->setView(freq, getBandwidth());
}
long long minFreq = wxGetApp().getFrequency()-(wxGetApp().getSampleRate()/2);
long long maxFreq = wxGetApp().getFrequency()+(wxGetApp().getSampleRate()/2);
if (freq < minFreq) {
wxGetApp().setFrequency(freq+(wxGetApp().getSampleRate()/2));
setStatusText("Set center frequency: %s", freq);
}
if (freq > maxFreq) {
wxGetApp().setFrequency(freq-(wxGetApp().getSampleRate()/2));
setStatusText("Set center frequency: %s", freq);
}
} else {
if (spectrumCanvas) {
spectrumCanvas->setCenterFrequency(freq);
}
wxGetApp().setFrequency(freq);
setStatusText("Set center frequency: %s", freq);
}
updateCenterFrequency(freq);
}
}
@ -406,7 +421,6 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
}
demod->setBandwidth(currentBW);
setStatusText("Set demodulator bandwidth: %s", demod->getBandwidth());
}
if (dragState == WF_DRAG_FREQUENCY) {
@ -424,8 +438,6 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
currentFreq = demod->getFrequency();
demod->updateLabel(currentFreq);
}
setStatusText("Set demodulator frequency: %s", demod->getFrequency());
}
} else if (mouseTracker.mouseRightDown()) {
mouseZoom = mouseZoom + ((1.0 - (mouseTracker.getDeltaMouseY() * 4.0)) - mouseZoom) * 0.1;
@ -505,14 +517,14 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
mouseTracker.setVertDragLock(true);
mouseTracker.setHorizDragLock(false);
setStatusText("Click and drag to change demodulator bandwidth. SPACE for direct frequency input. D to delete, S for stereo.");
setStatusText("Click and drag to change demodulator bandwidth. SPACE for direct frequency input. M for mute, D to delete, S for stereo.");
} else {
SetCursor(wxCURSOR_SIZING);
nextDragState = WF_DRAG_FREQUENCY;
mouseTracker.setVertDragLock(true);
mouseTracker.setHorizDragLock(false);
setStatusText("Click and drag to change demodulator frequency; SPACE for direct input. D to delete, S for stereo.");
setStatusText("Click and drag to change demodulator frequency; SPACE for direct input. M for mute, D to delete, S for stereo.");
}
} else {
SetCursor(wxCURSOR_CROSS);
@ -521,7 +533,7 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
setStatusText("Click to create a new demodulator or hold ALT to drag range, SPACE for direct center frequency input.");
} else {
setStatusText(
"Click to move active demodulator frequency or hold ALT to drag range; hold SHIFT to create new. Right drag or A / Z to Zoom. Arrow keys (+SHIFT) to move center frequency; SPACE for direct input.");
"Click to move active demodulator frequency or hold ALT to drag range; hold SHIFT to create new. Right drag or wheel to Zoom. Arrow keys to navigate/zoom.");
}
}
@ -600,6 +612,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
demod->setStereo(mgr->isLastStereo());
demod->setGain(mgr->getLastGain());
demod->setMuted(mgr->isLastMuted());
demod->run();
@ -740,3 +753,29 @@ void WaterfallCanvas::OnMouseRightReleased(wxMouseEvent& event) {
SpectrumVisualDataQueue *WaterfallCanvas::getVisualDataQueue() {
return &visualDataQueue;
}
void WaterfallCanvas::updateCenterFrequency(long long freq) {
if (isView) {
setView(freq, getBandwidth());
if (spectrumCanvas) {
spectrumCanvas->setView(freq, getBandwidth());
}
long long minFreq = wxGetApp().getFrequency()-(wxGetApp().getSampleRate()/2);
long long maxFreq = wxGetApp().getFrequency()+(wxGetApp().getSampleRate()/2);
if (freq < minFreq) {
wxGetApp().setFrequency(freq+(wxGetApp().getSampleRate()/2));
}
if (freq > maxFreq) {
wxGetApp().setFrequency(freq-(wxGetApp().getSampleRate()/2));
}
} else {
if (spectrumCanvas) {
spectrumCanvas->setCenterFrequency(freq);
}
wxGetApp().setFrequency(freq);
}
}

View File

@ -45,6 +45,8 @@ private:
void OnMouseEnterWindow(wxMouseEvent& event);
void OnMouseLeftWindow(wxMouseEvent& event);
void updateCenterFrequency(long long freq);
std::vector<float> spectrum_points;
SpectrumCanvas *spectrumCanvas;
@ -59,6 +61,8 @@ private:
int dragOfs;
float mouseZoom, zoom;
bool freqMoving;
long double freqMove;
float hoverAlpha;
SpectrumVisualDataQueue visualDataQueue;