Basic X/Y scope plot while in digital mode

This commit is contained in:
Charles J. Cliffe 2015-11-29 13:35:12 -05:00
parent 7e4d173996
commit c303b68284
19 changed files with 226 additions and 150 deletions

View File

@ -18,6 +18,7 @@ public:
int sampleRate;
int channels;
float peak;
int type;
std::vector<float> data;
std::mutex busy_update;

View File

@ -79,6 +79,7 @@ class DemodulatorThreadPostIQData: public ReferenceCounter {
public:
std::vector<liquid_float_complex> data;
long long sampleRate;
std::string modemName;
std::string modemType;
Modem *modem;
ModemKit *modemKit;

View File

@ -200,7 +200,8 @@ void DemodulatorPreThread::run() {
resamp->setRefCount(1);
resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten);
resamp->modemType = demodType;
resamp->modemType = cModem->getType();
resamp->modemName = cModem->getName();
resamp->modem = cModem;
resamp->modemKit = cModemKit;
resamp->sampleRate = currentBandwidth;
@ -248,8 +249,8 @@ void DemodulatorPreThread::run() {
currentSampleRate = result.sampleRate;
}
if (result.modemType != "") {
demodType = result.modemType;
if (result.modemName != "") {
demodType = result.modemName;
demodTypeChanged.store(false);
}

View File

@ -120,7 +120,7 @@ void DemodulatorThread::run() {
AudioThreadInput *ati = NULL;
ModemAnalog *modemAnalog = (cModem->getType() == "analog")?((ModemAnalog *)cModem):nullptr;
// ModemDigital *modemDigital = (cModem->getType() == "digital")?((ModemDigital *)cModem):nullptr;
ModemDigital *modemDigital = (cModem->getType() == "digital")?((ModemDigital *)cModem):nullptr;
if (modemAnalog != nullptr) {
ati = outputBuffers.getBuffer();
@ -128,7 +128,14 @@ void DemodulatorThread::run() {
ati->sampleRate = cModemKit->audioSampleRate;
ati->inputRate = inp->sampleRate;
ati->setRefCount(1);
} else if (modemDigital != nullptr) {
ati = outputBuffers.getBuffer();
ati->sampleRate = cModemKit->sampleRate;
ati->inputRate = inp->sampleRate;
ati->setRefCount(1);
}
cModem->demodulate(cModemKit, &modemData, ati);
if (currentSignalLevel > signalLevel) {
@ -160,7 +167,15 @@ void DemodulatorThread::run() {
ati_vis->inputRate = inp->sampleRate;
int num_vis = DEMOD_VIS_SIZE;
if (ati->channels==2) {
if (modemDigital) {
ati_vis->data.resize(inputData->size());
ati_vis->channels = 2;
for (int i = 0, iMax = inputData->size() / 2; i < iMax; i++) {
ati_vis->data[i * 2] = (*inputData)[i].real;
ati_vis->data[i * 2 + 1] = (*inputData)[i].imag;
}
ati_vis->type = 2;
} else if (ati->channels==2) {
ati_vis->channels = 2;
int stereoSize = ati->data.size();
if (stereoSize > DEMOD_VIS_SIZE * 2) {
@ -169,7 +184,7 @@ void DemodulatorThread::run() {
ati_vis->data.resize(stereoSize);
if (inp->modemType == "I/Q") {
if (inp->modemName == "I/Q") {
for (int i = 0; i < stereoSize / 2; i++) {
ati_vis->data[i] = (*inputData)[i].real * 0.75;
ati_vis->data[i + stereoSize / 2] = (*inputData)[i].imag * 0.75;
@ -182,6 +197,7 @@ void DemodulatorThread::run() {
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
}
}
ati_vis->type = 1;
} else {
int numAudioWritten = ati->data.size();
ati_vis->channels = 1;
@ -198,7 +214,7 @@ void DemodulatorThread::run() {
}
ati_vis->data.assign(demodOutData->begin(), demodOutData->begin() + num_vis);
}
ati_vis->type = 0;
}
audioVisOutputQueue->push(ati_vis);

View File

@ -51,7 +51,8 @@ void DemodulatorWorkerThread::run() {
if (makeDemod) {
cModem = Modem::makeModem(demodCommand.demodType);
cModemType = demodCommand.demodType;
cModemName = cModem->getName();
cModemType = cModem->getType();
if (demodCommand.settings.size()) {
cModem->writeSettings(demodCommand.settings);
}
@ -91,6 +92,7 @@ void DemodulatorWorkerThread::run() {
result.modemKit = cModemKit;
result.modemType = cModemType;
result.modemName = cModemName;
resultQueue->push(result);
}

View File

@ -37,6 +37,7 @@ public:
Modem *modem;
ModemKit *modemKit;
std::string modemType;
std::string modemName;
};
class DemodulatorWorkerThreadCommand {
@ -93,4 +94,5 @@ protected:
Modem *cModem;
ModemKit *cModemKit;
std::string cModemType;
std::string cModemName;
};

View File

@ -90,14 +90,23 @@
<event name="OnUpdateUI"></event>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer</property>
<property name="name">mainSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxTextCtrl" expanded="1">
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">dataViewSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxTextCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -184,20 +193,22 @@
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bSizer2</property>
<property name="name">buttonSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -281,11 +292,11 @@
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -369,11 +380,11 @@
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="proportion">1</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>

View File

@ -14,32 +14,38 @@ DigitalConsoleFrame::DigitalConsoleFrame( wxWindow* parent, wxWindowID id, const
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
this->SetExtraStyle( wxWS_EX_PROCESS_UI_UPDATES );
wxBoxSizer* bSizer;
bSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* mainSizer;
mainSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* dataViewSizer;
dataViewSizer = new wxBoxSizer( wxVERTICAL );
m_dataView = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_CHARWRAP|wxTE_MULTILINE|wxTE_NOHIDESEL|wxTE_READONLY|wxTE_WORDWRAP|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE|wxNO_BORDER|wxSIMPLE_BORDER|wxVSCROLL );
m_dataView->SetExtraStyle( wxWS_EX_PROCESS_UI_UPDATES );
m_dataView->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 76, 90, 90, false, wxEmptyString ) );
bSizer->Add( m_dataView, 1, wxEXPAND, 5 );
dataViewSizer->Add( m_dataView, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxHORIZONTAL );
mainSizer->Add( dataViewSizer, 1, wxEXPAND, 5 );
wxBoxSizer* buttonSizer;
buttonSizer = new wxBoxSizer( wxHORIZONTAL );
m_clearButton = new wxButton( this, wxID_ANY, wxT("Clear"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer2->Add( m_clearButton, 0, wxALL, 5 );
buttonSizer->Add( m_clearButton, 1, wxEXPAND, 5 );
m_copyButton = new wxButton( this, wxID_ANY, wxT("Copy"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer2->Add( m_copyButton, 0, wxALL, 5 );
buttonSizer->Add( m_copyButton, 1, wxEXPAND, 5 );
m_pauseButton = new wxButton( this, wxID_ANY, wxT("Stop"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer2->Add( m_pauseButton, 0, wxEXPAND, 5 );
buttonSizer->Add( m_pauseButton, 1, wxEXPAND, 5 );
bSizer->Add( bSizer2, 0, wxEXPAND, 5 );
mainSizer->Add( buttonSizer, 0, wxALL|wxEXPAND, 5 );
this->SetSizer( bSizer );
this->SetSizer( mainSizer );
this->Layout();
m_refreshTimer.SetOwner( this, wxID_ANY );
m_refreshTimer.Start( 250 );

View File

@ -16,8 +16,8 @@
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/timer.h>
#include <wx/frame.h>

View File

@ -44,9 +44,9 @@ ModemFactoryList Modem::getFactories() {
return modemFactories;
}
Modem *Modem::makeModem(std::string modemType) {
if (modemFactories.find(modemType) != modemFactories.end()) {
return modemFactories[modemType]->factory();
Modem *Modem::makeModem(std::string modemName) {
if (modemFactories.find(modemName) != modemFactories.end()) {
return modemFactories[modemName]->factory();
}
return nullptr;

View File

@ -112,7 +112,7 @@ public:
static void addModemFactory(Modem *factorySingle);
static ModemFactoryList getFactories();
static Modem *makeModem(std::string modemType);
static Modem *makeModem(std::string modemName);
virtual std::string getType() = 0;
virtual std::string getName() = 0;

View File

@ -16,6 +16,9 @@ void ScopePanel::setMode(ScopeMode scopeMode) {
this->scopeMode = scopeMode;
}
ScopePanel::ScopeMode ScopePanel::getMode() {
return this->scopeMode;
}
void ScopePanel::setPoints(std::vector<float> &points) {
this->points.assign(points.begin(),points.end());
@ -61,14 +64,29 @@ void ScopePanel::drawPanelContents() {
glEnd();
} else if (scopeMode == SCOPE_MODE_XY) {
// ...
RGBA4f bg1(ThemeMgr::mgr.currentTheme->scopeBackground), bg2(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0);
bg1.a = 0.1;
bg2.a = 0.1;
bgPanel.setFillColor(bg1, bg2);
bgPanel.calcTransform(transform);
bgPanel.draw();
glLineWidth(1.0);
glEnable(GL_POINT_SMOOTH);
glPointSize(2.0);
glLoadMatrixf(transform);
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
}
if (points.size()) {
glEnable (GL_BLEND);
glEnable (GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
if (scopeMode == SCOPE_MODE_XY) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
} else {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
glColor4f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b, 1.0);
glEnableClientState (GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
@ -83,7 +101,8 @@ void ScopePanel::drawPanelContents() {
glLoadMatrixf(bgPanelStereo[1].transform);
glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4);
} else if (scopeMode == SCOPE_MODE_XY) {
// ...
glLoadMatrixf(bgPanel.transform);
glDrawArrays(GL_POINTS, 0, points.size() / 2);
}
glLineWidth(1.0);
glDisableClientState(GL_VERTEX_ARRAY);

View File

@ -10,6 +10,7 @@ public:
ScopePanel();
void setMode(ScopeMode scopeMode);
ScopeMode getMode();
void setPoints(std::vector<float> &points);
protected:

View File

@ -95,7 +95,7 @@ void ScopeVisualProcessor::process() {
}
}
if (audioInputData->channels == 2) {
if (audioInputData->type == 1) {
iMax = audioInputData->data.size();
if (renderData->waveform_points.size() != iMax * 2) {
renderData->waveform_points.resize(iMax * 2);
@ -104,11 +104,23 @@ void ScopeVisualProcessor::process() {
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;
}
renderData->mode = ScopePanel::SCOPE_MODE_2Y;
} else if (audioInputData->type == 2) {
iMax = audioInputData->data.size();
if (renderData->waveform_points.size() != iMax) {
renderData->waveform_points.resize(iMax);
}
for (i = 0; i < iMax/2; i++) {
renderData->waveform_points[i * 2] = audioInputData->data[i * 2] / peak;
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i * 2 + 1] / peak;
}
renderData->mode = ScopePanel::SCOPE_MODE_XY;
} 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->mode = ScopePanel::SCOPE_MODE_Y;
}
renderData->spectrum = false;

View File

@ -3,10 +3,12 @@
#include "VisualProcessor.h"
#include "AudioThread.h"
#include "fftw3.h"
#include "ScopePanel.h"
class ScopeRenderData: public ReferenceCounter {
public:
std::vector<float> waveform_points;
ScopePanel::ScopeMode mode;
int inputRate;
int sampleRate;
int channels;

View File

@ -28,7 +28,7 @@ EVT_LEAVE_WINDOW(ScopeCanvas::OnMouseLeftWindow)
EVT_ENTER_WINDOW(ScopeCanvas::OnMouseEnterWindow)
wxEND_EVENT_TABLE()
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), stereo(false), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") {
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") {
glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
inputData.set_max_num_items(2);
@ -73,10 +73,6 @@ bool ScopeCanvas::spectrumVisible() {
return false;
}
void ScopeCanvas::setStereo(bool state) {
stereo = state;
}
void ScopeCanvas::setDeviceName(std::string device_name) {
deviceName = device_name;
deviceName.append(" ");
@ -106,12 +102,12 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
ScopeRenderData *avData;
inputData.pop(avData);
if (!avData->spectrum) {
scopePanel.setMode(avData->mode);
if (avData->waveform_points.size()) {
scopePanel.setPoints(avData->waveform_points);
setStereo(avData->channels == 2);
}
avData->decRefCount();
} else {
if (avData->waveform_points.size()) {
@ -133,13 +129,17 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glViewport(0, 0, ClientSize.x, ClientSize.y);
if (scopePanel.getMode() == ScopePanel::SCOPE_MODE_XY && !spectrumVisible()) {
glDrawBuffer(GL_FRONT);
glContext->DrawBegin(false);
} else {
glDrawBuffer(GL_BACK);
glContext->DrawBegin();
bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 3.0, RGBA4f(0,0,0,0));
bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 3.0, RGBA4f(0,0,0,1));
bgPanel.calcTransform(CubicVR::mat4::identity());
bgPanel.draw();
scopePanel.setMode(stereo?ScopePanel::SCOPE_MODE_2Y:ScopePanel::SCOPE_MODE_Y);
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@ -190,7 +190,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
spectrumPanel.setPosition(panelInterval+ctr, 0);
if (spectrumVisible()) {
spectrumPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0, RGBA4f(0,0,0,0));
spectrumPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0, RGBA4f(0,0,0,1));
spectrumPanel.contentsVisible = true;
roty = atan2(spectrumPanel.pos[0],1.2);
spectrumPanel.rot[1] = -(roty * (180.0 / M_PI));
@ -217,7 +217,9 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glContext->DrawTunerTitles(ppmMode);
glContext->DrawEnd();
if (scopePanel.getMode() != ScopePanel::SCOPE_MODE_XY || spectrumVisible()) {
SwapBuffers();
}
}

View File

@ -18,7 +18,6 @@ public:
ScopeCanvas(wxWindow *parent, int *attribList = NULL);
~ScopeCanvas();
void setStereo(bool state);
void setDeviceName(std::string device_name);
void setPPMMode(bool ppmMode);
bool getPPMMode();
@ -50,7 +49,6 @@ private:
GLPanel bgPanel;
ScopeContext *glContext;
std::string deviceName;
bool stereo;
bool ppmMode;
bool showDb;
float panelSpacing;

View File

@ -12,10 +12,12 @@ ScopeContext::ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext) :
glLoadIdentity();
}
void ScopeContext::DrawBegin() {
void ScopeContext::DrawBegin(bool clear) {
if (clear) {
glClearColor(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g,
ThemeMgr::mgr.currentTheme->scopeBackground.b, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();

View File

@ -11,7 +11,7 @@ class ScopeContext: public PrimaryGLContext {
public:
ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext);
void DrawBegin();
void DrawBegin(bool clear=true);
void DrawTunerTitles(bool ppmMode=false);
void DrawDeviceName(std::string deviceName);
void DrawDivider();