diff --git a/CMakeLists.txt b/CMakeLists.txt index 98eded18..b7a11028 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ option(OPT_BUILD_FALCON9_DECODER "Build the falcon9 live decoder (Dependencies: option(OPT_BUILD_M17_DECODER "Build the M17 decoder module (no dependencies required)" OFF) option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dependencies required)" ON) option(OPT_BUILD_RADIO "Main audio modulation decoder (AM, FM, SSB, etc...)" ON) -option(OPT_BUILD_NEW_RADIO "Beta Main audio modulation decoder (AM, FM, SSB, etc...)" ON) option(OPT_BUILD_WEATHER_SAT_DECODER "Build the HRPT decoder module (no dependencies required)" OFF) # Misc @@ -148,10 +147,6 @@ if (OPT_BUILD_RADIO) add_subdirectory("decoder_modules/radio") endif (OPT_BUILD_RADIO) -if (OPT_BUILD_NEW_RADIO) -add_subdirectory("decoder_modules/new_radio") -endif (OPT_BUILD_NEW_RADIO) - if (OPT_BUILD_WEATHER_SAT_DECODER) add_subdirectory("decoder_modules/weather_sat_decoder") endif (OPT_BUILD_WEATHER_SAT_DECODER) diff --git a/decoder_modules/new_radio/CMakeLists.txt b/decoder_modules/new_radio/CMakeLists.txt deleted file mode 100644 index 4e1f2268..00000000 --- a/decoder_modules/new_radio/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 3.13) -project(new_radio) - -file(GLOB_RECURSE SRC "src/*.cpp") - -add_library(new_radio SHARED ${SRC}) -target_link_libraries(new_radio PRIVATE sdrpp_core) -set_target_properties(new_radio PROPERTIES PREFIX "") - -target_include_directories(new_radio PRIVATE "src/") - -if (MSVC) - target_compile_options(new_radio PRIVATE /O2 /Ob2 /std:c++17 /EHsc) -elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - target_compile_options(new_radio PRIVATE -O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup) -else () - target_compile_options(new_radio PRIVATE -O3 -std=c++17) -endif () - -# Install directives -install(TARGETS new_radio DESTINATION lib/sdrpp/plugins) \ No newline at end of file diff --git a/decoder_modules/new_radio/src/main.cpp b/decoder_modules/new_radio/src/main.cpp deleted file mode 100644 index f045cc8d..00000000 --- a/decoder_modules/new_radio/src/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "radio_module.h" -#include - -SDRPP_MOD_INFO { - /* Name: */ "new_radio", - /* Description: */ "Analog radio decoder", - /* Author: */ "Ryzerth", - /* Version: */ 2, 0, 0, - /* Max instances */ -1 -}; - -MOD_EXPORT void _INIT_() { - json def = json({}); - config.setPath(options::opts.root + "/new_radio_config.json"); - config.load(def); - config.enableAutoSave(); -} - -MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { - return new NewRadioModule(name); -} - -MOD_EXPORT void _DELETE_INSTANCE_(void* instance) { - delete (NewRadioModule*)instance; -} - -MOD_EXPORT void _END_() { - config.disableAutoSave(); - config.save(); -} \ No newline at end of file diff --git a/decoder_modules/radio/CMakeLists.txt b/decoder_modules/radio/CMakeLists.txt index 1360a224..f554f2a8 100644 --- a/decoder_modules/radio/CMakeLists.txt +++ b/decoder_modules/radio/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.13) project(radio) -file(GLOB SRC "src/*.cpp") +file(GLOB_RECURSE SRC "src/*.cpp") add_library(radio SHARED ${SRC}) target_link_libraries(radio PRIVATE sdrpp_core) diff --git a/decoder_modules/radio/src/am_demod.h b/decoder_modules/radio/src/am_demod.h deleted file mode 100644 index 0135ea4f..00000000 --- a/decoder_modules/radio/src/am_demod.h +++ /dev/null @@ -1,219 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - - -class AMDemodulator : public Demodulator { -public: - AMDemodulator() {} - AMDemodulator(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - init(prefix, vfo, audioSampleRate, bandWidth, config); - } - - void init(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - uiPrefix = prefix; - _vfo = vfo; - audioSampRate = audioSampleRate; - bw = bandWidth; - _config = config; - - _config->acquire(); - if(_config->conf.contains(prefix)) { - if(!_config->conf[prefix].contains("AM")) { - _config->conf[prefix]["AM"]["bandwidth"] = bw; - _config->conf[prefix]["AM"]["snapInterval"] = snapInterval; - _config->conf[prefix]["AM"]["squelchLevel"] = squelchLevel; - } - json conf = _config->conf[prefix]["AM"]; - if (conf.contains("bandwidth")) { bw = conf["bandwidth"]; } - if (conf.contains("snapInterval")) { snapInterval = conf["snapInterval"]; } - if (conf.contains("squelchLevel")) { squelchLevel = conf["squelchLevel"]; } - } - else { - _config->conf[prefix]["AM"]["bandwidth"] = bw; - _config->conf[prefix]["AM"]["snapInterval"] = snapInterval; - _config->conf[prefix]["AM"]["squelchLevel"] = squelchLevel; - } - _config->release(true); - - squelch.init(_vfo->output, squelchLevel); - - demod.init(&squelch.out); - - agc.init(&demod.out, 20.0f, bbSampRate); - - float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); - win.init(audioBW, audioBW, bbSampRate); - resamp.init(&agc.out, &win, bbSampRate, audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - resamp.updateWindow(&win); - - m2s.init(&resamp.out); - - onUserChangedBandwidthHandler.handler = vfoUserChangedBandwidthHandler; - onUserChangedBandwidthHandler.ctx = this; - - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - void start() { - squelch.start(); - demod.start(); - agc.start(); - resamp.start(); - m2s.start(); - running = true; - } - - void stop() { - squelch.stop(); - demod.stop(); - agc.stop(); - resamp.stop(); - m2s.stop(); - running = false; - } - - bool isRunning() { - return running; - } - - void select() { - _vfo->setSampleRate(bbSampRate, bw); - _vfo->setSnapInterval(snapInterval); - _vfo->setReference(ImGui::WaterfallVFO::REF_CENTER); - _vfo->setBandwidthLimits(bwMin, bwMax, false); - } - - void setVFO(VFOManager::VFO* vfo) { - _vfo = vfo; - squelch.setInput(_vfo->output); - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - VFOManager::VFO* getVFO() { - return _vfo; - } - - void setAudioSampleRate(float sampleRate) { - if (running) { - resamp.stop(); - } - audioSampRate = sampleRate; - float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); - resamp.setOutSampleRate(audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - if (running) { - resamp.start(); - } - } - - float getAudioSampleRate() { - return audioSampRate; - } - - dsp::stream* getOutput() { - return &m2s.out; - } - - void showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - - ImGui::SetNextItemWidth(menuWidth); - if (ImGui::InputFloat(("##_radio_am_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) { - bw = std::clamp(bw, bwMin, bwMax); - setBandwidth(bw); - _config->acquire(); - _config->conf[uiPrefix]["AM"]["bandwidth"] = bw; - _config->release(true); - } - - ImGui::LeftLabel("Snap Interval"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::InputFloat(("##_radio_am_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) { - if (snapInterval < 1) { snapInterval = 1; } - setSnapInterval(snapInterval); - _config->acquire(); - _config->conf[uiPrefix]["AM"]["snapInterval"] = snapInterval; - _config->release(true); - } - - ImGui::LeftLabel("Squelch"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_am_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { - squelch.setLevel(squelchLevel); - _config->acquire(); - _config->conf[uiPrefix]["AM"]["squelchLevel"] = squelchLevel; - _config->release(true); - } - } - - static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { - AMDemodulator* _this = (AMDemodulator*)ctx; - if (_this->running) { - _this->bw = newBw; - _this->setBandwidth(_this->bw, false); - _this->_config->acquire(); - _this->_config->conf[_this->uiPrefix]["AM"]["bandwidth"] = _this->bw; - _this->_config->release(true); - } - } - - void setBandwidth(float bandWidth, bool updateWaterfall = true) { - bandWidth = std::clamp(bandWidth, bwMin, bwMax); - bw = bandWidth; - _vfo->setBandwidth(bw, updateWaterfall); - float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - } - - void saveParameters(bool lock = true) { - if (lock) { _config->acquire(); } - _config->conf[uiPrefix]["AM"]["bandwidth"] = bw; - _config->conf[uiPrefix]["AM"]["snapInterval"] = snapInterval; - _config->conf[uiPrefix]["AM"]["squelchLevel"] = squelchLevel; - if (lock) { _config->release(true); } - } - -private: - void setSnapInterval(float snapInt) { - snapInterval = snapInt; - _vfo->setSnapInterval(snapInterval); - } - - const float bwMax = 15000; - const float bwMin = 1000; - const float bbSampRate = 15000; - - std::string uiPrefix; - float snapInterval = 1000; - float audioSampRate = 48000; - float bw = 12500; - bool running = false; - float squelchLevel = -100.0f; - - VFOManager::VFO* _vfo; - dsp::Squelch squelch; - dsp::AMDemod demod; - dsp::AGC agc; - dsp::filter_window::BlackmanWindow win; - dsp::PolyphaseResampler resamp; - dsp::MonoToStereo m2s; - - ConfigManager* _config; - - EventHandler onUserChangedBandwidthHandler; - -}; \ No newline at end of file diff --git a/decoder_modules/radio/src/cw_demod.h b/decoder_modules/radio/src/cw_demod.h deleted file mode 100644 index e897c6e6..00000000 --- a/decoder_modules/radio/src/cw_demod.h +++ /dev/null @@ -1,224 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - - -class CWDemodulator : public Demodulator { -public: - CWDemodulator() {} - CWDemodulator(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - init(prefix, vfo, audioSampleRate, bandWidth, config); - } - - void init(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - uiPrefix = prefix; - _vfo = vfo; - audioSampRate = audioSampleRate; - bw = bandWidth; - _config = config; - - _config->acquire(); - if(_config->conf.contains(prefix)) { - if(!_config->conf[prefix].contains("CW")) { - _config->conf[prefix]["CW"]["bandwidth"] = bw; - _config->conf[prefix]["CW"]["snapInterval"] = snapInterval; - _config->conf[prefix]["CW"]["squelchLevel"] = squelchLevel; - } - json conf = _config->conf[prefix]["CW"]; - if (conf.contains("bandwidth")) { bw = conf["bandwidth"]; } - if (conf.contains("snapInterval")) { snapInterval = conf["snapInterval"]; } - if (conf.contains("squelchLevel")) { squelchLevel = conf["squelchLevel"]; } - } - else { - _config->conf[prefix]["CW"]["bandwidth"] = bw; - _config->conf[prefix]["CW"]["snapInterval"] = snapInterval; - _config->conf[prefix]["CW"]["squelchLevel"] = squelchLevel; - } - _config->release(true); - - squelch.init(_vfo->output, squelchLevel); - - xlator.init(&squelch.out, bbSampRate, 1000.0f); - - c2r.init(&xlator.out); - - agc.init(&c2r.out, 20.0f, bbSampRate); - - float audioBW = std::min(audioSampRate / 2.0f, (bw / 2.0f) + 1000.0f); - win.init(audioBW, audioBW, bbSampRate); - resamp.init(&agc.out, &win, bbSampRate, audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - resamp.updateWindow(&win); - - m2s.init(&resamp.out); - - onUserChangedBandwidthHandler.handler = vfoUserChangedBandwidthHandler; - onUserChangedBandwidthHandler.ctx = this; - - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - void start() { - squelch.start(); - xlator.start(); - c2r.start(); - agc.start(); - resamp.start(); - m2s.start(); - running = true; - } - - void stop() { - squelch.stop(); - xlator.stop(); - c2r.stop(); - agc.stop(); - resamp.stop(); - m2s.stop(); - running = false; - } - - bool isRunning() { - return running; - } - - void select() { - _vfo->setSampleRate(bbSampRate, bw); - _vfo->setSnapInterval(snapInterval); - _vfo->setReference(ImGui::WaterfallVFO::REF_CENTER); - _vfo->setBandwidthLimits(bwMin, bwMax, false); - } - - void setVFO(VFOManager::VFO* vfo) { - _vfo = vfo; - squelch.setInput(_vfo->output); - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - VFOManager::VFO* getVFO() { - return _vfo; - } - - void setAudioSampleRate(float sampleRate) { - if (running) { - resamp.stop(); - } - audioSampRate = sampleRate; - float audioBW = std::min(audioSampRate / 2.0f, (bw / 2.0f) + 1000.0f); - resamp.setOutSampleRate(audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - if (running) { - resamp.start(); - } - } - - float getAudioSampleRate() { - return audioSampRate; - } - - dsp::stream* getOutput() { - return &m2s.out; - } - - void showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - - ImGui::SetNextItemWidth(menuWidth); - if (ImGui::InputFloat(("##_radio_cw_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) { - bw = std::clamp(bw, bwMin, bwMax); - setBandwidth(bw); - _config->acquire(); - _config->conf[uiPrefix]["CW"]["bandwidth"] = bw; - _config->release(true); - } - - ImGui::LeftLabel("Snap Interval"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::InputFloat(("##_radio_cw_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) { - if (snapInterval < 1) { snapInterval = 1; } - setSnapInterval(snapInterval); - _config->acquire(); - _config->conf[uiPrefix]["CW"]["snapInterval"] = snapInterval; - _config->release(true); - } - - ImGui::LeftLabel("Squelch"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_cw_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { - squelch.setLevel(squelchLevel); - _config->acquire(); - _config->conf[uiPrefix]["CW"]["squelchLevel"] = squelchLevel; - _config->release(true); - } - } - - static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { - CWDemodulator* _this = (CWDemodulator*)ctx; - if (_this->running) { - _this->bw = newBw; - _this->setBandwidth(_this->bw, false); - _this->_config->acquire(); - _this->_config->conf[_this->uiPrefix]["CW"]["bandwidth"] = _this->bw; - _this->_config->release(true); - } - } - - void setBandwidth(float bandWidth, bool updateWaterfall = true) { - bandWidth = std::clamp(bandWidth, bwMin, bwMax); - bw = bandWidth; - _vfo->setBandwidth(bw, updateWaterfall); - float audioBW = std::min(audioSampRate / 2.0f, (bw / 2.0f) + 1000.0f); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - } - - void saveParameters(bool lock = true) { - if (lock) { _config->acquire(); } - _config->conf[uiPrefix]["CW"]["bandwidth"] = bw; - _config->conf[uiPrefix]["CW"]["snapInterval"] = snapInterval; - _config->conf[uiPrefix]["CW"]["squelchLevel"] = squelchLevel; - if (lock) { _config->release(true); } - } - -private: - void setSnapInterval(float snapInt) { - snapInterval = snapInt; - _vfo->setSnapInterval(snapInterval); - } - - const float bwMax = 500; - const float bwMin = 50; - const float bbSampRate = 3000; - - std::string uiPrefix; - float snapInterval = 10; - float audioSampRate = 48000; - float bw = 500; - bool running = false; - float squelchLevel = -100.0f; - - VFOManager::VFO* _vfo; - dsp::Squelch squelch; - dsp::FrequencyXlator xlator; - dsp::ComplexToReal c2r; - dsp::AGC agc; - dsp::filter_window::BlackmanWindow win; - dsp::PolyphaseResampler resamp; - dsp::MonoToStereo m2s; - - ConfigManager* _config; - - EventHandler onUserChangedBandwidthHandler; - -}; \ No newline at end of file diff --git a/decoder_modules/new_radio/src/demod.h b/decoder_modules/radio/src/demod.h similarity index 100% rename from decoder_modules/new_radio/src/demod.h rename to decoder_modules/radio/src/demod.h diff --git a/decoder_modules/new_radio/src/demodulators/am.h b/decoder_modules/radio/src/demodulators/am.h similarity index 100% rename from decoder_modules/new_radio/src/demodulators/am.h rename to decoder_modules/radio/src/demodulators/am.h diff --git a/decoder_modules/new_radio/src/demodulators/cw.h b/decoder_modules/radio/src/demodulators/cw.h similarity index 100% rename from decoder_modules/new_radio/src/demodulators/cw.h rename to decoder_modules/radio/src/demodulators/cw.h diff --git a/decoder_modules/new_radio/src/demodulators/dsb.h b/decoder_modules/radio/src/demodulators/dsb.h similarity index 100% rename from decoder_modules/new_radio/src/demodulators/dsb.h rename to decoder_modules/radio/src/demodulators/dsb.h diff --git a/decoder_modules/new_radio/src/demodulators/lsb.h b/decoder_modules/radio/src/demodulators/lsb.h similarity index 100% rename from decoder_modules/new_radio/src/demodulators/lsb.h rename to decoder_modules/radio/src/demodulators/lsb.h diff --git a/decoder_modules/new_radio/src/demodulators/nfm.h b/decoder_modules/radio/src/demodulators/nfm.h similarity index 100% rename from decoder_modules/new_radio/src/demodulators/nfm.h rename to decoder_modules/radio/src/demodulators/nfm.h diff --git a/decoder_modules/new_radio/src/demodulators/raw.h b/decoder_modules/radio/src/demodulators/raw.h similarity index 100% rename from decoder_modules/new_radio/src/demodulators/raw.h rename to decoder_modules/radio/src/demodulators/raw.h diff --git a/decoder_modules/new_radio/src/demodulators/usb.h b/decoder_modules/radio/src/demodulators/usb.h similarity index 100% rename from decoder_modules/new_radio/src/demodulators/usb.h rename to decoder_modules/radio/src/demodulators/usb.h diff --git a/decoder_modules/new_radio/src/demodulators/wfm.h b/decoder_modules/radio/src/demodulators/wfm.h similarity index 100% rename from decoder_modules/new_radio/src/demodulators/wfm.h rename to decoder_modules/radio/src/demodulators/wfm.h diff --git a/decoder_modules/radio/src/dsb_demod.h b/decoder_modules/radio/src/dsb_demod.h deleted file mode 100644 index 62fbaeaa..00000000 --- a/decoder_modules/radio/src/dsb_demod.h +++ /dev/null @@ -1,214 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - - -class DSBDemodulator : public Demodulator { -public: - DSBDemodulator() {} - DSBDemodulator(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - init(prefix, vfo, audioSampleRate, bandWidth, config); - } - - void init(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - uiPrefix = prefix; - _vfo = vfo; - audioSampRate = audioSampleRate; - bw = bandWidth; - _config = config; - - _config->acquire(); - if(_config->conf.contains(prefix)) { - if(!_config->conf[prefix].contains("DSB")) { - _config->conf[prefix]["DSB"]["bandwidth"] = bw; - _config->conf[prefix]["DSB"]["snapInterval"] = snapInterval; - _config->conf[prefix]["DSB"]["squelchLevel"] = squelchLevel; - } - json conf = _config->conf[prefix]["DSB"]; - if (conf.contains("bandwidth")) { bw = conf["bandwidth"]; } - if (conf.contains("snapInterval")) { snapInterval = conf["snapInterval"]; } - if (conf.contains("squelchLevel")) { squelchLevel = conf["squelchLevel"]; } - } - else { - _config->conf[prefix]["DSB"]["bandwidth"] = bw; - _config->conf[prefix]["DSB"]["snapInterval"] = snapInterval; - _config->conf[prefix]["DSB"]["squelchLevel"] = squelchLevel; - } - _config->release(true); - - squelch.init(_vfo->output, squelchLevel); - - demod.init(&squelch.out, bbSampRate, bw, dsp::SSBDemod::MODE_DSB); - - agc.init(&demod.out, 20.0f, bbSampRate); - - float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); - win.init(audioBW, audioBW, bbSampRate); - resamp.init(&agc.out, &win, bbSampRate, audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - resamp.updateWindow(&win); - - m2s.init(&resamp.out); - - onUserChangedBandwidthHandler.handler = vfoUserChangedBandwidthHandler; - onUserChangedBandwidthHandler.ctx = this; - - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - void start() { - squelch.start(); - demod.start(); - agc.start(); - resamp.start(); - m2s.start(); - running = true; - } - - void stop() { - squelch.stop(); - demod.stop(); - agc.stop(); - resamp.stop(); - m2s.stop(); - running = false; - } - - bool isRunning() { - return running; - } - - void select() { - _vfo->setSampleRate(bbSampRate, bw); - _vfo->setSnapInterval(snapInterval); - _vfo->setReference(ImGui::WaterfallVFO::REF_CENTER); - _vfo->setBandwidthLimits(bwMin, bwMax, false); - } - - void setVFO(VFOManager::VFO* vfo) { - _vfo = vfo; - squelch.setInput(_vfo->output); - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - VFOManager::VFO* getVFO() { - return _vfo; - } - - void setAudioSampleRate(float sampleRate) { - if (running) { - resamp.stop(); - } - audioSampRate = sampleRate; - float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); - resamp.setOutSampleRate(audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - if (running) { - resamp.start(); - } - } - - float getAudioSampleRate() { - return audioSampRate; - } - - dsp::stream* getOutput() { - return &m2s.out; - } - - void showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - - ImGui::SetNextItemWidth(menuWidth); - if (ImGui::InputFloat(("##_radio_dsb_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) { - bw = std::clamp(bw, bwMin, bwMax); - setBandwidth(bw); - _config->acquire(); - _config->conf[uiPrefix]["DSB"]["bandwidth"] = bw; - _config->release(true); - } - - ImGui::LeftLabel("Snap Interval"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::InputFloat(("##_radio_dsb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) { - if (snapInterval < 1) { snapInterval = 1; } - setSnapInterval(snapInterval); - _config->acquire(); - _config->conf[uiPrefix]["DSB"]["snapInterval"] = snapInterval; - _config->release(true); - } - - ImGui::LeftLabel("Squelch"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_dsb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { - squelch.setLevel(squelchLevel); - _config->acquire(); - _config->conf[uiPrefix]["DSB"]["squelchLevel"] = squelchLevel; - _config->release(true); - } - } - - static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { - DSBDemodulator* _this = (DSBDemodulator*)ctx; - if (_this->running) { - _this->bw = newBw; - _this->setBandwidth(_this->bw, false); - _this->_config->acquire(); - _this->_config->conf[_this->uiPrefix]["DSB"]["bandwidth"] = _this->bw; - _this->_config->release(true); - } - } - - void setBandwidth(float bandWidth, bool updateWaterfall = true) { - bandWidth = std::clamp(bandWidth, bwMin, bwMax); - bw = bandWidth; - _vfo->setBandwidth(bw, updateWaterfall); - } - - void saveParameters(bool lock = true) { - if (lock) { _config->acquire(); } - _config->conf[uiPrefix]["DSB"]["bandwidth"] = bw; - _config->conf[uiPrefix]["DSB"]["snapInterval"] = snapInterval; - _config->conf[uiPrefix]["DSB"]["squelchLevel"] = squelchLevel; - if (lock) { _config->release(true); } - } - -private: - void setSnapInterval(float snapInt) { - snapInterval = snapInt; - _vfo->setSnapInterval(snapInterval); - } - - const float bwMax = 12000; - const float bwMin = 1000; - const float bbSampRate = 12000; - - std::string uiPrefix; - float snapInterval = 100; - float audioSampRate = 48000; - float bw = 6000; - bool running = false; - float squelchLevel = -100.0f; - - VFOManager::VFO* _vfo; - dsp::Squelch squelch; - dsp::SSBDemod demod; - dsp::AGC agc; - dsp::filter_window::BlackmanWindow win; - dsp::PolyphaseResampler resamp; - dsp::MonoToStereo m2s; - - ConfigManager* _config; - - EventHandler onUserChangedBandwidthHandler; - -}; \ No newline at end of file diff --git a/decoder_modules/radio/src/fm_demod.h b/decoder_modules/radio/src/fm_demod.h deleted file mode 100644 index 36258807..00000000 --- a/decoder_modules/radio/src/fm_demod.h +++ /dev/null @@ -1,206 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - - -class FMDemodulator : public Demodulator { -public: - FMDemodulator() {} - FMDemodulator(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - init(prefix, vfo, audioSampleRate, bandWidth, config); - } - - void init(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - uiPrefix = prefix; - _vfo = vfo; - audioSampRate = audioSampleRate; - bw = bandWidth; - _config = config; - - _config->acquire(); - if(_config->conf.contains(prefix)) { - if(!_config->conf[prefix].contains("FM")) { - _config->conf[prefix]["FM"]["bandwidth"] = bw; - _config->conf[prefix]["FM"]["snapInterval"] = snapInterval; - _config->conf[prefix]["FM"]["squelchLevel"] = squelchLevel; - } - json conf = _config->conf[prefix]["FM"]; - if (conf.contains("bandwidth")) { bw = conf["bandwidth"]; } - if (conf.contains("snapInterval")) { snapInterval = conf["snapInterval"]; } - if (conf.contains("squelchLevel")) { squelchLevel = conf["squelchLevel"]; } - } - else { - _config->conf[prefix]["FM"]["bandwidth"] = bw; - _config->conf[prefix]["FM"]["snapInterval"] = snapInterval; - _config->conf[prefix]["FM"]["squelchLevel"] = squelchLevel; - } - _config->release(true); - - squelch.init(_vfo->output, squelchLevel); - - demod.init(&squelch.out, bbSampRate, bw / 2.0f); - - float audioBW = std::min(audioSampleRate / 2.0f, bw / 2.0f); - win.init(audioBW, audioBW, bbSampRate); - resamp.init(&demod.out, &win, bbSampRate, audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - resamp.updateWindow(&win); - - onUserChangedBandwidthHandler.handler = vfoUserChangedBandwidthHandler; - onUserChangedBandwidthHandler.ctx = this; - - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - void start() { - squelch.start(); - demod.start(); - resamp.start(); - running = true; - } - - void stop() { - squelch.stop(); - demod.stop(); - resamp.stop(); - running = false; - } - - bool isRunning() { - return running; - } - - void select() { - _vfo->setSampleRate(bbSampRate, bw); - _vfo->setSnapInterval(snapInterval); - _vfo->setReference(ImGui::WaterfallVFO::REF_CENTER); - _vfo->setBandwidthLimits(bwMin, bwMax, false); - } - - void setVFO(VFOManager::VFO* vfo) { - _vfo = vfo; - squelch.setInput(_vfo->output); - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - VFOManager::VFO* getVFO() { - return _vfo; - } - - void setAudioSampleRate(float sampleRate) { - if (running) { - resamp.stop(); - } - audioSampRate = sampleRate; - float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); - resamp.setOutSampleRate(audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - if (running) { - resamp.start(); - } - } - - float getAudioSampleRate() { - return audioSampRate; - } - - dsp::stream* getOutput() { - return &resamp.out; - } - - void showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - - ImGui::SetNextItemWidth(menuWidth); - if (ImGui::InputFloat(("##_radio_fm_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) { - bw = std::clamp(bw, bwMin, bwMax); - setBandwidth(bw); - _config->acquire(); - _config->conf[uiPrefix]["FM"]["bandwidth"] = bw; - _config->release(true); - } - - ImGui::LeftLabel("Snap Interval"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::InputFloat(("##_radio_fm_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) { - if (snapInterval < 1) { snapInterval = 1; } - setSnapInterval(snapInterval); - _config->acquire(); - _config->conf[uiPrefix]["FM"]["snapInterval"] = snapInterval; - _config->release(true); - } - - ImGui::LeftLabel("Squelch"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_fm_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { - squelch.setLevel(squelchLevel); - _config->acquire(); - _config->conf[uiPrefix]["FM"]["squelchLevel"] = squelchLevel; - _config->release(true); - } - } - - static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { - FMDemodulator* _this = (FMDemodulator*)ctx; - if (_this->running) { - _this->bw = newBw; - _this->setBandwidth(_this->bw, false); - _this->_config->acquire(); - _this->_config->conf[_this->uiPrefix]["FM"]["bandwidth"] = _this->bw; - _this->_config->release(true); - } - } - - void setBandwidth(float bandWidth, bool updateWaterfall = true) { - bandWidth = std::clamp(bandWidth, bwMin, bwMax); - bw = bandWidth; - _vfo->setBandwidth(bw, updateWaterfall); - demod.setDeviation(bw / 2.0f); - setAudioSampleRate(audioSampRate); - } - - void saveParameters(bool lock = true) { - if (lock) { _config->acquire(); } - _config->conf[uiPrefix]["FM"]["bandwidth"] = bw; - _config->conf[uiPrefix]["FM"]["snapInterval"] = snapInterval; - _config->conf[uiPrefix]["FM"]["squelchLevel"] = squelchLevel; - if (lock) { _config->release(true); } - } - -private: - void setSnapInterval(float snapInt) { - snapInterval = snapInt; - _vfo->setSnapInterval(snapInterval); - } - - const float bwMax = 50000; - const float bwMin = 1000; - const float bbSampRate = 50000; - - std::string uiPrefix; - float snapInterval = 2500; - float audioSampRate = 48000; - float bw = 50000; - bool running = false; - float squelchLevel = -100.0f; - - VFOManager::VFO* _vfo; - dsp::Squelch squelch; - dsp::FMDemod demod; - dsp::filter_window::BlackmanWindow win; - dsp::PolyphaseResampler resamp; - - ConfigManager* _config; - - EventHandler onUserChangedBandwidthHandler; - -}; \ No newline at end of file diff --git a/decoder_modules/radio/src/lsb_demod.h b/decoder_modules/radio/src/lsb_demod.h deleted file mode 100644 index 0dd688c5..00000000 --- a/decoder_modules/radio/src/lsb_demod.h +++ /dev/null @@ -1,220 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - - -class LSBDemodulator : public Demodulator { -public: - LSBDemodulator() {} - LSBDemodulator(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - init(prefix, vfo, audioSampleRate, bandWidth, config); - } - - void init(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - uiPrefix = prefix; - _vfo = vfo; - audioSampRate = audioSampleRate; - bw = bandWidth; - _config = config; - - _config->acquire(); - if(_config->conf.contains(prefix)) { - if(!_config->conf[prefix].contains("LSB")) { - _config->conf[prefix]["LSB"]["bandwidth"] = bw; - _config->conf[prefix]["LSB"]["snapInterval"] = snapInterval; - _config->conf[prefix]["LSB"]["squelchLevel"] = squelchLevel; - } - json conf = _config->conf[prefix]["LSB"]; - if (conf.contains("bandwidth")) { bw = conf["bandwidth"]; } - if (conf.contains("snapInterval")) { snapInterval = conf["snapInterval"]; } - if (conf.contains("squelchLevel")) { squelchLevel = conf["squelchLevel"]; } - } - else { - _config->conf[prefix]["LSB"]["bandwidth"] = bw; - _config->conf[prefix]["LSB"]["snapInterval"] = snapInterval; - _config->conf[prefix]["LSB"]["squelchLevel"] = squelchLevel; - } - _config->release(true); - - squelch.init(_vfo->output, squelchLevel); - - demod.init(&squelch.out, bbSampRate, bw, dsp::SSBDemod::MODE_LSB); - - agc.init(&demod.out, 20.0f, bbSampRate); - - float audioBW = std::min(audioSampRate / 2.0f, bw); - win.init(audioBW, audioBW, bbSampRate); - resamp.init(&agc.out, &win, bbSampRate, audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - resamp.updateWindow(&win); - - m2s.init(&resamp.out); - - onUserChangedBandwidthHandler.handler = vfoUserChangedBandwidthHandler; - onUserChangedBandwidthHandler.ctx = this; - - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - void start() { - squelch.start(); - demod.start(); - agc.start(); - resamp.start(); - m2s.start(); - running = true; - } - - void stop() { - squelch.stop(); - demod.stop(); - agc.stop(); - resamp.stop(); - m2s.stop(); - running = false; - } - - bool isRunning() { - return running; - } - - void select() { - _vfo->setSampleRate(bbSampRate, bw); - _vfo->setSnapInterval(snapInterval); - _vfo->setReference(ImGui::WaterfallVFO::REF_UPPER); - _vfo->setBandwidthLimits(bwMin, bwMax, false); - } - - void setVFO(VFOManager::VFO* vfo) { - _vfo = vfo; - squelch.setInput(_vfo->output); - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - VFOManager::VFO* getVFO() { - return _vfo; - } - - void setAudioSampleRate(float sampleRate) { - if (running) { - resamp.stop(); - } - audioSampRate = sampleRate; - float audioBW = std::min(audioSampRate / 2.0f, bw); - resamp.setOutSampleRate(audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - if (running) { - resamp.start(); - } - } - - float getAudioSampleRate() { - return audioSampRate; - } - - dsp::stream* getOutput() { - return &m2s.out; - } - - void showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - - ImGui::SetNextItemWidth(menuWidth); - if (ImGui::InputFloat(("##_radio_lsb_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) { - bw = std::clamp(bw, bwMin, bwMax); - setBandwidth(bw); - _config->acquire(); - _config->conf[uiPrefix]["LSB"]["bandwidth"] = bw; - _config->release(true); - } - - ImGui::LeftLabel("Snap Interval"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::InputFloat(("##_radio_lsb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) { - if (snapInterval < 1) { snapInterval = 1; } - setSnapInterval(snapInterval); - _config->acquire(); - _config->conf[uiPrefix]["LSB"]["snapInterval"] = snapInterval; - _config->release(true); - } - - ImGui::LeftLabel("Squelch"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_lsb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { - squelch.setLevel(squelchLevel); - _config->acquire(); - _config->conf[uiPrefix]["LSB"]["squelchLevel"] = squelchLevel; - _config->release(true); - } - } - - static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { - LSBDemodulator* _this = (LSBDemodulator*)ctx; - if (_this->running) { - _this->bw = newBw; - _this->setBandwidth(_this->bw, false); - _this->_config->acquire(); - _this->_config->conf[_this->uiPrefix]["LSB"]["bandwidth"] = _this->bw; - _this->_config->release(true); - } - } - - void setBandwidth(float bandWidth, bool updateWaterfall = true) { - bandWidth = std::clamp(bandWidth, bwMin, bwMax); - bw = bandWidth; - _vfo->setBandwidth(bw, updateWaterfall); - demod.setBandWidth(bw); - float audioBW = std::min(audioSampRate / 2.0f, bw); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - } - - void saveParameters(bool lock = true) { - if (lock) { _config->acquire(); } - _config->conf[uiPrefix]["LSB"]["bandwidth"] = bw; - _config->conf[uiPrefix]["LSB"]["snapInterval"] = snapInterval; - _config->conf[uiPrefix]["LSB"]["squelchLevel"] = squelchLevel; - if (lock) { _config->release(true); } - } - -private: - void setSnapInterval(float snapInt) { - snapInterval = snapInt; - _vfo->setSnapInterval(snapInterval); - } - - const float bwMax = 12000; - const float bwMin = 500; - const float bbSampRate = 24000; - - std::string uiPrefix; - float snapInterval = 100; - float audioSampRate = 48000; - float bw = 3000; - bool running = false; - float squelchLevel = -100.0f; - - VFOManager::VFO* _vfo; - dsp::Squelch squelch; - dsp::SSBDemod demod; - dsp::AGC agc; - dsp::filter_window::BlackmanWindow win; - dsp::PolyphaseResampler resamp; - dsp::MonoToStereo m2s; - - ConfigManager* _config; - - EventHandler onUserChangedBandwidthHandler; - -}; \ No newline at end of file diff --git a/decoder_modules/radio/src/main.cpp b/decoder_modules/radio/src/main.cpp index 0f89d7d0..f1bc4ebe 100644 --- a/decoder_modules/radio/src/main.cpp +++ b/decoder_modules/radio/src/main.cpp @@ -1,237 +1,14 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "radio_module.h" #include -#include - -#define CONCAT(a, b) ((std::string(a) + b).c_str()) SDRPP_MOD_INFO { /* Name: */ "radio", - /* Description: */ "Radio module for SDR++", + /* Description: */ "Analog radio decoder", /* Author: */ "Ryzerth", - /* Version: */ 0, 3, 0, + /* Version: */ 2, 0, 0, /* Max instances */ -1 }; -static ConfigManager config; - -class RadioModule : public ModuleManager::Instance { -public: - RadioModule(std::string name) { - this->name = name; - - vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 200000, 200000, 50000, 200000, false); - - ns.init(vfo->output); - - config.acquire(); - if (!config.conf.contains(name)) { - config.conf[name]["selectedDemodId"] = 1; - } - demodId = config.conf[name]["selectedDemodId"]; - config.release(true); - - wfmDemod.init(name, vfo, audioSampRate, 200000, &config); - fmDemod.init(name, vfo, audioSampRate, 12500, &config); - amDemod.init(name, vfo, audioSampRate, 12500, &config); - usbDemod.init(name, vfo, audioSampRate, 3000, &config); - lsbDemod.init(name, vfo, audioSampRate, 3000, &config); - dsbDemod.init(name, vfo, audioSampRate, 6000, &config); - rawDemod.init(name, vfo, audioSampRate, audioSampRate, &config); - cwDemod.init(name, vfo, audioSampRate, 200, &config); - - srChangeHandler.ctx = this; - srChangeHandler.handler = sampleRateChangeHandler; - stream.init(wfmDemod.getOutput(), &srChangeHandler, audioSampRate); - sigpath::sinkManager.registerStream(name, &stream); - - selectDemodById(demodId); - - stream.start(); - - gui::menu.registerEntry(name, menuHandler, this, this); - - core::modComManager.registerInterface("radio", name, moduleInterfaceHandler, this); - } - - ~RadioModule() { - core::modComManager.unregisterInterface(name); - gui::menu.removeEntry(name); - stream.stop(); - if (enabled) { - currentDemod->stop(); - sigpath::vfoManager.deleteVFO(vfo); - } - sigpath::sinkManager.unregisterStream(name); - } - - void postInit() {} - - void enable() { - double bw = gui::waterfall.getBandwidth(); - vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp(0, -bw/2.0, bw/2.0), 200000, 200000, 50000, 200000, false); - - wfmDemod.setVFO(vfo); - fmDemod.setVFO(vfo); - amDemod.setVFO(vfo); - usbDemod.setVFO(vfo); - lsbDemod.setVFO(vfo); - dsbDemod.setVFO(vfo); - rawDemod.setVFO(vfo); - cwDemod.setVFO(vfo); - - currentDemod->select(); - currentDemod->start(); - enabled = true; - } - - void disable() { - currentDemod->stop(); - sigpath::vfoManager.deleteVFO(vfo); - enabled = false; - } - - bool isEnabled() { - return enabled; - } - -private: - static void menuHandler(void* ctx) { - RadioModule* _this = (RadioModule*)ctx; - - if (!_this->enabled) { style::beginDisabled(); } - - float menuWidth = ImGui::GetContentRegionAvailWidth(); - ImGui::BeginGroup(); - - // TODO: Change VFO ref in signal path - - ImGui::Columns(4, CONCAT("RadioModeColumns##_", _this->name), false); - if (ImGui::RadioButton(CONCAT("NFM##_", _this->name), _this->demodId == 0) && _this->demodId != 0) { - _this->selectDemodById(0); - } - if (ImGui::RadioButton(CONCAT("WFM##_", _this->name), _this->demodId == 1) && _this->demodId != 1) { - _this->selectDemodById(1); - } - ImGui::NextColumn(); - if (ImGui::RadioButton(CONCAT("AM##_", _this->name), _this->demodId == 2) && _this->demodId != 2) { - _this->selectDemodById(2); - } - if (ImGui::RadioButton(CONCAT("DSB##_", _this->name), _this->demodId == 3) && _this->demodId != 3) { - _this->selectDemodById(3); - } - ImGui::NextColumn(); - if (ImGui::RadioButton(CONCAT("USB##_", _this->name), _this->demodId == 4) && _this->demodId != 4) { - _this->selectDemodById(4); - } - if (ImGui::RadioButton(CONCAT("CW##_", _this->name), _this->demodId == 5) && _this->demodId != 5) { - _this->selectDemodById(5); - }; - ImGui::NextColumn(); - if (ImGui::RadioButton(CONCAT("LSB##_", _this->name), _this->demodId == 6) && _this->demodId != 6) { - _this->selectDemodById(6); - } - if (ImGui::RadioButton(CONCAT("RAW##_", _this->name), _this->demodId == 7) && _this->demodId != 7) { - _this->selectDemodById(7); - }; - ImGui::Columns(1, CONCAT("EndRadioModeColumns##_", _this->name), false); - - ImGui::EndGroup(); - - _this->currentDemod->showMenu(); - - if (!_this->enabled) { style::endDisabled(); } - } - - static void sampleRateChangeHandler(float sampleRate, void* ctx) { - RadioModule* _this = (RadioModule*)ctx; - // TODO: If too slow, change all demods here and not when setting - _this->audioSampRate = sampleRate; - if (_this->currentDemod != NULL) { - _this->currentDemod->setAudioSampleRate(_this->audioSampRate); - } - } - - static void moduleInterfaceHandler(int code, void* in, void* out, void* ctx) { - RadioModule* _this = (RadioModule*)ctx; - if (code == RADIO_IFACE_CMD_GET_MODE) { - int* _out = (int*)out; - *_out = _this->demodId; - } - else if (code == RADIO_IFACE_CMD_SET_MODE) { - int* _in = (int*)in; - if (*_in != _this->demodId) { _this->selectDemodById(*_in); } - } - else if (code == RADIO_IFACE_CMD_SET_BANDWIDTH) { - float* _in = (float*)in; - _this->currentDemod->setBandwidth(*_in, true); - _this->currentDemod->saveParameters(); - } - } - - void selectDemod(Demodulator* demod) { - if (currentDemod != NULL) { currentDemod->stop(); } - currentDemod = demod; - currentDemod->setAudioSampleRate(audioSampRate); - stream.setInput(currentDemod->getOutput()); - currentDemod->select(); - vfo->output->flush(); - currentDemod->start(); - } - - void selectDemodById(int id) { - demodId = id; - if (id == 0) { selectDemod(&fmDemod); } - if (id == 1) { selectDemod(&wfmDemod); } - if (id == 2) { selectDemod(&amDemod); } - if (id == 3) { selectDemod(&dsbDemod); } - if (id == 4) { selectDemod(&usbDemod); } - if (id == 5) { selectDemod(&cwDemod); } - if (id == 6) { selectDemod(&lsbDemod); } - if (id == 7) { selectDemod(&rawDemod); } - config.acquire(); - config.conf[name]["selectedDemodId"] = demodId; - config.release(true); - } - - std::string name; - bool enabled = true; - int demodId = 0; - float audioSampRate = 48000; - Demodulator* currentDemod = NULL; - - VFOManager::VFO* vfo; - - WFMDemodulator wfmDemod; - FMDemodulator fmDemod; - AMDemodulator amDemod; - USBDemodulator usbDemod; - LSBDemodulator lsbDemod; - DSBDemodulator dsbDemod; - RAWDemodulator rawDemod; - CWDemodulator cwDemod; - - dsp::NullSink ns; - - EventHandler srChangeHandler; - SinkManager::Stream stream; - -}; - MOD_EXPORT void _INIT_() { json def = json({}); config.setPath(options::opts.root + "/radio_config.json"); diff --git a/decoder_modules/radio/src/radio_demod.h b/decoder_modules/radio/src/radio_demod.h deleted file mode 100644 index e83c8b02..00000000 --- a/decoder_modules/radio/src/radio_demod.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include -#include - -class Demodulator { -public: - virtual void start() = 0; - virtual void stop() = 0; - virtual bool isRunning() = 0; - virtual void select() = 0; - virtual void setVFO(VFOManager::VFO* vfo) = 0; - virtual VFOManager::VFO* getVFO() = 0; - virtual void setAudioSampleRate(float sampleRate) = 0; - virtual float getAudioSampleRate() = 0; - virtual void setBandwidth(float bandWidth, bool updateWaterfall = true) = 0; - virtual dsp::stream* getOutput() = 0; - virtual void showMenu() = 0; - virtual void saveParameters(bool lock = true) = 0; -}; \ No newline at end of file diff --git a/decoder_modules/radio/src/radio_interface.h b/decoder_modules/radio/src/radio_interface.h index 2e95c8f3..0f33294d 100644 --- a/decoder_modules/radio/src/radio_interface.h +++ b/decoder_modules/radio/src/radio_interface.h @@ -3,7 +3,12 @@ enum { RADIO_IFACE_CMD_GET_MODE, RADIO_IFACE_CMD_SET_MODE, + RADIO_IFACE_CMD_GET_BANDWIDTH, RADIO_IFACE_CMD_SET_BANDWIDTH, + RADIO_IFACE_CMD_GET_SQUELCH_ENABLED, + RADIO_IFACE_CMD_SET_SQUELCH_ENABLED, + RADIO_IFACE_CMD_GET_SQUELCH_LEVEL, + RADIO_IFACE_CMD_SET_SQUELCH_LEVEL, }; enum { diff --git a/decoder_modules/new_radio/src/radio_module.h b/decoder_modules/radio/src/radio_module.h similarity index 83% rename from decoder_modules/new_radio/src/radio_module.h rename to decoder_modules/radio/src/radio_module.h index 509ceef7..4b7cc24f 100644 --- a/decoder_modules/new_radio/src/radio_module.h +++ b/decoder_modules/radio/src/radio_module.h @@ -7,6 +7,9 @@ #include #include #include +#include +#include "radio_interface.h" +#include "demod.h" ConfigManager config; @@ -19,12 +22,9 @@ const double DeemphasisModes[] { const char* DeemhasisModesTxt = "50µS\00075µS\000None\000"; -class NewRadioModule; -#include "demod.h" - -class NewRadioModule : public ModuleManager::Instance { +class RadioModule : public ModuleManager::Instance { public: - NewRadioModule(std::string name) { + RadioModule(std::string name) { this->name = name; // Initialize the config if it doesn't exist @@ -77,7 +77,6 @@ public: config.conf[name][demod->getName()]["snapInterval"] = demod->getDefaultSnapInterval(); config.conf[name][demod->getName()]["squelchLevel"] = MIN_SQUELCH; config.conf[name][demod->getName()]["squelchEnabled"] = false; - config.conf[name][demod->getName()]["deempMode"] = demod->getDefaultDeemphasisMode(); } bw = std::clamp(bw, demod->getMinBandwidth(), demod->getMaxBandwidth()); @@ -116,10 +115,14 @@ public: // Start stream, the rest was started when selecting the demodulator stream.start(); + // Register the menu gui::menu.registerEntry(name, menuHandler, this, this); + + // Register the module interface + core::modComManager.registerInterface("radio", name, moduleInterfaceHandler, this); } - ~NewRadioModule() { + ~RadioModule() { gui::menu.removeEntry(name); stream.stop(); if (enabled) { @@ -136,7 +139,10 @@ public: vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 200000, 200000, 50000, 200000, false); vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); } + ifChain.setInput(vfo->output); + ifChain.start(); selectDemodByID((DemodID)selectedDemodID); + afChain.start(); } void disable() { @@ -168,7 +174,7 @@ public: private: static void menuHandler(void* ctx) { - NewRadioModule* _this = (NewRadioModule*)ctx; + RadioModule* _this = (RadioModule*)ctx; if (!_this->enabled) { style::beginDisabled(); } @@ -213,12 +219,10 @@ private: if (ImGui::InputFloat(("##_radio_bw_" + _this->name).c_str(), &_this->bandwidth, 1, 100, "%.0f")) { _this->bandwidth = std::clamp(_this->bandwidth, _this->minBandwidth, _this->maxBandwidth); _this->setBandwidth(_this->bandwidth); - config.acquire(); - config.conf[_this->name][_this->selectedDemod->getName()]["bandwidth"] = _this->bandwidth; - config.release(true); } } + // VFO snap interval ImGui::LeftLabel("Snap Interval"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); if (ImGui::InputInt(("##_radio_snap_" + _this->name).c_str(), &_this->snapInterval, 1, 100)) { @@ -229,34 +233,28 @@ private: config.release(true); } + // Deemphasis mode if (_this->deempAllowed) { ImGui::LeftLabel("De-emphasis"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); if (ImGui::Combo(("##_radio_wfm_deemp_" + _this->name).c_str(), &_this->deempMode, DeemhasisModesTxt)) { _this->setDeemphasisMode(_this->deempMode); - config.acquire(); - config.conf[_this->name][_this->selectedDemod->getName()]["deempMode"] = _this->deempMode; - config.release(true); } } + // Squelch if (ImGui::Checkbox(("Squelch##_radio_sqelch_ena_" + _this->name).c_str(), &_this->squelchEnabled)) { _this->setSquelchEnabled(_this->squelchEnabled); - config.acquire(); - config.conf[_this->name][_this->selectedDemod->getName()]["squelchEnabled"] = _this->squelchEnabled; - config.release(true); } if (!_this->squelchEnabled && _this->enabled) { style::beginDisabled(); } ImGui::SameLine(); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); if (ImGui::SliderFloat(("##_radio_sqelch_lvl_" + _this->name).c_str(), &_this->squelchLevel, _this->MIN_SQUELCH, _this->MAX_SQUELCH, "%.3fdB")) { - _this->squelch.block.setLevel(_this->squelchLevel); - config.acquire(); - config.conf[_this->name][_this->selectedDemod->getName()]["squelchLevel"] = _this->squelchLevel; - config.release(true); + _this->setSquelchLevel(_this->squelchLevel); } if (!_this->squelchEnabled && _this->enabled) { style::endDisabled(); } + // Demodulator specific menu _this->selectedDemod->showMenu(); if (!_this->enabled) { style::endDisabled(); } @@ -354,6 +352,7 @@ private: void setBandwidth(double bw) { + bw = std::clamp(bw, minBandwidth, maxBandwidth); bandwidth = bw; if (!selectedDemod) { return; } float audioBW = std::min(selectedDemod->getMaxAFBandwidth(), selectedDemod->getAFBandwidth(bandwidth)); @@ -405,46 +404,112 @@ private: } void setDeemphasisMode(int mode) { - deempMode = mode; - if (!postProcEnabled) { return; } + deempMode = std::clamp(mode, 0, _DEEMP_MODE_COUNT-1); + if (!postProcEnabled || !selectedDemod) { return; } bool deempEnabled = (deempMode != DEEMP_MODE_NONE); if (deempEnabled) { deemp.block.setTau(DeemphasisModes[deempMode]); } afChain.setState(&deemp, deempEnabled); + + // Save config + config.acquire(); + config.conf[name][selectedDemod->getName()]["deempMode"] = deempMode; + config.release(true); } void setSquelchEnabled(bool enable) { squelchEnabled = enable; if (!selectedDemod) { return; } ifChain.setState(&squelch, squelchEnabled); + + // Save config + config.acquire(); + config.conf[name][selectedDemod->getName()]["squelchEnabled"] = squelchEnabled; + config.release(true); + } + + void setSquelchLevel(float level) { + squelchLevel = std::clamp(level, MIN_SQUELCH, MAX_SQUELCH); + squelch.block.setLevel(squelchLevel); + + // Save config + config.acquire(); + config.conf[name][selectedDemod->getName()]["squelchLevel"] = squelchLevel; + config.release(true); } static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { - NewRadioModule* _this = (NewRadioModule*)ctx; + RadioModule* _this = (RadioModule*)ctx; _this->setBandwidth(newBw); } static void sampleRateChangeHandler(float sampleRate, void* ctx) { - NewRadioModule* _this = (NewRadioModule*)ctx; + RadioModule* _this = (RadioModule*)ctx; _this->setAudioSampleRate(sampleRate); } static void demodOutputChangeHandler(dsp::stream* output, void* ctx) { - NewRadioModule* _this = (NewRadioModule*)ctx; + RadioModule* _this = (RadioModule*)ctx; _this->afChain.setInput(output); } static void ifChainOutputChangeHandler(dsp::stream* output, void* ctx) { - NewRadioModule* _this = (NewRadioModule*)ctx; + RadioModule* _this = (RadioModule*)ctx; if (!_this->selectedDemod) { return; } _this->selectedDemod->setInput(output); } static void afChainOutputChangeHandler(dsp::stream* output, void* ctx) { - NewRadioModule* _this = (NewRadioModule*)ctx; + RadioModule* _this = (RadioModule*)ctx; _this->stream.setInput(output); } + + static void moduleInterfaceHandler(int code, void* in, void* out, void* ctx) { + RadioModule* _this = (RadioModule*)ctx; + if (!_this->enabled || !_this->selectedDemod) { return; } + + // Execute commands + if (code == RADIO_IFACE_CMD_GET_MODE && out) { + int* _out = (int*)out; + *_out = _this->selectedDemodID; + } + else if (code == RADIO_IFACE_CMD_SET_MODE && in) { + int* _in = (int*)in; + _this->selectDemodByID((DemodID)*_in); + } + else if (code == RADIO_IFACE_CMD_GET_BANDWIDTH && out) { + float* _out = (float*)out; + *_out = _this->bandwidth; + } + else if (code == RADIO_IFACE_CMD_SET_BANDWIDTH && in) { + float* _in = (float*)in; + if (_this->bandwidthLocked) { return; } + _this->setBandwidth(*_in); + } + else if (code == RADIO_IFACE_CMD_GET_SQUELCH_ENABLED && out) { + bool* _out = (bool*)out; + *_out = _this->squelchEnabled; + } + else if (code == RADIO_IFACE_CMD_SET_SQUELCH_ENABLED && in) { + bool* _in = (bool*)in; + _this->setSquelchEnabled(*_in); + } + else if (code == RADIO_IFACE_CMD_GET_SQUELCH_LEVEL && out) { + float* _out = (float*)out; + *_out = _this->squelchLevel; + } + else if (code == RADIO_IFACE_CMD_SET_SQUELCH_LEVEL && in) { + float* _in = (float*)in; + _this->setSquelchLevel(*_in); + } + else { + return; + } + + // Success + return; + } // Handlers EventHandler onUserChangedBandwidthHandler; diff --git a/decoder_modules/radio/src/raw_demod.h b/decoder_modules/radio/src/raw_demod.h deleted file mode 100644 index cdb04d23..00000000 --- a/decoder_modules/radio/src/raw_demod.h +++ /dev/null @@ -1,144 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - - -class RAWDemodulator : public Demodulator { -public: - RAWDemodulator() {} - RAWDemodulator(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - init(prefix, vfo, audioSampleRate, bandWidth, config); - } - - void init(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - uiPrefix = prefix; - _vfo = vfo; - audioSampRate = audioSampleRate; - bw = bandWidth; - _config = config; - - _config->acquire(); - if(_config->conf.contains(prefix)) { - if(!_config->conf[prefix].contains("RAW")) { - _config->conf[prefix]["RAW"]["snapInterval"] = snapInterval; - _config->conf[prefix]["RAW"]["squelchLevel"] = squelchLevel; - } - json conf = _config->conf[prefix]["RAW"]; - if (conf.contains("snapInterval")) { snapInterval = conf["snapInterval"]; } - if (conf.contains("squelchLevel")) { squelchLevel = conf["squelchLevel"]; } - } - else { - _config->conf[prefix]["RAW"]["snapInterval"] = snapInterval; - _config->conf[prefix]["RAW"]["squelchLevel"] = squelchLevel; - } - _config->release(true); - - squelch.init(_vfo->output, squelchLevel); - } - - void start() { - squelch.start(); - running = true; - } - - void stop() { - squelch.stop(); - running = false; - } - - bool isRunning() { - return running; - } - - void select() { - _vfo->setSampleRate(audioSampRate, audioSampRate); - _vfo->setSnapInterval(snapInterval); - _vfo->setReference(ImGui::WaterfallVFO::REF_CENTER); - _vfo->setBandwidthLimits(0, 0, true); - } - - void setVFO(VFOManager::VFO* vfo) { - _vfo = vfo; - squelch.setInput(_vfo->output); - } - - VFOManager::VFO* getVFO() { - return _vfo; - } - - void setAudioSampleRate(float sampleRate) { - audioSampRate = sampleRate; - if (running) { - _vfo->setSampleRate(audioSampRate, audioSampRate); - } - } - - float getAudioSampleRate() { - return audioSampRate; - } - - dsp::stream* getOutput() { - return (dsp::stream*)&squelch.out; - } - - void showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - - ImGui::LeftLabel("Snap Interval"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::InputFloat(("##_radio_raw_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) { - if (snapInterval < 1) { snapInterval = 1; } - setSnapInterval(snapInterval); - _config->acquire(); - _config->conf[uiPrefix]["RAW"]["snapInterval"] = snapInterval; - _config->release(true); - } - - ImGui::LeftLabel("Squelch"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_raw_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { - squelch.setLevel(squelchLevel); - _config->acquire(); - _config->conf[uiPrefix]["RAW"]["squelchLevel"] = squelchLevel; - _config->release(true); - } - - // TODO: Allow selection of the bandwidth - } - - void setBandwidth(float bandWidth, bool updateWaterfall = true) { - // Do nothing - } - - void saveParameters(bool lock = true) { - if (lock) { _config->acquire(); } - _config->conf[uiPrefix]["RAW"]["snapInterval"] = snapInterval; - _config->conf[uiPrefix]["RAW"]["squelchLevel"] = squelchLevel; - if (lock) { _config->release(true); } - } - -private: - void setSnapInterval(float snapInt) { - snapInterval = snapInt; - _vfo->setSnapInterval(snapInterval); - } - - std::string uiPrefix; - float snapInterval = 10000; - float audioSampRate = 48000; - float bw = 12500; - bool running = false; - float squelchLevel = -100.0f; - - VFOManager::VFO* _vfo; - dsp::Squelch squelch; - - ConfigManager* _config; - -}; \ No newline at end of file diff --git a/decoder_modules/radio/src/usb_demod.h b/decoder_modules/radio/src/usb_demod.h deleted file mode 100644 index 1b199d4c..00000000 --- a/decoder_modules/radio/src/usb_demod.h +++ /dev/null @@ -1,220 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - - -class USBDemodulator : public Demodulator { -public: - USBDemodulator() {} - USBDemodulator(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - init(prefix, vfo, audioSampleRate, bandWidth, config); - } - - void init(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - uiPrefix = prefix; - _vfo = vfo; - audioSampRate = audioSampleRate; - bw = bandWidth; - _config = config; - - _config->acquire(); - if(_config->conf.contains(prefix)) { - if(!_config->conf[prefix].contains("USB")) { - _config->conf[prefix]["USB"]["bandwidth"] = bw; - _config->conf[prefix]["USB"]["snapInterval"] = snapInterval; - _config->conf[prefix]["USB"]["squelchLevel"] = squelchLevel; - } - json conf = _config->conf[prefix]["USB"]; - if (conf.contains("bandwidth")) { bw = conf["bandwidth"]; } - if (conf.contains("snapInterval")) { snapInterval = conf["snapInterval"]; } - if (conf.contains("squelchLevel")) { squelchLevel = conf["squelchLevel"]; } - } - else { - _config->conf[prefix]["USB"]["bandwidth"] = bw; - _config->conf[prefix]["USB"]["snapInterval"] = snapInterval; - _config->conf[prefix]["USB"]["squelchLevel"] = squelchLevel; - } - _config->release(true); - - squelch.init(_vfo->output, squelchLevel); - - demod.init(&squelch.out, bbSampRate, bw, dsp::SSBDemod::MODE_USB); - - agc.init(&demod.out, 20.0f, bbSampRate); - - float audioBW = std::min(audioSampRate / 2.0f, bw); - win.init(audioBW, audioBW, bbSampRate); - resamp.init(&agc.out, &win, bbSampRate, audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - resamp.updateWindow(&win); - - m2s.init(&resamp.out); - - onUserChangedBandwidthHandler.handler = vfoUserChangedBandwidthHandler; - onUserChangedBandwidthHandler.ctx = this; - - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - void start() { - squelch.start(); - demod.start(); - agc.start(); - resamp.start(); - m2s.start(); - running = true; - } - - void stop() { - squelch.stop(); - demod.stop(); - agc.stop(); - resamp.stop(); - m2s.stop(); - running = false; - } - - bool isRunning() { - return running; - } - - void select() { - _vfo->setSampleRate(bbSampRate, bw); - _vfo->setSnapInterval(snapInterval); - _vfo->setReference(ImGui::WaterfallVFO::REF_LOWER); - _vfo->setBandwidthLimits(bwMin, bwMax, false); - } - - void setVFO(VFOManager::VFO* vfo) { - _vfo = vfo; - squelch.setInput(_vfo->output); - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - VFOManager::VFO* getVFO() { - return _vfo; - } - - void setAudioSampleRate(float sampleRate) { - if (running) { - resamp.stop(); - } - audioSampRate = sampleRate; - float audioBW = std::min(audioSampRate / 2.0f, bw); - resamp.setOutSampleRate(audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - if (running) { - resamp.start(); - } - } - - float getAudioSampleRate() { - return audioSampRate; - } - - dsp::stream* getOutput() { - return &m2s.out; - } - - void showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - - ImGui::SetNextItemWidth(menuWidth); - if (ImGui::InputFloat(("##_radio_usb_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) { - bw = std::clamp(bw, bwMin, bwMax); - setBandwidth(bw); - _config->acquire(); - _config->conf[uiPrefix]["USB"]["bandwidth"] = bw; - _config->release(true); - } - - ImGui::LeftLabel("Snap Interval"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::InputFloat(("##_radio_usb_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) { - if (snapInterval < 1) { snapInterval = 1; } - setSnapInterval(snapInterval); - _config->acquire(); - _config->conf[uiPrefix]["USB"]["snapInterval"] = snapInterval; - _config->release(true); - } - - ImGui::LeftLabel("Squelch"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_usb_squelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { - squelch.setLevel(squelchLevel); - _config->acquire(); - _config->conf[uiPrefix]["USB"]["squelchLevel"] = squelchLevel; - _config->release(true); - } - } - - static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { - USBDemodulator* _this = (USBDemodulator*)ctx; - if (_this->running) { - _this->bw = newBw; - _this->setBandwidth(_this->bw, false); - _this->_config->acquire(); - _this->_config->conf[_this->uiPrefix]["USB"]["bandwidth"] = _this->bw; - _this->_config->release(true); - } - } - - void setBandwidth(float bandWidth, bool updateWaterfall = true) { - bandWidth = std::clamp(bandWidth, bwMin, bwMax); - bw = bandWidth; - _vfo->setBandwidth(bw, updateWaterfall); - demod.setBandWidth(bw); - float audioBW = std::min(audioSampRate / 2.0f, bw); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - } - - void saveParameters(bool lock = true) { - if (lock) { _config->acquire(); } - _config->conf[uiPrefix]["USB"]["bandwidth"] = bw; - _config->conf[uiPrefix]["USB"]["snapInterval"] = snapInterval; - _config->conf[uiPrefix]["USB"]["squelchLevel"] = squelchLevel; - if (lock) { _config->release(true); } - } - -private: - void setSnapInterval(float snapInt) { - snapInterval = snapInt; - _vfo->setSnapInterval(snapInterval); - } - - const float bwMax = 12000; - const float bwMin = 500; - const float bbSampRate = 24000; - - std::string uiPrefix; - float snapInterval = 100; - float audioSampRate = 48000; - float bw = 3000; - bool running = false; - float squelchLevel = -100.0f; - - VFOManager::VFO* _vfo; - dsp::Squelch squelch; - dsp::SSBDemod demod; - dsp::AGC agc; - dsp::filter_window::BlackmanWindow win; - dsp::PolyphaseResampler resamp; - dsp::MonoToStereo m2s; - - ConfigManager* _config; - - EventHandler onUserChangedBandwidthHandler; - -}; \ No newline at end of file diff --git a/decoder_modules/radio/src/wfm_demod.h b/decoder_modules/radio/src/wfm_demod.h deleted file mode 100644 index 36d09557..00000000 --- a/decoder_modules/radio/src/wfm_demod.h +++ /dev/null @@ -1,295 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - - -class WFMDemodulator : public Demodulator { -public: - WFMDemodulator() {} - WFMDemodulator(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - init(prefix, vfo, audioSampleRate, bandWidth, config); - } - - void init(std::string prefix, VFOManager::VFO* vfo, float audioSampleRate, float bandWidth, ConfigManager* config) { - uiPrefix = prefix; - _vfo = vfo; - audioSampRate = audioSampleRate; - bw = bandWidth; - _config = config; - - _config->acquire(); - if(_config->conf.contains(prefix)) { - if(!_config->conf[prefix].contains("WFM")) { - _config->conf[prefix]["WFM"]["bandwidth"] = bw; - _config->conf[prefix]["WFM"]["snapInterval"] = snapInterval; - _config->conf[prefix]["WFM"]["deempMode"] = deempId; - _config->conf[prefix]["WFM"]["squelchLevel"] = squelchLevel; - _config->conf[prefix]["WFM"]["stereo"] = false; - } - - // Correct for new settings - if (!config->conf[prefix]["WFM"].contains("stereo")) { _config->conf[prefix]["WFM"]["stereo"] = false;} - - json conf = _config->conf[prefix]["WFM"]; - bw = conf["bandwidth"]; - snapInterval = conf["snapInterval"]; - deempId = conf["deempMode"]; - squelchLevel = conf["squelchLevel"]; - stereo = conf["stereo"]; - } - else { - _config->conf[prefix]["WFM"]["bandwidth"] = bw; - _config->conf[prefix]["WFM"]["snapInterval"] = snapInterval; - _config->conf[prefix]["WFM"]["deempMode"] = deempId; - _config->conf[prefix]["WFM"]["squelchLevel"] = squelchLevel; - _config->conf[prefix]["WFM"]["stereo"] = false; - } - _config->release(true); - - squelch.init(_vfo->output, squelchLevel); - - demod.init(&squelch.out, bbSampRate, bw / 2.0f); - demodStereo.init(&squelch.out, bbSampRate, bw / 2.0f); - - float audioBW = std::min(audioSampleRate / 2.0f, 16000.0f); - win.init(audioBW, audioBW, bbSampRate); - if (stereo) { - resamp.init(demodStereo.out, &win, bbSampRate, audioSampRate); - } - else { - resamp.init(&demod.out, &win, bbSampRate, audioSampRate); - } - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - resamp.updateWindow(&win); - - deemp.init(&resamp.out, audioSampRate, tau); - - if (deempId == 2) { deemp.bypass = true; } - - onUserChangedBandwidthHandler.handler = vfoUserChangedBandwidthHandler; - onUserChangedBandwidthHandler.ctx = this; - - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - void start() { - squelch.start(); - if (stereo) { - demodStereo.start(); - } - else { - demod.start(); - } - resamp.start(); - deemp.start(); - running = true; - } - - void stop() { - squelch.stop(); - if (stereo) { - demodStereo.stop(); - } - else { - demod.stop(); - } - resamp.stop(); - deemp.stop(); - running = false; - } - - bool isRunning() { - return running; - } - - void select() { - _vfo->setSampleRate(bbSampRate, bw); - _vfo->setSnapInterval(snapInterval); - _vfo->setReference(ImGui::WaterfallVFO::REF_CENTER); - _vfo->setBandwidthLimits(bwMin, bwMax, false); - } - - void setVFO(VFOManager::VFO* vfo) { - _vfo = vfo; - squelch.setInput(_vfo->output); - _vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler); - } - - VFOManager::VFO* getVFO() { - return _vfo; - } - - void setAudioSampleRate(float sampleRate) { - if (running) { - resamp.stop(); - deemp.stop(); - } - audioSampRate = sampleRate; - float audioBW = std::min(audioSampRate / 2.0f, 16000.0f); - resamp.setOutSampleRate(audioSampRate); - win.setSampleRate(bbSampRate * resamp.getInterpolation()); - win.setCutoff(audioBW); - win.setTransWidth(audioBW); - resamp.updateWindow(&win); - deemp.setSampleRate(audioSampRate); - if (running) { - resamp.start(); - deemp.start(); - } - } - - float getAudioSampleRate() { - return audioSampRate; - } - - dsp::stream* getOutput() { - return &deemp.out; - } - - void showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - - ImGui::SetNextItemWidth(menuWidth); - if (ImGui::InputFloat(("##_radio_wfm_bw_" + uiPrefix).c_str(), &bw, 1, 100, "%.0f", 0)) { - bw = std::clamp(bw, bwMin, bwMax); - setBandwidth(bw); - _config->acquire(); - _config->conf[uiPrefix]["WFM"]["bandwidth"] = bw; - _config->release(true); - } - - ImGui::LeftLabel("Snap Interval"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::InputFloat(("##_radio_wfm_snap_" + uiPrefix).c_str(), &snapInterval, 1, 100, "%.0f", 0)) { - if (snapInterval < 1) { snapInterval = 1; } - setSnapInterval(snapInterval); - _config->acquire(); - _config->conf[uiPrefix]["WFM"]["snapInterval"] = snapInterval; - _config->release(true); - } - - - ImGui::LeftLabel("De-emphasis"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::Combo(("##_radio_wfm_deemp_" + uiPrefix).c_str(), &deempId, deempModes)) { - setDeempIndex(deempId); - _config->acquire(); - _config->conf[uiPrefix]["WFM"]["deempMode"] = deempId; - _config->release(true); - } - - ImGui::LeftLabel("Squelch"); - ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_wfm_sqelch_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { - squelch.setLevel(squelchLevel); - _config->acquire(); - _config->conf[uiPrefix]["WFM"]["squelchLevel"] = squelchLevel; - _config->release(true); - } - - if (ImGui::Checkbox(("Stereo##_radio_wfm_stereo_" + uiPrefix).c_str(), &stereo)) { - setStereo(stereo); - _config->acquire(); - _config->conf[uiPrefix]["WFM"]["stereo"] = stereo; - _config->release(true); - } - } - - static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { - WFMDemodulator* _this = (WFMDemodulator*)ctx; - if (_this->running) { - _this->bw = newBw; - _this->setBandwidth(_this->bw, false); - _this->_config->acquire(); - _this->_config->conf[_this->uiPrefix]["WFM"]["bandwidth"] = _this->bw; - _this->_config->release(true); - } - } - - void setDeempIndex(int id) { - if (id >= 2 || id < 0) { - deemp.bypass = true; - return; - } - deemp.setTau(deempVals[id]); - deemp.bypass = false; - } - - void setSnapInterval(float snapInt) { - snapInterval = snapInt; - _vfo->setSnapInterval(snapInterval); - } - - void setBandwidth(float bandWidth, bool updateWaterfall = true) { - bandWidth = std::clamp(bandWidth, bwMin, bwMax); - bw = bandWidth; - _vfo->setBandwidth(bw, updateWaterfall); - demod.setDeviation(bw / 2.0f); - demodStereo.setDeviation(bw / 2.0f); - } - - void setStereo(bool enabled) { - if (running) { - demod.stop(); - demodStereo.stop(); - } - - if (enabled) { - resamp.setInput(demodStereo.out); - if (running) { demodStereo.start(); } - } - else { - resamp.setInput(&demod.out); - if (running) { demod.start(); } - } - } - - void saveParameters(bool lock = true) { - if (lock) { _config->acquire(); } - _config->conf[uiPrefix]["WFM"]["bandwidth"] = bw; - _config->conf[uiPrefix]["WFM"]["snapInterval"] = snapInterval; - _config->conf[uiPrefix]["WFM"]["deempMode"] = deempId; - _config->conf[uiPrefix]["WFM"]["squelchLevel"] = squelchLevel; - _config->conf[uiPrefix]["WFM"]["stereo"] = stereo; - if (lock) { _config->release(true); } - } - -private: - - const float bwMax = 250000; - const float bwMin = 50000; - const float bbSampRate = 250000; - const char* deempModes = "50µs\00075µs\000none\000"; - const float deempVals[2] = { 50e-6, 75e-6 }; - - std::string uiPrefix; - float snapInterval = 100000; - float audioSampRate = 48000; - float squelchLevel = -100.0f; - float bw = 200000; - bool stereo = false; - int deempId = 0; - float tau = 50e-6; - bool running = false; - - VFOManager::VFO* _vfo; - dsp::Squelch squelch; - - dsp::FMDemod demod; - dsp::StereoFMDemod demodStereo; - - dsp::filter_window::BlackmanWindow win; - dsp::PolyphaseResampler resamp; - dsp::BFMDeemp deemp; - - ConfigManager* _config; - - EventHandler onUserChangedBandwidthHandler; - -}; \ No newline at end of file