1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-08-01 16:38:06 -04:00

BFM Demodulator: added a combo to select de-emphasis time constant. Fixes #2374

This commit is contained in:
f4exb
2026-01-04 01:04:04 +01:00
parent 6d3a001f6b
commit 7c2272d913
17 changed files with 155 additions and 16 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.
+15
View File
@@ -217,6 +217,7 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_afBandwidth: " << settings.m_afBandwidth
<< " m_deEmphasis: " << settings.getDeEmphasisTimeConstant()
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_audioStereo: " << settings.m_audioStereo
@@ -257,6 +258,9 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
reverseAPIKeys.append("rfBandwidth");
}
if ((settings.m_deEmphasis != m_settings.m_deEmphasis) || force) {
reverseAPIKeys.append("deEmphasis");
}
if ((settings.m_squelch != m_settings.m_squelch) || force) {
reverseAPIKeys.append("squelch");
}
@@ -386,6 +390,13 @@ void BFMDemod::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("afBandwidth")) {
settings.m_afBandwidth = response.getBfmDemodSettings()->getAfBandwidth();
}
if (channelSettingsKeys.contains("deEmphasis"))
{
int deEmphasis = response.getBfmDemodSettings()->getDeEmphasis();
if (deEmphasis >= 0 && deEmphasis < 2) {
settings.m_deEmphasis = static_cast<BFMDemodSettings::DeEmphasis>(deEmphasis);
}
}
if (channelSettingsKeys.contains("volume")) {
settings.m_volume = response.getBfmDemodSettings()->getVolume();
}
@@ -461,6 +472,7 @@ void BFMDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp
response.getBfmDemodSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
response.getBfmDemodSettings()->setRfBandwidth(settings.m_rfBandwidth);
response.getBfmDemodSettings()->setAfBandwidth(settings.m_afBandwidth);
response.getBfmDemodSettings()->setDeEmphasis(static_cast<int>(settings.m_deEmphasis));
response.getBfmDemodSettings()->setVolume(settings.m_volume);
response.getBfmDemodSettings()->setSquelch(settings.m_squelch);
response.getBfmDemodSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
@@ -672,6 +684,9 @@ void BFMDemod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("afBandwidth") || force) {
swgBFMDemodSettings->setAfBandwidth(settings.m_afBandwidth);
}
if (channelSettingsKeys.contains("deEmphasis") || force) {
swgBFMDemodSettings->setDeEmphasis(static_cast<int>(settings.m_deEmphasis));
}
if (channelSettingsKeys.contains("volume") || force) {
swgBFMDemodSettings->setVolume(settings.m_volume);
}
@@ -179,6 +179,12 @@ void BFMDemodGUI::on_afBW_valueChanged(int value)
applySettings();
}
void BFMDemodGUI::on_deEmphasis_currentIndexChanged(int index)
{
m_settings.m_deEmphasis = static_cast<BFMDemodSettings::DeEmphasis>(index);
applySettings();
}
void BFMDemodGUI::on_volume_valueChanged(int value)
{
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
@@ -886,6 +892,7 @@ void BFMDemodGUI::makeUIConnections()
QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &BFMDemodGUI::on_deltaFrequency_changed);
QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &BFMDemodGUI::on_rfBW_valueChanged);
QObject::connect(ui->afBW, &QSlider::valueChanged, this, &BFMDemodGUI::on_afBW_valueChanged);
QObject::connect(ui->deEmphasis, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &BFMDemodGUI::on_deEmphasis_currentIndexChanged);
QObject::connect(ui->volume, &QSlider::valueChanged, this, &BFMDemodGUI::on_volume_valueChanged);
QObject::connect(ui->squelch, &QSlider::valueChanged, this, &BFMDemodGUI::on_squelch_valueChanged);
QObject::connect(ui->audioMute, &QToolButton::toggled, this, &BFMDemodGUI::on_audioMute_toggled);
+1
View File
@@ -108,6 +108,7 @@ private slots:
void on_deltaFrequency_changed(qint64 value);
void on_rfBW_valueChanged(int value);
void on_afBW_valueChanged(int value);
void on_deEmphasis_currentIndexChanged(int index);
void on_volume_valueChanged(int value);
void on_squelch_valueChanged(int value);
void on_audioMute_toggled(bool mute);
+31
View File
@@ -418,6 +418,37 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="deEmphasisLabel">
<property name="text">
<string>De-emph</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="deEmphasis">
<property name="toolTip">
<string>De-emphasis time constant</string>
</property>
<item>
<property name="text">
<string>50us</string>
</property>
</item>
<item>
<property name="text">
<string>75us</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
@@ -51,6 +51,7 @@ void BFMDemodSettings::resetToDefaults()
m_lsbStereo = false;
m_showPilot = false;
m_rdsActive = false;
m_deEmphasis = DeEmphasis50us;
m_rgbColor = QColor(80, 120, 228).rgb();
m_title = "Broadcast FM Demod";
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
@@ -103,6 +104,7 @@ QByteArray BFMDemodSettings::serialize() const
s.writeBlob(23, m_geometryBytes);
s.writeBool(24, m_hidden);
s.writeBool(25, m_audioMute);
s.writeS32(26, m_deEmphasis);
return s.final();
}
@@ -181,6 +183,8 @@ bool BFMDemodSettings::deserialize(const QByteArray& data)
d.readBlob(23, &m_geometryBytes);
d.readBool(24, &m_hidden, false);
d.readBool(25, &m_audioMute, false);
d.readS32(26, &tmp, DeEmphasis50us);
m_deEmphasis = static_cast<DeEmphasis>(tmp);
return true;
}
@@ -27,6 +27,12 @@ class Serializable;
struct BFMDemodSettings
{
enum DeEmphasis
{
DeEmphasis50us,
DeEmphasis75us,
};
qint64 m_inputFrequencyOffset;
Real m_rfBandwidth;
Real m_afBandwidth;
@@ -37,6 +43,7 @@ struct BFMDemodSettings
bool m_lsbStereo;
bool m_showPilot;
bool m_rdsActive;
DeEmphasis m_deEmphasis;
quint32 m_rgbColor;
QString m_title;
QString m_audioDeviceName;
@@ -76,6 +83,19 @@ struct BFMDemodSettings
return (3*rfBW)/2;
}
}
double getDeEmphasisTimeConstant() const
{
switch (m_deEmphasis)
{
case DeEmphasis50us:
return 50e-6;
case DeEmphasis75us:
return 75e-6;
default:
return 50e-6;
}
}
};
+13 -7
View File
@@ -30,7 +30,6 @@
#include "rdsparser.h"
#include "bfmdemodsink.h"
const Real BFMDemodSink::default_deemphasis = 50.0; // 50 us
const int BFMDemodSink::default_excursion = 750000; // +/- 75 kHz
BFMDemodSink::BFMDemodSink() :
@@ -41,8 +40,8 @@ BFMDemodSink::BFMDemodSink() :
m_audioBufferFill(0),
m_audioFifo(48000),
m_pilotPLL(19000/384000, 50/384000, 0.01),
m_deemphasisFilterX(default_deemphasis * 48000 * 1.0e-6),
m_deemphasisFilterY(default_deemphasis * 48000 * 1.0e-6),
m_deemphasisFilterX(m_settings.getDeEmphasisTimeConstant() * 48000),
m_deemphasisFilterY(m_settings.getDeEmphasisTimeConstant() * 48000),
m_fmExcursion(default_excursion)
{
m_magsq = 0.0f;
@@ -67,8 +66,8 @@ BFMDemodSink::BFMDemodSink() :
m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, filtFftLen);
m_deemphasisFilterX.configure(default_deemphasis * m_audioSampleRate * 1.0e-6);
m_deemphasisFilterY.configure(default_deemphasis * m_audioSampleRate * 1.0e-6);
m_deemphasisFilterX.configure(m_settings.getDeEmphasisTimeConstant() * m_audioSampleRate);
m_deemphasisFilterY.configure(m_settings.getDeEmphasisTimeConstant() * m_audioSampleRate);
m_phaseDiscri.setFMScaling(384000/m_fmExcursion);
m_audioBuffer.resize(1<<14);
@@ -287,8 +286,8 @@ void BFMDemodSink::applyAudioSampleRate(int sampleRate)
m_interpolatorStereoDistanceRemain = (Real) m_channelSampleRate / sampleRate;
m_interpolatorStereoDistance = (Real) m_channelSampleRate / (Real) sampleRate;
m_deemphasisFilterX.configure(default_deemphasis * sampleRate * 1.0e-6);
m_deemphasisFilterY.configure(default_deemphasis * sampleRate * 1.0e-6);
m_deemphasisFilterX.configure(m_settings.getDeEmphasisTimeConstant() * sampleRate);
m_deemphasisFilterY.configure(m_settings.getDeEmphasisTimeConstant() * sampleRate);
m_audioSampleRate = sampleRate;
}
@@ -337,6 +336,7 @@ void BFMDemodSink::applySettings(const BFMDemodSettings& settings, bool force)
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_afBandwidth: " << settings.m_afBandwidth
<< " m_deEmphasis: " << settings.getDeEmphasisTimeConstant()
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_audioStereo: " << settings.m_audioStereo
@@ -354,6 +354,12 @@ void BFMDemodSink::applySettings(const BFMDemodSettings& settings, bool force)
applyAudioSampleRate(m_audioSampleRate); // re-apply audio sample rate to reconfigure interpolators
}
if ((settings.getDeEmphasisTimeConstant() != m_settings.getDeEmphasisTimeConstant()) || force)
{
m_deemphasisFilterX.configure(settings.getDeEmphasisTimeConstant() * m_audioSampleRate);
m_deemphasisFilterY.configure(settings.getDeEmphasisTimeConstant() * m_audioSampleRate);
}
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
{
m_interpolator.create(16, m_channelSampleRate, settings.m_afBandwidth);
@@ -155,7 +155,6 @@ private:
LowPassFilterRC m_deemphasisFilterX;
LowPassFilterRC m_deemphasisFilterY;
static const Real default_deemphasis;
Real m_fmExcursion;
static const int default_excursion;
+13 -6
View File
@@ -48,29 +48,36 @@ This is the power of the reconstructed stereo pilot signal.
Use this button to activate or de-activate RDS decoding
<h3>Audio mute</h3>
<h3>A.8: Audio mute</h3>
Use this button to mute or unmute audio
<h3>A.8: Level meter in dB</h3>
<h3>A.9: Level meter in dB</h3>
- top bar (green): average value
- bottom bar (blue green): instantaneous peak value
- tip vertical bar (bright green): peak hold value
<h3>A.9: RF Bandwidth</h3>
<h3>A.10: RF Bandwidth</h3>
This is the bandwidth in kHz of the channel signal before demodulation. It can be set in steps: 80, 100, 120, 140, 160, 180, 200, 220 and 250 kHz. Inspect the baseband spectrum (B) to adjust for best quality.
<h3>A.10: AF bandwidth</h3>
<h3>A.11: AF bandwidth</h3>
This is the AF bandwidth in kHz. It can be varied continuously between 1 and 20 kHz in steps of 1 kHz.
<h3>A.11: AF volume</h3>
<h3>A.12: De-emphasis</h3>
Select the de-emphasis time constant:
- **50us**: for Europe, Australia...
- **75us**: for North America, Japan...
<h3>A.13: AF volume</h3>
This is the relative AF volume from 0 to 10.
<h3>A.12: Squelch</h3>
<h3>A.14: Squelch</h3>
Adjust squelch in dB.
@@ -2948,6 +2948,10 @@ margin-bottom: 20px;
"type" : "number",
"format" : "float"
},
"deEmphasis" : {
"type" : "integer",
"description" : "De-emphasis time constant (us)\n * 0 - 50us (Europe, Australia)\n * 1 - 75us (US, Japan)\n"
},
"volume" : {
"type" : "number",
"format" : "float"
@@ -59650,7 +59654,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2026-01-03T23:29:39.831+01:00
Generated 2026-01-04T00:29:36.688+01:00
</div>
</div>
</div>
@@ -10,6 +10,12 @@ BFMDemodSettings:
afBandwidth:
type: number
format: float
deEmphasis:
type: integer
description: >
De-emphasis time constant (us)
* 0 - 50us (Europe, Australia)
* 1 - 75us (US, Japan)
volume:
type: number
format: float
@@ -10,6 +10,12 @@ BFMDemodSettings:
afBandwidth:
type: number
format: float
deEmphasis:
type: integer
description: >
De-emphasis time constant (us)
* 0 - 50us (Europe, Australia)
* 1 - 75us (US, Japan)
volume:
type: number
format: float
+5 -1
View File
@@ -2948,6 +2948,10 @@ margin-bottom: 20px;
"type" : "number",
"format" : "float"
},
"deEmphasis" : {
"type" : "integer",
"description" : "De-emphasis time constant (us)\n * 0 - 50us (Europe, Australia)\n * 1 - 75us (US, Japan)\n"
},
"volume" : {
"type" : "number",
"format" : "float"
@@ -59650,7 +59654,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2026-01-03T23:29:39.831+01:00
Generated 2026-01-04T00:29:36.688+01:00
</div>
</div>
</div>
@@ -34,6 +34,8 @@ SWGBFMDemodSettings::SWGBFMDemodSettings() {
m_rf_bandwidth_isSet = false;
af_bandwidth = 0.0f;
m_af_bandwidth_isSet = false;
de_emphasis = 0;
m_de_emphasis_isSet = false;
volume = 0.0f;
m_volume_isSet = false;
squelch = 0.0f;
@@ -86,6 +88,8 @@ SWGBFMDemodSettings::init() {
m_rf_bandwidth_isSet = false;
af_bandwidth = 0.0f;
m_af_bandwidth_isSet = false;
de_emphasis = 0;
m_de_emphasis_isSet = false;
volume = 0.0f;
m_volume_isSet = false;
squelch = 0.0f;
@@ -139,6 +143,7 @@ SWGBFMDemodSettings::cleanup() {
if(title != nullptr) {
delete title;
}
@@ -181,6 +186,8 @@ SWGBFMDemodSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&af_bandwidth, pJson["afBandwidth"], "float", "");
::SWGSDRangel::setValue(&de_emphasis, pJson["deEmphasis"], "qint32", "");
::SWGSDRangel::setValue(&volume, pJson["volume"], "float", "");
::SWGSDRangel::setValue(&squelch, pJson["squelch"], "float", "");
@@ -244,6 +251,9 @@ SWGBFMDemodSettings::asJsonObject() {
if(m_af_bandwidth_isSet){
obj->insert("afBandwidth", QJsonValue(af_bandwidth));
}
if(m_de_emphasis_isSet){
obj->insert("deEmphasis", QJsonValue(de_emphasis));
}
if(m_volume_isSet){
obj->insert("volume", QJsonValue(volume));
}
@@ -335,6 +345,16 @@ SWGBFMDemodSettings::setAfBandwidth(float af_bandwidth) {
this->m_af_bandwidth_isSet = true;
}
qint32
SWGBFMDemodSettings::getDeEmphasis() {
return de_emphasis;
}
void
SWGBFMDemodSettings::setDeEmphasis(qint32 de_emphasis) {
this->de_emphasis = de_emphasis;
this->m_de_emphasis_isSet = true;
}
float
SWGBFMDemodSettings::getVolume() {
return volume;
@@ -539,6 +559,9 @@ SWGBFMDemodSettings::isSet(){
if(m_af_bandwidth_isSet){
isObjectUpdated = true; break;
}
if(m_de_emphasis_isSet){
isObjectUpdated = true; break;
}
if(m_volume_isSet){
isObjectUpdated = true; break;
}
@@ -54,6 +54,9 @@ public:
float getAfBandwidth();
void setAfBandwidth(float af_bandwidth);
qint32 getDeEmphasis();
void setDeEmphasis(qint32 de_emphasis);
float getVolume();
void setVolume(float volume);
@@ -124,6 +127,9 @@ private:
float af_bandwidth;
bool m_af_bandwidth_isSet;
qint32 de_emphasis;
bool m_de_emphasis_isSet;
float volume;
bool m_volume_isSet;