More fixes

This commit is contained in:
Ryzerth 2020-09-24 19:36:57 +02:00
parent 51ee02f9da
commit 48a8b04eaa
18 changed files with 372 additions and 252 deletions

View File

@ -1,62 +1,73 @@
#include <config.h> #include <config.h>
namespace config { ConfigManager::ConfigManager() {
bool configModified = false;
json config;
bool autoSaveRunning = false;
std::string _path;
std::thread _workerThread;
std::string rootDir;
void _autoSaveWorker() { }
while (autoSaveRunning) {
if (configModified) { void ConfigManager::setPath(std::string file) {
configModified = false; path = file;
std::ofstream file(_path.c_str()); }
file << std::setw(4) << config;
file.close(); void ConfigManager::load(json default, bool lock) {
spdlog::info("Config saved"); if (lock) { mtx.lock(); }
} if (path == "") {
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 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) { std::ifstream file(path.c_str());
if (!std::filesystem::exists(path)) { file >> conf;
spdlog::error("Config file does not exist"); file.close();
return; if (lock) { mtx.unlock(); }
} }
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();
}
void startAutoSave() { void ConfigManager::save(bool lock) {
if (autoSaveRunning) { if (lock) { mtx.lock(); }
return; 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; if (_this->changed) {
_workerThread = std::thread(_autoSaveWorker); _this->changed = false;
} _this->save(false);
void stopAutoSave() {
if (!autoSaveRunning) {
return;
} }
autoSaveRunning = false; _this->mtx.unlock();
_workerThread.join(); std::this_thread::sleep_for(std::chrono::milliseconds(1000));
} }
}
void setRootDirectory(std::string dir) {
rootDir = dir;
}
std::string getRootDirectory() {
return rootDir;
}
};

View File

@ -7,16 +7,42 @@
#include <iomanip> #include <iomanip>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <string>
using nlohmann::json; using nlohmann::json;
namespace config { //#define DEV_BUILD
void load(std::string path);
void startAutoSave(); #ifndef ROOT_DIR
void stopAutoSave(); #ifdef DEV_BUILD
void setRootDirectory(std::string dir); #define ROOT_DIR "../root_dev"
std::string getRootDirectory(); #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;
}; };

View File

@ -13,6 +13,7 @@
#include <module.h> #include <module.h>
#include <stb_image.h> #include <stb_image.h>
#include <config.h> #include <config.h>
#include <core.h>
#include <dsp/block.h> #include <dsp/block.h>
@ -23,8 +24,9 @@
#include <Windows.h> #include <Windows.h>
#endif #endif
// Comment to build a normal release namespace core {
#define DEV_BUILD ConfigManager configManager;
};
bool maximized = false; bool maximized = false;
bool fullScreen = false; bool fullScreen = false;
@ -50,18 +52,11 @@ int sdrpp_main() {
spdlog::info("SDR++ v" VERSION_STR); 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 // Load config
spdlog::info("Loading config"); spdlog::info("Loading config");
config::load(config::getRootDirectory() + "/config.json"); core::configManager.setPath(ROOT_DIR "/config.json");
config::startAutoSave(); core::configManager.load(json());
core::configManager.enableAutoSave();
// Setup window // Setup window
glfwSetErrorCallback(glfw_error_callback); 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_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
int winWidth = config::config["windowSize"]["w"]; core::configManager.aquire();
int winHeight = config::config["windowSize"]["h"]; int winWidth = core::configManager.conf["windowSize"]["w"];
maximized = config::config["maximized"]; int winHeight = core::configManager.conf["windowSize"]["h"];
maximized = core::configManager.conf["maximized"];
core::configManager.release();
// Create window with graphics context // Create window with graphics context
GLFWmonitor* monitor = glfwGetPrimaryMonitor(); GLFWmonitor* monitor = glfwGetPrimaryMonitor();
@ -94,7 +91,7 @@ int sdrpp_main() {
// Load app icon // Load app icon
GLFWimage icons[10]; 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[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[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; 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(); icons::load();
spdlog::info("Loading band plans"); spdlog::info("Loading band plans");
bandplan::loadFromDir(config::getRootDirectory() + "/bandplans"); bandplan::loadFromDir(ROOT_DIR "/bandplans");
spdlog::info("Loading band plans color table"); spdlog::info("Loading band plans color table");
bandplan::loadColorTable(config::getRootDirectory() + "/band_colors.json"); bandplan::loadColorTable(ROOT_DIR "/band_colors.json");
windowInit(); windowInit();
@ -185,11 +182,12 @@ int sdrpp_main() {
if (_maximized != maximized) { if (_maximized != maximized) {
_maximized = maximized; _maximized = maximized;
config::config["maximized"]= _maximized; core::configManager.aquire();
config::configModified = true; core::configManager.conf["maximized"]= _maximized;
if (!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; int _winWidth, _winHeight;
@ -214,9 +212,10 @@ int sdrpp_main() {
if ((_winWidth != winWidth || _winHeight != winHeight) && !maximized && _winWidth > 0 && _winHeight > 0) { if ((_winWidth != winWidth || _winHeight != winHeight) && !maximized && _winWidth > 0 && _winHeight > 0) {
winWidth = _winWidth; winWidth = _winWidth;
winHeight = _winHeight; winHeight = _winHeight;
config::config["windowSize"]["w"] = winWidth; core::configManager.aquire();
config::config["windowSize"]["h"] = winHeight; core::configManager.conf["windowSize"]["w"] = winWidth;
config::configModified = true; core::configManager.conf["windowSize"]["h"] = winHeight;
core::configManager.release(true);
} }
if (winWidth > 0 && winHeight > 0) { if (winWidth > 0 && winHeight > 0) {

View File

@ -1,3 +1,9 @@
#pragma once #pragma once
#include <module.h>
#include <config.h>
namespace core {
SDRPP_EXPORT ConfigManager configManager;
};
int sdrpp_main(); int sdrpp_main();

View File

@ -9,7 +9,7 @@ FrequencySelect::FrequencySelect() {
} }
void FrequencySelect::init() { 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++) { for (int i = 0; i < 12; i++) {
digits[i] = 0; digits[i] = 0;

View File

@ -3,4 +3,5 @@
namespace gui { namespace gui {
ImGui::WaterFall waterfall; ImGui::WaterFall waterfall;
FrequencySelect freqSelect; FrequencySelect freqSelect;
Menu menu;
}; };

View File

@ -1,9 +1,11 @@
#pragma once #pragma once
#include <gui/waterfall.h> #include <gui/waterfall.h>
#include <gui/frequency_select.h> #include <gui/frequency_select.h>
#include <gui/menu.h>
#include <module.h> #include <module.h>
namespace gui { namespace gui {
SDRPP_EXPORT ImGui::WaterFall waterfall; SDRPP_EXPORT ImGui::WaterFall waterfall;
SDRPP_EXPORT FrequencySelect freqSelect; SDRPP_EXPORT FrequencySelect freqSelect;
SDRPP_EXPORT Menu menu;
}; };

View File

@ -24,9 +24,9 @@ namespace icons {
} }
void load() { void load() {
LOGO = (ImTextureID)(uintptr_t)loadTexture(config::getRootDirectory() + "/res/icons/sdrpp.png"); LOGO = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/sdrpp.png");
PLAY = (ImTextureID)(uintptr_t)loadTexture(config::getRootDirectory() + "/res/icons/play.png"); PLAY = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/play.png");
STOP = (ImTextureID)(uintptr_t)loadTexture(config::getRootDirectory() + "/res/icons/stop.png"); STOP = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/stop.png");
MENU = (ImTextureID)(uintptr_t)loadTexture(config::getRootDirectory() + "/res/icons/menu.png"); MENU = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/menu.png");
} }
} }

View File

@ -10,6 +10,6 @@ namespace icons {
extern ImTextureID STOP; extern ImTextureID STOP;
extern ImTextureID MENU; extern ImTextureID MENU;
GLuint loadTexture(char* path); GLuint loadTexture(std::string path);
void load(); void load();
} }

View File

@ -64,14 +64,14 @@ bool showMenu = true;
void saveCurrentSource() { void saveCurrentSource() {
int i = 0; int i = 0;
for (std::string gainName : soapy.gainList) { for (std::string gainName : soapy.gainList) {
config::config["sourceSettings"][sourceName]["gains"][gainName] = uiGains[i]; core::configManager.conf["sourceSettings"][sourceName]["gains"][gainName] = uiGains[i];
i++; i++;
} }
config::config["sourceSettings"][sourceName]["sampleRate"] = soapy.sampleRates[srId]; core::configManager.conf["sourceSettings"][sourceName]["sampleRate"] = soapy.sampleRates[srId];
} }
void loadSourceConfig(std::string name) { void loadSourceConfig(std::string name) {
json sourceSettings = config::config["sourceSettings"][name]; json sourceSettings = core::configManager.conf["sourceSettings"][name];
sampleRate = sourceSettings["sampleRate"]; sampleRate = sourceSettings["sampleRate"];
@ -110,7 +110,7 @@ void loadSourceConfig(std::string name) {
} }
void loadAudioConfig(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"]; std::string devName = audioSettings["device"];
auto _devIt = std::find(audio::streams[name]->audio->deviceNames.begin(), audio::streams[name]->audio->deviceNames.end(), devName); 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) { void saveAudioConfig(std::string name) {
config::config["audio"][name]["device"] = audio::streams[name]->audio->deviceNames[audio::streams[name]->deviceId]; core::configManager.conf["audio"][name]["device"] = audio::streams[name]->audio->deviceNames[audio::streams[name]->deviceId];
config::config["audio"][name]["volume"] = audio::streams[name]->volume; core::configManager.conf["audio"][name]["volume"] = audio::streams[name]->volume;
config::config["audio"][name]["sampleRate"] = audio::streams[name]->sampleRate; 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() { void windowInit() {
spdlog::info("Initializing SoapySDR"); spdlog::info("Initializing SoapySDR");
soapy.init(); soapy.init();
gui::menu.registerEntry("Source", sourceMenu, NULL);
gui::freqSelect.init(); gui::freqSelect.init();
@ -168,16 +279,17 @@ void windowInit() {
spdlog::info("Loading modules"); spdlog::info("Loading modules");
mod::initAPI(&gui::waterfall); 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 // Load last source configuration
uint64_t frequency = config::config["frequency"]; core::configManager.aquire();
sourceName = config::config["source"]; uint64_t frequency = core::configManager.conf["frequency"];
sourceName = core::configManager.conf["source"];
auto _sourceIt = std::find(soapy.devNameList.begin(), soapy.devNameList.end(), sourceName); auto _sourceIt = std::find(soapy.devNameList.begin(), soapy.devNameList.end(), sourceName);
if (_sourceIt != soapy.devNameList.end() && config::config["sourceSettings"].contains(sourceName)) { if (_sourceIt != soapy.devNameList.end() && core::configManager.conf["sourceSettings"].contains(sourceName)) {
json sourceSettings = config::config["sourceSettings"][sourceName]; json sourceSettings = core::configManager.conf["sourceSettings"][sourceName];
devId = std::distance(soapy.devNameList.begin(), _sourceIt); devId = std::distance(soapy.devNameList.begin(), _sourceIt);
soapy.setDevice(soapy.devList[devId]); soapy.setDevice(soapy.devList[devId]);
loadSourceConfig(sourceName); loadSourceConfig(sourceName);
@ -186,7 +298,7 @@ void windowInit() {
int i = 0; int i = 0;
bool settingsFound = false; bool settingsFound = false;
for (std::string devName : soapy.devNameList) { for (std::string devName : soapy.devNameList) {
if (config::config["sourceSettings"].contains(devName)) { if (core::configManager.conf["sourceSettings"].contains(devName)) {
sourceName = devName; sourceName = devName;
settingsFound = true; settingsFound = true;
devId = i; devId = i;
@ -222,17 +334,17 @@ void windowInit() {
// Switch to double for all frequecies and bandwidth // Switch to double for all frequecies and bandwidth
// Update UI settings // Update UI settings
fftMin = config::config["min"]; fftMin = core::configManager.conf["min"];
fftMax = config::config["max"]; fftMax = core::configManager.conf["max"];
gui::waterfall.setFFTMin(fftMin); gui::waterfall.setFFTMin(fftMin);
gui::waterfall.setWaterfallMin(fftMin); gui::waterfall.setWaterfallMin(fftMin);
gui::waterfall.setFFTMax(fftMax); gui::waterfall.setFFTMax(fftMax);
gui::waterfall.setWaterfallMax(fftMax); gui::waterfall.setWaterfallMax(fftMax);
bandPlanEnabled.val = config::config["bandPlanEnabled"]; bandPlanEnabled.val = core::configManager.conf["bandPlanEnabled"];
bandPlanEnabled.markAsChanged(); bandPlanEnabled.markAsChanged();
std::string bandPlanName = config::config["bandPlan"]; std::string bandPlanName = core::configManager.conf["bandPlan"];
auto _bandplanIt = bandplan::bandplans.find(bandPlanName); auto _bandplanIt = bandplan::bandplans.find(bandPlanName);
if (_bandplanIt != bandplan::bandplans.end()) { if (_bandplanIt != bandplan::bandplans.end()) {
bandplanId.val = std::distance(bandplan::bandplans.begin(), bandplan::bandplans.find(bandPlanName)); bandplanId.val = std::distance(bandplan::bandplans.begin(), bandplan::bandplans.find(bandPlanName));
@ -262,7 +374,7 @@ void windowInit() {
gui::waterfall.selectFirstVFO(); gui::waterfall.selectFirstVFO();
for (auto [name, stream] : audio::streams) { 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; bool running = audio::streams[name]->running;
audio::stopStream(name); audio::stopStream(name);
loadAudioConfig(name); loadAudioConfig(name);
@ -277,16 +389,18 @@ void windowInit() {
volume = &audio::streams[audioStreamName]->volume; volume = &audio::streams[audioStreamName]->volume;
} }
menuWidth = config::config["menuWidth"]; menuWidth = core::configManager.conf["menuWidth"];
newWidth = menuWidth; newWidth = menuWidth;
showWaterfall = config::config["showWaterfall"]; showWaterfall = core::configManager.conf["showWaterfall"];
if (!showWaterfall) { if (!showWaterfall) {
gui::waterfall.hideWaterfall(); gui::waterfall.hideWaterfall();
} }
fftHeight = config::config["fftHeight"]; fftHeight = core::configManager.conf["fftHeight"];
gui::waterfall.setFFTHeight(fftHeight); gui::waterfall.setFFTHeight(fftHeight);
core::configManager.release();
} }
void setVFO(float freq) { void setVFO(float freq) {
@ -382,8 +496,9 @@ void drawWindow() {
if (vfo->centerOffsetChanged) { if (vfo->centerOffsetChanged) {
gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset); gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset);
gui::freqSelect.frequencyChanged = false; gui::freqSelect.frequencyChanged = false;
config::config["frequency"] = gui::freqSelect.frequency; core::configManager.aquire();
config::configModified = true; core::configManager.conf["frequency"] = gui::freqSelect.frequency;
core::configManager.release(true);
} }
sigpath::vfoManager.updateFromWaterfall(&gui::waterfall); sigpath::vfoManager.updateFromWaterfall(&gui::waterfall);
@ -397,8 +512,9 @@ void drawWindow() {
if (audioStreamName != "") { if (audioStreamName != "") {
volume = &audio::streams[audioStreamName]->volume; volume = &audio::streams[audioStreamName]->volume;
} }
config::config["frequency"] = gui::freqSelect.frequency; core::configManager.aquire();
config::configModified = true; core::configManager.conf["frequency"] = gui::freqSelect.frequency;
core::configManager.release(true);
} }
if (gui::freqSelect.frequencyChanged) { if (gui::freqSelect.frequencyChanged) {
@ -407,16 +523,18 @@ void drawWindow() {
vfo->centerOffsetChanged = false; vfo->centerOffsetChanged = false;
vfo->lowerOffsetChanged = false; vfo->lowerOffsetChanged = false;
vfo->upperOffsetChanged = false; vfo->upperOffsetChanged = false;
config::config["frequency"] = gui::freqSelect.frequency; core::configManager.aquire();
config::configModified = true; core::configManager.conf["frequency"] = gui::freqSelect.frequency;
core::configManager.release(true);
} }
if (gui::waterfall.centerFreqMoved) { if (gui::waterfall.centerFreqMoved) {
gui::waterfall.centerFreqMoved = false; gui::waterfall.centerFreqMoved = false;
soapy.setFrequency(gui::waterfall.getCenterFrequency()); soapy.setFrequency(gui::waterfall.getCenterFrequency());
gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset); gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset);
config::config["frequency"] = gui::freqSelect.frequency; core::configManager.aquire();
config::configModified = true; core::configManager.conf["frequency"] = gui::freqSelect.frequency;
core::configManager.release(true);
} }
if (dcbias.changed()) { if (dcbias.changed()) {
@ -434,8 +552,9 @@ void drawWindow() {
int _fftHeight = gui::waterfall.getFFTHeight(); int _fftHeight = gui::waterfall.getFFTHeight();
if (fftHeight != _fftHeight) { if (fftHeight != _fftHeight) {
fftHeight = _fftHeight; fftHeight = _fftHeight;
config::config["fftHeight"] = fftHeight; core::configManager.aquire();
config::configModified = true; core::configManager.conf["fftHeight"] = fftHeight;
core::configManager.release(true);
} }
ImVec2 vMin = ImGui::GetWindowContentRegionMin(); ImVec2 vMin = ImGui::GetWindowContentRegionMin();
@ -478,12 +597,13 @@ void drawWindow() {
ImGui::SetNextItemWidth(200); ImGui::SetNextItemWidth(200);
if (ImGui::SliderFloat("##_2_", volume, 0.0f, 1.0f, "")) { if (ImGui::SliderFloat("##_2_", volume, 0.0f, 1.0f, "")) {
if (audioStreamName != "") { if (audioStreamName != "") {
if (!config::config["audio"].contains(audioStreamName)) { core::configManager.aquire();
if (!core::configManager.conf["audio"].contains(audioStreamName)) {
saveAudioConfig(audioStreamName); saveAudioConfig(audioStreamName);
} }
audio::streams[audioStreamName]->audio->setVolume(*volume); audio::streams[audioStreamName]->audio->setVolume(*volume);
config::config["audio"][audioStreamName]["volume"] = *volume; core::configManager.conf["audio"][audioStreamName]["volume"] = *volume;
config::configModified = true; core::configManager.release(true);
} }
} }
@ -529,8 +649,9 @@ void drawWindow() {
if(!down && grabbingMenu) { if(!down && grabbingMenu) {
grabbingMenu = false; grabbingMenu = false;
menuWidth = newWidth; menuWidth = newWidth;
config::config["menuWidth"] = menuWidth; core::configManager.aquire();
config::configModified = true; core::configManager.conf["menuWidth"] = menuWidth;
core::configManager.release(true);
} }
// Left Column // Left Column
@ -543,104 +664,7 @@ void drawWindow() {
ImGui::BeginChild("Left Column"); ImGui::BeginChild("Left Column");
float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); float menuColumnWidth = ImGui::GetContentRegionAvailWidth();
if (ImGui::CollapsingHeader("Source", ImGuiTreeNodeFlags_DefaultOpen)) { gui::menu.draw();
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();
}
for (int i = 0; i < modCount; i++) { for (int i = 0; i < modCount; i++) {
if (ImGui::CollapsingHeader(mod::moduleNames[i].c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader(mod::moduleNames[i].c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
@ -673,12 +697,13 @@ void drawWindow() {
stream->sampleRateId = 0; stream->sampleRateId = 0;
// Create config if it doesn't exist // 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); saveAudioConfig(name);
} }
config::config["audio"][name]["device"] = stream->audio->deviceNames[stream->deviceId]; core::configManager.conf["audio"][name]["device"] = stream->audio->deviceNames[stream->deviceId];
config::config["audio"][name]["sampleRate"] = stream->audio->devices[stream->deviceId].sampleRates[0]; core::configManager.conf["audio"][name]["sampleRate"] = stream->audio->devices[stream->deviceId].sampleRates[0];
config::configModified = true; core::configManager.release(true);
} }
if (ImGui::Combo(("##_audio_sr_0_" + name).c_str(), &stream->sampleRateId, stream->audio->devices[deviceId].txtSampleRates.c_str())) { if (ImGui::Combo(("##_audio_sr_0_" + name).c_str(), &stream->sampleRateId, stream->audio->devices[deviceId].txtSampleRates.c_str())) {
audio::stopStream(name); audio::stopStream(name);
@ -688,21 +713,23 @@ void drawWindow() {
} }
// Create config if it doesn't exist // 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); saveAudioConfig(name);
} }
config::config["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]; core::configManager.conf["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId];
config::configModified = true; core::configManager.release(true);
} }
if (ImGui::SliderFloat(("##_audio_vol_0_" + name).c_str(), &stream->volume, 0.0f, 1.0f, "")) { if (ImGui::SliderFloat(("##_audio_vol_0_" + name).c_str(), &stream->volume, 0.0f, 1.0f, "")) {
stream->audio->setVolume(stream->volume); stream->audio->setVolume(stream->volume);
// Create config if it doesn't exist // 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); saveAudioConfig(name);
} }
config::config["audio"][name]["volume"] = stream->volume; core::configManager.conf["audio"][name]["volume"] = stream->volume;
config::configModified = true; core::configManager.release(true);
} }
ImGui::PopItemWidth(); ImGui::PopItemWidth();
count++; count++;
@ -718,13 +745,15 @@ void drawWindow() {
if (ImGui::CollapsingHeader("Band Plan", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader("Band Plan", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::PushItemWidth(menuColumnWidth); ImGui::PushItemWidth(menuColumnWidth);
if (ImGui::Combo("##_4_", &bandplanId.val, bandplan::bandplanNameTxt.c_str())) { if (ImGui::Combo("##_4_", &bandplanId.val, bandplan::bandplanNameTxt.c_str())) {
config::config["bandPlan"] = bandplan::bandplanNames[bandplanId.val]; core::configManager.aquire();
config::configModified = true; core::configManager.conf["bandPlan"] = bandplan::bandplanNames[bandplanId.val];
core::configManager.release(true);
} }
ImGui::PopItemWidth(); ImGui::PopItemWidth();
if (ImGui::Checkbox("Enabled", &bandPlanEnabled.val)) { if (ImGui::Checkbox("Enabled", &bandPlanEnabled.val)) {
config::config["bandPlanEnabled"] = bandPlanEnabled.val; core::configManager.aquire();
config::configModified = true; core::configManager.conf["bandPlanEnabled"] = bandPlanEnabled.val;
core::configManager.release(true);
} }
bandplan::BandPlan_t plan = bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]]; bandplan::BandPlan_t plan = bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]];
ImGui::Text("Country: %s (%s)", plan.countryName.c_str(), plan.countryCode.c_str()); 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); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0f) - 10);
if (ImGui::VSliderFloat("##_8_", ImVec2(20.0f, 150.0f), &fftMax, 0.0f, -100.0f, "")) { if (ImGui::VSliderFloat("##_8_", ImVec2(20.0f, 150.0f), &fftMax, 0.0f, -100.0f, "")) {
fftMax = std::max<float>(fftMax, fftMin + 10); fftMax = std::max<float>(fftMax, fftMin + 10);
config::config["max"] = fftMax; core::configManager.aquire();
config::configModified = true; core::configManager.conf["max"] = fftMax;
core::configManager.release(true);
} }
ImGui::NewLine(); ImGui::NewLine();
@ -795,8 +825,9 @@ void drawWindow() {
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0f) - 10); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0f) - 10);
if (ImGui::VSliderFloat("##_9_", ImVec2(20.0f, 150.0f), &fftMin, 0.0f, -100.0f, "")) { if (ImGui::VSliderFloat("##_9_", ImVec2(20.0f, 150.0f), &fftMin, 0.0f, -100.0f, "")) {
fftMin = std::min<float>(fftMax - 10, fftMin); fftMin = std::min<float>(fftMax - 10, fftMin);
config::config["min"] = fftMin; core::configManager.aquire();
config::configModified = true; core::configManager.conf["min"] = fftMin;
core::configManager.release(true);
} }
ImGui::EndChild(); ImGui::EndChild();

View File

@ -27,6 +27,7 @@
#include <gui/style.h> #include <gui/style.h>
#include <config.h> #include <config.h>
#include <signal_path/signal_path.h> #include <signal_path/signal_path.h>
#include <core.h>
#define WINDOW_FLAGS ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground #define WINDOW_FLAGS ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground

View File

@ -9,6 +9,9 @@ void Menu::registerEntry(std::string name, void (*drawHandler)(void* ctx), void*
item.drawHandler = drawHandler; item.drawHandler = drawHandler;
item.ctx = ctx; item.ctx = ctx;
items[name] = item; items[name] = item;
if (!isInOrderList(name)) {
order.push_back(name);
}
} }
void Menu::removeEntry(std::string name) { void Menu::removeEntry(std::string name) {
@ -18,7 +21,21 @@ void Menu::removeEntry(std::string name) {
void Menu::draw() { void Menu::draw() {
MenuItem_t item; MenuItem_t item;
for (std::string name : order) { for (std::string name : order) {
if (items.find(name) == items.end()) {
continue;
}
item = items[name]; 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;
}

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <imgui/imgui.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
@ -19,5 +20,7 @@ public:
std::vector<std::string> order; std::vector<std::string> order;
private: private:
bool isInOrderList(std::string name);
std::map<std::string, MenuItem_t> items; std::map<std::string, MenuItem_t> items;
}; };

View File

@ -9,7 +9,7 @@ namespace style {
ImGui::GetStyle().PopupRounding = 0.0f; ImGui::GetStyle().PopupRounding = 0.0f;
ImGui::GetStyle().ScrollbarRounding = 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::StyleColorsDark();
//ImGui::StyleColorsLight(); //ImGui::StyleColorsLight();
@ -27,7 +27,7 @@ namespace style {
ImGui::GetStyle().PopupRounding = 0.0f; ImGui::GetStyle().PopupRounding = 0.0f;
ImGui::GetStyle().ScrollbarRounding = 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::StyleColorsDark();

View File

@ -2,12 +2,16 @@
#include <module.h> #include <module.h>
#include <path.h> #include <path.h>
#include <watcher.h> #include <watcher.h>
#include <config.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str()) #define CONCAT(a, b) ((std::string(a) + b).c_str())
#define DEEMP_LIST "50µS\00075µS\000none\000" #define DEEMP_LIST "50µS\00075µS\000none\000"
mod::API_t* API; mod::API_t* API;
ConfigManager config;
bool firstInit = true;
struct RadioContext_t { struct RadioContext_t {
std::string name; std::string name;
int demod = 1; int demod = 1;
@ -21,12 +25,16 @@ struct RadioContext_t {
MOD_EXPORT void* _INIT_(mod::API_t* _API, ImGuiContext* imctx, std::string _name) { MOD_EXPORT void* _INIT_(mod::API_t* _API, ImGuiContext* imctx, std::string _name) {
API = _API; API = _API;
RadioContext_t* ctx = new RadioContext_t; RadioContext_t* ctx = new RadioContext_t;
ctx->name = _name; ctx->name = _name;
ctx->demod = 1;
ctx->bandWidth = 200000; ctx->bandWidth = 200000;
ctx->bandWidthMin = 100000; ctx->bandWidthMin = 100000;
ctx->bandWidthMax = 200000; ctx->bandWidthMax = 200000;
ctx->sigPath.init(_name, 200000, 1000); ctx->sigPath.init(_name, 200000, 1000);
ctx->sigPath.start(); ctx->sigPath.start();
ctx->sigPath.setDemodulator(SigPath::DEMOD_FM, ctx->bandWidth);
ImGui::SetCurrentContext(imctx); ImGui::SetCurrentContext(imctx);
return ctx; return ctx;
} }

View File

@ -4,6 +4,16 @@
"device": "Speakers (Realtek High Definiti", "device": "Speakers (Realtek High Definiti",
"sampleRate": 48000.0, "sampleRate": 48000.0,
"volume": 0.602150559425354 "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", "bandPlan": "General",
@ -19,7 +29,7 @@
"sourceSettings": { "sourceSettings": {
"Generic RTL2832U OEM :: 00000001": { "Generic RTL2832U OEM :: 00000001": {
"gains": { "gains": {
"TUNER": 0.0 "TUNER": 11.625
}, },
"sampleRate": 2560000 "sampleRate": 2560000
}, },
@ -36,7 +46,7 @@
} }
}, },
"windowSize": { "windowSize": {
"h": 720, "h": 784,
"w": 1280 "w": 1460
} }
} }

View File

@ -1,4 +1,4 @@
{ {
"Radio": "./radio/Release/radio.dll", "Radio 1": "./radio/Release/radio.dll",
"Recorder": "./recorder/Release/recorder.dll" "Recorder 1": "./recorder/Release/recorder.dll"
} }

View File

@ -0,0 +1,5 @@
{
"Radio 1": {
"demodulator":1
}
}