diff --git a/plugins/channeltx/modam/ammod.cpp b/plugins/channeltx/modam/ammod.cpp index 7b33982cb..5647cac76 100644 --- a/plugins/channeltx/modam/ammod.cpp +++ b/plugins/channeltx/modam/ammod.cpp @@ -33,6 +33,7 @@ MESSAGE_CLASS_DEFINITION(AMMod::MsgConfigureFileSourceStreamTiming, Message) MESSAGE_CLASS_DEFINITION(AMMod::MsgReportFileSourceStreamData, Message) MESSAGE_CLASS_DEFINITION(AMMod::MsgReportFileSourceStreamTiming, Message) +const int AMMod::m_levelNbSamples = 480; // every 10ms AMMod::AMMod() : m_audioFifo(4, 48000), @@ -40,7 +41,10 @@ AMMod::AMMod() : m_fileSize(0), m_recordLength(0), m_sampleRate(48000), - m_afInput(AMModInputNone) + m_afInput(AMModInputNone), + m_levelCalcCount(0), + m_peakLevel(0.0f), + m_levelSum(0.0f) { setObjectName("AMMod"); @@ -73,11 +77,11 @@ void AMMod::configure(MessageQueue* messageQueue, Real rfBandwidth, float modFactor, float toneFrequency, - int volumeTenths, + float volumeFactor, bool audioMute, bool playLoop) { - Message* cmd = MsgConfigureAMMod::create(rfBandwidth, modFactor, toneFrequency, volumeTenths, audioMute, playLoop); + Message* cmd = MsgConfigureAMMod::create(rfBandwidth, modFactor, toneFrequency, volumeFactor, audioMute, playLoop); messageQueue->push(cmd); } @@ -124,6 +128,7 @@ void AMMod::modulateSample() Real t; pullAF(t); + calculateLevel(t); m_modSample.real((t*m_running.m_modFactor + 1.0f) * 16384.0f); // modulate and scale zero frequency carrier m_modSample.imag(0.0f); @@ -159,6 +164,7 @@ void AMMod::pullAF(Real& sample) else { m_ifstream.read(reinterpret_cast(&sample), sizeof(Real)); + sample *= m_running.m_volumeFactor; } } else @@ -168,7 +174,7 @@ void AMMod::pullAF(Real& sample) break; case AMModInputAudio: m_audioFifo.read(reinterpret_cast(audioSample), 1, 10); - sample = ((audioSample[0] + audioSample[1]) * m_running.m_volumeFactor) / 6553600.0f; + sample = ((audioSample[0] + audioSample[1]) / 65536.0f) * m_running.m_volumeFactor; break; case AMModInputNone: default: @@ -177,6 +183,25 @@ void AMMod::pullAF(Real& sample) } } +void AMMod::calculateLevel(Real& sample) +{ + if (m_levelCalcCount < m_levelNbSamples) + { + m_peakLevel = std::max(std::fabs(m_peakLevel), sample); + m_levelSum += sample * sample; + m_levelCalcCount++; + } + else + { + qreal rmsLevel = sqrt(m_levelSum / m_levelNbSamples); + //qDebug("NFMMod::calculateLevel: %f %f", rmsLevel, m_peakLevel); + emit levelChanged(rmsLevel, m_peakLevel, m_levelNbSamples); + m_peakLevel = 0.0f; + m_levelSum = 0.0f; + m_levelCalcCount = 0; + } +} + void AMMod::start() { qDebug() << "AMMod::start: m_outputSampleRate: " << m_config.m_outputSampleRate diff --git a/plugins/channeltx/modam/ammod.h b/plugins/channeltx/modam/ammod.h index 0a2bd211a..e832f12d5 100644 --- a/plugins/channeltx/modam/ammod.h +++ b/plugins/channeltx/modam/ammod.h @@ -177,7 +177,7 @@ public: Real rfBandwidth, float modFactor, float toneFrequency, - int volumeFactor, + float volumeFactor, bool audioMute, bool playLoop); @@ -188,6 +188,16 @@ public: Real getMagSq() const { return m_magsq; } +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 levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples); + + private: class MsgConfigureAMMod : public Message { @@ -197,11 +207,11 @@ private: Real getRFBandwidth() const { return m_rfBandwidth; } float getModFactor() const { return m_modFactor; } float getToneFrequency() const { return m_toneFrequency; } - int getVolumeFactor() const { return m_volumeFactor; } + float getVolumeFactor() const { return m_volumeFactor; } bool getAudioMute() const { return m_audioMute; } bool getPlayLoop() const { return m_playLoop; } - static MsgConfigureAMMod* create(Real rfBandwidth, float modFactor, float toneFreqeuncy, int volumeFactor, bool audioMute, bool playLoop) + static MsgConfigureAMMod* create(Real rfBandwidth, float modFactor, float toneFreqeuncy, float volumeFactor, bool audioMute, bool playLoop) { return new MsgConfigureAMMod(rfBandwidth, modFactor, toneFreqeuncy, volumeFactor, audioMute, playLoop); } @@ -210,11 +220,11 @@ private: Real m_rfBandwidth; float m_modFactor; float m_toneFrequency; - int m_volumeFactor; + float m_volumeFactor; bool m_audioMute; bool m_playLoop; - MsgConfigureAMMod(Real rfBandwidth, float modFactor, float toneFrequency, int volumeFactor, bool audioMute, bool playLoop) : + MsgConfigureAMMod(Real rfBandwidth, float modFactor, float toneFrequency, float volumeFactor, bool audioMute, bool playLoop) : Message(), m_rfBandwidth(rfBandwidth), m_modFactor(modFactor), @@ -244,7 +254,7 @@ private: Real m_rfBandwidth; float m_modFactor; float m_toneFrequency; - int m_volumeFactor; + float m_volumeFactor; quint32 m_audioSampleRate; bool m_audioMute; bool m_playLoop; @@ -255,7 +265,7 @@ private: m_rfBandwidth(-1), m_modFactor(0.2f), m_toneFrequency(100), - m_volumeFactor(20), + m_volumeFactor(1.0f), m_audioSampleRate(0), m_audioMute(false), m_playLoop(false) @@ -293,9 +303,14 @@ private: int m_sampleRate; AMModInputAF m_afInput; + quint32 m_levelCalcCount; + Real m_peakLevel; + Real m_levelSum; + static const int m_levelNbSamples; void apply(); void pullAF(Real& sample); + void calculateLevel(Real& sample); void modulateSample(); void openFileStream(); void seekFileStream(int seekPercentage); diff --git a/plugins/channeltx/modam/ammodgui.cpp b/plugins/channeltx/modam/ammodgui.cpp index 656f15ace..362245229 100644 --- a/plugins/channeltx/modam/ammodgui.cpp +++ b/plugins/channeltx/modam/ammodgui.cpp @@ -72,7 +72,7 @@ void AMModGUI::resetToDefaults() ui->rfBW->setValue(50); ui->modPercent->setValue(20); - ui->micVolume->setValue(50); + ui->volume->setValue(10); ui->toneFrequency->setValue(100); ui->deltaFrequency->setValue(0); @@ -83,11 +83,14 @@ void AMModGUI::resetToDefaults() QByteArray AMModGUI::serialize() const { SimpleSerializer s(1); + s.writeS32(1, m_channelMarker.getCenterFrequency()); s.writeS32(2, ui->rfBW->value()); s.writeS32(3, ui->toneFrequency->value()); s.writeS32(4, ui->modPercent->value()); s.writeU32(5, m_channelMarker.getColor().rgb()); + s.writeS32(6, ui->volume->value()); + return s.final(); } @@ -124,6 +127,9 @@ bool AMModGUI::deserialize(const QByteArray& data) m_channelMarker.setColor(u32tmp); } + d.readS32(6, &tmp, 10); + ui->volume->setValue(tmp); + blockApplySettings(false); m_channelMarker.blockSignals(false); @@ -210,9 +216,9 @@ void AMModGUI::on_modPercent_valueChanged(int value) applySettings(); } -void AMModGUI::on_micVolume_valueChanged(int value) +void AMModGUI::on_volume_valueChanged(int value) { - ui->micVolumeText->setText(QString("%1").arg(value)); + ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); applySettings(); } @@ -360,6 +366,7 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pare applySettings(); connect(m_amMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + connect(m_amMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); } AMModGUI::~AMModGUI() @@ -395,7 +402,7 @@ void AMModGUI::applySettings() ui->rfBW->value() * 100.0, ui->modPercent->value() / 100.0f, ui->toneFrequency->value() * 10.0f, - ui->micVolume->value(), + ui->volume->value() / 10.0f , ui->audioMute->isChecked(), ui->playLoop->isChecked()); } diff --git a/plugins/channeltx/modam/ammodgui.h b/plugins/channeltx/modam/ammodgui.h index f27d57a8b..5e9dbc73a 100644 --- a/plugins/channeltx/modam/ammodgui.h +++ b/plugins/channeltx/modam/ammodgui.h @@ -62,7 +62,7 @@ private slots: void on_deltaMinus_toggled(bool minus); void on_rfBW_valueChanged(int value); void on_modPercent_valueChanged(int value); - void on_micVolume_valueChanged(int value); + void on_volume_valueChanged(int value); void on_audioMute_toggled(bool checked); void on_tone_toggled(bool checked); void on_toneFrequency_valueChanged(int value); diff --git a/plugins/channeltx/modam/ammodgui.ui b/plugins/channeltx/modam/ammodgui.ui index ec5cbf2e1..4c7c8ead7 100644 --- a/plugins/channeltx/modam/ammodgui.ui +++ b/plugins/channeltx/modam/ammodgui.ui @@ -50,7 +50,16 @@ 3 - + + 2 + + + 2 + + + 2 + + 2 @@ -287,6 +296,81 @@ + + + + Qt::Horizontal + + + + + + + + + Vol + + + + + + + + 24 + 24 + + + + Audio input gain + + + 100 + + + 1 + + + 10 + + + + + + + + 25 + 0 + + + + Audio input gain value + + + + + + 1.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Volume meter. White line is 100% and shoul not be exceeded (red zone) + + + + + @@ -371,47 +455,6 @@ - - - - - 24 - 24 - - - - Audio input volume - - - 100 - - - 1 - - - 50 - - - - - - - - 20 - 0 - - - - Audio input volume level - - - 50 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -427,6 +470,13 @@ + + + + Qt::Horizontal + + + @@ -611,29 +661,15 @@ QToolButton
gui/buttonswitch.h
+ + LevelMeter + QWidget +
gui/levelmeter.h
+ 1 +
- - - - - - - - - - - - - - - - - - - - diff --git a/plugins/channeltx/modnfm/nfmmodgui.ui b/plugins/channeltx/modnfm/nfmmodgui.ui index 2ebc97999..d819d29db 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.ui +++ b/plugins/channeltx/modnfm/nfmmodgui.ui @@ -694,26 +694,6 @@ - - - - - - - - - - - - - - - - - - - -