FreeDV demod: implement VU meter on modem input

This commit is contained in:
f4exb 2019-02-28 15:15:04 +01:00
parent 64993cfa2f
commit 4e7b2ac72a
7 changed files with 147 additions and 34 deletions

View File

@ -46,6 +46,7 @@ MESSAGE_CLASS_DEFINITION(FreeDVDemod::MsgConfigureChannelizer, Message)
const QString FreeDVDemod::m_channelIdURI = "sdrangel.channel.freedvdemod";
const QString FreeDVDemod::m_channelId = "FreeDVDemod";
const int FreeDVDemod::m_levelInNbSamples = 160; // 10ms @ 8kS/s modem input
FreeDVDemod::FreeDVStats::FreeDVStats()
{
@ -118,6 +119,31 @@ void FreeDVDemod::FreeDVSNR::accumulate(float snrdB)
}
}
FreeDVDemod::LevelRMS::LevelRMS()
{
m_sum = 0.0f;
m_peak = 0.0f;
m_n = 0;
m_reset = true;
}
void FreeDVDemod::LevelRMS::accumulate(float level)
{
if (m_reset)
{
m_sum = level * level;
m_peak = std::fabs(level);
m_n = 1;
m_reset = false;
}
else
{
m_sum += level * level;
m_peak = std::max(m_peak, std::fabs(level));
m_n++;
}
}
FreeDVDemod::FreeDVDemod(DeviceSourceAPI *deviceAPI) :
ChannelSinkAPI(m_channelIdURI),
m_deviceAPI(deviceAPI),
@ -400,6 +426,17 @@ void FreeDVDemod::pushSampleToDV(int16_t sample)
{
qint16 audioSample;
if (m_levelIn.m_n >= m_levelInNbSamples)
{
qreal rmsLevel = sqrt(m_levelIn.m_sum / m_levelInNbSamples);
// qDebug("FreeDVDemod::pushSampleToDV: rmsLevel: %f m_peak: %f m_levelInNbSamples: %d",
// rmsLevel, m_levelIn.m_peak, m_levelInNbSamples);
emit levelInChanged(rmsLevel, m_levelIn.m_peak, m_levelInNbSamples);
m_levelIn.m_reset = true;
}
m_levelIn.accumulate(sample/32768.0f);
if (m_iModem == m_nin)
{
int nout = freedv_rx(m_freeDV, m_speechOut, m_modIn);

View File

@ -184,6 +184,15 @@ public:
static const QString m_channelIdURI;
static const QString m_channelId;
signals:
/**
* Level changed
* \param rmsLevel RMS level in range 0.0 - 1.0
* \param peakLevel Peak level in range 0.0 - 1.0
* \param numSamples Number of audio samples analyzed
*/
void levelInChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
private:
struct MagSqLevelsStore
{
@ -225,6 +234,17 @@ private:
bool m_reset;
};
struct LevelRMS
{
LevelRMS();
void accumulate(float fsample);
double m_sum;
float m_peak;
int m_n;
bool m_reset;
};
class MsgConfigureFreeDVDemodPrivate : public Message {
MESSAGE_CLASS_DECLARATION
@ -372,6 +392,8 @@ private:
AudioResampler m_audioResampler;
FreeDVStats m_freeDVStats;
FreeDVSNR m_freeDVSNR;
LevelRMS m_levelIn;
static const int m_levelInNbSamples;
QMutex m_settingsMutex;

View File

@ -174,6 +174,13 @@ void FreeDVDemodGUI::on_volume_valueChanged(int value)
applySettings();
}
void FreeDVDemodGUI::on_volumeIn_valueChanged(int value)
{
ui->volumeInText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_volumeIn = value / 10.0;
applySettings();
}
void FreeDVDemodGUI::on_agc_toggled(bool checked)
{
m_settings.m_agc = checked;
@ -286,6 +293,7 @@ FreeDVDemodGUI::FreeDVDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(m_freeDVDemod, SIGNAL(levelInChanged(qreal, qreal, int)), ui->volumeInMeter, SLOT(levelChanged(qreal, qreal, int)));
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);

View File

@ -97,6 +97,7 @@ private slots:
void on_reSync_clicked(bool checked);
void on_freeDVMode_currentIndexChanged(int index);
void on_volume_valueChanged(int value);
void on_volumeIn_valueChanged(int value);
void on_agc_toggled(bool checked);
void on_audioMute_toggled(bool checked);
void on_spanLog2_valueChanged(int value);

View File

@ -272,10 +272,78 @@
</item>
<item>
<layout class="QHBoxLayout" name="volumeLayout">
<item>
<widget class="ButtonSwitch" name="agc">
<property name="toolTip">
<string>Toggle AGC</string>
</property>
<property name="text">
<string>AGC</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="voluneInLabel">
<property name="text">
<string>Input</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="volumeIn">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="volumeInText">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>2.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="LevelMeterVU" name="volumeInMeter" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>24</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="volumeLabel">
<property name="text">
<string>Vol</string>
<string>Audio</string>
</property>
</widget>
</item>
@ -314,39 +382,6 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="agc">
<property name="toolTip">
<string>Toggle AGC</string>
</property>
<property name="text">
<string>AGC</string>
</property>
<property name="checkable">
<bool>true</bool>
</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>
<item>
<widget class="QToolButton" name="audioMute">
<property name="toolTip">
@ -684,6 +719,12 @@
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>LevelMeterVU</class>
<extends>QWidget</extends>
<header>gui/levelmeter.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>

View File

@ -41,6 +41,7 @@ void FreeDVDemodSettings::resetToDefaults()
m_audioMute = false;
m_agc = true;
m_volume = 3.0;
m_volumeIn = 3.0;
m_spanLog2 = 3;
m_inputFrequencyOffset = 0;
m_rgbColor = QColor(0, 255, 204).rgb();
@ -65,6 +66,7 @@ QByteArray FreeDVDemodSettings::serialize() const
}
s.writeU32(5, m_rgbColor);
s.writeS32(6, m_volumeIn * 10.0);
s.writeS32(7, m_spanLog2);
s.writeBool(11, m_agc);
s.writeString(16, m_title);
@ -108,6 +110,7 @@ bool FreeDVDemodSettings::deserialize(const QByteArray& data)
d.readU32(5, &m_rgbColor);
d.readS32(6, &tmp, 30);
m_volumeIn = tmp / 10.0;
d.readS32(7, &m_spanLog2, 3);
d.readBool(11, &m_agc, false);
d.readString(16, &m_title, "SSB Demodulator");

View File

@ -36,6 +36,7 @@ struct FreeDVDemodSettings
qint32 m_inputFrequencyOffset;
Real m_volume;
Real m_volumeIn;
int m_spanLog2;
bool m_audioMute;
bool m_agc;