diff --git a/core/src/dsp/noise_reduction.h b/core/src/dsp/noise_reduction.h index 9409161b..79ea4c41 100644 --- a/core/src/dsp/noise_reduction.h +++ b/core/src/dsp/noise_reduction.h @@ -267,7 +267,7 @@ namespace dsp { public: NoiseBlanker() {} - NoiseBlanker(stream* in, float attack, float decay, float threshold, float level, float sampleRate) { init(in, attack, decay, threshold, level, sampleRate); } + NoiseBlanker(stream* in, float level) { init(in, level); } ~NoiseBlanker() { if (!generic_block::_block_init) { return; } @@ -275,16 +275,9 @@ namespace dsp { volk_free(ampBuf); } - void init(stream* in, float attack, float decay, float threshold, float level, float sampleRate) { + void init(stream* in, float level) { _in = in; - _attack = attack; - _decay = decay; - _threshold = powf(10.0f, threshold / 10.0f); - _level = level; - _sampleRate = sampleRate; - - _inv_attack = 1.0f - _attack; - _inv_decay = 1.0f - _decay; + _level = powf(10.0f, level / 10.0f);; ampBuf = (float*)volk_malloc(STREAM_BUFFER_SIZE*sizeof(float), volk_get_alignment()); @@ -293,28 +286,8 @@ namespace dsp { generic_block::_block_init = true; } - void setAttack(float attack) { - _attack = attack; - _inv_attack = 1.0f - _attack; - } - - void setDecay(float decay) { - _decay = decay; - _inv_decay = 1.0f - _decay; - } - - void setThreshold(float threshold) { - _threshold = powf(10.0f, threshold / 10.0f); - spdlog::warn("Threshold {0}", _threshold); - } - void setLevel(float level) { - _level = level; - } - - void setSampleRate(float sampleRate) { - _sampleRate = sampleRate; - // TODO: Change parameters if the algo needs it + _level = powf(10.0f, level / 10.0f); } void setInput(stream* in) { @@ -334,33 +307,13 @@ namespace dsp { // Get amplitudes volk_32fc_magnitude_32f(ampBuf, (lv_32fc_t*)_in->readBuf, count); - // Apply filtering and threshold - float val; + // Hard limit the amplitude + complex_t inVal; for (int i = 0; i < count; i++) { - // Filter using attack/threshold methode - val = ampBuf[i]; - if (val > lastValue) { - lastValue = (_inv_attack*lastValue) + (_attack*val); - } - else { - lastValue = (_inv_decay*lastValue) + (_decay*val); - } - - // Apply threshold and invert - if (lastValue > _threshold) { - ampBuf[i] = _threshold / (lastValue * _level); - if (ampBuf[i] == 0) { - spdlog::warn("WTF???"); - } - } - else { - ampBuf[i] = 1.0f; - } + inVal = _in->readBuf[i]; + out.writeBuf[i] = (ampBuf[i] > _level) ? inVal * (_level / inVal.amplitude()) : inVal; } - // Multiply - volk_32fc_32f_multiply_32fc((lv_32fc_t*)out.writeBuf, (lv_32fc_t*)_in->readBuf, ampBuf, count); - _in->flush(); if (!out.swap(count)) { return -1; } return count; @@ -371,15 +324,7 @@ namespace dsp { private: float* ampBuf; - float _attack; - float _decay; - float _inv_attack; - float _inv_decay; - float _threshold; float _level; - float _sampleRate; - - float lastValue = 0.0f; stream* _in; diff --git a/decoder_modules/radio/src/demod.h b/decoder_modules/radio/src/demod.h index 5f807de9..18d51c85 100644 --- a/decoder_modules/radio/src/demod.h +++ b/decoder_modules/radio/src/demod.h @@ -38,6 +38,7 @@ namespace demod { virtual int getDefaultDeemphasisMode() = 0; virtual double getAFBandwidth(double bandwidth) = 0; virtual bool getFMIFNRAllowed() = 0; + virtual bool getNBAllowed() = 0; virtual bool getDynamicAFBandwidth() = 0; virtual dsp::stream* getOutput() = 0; diff --git a/decoder_modules/radio/src/demodulators/am.h b/decoder_modules/radio/src/demodulators/am.h index 5ef11cd0..f2470fec 100644 --- a/decoder_modules/radio/src/demodulators/am.h +++ b/decoder_modules/radio/src/demodulators/am.h @@ -68,6 +68,7 @@ namespace demod { double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; } bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } + bool getNBAllowed() { return false; } dsp::stream* getOutput() { return &m2s.out; } private: diff --git a/decoder_modules/radio/src/demodulators/cw.h b/decoder_modules/radio/src/demodulators/cw.h index 5b8e3dc6..9eafd2b7 100644 --- a/decoder_modules/radio/src/demodulators/cw.h +++ b/decoder_modules/radio/src/demodulators/cw.h @@ -69,6 +69,7 @@ namespace demod { double getAFBandwidth(double bandwidth) { return (bandwidth / 2.0) + 1000.0; } bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } + bool getNBAllowed() { return false; } dsp::stream* getOutput() { return &m2s.out; } private: diff --git a/decoder_modules/radio/src/demodulators/dsb.h b/decoder_modules/radio/src/demodulators/dsb.h index 08d0c03d..f0854e1d 100644 --- a/decoder_modules/radio/src/demodulators/dsb.h +++ b/decoder_modules/radio/src/demodulators/dsb.h @@ -70,6 +70,7 @@ namespace demod { double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; } bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } + bool getNBAllowed() { return true; } dsp::stream* getOutput() { return &m2s.out; } private: diff --git a/decoder_modules/radio/src/demodulators/lsb.h b/decoder_modules/radio/src/demodulators/lsb.h index 0b47b69c..0d423ebc 100644 --- a/decoder_modules/radio/src/demodulators/lsb.h +++ b/decoder_modules/radio/src/demodulators/lsb.h @@ -70,6 +70,7 @@ namespace demod { double getAFBandwidth(double bandwidth) { return bandwidth; } bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } + bool getNBAllowed() { return true; } dsp::stream* getOutput() { return &m2s.out; } private: diff --git a/decoder_modules/radio/src/demodulators/nfm.h b/decoder_modules/radio/src/demodulators/nfm.h index 7c988f2b..6a5f93ce 100644 --- a/decoder_modules/radio/src/demodulators/nfm.h +++ b/decoder_modules/radio/src/demodulators/nfm.h @@ -62,6 +62,7 @@ namespace demod { double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; } bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return true; } + bool getNBAllowed() { return false; } dsp::stream* getOutput() { return &demod.out; } private: diff --git a/decoder_modules/radio/src/demodulators/raw.h b/decoder_modules/radio/src/demodulators/raw.h index 19d030ac..1956a807 100644 --- a/decoder_modules/radio/src/demodulators/raw.h +++ b/decoder_modules/radio/src/demodulators/raw.h @@ -63,6 +63,7 @@ namespace demod { double getAFBandwidth(double bandwidth) { return bandwidth; } bool getDynamicAFBandwidth() { return false; } bool getFMIFNRAllowed() { return false; } + bool getNBAllowed() { return true; } dsp::stream* getOutput() { return &c2s.out; } private: diff --git a/decoder_modules/radio/src/demodulators/usb.h b/decoder_modules/radio/src/demodulators/usb.h index 5686a08d..1b9ac233 100644 --- a/decoder_modules/radio/src/demodulators/usb.h +++ b/decoder_modules/radio/src/demodulators/usb.h @@ -70,6 +70,7 @@ namespace demod { double getAFBandwidth(double bandwidth) { return bandwidth; } bool getDynamicAFBandwidth() { return true; } bool getFMIFNRAllowed() { return false; } + bool getNBAllowed() { return true; } dsp::stream* getOutput() { return &m2s.out; } private: diff --git a/decoder_modules/radio/src/demodulators/wfm.h b/decoder_modules/radio/src/demodulators/wfm.h index cab30b44..5d512a0f 100644 --- a/decoder_modules/radio/src/demodulators/wfm.h +++ b/decoder_modules/radio/src/demodulators/wfm.h @@ -86,6 +86,7 @@ namespace demod { double getAFBandwidth(double bandwidth) { return 16000.0; } bool getDynamicAFBandwidth() { return false; } bool getFMIFNRAllowed() { return true; } + bool getNBAllowed() { return false; } dsp::stream* getOutput() { return stereo ? demodStereo.out : &demod.out; } // ============= DEDICATED FUNCTIONS ============= diff --git a/decoder_modules/radio/src/radio_module.h b/decoder_modules/radio/src/radio_module.h index a2f2ffec..c63694b2 100644 --- a/decoder_modules/radio/src/radio_module.h +++ b/decoder_modules/radio/src/radio_module.h @@ -62,10 +62,12 @@ public: fmnr.block.init(NULL, 32); notch.block.init(NULL, 0.5, 0, 250000); // TODO: The rate has to depend on IF sample rate so the width is always the same squelch.block.init(NULL, MIN_SQUELCH); + nb.block.init(NULL, -100.0f); ifChain.add(¬ch); ifChain.add(&squelch); ifChain.add(&fmnr); + ifChain.add(&nb); // Load configuration for and enabled all demodulators EventHandler*> _demodOutputChangeHandler; @@ -258,6 +260,21 @@ private: } if (!_this->squelchEnabled && _this->enabled) { style::endDisabled(); } + // Noise blanker + if (_this->nbAllowed) { + if (ImGui::Checkbox(("Noise Blanker##_radio_nb_ena_" + _this->name).c_str(), &_this->nbEnabled)) { + _this->setNoiseBlankerEnabled(_this->nbEnabled); + } + if (!_this->nbEnabled && _this->enabled) { style::beginDisabled(); } + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_nb_lvl_" + _this->name).c_str(), &_this->nbLevel, 0.0f, -100.0f, "%.3fdB")) { + _this->setNoiseBlankerLevel(_this->nbLevel); + } + if (!_this->nbEnabled && _this->enabled) { style::endDisabled(); } + } + + // // Notch filter // if (ImGui::Checkbox("Notch##_radio_notch_ena_", &_this->notchEnabled)) { // _this->ifChain.setState(&_this->notch, _this->notchEnabled); @@ -324,6 +341,10 @@ private: postProcEnabled = selectedDemod->getPostProcEnabled(); FMIFNRAllowed = selectedDemod->getFMIFNRAllowed(); FMIFNREnabled = false; + nbAllowed = selectedDemod->getNBAllowed(); + nbEnabled = false; + nbLevel = 0.0f; + config.acquire(); if (config.conf[name][selectedDemod->getName()].contains("bandwidth")) { bandwidth = config.conf[name][selectedDemod->getName()]["bandwidth"]; bandwidth = std::clamp(bandwidth, minBandwidth, maxBandwidth); @@ -343,6 +364,16 @@ private: if (config.conf[name][selectedDemod->getName()].contains("FMIFNREnabled")) { FMIFNREnabled = config.conf[name][selectedDemod->getName()]["FMIFNREnabled"]; } + if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerEnabled")) { + nbEnabled = config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"]; + } + if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerEnabled")) { + nbEnabled = config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"]; + } + if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerLevel")) { + nbLevel = config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"]; + } + config.release(); deempMode = std::clamp(deempMode, 0, _DEEMP_MODE_COUNT-1); // Configure VFO @@ -363,6 +394,10 @@ private: squelch.block.setLevel(squelchLevel); setSquelchEnabled(squelchEnabled); + // Configure noise blanker + nb.block.setLevel(nbLevel); + setNoiseBlankerEnabled(nbEnabled); + // Configure AF chain if (postProcEnabled) { // Configure resampler @@ -483,6 +518,28 @@ private: config.release(true); } + void setNoiseBlankerEnabled(bool enabled) { + nbEnabled = enabled; + if (!selectedDemod) { return; } + ifChain.setState(&nb, nbEnabled); + + // Save config + config.acquire(); + config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"] = nbEnabled; + config.release(true); + } + + void setNoiseBlankerLevel(float level) { + nbLevel = level; + if (!selectedDemod) { return; } + nb.block.setLevel(nbLevel); + + // Save config + config.acquire(); + config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"] = nbLevel; + config.release(true); + } + static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { RadioModule* _this = (RadioModule*)ctx; _this->setBandwidth(newBw); @@ -568,6 +625,7 @@ private: dsp::ChainLink fmnr; dsp::ChainLink notch; dsp::ChainLink squelch; + dsp::ChainLink nb; // Audio chain dsp::stream dummyAudioStream; @@ -587,12 +645,15 @@ private: float bandwidth; bool bandwidthLocked; int snapInterval; + int selectedDemodID = 1; + bool postProcEnabled; + bool squelchEnabled = false; float squelchLevel; - int selectedDemodID = 1; + int deempMode = DEEMP_MODE_NONE; bool deempAllowed; - bool postProcEnabled; + bool FMIFNRAllowed; bool FMIFNREnabled = false; @@ -600,6 +661,10 @@ private: float notchPos = 0; float notchWidth = 500; + bool nbAllowed; + bool nbEnabled; + float nbLevel = -100.0f; + const double MIN_SQUELCH = -100.0; const double MAX_SQUELCH = 0.0;