From d6cafa08c533287b4969129531cd31266d8e7ad4 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 16 Jan 2023 21:51:26 +0100 Subject: [PATCH] FT8 demod: volume meter --- plugins/channelrx/demodft8/ft8demod.cpp | 2 +- plugins/channelrx/demodft8/ft8demod.h | 3 ++ .../channelrx/demodft8/ft8demodbaseband.cpp | 5 +++ plugins/channelrx/demodft8/ft8demodbaseband.h | 9 ++++ plugins/channelrx/demodft8/ft8demodgui.cpp | 1 + plugins/channelrx/demodft8/ft8demodgui.ui | 39 +++++++++++------- plugins/channelrx/demodft8/ft8demodsink.cpp | 41 ++++++++++++++++++- plugins/channelrx/demodft8/ft8demodsink.h | 30 ++++++++++++++ 8 files changed, 114 insertions(+), 16 deletions(-) diff --git a/plugins/channelrx/demodft8/ft8demod.cpp b/plugins/channelrx/demodft8/ft8demod.cpp index 5459d17a4..86ca3690f 100644 --- a/plugins/channelrx/demodft8/ft8demod.cpp +++ b/plugins/channelrx/demodft8/ft8demod.cpp @@ -746,5 +746,5 @@ void FT8Demod::handleIndexInDeviceSetChanged(int index) .arg(m_deviceAPI->getDeviceSetIndex()) .arg(index); m_basebandSink->setFifoLabel(fifoLabel); - m_basebandSink->setAudioFifoLabel(fifoLabel); + m_basebandSink->setAudioFifoLabel(fifoLabel); } diff --git a/plugins/channelrx/demodft8/ft8demod.h b/plugins/channelrx/demodft8/ft8demod.h index d378ea7e1..a92f208cb 100644 --- a/plugins/channelrx/demodft8/ft8demod.h +++ b/plugins/channelrx/demodft8/ft8demod.h @@ -136,6 +136,9 @@ public: SWGSDRangel::SWGChannelSettings& response); uint32_t getNumberOfDeviceStreams() const; + void setLevelMeter(QObject *levelMeter) { + connect(m_basebandSink, SIGNAL(levelChanged(qreal, qreal, int)), levelMeter, SLOT(levelChanged(qreal, qreal, int))); + } static const char* const m_channelIdURI; static const char* const m_channelId; diff --git a/plugins/channelrx/demodft8/ft8demodbaseband.cpp b/plugins/channelrx/demodft8/ft8demodbaseband.cpp index bd873b852..54a8ac610 100644 --- a/plugins/channelrx/demodft8/ft8demodbaseband.cpp +++ b/plugins/channelrx/demodft8/ft8demodbaseband.cpp @@ -94,6 +94,11 @@ void FT8DemodBaseband::handleData() m_sampleFifo.readCommit((unsigned int) count); } + + qreal rmsLevel, peakLevel; + int numSamples; + m_sink.getLevels(rmsLevel, peakLevel, numSamples); + emit levelChanged(rmsLevel, peakLevel, numSamples); } void FT8DemodBaseband::handleInputMessages() diff --git a/plugins/channelrx/demodft8/ft8demodbaseband.h b/plugins/channelrx/demodft8/ft8demodbaseband.h index b23f5de55..b05e8a627 100644 --- a/plugins/channelrx/demodft8/ft8demodbaseband.h +++ b/plugins/channelrx/demodft8/ft8demodbaseband.h @@ -75,6 +75,15 @@ public: void setFifoLabel(const QString& label) { m_sampleFifo.setLabel(label); } void setAudioFifoLabel(const QString& label) { m_sink.setAudioFifoLabel(label); } +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 samples analyzed + */ + void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples); + private: SampleSinkFifo m_sampleFifo; DownChannelizer m_channelizer; diff --git a/plugins/channelrx/demodft8/ft8demodgui.cpp b/plugins/channelrx/demodft8/ft8demodgui.cpp index 51aff69b1..5b1e9714d 100644 --- a/plugins/channelrx/demodft8/ft8demodgui.cpp +++ b/plugins/channelrx/demodft8/ft8demodgui.cpp @@ -324,6 +324,7 @@ FT8DemodGUI::FT8DemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); + m_ft8Demod->setLevelMeter(ui->volumeMeter); ui->BW->setMaximum(60); ui->BW->setMinimum(10); diff --git a/plugins/channelrx/demodft8/ft8demodgui.ui b/plugins/channelrx/demodft8/ft8demodgui.ui index 978d1dbe9..ad055f60c 100644 --- a/plugins/channelrx/demodft8/ft8demodgui.ui +++ b/plugins/channelrx/demodft8/ft8demodgui.ui @@ -635,24 +635,29 @@ - - - Qt::Vertical + + + + 0 + 0 + - - - - - - Qt::Horizontal - - + - 40 - 20 + 140 + 24 - + + + Liberation Mono + 8 + + + + Modem input volume + + @@ -774,6 +779,12 @@ QSlider
gui/tickedslider.h
+ + LevelMeterVU + QWidget +
gui/levelmeter.h
+ 1 +
diff --git a/plugins/channelrx/demodft8/ft8demodsink.cpp b/plugins/channelrx/demodft8/ft8demodsink.cpp index c877d6a6d..f6e8180b6 100644 --- a/plugins/channelrx/demodft8/ft8demodsink.cpp +++ b/plugins/channelrx/demodft8/ft8demodsink.cpp @@ -36,13 +36,39 @@ const int FT8DemodSink::m_ssbFftLen = 1024; const int FT8DemodSink::m_agcTarget = 3276; // 32768/10 -10 dB amplitude => -20 dB power: center of normal signal +FT8DemodSink::LevelRMS::LevelRMS() +{ + m_sum = 0.0f; + m_peak = 0.0f; + m_n = 0; + m_reset = true; +} + +void FT8DemodSink::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++; + } +} + FT8DemodSink::FT8DemodSink() : m_agc(12000, m_agcTarget, 1e-2), m_agcActive(false), m_audioActive(false), m_spectrumSink(nullptr), m_audioFifo(24000), - m_ft8SampleRate(12000) + m_ft8SampleRate(12000), + m_levelInNbSamples(1200) // 100 ms { m_Bandwidth = 5000; m_LowCutoff = 300; @@ -155,6 +181,7 @@ void FT8DemodSink::processOneSample(Complex &ci) m_audioBuffer[m_audioBufferFill].l = sample; m_audioBuffer[m_audioBufferFill].r = sample; m_demodBuffer[m_demodBufferFill++] = sample; + calculateLevel(sample); if (m_demodBufferFill >= m_demodBuffer.size()) { @@ -241,6 +268,7 @@ void FT8DemodSink::applyFT8SampleRate(int sampleRate) m_audioFifo.setSize(sampleRate); m_ft8SampleRate = sampleRate; + m_levelInNbSamples = m_ft8SampleRate / 10; // 100 ms QList pipes; MainCore::instance()->getMessagePipes().getMessagePipes(m_channel, "reportdemod", pipes); @@ -324,3 +352,14 @@ void FT8DemodSink::applySettings(const FT8DemodSettings& settings, bool force) m_settings = settings; } +void FT8DemodSink::calculateLevel(int16_t& sample) +{ + if (m_levelIn.m_n >= m_levelInNbSamples) + { + m_rmsLevel = sqrt(m_levelIn.m_sum / m_levelInNbSamples); + m_peakLevel = m_levelIn.m_peak; + m_levelIn.m_reset = true; + } + + m_levelIn.accumulate(sample/29491.2f); // scale on 90% (0.9 * 32768.0) +} diff --git a/plugins/channelrx/demodft8/ft8demodsink.h b/plugins/channelrx/demodft8/ft8demodsink.h index 82b9971c6..fae7d5eca 100644 --- a/plugins/channelrx/demodft8/ft8demodsink.h +++ b/plugins/channelrx/demodft8/ft8demodsink.h @@ -69,6 +69,19 @@ public: m_magsqCount = 0; } + /** + * 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 samples analyzed + */ + void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) + { + rmsLevel = m_rmsLevel; + peakLevel = m_peakLevel; + numSamples = m_levelInNbSamples; + } + private: struct MagSqLevelsStore { @@ -80,6 +93,17 @@ private: double m_magsqPeak; }; + struct LevelRMS + { + LevelRMS(); + void accumulate(float fsample); + + double m_sum; + float m_peak; + int m_n; + bool m_reset; + }; + FT8DemodSettings m_settings; ChannelAPI *m_channel; @@ -118,10 +142,16 @@ private: QVector m_demodBuffer; int m_demodBufferFill; + LevelRMS m_levelIn; + int m_levelInNbSamples; + Real m_rmsLevel; + Real m_peakLevel; + static const int m_ssbFftLen; static const int m_agcTarget; void processOneSample(Complex &ci); + void calculateLevel(int16_t& sample); }; #endif // INCLUDE_FT8DEMODSINK_H