mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-26 01:39:05 -05:00
SSM modulator: added audio compressor
This commit is contained in:
parent
0f9c8d17a5
commit
d8f7dcebdc
@ -325,6 +325,7 @@ bool SSBDemod::handleMessage(const Message& cmd)
|
||||
if (m_agcNbSamples != agcNbSamples)
|
||||
{
|
||||
m_agc.resize(agcNbSamples, agcTarget);
|
||||
m_agc.setStepDownDelay(agcNbSamples);
|
||||
m_agcNbSamples = agcNbSamples;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <dsp/upchannelizer.h>
|
||||
#include "dsp/dspengine.h"
|
||||
#include "dsp/pidcontroller.h"
|
||||
#include "util/db.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(SSBMod::MsgConfigureSSBMod, Message)
|
||||
MESSAGE_CLASS_DEFINITION(SSBMod::MsgConfigureFileSourceName, Message)
|
||||
@ -45,7 +46,6 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) :
|
||||
m_DSBFilterBufferIndex(0),
|
||||
m_sampleSink(sampleSink),
|
||||
m_movingAverage(40, 0),
|
||||
m_volumeAGC(40, 0),
|
||||
m_audioFifo(4, 48000),
|
||||
m_settingsMutex(QMutex::Recursive),
|
||||
m_fileSize(0),
|
||||
@ -54,7 +54,8 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) :
|
||||
m_afInput(SSBModInputNone),
|
||||
m_levelCalcCount(0),
|
||||
m_peakLevel(0.0f),
|
||||
m_levelSum(0.0f)
|
||||
m_levelSum(0.0f),
|
||||
m_inAGC(9600, 0.2, 1e-4)
|
||||
{
|
||||
setObjectName("SSBMod");
|
||||
|
||||
@ -84,7 +85,6 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) :
|
||||
m_sumCount = 0;
|
||||
|
||||
m_movingAverage.resize(16, 0);
|
||||
m_volumeAGC.resize(4096, 0.003, 0);
|
||||
m_magsq = 0.0;
|
||||
|
||||
m_toneNco.setFreq(1000.0, m_config.m_audioSampleRate);
|
||||
@ -96,6 +96,9 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) :
|
||||
m_cwKeyer.setMode(CWKeyer::CWNone);
|
||||
|
||||
m_cwSmoother.setNbFadeSamples(192); // 4 ms at 48 kHz
|
||||
m_inAGC.setGate(m_config.m_agcThresholdGate);
|
||||
m_inAGC.setStepDownDelay(m_config.m_agcThresholdDelay);
|
||||
m_inAGC.setClamping(true);
|
||||
apply();
|
||||
}
|
||||
|
||||
@ -130,7 +133,12 @@ void SSBMod::configure(MessageQueue* messageQueue,
|
||||
bool audioFlipChannels,
|
||||
bool dsb,
|
||||
bool audioMute,
|
||||
bool playLoop)
|
||||
bool playLoop,
|
||||
bool agc,
|
||||
int agcTime,
|
||||
int agcThreshold,
|
||||
int agcThresholdGate,
|
||||
int agcThresholdDelay)
|
||||
{
|
||||
Message* cmd = MsgConfigureSSBMod::create(bandwidth,
|
||||
lowCutoff,
|
||||
@ -141,7 +149,12 @@ void SSBMod::configure(MessageQueue* messageQueue,
|
||||
audioFlipChannels,
|
||||
dsb,
|
||||
audioMute,
|
||||
playLoop);
|
||||
playLoop,
|
||||
agc,
|
||||
agcTime,
|
||||
agcThreshold,
|
||||
agcThresholdGate,
|
||||
agcThresholdDelay);
|
||||
messageQueue->push(cmd);
|
||||
}
|
||||
|
||||
@ -282,8 +295,19 @@ void SSBMod::pullAF(Complex& sample)
|
||||
{
|
||||
Real real;
|
||||
m_ifstream.read(reinterpret_cast<char*>(&real), sizeof(Real));
|
||||
ci.real(real * m_running.m_volumeFactor);
|
||||
ci.imag(0.0f);
|
||||
|
||||
if (m_running.m_agc)
|
||||
{
|
||||
ci.real(real);
|
||||
ci.imag(0.0f);
|
||||
m_inAGC.feed(ci);
|
||||
ci *= m_running.m_volumeFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
ci.real(real * m_running.m_volumeFactor);
|
||||
ci.imag(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -309,8 +333,18 @@ void SSBMod::pullAF(Complex& sample)
|
||||
}
|
||||
else
|
||||
{
|
||||
ci.real(((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f) * m_running.m_volumeFactor);
|
||||
ci.imag(0.0f);
|
||||
if (m_running.m_agc)
|
||||
{
|
||||
ci.real(((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f));
|
||||
ci.imag(0.0f);
|
||||
m_inAGC.feed(ci);
|
||||
ci *= m_running.m_volumeFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
ci.real(((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f) * m_running.m_volumeFactor);
|
||||
ci.imag(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@ -580,6 +614,13 @@ bool SSBMod::handleMessage(const Message& cmd)
|
||||
m_config.m_dsb = cfg.getDSB();
|
||||
m_config.m_audioMute = cfg.getAudioMute();
|
||||
m_config.m_playLoop = cfg.getPlayLoop();
|
||||
m_config.m_agc = cfg.getAGC();
|
||||
|
||||
m_config.m_agcTime = 48 * cfg.getAGCTime(); // ms
|
||||
m_config.m_agcThresholdEnable = cfg.getAGCThreshold() != -99;
|
||||
m_config.m_agcThreshold = CalcDb::powerFromdB(cfg.getAGCThreshold()); // power dB
|
||||
m_config.m_agcThresholdGate = 48 * cfg.getAGCThresholdGate(); // ms
|
||||
m_config.m_agcThresholdDelay = 48 * cfg.getAGCThresholdDelay(); // ms
|
||||
|
||||
apply();
|
||||
|
||||
@ -595,7 +636,13 @@ bool SSBMod::handleMessage(const Message& cmd)
|
||||
<< " m_audioFlipChannels: " << m_config.m_audioFlipChannels
|
||||
<< " m_dsb: " << m_config.m_dsb
|
||||
<< " m_audioMute: " << m_config.m_audioMute
|
||||
<< " m_playLoop: " << m_config.m_playLoop;
|
||||
<< " m_playLoop: " << m_config.m_playLoop
|
||||
<< " m_agc: " << m_config.m_agc
|
||||
<< " m_agcTime: " << m_config.m_agcTime
|
||||
<< " m_agcThresholdEnable: " << m_config.m_agcThresholdEnable
|
||||
<< " m_agcThreshold: " << m_config.m_agcThreshold
|
||||
<< " m_agcThresholdGate: " << m_config.m_agcThresholdGate
|
||||
<< " m_agcThresholdDelay: " << m_config.m_agcThresholdDelay;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -705,6 +752,31 @@ void SSBMod::apply()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_config.m_agcTime != m_running.m_agcTime)
|
||||
{
|
||||
m_inAGC.resize(m_config.m_agcTime, 0.2);
|
||||
}
|
||||
|
||||
if (m_config.m_agcThresholdEnable != m_running.m_agcThresholdEnable)
|
||||
{
|
||||
m_inAGC.setThresholdEnable(m_config.m_agcThresholdEnable);
|
||||
}
|
||||
|
||||
if (m_config.m_agcThreshold != m_running.m_agcThreshold)
|
||||
{
|
||||
m_inAGC.setThreshold(m_config.m_agcThreshold);
|
||||
}
|
||||
|
||||
if (m_config.m_agcThresholdGate != m_running.m_agcThresholdGate)
|
||||
{
|
||||
m_inAGC.setGate(m_config.m_agcThresholdGate);
|
||||
}
|
||||
|
||||
if (m_config.m_agcThresholdDelay != m_running.m_agcThresholdDelay)
|
||||
{
|
||||
m_inAGC.setStepDownDelay(m_config.m_agcThresholdDelay);
|
||||
}
|
||||
|
||||
m_running.m_outputSampleRate = m_config.m_outputSampleRate;
|
||||
m_running.m_inputFrequencyOffset = m_config.m_inputFrequencyOffset;
|
||||
m_running.m_bandwidth = m_config.m_bandwidth;
|
||||
@ -719,6 +791,12 @@ void SSBMod::apply()
|
||||
m_running.m_dsb = m_config.m_dsb;
|
||||
m_running.m_audioMute = m_config.m_audioMute;
|
||||
m_running.m_playLoop = m_config.m_playLoop;
|
||||
m_running.m_agc = m_config.m_agc;
|
||||
m_running.m_agcTime = m_config.m_agcTime;
|
||||
m_running.m_agcThresholdEnable = m_config.m_agcThresholdEnable;
|
||||
m_running.m_agcThreshold = m_config.m_agcThreshold;
|
||||
m_running.m_agcThresholdGate = m_config.m_agcThresholdGate;
|
||||
m_running.m_agcThresholdDelay = m_config.m_agcThresholdDelay;
|
||||
}
|
||||
|
||||
void SSBMod::openFileStream()
|
||||
|
@ -187,7 +187,12 @@ public:
|
||||
bool audioFlipChannels,
|
||||
bool dsb,
|
||||
bool audioMute,
|
||||
bool playLoop);
|
||||
bool playLoop,
|
||||
bool agc,
|
||||
int agcTime,
|
||||
int agcThreshold,
|
||||
int agcThresholdGate,
|
||||
int agcThresholdDelay);
|
||||
|
||||
virtual void pull(Sample& sample);
|
||||
virtual void pullAudio(int nbSamples);
|
||||
@ -225,6 +230,11 @@ private:
|
||||
bool getDSB() const { return m_dsb; }
|
||||
bool getAudioMute() const { return m_audioMute; }
|
||||
bool getPlayLoop() const { return m_playLoop; }
|
||||
bool getAGC() const { return m_agc; }
|
||||
int getAGCTime() const { return m_agcTime; }
|
||||
int getAGCThreshold() const { return m_agcThreshold; }
|
||||
int getAGCThresholdGate() const { return m_agcThresholdGate; }
|
||||
int getAGCThresholdDelay() const { return m_agcThresholdDelay; }
|
||||
|
||||
static MsgConfigureSSBMod* create(Real bandwidth,
|
||||
Real lowCutoff,
|
||||
@ -235,7 +245,12 @@ private:
|
||||
bool audioFlipChannels,
|
||||
bool dsb,
|
||||
bool audioMute,
|
||||
bool playLoop)
|
||||
bool playLoop,
|
||||
bool agc,
|
||||
int agcTime,
|
||||
int agcThreshold,
|
||||
int agcThresholdGate,
|
||||
int agcThresholdDelay)
|
||||
{
|
||||
return new MsgConfigureSSBMod(bandwidth,
|
||||
lowCutoff,
|
||||
@ -246,7 +261,12 @@ private:
|
||||
audioFlipChannels,
|
||||
dsb,
|
||||
audioMute,
|
||||
playLoop);
|
||||
playLoop,
|
||||
agc,
|
||||
agcTime,
|
||||
agcThreshold,
|
||||
agcThresholdGate,
|
||||
agcThresholdDelay);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -260,6 +280,11 @@ private:
|
||||
bool m_dsb;
|
||||
bool m_audioMute;
|
||||
bool m_playLoop;
|
||||
bool m_agc;
|
||||
int m_agcTime;
|
||||
int m_agcThreshold;
|
||||
int m_agcThresholdGate;
|
||||
int m_agcThresholdDelay;
|
||||
|
||||
MsgConfigureSSBMod(Real bandwidth,
|
||||
Real lowCutoff,
|
||||
@ -270,7 +295,12 @@ private:
|
||||
bool audioFlipChannels,
|
||||
bool dsb,
|
||||
bool audioMute,
|
||||
bool playLoop) :
|
||||
bool playLoop,
|
||||
bool agc,
|
||||
int agcTime,
|
||||
int agcThreshold,
|
||||
int agcThresholdGate,
|
||||
int agcThresholdDelay) :
|
||||
Message(),
|
||||
m_bandwidth(bandwidth),
|
||||
m_lowCutoff(lowCutoff),
|
||||
@ -281,7 +311,12 @@ private:
|
||||
m_audioFlipChannels(audioFlipChannels),
|
||||
m_dsb(dsb),
|
||||
m_audioMute(audioMute),
|
||||
m_playLoop(playLoop)
|
||||
m_playLoop(playLoop),
|
||||
m_agc(agc),
|
||||
m_agcTime(agcTime),
|
||||
m_agcThreshold(agcThreshold),
|
||||
m_agcThresholdGate(agcThresholdGate),
|
||||
m_agcThresholdDelay(agcThresholdDelay)
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -313,6 +348,12 @@ private:
|
||||
bool m_dsb;
|
||||
bool m_audioMute;
|
||||
bool m_playLoop;
|
||||
bool m_agc;
|
||||
int m_agcTime;
|
||||
bool m_agcThresholdEnable;
|
||||
double m_agcThreshold;
|
||||
int m_agcThresholdGate;
|
||||
int m_agcThresholdDelay;
|
||||
|
||||
Config() :
|
||||
m_outputSampleRate(0),
|
||||
@ -328,7 +369,13 @@ private:
|
||||
m_audioFlipChannels(false),
|
||||
m_dsb(false),
|
||||
m_audioMute(false),
|
||||
m_playLoop(false)
|
||||
m_playLoop(false),
|
||||
m_agc(false),
|
||||
m_agcTime(9600),
|
||||
m_agcThresholdEnable(true),
|
||||
m_agcThreshold(1e-4),
|
||||
m_agcThresholdGate(192),
|
||||
m_agcThresholdDelay(2400)
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -365,7 +412,6 @@ private:
|
||||
|
||||
double m_magsq;
|
||||
MovingAverage<double> m_movingAverage;
|
||||
SimpleAGC m_volumeAGC;
|
||||
|
||||
AudioVector m_audioBuffer;
|
||||
uint m_audioBufferFill;
|
||||
@ -386,6 +432,8 @@ private:
|
||||
CWKeyer m_cwKeyer;
|
||||
CWSmoother m_cwSmoother;
|
||||
|
||||
MagAGC m_inAGC;
|
||||
|
||||
static const int m_levelNbSamples;
|
||||
|
||||
void apply();
|
||||
|
@ -36,6 +36,18 @@
|
||||
|
||||
const QString SSBModGUI::m_channelID = "sdrangel.channeltx.modssb";
|
||||
|
||||
const int SSBModGUI::m_agcTimeConstant[] = {
|
||||
1,
|
||||
2,
|
||||
5,
|
||||
10,
|
||||
20,
|
||||
50,
|
||||
100,
|
||||
200,
|
||||
500,
|
||||
990};
|
||||
|
||||
SSBModGUI* SSBModGUI::create(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI)
|
||||
{
|
||||
SSBModGUI* gui = new SSBModGUI(pluginAPI, deviceAPI);
|
||||
@ -105,6 +117,11 @@ QByteArray SSBModGUI::serialize() const
|
||||
s.writeBool(9, ui->audioBinaural->isChecked());
|
||||
s.writeBool(10, ui->audioFlipChannels->isChecked());
|
||||
s.writeBool(11, ui->dsb->isChecked());
|
||||
s.writeBool(12, ui->agc->isChecked());
|
||||
s.writeS32(13, ui->agcTime->value());
|
||||
s.writeS32(14, ui->agcThreshold->value());
|
||||
s.writeS32(15, ui->agcThresholdGate->value());
|
||||
s.writeS32(16, ui->agcThresholdDelay->value());
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -158,6 +175,18 @@ bool SSBModGUI::deserialize(const QByteArray& data)
|
||||
ui->audioFlipChannels->setChecked(booltmp);
|
||||
d.readBool(11, &booltmp);
|
||||
ui->dsb->setChecked(booltmp);
|
||||
d.readBool(12, &booltmp, false);
|
||||
ui->agc->setChecked(booltmp);
|
||||
d.readS32(13, &tmp, 7);
|
||||
ui->agcTime->setValue(tmp > 9 ? 9 : tmp);
|
||||
d.readS32(14, &tmp, -40);
|
||||
ui->agcThreshold->setValue(tmp);
|
||||
d.readS32(15, &tmp, 4);
|
||||
ui->agcThresholdGate->setValue(tmp);
|
||||
d.readS32(16, &tmp, 5);
|
||||
ui->agcThresholdDelay->setValue(tmp);
|
||||
|
||||
displaySettings();
|
||||
|
||||
blockApplySettings(false);
|
||||
m_channelMarker.blockSignals(false);
|
||||
@ -399,6 +428,37 @@ void SSBModGUI::on_mic_toggled(bool checked)
|
||||
m_ssbMod->getInputMessageQueue()->push(message);
|
||||
}
|
||||
|
||||
void SSBModGUI::on_agc_stateChanged(int state __attribute((__unused__)))
|
||||
{
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void SSBModGUI::on_agcTime_valueChanged(int value){
|
||||
QString s = QString::number(m_agcTimeConstant[value], 'f', 0);
|
||||
ui->agcTimeText->setText(s);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void SSBModGUI::on_agcThreshold_valueChanged(int value)
|
||||
{
|
||||
displayAGCPowerThreshold(value);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void SSBModGUI::on_agcThresholdGate_valueChanged(int value)
|
||||
{
|
||||
QString s = QString::number(value, 'f', 0);
|
||||
ui->agcThresholdGateText->setText(s);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void SSBModGUI::on_agcThresholdDelay_valueChanged(int value)
|
||||
{
|
||||
QString s = QString::number(value * 10, 'f', 0);
|
||||
ui->agcThresholdDelayText->setText(s);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void SSBModGUI::on_navTimeSlider_valueChanged(int value)
|
||||
{
|
||||
if (m_enableNavTime && ((value >= 0) && (value <= 100)))
|
||||
@ -507,6 +567,7 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa
|
||||
ui->cwKeyerGUI->setBuddies(m_ssbMod->getInputMessageQueue(), m_ssbMod->getCWKeyer());
|
||||
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
|
||||
|
||||
displaySettings();
|
||||
applySettings();
|
||||
setNewRate(m_spanLog2);
|
||||
|
||||
@ -629,10 +690,39 @@ void SSBModGUI::applySettings()
|
||||
ui->audioFlipChannels->isChecked(),
|
||||
ui->dsb->isChecked(),
|
||||
ui->audioMute->isChecked(),
|
||||
ui->playLoop->isChecked());
|
||||
ui->playLoop->isChecked(),
|
||||
ui->agc->isChecked(),
|
||||
m_agcTimeConstant[ui->agcTime->value()],
|
||||
ui->agcThreshold->value(),
|
||||
ui->agcThresholdGate->value(),
|
||||
ui->agcThresholdDelay->value() * 10);
|
||||
}
|
||||
}
|
||||
|
||||
void SSBModGUI::displaySettings()
|
||||
{
|
||||
QString s = QString::number(m_agcTimeConstant[ui->agcTime->value()], 'f', 0);
|
||||
ui->agcTimeText->setText(s);
|
||||
displayAGCPowerThreshold(ui->agcThreshold->value());
|
||||
s = QString::number(ui->agcThresholdGate->value(), 'f', 0);
|
||||
ui->agcThresholdGateText->setText(s);
|
||||
s = QString::number(ui->agcThresholdDelay->value() * 10, 'f', 0);
|
||||
ui->agcThresholdDelayText->setText(s);
|
||||
}
|
||||
|
||||
void SSBModGUI::displayAGCPowerThreshold(int value)
|
||||
{
|
||||
if (value == -99)
|
||||
{
|
||||
ui->agcThresholdText->setText("---");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString s = QString::number(value, 'f', 0);
|
||||
ui->agcThresholdText->setText(s);
|
||||
}
|
||||
}
|
||||
|
||||
void SSBModGUI::leaveEvent(QEvent*)
|
||||
{
|
||||
blockApplySettings(true);
|
||||
|
@ -71,6 +71,11 @@ private slots:
|
||||
void on_tone_toggled(bool checked);
|
||||
void on_toneFrequency_valueChanged(int value);
|
||||
void on_mic_toggled(bool checked);
|
||||
void on_agc_stateChanged(int state);
|
||||
void on_agcTime_valueChanged(int value);
|
||||
void on_agcThreshold_valueChanged(int value);
|
||||
void on_agcThresholdGate_valueChanged(int value);
|
||||
void on_agcThresholdDelay_valueChanged(int value);
|
||||
void on_play_toggled(bool checked);
|
||||
void on_playLoop_toggled(bool checked);
|
||||
void on_morseKeyer_toggled(bool checked);
|
||||
@ -107,6 +112,7 @@ private:
|
||||
std::size_t m_tickCount;
|
||||
bool m_enableNavTime;
|
||||
SSBMod::SSBModInputAF m_modAFInput;
|
||||
static const int m_agcTimeConstant[]; //!< time constant index to value in ms
|
||||
|
||||
explicit SSBModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* parent = NULL);
|
||||
virtual ~SSBModGUI();
|
||||
@ -116,6 +122,8 @@ private:
|
||||
|
||||
void blockApplySettings(bool block);
|
||||
void applySettings();
|
||||
void displaySettings();
|
||||
void displayAGCPowerThreshold(int value);
|
||||
void updateWithStreamData();
|
||||
void updateWithStreamTime();
|
||||
|
||||
|
@ -463,6 +463,204 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_agc">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="agc">
|
||||
<property name="toolTip">
|
||||
<string>Toggle audio compressor</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cmp</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDial" name="agcTime">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Compressor time constant (attack)</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="agcTimeText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Compressor time constant in ms</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDial" name="agcThreshold">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio squelch threshold</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-99</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>-40</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="agcThresholdText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>14</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio squelch threshold (dB power)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-00</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDial" name="agcThresholdGate">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio squelch gate</string>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="agcThresholdGateText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio squelch gate in ms</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDial" name="agcThresholdDelay">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio squelch delay (release)</string>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="agcThresholdDelayText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio squelch delay in ms</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="inputSelectLayout">
|
||||
<item>
|
||||
|
@ -53,7 +53,11 @@ MagAGC::MagAGC(int historySize, double R, double threshold) :
|
||||
m_stepDelta(1.0/m_stepLength),
|
||||
m_stepUpCounter(0),
|
||||
m_stepDownCounter(m_stepLength),
|
||||
m_gateCounter(0)
|
||||
m_gateCounter(0),
|
||||
m_stepDownDelay(historySize),
|
||||
m_clamping(false),
|
||||
m_R2(R*R),
|
||||
m_clampMax(1.0)
|
||||
{}
|
||||
|
||||
MagAGC::~MagAGC()
|
||||
@ -61,6 +65,7 @@ MagAGC::~MagAGC()
|
||||
|
||||
void MagAGC::resize(int historySize, Real R)
|
||||
{
|
||||
m_R2 = R*R;
|
||||
m_stepLength = std::min(StepLengthMax, historySize/2);
|
||||
m_stepDelta = 1.0 / m_stepLength;
|
||||
m_stepUpCounter = 0;
|
||||
@ -88,7 +93,24 @@ double MagAGC::feedAndGetValue(const Complex& ci)
|
||||
{
|
||||
m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
|
||||
m_moving_average.feed(m_magsq);
|
||||
m_u0 = m_R / (m_squared ? m_moving_average.average() : sqrt(m_moving_average.average()));
|
||||
|
||||
if (m_clamping)
|
||||
{
|
||||
if (m_squared)
|
||||
{
|
||||
double u0 = m_R / m_moving_average.average();
|
||||
m_u0 = (u0 * m_magsq > m_clampMax) ? m_clampMax / m_magsq : u0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double u02 = m_R2 / m_moving_average.average();
|
||||
m_u0 = (u02 * m_magsq > m_clampMax) ? m_clampMax / sqrt(m_magsq) : sqrt(u02);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_u0 = m_R / (m_squared ? m_moving_average.average() : sqrt(m_moving_average.average()));
|
||||
}
|
||||
|
||||
if (m_thresholdEnable)
|
||||
{
|
||||
@ -105,14 +127,14 @@ double MagAGC::feedAndGetValue(const Complex& ci)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_count < m_moving_average.historySize()) {
|
||||
if (m_count < m_stepDownDelay) {
|
||||
m_count++;
|
||||
}
|
||||
|
||||
m_gateCounter = 0;
|
||||
}
|
||||
|
||||
if (m_count < m_moving_average.historySize())
|
||||
if (m_count < m_stepDownDelay)
|
||||
{
|
||||
m_stepDownCounter = m_stepUpCounter;
|
||||
|
||||
|
@ -22,11 +22,11 @@ public:
|
||||
virtual void feed(Complex& ci) = 0;
|
||||
|
||||
protected:
|
||||
double m_u0;
|
||||
double m_R; // objective mag
|
||||
MovingAverage<double> m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC.
|
||||
int m_historySize;
|
||||
int m_count;
|
||||
double m_u0; //!< AGC factor
|
||||
double m_R; //!< objective mag
|
||||
MovingAverage<double> m_moving_average; //!< Averaging engine. The stack length conditions the smoothness of AGC.
|
||||
int m_historySize; //!< Averaging length (attack)
|
||||
int m_count; //!< Samples counter
|
||||
};
|
||||
|
||||
|
||||
@ -43,6 +43,9 @@ public:
|
||||
void setThreshold(double threshold) { m_threshold = threshold; }
|
||||
void setThresholdEnable(bool enable);
|
||||
void setGate(int gate) { m_gate = gate; }
|
||||
void setStepDownDelay(int stepDownDelay) { m_stepDownDelay = stepDownDelay; }
|
||||
void setClamping(bool clamping) { m_clamping = clamping; }
|
||||
void setClampMax(double clampMax) { m_clampMax = clampMax; }
|
||||
private:
|
||||
bool m_squared; //!< use squared magnitude (power) to compute AGC value
|
||||
double m_magsq; //!< current squared magnitude (power)
|
||||
@ -54,6 +57,10 @@ private:
|
||||
int m_stepUpCounter; //!< step up transition samples counter
|
||||
int m_stepDownCounter; //!< step down transition samples counter
|
||||
int m_gateCounter; //!< threshold gate samples counter
|
||||
int m_stepDownDelay; //!< delay in samples before cutoff (release)
|
||||
bool m_clamping; //!< clamping active
|
||||
double m_R2; //!< square of objective magnitude
|
||||
double m_clampMax; //!< maximum to clamp to
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user