From 153b58fbbdbc73ea6edcfad2b8f78574501f521a Mon Sep 17 00:00:00 2001 From: cropinghigh Date: Sat, 26 Dec 2020 21:00:09 +0300 Subject: [PATCH 1/4] Stepped sliders --- core/src/imgui/imgui.h | 1 + core/src/imgui/imgui_widgets.cpp | 19 ++++++ soapy_source/src/main.cpp | 99 ++++++++++++++++++++++++++++++-- 3 files changed, 113 insertions(+), 6 deletions(-) diff --git a/core/src/imgui/imgui.h b/core/src/imgui/imgui.h index b6c91a03..db6a16a5 100644 --- a/core/src/imgui/imgui.h +++ b/core/src/imgui/imgui.h @@ -481,6 +481,7 @@ namespace ImGui // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders + IMGUI_API bool SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format = "%.3f"); IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); diff --git a/core/src/imgui/imgui_widgets.cpp b/core/src/imgui/imgui_widgets.cpp index 6961d80b..aa1d72b4 100644 --- a/core/src/imgui/imgui_widgets.cpp +++ b/core/src/imgui/imgui_widgets.cpp @@ -2702,6 +2702,25 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } +bool ImGui::SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format) +{ + if (!display_format) + display_format = "%.3f"; + + char text_buf[64] = {}; + ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), display_format, *v); + + // Map from [v_min,v_max] to [0,N] + const int countValues = int((v_max-v_min)/v_step); + int v_i = int((*v - v_min)/v_step); + const bool value_changed = ImGui::SliderInt(label, &v_i, 0, countValues, text_buf); + + // Remap from [0,N] to [v_min,v_max] + *v = v_min + float(v_i) * v_step; + return value_changed; +} + + bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); diff --git a/soapy_source/src/main.cpp b/soapy_source/src/main.cpp index d88d0433..e7949b7f 100644 --- a/soapy_source/src/main.cpp +++ b/soapy_source/src/main.cpp @@ -67,6 +67,14 @@ public: bool isEnabled() { return enabled; } + + template + std::string to_string_with_precision(const T a_value, const int n = 6) { + std::ostringstream out; + out.precision(n); + out << std::fixed << a_value; + return out.str(); + } private: void refresh() { @@ -79,6 +87,21 @@ private: i++; } } + + float selectBwBySr(double samplerate) { + float cur = bandwidthList[1]; + std::vector bwListReversed = bandwidthList; + std::reverse(bwListReversed.begin(), bwListReversed.end()); + for(auto bw : bwListReversed) { + if(bw >= samplerate) { + cur = bw; + } else { + break; + } + } + spdlog::info("Bandwidth for samplerate {0} is {1}", samplerate, cur); + return cur; + } void selectSampleRate(double samplerate) { spdlog::info("Setting sample rate to {0}", samplerate); @@ -131,19 +154,41 @@ private: gainList = dev->listGains(SOAPY_SDR_RX, channelId); delete[] uiGains; uiGains = new float[gainList.size()]; + for (auto gain : gainList) { gainRanges.push_back(dev->getGainRange(SOAPY_SDR_RX, channelId, gain)); } + + SoapySDR::RangeList bandwidthRange = dev->getBandwidthRange(SOAPY_SDR_RX, channelId); + + txtBwList = ""; + + bandwidthList.push_back(-1); + txtBwList += "Auto"; + txtBwList += '\0'; + + for(auto bwr : bandwidthRange) { + float bw = bwr.minimum(); + bandwidthList.push_back(bw); + if (bw > 1.0e3 && bw <= 1.0e6) { + txtBwList += to_string_with_precision((bw / 1.0e3), 2) + " kHz"; + } else if (bw > 1.0e6) { + txtBwList += to_string_with_precision((bw / 1.0e6), 2) + " MHz"; + } else { + txtBwList += to_string_with_precision(bw, 0); + } + txtBwList += '\0'; + } sampleRates = dev->listSampleRates(SOAPY_SDR_RX, channelId); txtSrList = ""; for (double sr : sampleRates) { if (sr > 1.0e3 && sr <= 1.0e6) { - txtSrList += std::to_string((sr / 1.0e3)) + " kHz"; + txtSrList += to_string_with_precision((sr / 1.0e3), 2) + " kHz"; } else if (sr > 1.0e6) { - txtSrList += std::to_string((sr / 1.0e6)) + " MHz"; + txtSrList += to_string_with_precision((sr / 1.0e6), 2) + " MHz"; } else { - txtSrList += std::to_string((int) sr); + txtSrList += to_string_with_precision(sr, 0); } txtSrList += '\0'; } @@ -164,6 +209,11 @@ private: } i++; } + if(config.conf["devices"][name].contains("bandwidth")) { + uiBandwidthId = config.conf["devices"][name]["bandwidth"]; + } else if(bandwidthList.size() > 1) { + uiBandwidthId = bandwidthList[0]; + } if (hasAgc && config.conf["devices"][name].contains("agc")) { agc = config.conf["devices"][name]["agc"]; } @@ -183,6 +233,8 @@ private: uiGains[i] = gainRanges[i].minimum(); i++; } + if(bandwidthList.size() > 1) + uiBandwidthId = bandwidthList[0]; if (hasAgc) { agc = false; } @@ -200,6 +252,8 @@ private: conf["gains"][gain] = uiGains[i]; i++; } + if(bandwidthList.size() > 1) + conf["bandwidth"] = uiBandwidthId; if (hasAgc) { conf["agc"] = agc; } @@ -233,6 +287,12 @@ private: _this->dev->setGain(SOAPY_SDR_RX, _this->channelId, gain, _this->uiGains[i]); i++; } + if(_this->bandwidthList.size() > 1) { + if(_this->bandwidthList[_this->uiBandwidthId] == -1) + _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId])); + else + _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->bandwidthList[_this->uiBandwidthId]); + } if (_this->hasAgc) { _this->dev->setGainMode(SOAPY_SDR_RX, _this->channelId, _this->agc); @@ -291,6 +351,8 @@ private: if (ImGui::Combo(CONCAT("##_sr_select_", _this->name), &_this->srId, _this->txtSrList.c_str())) { _this->selectSampleRate(_this->sampleRates[_this->srId]); + if(_this->bandwidthList.size() > 1 && _this->running && _this->bandwidthList[_this->uiBandwidthId] == -1) + _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId])); _this->saveCurrent(); } @@ -334,8 +396,13 @@ private: ImGui::SameLine(); ImGui::SetCursorPosX(gainNameLen); ImGui::SetNextItemWidth(menuWidth - gainNameLen); - if (ImGui::SliderFloat((gain + std::string("##_gain_sel_") + _this->name).c_str(), &_this->uiGains[i], - _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum())) { + float step = _this->gainRanges[i].step(); + bool res; + if(step == 0.0f) + res = ImGui::SliderFloat((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum()); + else + res = ImGui::SliderFloatWithSteps((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum(), step); + if(res) { if (_this->running) { _this->dev->setGain(SOAPY_SDR_RX, _this->channelId, gain, _this->uiGains[i]); } @@ -343,6 +410,23 @@ private: } i++; } + if(_this->bandwidthList.size() > 1) { + float bwLen = ImGui::CalcTextSize("Bandwidth").x + 5.0f; + ImGui::Text("Bandwidth"); + ImGui::SameLine(); + ImGui::SetCursorPosX(bwLen); + ImGui::SetNextItemWidth(menuWidth - bwLen); + + if (ImGui::Combo(CONCAT("##_bw_select_", _this->name), &_this->uiBandwidthId, _this->txtBwList.c_str())) { + if(_this->running) { + if(_this->bandwidthList[_this->uiBandwidthId] == -1) + _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId])); + else + _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->bandwidthList[_this->uiBandwidthId]); + } + _this->saveCurrent(); + } + } } static void _worker(SoapyModule* _this) { @@ -383,6 +467,9 @@ private: int channelId = 0; std::vector gainList; std::vector gainRanges; + int uiBandwidthId = 0; + std::vector bandwidthList; + std::string txtBwList; }; MOD_EXPORT void _INIT_() { @@ -405,4 +492,4 @@ MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) { MOD_EXPORT void _END_() { config.disableAutoSave(); config.save(); -} \ No newline at end of file +} From 04823abb83a9c80563de7e9784a8fb8bedf6041c Mon Sep 17 00:00:00 2001 From: cropinghigh Date: Sat, 26 Dec 2020 21:36:16 +0300 Subject: [PATCH 2/4] Fix bugs --- soapy_source/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soapy_source/src/main.cpp b/soapy_source/src/main.cpp index e7949b7f..9b88fb7c 100644 --- a/soapy_source/src/main.cpp +++ b/soapy_source/src/main.cpp @@ -162,7 +162,7 @@ private: SoapySDR::RangeList bandwidthRange = dev->getBandwidthRange(SOAPY_SDR_RX, channelId); txtBwList = ""; - + bandwidthList.clear(); bandwidthList.push_back(-1); txtBwList += "Auto"; txtBwList += '\0'; @@ -212,7 +212,7 @@ private: if(config.conf["devices"][name].contains("bandwidth")) { uiBandwidthId = config.conf["devices"][name]["bandwidth"]; } else if(bandwidthList.size() > 1) { - uiBandwidthId = bandwidthList[0]; + uiBandwidthId = 0; } if (hasAgc && config.conf["devices"][name].contains("agc")) { agc = config.conf["devices"][name]["agc"]; @@ -234,7 +234,7 @@ private: i++; } if(bandwidthList.size() > 1) - uiBandwidthId = bandwidthList[0]; + uiBandwidthId = 0; if (hasAgc) { agc = false; } From b370eda0d51c2d039b45fee7da6ed7616e2afa4c Mon Sep 17 00:00:00 2001 From: cropinghigh Date: Sun, 27 Dec 2020 00:56:39 +0300 Subject: [PATCH 3/4] Fix bugs+move widget --- core/src/gui/widgets/stepped_slider.cpp | 23 +++++++++++++++++++++++ core/src/gui/widgets/stepped_slider.h | 5 +++++ core/src/imgui/imgui.h | 1 - core/src/imgui/imgui_widgets.cpp | 19 ------------------- soapy_source/src/main.cpp | 7 +++++-- 5 files changed, 33 insertions(+), 22 deletions(-) create mode 100644 core/src/gui/widgets/stepped_slider.cpp create mode 100644 core/src/gui/widgets/stepped_slider.h diff --git a/core/src/gui/widgets/stepped_slider.cpp b/core/src/gui/widgets/stepped_slider.cpp new file mode 100644 index 00000000..be2f7c23 --- /dev/null +++ b/core/src/gui/widgets/stepped_slider.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +namespace ImGui { + bool SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format) { + if (!display_format) { + display_format = "%.3f"; + } + + char text_buf[64] = {}; + ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), display_format, *v); + + // Map from [v_min,v_max] to [0,N] + const int countValues = int((v_max-v_min)/v_step); + int v_i = int((*v - v_min)/v_step); + const bool value_changed = ImGui::SliderInt(label, &v_i, 0, countValues, text_buf); + + // Remap from [0,N] to [v_min,v_max] + *v = v_min + float(v_i) * v_step; + return value_changed; + } +} diff --git a/core/src/gui/widgets/stepped_slider.h b/core/src/gui/widgets/stepped_slider.h new file mode 100644 index 00000000..06aefe6e --- /dev/null +++ b/core/src/gui/widgets/stepped_slider.h @@ -0,0 +1,5 @@ +#pragma once + +namespace ImGui { + bool SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format = "%.3f"); +} diff --git a/core/src/imgui/imgui.h b/core/src/imgui/imgui.h index db6a16a5..b6c91a03 100644 --- a/core/src/imgui/imgui.h +++ b/core/src/imgui/imgui.h @@ -481,7 +481,6 @@ namespace ImGui // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders - IMGUI_API bool SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format = "%.3f"); IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); diff --git a/core/src/imgui/imgui_widgets.cpp b/core/src/imgui/imgui_widgets.cpp index aa1d72b4..6961d80b 100644 --- a/core/src/imgui/imgui_widgets.cpp +++ b/core/src/imgui/imgui_widgets.cpp @@ -2702,25 +2702,6 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } -bool ImGui::SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format) -{ - if (!display_format) - display_format = "%.3f"; - - char text_buf[64] = {}; - ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), display_format, *v); - - // Map from [v_min,v_max] to [0,N] - const int countValues = int((v_max-v_min)/v_step); - int v_i = int((*v - v_min)/v_step); - const bool value_changed = ImGui::SliderInt(label, &v_i, 0, countValues, text_buf); - - // Remap from [0,N] to [v_min,v_max] - *v = v_min + float(v_i) * v_step; - return value_changed; -} - - bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); diff --git a/soapy_source/src/main.cpp b/soapy_source/src/main.cpp index 9b88fb7c..faa31a02 100644 --- a/soapy_source/src/main.cpp +++ b/soapy_source/src/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -154,6 +155,7 @@ private: gainList = dev->listGains(SOAPY_SDR_RX, channelId); delete[] uiGains; uiGains = new float[gainList.size()]; + gainRanges.clear(); for (auto gain : gainList) { gainRanges.push_back(dev->getGainRange(SOAPY_SDR_RX, channelId, gain)); @@ -398,10 +400,11 @@ private: ImGui::SetNextItemWidth(menuWidth - gainNameLen); float step = _this->gainRanges[i].step(); bool res; - if(step == 0.0f) + if(step == 0.0f) { res = ImGui::SliderFloat((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum()); - else + } else { res = ImGui::SliderFloatWithSteps((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum(), step); + } if(res) { if (_this->running) { _this->dev->setGain(SOAPY_SDR_RX, _this->channelId, gain, _this->uiGains[i]); From 8e764f48ae5cd2b3d47b026441a8379ddc34c708 Mon Sep 17 00:00:00 2001 From: cropinghigh Date: Mon, 28 Dec 2020 16:05:35 +0300 Subject: [PATCH 4/4] Fix unusable bw --- soapy_source/src/main.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/soapy_source/src/main.cpp b/soapy_source/src/main.cpp index faa31a02..5a206e4d 100644 --- a/soapy_source/src/main.cpp +++ b/soapy_source/src/main.cpp @@ -213,7 +213,7 @@ private: } if(config.conf["devices"][name].contains("bandwidth")) { uiBandwidthId = config.conf["devices"][name]["bandwidth"]; - } else if(bandwidthList.size() > 1) { + } else if(bandwidthList.size() > 2) { uiBandwidthId = 0; } if (hasAgc && config.conf["devices"][name].contains("agc")) { @@ -235,7 +235,7 @@ private: uiGains[i] = gainRanges[i].minimum(); i++; } - if(bandwidthList.size() > 1) + if(bandwidthList.size() > 2) uiBandwidthId = 0; if (hasAgc) { agc = false; @@ -254,7 +254,7 @@ private: conf["gains"][gain] = uiGains[i]; i++; } - if(bandwidthList.size() > 1) + if(bandwidthList.size() > 2) conf["bandwidth"] = uiBandwidthId; if (hasAgc) { conf["agc"] = agc; @@ -289,7 +289,7 @@ private: _this->dev->setGain(SOAPY_SDR_RX, _this->channelId, gain, _this->uiGains[i]); i++; } - if(_this->bandwidthList.size() > 1) { + if(_this->bandwidthList.size() > 2) { if(_this->bandwidthList[_this->uiBandwidthId] == -1) _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId])); else @@ -353,7 +353,7 @@ private: if (ImGui::Combo(CONCAT("##_sr_select_", _this->name), &_this->srId, _this->txtSrList.c_str())) { _this->selectSampleRate(_this->sampleRates[_this->srId]); - if(_this->bandwidthList.size() > 1 && _this->running && _this->bandwidthList[_this->uiBandwidthId] == -1) + if(_this->bandwidthList.size() > 2 && _this->running && _this->bandwidthList[_this->uiBandwidthId] == -1) _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId])); _this->saveCurrent(); } @@ -413,7 +413,7 @@ private: } i++; } - if(_this->bandwidthList.size() > 1) { + if(_this->bandwidthList.size() > 2) { float bwLen = ImGui::CalcTextSize("Bandwidth").x + 5.0f; ImGui::Text("Bandwidth"); ImGui::SameLine();