2014-10-27 21:22:29 -04:00
|
|
|
#include "AppFrame.h"
|
|
|
|
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
|
|
|
|
#ifndef WX_PRECOMP
|
|
|
|
#include "wx/wx.h"
|
|
|
|
#endif
|
|
|
|
|
2015-01-06 00:57:57 -05:00
|
|
|
#include "wx/numdlg.h"
|
2015-01-08 23:57:58 -05:00
|
|
|
#include "wx/filedlg.h"
|
2015-01-06 00:57:57 -05:00
|
|
|
|
2014-10-27 21:22:29 -04:00
|
|
|
#if !wxUSE_GLCANVAS
|
|
|
|
#error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
|
|
|
|
#endif
|
|
|
|
|
2014-10-28 21:39:59 -04:00
|
|
|
#include <vector>
|
|
|
|
#include "SDRThread.h"
|
2014-11-17 22:58:56 -05:00
|
|
|
#include "DemodulatorMgr.h"
|
2014-11-16 16:51:45 -05:00
|
|
|
#include "AudioThread.h"
|
2014-11-16 19:02:40 -05:00
|
|
|
#include "CubicSDR.h"
|
2015-01-09 17:17:56 -05:00
|
|
|
#include "DataTree.h"
|
2014-10-27 21:22:29 -04:00
|
|
|
|
2014-11-21 21:50:14 -05:00
|
|
|
#include <thread>
|
|
|
|
|
2014-12-27 23:47:56 -05:00
|
|
|
#include <wx/panel.h>
|
|
|
|
|
2014-10-28 21:39:59 -04:00
|
|
|
wxBEGIN_EVENT_TABLE(AppFrame, wxFrame)
|
|
|
|
//EVT_MENU(wxID_NEW, AppFrame::OnNewWindow)
|
2014-12-31 22:38:59 -05:00
|
|
|
EVT_MENU(wxID_CLOSE, AppFrame::OnClose)
|
2014-12-31 21:31:37 -05:00
|
|
|
EVT_MENU(wxID_ANY, AppFrame::OnMenu)
|
2014-11-17 18:14:37 -05:00
|
|
|
EVT_COMMAND(wxID_ANY, wxEVT_THREAD, AppFrame::OnThread)
|
2014-10-28 21:39:59 -04:00
|
|
|
EVT_IDLE(AppFrame::OnIdle)
|
2014-10-27 21:22:29 -04:00
|
|
|
wxEND_EVENT_TABLE()
|
|
|
|
|
|
|
|
AppFrame::AppFrame() :
|
2015-01-10 12:27:03 -05:00
|
|
|
wxFrame(NULL, wxID_ANY, wxT("CubicSDR " CUBICSDR_VERSION " by Charles J. Cliffe (@ccliffe)")), activeDemodulator(NULL) {
|
2014-10-27 21:22:29 -04:00
|
|
|
|
2014-11-15 23:41:41 -05:00
|
|
|
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
|
2014-12-27 23:47:56 -05:00
|
|
|
wxBoxSizer *demodOpts = new wxBoxSizer(wxVERTICAL);
|
2014-12-28 20:55:05 -05:00
|
|
|
wxBoxSizer *demodVisuals = new wxBoxSizer(wxVERTICAL);
|
|
|
|
wxBoxSizer *demodTray = new wxBoxSizer(wxHORIZONTAL);
|
2015-01-04 17:11:20 -05:00
|
|
|
wxBoxSizer *demodScopeTray = new wxBoxSizer(wxVERTICAL);
|
2014-12-27 23:47:56 -05:00
|
|
|
|
2015-01-05 19:12:16 -05:00
|
|
|
demodModeSelector = new ModeSelectorCanvas(this, NULL);
|
2015-01-10 12:27:03 -05:00
|
|
|
demodModeSelector->addChoice(DEMOD_TYPE_FM, "FM");
|
|
|
|
demodModeSelector->addChoice(DEMOD_TYPE_AM, "AM");
|
|
|
|
demodModeSelector->addChoice(DEMOD_TYPE_LSB, "LSB");
|
|
|
|
demodModeSelector->addChoice(DEMOD_TYPE_USB, "USB");
|
|
|
|
demodModeSelector->addChoice(DEMOD_TYPE_DSB, "DSB");
|
2015-01-05 19:12:16 -05:00
|
|
|
demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0);
|
|
|
|
|
|
|
|
// demodTray->AddSpacer(2);
|
|
|
|
|
2014-12-29 00:24:10 -05:00
|
|
|
demodSpectrumCanvas = new SpectrumCanvas(this, NULL);
|
2015-01-03 17:07:39 -05:00
|
|
|
demodSpectrumCanvas->setup(1024);
|
|
|
|
demodSpectrumCanvas->setView(DEFAULT_FREQ, 300000);
|
2015-01-06 19:15:27 -05:00
|
|
|
demodVisuals->Add(demodSpectrumCanvas, 3, wxEXPAND | wxALL, 0);
|
2014-12-29 00:24:10 -05:00
|
|
|
|
|
|
|
demodVisuals->AddSpacer(1);
|
2014-12-28 20:55:05 -05:00
|
|
|
|
2014-12-28 05:13:46 -05:00
|
|
|
demodWaterfallCanvas = new WaterfallCanvas(this, NULL);
|
2015-01-06 19:15:27 -05:00
|
|
|
demodWaterfallCanvas->setup(1024, 128);
|
2015-01-03 17:07:39 -05:00
|
|
|
demodWaterfallCanvas->setView(DEFAULT_FREQ, 300000);
|
2014-12-29 00:24:10 -05:00
|
|
|
demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas);
|
2015-01-01 21:10:54 -05:00
|
|
|
demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas);
|
2015-01-06 19:15:27 -05:00
|
|
|
demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0);
|
2014-12-28 20:55:05 -05:00
|
|
|
|
2014-12-31 19:45:01 -05:00
|
|
|
demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);
|
|
|
|
|
|
|
|
demodTray->AddSpacer(2);
|
|
|
|
|
|
|
|
demodSignalMeter = new MeterCanvas(this, NULL);
|
|
|
|
demodSignalMeter->setMax(0.5);
|
2015-01-04 13:20:31 -05:00
|
|
|
demodSignalMeter->setHelpTip("Current Signal Level. Click / Drag to set Squelch level.");
|
2014-12-31 19:45:01 -05:00
|
|
|
demodTray->Add(demodSignalMeter, 1, wxEXPAND | wxALL, 0);
|
2014-12-28 20:55:05 -05:00
|
|
|
|
|
|
|
demodTray->AddSpacer(2);
|
2014-12-28 05:13:46 -05:00
|
|
|
|
2014-11-15 23:41:41 -05:00
|
|
|
scopeCanvas = new ScopeCanvas(this, NULL);
|
2015-01-04 17:11:20 -05:00
|
|
|
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
|
|
|
|
|
|
|
|
demodScopeTray->AddSpacer(2);
|
|
|
|
|
|
|
|
demodTuner = new TuningCanvas(this, NULL);
|
|
|
|
demodTuner->setHelpTip("Testing tuner");
|
|
|
|
demodScopeTray->Add(demodTuner, 1, wxEXPAND | wxALL, 0);
|
|
|
|
|
|
|
|
demodTray->Add(demodScopeTray, 30, wxEXPAND | wxALL, 0);
|
2014-12-27 23:47:56 -05:00
|
|
|
|
2015-01-06 19:15:27 -05:00
|
|
|
vbox->Add(demodTray, 12, wxEXPAND | wxALL, 0);
|
2014-11-15 23:41:41 -05:00
|
|
|
vbox->AddSpacer(2);
|
|
|
|
spectrumCanvas = new SpectrumCanvas(this, NULL);
|
2015-01-03 17:07:39 -05:00
|
|
|
spectrumCanvas->setup(2048);
|
2015-01-06 19:15:27 -05:00
|
|
|
vbox->Add(spectrumCanvas, 5, wxEXPAND | wxALL, 0);
|
2014-11-15 23:41:41 -05:00
|
|
|
vbox->AddSpacer(2);
|
|
|
|
waterfallCanvas = new WaterfallCanvas(this, NULL);
|
2015-01-03 17:07:39 -05:00
|
|
|
waterfallCanvas->setup(2048, 512);
|
2014-12-29 00:24:10 -05:00
|
|
|
waterfallCanvas->attachSpectrumCanvas(spectrumCanvas);
|
2015-01-01 21:10:54 -05:00
|
|
|
spectrumCanvas->attachWaterfallCanvas(waterfallCanvas);
|
2015-01-06 19:15:27 -05:00
|
|
|
vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0);
|
2014-11-15 23:41:41 -05:00
|
|
|
|
|
|
|
this->SetSizer(vbox);
|
2014-10-27 21:22:29 -04:00
|
|
|
|
2015-01-06 00:29:33 -05:00
|
|
|
// waterfallCanvas->SetFocusFromKbd();
|
2014-12-10 21:22:13 -05:00
|
|
|
waterfallCanvas->SetFocus();
|
|
|
|
|
2014-10-27 23:52:25 -04:00
|
|
|
// SetIcon(wxICON(sample));
|
2014-10-27 21:22:29 -04:00
|
|
|
|
2014-10-28 21:39:59 -04:00
|
|
|
// Make a menubar
|
2015-01-06 00:29:33 -05:00
|
|
|
wxMenuBar *menuBar = new wxMenuBar;
|
|
|
|
wxMenu *menu = new wxMenu;
|
2014-10-27 21:22:29 -04:00
|
|
|
// menu->Append(wxID_NEW);
|
2015-01-06 00:57:57 -05:00
|
|
|
menu->Append(wxID_SET_FREQ_OFFSET, "Set Frequency Offset");
|
2015-01-08 23:57:58 -05:00
|
|
|
menu->Append(wxID_OPEN, "&Open Session");
|
|
|
|
menu->Append(wxID_SAVE, "&Save Session");
|
|
|
|
menu->Append(wxID_SAVEAS, "Save Session &As..");
|
2015-01-06 00:57:57 -05:00
|
|
|
menu->AppendSeparator();
|
2015-01-10 12:27:03 -05:00
|
|
|
menu->Append(wxID_RESET, "&Reset Session");
|
2015-01-06 00:29:33 -05:00
|
|
|
menu->Append(wxID_CLOSE);
|
2014-12-31 19:45:01 -05:00
|
|
|
|
2015-01-06 00:29:33 -05:00
|
|
|
menuBar->Append(menu, wxT("&File"));
|
|
|
|
|
|
|
|
menu = new wxMenu;
|
2014-12-31 19:45:01 -05:00
|
|
|
|
|
|
|
std::vector<RtAudio::DeviceInfo>::iterator devices_i;
|
2015-01-01 18:08:54 -05:00
|
|
|
std::map<int, RtAudio::DeviceInfo>::iterator mdevices_i;
|
2014-12-31 19:45:01 -05:00
|
|
|
AudioThread::enumerateDevices(devices);
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (devices_i = devices.begin(); devices_i != devices.end(); devices_i++) {
|
|
|
|
if (devices_i->inputChannels) {
|
2015-01-03 17:07:39 -05:00
|
|
|
inputDevices[i] = *devices_i;
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
|
|
|
if (devices_i->outputChannels) {
|
2015-01-03 17:07:39 -05:00
|
|
|
outputDevices[i] = *devices_i;
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2014-12-31 21:31:37 -05:00
|
|
|
i = 0;
|
2014-12-31 19:45:01 -05:00
|
|
|
|
2015-01-03 17:07:39 -05:00
|
|
|
for (mdevices_i = outputDevices.begin(); mdevices_i != outputDevices.end(); mdevices_i++) {
|
2015-01-01 18:08:54 -05:00
|
|
|
wxMenuItem *itm = menu->AppendRadioItem(wxID_RT_AUDIO_DEVICE + mdevices_i->first, mdevices_i->second.name, wxT("Description?"));
|
|
|
|
itm->SetId(wxID_RT_AUDIO_DEVICE + mdevices_i->first);
|
2014-12-31 19:45:01 -05:00
|
|
|
if (mdevices_i->second.isDefaultOutput) {
|
|
|
|
itm->Check(true);
|
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
outputDeviceMenuItems[mdevices_i->first] = itm;
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
|
|
|
|
2015-01-02 22:44:09 -05:00
|
|
|
menuBar->Append(menu, wxT("Active Demodulator &Output"));
|
2015-01-01 03:48:32 -05:00
|
|
|
|
2014-10-27 21:22:29 -04:00
|
|
|
SetMenuBar(menuBar);
|
|
|
|
|
|
|
|
CreateStatusBar();
|
2014-11-16 19:02:40 -05:00
|
|
|
SetClientSize(1280, 600);
|
2014-10-31 01:37:01 -04:00
|
|
|
Centre();
|
2014-10-27 21:22:29 -04:00
|
|
|
Show();
|
|
|
|
|
2014-12-16 21:30:03 -05:00
|
|
|
GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), DEFAULT_FREQ));
|
2014-11-25 00:35:06 -05:00
|
|
|
|
2015-01-10 12:27:03 -05:00
|
|
|
wxAcceleratorEntry entries[3];
|
|
|
|
entries[0].Set(wxACCEL_CTRL, (int) 'O', wxID_OPEN);
|
|
|
|
entries[1].Set(wxACCEL_CTRL, (int) 'S', wxID_SAVE);
|
|
|
|
entries[2].Set(wxACCEL_CTRL, (int) 'A', wxID_SAVEAS);
|
|
|
|
|
|
|
|
wxAcceleratorTable accel(3, entries);
|
|
|
|
SetAcceleratorTable(accel);
|
|
|
|
|
2014-10-27 21:22:29 -04:00
|
|
|
// static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 };
|
|
|
|
// wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not");
|
|
|
|
// ShowFullScreen(true);
|
|
|
|
}
|
|
|
|
|
2014-11-04 18:39:08 -05:00
|
|
|
AppFrame::~AppFrame() {
|
|
|
|
|
2014-11-11 20:25:16 -05:00
|
|
|
}
|
|
|
|
|
2014-12-31 21:31:37 -05:00
|
|
|
void AppFrame::OnMenu(wxCommandEvent& event) {
|
2015-01-01 18:08:54 -05:00
|
|
|
if (event.GetId() >= wxID_RT_AUDIO_DEVICE && event.GetId() < wxID_RT_AUDIO_DEVICE + devices.size()) {
|
2014-12-31 21:31:37 -05:00
|
|
|
if (activeDemodulator) {
|
2015-01-01 18:08:54 -05:00
|
|
|
activeDemodulator->setOutputDevice(event.GetId() - wxID_RT_AUDIO_DEVICE);
|
2014-12-31 21:31:37 -05:00
|
|
|
activeDemodulator = NULL;
|
|
|
|
}
|
2015-01-06 00:57:57 -05:00
|
|
|
} else if (event.GetId() == wxID_SET_FREQ_OFFSET) {
|
2015-01-08 23:57:58 -05:00
|
|
|
long ofs = wxGetNumberFromUser("Shift the displayed frequency by this amount.\ni.e. -125000000 for -125 MHz", "Frequency (Hz)",
|
|
|
|
"Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this);
|
2015-01-06 19:15:27 -05:00
|
|
|
if (ofs != -1) {
|
|
|
|
wxGetApp().setOffset(ofs);
|
|
|
|
}
|
2015-01-08 23:57:58 -05:00
|
|
|
} else if (event.GetId() == wxID_SAVE) {
|
2015-01-10 12:27:03 -05:00
|
|
|
if (!currentSessionFile.empty()) {
|
|
|
|
saveSession(currentSessionFile);
|
|
|
|
} else {
|
|
|
|
wxFileDialog saveFileDialog(this, _("Save XML Session file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
|
|
if (saveFileDialog.ShowModal() == wxID_CANCEL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
saveSession(saveFileDialog.GetPath().ToStdString());
|
|
|
|
}
|
2015-01-08 23:57:58 -05:00
|
|
|
} else if (event.GetId() == wxID_OPEN) {
|
2015-01-10 12:27:03 -05:00
|
|
|
wxFileDialog openFileDialog(this, _("Open XML Session file"), "", "", "XML files (*.xml)|*.xml", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
|
|
|
if (openFileDialog.ShowModal() == wxID_CANCEL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
loadSession(openFileDialog.GetPath().ToStdString());
|
2015-01-08 23:57:58 -05:00
|
|
|
} else if (event.GetId() == wxID_SAVEAS) {
|
2015-01-10 12:27:03 -05:00
|
|
|
wxFileDialog saveFileDialog(this, _("Save XML Session file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
|
|
if (saveFileDialog.ShowModal() == wxID_CANCEL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
saveSession(saveFileDialog.GetPath().ToStdString());
|
|
|
|
} else if (event.GetId() == wxID_RESET) {
|
|
|
|
wxGetApp().getDemodMgr().terminateAll();
|
|
|
|
wxGetApp().setFrequency(DEFAULT_FREQ);
|
|
|
|
wxGetApp().setOffset(0);
|
2015-01-08 23:57:58 -05:00
|
|
|
} else if (event.GetId() == wxID_EXIT) {
|
|
|
|
Close(false);
|
2014-12-31 21:31:37 -05:00
|
|
|
}
|
2014-10-27 21:22:29 -04:00
|
|
|
}
|
|
|
|
|
2014-12-31 22:38:59 -05:00
|
|
|
void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) {
|
2015-01-08 23:57:58 -05:00
|
|
|
Close(false);
|
2014-12-31 22:38:59 -05:00
|
|
|
}
|
|
|
|
|
2014-10-27 21:22:29 -04:00
|
|
|
void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) {
|
|
|
|
new AppFrame();
|
|
|
|
}
|
2014-10-28 21:39:59 -04:00
|
|
|
|
2014-11-17 18:14:37 -05:00
|
|
|
void AppFrame::OnThread(wxCommandEvent& event) {
|
2014-11-22 22:17:33 -05:00
|
|
|
event.Skip();
|
2014-11-16 16:51:45 -05:00
|
|
|
}
|
|
|
|
|
2014-10-28 21:39:59 -04:00
|
|
|
void AppFrame::OnIdle(wxIdleEvent& event) {
|
2014-11-22 20:57:06 -05:00
|
|
|
bool work_done = false;
|
2014-10-28 21:39:59 -04:00
|
|
|
|
2014-12-16 20:33:44 -05:00
|
|
|
//#ifdef __APPLE__
|
|
|
|
// std::this_thread::sleep_for(std::chrono::milliseconds(4));
|
|
|
|
// std::this_thread::yield();
|
|
|
|
//#endif
|
2014-12-28 05:13:46 -05:00
|
|
|
|
|
|
|
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
|
|
|
|
|
|
|
if (demod) {
|
2014-12-31 19:45:01 -05:00
|
|
|
if (demod != activeDemodulator) {
|
|
|
|
demodSignalMeter->setInputValue(demod->getSquelchLevel());
|
2014-12-31 21:31:37 -05:00
|
|
|
int outputDevice = demod->getOutputDevice();
|
2015-01-03 17:07:39 -05:00
|
|
|
scopeCanvas->setDeviceName(outputDevices[outputDevice].name);
|
|
|
|
outputDeviceMenuItems[outputDevice]->Check(true);
|
2015-01-01 18:08:54 -05:00
|
|
|
int dType = demod->getDemodulatorType();
|
2015-01-06 00:29:33 -05:00
|
|
|
demodModeSelector->setSelection(dType);
|
2014-12-31 19:45:01 -05:00
|
|
|
}
|
2014-12-28 20:55:05 -05:00
|
|
|
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
|
2015-01-03 17:07:39 -05:00
|
|
|
if (demod->getParams().frequency != demodWaterfallCanvas->getCenterFrequency()) {
|
2015-01-04 17:11:20 -05:00
|
|
|
demodWaterfallCanvas->setCenterFrequency(demod->getFrequency());
|
|
|
|
demodSpectrumCanvas->setCenterFrequency(demod->getFrequency());
|
2014-12-28 20:55:05 -05:00
|
|
|
}
|
2015-01-06 00:29:33 -05:00
|
|
|
int dSelection = demodModeSelector->getSelection();
|
|
|
|
if (dSelection != -1 && dSelection != demod->getDemodulatorType()) {
|
|
|
|
demod->setDemodulatorType(dSelection);
|
|
|
|
}
|
|
|
|
|
2014-12-28 20:55:05 -05:00
|
|
|
unsigned int demodBw = (unsigned int) ceil((float) demod->getParams().bandwidth * 2.5);
|
2014-12-29 00:24:10 -05:00
|
|
|
if (demodBw > SRATE / 2) {
|
|
|
|
demodBw = SRATE / 2;
|
2014-12-28 20:55:05 -05:00
|
|
|
}
|
2015-01-01 18:08:54 -05:00
|
|
|
if (demodBw < 80000) {
|
|
|
|
demodBw = 80000;
|
2014-12-28 20:55:05 -05:00
|
|
|
}
|
2015-01-03 17:07:39 -05:00
|
|
|
demodWaterfallCanvas->setBandwidth(demodBw);
|
|
|
|
demodSpectrumCanvas->setBandwidth(demodBw);
|
2014-12-28 05:13:46 -05:00
|
|
|
}
|
2014-12-31 19:45:01 -05:00
|
|
|
demodSignalMeter->setLevel(demod->getSignalLevel());
|
|
|
|
if (demodSignalMeter->inputChanged()) {
|
|
|
|
demod->setSquelchLevel(demodSignalMeter->getInputValue());
|
|
|
|
}
|
|
|
|
activeDemodulator = demod;
|
2014-12-28 05:13:46 -05:00
|
|
|
}
|
|
|
|
|
2014-11-23 19:39:27 -05:00
|
|
|
if (!wxGetApp().getIQVisualQueue()->empty()) {
|
2014-12-26 16:15:35 -05:00
|
|
|
DemodulatorThreadIQData *iqData;
|
2014-11-23 19:39:27 -05:00
|
|
|
wxGetApp().getIQVisualQueue()->pop(iqData);
|
2014-11-22 20:57:06 -05:00
|
|
|
|
2014-12-23 01:59:03 -05:00
|
|
|
if (iqData && iqData->data.size()) {
|
2014-12-29 00:24:10 -05:00
|
|
|
// spectrumCanvas->setData(iqData);
|
2014-12-28 05:13:46 -05:00
|
|
|
waterfallCanvas->setData(iqData);
|
|
|
|
demodWaterfallCanvas->setData(iqData);
|
2014-12-23 01:59:03 -05:00
|
|
|
delete iqData;
|
2014-11-22 20:57:06 -05:00
|
|
|
} else {
|
|
|
|
std::cout << "Incoming IQ data empty?" << std::endl;
|
|
|
|
}
|
|
|
|
work_done = true;
|
|
|
|
}
|
|
|
|
|
2014-11-23 19:39:27 -05:00
|
|
|
if (!wxGetApp().getAudioVisualQueue()->empty()) {
|
2014-12-23 01:59:03 -05:00
|
|
|
AudioThreadInput *demodAudioData;
|
2014-11-23 19:39:27 -05:00
|
|
|
wxGetApp().getAudioVisualQueue()->pop(demodAudioData);
|
2014-12-23 01:59:03 -05:00
|
|
|
if (demodAudioData && demodAudioData->data.size()) {
|
2014-12-28 05:13:46 -05:00
|
|
|
if (scopeCanvas->waveform_points.size() != demodAudioData->data.size() * 2) {
|
|
|
|
scopeCanvas->waveform_points.resize(demodAudioData->data.size() * 2);
|
2014-11-22 22:17:33 -05:00
|
|
|
}
|
|
|
|
|
2014-12-23 01:59:03 -05:00
|
|
|
for (int i = 0, iMax = demodAudioData->data.size(); i < iMax; i++) {
|
|
|
|
scopeCanvas->waveform_points[i * 2 + 1] = demodAudioData->data[i] * 0.5f;
|
2014-11-22 22:17:33 -05:00
|
|
|
scopeCanvas->waveform_points[i * 2] = ((double) i / (double) iMax);
|
|
|
|
}
|
|
|
|
|
2014-12-29 00:24:10 -05:00
|
|
|
scopeCanvas->setStereo(demodAudioData->channels == 2);
|
2014-12-26 23:28:18 -05:00
|
|
|
|
2014-12-23 01:59:03 -05:00
|
|
|
delete demodAudioData;
|
2014-11-22 22:17:33 -05:00
|
|
|
} else {
|
|
|
|
std::cout << "Incoming Demodulator data empty?" << std::endl;
|
|
|
|
}
|
|
|
|
work_done = true;
|
|
|
|
}
|
|
|
|
|
2015-01-06 00:29:33 -05:00
|
|
|
if (!waterfallCanvas->HasFocus()) {
|
|
|
|
waterfallCanvas->SetFocus();
|
|
|
|
}
|
|
|
|
|
2014-11-22 20:57:06 -05:00
|
|
|
if (!work_done) {
|
2014-12-16 21:30:03 -05:00
|
|
|
event.Skip();
|
2014-11-22 20:57:06 -05:00
|
|
|
}
|
2014-10-28 21:39:59 -04:00
|
|
|
}
|
2015-01-09 17:17:56 -05:00
|
|
|
|
|
|
|
void AppFrame::saveSession(std::string fileName) {
|
|
|
|
DataTree s("cubicsdr_session");
|
2015-01-09 20:56:43 -05:00
|
|
|
DataNode *header = s.rootNode()->newChild("header");
|
|
|
|
*header->newChild("version") = std::string(CUBICSDR_VERSION);
|
|
|
|
*header->newChild("center_freq") = wxGetApp().getFrequency();
|
|
|
|
*header->newChild("offset") = wxGetApp().getOffset();
|
2015-01-09 17:17:56 -05:00
|
|
|
|
2015-01-09 20:56:43 -05:00
|
|
|
DataNode *demods = s.rootNode()->newChild("demodulators");
|
2015-01-09 17:17:56 -05:00
|
|
|
|
|
|
|
std::vector<DemodulatorInstance *> &instances = wxGetApp().getDemodMgr().getDemodulators();
|
|
|
|
std::vector<DemodulatorInstance *>::iterator instance_i;
|
|
|
|
for (instance_i = instances.begin(); instance_i != instances.end(); instance_i++) {
|
2015-01-09 20:56:43 -05:00
|
|
|
DataNode *demod = demods->newChild("demodulator");
|
|
|
|
*demod->newChild("bandwidth") = (*instance_i)->getBandwidth();
|
|
|
|
*demod->newChild("frequency") = (*instance_i)->getFrequency();
|
|
|
|
*demod->newChild("type") = (*instance_i)->getDemodulatorType();
|
|
|
|
*demod->newChild("squelch_level") = (*instance_i)->getSquelchLevel();
|
2015-01-10 12:27:03 -05:00
|
|
|
*demod->newChild("squelch_enabled") = (*instance_i)->isSquelchEnabled() ? 1 : 0;
|
|
|
|
*demod->newChild("stereo") = (*instance_i)->isStereo() ? 1 : 0;
|
2015-01-09 20:56:43 -05:00
|
|
|
*demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name;
|
2015-01-09 17:17:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
s.SaveToFileXML(fileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AppFrame::loadSession(std::string fileName) {
|
2015-01-09 20:56:43 -05:00
|
|
|
DataTree l;
|
|
|
|
if (!l.LoadFromFileXML(fileName)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-10 12:27:03 -05:00
|
|
|
wxGetApp().getDemodMgr().terminateAll();
|
2015-01-09 20:56:43 -05:00
|
|
|
|
|
|
|
try {
|
|
|
|
DataNode *header = l.rootNode()->getNext("header");
|
|
|
|
|
2015-01-10 11:00:03 -05:00
|
|
|
std::string version(*header->getNext("version"));
|
2015-01-09 20:56:43 -05:00
|
|
|
long long center_freq = *header->getNext("center_freq");
|
|
|
|
long long offset = *header->getNext("offset");
|
|
|
|
|
|
|
|
std::cout << "Loading " << version << " session file" << std::endl;
|
|
|
|
std::cout << "\tCenter Frequency: " << center_freq << std::endl;
|
|
|
|
std::cout << "\tOffset: " << offset << std::endl;
|
|
|
|
|
2015-01-10 12:27:03 -05:00
|
|
|
wxGetApp().setOffset(offset);
|
|
|
|
wxGetApp().setFrequency(center_freq);
|
2015-01-09 20:56:43 -05:00
|
|
|
|
|
|
|
DataNode *demodulators = l.rootNode()->getNext("demodulators");
|
|
|
|
|
|
|
|
while (demodulators->hasAnother("demodulator")) {
|
|
|
|
DataNode *demod = demodulators->getNext("demodulator");
|
|
|
|
|
|
|
|
if (!demod->hasAnother("bandwidth") || !demod->hasAnother("frequency")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
long bandwidth = *demod->getNext("bandwidth");
|
|
|
|
long long freq = *demod->getNext("frequency");
|
2015-01-10 12:27:03 -05:00
|
|
|
int type = demod->hasAnother("type") ? *demod->getNext("type") : DEMOD_TYPE_FM;
|
|
|
|
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;
|
|
|
|
std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : "";
|
|
|
|
|
|
|
|
DemodulatorInstance *newDemod = wxGetApp().getDemodMgr().newThread();
|
|
|
|
newDemod->setDemodulatorType(type);
|
|
|
|
newDemod->setBandwidth(bandwidth);
|
|
|
|
newDemod->setFrequency(freq);
|
|
|
|
newDemod->updateLabel(freq);
|
|
|
|
if (squelch_enabled) {
|
|
|
|
newDemod->setSquelchEnabled(true);
|
|
|
|
newDemod->setSquelchLevel(squelch_level);
|
|
|
|
}
|
|
|
|
if (stereo) {
|
|
|
|
newDemod->setStereo(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool found_device = false;
|
|
|
|
std::map<int, RtAudio::DeviceInfo>::iterator i;
|
|
|
|
for (i = outputDevices.begin(); i != outputDevices.end(); i++) {
|
|
|
|
if (i->second.name == output_device) {
|
|
|
|
newDemod->setOutputDevice(i->first);
|
|
|
|
found_device = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found_device) {
|
|
|
|
std::cout << "\tWarning: named output device '" << output_device << "' was not found. Using default output.";
|
|
|
|
}
|
|
|
|
|
|
|
|
newDemod->run();
|
|
|
|
|
|
|
|
wxGetApp().bindDemodulator(newDemod);
|
2015-01-09 20:56:43 -05:00
|
|
|
|
2015-01-10 12:27:03 -05:00
|
|
|
std::cout << "\tAdded demodulator at frequency " << freq << " type " << type << std::endl;
|
2015-01-09 20:56:43 -05:00
|
|
|
std::cout << "\t\tBandwidth: " << bandwidth << std::endl;
|
|
|
|
std::cout << "\t\tSquelch Level: " << squelch_level << std::endl;
|
2015-01-10 12:27:03 -05:00
|
|
|
std::cout << "\t\tSquelch Enabled: " << (squelch_enabled ? "true" : "false") << std::endl;
|
|
|
|
std::cout << "\t\tStereo: " << (stereo ? "true" : "false") << std::endl;
|
2015-01-09 20:56:43 -05:00
|
|
|
std::cout << "\t\tOutput Device: " << output_device << std::endl;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (DataInvalidChildException &e) {
|
|
|
|
std::cout << e.what() << std::endl;
|
|
|
|
return false;
|
|
|
|
} catch (DataTypeMismatchException &e) {
|
|
|
|
std::cout << e.what() << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-10 12:27:03 -05:00
|
|
|
currentSessionFile = fileName;
|
2015-01-09 17:17:56 -05:00
|
|
|
}
|