diff --git a/core/src/dsp/demod/am.h b/core/src/dsp/demod/am.h index 71026609..06248d17 100644 --- a/core/src/dsp/demod/am.h +++ b/core/src/dsp/demod/am.h @@ -2,10 +2,14 @@ #include "../processor.h" #include "../loop/agc.h" #include "../correction/dc_blocker.h" +#include "../convert/mono_to_stereo.h" +#include "../filter/fir.h" +#include "../taps/low_pass.h" namespace dsp::demod { - class AM : public Processor { - using base_type = Processor; + template + class AM : public Processor { + using base_type = Processor; public: enum AGCMode { CARRIER, @@ -14,17 +18,30 @@ namespace dsp::demod { AM() {} - AM(stream* in, AGCMode agcMode, double agcAttack, double agcDecay, double dcBlockRate) { init(in, agcMode, agcAttack, agcDecay, dcBlockRate); } + AM(stream* in, AGCMode agcMode, double bandwidth, double agcAttack, double agcDecay, double dcBlockRate, double samplerate) { init(in, agcMode, bandwidth, agcAttack, agcDecay, dcBlockRate, samplerate); } - void init(stream* in, AGCMode agcMode, double agcAttack, double agcDecay, double dcBlockRate) { + ~AM() { + if (!base_type::_block_init) { return; } + base_type::stop(); + taps::free(lpfTaps); + } + + void init(stream* in, AGCMode agcMode, double bandwidth, double agcAttack, double agcDecay, double dcBlockRate, double samplerate) { _agcMode = agcMode; + _bandwidth = bandwidth; + _samplerate = samplerate; carrierAgc.init(NULL, 1.0, agcAttack, agcDecay, 10e6, 10.0); audioAgc.init(NULL, 1.0, agcAttack, agcDecay, 10e6, 10.0); dcBlock.init(NULL, dcBlockRate); + lpfTaps = taps::lowPass(bandwidth / 2.0, (bandwidth / 2.0) * 0.1, samplerate); + lpf.init(NULL, lpfTaps); - audioAgc.out.free(); + if constexpr (std::is_same_v) { + audioAgc.out.free(); + } dcBlock.out.free(); + lpf.out.free(); base_type::init(in); } @@ -38,6 +55,17 @@ namespace dsp::demod { base_type::tempStart(); } + void setBandwidth(double bandwidth) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + if (bandwidth == _bandwidth) { return; } + _bandwidth = bandwidth; + std::lock_guard lck2(lpfMtx); + taps::free(lpfTaps); + lpfTaps = taps::lowPass(_bandwidth / 2.0, (_bandwidth / 2.0) * 0.1, _samplerate); + lpf.setTaps(lpfTaps); + } + void setAGCAttack(double attack) { assert(base_type::_block_init); std::lock_guard lck(base_type::ctrlMtx); @@ -58,6 +86,8 @@ namespace dsp::demod { dcBlock.setRate(rate); } + // TODO: Implement setSamplerate + void reset() { assert(base_type::_block_init); std::lock_guard lck(base_type::ctrlMtx); @@ -68,20 +98,35 @@ namespace dsp::demod { base_type::tempStart(); } - int process(int count, complex_t* in, float* out) { + int process(int count, complex_t* in, T* out) { // Apply carrier AGC if needed if (_agcMode == AGCMode::CARRIER) { carrierAgc.process(count, in, carrierAgc.out.writeBuf); in = carrierAgc.out.writeBuf; } - // Get magnitude of each sample and remove DC (TODO: use block instead) - volk_32fc_magnitude_32f(out, (lv_32fc_t*)in, count); - dcBlock.process(count, out, out); - - // Apply audio AGC if needed - if (_agcMode == AGCMode::AUDIO) { - audioAgc.process(count, out, out); + if constexpr (std::is_same_v) { + volk_32fc_magnitude_32f(out, (lv_32fc_t*)in, count); + dcBlock.process(count, out, out); + if (_agcMode == AGCMode::AUDIO) { + audioAgc.process(count, out, out); + } + { + std::lock_guard lck(lpfMtx); + lpf.process(count, out, out); + } + } + if constexpr (std::is_same_v) { + volk_32fc_magnitude_32f(audioAgc.out.writeBuf, (lv_32fc_t*)in, count); + dcBlock.process(count, audioAgc.out.writeBuf, audioAgc.out.writeBuf); + if (_agcMode == AGCMode::AUDIO) { + audioAgc.process(count, audioAgc.out.writeBuf, audioAgc.out.writeBuf); + } + { + std::lock_guard lck(lpfMtx); + lpf.process(count, audioAgc.out.writeBuf, audioAgc.out.writeBuf); + } + convert::MonoToStereo::process(count, audioAgc.out.writeBuf, out); } return count; @@ -101,9 +146,15 @@ namespace dsp::demod { protected: AGCMode _agcMode; + double _samplerate; + double _bandwidth; + loop::AGC carrierAgc; loop::AGC audioAgc; correction::DCBlocker dcBlock; + tap lpfTaps; + filter::FIR lpf; + std::mutex lpfMtx; }; } \ No newline at end of file diff --git a/core/src/dsp/demod/broadcast_fm.h b/core/src/dsp/demod/broadcast_fm.h index ca751d6f..f0269829 100644 --- a/core/src/dsp/demod/broadcast_fm.h +++ b/core/src/dsp/demod/broadcast_fm.h @@ -1,5 +1,5 @@ #pragma once -#include "fm.h" +#include "quadrature.h" #include "../taps/low_pass.h" #include "../taps/band_pass.h" #include "../filter/fir.h" @@ -193,7 +193,7 @@ namespace dsp::demod { bool _stereo; bool _lowPass = true; - FM demod; + Quadrature demod; tap pilotFirTaps; filter::FIR pilotFir; convert::RealToComplex rtoc; diff --git a/core/src/dsp/demod/cw.h b/core/src/dsp/demod/cw.h new file mode 100644 index 00000000..29103e34 --- /dev/null +++ b/core/src/dsp/demod/cw.h @@ -0,0 +1,87 @@ +#pragma once +#include "../processor.h" +#include "../channel/frequency_xlator.h" +#include "../convert/complex_to_real.h" +#include "../loop/agc.h" +#include "../convert/mono_to_stereo.h" + +namespace dsp::demod { + template + class CW : public Processor { + using base_type = Processor; + public: + CW() {} + + CW(stream* in, double tone, double agcAttack, double agcDecay, double samplerate) { init(in, tone, agcAttack, agcDecay, samplerate); } + + void init(stream* in, double tone, double agcAttack, double agcDecay, double samplerate) { + _tone = tone; + + xlator.init(NULL, tone, samplerate); + agc.init(NULL, 1.0, agcAttack, agcDecay, 10e6, 10.0); + + if constexpr (std::is_same_v) { + agc.out.free(); + } + + base_type::init(in); + } + + void setTone(double tone) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + _tone = tone; + xlator.setOffset(_tone); + } + + void setAGCAttack(double attack) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + agc.setAttack(attack); + } + + void setAGCDecay(double decay) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + agc.setDecay(decay); + } + + void setSamplerate(double samplerate) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + xlator.setOffset(_tone, samplerate); + } + + inline int process(int count, const complex_t* in, T* out) { + xlator.process(count, in, xlator.out.writeBuf); + if constexpr (std::is_same_v) { + dsp::convert::ComplexToReal::process(count, xlator.out.writeBuf, out); + agc.process(count, out, out); + } + if constexpr (std::is_same_v) { + dsp::convert::ComplexToReal::process(count, xlator.out.writeBuf, agc.out.writeBuf); + agc.process(count, agc.out.writeBuf, agc.out.writeBuf); + convert::MonoToStereo::process(count, agc.out.writeBuf, out); + } + return count; + } + + int run() { + int count = base_type::_in->read(); + if (count < 0) { return -1; } + + process(count, base_type::_in->readBuf, base_type::out.writeBuf); + + base_type::_in->flush(); + if (!base_type::out.swap(count)) { return -1; } + return count; + } + + private: + double _tone; + + dsp::channel::FrequencyXlator xlator; + dsp::loop::AGC agc; + + }; +} \ No newline at end of file diff --git a/core/src/dsp/demod/fm.h b/core/src/dsp/demod/fm.h index efda2748..8a79f505 100644 --- a/core/src/dsp/demod/fm.h +++ b/core/src/dsp/demod/fm.h @@ -1,54 +1,98 @@ #pragma once #include "../processor.h" -#include "../math/fast_atan2.h" -#include "../math/freq_to_omega.h" -#include "../math/norm_phase_diff.h" +#include "quadrature.h" +#include "../filter/fir.h" +#include "../taps/low_pass.h" +#include "../convert/mono_to_stereo.h" namespace dsp::demod { - class FM : public Processor { - using base_type = Processor; + template + class FM : public dsp::Processor { + using base_type = dsp::Processor; public: FM() {} - FM(stream* in, double deviation) { init(in, deviation); } + FM(dsp::stream* in, double samplerate, double bandwidth, bool lowPass) { init(in, samplerate, bandwidth, lowPass); } - FM(stream* in, double deviation, double samplerate) { init(in, deviation, samplerate); } - - - virtual void init(stream* in, double deviation) { - _invDeviation = 1.0 / deviation; - base_type::init(in); + ~FM() { + if (!base_type::_block_init) { return; } + base_type::stop(); + dsp::taps::free(lpfTaps); } - virtual void init(stream* in, double deviation, double samplerate) { - init(in, math::freqToOmega(deviation, samplerate)); - } + void init(dsp::stream* in, double samplerate, double bandwidth, bool lowPass) { + _samplerate = samplerate; + _bandwidth = bandwidth; + _lowPass = lowPass; - void setDeviation(double deviation) { - assert(base_type::_block_init); - std::lock_guard lck(base_type::ctrlMtx); - _invDeviation = 1.0 / deviation; - } + demod.init(NULL, bandwidth / 2.0, _samplerate); + lpfTaps = dsp::taps::lowPass(_bandwidth / 2.0, (_bandwidth / 2.0) * 0.1, _samplerate); + lpf.init(NULL, lpfTaps); - void setDeviation(double deviation, double samplerate) { - assert(base_type::_block_init); - std::lock_guard lck(base_type::ctrlMtx); - _invDeviation = 1.0 / math::freqToOmega(deviation, samplerate); - } - - inline int process(int count, complex_t* in, float* out) { - for (int i = 0; i < count; i++) { - float cphase = in[i].phase(); - out[i] = math::normPhaseDiff(cphase - phase) * _invDeviation; - phase = cphase; + if constexpr (std::is_same_v) { + demod.out.free(); } - return count; + lpf.out.free(); + } + + void setSamplerate(double samplerate) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + base_type::tempStop(); + _samplerate = samplerate; + demod.setDeviation(_bandwidth / 2.0, _samplerate); + dsp::taps::free(lpfTaps); + lpfTaps = dsp::taps::lowPass(_bandwidth / 2.0, (_bandwidth / 2.0) * 0.1, _samplerate); + lpf.setTaps(lpfTaps); + base_type::tempStart(); + } + + void setBandwidth(double bandwidth) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + if (bandwidth == _bandwidth) { return; } + _bandwidth = bandwidth; + std::lock_guard lck2(lpfMtx); + demod.setDeviation(_bandwidth / 2.0, _samplerate); + dsp::taps::free(lpfTaps); + lpfTaps = dsp::taps::lowPass(_bandwidth / 2, (_bandwidth / 2) * 0.1, _samplerate); + lpf.setTaps(lpfTaps); + } + + void setLowPass(bool lowPass) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + std::lock_guard lck2(lpfMtx); + _lowPass = lowPass; + lpf.reset(); } void reset() { assert(base_type::_block_init); std::lock_guard lck(base_type::ctrlMtx); - phase = 0.0f; + base_type::tempStop(); + demod.reset(); + lpf.reset(); + base_type::tempStart(); + } + + inline int process(int count, dsp::complex_t* in, T* out) { + if constexpr (std::is_same_v) { + demod.process(count, in, out); + if (_lowPass) { + std::lock_guard lck(lpfMtx); + lpf.process(count, out, out); + } + } + if constexpr (std::is_same_v) { + demod.process(count, in, demod.out.writeBuf); + if (_lowPass) { + std::lock_guard lck(lpfMtx); + lpf.process(count, demod.out.writeBuf, demod.out.writeBuf); + } + convert::MonoToStereo::process(count, demod.out.writeBuf, out); + } + return count; } int run() { @@ -62,8 +106,14 @@ namespace dsp::demod { return count; } - protected: - float _invDeviation; - float phase = 0.0f; + private: + double _samplerate; + double _bandwidth; + bool _lowPass; + + Quadrature demod; + tap lpfTaps; + filter::FIR lpf; + std::mutex lpfMtx; }; } \ No newline at end of file diff --git a/core/src/dsp/demod/narrow_fm.h b/core/src/dsp/demod/narrow_fm.h new file mode 100644 index 00000000..d16ab5eb --- /dev/null +++ b/core/src/dsp/demod/narrow_fm.h @@ -0,0 +1,114 @@ +#pragma once +#include "../processor.h" +#include "fm.h" +#include "../filter/fir.h" +#include "../taps/low_pass.h" +#include "../convert/mono_to_stereo.h" + +namespace dsp::demod { + template + class NarrowFM : public dsp::Processor { + using base_type = dsp::Processor; + public: + NarrowFM() {} + + NarrowFM(dsp::stream* in, double samplerate, double bandwidth, bool lowPass) { init(in, samplerate, bandwidth, lowPass); } + + ~NarrowFM() { + if (!base_type::_block_init) { return; } + base_type::stop(); + dsp::taps::free(lpfTaps); + } + + void init(dsp::stream* in, double samplerate, double bandwidth, bool lowPass) { + _samplerate = samplerate; + _bandwidth = bandwidth; + _lowPass = lowPass; + + demod.init(NULL, bandwidth / 2.0, _samplerate); + lpfTaps = dsp::taps::lowPass(_bandwidth / 2, (_bandwidth / 2) * 0.1, _samplerate); + lpf.init(NULL, lpfTaps); + + if constexpr (std::is_same_v) { + demod.out.free(); + } + lpf.out.free(); + } + + void setSamplerate(double samplerate) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + base_type::tempStop(); + _samplerate = samplerate; + demod.setDeviation(_bandwidth / 2.0, _samplerate); + dsp::taps::free(lpfTaps); + lpfTaps = dsp::taps::lowPass(_bandwidth / 2, (_bandwidth / 2) * 0.1, _samplerate); + lpf.setTaps(lpfTaps); + base_type::tempStart(); + } + + void setBandwidth(double bandwidth) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + if (bandwidth == _bandwidth) { return; } + _bandwidth = bandwidth; + demod.setDeviation(_bandwidth / 2.0, _samplerate); + dsp::taps::free(lpfTaps); + lpfTaps = dsp::taps::lowPass(_bandwidth / 2, (_bandwidth / 2) * 0.1, _samplerate); + lpf.setTaps(lpfTaps); + } + + void setLowPass(bool lowPass) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + _lowPass = lowPass; + lpf.reset(); + } + + void reset() { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + base_type::tempStop(); + demod.reset(); + lpf.reset(); + base_type::tempStart(); + } + + inline int process(int count, dsp::complex_t* in, float* out) { + if constexpr (std::is_same_v) { + demod.process(count, in, out); + if (_lowPass) { + lpf.process(count, out, out); + } + } + if constexpr (std::is_same_v) { + demod.process(count, in, demod.out.writeBuf); + if (_lowPass) { + lpf.process(count, demod.out.writeBuf, demod.out.writeBuf); + } + convert::MonoToStereo::process(count, demod.out.writeBuf, out); + } + return count; + } + + int run() { + int count = base_type::_in->read(); + if (count < 0) { return -1; } + + process(count, base_type::_in->readBuf, base_type::out.writeBuf); + + base_type::_in->flush(); + if (!base_type::out.swap(count)) { return -1; } + return count; + } + + private: + double _samplerate; + double _bandwidth; + bool _lowPass; + + dsp::demod::FM demod; + dsp::tap lpfTaps; + dsp::filter::FIR lpf; + }; +} \ No newline at end of file diff --git a/core/src/dsp/demod/quadrature.h b/core/src/dsp/demod/quadrature.h new file mode 100644 index 00000000..9c5cd31e --- /dev/null +++ b/core/src/dsp/demod/quadrature.h @@ -0,0 +1,69 @@ +#pragma once +#include "../processor.h" +#include "../math/fast_atan2.h" +#include "../math/freq_to_omega.h" +#include "../math/norm_phase_diff.h" + +namespace dsp::demod { + class Quadrature : public Processor { + using base_type = Processor; + public: + Quadrature() {} + + Quadrature(stream* in, double deviation) { init(in, deviation); } + + Quadrature(stream* in, double deviation, double samplerate) { init(in, deviation, samplerate); } + + + virtual void init(stream* in, double deviation) { + _invDeviation = 1.0 / deviation; + base_type::init(in); + } + + virtual void init(stream* in, double deviation, double samplerate) { + init(in, math::freqToOmega(deviation, samplerate)); + } + + void setDeviation(double deviation) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + _invDeviation = 1.0 / deviation; + } + + void setDeviation(double deviation, double samplerate) { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + _invDeviation = 1.0 / math::freqToOmega(deviation, samplerate); + } + + inline int process(int count, complex_t* in, float* out) { + for (int i = 0; i < count; i++) { + float cphase = in[i].phase(); + out[i] = math::normPhaseDiff(cphase - phase) * _invDeviation; + phase = cphase; + } + return count; + } + + void reset() { + assert(base_type::_block_init); + std::lock_guard lck(base_type::ctrlMtx); + phase = 0.0f; + } + + int run() { + int count = base_type::_in->read(); + if (count < 0) { return -1; } + + process(count, base_type::_in->readBuf, base_type::out.writeBuf); + + base_type::_in->flush(); + if (!base_type::out.swap(count)) { return -1; } + return count; + } + + protected: + float _invDeviation; + float phase = 0.0f; + }; +} \ No newline at end of file diff --git a/core/src/dsp/demod/ssb.h b/core/src/dsp/demod/ssb.h index b67feeb4..3b25de69 100644 --- a/core/src/dsp/demod/ssb.h +++ b/core/src/dsp/demod/ssb.h @@ -3,10 +3,12 @@ #include "../channel/frequency_xlator.h" #include "../convert/complex_to_real.h" #include "../loop/agc.h" +#include "../convert/mono_to_stereo.h" namespace dsp::demod { - class SSB : public Processor { - using base_type = Processor; + template + class SSB : public Processor { + using base_type = Processor; public: enum Mode { USB, @@ -26,7 +28,9 @@ namespace dsp::demod { xlator.init(NULL, getTranslation(), _samplerate); agc.init(NULL, 1.0, agcAttack, agcDecay, 10e6, 10.0); - agc.out.free(); + if constexpr (std::is_same_v) { + agc.out.free(); + } base_type::init(in); } @@ -70,15 +74,19 @@ namespace dsp::demod { agc.setDecay(decay); } - int process(int count, const complex_t* in, float* out) { + int process(int count, const complex_t* in, T* out) { // Move back sideband xlator.process(count, in, xlator.out.writeBuf); - // Extract the real component - convert::ComplexToReal::process(count, xlator.out.writeBuf, out); - - // Apply AGC - agc.process(count, out, out); + if constexpr (std::is_same_v) { + convert::ComplexToReal::process(count, xlator.out.writeBuf, out); + agc.process(count, out, out); + } + if constexpr (std::is_same_v) { + convert::ComplexToReal::process(count, xlator.out.writeBuf, agc.out.writeBuf); + agc.process(count, agc.out.writeBuf, agc.out.writeBuf); + convert::MonoToStereo::process(count, agc.out.writeBuf, out); + } return count; } diff --git a/core/src/dsp/sink/ring_buffer.h b/core/src/dsp/sink/ring_buffer.h index e6bdbc9a..5298ae67 100644 --- a/core/src/dsp/sink/ring_buffer.h +++ b/core/src/dsp/sink/ring_buffer.h @@ -17,7 +17,7 @@ namespace dsp::sink { int count = base_type::_in->read(); if (count < 0) { return -1; } - if (data.write(_in->readBuf, count) < 0) { return -1; } + if (data.write(base_type::_in->readBuf, count) < 0) { return -1; } base_type::_in->flush(); return count; diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index 2979dee1..b6ec07bf 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -259,6 +259,7 @@ void MainWindow::vfoAddedHandler(VFOManager::VFO* vfo, void* ctx) { void MainWindow::draw() { ImGui::Begin("Main", NULL, WINDOW_FLAGS); + ImVec4 textCol = ImGui::GetStyleColorVec4(ImGuiCol_Text); ImGui::WaterfallVFO* vfo = NULL; if (gui::waterfall.selectedVFO != "") { @@ -332,7 +333,7 @@ void MainWindow::draw() { // ImGui::BeginChild("TopBarChild", ImVec2(0, 49.0f * style::uiScale), false, ImGuiWindowFlags_HorizontalScrollbar); ImVec2 btnSize(30 * style::uiScale, 30 * style::uiScale); ImGui::PushID(ImGui::GetID("sdrpp_menu_btn")); - if (ImGui::ImageButton(icons::MENU, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(ImGuiKey_Menu, false)) { + if (ImGui::ImageButton(icons::MENU, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5, ImVec4(0, 0, 0, 0), textCol) || ImGui::IsKeyPressed(ImGuiKey_Menu, false)) { showMenu = !showMenu; core::configManager.acquire(); core::configManager.conf["showMenu"] = showMenu; @@ -346,14 +347,14 @@ void MainWindow::draw() { if (playButtonLocked && !tmpPlaySate) { style::beginDisabled(); } if (playing) { ImGui::PushID(ImGui::GetID("sdrpp_stop_btn")); - if (ImGui::ImageButton(icons::STOP, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(ImGuiKey_End, false)) { + if (ImGui::ImageButton(icons::STOP, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5, ImVec4(0, 0, 0, 0), textCol) || ImGui::IsKeyPressed(ImGuiKey_End, false)) { setPlayState(false); } ImGui::PopID(); } else { // TODO: Might need to check if there even is a device ImGui::PushID(ImGui::GetID("sdrpp_play_btn")); - if (ImGui::ImageButton(icons::PLAY, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(ImGuiKey_End, false)) { + if (ImGui::ImageButton(icons::PLAY, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5, ImVec4(0, 0, 0, 0), textCol) || ImGui::IsKeyPressed(ImGuiKey_End, false)) { setPlayState(true); } ImGui::PopID(); @@ -381,7 +382,7 @@ void MainWindow::draw() { ImGui::SetCursorPosY(origY); if (tuningMode == tuner::TUNER_MODE_CENTER) { ImGui::PushID(ImGui::GetID("sdrpp_ena_st_btn")); - if (ImGui::ImageButton(icons::CENTER_TUNING, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5)) { + if (ImGui::ImageButton(icons::CENTER_TUNING, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5, ImVec4(0, 0, 0, 0), textCol)) { tuningMode = tuner::TUNER_MODE_NORMAL; gui::waterfall.VFOMoveSingleClick = false; core::configManager.acquire(); @@ -392,7 +393,7 @@ void MainWindow::draw() { } else { // TODO: Might need to check if there even is a device ImGui::PushID(ImGui::GetID("sdrpp_dis_st_btn")); - if (ImGui::ImageButton(icons::NORMAL_TUNING, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5)) { + if (ImGui::ImageButton(icons::NORMAL_TUNING, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5, ImVec4(0, 0, 0, 0), textCol)) { tuningMode = tuner::TUNER_MODE_CENTER; gui::waterfall.VFOMoveSingleClick = true; tuner::tune(tuner::TUNER_MODE_CENTER, gui::waterfall.selectedVFO, gui::freqSelect.frequency); diff --git a/core/src/signal_path/sink.cpp b/core/src/signal_path/sink.cpp index 8f513a4d..9750214d 100644 --- a/core/src/signal_path/sink.cpp +++ b/core/src/signal_path/sink.cpp @@ -239,7 +239,7 @@ void SinkManager::setStreamSink(std::string name, std::string providerName) { } } -void SinkManager::showVolumeSlider(std::string name, std::string prefix, float width, float btnHeight, int btwBorder, bool sameLine) { +void SinkManager::showVolumeSlider(std::string name, std::string prefix, float width, float btnHeight, int btnBorder, bool sameLine) { // TODO: Replace map with some hashmap for it to be faster float height = ImGui::GetTextLineHeightWithSpacing() + 2; float sliderHeight = height; @@ -254,11 +254,11 @@ void SinkManager::showVolumeSlider(std::string name, std::string prefix, float w float dummy = 0.0f; style::beginDisabled(); ImGui::PushID(ImGui::GetID(("sdrpp_unmute_btn_" + name).c_str())); - ImGui::ImageButton(icons::MUTED, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), btwBorder); + ImGui::ImageButton(icons::MUTED, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), btnBorder, ImVec4(0, 0, 0, 0), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); ImGui::SameLine(); ImGui::SetNextItemWidth(width - height - sliderOffset); - ImGui::SetCursorPosY(ypos + ((height - sliderHeight) / 2.0f) + btwBorder); + ImGui::SetCursorPosY(ypos + ((height - sliderHeight) / 2.0f) + btnBorder); ImGui::SliderFloat((prefix + name).c_str(), &dummy, 0.0f, 1.0f, ""); style::endDisabled(); if (sameLine) { ImGui::SetCursorPosY(ypos); } @@ -269,7 +269,7 @@ void SinkManager::showVolumeSlider(std::string name, std::string prefix, float w if (stream->volumeAjust.getMuted()) { ImGui::PushID(ImGui::GetID(("sdrpp_unmute_btn_" + name).c_str())); - if (ImGui::ImageButton(icons::MUTED, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), btwBorder)) { + if (ImGui::ImageButton(icons::MUTED, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), btnBorder, ImVec4(0, 0, 0, 0), ImGui::GetStyleColorVec4(ImGuiCol_Text))) { stream->volumeAjust.setMuted(false); core::configManager.acquire(); saveStreamConfig(name); @@ -279,7 +279,7 @@ void SinkManager::showVolumeSlider(std::string name, std::string prefix, float w } else { ImGui::PushID(ImGui::GetID(("sdrpp_mute_btn_" + name).c_str())); - if (ImGui::ImageButton(icons::UNMUTED, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), btwBorder)) { + if (ImGui::ImageButton(icons::UNMUTED, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), btnBorder, ImVec4(0, 0, 0, 0), ImGui::GetStyleColorVec4(ImGuiCol_Text))) { stream->volumeAjust.setMuted(true); core::configManager.acquire(); saveStreamConfig(name); @@ -291,7 +291,7 @@ void SinkManager::showVolumeSlider(std::string name, std::string prefix, float w ImGui::SameLine(); ImGui::SetNextItemWidth(width - height - sliderOffset); - ImGui::SetCursorPosY(ypos + ((height - sliderHeight) / 2.0f) + btwBorder); + ImGui::SetCursorPosY(ypos + ((height - sliderHeight) / 2.0f) + btnBorder); if (ImGui::SliderFloat((prefix + name).c_str(), &stream->guiVolume, 0.0f, 1.0f, "")) { stream->setVolume(stream->guiVolume); core::configManager.acquire(); diff --git a/core/src/signal_path/sink.h b/core/src/signal_path/sink.h index acdd0beb..a06ac1f1 100644 --- a/core/src/signal_path/sink.h +++ b/core/src/signal_path/sink.h @@ -101,7 +101,7 @@ public: void setStreamSink(std::string name, std::string providerName); - void showVolumeSlider(std::string name, std::string prefix, float width, float btnHeight = -1.0f, int btwBorder = 0, bool sameLine = false); + void showVolumeSlider(std::string name, std::string prefix, float width, float btnHeight = -1.0f, int btnBorder = 0, bool sameLine = false); dsp::stream* bindStream(std::string name); void unbindStream(std::string name, dsp::stream* stream); diff --git a/decoder_modules/radio/src/demodulators/am.h b/decoder_modules/radio/src/demodulators/am.h index 9b00e026..bb0a6c9a 100644 --- a/decoder_modules/radio/src/demodulators/am.h +++ b/decoder_modules/radio/src/demodulators/am.h @@ -1,7 +1,6 @@ #pragma once #include "../demod.h" #include -#include namespace demod { class AM : public Demodulator { @@ -12,9 +11,7 @@ namespace demod { init(name, config, input, bandwidth, outputChangeHandler, afbwChangeHandler, audioSR); } - ~AM() { - stop(); - } + ~AM() { stop(); } void init(std::string name, ConfigManager* config, dsp::stream* input, double bandwidth, EventHandler*> outputChangeHandler, EventHandler afbwChangeHandler, double audioSR) { this->name = name; @@ -34,25 +31,18 @@ namespace demod { config->release(); // Define structure - demod.init(input, carrierAgc ? dsp::demod::AM::AGCMode::CARRIER : dsp::demod::AM::AGCMode::AUDIO, agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate(), 100.0 / getIFSampleRate()); - m2s.init(&demod.out); + demod.init(input, carrierAgc ? dsp::demod::AM::AGCMode::CARRIER : dsp::demod::AM::AGCMode::AUDIO, bandwidth, agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate(), 100.0 / getIFSampleRate(), getIFSampleRate()); } - void start() { - demod.start(); - m2s.start(); - } + void start() { demod.start(); } - void stop() { - demod.stop(); - m2s.stop(); - } + void stop() { demod.stop(); } void showMenu() { float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::LeftLabel("AGC Attack"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_am_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 100.0f)) { + if (ImGui::SliderFloat(("##_radio_am_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 200.0f)) { demod.setAGCAttack(agcAttack / getIFSampleRate()); _config->acquire(); _config->conf[name][getName()]["agcAttack"] = agcAttack; @@ -66,19 +56,17 @@ namespace demod { _config->conf[name][getName()]["agcDecay"] = agcDecay; _config->release(true); } - if (ImGui::Checkbox(("Carrier AGC (W.I.P.)##_radio_am_carrier_agc_" + name).c_str(), &carrierAgc)) { - demod.setAGCMode(carrierAgc ? dsp::demod::AM::AGCMode::CARRIER : dsp::demod::AM::AGCMode::AUDIO); + if (ImGui::Checkbox(("Carrier AGC##_radio_am_carrier_agc_" + name).c_str(), &carrierAgc)) { + demod.setAGCMode(carrierAgc ? dsp::demod::AM::AGCMode::CARRIER : dsp::demod::AM::AGCMode::AUDIO); _config->acquire(); _config->conf[name][getName()]["carrierAgc"] = carrierAgc; _config->release(true); } } - void setBandwidth(double bandwidth) {} + void setBandwidth(double bandwidth) { demod.setBandwidth(bandwidth); } - void setInput(dsp::stream* input) { - demod.setInput(input); - } + void setInput(dsp::stream* input) { demod.setInput(input); } void AFSampRateChanged(double newSR) {} @@ -101,11 +89,10 @@ namespace demod { bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } bool getNBAllowed() { return false; } - dsp::stream* getOutput() { return &m2s.out; } + dsp::stream* getOutput() { return &demod.out; } private: - dsp::demod::AM demod; - dsp::convert::MonoToStereo m2s; + dsp::demod::AM demod; ConfigManager* _config = NULL; diff --git a/decoder_modules/radio/src/demodulators/cw.h b/decoder_modules/radio/src/demodulators/cw.h index a44c46b9..bc53f9c5 100644 --- a/decoder_modules/radio/src/demodulators/cw.h +++ b/decoder_modules/radio/src/demodulators/cw.h @@ -1,9 +1,6 @@ #pragma once #include "../demod.h" -#include -#include -#include -#include +#include namespace demod { class CW : public Demodulator { @@ -21,7 +18,6 @@ namespace demod { void init(std::string name, ConfigManager* config, dsp::stream* input, double bandwidth, EventHandler*> outputChangeHandler, EventHandler afbwChangeHandler, double audioSR) { this->name = name; this->_config = config; - this->_bandwidth = bandwidth; this->afbwChangeHandler = afbwChangeHandler; // Load config @@ -38,32 +34,19 @@ namespace demod { config->release(); // Define structure - xlator.init(input, tone, getIFSampleRate()); - c2r.init(&xlator.out); - agc.init(&c2r.out, 1.0, agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate(), 10e6, 10.0); - m2s.init(&agc.out); + demod.init(input, tone, agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate(), getIFSampleRate()); } - void start() { - xlator.start(); - c2r.start(); - agc.start(); - m2s.start(); - } + void start() { demod.start(); } - void stop() { - xlator.stop(); - c2r.stop(); - agc.stop(); - m2s.stop(); - } + void stop() { demod.stop(); } void showMenu() { float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::LeftLabel("AGC Attack"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_cw_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 100.0f)) { - agc.setAttack(agcAttack / getIFSampleRate()); + if (ImGui::SliderFloat(("##_radio_cw_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 200.0f)) { + demod.setAGCAttack(agcAttack / getIFSampleRate()); _config->acquire(); _config->conf[name][getName()]["agcAttack"] = agcAttack; _config->release(true); @@ -71,7 +54,7 @@ namespace demod { ImGui::LeftLabel("AGC Decay"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); if (ImGui::SliderFloat(("AGC Decay##_radio_cw_agc_decay_" + name).c_str(), &agcDecay, 1.0f, 20.0f)) { - agc.setDecay(agcDecay / getIFSampleRate()); + demod.setAGCDecay(agcDecay / getIFSampleRate()); _config->acquire(); _config->conf[name][getName()]["agcDecay"] = agcDecay; _config->release(true); @@ -80,19 +63,16 @@ namespace demod { ImGui::FillWidth(); if (ImGui::InputInt(("Stereo##_radio_cw_tone_" + name).c_str(), &tone, 10, 100)) { tone = std::clamp(tone, 250, 1250); - xlator.setOffset(tone, getIFSampleRate()); - afbwChangeHandler.handler(getAFBandwidth(_bandwidth), afbwChangeHandler.ctx); + demod.setTone(tone); _config->acquire(); _config->conf[name][getName()]["tone"] = tone; _config->release(true); } } - void setBandwidth(double bandwidth) { _bandwidth = bandwidth; } + void setBandwidth(double bandwidth) {} - void setInput(dsp::stream* input) { - xlator.setInput(input); - } + void setInput(dsp::stream* input) { demod.setInput(input); } void AFSampRateChanged(double newSR) {} @@ -115,21 +95,17 @@ namespace demod { bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } bool getNBAllowed() { return false; } - dsp::stream* getOutput() { return &m2s.out; } + dsp::stream* getOutput() { return &demod.out; } private: ConfigManager* _config = NULL; - dsp::channel::FrequencyXlator xlator; - dsp::convert::ComplexToReal c2r; - dsp::loop::AGC agc; - dsp::convert::MonoToStereo m2s; + dsp::demod::CW demod; std::string name; - float agcAttack = 50.0f; + float agcAttack = 100.0f; float agcDecay = 5.0f; int tone = 800; - double _bandwidth; EventHandler afbwChangeHandler; }; diff --git a/decoder_modules/radio/src/demodulators/dsb.h b/decoder_modules/radio/src/demodulators/dsb.h index 053abe05..34012105 100644 --- a/decoder_modules/radio/src/demodulators/dsb.h +++ b/decoder_modules/radio/src/demodulators/dsb.h @@ -1,7 +1,6 @@ #pragma once #include "../demod.h" #include -#include namespace demod { class DSB : public Demodulator { @@ -31,25 +30,18 @@ namespace demod { config->release(); // Define structure - demod.init(input, dsp::demod::SSB::Mode::DSB, bandwidth, getIFSampleRate(), agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate()); - m2s.init(&demod.out); + demod.init(input, dsp::demod::SSB::Mode::DSB, bandwidth, getIFSampleRate(), agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate()); } - void start() { - demod.start(); - m2s.start(); - } + void start() { demod.start(); } - void stop() { - demod.stop(); - m2s.stop(); - } + void stop() { demod.stop(); } void showMenu() { float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::LeftLabel("AGC Attack"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_dsb_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 100.0f)) { + if (ImGui::SliderFloat(("##_radio_dsb_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 200.0f)) { demod.setAGCAttack(agcAttack / getIFSampleRate()); _config->acquire(); _config->conf[name][getName()]["agcAttack"] = agcAttack; @@ -65,13 +57,9 @@ namespace demod { } } - void setBandwidth(double bandwidth) { - demod.setBandwidth(bandwidth); - } + void setBandwidth(double bandwidth) { demod.setBandwidth(bandwidth); } - void setInput(dsp::stream* input) { - demod.setInput(input); - } + void setInput(dsp::stream* input) { demod.setInput(input); } void AFSampRateChanged(double newSR) {} @@ -94,11 +82,10 @@ namespace demod { bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } bool getNBAllowed() { return true; } - dsp::stream* getOutput() { return &m2s.out; } + dsp::stream* getOutput() { return &demod.out; } private: - dsp::demod::SSB demod; - dsp::convert::MonoToStereo m2s; + dsp::demod::SSB demod; ConfigManager* _config; diff --git a/decoder_modules/radio/src/demodulators/lsb.h b/decoder_modules/radio/src/demodulators/lsb.h index ffffd05c..a5ee7705 100644 --- a/decoder_modules/radio/src/demodulators/lsb.h +++ b/decoder_modules/radio/src/demodulators/lsb.h @@ -1,7 +1,6 @@ #pragma once #include "../demod.h" #include -#include namespace demod { class LSB : public Demodulator { @@ -31,25 +30,18 @@ namespace demod { config->release(); // Define structure - demod.init(input, dsp::demod::SSB::Mode::LSB, bandwidth, getIFSampleRate(), agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate()); - m2s.init(&demod.out); + demod.init(input, dsp::demod::SSB::Mode::LSB, bandwidth, getIFSampleRate(), agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate()); } - void start() { - demod.start(); - m2s.start(); - } + void start() { demod.start(); } - void stop() { - demod.stop(); - m2s.stop(); - } + void stop() { demod.stop(); } void showMenu() { float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::LeftLabel("AGC Attack"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_lsb_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 100.0f)) { + if (ImGui::SliderFloat(("##_radio_lsb_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 200.0f)) { demod.setAGCAttack(agcAttack / getIFSampleRate()); _config->acquire(); _config->conf[name][getName()]["agcAttack"] = agcAttack; @@ -65,13 +57,9 @@ namespace demod { } } - void setBandwidth(double bandwidth) { - demod.setBandwidth(bandwidth); - } + void setBandwidth(double bandwidth) { demod.setBandwidth(bandwidth); } - void setInput(dsp::stream* input) { - demod.setInput(input); - } + void setInput(dsp::stream* input) { demod.setInput(input); } void AFSampRateChanged(double newSR) {} @@ -94,11 +82,10 @@ namespace demod { bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } bool getNBAllowed() { return true; } - dsp::stream* getOutput() { return &m2s.out; } + dsp::stream* getOutput() { return &demod.out; } private: - dsp::demod::SSB demod; - dsp::convert::MonoToStereo m2s; + dsp::demod::SSB demod; ConfigManager* _config; diff --git a/decoder_modules/radio/src/demodulators/nfm.h b/decoder_modules/radio/src/demodulators/nfm.h index f7315d3d..b47a5d02 100644 --- a/decoder_modules/radio/src/demodulators/nfm.h +++ b/decoder_modules/radio/src/demodulators/nfm.h @@ -1,7 +1,6 @@ #pragma once #include "../demod.h" #include -#include namespace demod { class NFM : public Demodulator { @@ -12,37 +11,33 @@ namespace demod { init(name, config, input, bandwidth, outputChangeHandler, afbwChangeHandler, audioSR); } - ~NFM() { - stop(); - } + ~NFM() { stop(); } void init(std::string name, ConfigManager* config, dsp::stream* input, double bandwidth, EventHandler*> outputChangeHandler, EventHandler afbwChangeHandler, double audioSR) { this->name = name; // Define structure - demod.init(input, bandwidth / 2.0, getIFSampleRate()); - m2s.init(&demod.out); + demod.init(input, getIFSampleRate(), bandwidth, _lowPass); } - void start() { - demod.start(); - m2s.start(); - } + void start() { demod.start(); } - void stop() { - demod.stop(); - m2s.stop(); - } + void stop() { demod.stop(); } - void showMenu() {} + void showMenu() { + if (ImGui::Checkbox(("Low Pass##_radio_wfm_lowpass_" + name).c_str(), &_lowPass)) { + demod.setLowPass(_lowPass); + // _config->acquire(); + // _config->conf[name][getName()]["lowPass"] = _lowPass; + // _config->release(true); + } + } void setBandwidth(double bandwidth) { - demod.setDeviation(bandwidth / 2.0, getIFSampleRate()); + demod.setBandwidth(bandwidth); } - void setInput(dsp::stream* input) { - demod.setInput(input); - } + void setInput(dsp::stream* input) { demod.setInput(input); } void AFSampRateChanged(double newSR) {} @@ -65,11 +60,12 @@ namespace demod { bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return true; } bool getNBAllowed() { return false; } - dsp::stream* getOutput() { return &m2s.out; } + dsp::stream* getOutput() { return &demod.out; } private: - dsp::demod::FM demod; - dsp::convert::MonoToStereo m2s; + dsp::demod::FM demod; + + bool _lowPass = true; std::string name; }; diff --git a/decoder_modules/radio/src/demodulators/usb.h b/decoder_modules/radio/src/demodulators/usb.h index 82f8683b..49e5596f 100644 --- a/decoder_modules/radio/src/demodulators/usb.h +++ b/decoder_modules/radio/src/demodulators/usb.h @@ -31,25 +31,18 @@ namespace demod { config->release(); // Define structure - demod.init(input, dsp::demod::SSB::Mode::USB, bandwidth, getIFSampleRate(), agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate()); - m2s.init(&demod.out); + demod.init(input, dsp::demod::SSB::Mode::USB, bandwidth, getIFSampleRate(), agcAttack / getIFSampleRate(), agcDecay / getIFSampleRate()); } - void start() { - demod.start(); - m2s.start(); - } + void start() { demod.start(); } - void stop() { - demod.stop(); - m2s.stop(); - } + void stop() { demod.stop(); } void showMenu() { float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::LeftLabel("AGC Attack"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); - if (ImGui::SliderFloat(("##_radio_usb_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 100.0f)) { + if (ImGui::SliderFloat(("##_radio_usb_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 200.0f)) { demod.setAGCAttack(agcAttack / getIFSampleRate()); _config->acquire(); _config->conf[name][getName()]["agcAttack"] = agcAttack; @@ -65,13 +58,9 @@ namespace demod { } } - void setBandwidth(double bandwidth) { - demod.setBandwidth(bandwidth); - } + void setBandwidth(double bandwidth) { demod.setBandwidth(bandwidth); } - void setInput(dsp::stream* input) { - demod.setInput(input); - } + void setInput(dsp::stream* input) { demod.setInput(input); } void AFSampRateChanged(double newSR) {} @@ -94,11 +83,10 @@ namespace demod { bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } bool getNBAllowed() { return true; } - dsp::stream* getOutput() { return &m2s.out; } + dsp::stream* getOutput() { return &demod.out; } private: - dsp::demod::SSB demod; - dsp::convert::MonoToStereo m2s; + dsp::demod::SSB demod; ConfigManager* _config;