From 48a8b04eaa70286e0e7c717c0e9b9eea19772e76 Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Thu, 24 Sep 2020 19:36:57 +0200 Subject: [PATCH] More fixes --- core/src/config.cpp | 117 ++++++----- core/src/config.h | 42 +++- core/src/core.cpp | 47 ++--- core/src/core.h | 6 + core/src/gui/frequency_select.cpp | 2 +- core/src/gui/gui.cpp | 1 + core/src/gui/gui.h | 2 + core/src/gui/icons.cpp | 8 +- core/src/gui/icons.h | 2 +- core/src/gui/main_window.cpp | 337 ++++++++++++++++-------------- core/src/gui/main_window.h | 1 + core/src/gui/menu.cpp | 19 +- core/src/gui/menu.h | 3 + core/src/gui/style.cpp | 4 +- radio/src/main.cpp | 8 + root_dev/config.json | 16 +- root_dev/module_list.json | 4 +- root_dev/radio_config.json | 5 + 18 files changed, 372 insertions(+), 252 deletions(-) create mode 100644 root_dev/radio_config.json diff --git a/core/src/config.cpp b/core/src/config.cpp index 6dccaa2b..ae03cac1 100644 --- a/core/src/config.cpp +++ b/core/src/config.cpp @@ -1,62 +1,73 @@ #include -namespace config { - bool configModified = false; - json config; - bool autoSaveRunning = false; - std::string _path; - std::thread _workerThread; - std::string rootDir; +ConfigManager::ConfigManager() { - void _autoSaveWorker() { - while (autoSaveRunning) { - if (configModified) { - configModified = false; - std::ofstream file(_path.c_str()); - file << std::setw(4) << config; - file.close(); - spdlog::info("Config saved"); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - } +} + +void ConfigManager::setPath(std::string file) { + path = file; +} + +void ConfigManager::load(json default, bool lock) { + if (lock) { mtx.lock(); } + if (path == "") { + spdlog::error("Config manager tried to load file with no path specified"); + return; + } + if (!std::filesystem::exists(path)) { + spdlog::warn("Config file '{0}' does not exist, creating it", path); + conf = default; + save(false); + } + if (!std::filesystem::is_regular_file(path)) { + spdlog::error("Config file '{0}' isn't a file", path); + return; } - void load(std::string path) { - if (!std::filesystem::exists(path)) { - spdlog::error("Config file does not exist"); - return; - } - if (!std::filesystem::is_regular_file(path)) { - spdlog::error("Config file isn't a file..."); - return; - } - _path = path; - std::ifstream file(path.c_str()); - file >> config; - file.close(); - } + std::ifstream file(path.c_str()); + file >> conf; + file.close(); + if (lock) { mtx.unlock(); } +} - void startAutoSave() { - if (autoSaveRunning) { - return; +void ConfigManager::save(bool lock) { + if (lock) { mtx.lock(); } + std::ofstream file(path.c_str()); + file << conf.dump(4); + file.close(); + if (lock) { mtx.unlock(); } +} + +void ConfigManager::enableAutoSave() { + autoSaveEnabled = true; + autoSaveThread = std::thread(autoSaveWorker, this); +} + +void ConfigManager::disableAutoSave() { + autoSaveEnabled = false; + autoSaveThread.join(); +} + +void ConfigManager::aquire() { + mtx.lock(); +} + +void ConfigManager::release(bool changed) { + this->changed |= changed; + mtx.unlock(); +} + +void ConfigManager::autoSaveWorker(ConfigManager* _this) { + while (_this->autoSaveEnabled) { + if (!_this->mtx.try_lock()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + continue; } - autoSaveRunning = true; - _workerThread = std::thread(_autoSaveWorker); - } - - void stopAutoSave() { - if (!autoSaveRunning) { - return; + if (_this->changed) { + _this->changed = false; + _this->save(false); } - autoSaveRunning = false; - _workerThread.join(); + _this->mtx.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } - - void setRootDirectory(std::string dir) { - rootDir = dir; - } - - std::string getRootDirectory() { - return rootDir; - } -}; \ No newline at end of file +} diff --git a/core/src/config.h b/core/src/config.h index da6b0ee0..14feeb8b 100644 --- a/core/src/config.h +++ b/core/src/config.h @@ -7,16 +7,42 @@ #include #include #include +#include using nlohmann::json; -namespace config { - void load(std::string path); - void startAutoSave(); - void stopAutoSave(); - void setRootDirectory(std::string dir); - std::string getRootDirectory(); +//#define DEV_BUILD + +#ifndef ROOT_DIR +#ifdef DEV_BUILD +#define ROOT_DIR "../root_dev" +#elif _WIN32 +#define ROOT_DIR "." +#else +#define ROOT_DIR "/etc/sdrpp" +#endif +#endif + +class ConfigManager { +public: + ConfigManager(); + void setPath(std::string file); + void load(json default, bool lock = true); + void save(bool lock = true); + void enableAutoSave(); + void disableAutoSave(); + void aquire(); + void release(bool changed = false); + + json conf; + +private: + static void autoSaveWorker(ConfigManager* _this); + + std::string path = ""; + bool changed = false; + bool autoSaveEnabled = false; + std::thread autoSaveThread; + std::mutex mtx; - extern bool configModified; - extern json config; }; \ No newline at end of file diff --git a/core/src/core.cpp b/core/src/core.cpp index d77835a8..fe20dcb5 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -23,8 +24,9 @@ #include #endif -// Comment to build a normal release -#define DEV_BUILD +namespace core { + ConfigManager configManager; +}; bool maximized = false; bool fullScreen = false; @@ -50,18 +52,11 @@ int sdrpp_main() { spdlog::info("SDR++ v" VERSION_STR); -#ifdef DEV_BUILD - config::setRootDirectory("../root_dev"); -#elif _WIN32 - config::setRootDirectory("."); -#else - config::setRootDirectory("/etc/sdrpp"); -#endif - // Load config spdlog::info("Loading config"); - config::load(config::getRootDirectory() + "/config.json"); - config::startAutoSave(); + core::configManager.setPath(ROOT_DIR "/config.json"); + core::configManager.load(json()); + core::configManager.enableAutoSave(); // Setup window glfwSetErrorCallback(glfw_error_callback); @@ -74,9 +69,11 @@ int sdrpp_main() { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac - int winWidth = config::config["windowSize"]["w"]; - int winHeight = config::config["windowSize"]["h"]; - maximized = config::config["maximized"]; + core::configManager.aquire(); + int winWidth = core::configManager.conf["windowSize"]["w"]; + int winHeight = core::configManager.conf["windowSize"]["h"]; + maximized = core::configManager.conf["maximized"]; + core::configManager.release(); // Create window with graphics context GLFWmonitor* monitor = glfwGetPrimaryMonitor(); @@ -94,7 +91,7 @@ int sdrpp_main() { // Load app icon GLFWimage icons[10]; - icons[0].pixels = stbi_load((config::getRootDirectory() + "/res/icons/sdrpp.png").c_str(), &icons[0].width, &icons[0].height, 0, 4); + icons[0].pixels = stbi_load(((std::string)(ROOT_DIR "/res/icons/sdrpp.png")).c_str(), &icons[0].width, &icons[0].height, 0, 4); icons[1].pixels = (unsigned char*)malloc(16 * 16 * 4); icons[1].width = icons[1].height = 16; icons[2].pixels = (unsigned char*)malloc(24 * 24 * 4); icons[2].width = icons[2].height = 24; icons[3].pixels = (unsigned char*)malloc(32 * 32 * 4); icons[3].width = icons[3].height = 32; @@ -162,10 +159,10 @@ int sdrpp_main() { icons::load(); spdlog::info("Loading band plans"); - bandplan::loadFromDir(config::getRootDirectory() + "/bandplans"); + bandplan::loadFromDir(ROOT_DIR "/bandplans"); spdlog::info("Loading band plans color table"); - bandplan::loadColorTable(config::getRootDirectory() + "/band_colors.json"); + bandplan::loadColorTable(ROOT_DIR "/band_colors.json"); windowInit(); @@ -185,11 +182,12 @@ int sdrpp_main() { if (_maximized != maximized) { _maximized = maximized; - config::config["maximized"]= _maximized; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["maximized"]= _maximized; if (!maximized) { - glfwSetWindowSize(window, config::config["windowSize"]["w"], config::config["windowSize"]["h"]); + glfwSetWindowSize(window, core::configManager.conf["windowSize"]["w"], core::configManager.conf["windowSize"]["h"]); } + core::configManager.release(true); } int _winWidth, _winHeight; @@ -214,9 +212,10 @@ int sdrpp_main() { if ((_winWidth != winWidth || _winHeight != winHeight) && !maximized && _winWidth > 0 && _winHeight > 0) { winWidth = _winWidth; winHeight = _winHeight; - config::config["windowSize"]["w"] = winWidth; - config::config["windowSize"]["h"] = winHeight; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["windowSize"]["w"] = winWidth; + core::configManager.conf["windowSize"]["h"] = winHeight; + core::configManager.release(true); } if (winWidth > 0 && winHeight > 0) { diff --git a/core/src/core.h b/core/src/core.h index ce5ea1fd..14983520 100644 --- a/core/src/core.h +++ b/core/src/core.h @@ -1,3 +1,9 @@ #pragma once +#include +#include + +namespace core { + SDRPP_EXPORT ConfigManager configManager; +}; int sdrpp_main(); \ No newline at end of file diff --git a/core/src/gui/frequency_select.cpp b/core/src/gui/frequency_select.cpp index b40aabad..711b8f09 100644 --- a/core/src/gui/frequency_select.cpp +++ b/core/src/gui/frequency_select.cpp @@ -9,7 +9,7 @@ FrequencySelect::FrequencySelect() { } void FrequencySelect::init() { - font = ImGui::GetIO().Fonts->AddFontFromFileTTF((config::getRootDirectory() + "/res/fonts/Roboto-Medium.ttf").c_str(), 42.0f); + font = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 42.0f); for (int i = 0; i < 12; i++) { digits[i] = 0; diff --git a/core/src/gui/gui.cpp b/core/src/gui/gui.cpp index 59c8b375..57c09e29 100644 --- a/core/src/gui/gui.cpp +++ b/core/src/gui/gui.cpp @@ -3,4 +3,5 @@ namespace gui { ImGui::WaterFall waterfall; FrequencySelect freqSelect; + Menu menu; }; \ No newline at end of file diff --git a/core/src/gui/gui.h b/core/src/gui/gui.h index c65833c2..32d48b37 100644 --- a/core/src/gui/gui.h +++ b/core/src/gui/gui.h @@ -1,9 +1,11 @@ #pragma once #include #include +#include #include namespace gui { SDRPP_EXPORT ImGui::WaterFall waterfall; SDRPP_EXPORT FrequencySelect freqSelect; + SDRPP_EXPORT Menu menu; }; \ No newline at end of file diff --git a/core/src/gui/icons.cpp b/core/src/gui/icons.cpp index e12810e9..b6af76d3 100644 --- a/core/src/gui/icons.cpp +++ b/core/src/gui/icons.cpp @@ -24,9 +24,9 @@ namespace icons { } void load() { - LOGO = (ImTextureID)(uintptr_t)loadTexture(config::getRootDirectory() + "/res/icons/sdrpp.png"); - PLAY = (ImTextureID)(uintptr_t)loadTexture(config::getRootDirectory() + "/res/icons/play.png"); - STOP = (ImTextureID)(uintptr_t)loadTexture(config::getRootDirectory() + "/res/icons/stop.png"); - MENU = (ImTextureID)(uintptr_t)loadTexture(config::getRootDirectory() + "/res/icons/menu.png"); + LOGO = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/sdrpp.png"); + PLAY = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/play.png"); + STOP = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/stop.png"); + MENU = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/menu.png"); } } \ No newline at end of file diff --git a/core/src/gui/icons.h b/core/src/gui/icons.h index 7595682a..f932c4d0 100644 --- a/core/src/gui/icons.h +++ b/core/src/gui/icons.h @@ -10,6 +10,6 @@ namespace icons { extern ImTextureID STOP; extern ImTextureID MENU; - GLuint loadTexture(char* path); + GLuint loadTexture(std::string path); void load(); } \ No newline at end of file diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index b47a6034..4dd8437c 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -64,14 +64,14 @@ bool showMenu = true; void saveCurrentSource() { int i = 0; for (std::string gainName : soapy.gainList) { - config::config["sourceSettings"][sourceName]["gains"][gainName] = uiGains[i]; + core::configManager.conf["sourceSettings"][sourceName]["gains"][gainName] = uiGains[i]; i++; } - config::config["sourceSettings"][sourceName]["sampleRate"] = soapy.sampleRates[srId]; + core::configManager.conf["sourceSettings"][sourceName]["sampleRate"] = soapy.sampleRates[srId]; } void loadSourceConfig(std::string name) { - json sourceSettings = config::config["sourceSettings"][name]; + json sourceSettings = core::configManager.conf["sourceSettings"][name]; sampleRate = sourceSettings["sampleRate"]; @@ -110,7 +110,7 @@ void loadSourceConfig(std::string name) { } void loadAudioConfig(std::string name) { - json audioSettings = config::config["audio"][name]; + json audioSettings = core::configManager.conf["audio"][name]; std::string devName = audioSettings["device"]; auto _devIt = std::find(audio::streams[name]->audio->deviceNames.begin(), audio::streams[name]->audio->deviceNames.end(), devName); @@ -146,14 +146,125 @@ void loadAudioConfig(std::string name) { } void saveAudioConfig(std::string name) { - config::config["audio"][name]["device"] = audio::streams[name]->audio->deviceNames[audio::streams[name]->deviceId]; - config::config["audio"][name]["volume"] = audio::streams[name]->volume; - config::config["audio"][name]["sampleRate"] = audio::streams[name]->sampleRate; + core::configManager.conf["audio"][name]["device"] = audio::streams[name]->audio->deviceNames[audio::streams[name]->deviceId]; + core::configManager.conf["audio"][name]["volume"] = audio::streams[name]->volume; + core::configManager.conf["audio"][name]["sampleRate"] = audio::streams[name]->sampleRate; } +void setVFO(float freq); + +// ======================================================= + +void sourceMenu(void* ctx) { + float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); + if (playing) { style::beginDisabled(); }; + + ImGui::PushItemWidth(menuColumnWidth); + if (ImGui::Combo("##_0_", &devId, soapy.txtDevList.c_str())) { + spdlog::info("Changed input device: {0}", devId); + sourceName = soapy.devNameList[devId]; + soapy.setDevice(soapy.devList[devId]); + + core::configManager.aquire(); + if (core::configManager.conf["sourceSettings"].contains(sourceName)) { + loadSourceConfig(sourceName); + } + else { + srId = 0; + sampleRate = soapy.getSampleRate(); + bw.val = sampleRate; + gui::waterfall.setBandwidth(sampleRate); + gui::waterfall.setViewBandwidth(sampleRate); + sigpath::signalPath.setSampleRate(sampleRate); + + if (soapy.gainList.size() >= 0) { + delete[] uiGains; + uiGains = new float[soapy.gainList.size()]; + for (int i = 0; i < soapy.gainList.size(); i++) { + uiGains[i] = soapy.currentGains[i]; + } + } + } + setVFO(gui::freqSelect.frequency); + core::configManager.conf["source"] = sourceName; + core::configManager.release(true); + } + ImGui::PopItemWidth(); + + if (ImGui::Combo("##_1_", &srId, soapy.txtSampleRateList.c_str())) { + spdlog::info("Changed sample rate: {0}", srId); + sampleRate = soapy.sampleRates[srId]; + soapy.setSampleRate(sampleRate); + gui::waterfall.setBandwidth(sampleRate); + gui::waterfall.setViewBandwidth(sampleRate); + sigpath::signalPath.setSampleRate(sampleRate); + bw.val = sampleRate; + + core::configManager.aquire(); + if (!core::configManager.conf["sourceSettings"].contains(sourceName)) { + saveCurrentSource(); + } + core::configManager.conf["sourceSettings"][sourceName]["sampleRate"] = sampleRate; + core::configManager.release(true); + } + + ImGui::SameLine(); + bool noDevice = (soapy.devList.size() == 0); + if (ImGui::Button("Refresh", ImVec2(menuColumnWidth - ImGui::GetCursorPosX(), 0.0f))) { + soapy.refresh(); + if (noDevice && soapy.devList.size() > 0) { + sourceName = soapy.devNameList[0]; + soapy.setDevice(soapy.devList[0]); + if (core::configManager.conf["sourceSettings"][sourceName]) { + loadSourceConfig(sourceName); + } + } + } + + if (playing) { style::endDisabled(); }; + + float maxTextLength = 0; + float txtLen = 0; + char buf[100]; + + // Calculate the spacing + for (int i = 0; i < soapy.gainList.size(); i++) { + sprintf(buf, "%s gain", soapy.gainList[i].c_str()); + txtLen = ImGui::CalcTextSize(buf).x; + if (txtLen > maxTextLength) { + maxTextLength = txtLen; + } + } + + for (int i = 0; i < soapy.gainList.size(); i++) { + ImGui::Text("%s gain", soapy.gainList[i].c_str()); + ImGui::SameLine(); + sprintf(buf, "##_gain_slide_%d_", i); + + ImGui::SetCursorPosX(maxTextLength + 5); + ImGui::PushItemWidth(menuColumnWidth - (maxTextLength + 5)); + if (ImGui::SliderFloat(buf, &uiGains[i], soapy.gainRanges[i].minimum(), soapy.gainRanges[i].maximum())) { + soapy.setGain(i, uiGains[i]); + core::configManager.aquire(); + if (!core::configManager.conf["sourceSettings"].contains(sourceName)) { + saveCurrentSource(); + } + core::configManager.conf["sourceSettings"][sourceName]["gains"][soapy.gainList[i]] = uiGains[i]; + core::configManager.release(true); + } + ImGui::PopItemWidth(); + } + + ImGui::Spacing(); +} + +// ======================================================= + void windowInit() { spdlog::info("Initializing SoapySDR"); soapy.init(); + + gui::menu.registerEntry("Source", sourceMenu, NULL); gui::freqSelect.init(); @@ -168,16 +279,17 @@ void windowInit() { spdlog::info("Loading modules"); mod::initAPI(&gui::waterfall); - mod::loadFromList(config::getRootDirectory() + "/module_list.json"); + mod::loadFromList(ROOT_DIR "/module_list.json"); - bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF((config::getRootDirectory() + "/res/fonts/Roboto-Medium.ttf").c_str(), 128.0f); + bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 128.0f); // Load last source configuration - uint64_t frequency = config::config["frequency"]; - sourceName = config::config["source"]; + core::configManager.aquire(); + uint64_t frequency = core::configManager.conf["frequency"]; + sourceName = core::configManager.conf["source"]; auto _sourceIt = std::find(soapy.devNameList.begin(), soapy.devNameList.end(), sourceName); - if (_sourceIt != soapy.devNameList.end() && config::config["sourceSettings"].contains(sourceName)) { - json sourceSettings = config::config["sourceSettings"][sourceName]; + if (_sourceIt != soapy.devNameList.end() && core::configManager.conf["sourceSettings"].contains(sourceName)) { + json sourceSettings = core::configManager.conf["sourceSettings"][sourceName]; devId = std::distance(soapy.devNameList.begin(), _sourceIt); soapy.setDevice(soapy.devList[devId]); loadSourceConfig(sourceName); @@ -186,7 +298,7 @@ void windowInit() { int i = 0; bool settingsFound = false; for (std::string devName : soapy.devNameList) { - if (config::config["sourceSettings"].contains(devName)) { + if (core::configManager.conf["sourceSettings"].contains(devName)) { sourceName = devName; settingsFound = true; devId = i; @@ -222,17 +334,17 @@ void windowInit() { // Switch to double for all frequecies and bandwidth // Update UI settings - fftMin = config::config["min"]; - fftMax = config::config["max"]; + fftMin = core::configManager.conf["min"]; + fftMax = core::configManager.conf["max"]; gui::waterfall.setFFTMin(fftMin); gui::waterfall.setWaterfallMin(fftMin); gui::waterfall.setFFTMax(fftMax); gui::waterfall.setWaterfallMax(fftMax); - bandPlanEnabled.val = config::config["bandPlanEnabled"]; + bandPlanEnabled.val = core::configManager.conf["bandPlanEnabled"]; bandPlanEnabled.markAsChanged(); - std::string bandPlanName = config::config["bandPlan"]; + std::string bandPlanName = core::configManager.conf["bandPlan"]; auto _bandplanIt = bandplan::bandplans.find(bandPlanName); if (_bandplanIt != bandplan::bandplans.end()) { bandplanId.val = std::distance(bandplan::bandplans.begin(), bandplan::bandplans.find(bandPlanName)); @@ -262,7 +374,7 @@ void windowInit() { gui::waterfall.selectFirstVFO(); for (auto [name, stream] : audio::streams) { - if (config::config["audio"].contains(name)) { + if (core::configManager.conf["audio"].contains(name)) { bool running = audio::streams[name]->running; audio::stopStream(name); loadAudioConfig(name); @@ -277,16 +389,18 @@ void windowInit() { volume = &audio::streams[audioStreamName]->volume; } - menuWidth = config::config["menuWidth"]; + menuWidth = core::configManager.conf["menuWidth"]; newWidth = menuWidth; - showWaterfall = config::config["showWaterfall"]; + showWaterfall = core::configManager.conf["showWaterfall"]; if (!showWaterfall) { gui::waterfall.hideWaterfall(); } - fftHeight = config::config["fftHeight"]; + fftHeight = core::configManager.conf["fftHeight"]; gui::waterfall.setFFTHeight(fftHeight); + + core::configManager.release(); } void setVFO(float freq) { @@ -382,8 +496,9 @@ void drawWindow() { if (vfo->centerOffsetChanged) { gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset); gui::freqSelect.frequencyChanged = false; - config::config["frequency"] = gui::freqSelect.frequency; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["frequency"] = gui::freqSelect.frequency; + core::configManager.release(true); } sigpath::vfoManager.updateFromWaterfall(&gui::waterfall); @@ -397,8 +512,9 @@ void drawWindow() { if (audioStreamName != "") { volume = &audio::streams[audioStreamName]->volume; } - config::config["frequency"] = gui::freqSelect.frequency; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["frequency"] = gui::freqSelect.frequency; + core::configManager.release(true); } if (gui::freqSelect.frequencyChanged) { @@ -407,16 +523,18 @@ void drawWindow() { vfo->centerOffsetChanged = false; vfo->lowerOffsetChanged = false; vfo->upperOffsetChanged = false; - config::config["frequency"] = gui::freqSelect.frequency; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["frequency"] = gui::freqSelect.frequency; + core::configManager.release(true); } if (gui::waterfall.centerFreqMoved) { gui::waterfall.centerFreqMoved = false; soapy.setFrequency(gui::waterfall.getCenterFrequency()); gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset); - config::config["frequency"] = gui::freqSelect.frequency; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["frequency"] = gui::freqSelect.frequency; + core::configManager.release(true); } if (dcbias.changed()) { @@ -434,8 +552,9 @@ void drawWindow() { int _fftHeight = gui::waterfall.getFFTHeight(); if (fftHeight != _fftHeight) { fftHeight = _fftHeight; - config::config["fftHeight"] = fftHeight; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["fftHeight"] = fftHeight; + core::configManager.release(true); } ImVec2 vMin = ImGui::GetWindowContentRegionMin(); @@ -478,12 +597,13 @@ void drawWindow() { ImGui::SetNextItemWidth(200); if (ImGui::SliderFloat("##_2_", volume, 0.0f, 1.0f, "")) { if (audioStreamName != "") { - if (!config::config["audio"].contains(audioStreamName)) { + core::configManager.aquire(); + if (!core::configManager.conf["audio"].contains(audioStreamName)) { saveAudioConfig(audioStreamName); } audio::streams[audioStreamName]->audio->setVolume(*volume); - config::config["audio"][audioStreamName]["volume"] = *volume; - config::configModified = true; + core::configManager.conf["audio"][audioStreamName]["volume"] = *volume; + core::configManager.release(true); } } @@ -529,8 +649,9 @@ void drawWindow() { if(!down && grabbingMenu) { grabbingMenu = false; menuWidth = newWidth; - config::config["menuWidth"] = menuWidth; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["menuWidth"] = menuWidth; + core::configManager.release(true); } // Left Column @@ -543,104 +664,7 @@ void drawWindow() { ImGui::BeginChild("Left Column"); float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); - if (ImGui::CollapsingHeader("Source", ImGuiTreeNodeFlags_DefaultOpen)) { - if (playing) { style::beginDisabled(); }; - - ImGui::PushItemWidth(menuColumnWidth); - if (ImGui::Combo("##_0_", &devId, soapy.txtDevList.c_str())) { - spdlog::info("Changed input device: {0}", devId); - sourceName = soapy.devNameList[devId]; - soapy.setDevice(soapy.devList[devId]); - - if (config::config["sourceSettings"].contains(sourceName)) { - loadSourceConfig(sourceName); - } - else { - srId = 0; - sampleRate = soapy.getSampleRate(); - bw.val = sampleRate; - gui::waterfall.setBandwidth(sampleRate); - gui::waterfall.setViewBandwidth(sampleRate); - sigpath::signalPath.setSampleRate(sampleRate); - - if (soapy.gainList.size() >= 0) { - delete[] uiGains; - uiGains = new float[soapy.gainList.size()]; - for (int i = 0; i < soapy.gainList.size(); i++) { - uiGains[i] = soapy.currentGains[i]; - } - } - } - setVFO(gui::freqSelect.frequency); - config::config["source"] = sourceName; - config::configModified = true; - } - ImGui::PopItemWidth(); - - if (ImGui::Combo("##_1_", &srId, soapy.txtSampleRateList.c_str())) { - spdlog::info("Changed sample rate: {0}", srId); - sampleRate = soapy.sampleRates[srId]; - soapy.setSampleRate(sampleRate); - gui::waterfall.setBandwidth(sampleRate); - gui::waterfall.setViewBandwidth(sampleRate); - sigpath::signalPath.setSampleRate(sampleRate); - bw.val = sampleRate; - - if (!config::config["sourceSettings"].contains(sourceName)) { - saveCurrentSource(); - } - config::config["sourceSettings"][sourceName]["sampleRate"] = sampleRate; - config::configModified = true; - } - - ImGui::SameLine(); - bool noDevice = (soapy.devList.size() == 0); - if (ImGui::Button("Refresh", ImVec2(menuColumnWidth - ImGui::GetCursorPosX(), 0.0f))) { - soapy.refresh(); - if (noDevice && soapy.devList.size() > 0) { - sourceName = soapy.devNameList[0]; - soapy.setDevice(soapy.devList[0]); - if (config::config["sourceSettings"][sourceName]) { - loadSourceConfig(sourceName); - } - } - } - - if (playing) { style::endDisabled(); }; - - float maxTextLength = 0; - float txtLen = 0; - char buf[100]; - - // Calculate the spacing - for (int i = 0; i < soapy.gainList.size(); i++) { - sprintf(buf, "%s gain", soapy.gainList[i].c_str()); - txtLen = ImGui::CalcTextSize(buf).x; - if (txtLen > maxTextLength) { - maxTextLength = txtLen; - } - } - - for (int i = 0; i < soapy.gainList.size(); i++) { - ImGui::Text("%s gain", soapy.gainList[i].c_str()); - ImGui::SameLine(); - sprintf(buf, "##_gain_slide_%d_", i); - - ImGui::SetCursorPosX(maxTextLength + 5); - ImGui::PushItemWidth(menuColumnWidth - (maxTextLength + 5)); - if (ImGui::SliderFloat(buf, &uiGains[i], soapy.gainRanges[i].minimum(), soapy.gainRanges[i].maximum())) { - soapy.setGain(i, uiGains[i]); - if (!config::config["sourceSettings"].contains(sourceName)) { - saveCurrentSource(); - } - config::config["sourceSettings"][sourceName]["gains"][soapy.gainList[i]] = uiGains[i]; - config::configModified = true; - } - ImGui::PopItemWidth(); - } - - ImGui::Spacing(); - } + gui::menu.draw(); for (int i = 0; i < modCount; i++) { if (ImGui::CollapsingHeader(mod::moduleNames[i].c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { @@ -673,12 +697,13 @@ void drawWindow() { stream->sampleRateId = 0; // Create config if it doesn't exist - if (!config::config["audio"].contains(name)) { + core::configManager.aquire(); + if (!core::configManager.conf["audio"].contains(name)) { saveAudioConfig(name); } - config::config["audio"][name]["device"] = stream->audio->deviceNames[stream->deviceId]; - config::config["audio"][name]["sampleRate"] = stream->audio->devices[stream->deviceId].sampleRates[0]; - config::configModified = true; + core::configManager.conf["audio"][name]["device"] = stream->audio->deviceNames[stream->deviceId]; + core::configManager.conf["audio"][name]["sampleRate"] = stream->audio->devices[stream->deviceId].sampleRates[0]; + core::configManager.release(true); } if (ImGui::Combo(("##_audio_sr_0_" + name).c_str(), &stream->sampleRateId, stream->audio->devices[deviceId].txtSampleRates.c_str())) { audio::stopStream(name); @@ -688,21 +713,23 @@ void drawWindow() { } // Create config if it doesn't exist - if (!config::config["audio"].contains(name)) { + core::configManager.aquire(); + if (!core::configManager.conf["audio"].contains(name)) { saveAudioConfig(name); } - config::config["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]; - config::configModified = true; + core::configManager.conf["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]; + core::configManager.release(true); } if (ImGui::SliderFloat(("##_audio_vol_0_" + name).c_str(), &stream->volume, 0.0f, 1.0f, "")) { stream->audio->setVolume(stream->volume); // Create config if it doesn't exist - if (!config::config["audio"].contains(name)) { + core::configManager.aquire(); + if (!core::configManager.conf["audio"].contains(name)) { saveAudioConfig(name); } - config::config["audio"][name]["volume"] = stream->volume; - config::configModified = true; + core::configManager.conf["audio"][name]["volume"] = stream->volume; + core::configManager.release(true); } ImGui::PopItemWidth(); count++; @@ -718,13 +745,15 @@ void drawWindow() { if (ImGui::CollapsingHeader("Band Plan", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::PushItemWidth(menuColumnWidth); if (ImGui::Combo("##_4_", &bandplanId.val, bandplan::bandplanNameTxt.c_str())) { - config::config["bandPlan"] = bandplan::bandplanNames[bandplanId.val]; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["bandPlan"] = bandplan::bandplanNames[bandplanId.val]; + core::configManager.release(true); } ImGui::PopItemWidth(); if (ImGui::Checkbox("Enabled", &bandPlanEnabled.val)) { - config::config["bandPlanEnabled"] = bandPlanEnabled.val; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["bandPlanEnabled"] = bandPlanEnabled.val; + core::configManager.release(true); } bandplan::BandPlan_t plan = bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]]; ImGui::Text("Country: %s (%s)", plan.countryName.c_str(), plan.countryCode.c_str()); @@ -784,8 +813,9 @@ void drawWindow() { ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0f) - 10); if (ImGui::VSliderFloat("##_8_", ImVec2(20.0f, 150.0f), &fftMax, 0.0f, -100.0f, "")) { fftMax = std::max(fftMax, fftMin + 10); - config::config["max"] = fftMax; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["max"] = fftMax; + core::configManager.release(true); } ImGui::NewLine(); @@ -795,8 +825,9 @@ void drawWindow() { ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0f) - 10); if (ImGui::VSliderFloat("##_9_", ImVec2(20.0f, 150.0f), &fftMin, 0.0f, -100.0f, "")) { fftMin = std::min(fftMax - 10, fftMin); - config::config["min"] = fftMin; - config::configModified = true; + core::configManager.aquire(); + core::configManager.conf["min"] = fftMin; + core::configManager.release(true); } ImGui::EndChild(); diff --git a/core/src/gui/main_window.h b/core/src/gui/main_window.h index 265717fb..0234b6a1 100644 --- a/core/src/gui/main_window.h +++ b/core/src/gui/main_window.h @@ -27,6 +27,7 @@ #include #include #include +#include #define WINDOW_FLAGS ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground diff --git a/core/src/gui/menu.cpp b/core/src/gui/menu.cpp index b967698b..278f1f5c 100644 --- a/core/src/gui/menu.cpp +++ b/core/src/gui/menu.cpp @@ -9,6 +9,9 @@ void Menu::registerEntry(std::string name, void (*drawHandler)(void* ctx), void* item.drawHandler = drawHandler; item.ctx = ctx; items[name] = item; + if (!isInOrderList(name)) { + order.push_back(name); + } } void Menu::removeEntry(std::string name) { @@ -18,7 +21,21 @@ void Menu::removeEntry(std::string name) { void Menu::draw() { MenuItem_t item; for (std::string name : order) { + if (items.find(name) == items.end()) { + continue; + } item = items[name]; - item.drawHandler(item.ctx); + if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + item.drawHandler(item.ctx); + } } } + +bool Menu::isInOrderList(std::string name) { + for (std::string _name : order) { + if (_name == name) { + return true; + } + } + return false; +} diff --git a/core/src/gui/menu.h b/core/src/gui/menu.h index e7f21f5d..1b3c8be4 100644 --- a/core/src/gui/menu.h +++ b/core/src/gui/menu.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -19,5 +20,7 @@ public: std::vector order; private: + bool isInOrderList(std::string name); + std::map items; }; \ No newline at end of file diff --git a/core/src/gui/style.cpp b/core/src/gui/style.cpp index e55df3d7..ea9a6a8d 100644 --- a/core/src/gui/style.cpp +++ b/core/src/gui/style.cpp @@ -9,7 +9,7 @@ namespace style { ImGui::GetStyle().PopupRounding = 0.0f; ImGui::GetStyle().ScrollbarRounding = 0.0f; - ImGui::GetIO().Fonts->AddFontFromFileTTF((config::getRootDirectory() + "/res/fonts/Roboto-Medium.ttf").c_str(), 16.0f); + ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 16.0f); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); @@ -27,7 +27,7 @@ namespace style { ImGui::GetStyle().PopupRounding = 0.0f; ImGui::GetStyle().ScrollbarRounding = 0.0f; - ImGui::GetIO().Fonts->AddFontFromFileTTF((config::getRootDirectory() + "/res/fonts/Roboto-Medium.ttf").c_str(), 16.0f); + ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 16.0f); ImGui::StyleColorsDark(); diff --git a/radio/src/main.cpp b/radio/src/main.cpp index c007df3d..39e98611 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -2,12 +2,16 @@ #include #include #include +#include #define CONCAT(a, b) ((std::string(a) + b).c_str()) #define DEEMP_LIST "50µS\00075µS\000none\000" mod::API_t* API; +ConfigManager config; +bool firstInit = true; + struct RadioContext_t { std::string name; int demod = 1; @@ -21,12 +25,16 @@ struct RadioContext_t { MOD_EXPORT void* _INIT_(mod::API_t* _API, ImGuiContext* imctx, std::string _name) { API = _API; RadioContext_t* ctx = new RadioContext_t; + ctx->name = _name; + + ctx->demod = 1; ctx->bandWidth = 200000; ctx->bandWidthMin = 100000; ctx->bandWidthMax = 200000; ctx->sigPath.init(_name, 200000, 1000); ctx->sigPath.start(); + ctx->sigPath.setDemodulator(SigPath::DEMOD_FM, ctx->bandWidth); ImGui::SetCurrentContext(imctx); return ctx; } diff --git a/root_dev/config.json b/root_dev/config.json index a0d5796f..1960e66f 100644 --- a/root_dev/config.json +++ b/root_dev/config.json @@ -4,6 +4,16 @@ "device": "Speakers (Realtek High Definiti", "sampleRate": 48000.0, "volume": 0.602150559425354 + }, + "Radio 1": { + "device": "Speakers (Realtek High Definiti", + "sampleRate": 48000.0, + "volume": 0.6881720423698425 + }, + "Radio 2": { + "device": "Speakers (Realtek High Definiti", + "sampleRate": 48000.0, + "volume": 0.0 } }, "bandPlan": "General", @@ -19,7 +29,7 @@ "sourceSettings": { "Generic RTL2832U OEM :: 00000001": { "gains": { - "TUNER": 0.0 + "TUNER": 11.625 }, "sampleRate": 2560000 }, @@ -36,7 +46,7 @@ } }, "windowSize": { - "h": 720, - "w": 1280 + "h": 784, + "w": 1460 } } \ No newline at end of file diff --git a/root_dev/module_list.json b/root_dev/module_list.json index 6036c3d6..ac435873 100644 --- a/root_dev/module_list.json +++ b/root_dev/module_list.json @@ -1,4 +1,4 @@ { - "Radio": "./radio/Release/radio.dll", - "Recorder": "./recorder/Release/recorder.dll" + "Radio 1": "./radio/Release/radio.dll", + "Recorder 1": "./recorder/Release/recorder.dll" } diff --git a/root_dev/radio_config.json b/root_dev/radio_config.json new file mode 100644 index 00000000..c6ea5a59 --- /dev/null +++ b/root_dev/radio_config.json @@ -0,0 +1,5 @@ +{ + "Radio 1": { + "demodulator":1 + } +} \ No newline at end of file