SSB Mod: added audio compressor preamp gain and threshold controls

This commit is contained in:
f4exb 2020-11-25 14:19:21 +01:00
parent d1e0f8d865
commit 6de27fc3d0
18 changed files with 284 additions and 14 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

View File

@ -113,26 +113,44 @@ Use this button to toggle audio compression on or off.
<h3>13: Input source control</h3> <h3>13: Input source control</h3>
![Modulator input source control GUI](../../../doc/img/ModControls.png) ![Modulator input source control GUI](../../../doc/img/SSBModulator_plugin_cmp.png)
<h4>13.1: Tone input select</h4> <h4>13.1: Audio compressor</h4>
Activate/deactivate it for file and audio input only.
<h4>13.2: Audio compressor input gain</h4>
Gain in dB before compression
<h4>13.3: Audio compressor threshold</h4>
Threshold in dB above which compression applies a.k.a. "knee" point. The lower the value the harder is the compression and consequently higher the distorsion.
<h4>13.4: Tone input select</h4>
Switches to the tone input. You must switch it off to make other inputs available. Switches to the tone input. You must switch it off to make other inputs available.
<h4>13.2: Morse keyer input select</h4> <h4>13.5: Morse keyer input select</h4>
Switches to the Morse keyer input. You must switch it off to make other inputs available. Switches to the Morse keyer input. You must switch it off to make other inputs available.
<h4>13.3: Tone frequency (kHz)</h4> <h4>13.6: Tone frequency (kHz)</h4>
Adjusts the tone frequency from 0.1 to 2.5 kHz in 0.01 kHz steps Adjusts the tone frequency from 0.1 to 2.5 kHz in 0.01 kHz steps
<h4>13.4: Audio input select and select audio input device</h4> <h4>13.7: Audio input select and select audio input device</h4>
Left click to switch to the audio input. You must switch it off to make other inputs available. Left click to switch to the audio input. You must switch it off to make other inputs available.
Right click to select audio input device. See [audio management documentation](../../../sdrgui/audio.md) for details. Right click to select audio input device. See [audio management documentation](../../../sdrgui/audio.md) for details.
<h4>13.8: Audio feedback</h4>
Left click to activate audio feedback.
Right click to select audio output device for audio feedback. See [audio management documentation](../../../sdrgui/audio.md) for details.
<h3>14: CW (Morse) text</h3> <h3>14: CW (Morse) text</h3>
Enter the text to be keyed when Morse input is active and in text mode Enter the text to be keyed when Morse input is active and in text mode

View File

@ -262,6 +262,12 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force)
if ((settings.m_agc != m_settings.m_agc) || force) { if ((settings.m_agc != m_settings.m_agc) || force) {
reverseAPIKeys.append("agc"); reverseAPIKeys.append("agc");
} }
if ((settings.m_cmpPreGainDB != m_settings.m_cmpPreGainDB) || force) {
reverseAPIKeys.append("cmpPreGainDB");
}
if ((settings.m_cmpThresholdDB != m_settings.m_cmpThresholdDB) || force) {
reverseAPIKeys.append("cmpThresholdDB");
}
if ((settings.m_rgbColor != m_settings.m_rgbColor) || force) { if ((settings.m_rgbColor != m_settings.m_rgbColor) || force) {
reverseAPIKeys.append("rgbColor"); reverseAPIKeys.append("rgbColor");
} }
@ -449,6 +455,12 @@ void SSBMod::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("agc")) { if (channelSettingsKeys.contains("agc")) {
settings.m_agc = response.getSsbModSettings()->getAgc() != 0; settings.m_agc = response.getSsbModSettings()->getAgc() != 0;
} }
if (channelSettingsKeys.contains("cmpPreGainDB")) {
settings.m_cmpPreGainDB = response.getSsbModSettings()->getCmpPreGainDb();
}
if (channelSettingsKeys.contains("cmpThresholdDB")) {
settings.m_cmpThresholdDB = response.getSsbModSettings()->getCmpThresholdDb();
}
if (channelSettingsKeys.contains("rgbColor")) { if (channelSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getSsbModSettings()->getRgbColor(); settings.m_rgbColor = response.getSsbModSettings()->getRgbColor();
} }
@ -507,6 +519,8 @@ void SSBMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respon
response.getSsbModSettings()->setAudioMute(settings.m_audioMute ? 1 : 0); response.getSsbModSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
response.getSsbModSettings()->setPlayLoop(settings.m_playLoop ? 1 : 0); response.getSsbModSettings()->setPlayLoop(settings.m_playLoop ? 1 : 0);
response.getSsbModSettings()->setAgc(settings.m_agc ? 1 : 0); response.getSsbModSettings()->setAgc(settings.m_agc ? 1 : 0);
response.getSsbModSettings()->setCmpPreGainDb(settings.m_cmpPreGainDB);
response.getSsbModSettings()->setCmpThresholdDb(settings.m_cmpThresholdDB);
response.getSsbModSettings()->setRgbColor(settings.m_rgbColor); response.getSsbModSettings()->setRgbColor(settings.m_rgbColor);
if (response.getSsbModSettings()->getTitle()) { if (response.getSsbModSettings()->getTitle()) {
@ -687,6 +701,12 @@ void SSBMod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("agc") || force) { if (channelSettingsKeys.contains("agc") || force) {
swgSSBModSettings->setAgc(settings.m_agc ? 1 : 0); swgSSBModSettings->setAgc(settings.m_agc ? 1 : 0);
} }
if (channelSettingsKeys.contains("cmpPreGainDB") || force) {
swgSSBModSettings->setCmpPreGainDb(settings.m_cmpPreGainDB);
}
if (channelSettingsKeys.contains("cmpThresholdDB") || force) {
swgSSBModSettings->setCmpThresholdDb(settings.m_cmpThresholdDB);
}
if (channelSettingsKeys.contains("rgbColor") || force) { if (channelSettingsKeys.contains("rgbColor") || force) {
swgSSBModSettings->setRgbColor(settings.m_rgbColor); swgSSBModSettings->setRgbColor(settings.m_rgbColor);
} }

View File

@ -292,6 +292,20 @@ void SSBModGUI::on_agc_toggled(bool checked)
applySettings(); applySettings();
} }
void SSBModGUI::on_cmpPreGain_valueChanged(int value)
{
m_settings.m_cmpPreGainDB = value;
ui->cmpPreGainText->setText(QString("%1").arg(value));
applySettings();
}
void SSBModGUI::on_cmpThreshold_valueChanged(int value)
{
m_settings.m_cmpThresholdDB = value;
ui->cmpThresholdText->setText(QString("%1").arg(value));
applySettings();
}
void SSBModGUI::on_navTimeSlider_valueChanged(int value) void SSBModGUI::on_navTimeSlider_valueChanged(int value)
{ {
if (m_enableNavTime && ((value >= 0) && (value <= 100))) if (m_enableNavTime && ((value >= 0) && (value <= 100)))
@ -633,6 +647,8 @@ void SSBModGUI::displaySettings()
blockApplySettings(true); blockApplySettings(true);
ui->agc->setChecked(m_settings.m_agc); ui->agc->setChecked(m_settings.m_agc);
ui->cmpPreGainText->setText(QString("%1").arg(m_settings.m_cmpPreGainDB));
ui->cmpThresholdText->setText(QString("%1").arg(m_settings.m_cmpThresholdDB));
ui->audioBinaural->setChecked(m_settings.m_audioBinaural); ui->audioBinaural->setChecked(m_settings.m_audioBinaural);
ui->audioFlipChannels->setChecked(m_settings.m_audioFlipChannels); ui->audioFlipChannels->setChecked(m_settings.m_audioFlipChannels);
ui->audioMute->setChecked(m_settings.m_audioMute); ui->audioMute->setChecked(m_settings.m_audioMute);

View File

@ -110,6 +110,8 @@ private slots:
void on_toneFrequency_valueChanged(int value); void on_toneFrequency_valueChanged(int value);
void on_mic_toggled(bool checked); void on_mic_toggled(bool checked);
void on_agc_toggled(bool checked); void on_agc_toggled(bool checked);
void on_cmpPreGain_valueChanged(int value);
void on_cmpThreshold_valueChanged(int value);
void on_play_toggled(bool checked); void on_play_toggled(bool checked);
void on_playLoop_toggled(bool checked); void on_playLoop_toggled(bool checked);
void on_morseKeyer_toggled(bool checked); void on_morseKeyer_toggled(bool checked);

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>390</width> <width>430</width>
<height>643</height> <height>643</height>
</rect> </rect>
</property> </property>
@ -18,7 +18,7 @@
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>390</width> <width>430</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -36,7 +36,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>385</width> <width>430</width>
<height>331</height> <height>331</height>
</rect> </rect>
</property> </property>
@ -739,6 +739,121 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="cmpPreGainLabel">
<property name="text">
<string>G</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="cmpPreGain">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Compressor input gain (dB)</string>
</property>
<property name="minimum">
<number>-20</number>
</property>
<property name="maximum">
<number>20</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="cmpPreGainText">
<property name="minimumSize">
<size>
<width>25</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Audio input gain value</string>
</property>
<property name="statusTip">
<string/>
</property>
<property name="text">
<string>-10</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="cmpThresholdLabel">
<property name="text">
<string>T</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="cmpThreshold">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Compressor threshold (dB)</string>
</property>
<property name="minimum">
<number>-80</number>
</property>
<property name="maximum">
<number>-20</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>-60</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="cmpThresholdText">
<property name="minimumSize">
<size>
<width>25</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Audio input gain value</string>
</property>
<property name="statusTip">
<string/>
</property>
<property name="text">
<string>-60</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item> <item>
<widget class="ButtonSwitch" name="tone"> <widget class="ButtonSwitch" name="tone">
<property name="toolTip"> <property name="toolTip">
@ -1092,7 +1207,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>340</y> <y>340</y>
<width>351</width> <width>430</width>
<height>284</height> <height>284</height>
</rect> </rect>
</property> </property>

View File

@ -59,6 +59,8 @@ void SSBModSettings::resetToDefaults()
m_audioMute = false; m_audioMute = false;
m_playLoop = false; m_playLoop = false;
m_agc = false; m_agc = false;
m_cmpPreGainDB = -10;
m_cmpThresholdDB = -60;
m_rgbColor = QColor(0, 255, 0).rgb(); m_rgbColor = QColor(0, 255, 0).rgb();
m_title = "SSB Modulator"; m_title = "SSB Modulator";
m_modAFInput = SSBModInputAF::SSBModInputNone; m_modAFInput = SSBModInputAF::SSBModInputNone;
@ -100,6 +102,8 @@ QByteArray SSBModSettings::serialize() const
s.writeBool(10, m_audioFlipChannels); s.writeBool(10, m_audioFlipChannels);
s.writeBool(11, m_dsb); s.writeBool(11, m_dsb);
s.writeBool(12, m_agc); s.writeBool(12, m_agc);
s.writeS32(13, m_cmpPreGainDB);
s.writeS32(14, m_cmpThresholdDB);
if (m_channelMarker) { if (m_channelMarker) {
s.writeBlob(18, m_channelMarker->serialize()); s.writeBlob(18, m_channelMarker->serialize());
@ -169,7 +173,8 @@ bool SSBModSettings::deserialize(const QByteArray& data)
d.readBool(10, &m_audioFlipChannels, false); d.readBool(10, &m_audioFlipChannels, false);
d.readBool(11, &m_dsb, false); d.readBool(11, &m_dsb, false);
d.readBool(12, &m_agc, false); d.readBool(12, &m_agc, false);
d.readS32(13, &tmp, 7); d.readS32(13, &m_cmpPreGainDB, -10);
d.readS32(14, &m_cmpThresholdDB, -60);
if (m_channelMarker) { if (m_channelMarker) {
d.readBlob(18, &bytetmp); d.readBlob(18, &bytetmp);

View File

@ -53,6 +53,8 @@ struct SSBModSettings
bool m_audioMute; bool m_audioMute;
bool m_playLoop; bool m_playLoop;
bool m_agc; bool m_agc;
int m_cmpPreGainDB;
int m_cmpThresholdDB;
quint32 m_rgbColor; quint32 m_rgbColor;
QString m_title; QString m_title;

View File

@ -64,8 +64,8 @@ SSBModSource::SSBModSource() :
m_audioCompressor.initSimple( m_audioCompressor.initSimple(
m_audioSampleRate, m_audioSampleRate,
-10, // pregain (dB) -3 m_settings.m_cmpPreGainDB, // pregain (dB)
-60, // threshold (dB) -50 m_settings.m_cmpThresholdDB, // threshold (dB)
20, // knee (dB) 20, // knee (dB)
12, // ratio (dB) 12, // ratio (dB)
0.003, // attack (s) 0.003, // attack (s)
@ -648,6 +648,20 @@ void SSBModSource::applySettings(const SSBModSettings& settings, bool force)
} }
} }
if ((settings.m_cmpThresholdDB != m_settings.m_cmpThresholdDB) ||
(settings.m_cmpPreGainDB != m_settings.m_cmpPreGainDB) || force)
{
m_audioCompressor.initSimple(
m_audioSampleRate,
settings.m_cmpPreGainDB, // pregain (dB)
settings.m_cmpThresholdDB, // threshold (dB)
20, // knee (dB)
12, // ratio (dB)
0.003, // attack (s)
0.25 // release (s)
);
}
m_settings = settings; m_settings = settings;
m_settings.m_bandwidth = band; m_settings.m_bandwidth = band;
m_settings.m_lowCutoff = lowCutoff; m_settings.m_lowCutoff = lowCutoff;

View File

@ -7968,6 +7968,12 @@ margin-bottom: 20px;
"agc" : { "agc" : {
"type" : "integer" "type" : "integer"
}, },
"cmpPreGainDB" : {
"type" : "integer"
},
"cmpThresholdDB" : {
"type" : "integer"
},
"rgbColor" : { "rgbColor" : {
"type" : "integer" "type" : "integer"
}, },
@ -44706,7 +44712,7 @@ except ApiException as e:
</div> </div>
<div id="generator"> <div id="generator">
<div class="content"> <div class="content">
Generated 2020-11-24T20:20:00.458+01:00 Generated 2020-11-25T13:34:12.214+01:00
</div> </div>
</div> </div>
</div> </div>

View File

@ -32,6 +32,10 @@ SSBModSettings:
type: integer type: integer
agc: agc:
type: integer type: integer
cmpPreGainDB:
type: integer
cmpThresholdDB:
type: integer
rgbColor: rgbColor:
type: integer type: integer
title: title:

View File

@ -32,6 +32,10 @@ SSBModSettings:
type: integer type: integer
agc: agc:
type: integer type: integer
cmpPreGainDB:
type: integer
cmpThresholdDB:
type: integer
rgbColor: rgbColor:
type: integer type: integer
title: title:

View File

@ -7968,6 +7968,12 @@ margin-bottom: 20px;
"agc" : { "agc" : {
"type" : "integer" "type" : "integer"
}, },
"cmpPreGainDB" : {
"type" : "integer"
},
"cmpThresholdDB" : {
"type" : "integer"
},
"rgbColor" : { "rgbColor" : {
"type" : "integer" "type" : "integer"
}, },
@ -44706,7 +44712,7 @@ except ApiException as e:
</div> </div>
<div id="generator"> <div id="generator">
<div class="content"> <div class="content">
Generated 2020-11-24T20:20:00.458+01:00 Generated 2020-11-25T13:34:12.214+01:00
</div> </div>
</div> </div>
</div> </div>

View File

@ -54,6 +54,10 @@ SWGSSBModSettings::SWGSSBModSettings() {
m_play_loop_isSet = false; m_play_loop_isSet = false;
agc = 0; agc = 0;
m_agc_isSet = false; m_agc_isSet = false;
cmp_pre_gain_db = 0;
m_cmp_pre_gain_db_isSet = false;
cmp_threshold_db = 0;
m_cmp_threshold_db_isSet = false;
rgb_color = 0; rgb_color = 0;
m_rgb_color_isSet = false; m_rgb_color_isSet = false;
title = nullptr; title = nullptr;
@ -110,6 +114,10 @@ SWGSSBModSettings::init() {
m_play_loop_isSet = false; m_play_loop_isSet = false;
agc = 0; agc = 0;
m_agc_isSet = false; m_agc_isSet = false;
cmp_pre_gain_db = 0;
m_cmp_pre_gain_db_isSet = false;
cmp_threshold_db = 0;
m_cmp_threshold_db_isSet = false;
rgb_color = 0; rgb_color = 0;
m_rgb_color_isSet = false; m_rgb_color_isSet = false;
title = new QString(""); title = new QString("");
@ -150,6 +158,8 @@ SWGSSBModSettings::cleanup() {
if(title != nullptr) { if(title != nullptr) {
delete title; delete title;
} }
@ -207,6 +217,10 @@ SWGSSBModSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&agc, pJson["agc"], "qint32", ""); ::SWGSDRangel::setValue(&agc, pJson["agc"], "qint32", "");
::SWGSDRangel::setValue(&cmp_pre_gain_db, pJson["cmpPreGainDB"], "qint32", "");
::SWGSDRangel::setValue(&cmp_threshold_db, pJson["cmpThresholdDB"], "qint32", "");
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
@ -284,6 +298,12 @@ SWGSSBModSettings::asJsonObject() {
if(m_agc_isSet){ if(m_agc_isSet){
obj->insert("agc", QJsonValue(agc)); obj->insert("agc", QJsonValue(agc));
} }
if(m_cmp_pre_gain_db_isSet){
obj->insert("cmpPreGainDB", QJsonValue(cmp_pre_gain_db));
}
if(m_cmp_threshold_db_isSet){
obj->insert("cmpThresholdDB", QJsonValue(cmp_threshold_db));
}
if(m_rgb_color_isSet){ if(m_rgb_color_isSet){
obj->insert("rgbColor", QJsonValue(rgb_color)); obj->insert("rgbColor", QJsonValue(rgb_color));
} }
@ -451,6 +471,26 @@ SWGSSBModSettings::setAgc(qint32 agc) {
this->m_agc_isSet = true; this->m_agc_isSet = true;
} }
qint32
SWGSSBModSettings::getCmpPreGainDb() {
return cmp_pre_gain_db;
}
void
SWGSSBModSettings::setCmpPreGainDb(qint32 cmp_pre_gain_db) {
this->cmp_pre_gain_db = cmp_pre_gain_db;
this->m_cmp_pre_gain_db_isSet = true;
}
qint32
SWGSSBModSettings::getCmpThresholdDb() {
return cmp_threshold_db;
}
void
SWGSSBModSettings::setCmpThresholdDb(qint32 cmp_threshold_db) {
this->cmp_threshold_db = cmp_threshold_db;
this->m_cmp_threshold_db_isSet = true;
}
qint32 qint32
SWGSSBModSettings::getRgbColor() { SWGSSBModSettings::getRgbColor() {
return rgb_color; return rgb_color;
@ -605,6 +645,12 @@ SWGSSBModSettings::isSet(){
if(m_agc_isSet){ if(m_agc_isSet){
isObjectUpdated = true; break; isObjectUpdated = true; break;
} }
if(m_cmp_pre_gain_db_isSet){
isObjectUpdated = true; break;
}
if(m_cmp_threshold_db_isSet){
isObjectUpdated = true; break;
}
if(m_rgb_color_isSet){ if(m_rgb_color_isSet){
isObjectUpdated = true; break; isObjectUpdated = true; break;
} }

View File

@ -82,6 +82,12 @@ public:
qint32 getAgc(); qint32 getAgc();
void setAgc(qint32 agc); void setAgc(qint32 agc);
qint32 getCmpPreGainDb();
void setCmpPreGainDb(qint32 cmp_pre_gain_db);
qint32 getCmpThresholdDb();
void setCmpThresholdDb(qint32 cmp_threshold_db);
qint32 getRgbColor(); qint32 getRgbColor();
void setRgbColor(qint32 rgb_color); void setRgbColor(qint32 rgb_color);
@ -158,6 +164,12 @@ private:
qint32 agc; qint32 agc;
bool m_agc_isSet; bool m_agc_isSet;
qint32 cmp_pre_gain_db;
bool m_cmp_pre_gain_db_isSet;
qint32 cmp_threshold_db;
bool m_cmp_threshold_db_isSet;
qint32 rgb_color; qint32 rgb_color;
bool m_rgb_color_isSet; bool m_rgb_color_isSet;