2020-09-20 00:19:39 +02:00
|
|
|
#include <gui/main_window.h>
|
|
|
|
#include <gui/gui.h>
|
2020-10-07 22:44:54 +02:00
|
|
|
#include "imgui.h"
|
|
|
|
#include "imgui_impl_glfw.h"
|
|
|
|
#include "imgui_impl_opengl3.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <GL/glew.h>
|
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include <imgui_plot.h>
|
|
|
|
#include <thread>
|
|
|
|
#include <complex>
|
2020-12-05 22:42:12 +01:00
|
|
|
#include <gui/widgets/waterfall.h>
|
|
|
|
#include <gui/widgets/frequency_select.h>
|
2020-10-07 22:44:54 +02:00
|
|
|
#include <fftw3.h>
|
|
|
|
#include <signal_path/dsp.h>
|
|
|
|
#include <gui/icons.h>
|
2020-12-05 22:42:12 +01:00
|
|
|
#include <gui/widgets/bandplan.h>
|
2020-10-07 22:44:54 +02:00
|
|
|
#include <watcher.h>
|
|
|
|
#include <signal_path/vfo_manager.h>
|
|
|
|
#include <gui/style.h>
|
|
|
|
#include <config.h>
|
|
|
|
#include <signal_path/signal_path.h>
|
|
|
|
#include <core.h>
|
|
|
|
#include <gui/menus/source.h>
|
|
|
|
#include <gui/menus/display.h>
|
|
|
|
#include <gui/menus/bandplan.h>
|
2020-11-29 20:55:00 +01:00
|
|
|
#include <gui/menus/sink.h>
|
2020-10-07 22:44:54 +02:00
|
|
|
#include <gui/menus/scripting.h>
|
|
|
|
#include <gui/dialogs/credits.h>
|
2020-12-08 04:36:37 +01:00
|
|
|
#include <filesystem>
|
2020-10-07 22:44:54 +02:00
|
|
|
#include <signal_path/source.h>
|
2020-11-30 21:17:36 +01:00
|
|
|
#include <gui/dialogs/loading_screen.h>
|
2020-12-22 14:50:26 +01:00
|
|
|
#include <options.h>
|
2020-12-31 14:26:12 +01:00
|
|
|
#include <gui/colormaps.h>
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-12-13 14:52:54 +01:00
|
|
|
// const int FFTSizes[] = {
|
|
|
|
// 65536,
|
|
|
|
// 32768,
|
|
|
|
// 16384,
|
|
|
|
// 8192,
|
|
|
|
// 4096,
|
|
|
|
// 2048
|
|
|
|
// };
|
|
|
|
|
|
|
|
// const char* FFTSizesStr[] = {
|
|
|
|
// "65536",
|
|
|
|
// "32768",
|
|
|
|
// "16384",
|
|
|
|
// "8192",
|
|
|
|
// "4096",
|
|
|
|
// "2048"
|
|
|
|
// };
|
|
|
|
|
|
|
|
// int fftSizeId = 0;
|
|
|
|
int fftSize = 8192 * 8;
|
|
|
|
|
2020-06-10 04:13:56 +02:00
|
|
|
std::thread worker;
|
|
|
|
std::mutex fft_mtx;
|
2020-06-10 18:52:07 +02:00
|
|
|
fftwf_complex *fft_in, *fft_out;
|
|
|
|
fftwf_plan p;
|
2020-12-12 05:34:58 +01:00
|
|
|
float* tempFFT;
|
|
|
|
float* FFTdata;
|
2020-07-19 21:26:37 +02:00
|
|
|
char buf[1024];
|
2020-06-10 18:52:07 +02:00
|
|
|
|
2020-12-13 14:52:54 +01:00
|
|
|
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-11-02 03:57:44 +01:00
|
|
|
void fftHandler(dsp::complex_t* samples, int count, void* ctx) {
|
2020-11-04 04:11:51 +01:00
|
|
|
memcpy(fft_in, samples, count * sizeof(dsp::complex_t));
|
2020-06-15 15:53:45 +02:00
|
|
|
fftwf_execute(p);
|
2020-12-13 14:52:54 +01:00
|
|
|
int half = count / 2;
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-12-13 14:52:54 +01:00
|
|
|
volk_32fc_s32f_power_spectrum_32f(tempFFT, (lv_32fc_t*)fft_out, count, count);
|
|
|
|
volk_32f_s32f_multiply_32f(FFTdata, tempFFT, 0.5f, count);
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-12-12 05:34:58 +01:00
|
|
|
memcpy(tempFFT, &FFTdata[half], half * sizeof(float));
|
|
|
|
memmove(&FFTdata[half], FFTdata, half * sizeof(float));
|
|
|
|
memcpy(FFTdata, tempFFT, half * sizeof(float));
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-12-12 05:34:58 +01:00
|
|
|
float* fftBuf = gui::waterfall.getFFTBuffer();
|
|
|
|
if (fftBuf == NULL) {
|
|
|
|
gui::waterfall.pushFFT();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
float last = FFTdata[0];
|
2020-12-13 14:52:54 +01:00
|
|
|
for (int i = 0; i < count; i++) {
|
2020-12-12 05:34:58 +01:00
|
|
|
last = (FFTdata[i] * 0.1f) + (last * 0.9f);
|
|
|
|
fftBuf[i] = last;
|
|
|
|
}
|
|
|
|
gui::waterfall.pushFFT();
|
2020-06-15 15:53:45 +02:00
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-08-21 15:38:27 +02:00
|
|
|
watcher<uint64_t> freq((uint64_t)90500000);
|
2020-10-15 16:09:01 +02:00
|
|
|
watcher<double> vfoFreq(92000000.0);
|
|
|
|
float fftMin = -70.0;
|
|
|
|
float fftMax = 0.0;
|
|
|
|
watcher<double> offset(0.0, true);
|
2020-11-28 23:24:45 +01:00
|
|
|
float bw = 8000000;
|
2020-08-16 03:39:05 +02:00
|
|
|
bool playing = false;
|
|
|
|
watcher<bool> dcbias(false, false);
|
|
|
|
bool showCredits = false;
|
|
|
|
std::string audioStreamName = "";
|
|
|
|
std::string sourceName = "";
|
2020-08-20 18:29:23 +02:00
|
|
|
int menuWidth = 300;
|
|
|
|
bool grabbingMenu = false;
|
|
|
|
int newWidth = 300;
|
|
|
|
int fftHeight = 300;
|
2020-08-21 15:34:50 +02:00
|
|
|
bool showMenu = true;
|
2020-12-08 04:36:37 +01:00
|
|
|
bool centerTuning = false;
|
2020-10-01 01:21:15 +02:00
|
|
|
dsp::stream<dsp::complex_t> dummyStream;
|
2020-12-10 05:18:40 +01:00
|
|
|
bool demoWindow = false;
|
2020-09-24 19:36:57 +02:00
|
|
|
|
2020-08-16 03:39:05 +02:00
|
|
|
void windowInit() {
|
2020-11-30 21:17:36 +01:00
|
|
|
LoadingScreen::show("Initializing UI");
|
2020-10-22 03:16:11 +02:00
|
|
|
gui::waterfall.init();
|
2020-12-12 05:34:58 +01:00
|
|
|
gui::waterfall.setRawFFTSize(fftSize);
|
|
|
|
|
|
|
|
tempFFT = new float[fftSize];
|
|
|
|
FFTdata = new float[fftSize];
|
2020-09-24 19:36:57 +02:00
|
|
|
|
2020-09-25 14:25:36 +02:00
|
|
|
credits::init();
|
|
|
|
|
2020-10-20 00:32:17 +02:00
|
|
|
core::configManager.aquire();
|
|
|
|
gui::menu.order = core::configManager.conf["menuOrder"].get<std::vector<std::string>>();
|
2020-12-22 22:39:24 +01:00
|
|
|
std::string modulesDir = core::configManager.conf["modulesDirectory"];
|
2020-12-31 14:26:12 +01:00
|
|
|
std::string resourcesDir = core::configManager.conf["resourcesDirectory"];
|
2020-10-20 00:32:17 +02:00
|
|
|
core::configManager.release();
|
|
|
|
|
2020-10-01 01:21:15 +02:00
|
|
|
gui::menu.registerEntry("Source", sourecmenu::draw, NULL);
|
2020-11-29 20:55:00 +01:00
|
|
|
gui::menu.registerEntry("Sinks", sinkmenu::draw, NULL);
|
2020-10-07 14:44:39 +02:00
|
|
|
gui::menu.registerEntry("Scripting", scriptingmenu::draw, NULL);
|
2020-09-25 14:25:36 +02:00
|
|
|
gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL);
|
|
|
|
gui::menu.registerEntry("Display", displaymenu::draw, NULL);
|
2020-09-19 12:48:34 +02:00
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::freqSelect.init();
|
2020-11-28 23:24:45 +01:00
|
|
|
|
|
|
|
// Set default values for waterfall in case no source init's it
|
|
|
|
gui::waterfall.setBandwidth(8000000);
|
|
|
|
gui::waterfall.setViewBandwidth(8000000);
|
2020-06-15 15:53:45 +02:00
|
|
|
|
2020-07-20 15:26:59 +02:00
|
|
|
fft_in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
|
|
|
fft_out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
2020-06-15 15:53:45 +02:00
|
|
|
p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE);
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::signalPath.init(8000000, 20, fftSize, &dummyStream, (dsp::complex_t*)fft_in, fftHandler);
|
2020-09-20 00:19:39 +02:00
|
|
|
sigpath::signalPath.start();
|
2020-08-11 18:33:42 +02:00
|
|
|
|
2020-08-12 16:43:44 +02:00
|
|
|
spdlog::info("Loading modules");
|
2020-12-08 04:36:37 +01:00
|
|
|
|
|
|
|
// Load modules from /module directory
|
2020-12-22 22:39:24 +01:00
|
|
|
if (std::filesystem::is_directory(modulesDir)) {
|
|
|
|
for (const auto & file : std::filesystem::directory_iterator(modulesDir)) {
|
2020-12-08 04:36:37 +01:00
|
|
|
std::string path = file.path().generic_string();
|
|
|
|
if (file.path().extension().generic_string() != SDRPP_MOD_EXTENTSION) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!file.is_regular_file()) { continue; }
|
|
|
|
spdlog::info("Loading {0}", path);
|
|
|
|
LoadingScreen::show("Loading " + path);
|
|
|
|
core::moduleManager.loadModule(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-12-22 22:39:24 +01:00
|
|
|
spdlog::warn("Module directory {0} does not exist, not loading modules from directory", modulesDir);
|
2020-12-08 04:36:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read module config
|
|
|
|
core::configManager.aquire();
|
|
|
|
std::vector<std::string> modules = core::configManager.conf["modules"];
|
|
|
|
std::map<std::string, std::string> modList = core::configManager.conf["moduleInstances"];
|
|
|
|
core::configManager.release();
|
|
|
|
|
|
|
|
// Load additional modules specified through config
|
|
|
|
for (auto const& path : modules) {
|
|
|
|
spdlog::info("Loading {0}", path);
|
|
|
|
LoadingScreen::show("Loading " + path);
|
|
|
|
core::moduleManager.loadModule(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create module instances
|
|
|
|
for (auto const& [name, module] : modList) {
|
|
|
|
spdlog::info("Initializing {0} ({1})", name, module);
|
|
|
|
LoadingScreen::show("Initializing " + name + " (" + module + ")");
|
|
|
|
core::moduleManager.createInstance(name, module);
|
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-12-31 14:26:12 +01:00
|
|
|
// Load color maps
|
|
|
|
LoadingScreen::show("Loading color maps");
|
|
|
|
spdlog::info("Loading color maps");
|
|
|
|
if (std::filesystem::is_directory(resourcesDir + "/colormaps")) {
|
|
|
|
for (const auto & file : std::filesystem::directory_iterator(resourcesDir + "/colormaps")) {
|
|
|
|
std::string path = file.path().generic_string();
|
|
|
|
LoadingScreen::show("Loading " + path);
|
|
|
|
spdlog::info("Loading {0}", path);
|
|
|
|
if (file.path().extension().generic_string() != ".json") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!file.is_regular_file()) { continue; }
|
|
|
|
colormaps::loadMap(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
spdlog::warn("Color map directory {0} does not exist, not loading modules from directory", modulesDir);
|
|
|
|
}
|
|
|
|
|
|
|
|
gui::waterfall.updatePalletteFromArray(colormaps::maps["Turbo"].map, colormaps::maps["Turbo"].entryCount);
|
|
|
|
|
2020-10-01 01:21:15 +02:00
|
|
|
sourecmenu::init();
|
2020-11-29 20:55:00 +01:00
|
|
|
sinkmenu::init();
|
2020-10-07 14:44:39 +02:00
|
|
|
scriptingmenu::init();
|
2020-10-01 01:21:15 +02:00
|
|
|
bandplanmenu::init();
|
|
|
|
displaymenu::init();
|
|
|
|
|
2020-11-30 17:43:53 +01:00
|
|
|
// TODO for 0.2.5
|
2020-12-09 04:47:30 +01:00
|
|
|
// Add "select file" option for the file source
|
|
|
|
// Have a good directory system on both linux and windows
|
|
|
|
// Switch to double buffering (should fix occassional underruns)
|
2020-12-08 16:27:52 +01:00
|
|
|
// Fix gain not updated on startup, soapysdr
|
2020-08-21 17:11:12 +02:00
|
|
|
|
2020-11-30 17:43:53 +01:00
|
|
|
// TODO for 0.2.6
|
2020-12-06 16:13:47 +01:00
|
|
|
// Add a module add/remove/change order menu
|
2020-08-16 03:39:05 +02:00
|
|
|
|
|
|
|
// Update UI settings
|
2020-11-30 21:17:36 +01:00
|
|
|
LoadingScreen::show("Loading configuration");
|
2020-10-20 00:32:17 +02:00
|
|
|
core::configManager.aquire();
|
2020-09-24 19:36:57 +02:00
|
|
|
fftMin = core::configManager.conf["min"];
|
|
|
|
fftMax = core::configManager.conf["max"];
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.setFFTMin(fftMin);
|
|
|
|
gui::waterfall.setWaterfallMin(fftMin);
|
|
|
|
gui::waterfall.setFFTMax(fftMax);
|
|
|
|
gui::waterfall.setWaterfallMax(fftMax);
|
2020-10-01 01:21:15 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
double frequency = core::configManager.conf["frequency"];
|
2020-08-16 03:39:05 +02:00
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::freqSelect.setFrequency(frequency);
|
|
|
|
gui::freqSelect.frequencyChanged = false;
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::sourceManager.tune(frequency);
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.setCenterFrequency(frequency);
|
2020-11-28 23:24:45 +01:00
|
|
|
bw = gui::waterfall.getBandwidth();
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.vfoFreqChanged = false;
|
|
|
|
gui::waterfall.centerFreqMoved = false;
|
|
|
|
gui::waterfall.selectFirstVFO();
|
2020-08-16 03:39:05 +02:00
|
|
|
|
2020-09-24 19:36:57 +02:00
|
|
|
menuWidth = core::configManager.conf["menuWidth"];
|
2020-08-20 18:29:23 +02:00
|
|
|
newWidth = menuWidth;
|
|
|
|
|
2020-09-24 19:36:57 +02:00
|
|
|
fftHeight = core::configManager.conf["fftHeight"];
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.setFFTHeight(fftHeight);
|
2020-09-24 19:36:57 +02:00
|
|
|
|
2020-12-08 04:36:37 +01:00
|
|
|
centerTuning = core::configManager.conf["centerTuning"];
|
|
|
|
|
2020-09-24 19:36:57 +02:00
|
|
|
core::configManager.release();
|
2020-08-16 03:39:05 +02:00
|
|
|
}
|
2020-07-19 18:23:00 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
void setVFO(double freq) {
|
2020-12-08 04:36:37 +01:00
|
|
|
double viewBW = gui::waterfall.getViewBandwidth();
|
|
|
|
double BW = gui::waterfall.getBandwidth();
|
|
|
|
if (gui::waterfall.selectedVFO == "") {
|
|
|
|
gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0));
|
|
|
|
gui::waterfall.setCenterFrequency(freq);
|
|
|
|
sigpath::sourceManager.tune(freq);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
ImGui::WaterfallVFO* vfo = gui::waterfall.vfos[gui::waterfall.selectedVFO];
|
2020-08-10 02:30:25 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
double currentOff = vfo->centerOffset;
|
|
|
|
double currentTune = gui::waterfall.getCenterFrequency() + vfo->generalOffset;
|
|
|
|
double delta = freq - currentTune;
|
2020-07-19 15:59:44 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
double newVFO = currentOff + delta;
|
|
|
|
double vfoBW = vfo->bandwidth;
|
|
|
|
double vfoBottom = newVFO - (vfoBW / 2.0);
|
|
|
|
double vfoTop = newVFO + (vfoBW / 2.0);
|
2020-07-19 15:59:44 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
double view = gui::waterfall.getViewOffset();
|
|
|
|
double viewBottom = view - (viewBW / 2.0);
|
|
|
|
double viewTop = view + (viewBW / 2.0);
|
2020-07-19 15:59:44 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
double wholeFreq = gui::waterfall.getCenterFrequency();
|
|
|
|
double bottom = -(BW / 2.0);
|
|
|
|
double top = (BW / 2.0);
|
2020-07-19 15:59:44 +02:00
|
|
|
|
2020-12-08 04:36:37 +01:00
|
|
|
if (centerTuning) {
|
|
|
|
gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0));
|
|
|
|
gui::waterfall.setCenterFrequency(freq);
|
2020-12-08 16:27:52 +01:00
|
|
|
gui::waterfall.setViewOffset(0);
|
2020-12-10 05:18:40 +01:00
|
|
|
sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, 0);
|
2020-12-08 04:36:37 +01:00
|
|
|
sigpath::sourceManager.tune(freq);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-19 15:59:44 +02:00
|
|
|
// VFO still fints in the view
|
|
|
|
if (vfoBottom > viewBottom && vfoTop < viewTop) {
|
2020-09-20 00:19:39 +02:00
|
|
|
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO);
|
2020-07-19 15:59:44 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// VFO too low for current SDR tuning
|
|
|
|
if (vfoBottom < bottom) {
|
2020-10-15 16:09:01 +02:00
|
|
|
gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0));
|
|
|
|
double newVFOOffset = (BW / 2.0) - (vfoBW / 2.0) - (viewBW / 10.0);
|
2021-02-02 21:49:35 +01:00
|
|
|
sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::sourceManager.tune(freq - newVFOOffset);
|
2020-07-19 15:59:44 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// VFO too high for current SDR tuning
|
|
|
|
if (vfoTop > top) {
|
2020-10-15 16:09:01 +02:00
|
|
|
gui::waterfall.setViewOffset((viewBW / 2.0) - (BW / 2.0));
|
|
|
|
double newVFOOffset = (vfoBW / 2.0) - (BW / 2.0) + (viewBW / 10.0);
|
2021-02-02 21:49:35 +01:00
|
|
|
sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::sourceManager.tune(freq - newVFOOffset);
|
2020-07-19 15:59:44 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// VFO is still without the SDR's bandwidth
|
|
|
|
if (delta < 0) {
|
2020-10-15 16:09:01 +02:00
|
|
|
double newViewOff = vfoTop - (viewBW / 2.0) + (viewBW / 10.0);
|
|
|
|
double newViewBottom = newViewOff - (viewBW / 2.0);
|
|
|
|
double newViewTop = newViewOff + (viewBW / 2.0);
|
2020-07-19 15:59:44 +02:00
|
|
|
|
|
|
|
if (newViewBottom > bottom) {
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.setViewOffset(newViewOff);
|
|
|
|
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO);
|
2020-07-19 15:59:44 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0));
|
|
|
|
double newVFOOffset = (BW / 2.0) - (vfoBW / 2.0) - (viewBW / 10.0);
|
2020-09-20 00:19:39 +02:00
|
|
|
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
|
|
|
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::sourceManager.tune(freq - newVFOOffset);
|
2020-07-19 15:59:44 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-10-15 16:09:01 +02:00
|
|
|
double newViewOff = vfoBottom + (viewBW / 2.0) - (viewBW / 10.0);
|
|
|
|
double newViewBottom = newViewOff - (viewBW / 2.0);
|
|
|
|
double newViewTop = newViewOff + (viewBW / 2.0);
|
2020-07-19 15:59:44 +02:00
|
|
|
|
|
|
|
if (newViewTop < top) {
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.setViewOffset(newViewOff);
|
|
|
|
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO);
|
2020-07-19 15:59:44 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
gui::waterfall.setViewOffset((viewBW / 2.0) - (BW / 2.0));
|
|
|
|
double newVFOOffset = (vfoBW / 2.0) - (BW / 2.0) + (viewBW / 10.0);
|
2020-09-20 00:19:39 +02:00
|
|
|
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
|
|
|
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::sourceManager.tune(freq - newVFOOffset);
|
2020-07-19 15:59:44 +02:00
|
|
|
}
|
|
|
|
}
|
2020-07-11 21:15:10 +02:00
|
|
|
|
2020-06-10 04:13:56 +02:00
|
|
|
void drawWindow() {
|
2020-08-16 03:39:05 +02:00
|
|
|
ImGui::Begin("Main", NULL, WINDOW_FLAGS);
|
2020-08-11 18:33:42 +02:00
|
|
|
|
2020-12-08 04:36:37 +01:00
|
|
|
ImGui::WaterfallVFO* vfo = NULL;
|
|
|
|
if (gui::waterfall.selectedVFO != "") {
|
|
|
|
vfo = gui::waterfall.vfos[gui::waterfall.selectedVFO];
|
2020-08-11 18:33:42 +02:00
|
|
|
}
|
|
|
|
|
2020-12-08 04:36:37 +01:00
|
|
|
if (vfo != NULL) {
|
|
|
|
if (vfo->centerOffsetChanged) {
|
2020-12-08 16:27:52 +01:00
|
|
|
if (centerTuning) {
|
|
|
|
setVFO(gui::waterfall.getCenterFrequency() + vfo->generalOffset);
|
|
|
|
}
|
2020-12-08 04:36:37 +01:00
|
|
|
gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset);
|
|
|
|
gui::freqSelect.frequencyChanged = false;
|
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["frequency"] = gui::freqSelect.frequency;
|
|
|
|
core::configManager.release(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
sigpath::vfoManager.updateFromWaterfall(&gui::waterfall);
|
2020-08-11 18:33:42 +02:00
|
|
|
|
2020-12-08 04:36:37 +01:00
|
|
|
if (gui::waterfall.selectedVFOChanged && vfo != NULL) {
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.selectedVFOChanged = false;
|
|
|
|
gui::freqSelect.setFrequency(vfo->generalOffset + gui::waterfall.getCenterFrequency());
|
|
|
|
gui::freqSelect.frequencyChanged = false;
|
2020-09-24 19:36:57 +02:00
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["frequency"] = gui::freqSelect.frequency;
|
|
|
|
core::configManager.release(true);
|
2020-08-10 02:30:25 +02:00
|
|
|
}
|
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
if (gui::freqSelect.frequencyChanged) {
|
|
|
|
gui::freqSelect.frequencyChanged = false;
|
|
|
|
setVFO(gui::freqSelect.frequency);
|
2020-12-08 04:36:37 +01:00
|
|
|
if (vfo != NULL) {
|
|
|
|
vfo->centerOffsetChanged = false;
|
|
|
|
vfo->lowerOffsetChanged = false;
|
|
|
|
vfo->upperOffsetChanged = false;
|
|
|
|
}
|
2020-09-24 19:36:57 +02:00
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["frequency"] = gui::freqSelect.frequency;
|
|
|
|
core::configManager.release(true);
|
2020-06-10 04:13:56 +02:00
|
|
|
}
|
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
if (gui::waterfall.centerFreqMoved) {
|
|
|
|
gui::waterfall.centerFreqMoved = false;
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::sourceManager.tune(gui::waterfall.getCenterFrequency());
|
2020-12-08 04:36:37 +01:00
|
|
|
if (vfo != NULL) {
|
|
|
|
gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency());
|
|
|
|
}
|
2020-09-24 19:36:57 +02:00
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["frequency"] = gui::freqSelect.frequency;
|
|
|
|
core::configManager.release(true);
|
2020-08-04 21:34:56 +02:00
|
|
|
}
|
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
int _fftHeight = gui::waterfall.getFFTHeight();
|
2020-08-20 18:29:23 +02:00
|
|
|
if (fftHeight != _fftHeight) {
|
|
|
|
fftHeight = _fftHeight;
|
2020-09-24 19:36:57 +02:00
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["fftHeight"] = fftHeight;
|
|
|
|
core::configManager.release(true);
|
2020-08-20 18:29:23 +02:00
|
|
|
}
|
|
|
|
|
2020-06-10 04:13:56 +02:00
|
|
|
ImVec2 vMin = ImGui::GetWindowContentRegionMin();
|
|
|
|
ImVec2 vMax = ImGui::GetWindowContentRegionMax();
|
|
|
|
|
|
|
|
int width = vMax.x - vMin.x;
|
|
|
|
int height = vMax.y - vMin.y;
|
|
|
|
|
2020-07-19 15:59:44 +02:00
|
|
|
// To Bar
|
2020-11-30 16:05:51 +01:00
|
|
|
ImGui::PushID(ImGui::GetID("sdrpp_menu_btn"));
|
|
|
|
if (ImGui::ImageButton(icons::MENU, ImVec2(30, 30), ImVec2(0, 0), ImVec2(1, 1), 5)) {
|
2020-08-21 15:34:50 +02:00
|
|
|
showMenu = !showMenu;
|
|
|
|
}
|
2020-11-30 16:45:02 +01:00
|
|
|
ImGui::PopID();
|
2020-08-21 15:34:50 +02:00
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
2020-07-19 15:59:44 +02:00
|
|
|
if (playing) {
|
2020-11-30 16:05:51 +01:00
|
|
|
ImGui::PushID(ImGui::GetID("sdrpp_stop_btn"));
|
|
|
|
if (ImGui::ImageButton(icons::STOP, ImVec2(30, 30), ImVec2(0, 0), ImVec2(1, 1), 5)) {
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::sourceManager.stop();
|
2020-07-19 15:59:44 +02:00
|
|
|
playing = false;
|
|
|
|
}
|
2020-11-30 16:45:02 +01:00
|
|
|
ImGui::PopID();
|
2020-07-19 15:59:44 +02:00
|
|
|
}
|
2020-10-01 01:21:15 +02:00
|
|
|
else { // TODO: Might need to check if there even is a device
|
2020-11-30 16:05:51 +01:00
|
|
|
ImGui::PushID(ImGui::GetID("sdrpp_play_btn"));
|
|
|
|
if (ImGui::ImageButton(icons::PLAY, ImVec2(30, 30), ImVec2(0, 0), ImVec2(1, 1), 5)) {
|
2020-10-01 01:21:15 +02:00
|
|
|
sigpath::sourceManager.start();
|
|
|
|
// TODO: tune in module instead
|
|
|
|
sigpath::sourceManager.tune(gui::waterfall.getCenterFrequency());
|
2020-07-19 15:59:44 +02:00
|
|
|
playing = true;
|
|
|
|
}
|
2020-11-30 16:45:02 +01:00
|
|
|
ImGui::PopID();
|
2020-07-19 15:59:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
2020-11-30 16:05:51 +01:00
|
|
|
//ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8);
|
2020-12-08 16:27:52 +01:00
|
|
|
sigpath::sinkManager.showVolumeSlider(gui::waterfall.selectedVFO, "##_sdrpp_main_volume_", 248, 30, 5, true);
|
2020-07-19 15:59:44 +02:00
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::freqSelect.draw();
|
2020-07-19 15:59:44 +02:00
|
|
|
|
2021-01-28 21:10:08 +01:00
|
|
|
ImGui::SameLine();
|
2020-12-08 16:27:52 +01:00
|
|
|
|
|
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 9);
|
|
|
|
if (centerTuning) {
|
|
|
|
ImGui::PushID(ImGui::GetID("sdrpp_ena_st_btn"));
|
|
|
|
if (ImGui::ImageButton(icons::CENTER_TUNING, ImVec2(30, 30), ImVec2(0, 0), ImVec2(1, 1), 5)) {
|
|
|
|
centerTuning = false;
|
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["centerTuning"] = centerTuning;
|
|
|
|
core::configManager.release(true);
|
|
|
|
}
|
|
|
|
ImGui::PopID();
|
|
|
|
}
|
|
|
|
else { // TODO: Might need to check if there even is a device
|
|
|
|
ImGui::PushID(ImGui::GetID("sdrpp_dis_st_btn"));
|
|
|
|
if (ImGui::ImageButton(icons::NORMAL_TUNING, ImVec2(30, 30), ImVec2(0, 0), ImVec2(1, 1), 5)) {
|
|
|
|
centerTuning = true;
|
|
|
|
setVFO(gui::freqSelect.frequency);
|
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["centerTuning"] = centerTuning;
|
|
|
|
core::configManager.release(true);
|
|
|
|
}
|
|
|
|
ImGui::PopID();
|
|
|
|
}
|
|
|
|
|
2020-08-16 03:39:05 +02:00
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
// Logo button
|
|
|
|
ImGui::SetCursorPosX(ImGui::GetWindowSize().x - 48);
|
|
|
|
ImGui::SetCursorPosY(10);
|
|
|
|
if (ImGui::ImageButton(icons::LOGO, ImVec2(32, 32), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
|
|
|
showCredits = true;
|
|
|
|
}
|
|
|
|
if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
|
|
|
|
showCredits = false;
|
|
|
|
}
|
|
|
|
if (ImGui::IsKeyPressed(GLFW_KEY_ESCAPE)) {
|
|
|
|
showCredits = false;
|
|
|
|
}
|
|
|
|
|
2020-08-20 18:29:23 +02:00
|
|
|
// Handle menu resize
|
|
|
|
float curY = ImGui::GetCursorPosY();
|
2020-07-19 15:59:44 +02:00
|
|
|
ImVec2 winSize = ImGui::GetWindowSize();
|
2020-08-20 18:29:23 +02:00
|
|
|
ImVec2 mousePos = ImGui::GetMousePos();
|
|
|
|
bool click = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
|
|
|
|
bool down = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
|
|
|
if (grabbingMenu) {
|
|
|
|
newWidth = mousePos.x;
|
|
|
|
newWidth = std::clamp<float>(newWidth, 250, winSize.x - 250);
|
|
|
|
ImGui::GetForegroundDrawList()->AddLine(ImVec2(newWidth, curY), ImVec2(newWidth, winSize.y - 10), ImGui::GetColorU32(ImGuiCol_SeparatorActive));
|
|
|
|
}
|
|
|
|
if (mousePos.x >= newWidth - 2 && mousePos.x <= newWidth + 2 && mousePos.y > curY) {
|
|
|
|
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
|
|
|
|
if (click) {
|
|
|
|
grabbingMenu = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ImGui::SetMouseCursor(ImGuiMouseCursor_Arrow);
|
|
|
|
}
|
|
|
|
if(!down && grabbingMenu) {
|
|
|
|
grabbingMenu = false;
|
|
|
|
menuWidth = newWidth;
|
2020-09-24 19:36:57 +02:00
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["menuWidth"] = menuWidth;
|
|
|
|
core::configManager.release(true);
|
2020-08-20 18:29:23 +02:00
|
|
|
}
|
|
|
|
|
2020-06-10 04:13:56 +02:00
|
|
|
// Left Column
|
2020-08-16 03:39:05 +02:00
|
|
|
|
2020-08-21 15:34:50 +02:00
|
|
|
if (showMenu) {
|
|
|
|
ImGui::Columns(3, "WindowColumns", false);
|
|
|
|
ImGui::SetColumnWidth(0, menuWidth);
|
|
|
|
ImGui::SetColumnWidth(1, winSize.x - menuWidth - 60);
|
|
|
|
ImGui::SetColumnWidth(2, 60);
|
|
|
|
ImGui::BeginChild("Left Column");
|
|
|
|
float menuColumnWidth = ImGui::GetContentRegionAvailWidth();
|
2020-08-16 03:39:05 +02:00
|
|
|
|
2020-09-24 19:36:57 +02:00
|
|
|
gui::menu.draw();
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-08-21 15:34:50 +02:00
|
|
|
if(ImGui::CollapsingHeader("Debug")) {
|
2020-10-15 16:09:01 +02:00
|
|
|
ImGui::Text("Frame time: %.3f ms/frame", 1000.0 / ImGui::GetIO().Framerate);
|
2020-08-21 15:34:50 +02:00
|
|
|
ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate);
|
2020-10-22 02:47:10 +02:00
|
|
|
ImGui::Text("Center Frequency: %.0f Hz", gui::waterfall.getCenterFrequency());
|
2020-08-21 17:11:12 +02:00
|
|
|
ImGui::Text("Source name: %s", sourceName.c_str());
|
2020-10-20 00:32:17 +02:00
|
|
|
if (ImGui::Checkbox("Test technique", &dcbias.val)) {
|
2020-11-02 03:57:44 +01:00
|
|
|
//sigpath::signalPath.setDCBiasCorrection(dcbias.val);
|
2020-10-20 00:32:17 +02:00
|
|
|
}
|
2020-12-10 05:18:40 +01:00
|
|
|
ImGui::Checkbox("Show demo window", &demoWindow);
|
2020-08-21 15:34:50 +02:00
|
|
|
ImGui::Spacing();
|
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-08-21 15:34:50 +02:00
|
|
|
ImGui::EndChild();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// When hiding the menu bar
|
|
|
|
ImGui::Columns(3, "WindowColumns", false);
|
|
|
|
ImGui::SetColumnWidth(0, 8);
|
|
|
|
ImGui::SetColumnWidth(1, winSize.x - 8 - 60);
|
|
|
|
ImGui::SetColumnWidth(2, 60);
|
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
|
|
|
|
// Right Column
|
2020-08-16 03:39:05 +02:00
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
2020-06-10 04:13:56 +02:00
|
|
|
ImGui::NextColumn();
|
2020-08-17 02:39:56 +02:00
|
|
|
ImGui::PopStyleVar();
|
|
|
|
|
2020-06-10 04:13:56 +02:00
|
|
|
ImGui::BeginChild("Waterfall");
|
2020-08-16 03:39:05 +02:00
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.draw();
|
2020-08-16 03:39:05 +02:00
|
|
|
|
2020-06-10 04:13:56 +02:00
|
|
|
ImGui::EndChild();
|
2020-07-19 15:59:44 +02:00
|
|
|
|
2020-08-20 18:29:23 +02:00
|
|
|
|
2020-07-19 15:59:44 +02:00
|
|
|
ImGui::NextColumn();
|
2020-08-16 03:39:05 +02:00
|
|
|
ImGui::BeginChild("WaterfallControls");
|
2020-07-19 15:59:44 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Zoom").x / 2.0));
|
2020-07-19 15:59:44 +02:00
|
|
|
ImGui::Text("Zoom");
|
2020-10-15 16:09:01 +02:00
|
|
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10);
|
2020-11-28 23:24:45 +01:00
|
|
|
if (ImGui::VSliderFloat("##_7_", ImVec2(20.0, 150.0), &bw, gui::waterfall.getBandwidth(), 1000.0, "")) {
|
|
|
|
gui::waterfall.setViewBandwidth(bw);
|
2020-12-08 04:36:37 +01:00
|
|
|
if (vfo != NULL) {
|
|
|
|
gui::waterfall.setViewOffset(vfo->centerOffset); // center vfo on screen
|
|
|
|
}
|
2020-11-28 23:24:45 +01:00
|
|
|
}
|
2020-07-19 15:59:44 +02:00
|
|
|
|
|
|
|
ImGui::NewLine();
|
2020-07-19 18:09:59 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Max").x / 2.0));
|
2020-07-19 18:09:59 +02:00
|
|
|
ImGui::Text("Max");
|
2020-10-15 16:09:01 +02:00
|
|
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10);
|
|
|
|
if (ImGui::VSliderFloat("##_8_", ImVec2(20.0, 150.0), &fftMax, 0.0, -100.0, "")) {
|
2020-08-17 02:39:56 +02:00
|
|
|
fftMax = std::max<float>(fftMax, fftMin + 10);
|
2020-09-24 19:36:57 +02:00
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["max"] = fftMax;
|
|
|
|
core::configManager.release(true);
|
2020-08-16 03:39:05 +02:00
|
|
|
}
|
2020-07-19 15:59:44 +02:00
|
|
|
|
|
|
|
ImGui::NewLine();
|
2020-07-19 18:09:59 +02:00
|
|
|
|
2020-10-15 16:09:01 +02:00
|
|
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Min").x / 2.0));
|
2020-07-19 18:09:59 +02:00
|
|
|
ImGui::Text("Min");
|
2020-10-15 16:09:01 +02:00
|
|
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10);
|
|
|
|
if (ImGui::VSliderFloat("##_9_", ImVec2(20.0, 150.0), &fftMin, 0.0, -100.0, "")) {
|
2020-08-17 02:39:56 +02:00
|
|
|
fftMin = std::min<float>(fftMax - 10, fftMin);
|
2020-09-24 19:36:57 +02:00
|
|
|
core::configManager.aquire();
|
|
|
|
core::configManager.conf["min"] = fftMin;
|
|
|
|
core::configManager.release(true);
|
2020-08-16 03:39:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndChild();
|
2020-07-19 15:59:44 +02:00
|
|
|
|
2020-09-20 00:19:39 +02:00
|
|
|
gui::waterfall.setFFTMin(fftMin);
|
|
|
|
gui::waterfall.setFFTMax(fftMax);
|
|
|
|
gui::waterfall.setWaterfallMin(fftMin);
|
|
|
|
gui::waterfall.setWaterfallMax(fftMax);
|
2020-08-16 03:39:05 +02:00
|
|
|
|
|
|
|
ImGui::End();
|
|
|
|
|
|
|
|
if (showCredits) {
|
2020-09-25 14:25:36 +02:00
|
|
|
credits::show();
|
2020-08-16 03:39:05 +02:00
|
|
|
}
|
2020-12-10 05:18:40 +01:00
|
|
|
|
|
|
|
if (demoWindow) {
|
|
|
|
ImGui::ShowDemoWindow();
|
|
|
|
}
|
2020-11-28 23:24:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void setViewBandwidthSlider(float bandwidth) {
|
|
|
|
bw = bandwidth;
|
2020-12-23 19:23:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool sdrIsRunning() {
|
|
|
|
return playing;
|
2020-06-10 04:13:56 +02:00
|
|
|
}
|