mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-06 10:47:34 +01:00
Prototype noise blanker
This commit is contained in:
parent
c3ddffb3a9
commit
3f6687659e
78
core/src/dsp/noise_reduction/noise_blanker.h
Normal file
78
core/src/dsp/noise_reduction/noise_blanker.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../processor.h"
|
||||||
|
|
||||||
|
namespace dsp::noise_reduction {
|
||||||
|
class NoiseBlanker : public Processor<complex_t, complex_t> {
|
||||||
|
using base_type = Processor<complex_t, complex_t>;
|
||||||
|
public:
|
||||||
|
NoiseBlanker() {}
|
||||||
|
|
||||||
|
NoiseBlanker(stream<complex_t>* in, double rate, double level) { init(in, rate, level); }
|
||||||
|
|
||||||
|
void init(stream<complex_t>* in, double rate, double level) {
|
||||||
|
_rate = rate;
|
||||||
|
_invRate = 1.0f - _rate;
|
||||||
|
_level = level;
|
||||||
|
base_type::init(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRate(double rate) {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
_rate = rate;
|
||||||
|
_invRate = 1.0f - _rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLevel(double level) {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
amp = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int process(int count, complex_t* in, complex_t* out) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
// Get signal amplitude
|
||||||
|
float inAmp = in[i].amplitude();
|
||||||
|
|
||||||
|
// Update average amplitude
|
||||||
|
float gain = 1.0f;
|
||||||
|
if (inAmp != 0.0f) {
|
||||||
|
amp = (amp * _invRate) + (inAmp * _rate);
|
||||||
|
float excess = inAmp / amp;
|
||||||
|
if (excess > _level) {
|
||||||
|
gain = 1.0f / excess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale output by gain
|
||||||
|
out[i] = in[i] * gain;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float _rate;
|
||||||
|
float _invRate;
|
||||||
|
float _level;
|
||||||
|
|
||||||
|
float amp = 1.0;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
@ -38,17 +38,13 @@ namespace demod {
|
|||||||
virtual double getMinBandwidth() = 0;
|
virtual double getMinBandwidth() = 0;
|
||||||
virtual double getMaxBandwidth() = 0;
|
virtual double getMaxBandwidth() = 0;
|
||||||
virtual bool getBandwidthLocked() = 0;
|
virtual bool getBandwidthLocked() = 0;
|
||||||
virtual double getMaxAFBandwidth() = 0;
|
|
||||||
virtual double getDefaultSnapInterval() = 0;
|
virtual double getDefaultSnapInterval() = 0;
|
||||||
virtual int getVFOReference() = 0;
|
virtual int getVFOReference() = 0;
|
||||||
virtual bool getDeempAllowed() = 0;
|
virtual bool getDeempAllowed() = 0;
|
||||||
virtual bool getPostProcEnabled() = 0;
|
virtual bool getPostProcEnabled() = 0;
|
||||||
virtual int getDefaultDeemphasisMode() = 0;
|
virtual int getDefaultDeemphasisMode() = 0;
|
||||||
virtual double getAFBandwidth(double bandwidth) = 0;
|
|
||||||
virtual bool getFMIFNRAllowed() = 0;
|
virtual bool getFMIFNRAllowed() = 0;
|
||||||
virtual bool getNBAllowed() = 0;
|
virtual bool getNBAllowed() = 0;
|
||||||
|
|
||||||
virtual bool getDynamicAFBandwidth() = 0;
|
|
||||||
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;
|
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -79,14 +79,11 @@ namespace demod {
|
|||||||
double getMinBandwidth() { return 1000.0; }
|
double getMinBandwidth() { return 1000.0; }
|
||||||
double getMaxBandwidth() { return getIFSampleRate(); }
|
double getMaxBandwidth() { return getIFSampleRate(); }
|
||||||
bool getBandwidthLocked() { return false; }
|
bool getBandwidthLocked() { return false; }
|
||||||
double getMaxAFBandwidth() { return getIFSampleRate() / 2.0; }
|
|
||||||
double getDefaultSnapInterval() { return 1000.0; }
|
double getDefaultSnapInterval() { return 1000.0; }
|
||||||
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
||||||
bool getDeempAllowed() { return false; }
|
bool getDeempAllowed() { return false; }
|
||||||
bool getPostProcEnabled() { return true; }
|
bool getPostProcEnabled() { return true; }
|
||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; }
|
|
||||||
bool getDynamicAFBandwidth() { return true; }
|
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
@ -85,14 +85,11 @@ namespace demod {
|
|||||||
double getMinBandwidth() { return 50.0; }
|
double getMinBandwidth() { return 50.0; }
|
||||||
double getMaxBandwidth() { return 500.0; }
|
double getMaxBandwidth() { return 500.0; }
|
||||||
bool getBandwidthLocked() { return false; }
|
bool getBandwidthLocked() { return false; }
|
||||||
double getMaxAFBandwidth() { return getIFSampleRate() / 2.0; }
|
|
||||||
double getDefaultSnapInterval() { return 10.0; }
|
double getDefaultSnapInterval() { return 10.0; }
|
||||||
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
||||||
bool getDeempAllowed() { return false; }
|
bool getDeempAllowed() { return false; }
|
||||||
bool getPostProcEnabled() { return true; }
|
bool getPostProcEnabled() { return true; }
|
||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
double getAFBandwidth(double bandwidth) { return (bandwidth / 2.0) + (float)tone; }
|
|
||||||
bool getDynamicAFBandwidth() { return true; }
|
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
@ -72,14 +72,11 @@ namespace demod {
|
|||||||
double getMinBandwidth() { return 1000.0; }
|
double getMinBandwidth() { return 1000.0; }
|
||||||
double getMaxBandwidth() { return getIFSampleRate() / 2.0; }
|
double getMaxBandwidth() { return getIFSampleRate() / 2.0; }
|
||||||
bool getBandwidthLocked() { return false; }
|
bool getBandwidthLocked() { return false; }
|
||||||
double getMaxAFBandwidth() { return getIFSampleRate() / 2.0; }
|
|
||||||
double getDefaultSnapInterval() { return 100.0; }
|
double getDefaultSnapInterval() { return 100.0; }
|
||||||
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
||||||
bool getDeempAllowed() { return false; }
|
bool getDeempAllowed() { return false; }
|
||||||
bool getPostProcEnabled() { return true; }
|
bool getPostProcEnabled() { return true; }
|
||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; }
|
|
||||||
bool getDynamicAFBandwidth() { return true; }
|
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
@ -72,14 +72,11 @@ namespace demod {
|
|||||||
double getMinBandwidth() { return 500.0; }
|
double getMinBandwidth() { return 500.0; }
|
||||||
double getMaxBandwidth() { return getIFSampleRate() / 2.0; }
|
double getMaxBandwidth() { return getIFSampleRate() / 2.0; }
|
||||||
bool getBandwidthLocked() { return false; }
|
bool getBandwidthLocked() { return false; }
|
||||||
double getMaxAFBandwidth() { return getIFSampleRate() / 2.0; }
|
|
||||||
double getDefaultSnapInterval() { return 100.0; }
|
double getDefaultSnapInterval() { return 100.0; }
|
||||||
int getVFOReference() { return ImGui::WaterfallVFO::REF_UPPER; }
|
int getVFOReference() { return ImGui::WaterfallVFO::REF_UPPER; }
|
||||||
bool getDeempAllowed() { return false; }
|
bool getDeempAllowed() { return false; }
|
||||||
bool getPostProcEnabled() { return true; }
|
bool getPostProcEnabled() { return true; }
|
||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
double getAFBandwidth(double bandwidth) { return bandwidth; }
|
|
||||||
bool getDynamicAFBandwidth() { return true; }
|
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
@ -50,14 +50,11 @@ namespace demod {
|
|||||||
double getMinBandwidth() { return 1000.0; }
|
double getMinBandwidth() { return 1000.0; }
|
||||||
double getMaxBandwidth() { return getIFSampleRate(); }
|
double getMaxBandwidth() { return getIFSampleRate(); }
|
||||||
bool getBandwidthLocked() { return false; }
|
bool getBandwidthLocked() { return false; }
|
||||||
double getMaxAFBandwidth() { return getIFSampleRate() / 2.0; }
|
|
||||||
double getDefaultSnapInterval() { return 2500.0; }
|
double getDefaultSnapInterval() { return 2500.0; }
|
||||||
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
||||||
bool getDeempAllowed() { return true; }
|
bool getDeempAllowed() { return true; }
|
||||||
bool getPostProcEnabled() { return true; }
|
bool getPostProcEnabled() { return true; }
|
||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; }
|
|
||||||
bool getDynamicAFBandwidth() { return true; }
|
|
||||||
bool getFMIFNRAllowed() { return true; }
|
bool getFMIFNRAllowed() { return true; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
@ -52,14 +52,11 @@ namespace demod {
|
|||||||
double getMinBandwidth() { return audioSampleRate; }
|
double getMinBandwidth() { return audioSampleRate; }
|
||||||
double getMaxBandwidth() { return audioSampleRate; }
|
double getMaxBandwidth() { return audioSampleRate; }
|
||||||
bool getBandwidthLocked() { return true; }
|
bool getBandwidthLocked() { return true; }
|
||||||
double getMaxAFBandwidth() { return audioSampleRate; }
|
|
||||||
double getDefaultSnapInterval() { return 2500.0; }
|
double getDefaultSnapInterval() { return 2500.0; }
|
||||||
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
||||||
bool getDeempAllowed() { return false; }
|
bool getDeempAllowed() { return false; }
|
||||||
bool getPostProcEnabled() { return false; }
|
bool getPostProcEnabled() { return false; }
|
||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
double getAFBandwidth(double bandwidth) { return bandwidth; }
|
|
||||||
bool getDynamicAFBandwidth() { return false; }
|
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &c2s.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &c2s.out; }
|
||||||
|
@ -73,14 +73,11 @@ namespace demod {
|
|||||||
double getMinBandwidth() { return 500.0; }
|
double getMinBandwidth() { return 500.0; }
|
||||||
double getMaxBandwidth() { return getIFSampleRate() / 2.0; }
|
double getMaxBandwidth() { return getIFSampleRate() / 2.0; }
|
||||||
bool getBandwidthLocked() { return false; }
|
bool getBandwidthLocked() { return false; }
|
||||||
double getMaxAFBandwidth() { return getIFSampleRate() / 2.0; }
|
|
||||||
double getDefaultSnapInterval() { return 100.0; }
|
double getDefaultSnapInterval() { return 100.0; }
|
||||||
int getVFOReference() { return ImGui::WaterfallVFO::REF_LOWER; }
|
int getVFOReference() { return ImGui::WaterfallVFO::REF_LOWER; }
|
||||||
bool getDeempAllowed() { return false; }
|
bool getDeempAllowed() { return false; }
|
||||||
bool getPostProcEnabled() { return true; }
|
bool getPostProcEnabled() { return true; }
|
||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
double getAFBandwidth(double bandwidth) { return bandwidth; }
|
|
||||||
bool getDynamicAFBandwidth() { return true; }
|
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
@ -76,14 +76,11 @@ namespace demod {
|
|||||||
double getMinBandwidth() { return 50000.0; }
|
double getMinBandwidth() { return 50000.0; }
|
||||||
double getMaxBandwidth() { return getIFSampleRate(); }
|
double getMaxBandwidth() { return getIFSampleRate(); }
|
||||||
bool getBandwidthLocked() { return false; }
|
bool getBandwidthLocked() { return false; }
|
||||||
double getMaxAFBandwidth() { return 16000.0; }
|
|
||||||
double getDefaultSnapInterval() { return 100000.0; }
|
double getDefaultSnapInterval() { return 100000.0; }
|
||||||
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
int getVFOReference() { return ImGui::WaterfallVFO::REF_CENTER; }
|
||||||
bool getDeempAllowed() { return true; }
|
bool getDeempAllowed() { return true; }
|
||||||
bool getPostProcEnabled() { return true; }
|
bool getPostProcEnabled() { return true; }
|
||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_50US; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_50US; }
|
||||||
double getAFBandwidth(double bandwidth) { return 16000.0; }
|
|
||||||
bool getDynamicAFBandwidth() { return false; }
|
|
||||||
bool getFMIFNRAllowed() { return true; }
|
bool getFMIFNRAllowed() { return true; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <dsp/chain.h>
|
#include <dsp/chain.h>
|
||||||
|
#include <dsp/noise_reduction/noise_blanker.h>
|
||||||
#include <dsp/noise_reduction/fm_if.h>
|
#include <dsp/noise_reduction/fm_if.h>
|
||||||
#include <dsp/noise_reduction/squelch.h>
|
#include <dsp/noise_reduction/squelch.h>
|
||||||
#include <dsp/multirate/rational_resampler.h>
|
#include <dsp/multirate/rational_resampler.h>
|
||||||
@ -68,9 +69,11 @@ public:
|
|||||||
ifChainOutputChanged.handler = ifChainOutputChangeHandler;
|
ifChainOutputChanged.handler = ifChainOutputChangeHandler;
|
||||||
ifChain.init(vfo->output);
|
ifChain.init(vfo->output);
|
||||||
|
|
||||||
|
nb.init(NULL, 500.0 / 24000.0, 10.0);
|
||||||
fmnr.init(NULL, 32);
|
fmnr.init(NULL, 32);
|
||||||
squelch.init(NULL, MIN_SQUELCH);
|
squelch.init(NULL, MIN_SQUELCH);
|
||||||
|
|
||||||
|
ifChain.addBlock(&nb, false);
|
||||||
ifChain.addBlock(&squelch, false);
|
ifChain.addBlock(&squelch, false);
|
||||||
ifChain.addBlock(&fmnr, false);
|
ifChain.addBlock(&fmnr, false);
|
||||||
|
|
||||||
@ -228,6 +231,18 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Noise blanker
|
||||||
|
if (ImGui::Checkbox(("Noise blanker (W.I.P.)##_radio_nb_ena_" + _this->name).c_str(), &_this->nbEnabled)) {
|
||||||
|
_this->setNBEnabled(_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, _this->MIN_NB, _this->MAX_NB, "%.3fdB")) {
|
||||||
|
_this->setNBLevel(_this->nbLevel);
|
||||||
|
}
|
||||||
|
if (!_this->nbEnabled && _this->enabled) { style::endDisabled(); }
|
||||||
|
|
||||||
// Squelch
|
// Squelch
|
||||||
if (ImGui::Checkbox(("Squelch##_radio_sqelch_ena_" + _this->name).c_str(), &_this->squelchEnabled)) {
|
if (ImGui::Checkbox(("Squelch##_radio_sqelch_ena_" + _this->name).c_str(), &_this->squelchEnabled)) {
|
||||||
_this->setSquelchEnabled(_this->squelchEnabled);
|
_this->setSquelchEnabled(_this->squelchEnabled);
|
||||||
@ -351,6 +366,7 @@ private:
|
|||||||
nbAllowed = selectedDemod->getNBAllowed();
|
nbAllowed = selectedDemod->getNBAllowed();
|
||||||
nbEnabled = false;
|
nbEnabled = false;
|
||||||
nbLevel = 0.0f;
|
nbLevel = 0.0f;
|
||||||
|
double ifSamplerate = selectedDemod->getIFSampleRate();
|
||||||
config.acquire();
|
config.acquire();
|
||||||
if (config.conf[name][selectedDemod->getName()].contains("bandwidth")) {
|
if (config.conf[name][selectedDemod->getName()].contains("bandwidth")) {
|
||||||
bandwidth = config.conf[name][selectedDemod->getName()]["bandwidth"];
|
bandwidth = config.conf[name][selectedDemod->getName()]["bandwidth"];
|
||||||
@ -387,9 +403,6 @@ private:
|
|||||||
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerEnabled")) {
|
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerEnabled")) {
|
||||||
nbEnabled = config.conf[name][selectedDemod->getName()]["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")) {
|
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerLevel")) {
|
||||||
nbLevel = config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"];
|
nbLevel = config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"];
|
||||||
}
|
}
|
||||||
@ -400,18 +413,23 @@ private:
|
|||||||
vfo->setBandwidthLimits(minBandwidth, maxBandwidth, selectedDemod->getBandwidthLocked());
|
vfo->setBandwidthLimits(minBandwidth, maxBandwidth, selectedDemod->getBandwidthLocked());
|
||||||
vfo->setReference(selectedDemod->getVFOReference());
|
vfo->setReference(selectedDemod->getVFOReference());
|
||||||
vfo->setSnapInterval(snapInterval);
|
vfo->setSnapInterval(snapInterval);
|
||||||
vfo->setSampleRate(selectedDemod->getIFSampleRate(), bandwidth);
|
vfo->setSampleRate(ifSamplerate, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure bandwidth
|
// Configure bandwidth
|
||||||
setBandwidth(bandwidth);
|
setBandwidth(bandwidth);
|
||||||
|
|
||||||
|
// Configure noise blanker
|
||||||
|
nb.setRate(500.0 / ifSamplerate);
|
||||||
|
setNBLevel(nbLevel);
|
||||||
|
setNBEnabled(nbEnabled);
|
||||||
|
|
||||||
// Configure FM IF Noise Reduction
|
// Configure FM IF Noise Reduction
|
||||||
setIFNRPreset((selectedDemodID == RADIO_DEMOD_NFM) ? ifnrPresets[fmIFPresetId] : IFNR_PRESET_BROADCAST);
|
setIFNRPreset((selectedDemodID == RADIO_DEMOD_NFM) ? ifnrPresets[fmIFPresetId] : IFNR_PRESET_BROADCAST);
|
||||||
setFMIFNREnabled(FMIFNRAllowed ? FMIFNREnabled : false);
|
setFMIFNREnabled(FMIFNRAllowed ? FMIFNREnabled : false);
|
||||||
|
|
||||||
// Configure squelch
|
// Configure squelch
|
||||||
squelch.setLevel(squelchLevel);
|
setSquelchLevel(squelchLevel);
|
||||||
setSquelchEnabled(squelchEnabled);
|
setSquelchEnabled(squelchEnabled);
|
||||||
|
|
||||||
// Configure AF chain
|
// Configure AF chain
|
||||||
@ -439,18 +457,9 @@ private:
|
|||||||
bw = std::clamp<double>(bw, minBandwidth, maxBandwidth);
|
bw = std::clamp<double>(bw, minBandwidth, maxBandwidth);
|
||||||
bandwidth = bw;
|
bandwidth = bw;
|
||||||
if (!selectedDemod) { return; }
|
if (!selectedDemod) { return; }
|
||||||
float audioBW = std::min<float>(selectedDemod->getMaxAFBandwidth(), selectedDemod->getAFBandwidth(bandwidth));
|
|
||||||
audioBW = std::min<float>(audioBW, audioSampleRate / 2.0);
|
|
||||||
vfo->setBandwidth(bandwidth);
|
vfo->setBandwidth(bandwidth);
|
||||||
selectedDemod->setBandwidth(bandwidth);
|
selectedDemod->setBandwidth(bandwidth);
|
||||||
|
|
||||||
// // Only bother with setting the resampling setting if we're actually post processing and dynamic bw is enabled
|
|
||||||
// if (selectedDemod->getDynamicAFBandwidth() && postProcEnabled) {
|
|
||||||
// win.setCutoff(audioBW);
|
|
||||||
// win.setTransWidth(audioBW);
|
|
||||||
// resamp.block.updateWindow(&win);
|
|
||||||
// }
|
|
||||||
|
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[name][selectedDemod->getName()]["bandwidth"] = bandwidth;
|
config.conf[name][selectedDemod->getName()]["bandwidth"] = bandwidth;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
@ -469,17 +478,10 @@ private:
|
|||||||
vfo->setSampleRate(selectedDemod->getIFSampleRate(), bandwidth);
|
vfo->setSampleRate(selectedDemod->getIFSampleRate(), bandwidth);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float audioBW = std::min<float>(selectedDemod->getMaxAFBandwidth(), selectedDemod->getAFBandwidth(bandwidth));
|
|
||||||
audioBW = std::min<float>(audioBW, audioSampleRate / 2.0);
|
|
||||||
|
|
||||||
afChain.stop();
|
afChain.stop();
|
||||||
|
|
||||||
// // Configure resampler
|
// Configure resampler
|
||||||
// resamp.block.setOutSampleRate(audioSampleRate);
|
|
||||||
// win.setSampleRate(selectedDemod->getAFSampleRate() * resamp.block.getInterpolation());
|
|
||||||
// win.setCutoff(audioBW);
|
|
||||||
// win.setTransWidth(audioBW);
|
|
||||||
// resamp.block.updateWindow(&win);
|
|
||||||
resamp.setOutSamplerate(audioSampleRate);
|
resamp.setOutSamplerate(audioSampleRate);
|
||||||
|
|
||||||
// Configure deemphasis sample rate
|
// Configure deemphasis sample rate
|
||||||
@ -501,6 +503,27 @@ private:
|
|||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setNBEnabled(bool enable) {
|
||||||
|
nbEnabled = enable;
|
||||||
|
if (!selectedDemod) { return; }
|
||||||
|
ifChain.setBlockEnabled(&nb, nbEnabled, [=](dsp::stream<dsp::complex_t>* out){ selectedDemod->setInput(out); });
|
||||||
|
|
||||||
|
// Save config
|
||||||
|
config.acquire();
|
||||||
|
config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"] = nbEnabled;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNBLevel(float level) {
|
||||||
|
nbLevel = std::clamp<float>(level, MIN_NB, MAX_NB);
|
||||||
|
nb.setLevel(nbLevel);
|
||||||
|
|
||||||
|
// Save config
|
||||||
|
config.acquire();
|
||||||
|
config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"] = nbLevel;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
|
||||||
void setSquelchEnabled(bool enable) {
|
void setSquelchEnabled(bool enable) {
|
||||||
squelchEnabled = enable;
|
squelchEnabled = enable;
|
||||||
if (!selectedDemod) { return; }
|
if (!selectedDemod) { return; }
|
||||||
@ -623,6 +646,7 @@ private:
|
|||||||
|
|
||||||
// IF chain
|
// IF chain
|
||||||
dsp::chain<dsp::complex_t> ifChain;
|
dsp::chain<dsp::complex_t> ifChain;
|
||||||
|
dsp::noise_reduction::NoiseBlanker nb;
|
||||||
dsp::noise_reduction::FMIF fmnr;
|
dsp::noise_reduction::FMIF fmnr;
|
||||||
dsp::noise_reduction::Squelch squelch;
|
dsp::noise_reduction::Squelch squelch;
|
||||||
|
|
||||||
@ -663,9 +687,11 @@ private:
|
|||||||
float notchWidth = 500;
|
float notchWidth = 500;
|
||||||
|
|
||||||
bool nbAllowed;
|
bool nbAllowed;
|
||||||
bool nbEnabled;
|
bool nbEnabled = false;
|
||||||
float nbLevel = -100.0f;
|
float nbLevel = 10.0f;
|
||||||
|
|
||||||
|
const double MIN_NB = 1.0;
|
||||||
|
const double MAX_NB = 10.0;
|
||||||
const double MIN_SQUELCH = -100.0;
|
const double MIN_SQUELCH = -100.0;
|
||||||
const double MAX_SQUELCH = 0.0;
|
const double MAX_SQUELCH = 0.0;
|
||||||
|
|
||||||
|
@ -67,11 +67,15 @@ public:
|
|||||||
if (!config.conf[name].contains("audioVolume")) {
|
if (!config.conf[name].contains("audioVolume")) {
|
||||||
config.conf[name]["audioVolume"] = 1.0;
|
config.conf[name]["audioVolume"] = 1.0;
|
||||||
}
|
}
|
||||||
|
if (!config.conf[name].contains("ignoreSilence")) {
|
||||||
|
config.conf[name]["ignoreSilence"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
recMode = config.conf[name]["mode"];
|
recMode = config.conf[name]["mode"];
|
||||||
folderSelect.setPath(config.conf[name]["recPath"]);
|
folderSelect.setPath(config.conf[name]["recPath"]);
|
||||||
selectedStreamName = config.conf[name]["audioStream"];
|
selectedStreamName = config.conf[name]["audioStream"];
|
||||||
audioVolume = config.conf[name]["audioVolume"];
|
audioVolume = config.conf[name]["audioVolume"];
|
||||||
|
ignoreSilence = config.conf[name]["ignoreSilence"];
|
||||||
config.release(created);
|
config.release(created);
|
||||||
|
|
||||||
// Init audio path
|
// Init audio path
|
||||||
@ -291,6 +295,12 @@ private:
|
|||||||
}
|
}
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
if (ImGui::Checkbox(CONCAT("Ignore silence##_recorder_ing_silence_", name), &ignoreSilence)) {
|
||||||
|
config.acquire();
|
||||||
|
config.conf[name]["ignoreSilence"] = ignoreSilence;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (!folderSelect.pathIsValid() || selectedStreamName == "") { style::beginDisabled(); }
|
if (!folderSelect.pathIsValid() || selectedStreamName == "") { style::beginDisabled(); }
|
||||||
if (!recording) {
|
if (!recording) {
|
||||||
if (ImGui::Button(CONCAT("Record##_recorder_rec_", name), ImVec2(menuColumnWidth, 0))) {
|
if (ImGui::Button(CONCAT("Record##_recorder_rec_", name), ImVec2(menuColumnWidth, 0))) {
|
||||||
@ -314,6 +324,9 @@ private:
|
|||||||
|
|
||||||
static void _audioHandler(dsp::stereo_t* data, int count, void* ctx) {
|
static void _audioHandler(dsp::stereo_t* data, int count, void* ctx) {
|
||||||
RecorderModule* _this = (RecorderModule*)ctx;
|
RecorderModule* _this = (RecorderModule*)ctx;
|
||||||
|
if (_this->ignoreSilence && data[0].l == 0.0f && data[0].r == 0.0f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
volk_32f_s32f_convert_16i(_this->wavSampleBuf, (float*)data, 32767.0f, count * 2);
|
volk_32f_s32f_convert_16i(_this->wavSampleBuf, (float*)data, 32767.0f, count * 2);
|
||||||
_this->audioWriter->writeSamples(_this->wavSampleBuf, count * 2 * sizeof(int16_t));
|
_this->audioWriter->writeSamples(_this->wavSampleBuf, count * 2 * sizeof(int16_t));
|
||||||
_this->samplesWritten += count;
|
_this->samplesWritten += count;
|
||||||
@ -514,6 +527,8 @@ private:
|
|||||||
EventHandler<std::string> streamRegisteredHandler;
|
EventHandler<std::string> streamRegisteredHandler;
|
||||||
EventHandler<std::string> streamUnregisterHandler;
|
EventHandler<std::string> streamUnregisterHandler;
|
||||||
EventHandler<std::string> streamUnregisteredHandler;
|
EventHandler<std::string> streamUnregisteredHandler;
|
||||||
|
|
||||||
|
bool ignoreSilence = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RecorderContext_t {
|
struct RecorderContext_t {
|
||||||
|
Loading…
Reference in New Issue
Block a user