From 27d504e1ac5acd76646034ddd72ab2c82803ea84 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 26 Aug 2017 05:32:01 +0200 Subject: [PATCH] AM demod: implement copy audio to UDP and basic channel settings dialog --- plugins/channelrx/demodam/amdemod.cpp | 67 +++++++++++++------ plugins/channelrx/demodam/amdemod.h | 75 +++++++++++++++++++--- plugins/channelrx/demodam/amdemodgui.cpp | 71 ++++++++++++++------ plugins/channelrx/demodam/amdemodgui.h | 9 +-- plugins/channelrx/demodam/amdemodgui.ui | 24 +++++-- plugins/channelrx/demodbfm/bfmdemod.cpp | 3 +- plugins/channelrx/demodbfm/bfmdemodgui.cpp | 2 +- plugins/channelrx/demoddsd/dsddemod.cpp | 2 +- 8 files changed, 192 insertions(+), 61 deletions(-) diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 0adb68cd9..55db10363 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -18,22 +18,26 @@ #include #include + #include #include -#include + +#include "dsp/downchannelizer.h" #include "audio/audiooutput.h" #include "dsp/dspengine.h" #include "dsp/pidcontroller.h" MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message) +const int AMDemod::m_udpBlockSize = 512; + AMDemod::AMDemod() : m_squelchOpen(false), m_magsqSum(0.0f), m_magsqPeak(0.0f), m_magsqCount(0), m_movingAverage(40, 0), - m_volumeAGC(2400, 1.0), + m_volumeAGC(1200, 1.0), m_audioFifo(48000), m_settingsMutex(QMutex::Recursive) { @@ -56,16 +60,35 @@ AMDemod::AMDemod() : m_magsq = 0.0; DSPEngine::instance()->addAudioSink(&m_audioFifo); + m_udpBufferAudio = new UDPSink(this, m_udpBlockSize, m_config.m_udpPort); } AMDemod::~AMDemod() { DSPEngine::instance()->removeAudioSink(&m_audioFifo); + delete m_udpBufferAudio; } -void AMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real volume, Real squelch, bool audioMute, bool bandpassEnable) +void AMDemod::configure(MessageQueue* messageQueue, + Real rfBandwidth, + Real volume, + Real squelch, + bool audioMute, + bool bandpassEnable, + bool copyAudioToUDP, + const QString& udpAddress, + quint16 udpPort, + bool force) { - Message* cmd = MsgConfigureAMDemod::create(rfBandwidth, volume, squelch, audioMute, bandpassEnable); + Message* cmd = MsgConfigureAMDemod::create(rfBandwidth, + volume, + squelch, + audioMute, + bandpassEnable, + copyAudioToUDP, + udpAddress, + udpPort, + force); messageQueue->push(cmd); } @@ -158,15 +181,21 @@ bool AMDemod::handleMessage(const Message& cmd) m_config.m_squelch = cfg.getSquelch(); m_config.m_audioMute = cfg.getAudioMute(); m_config.m_bandpassEnable = cfg.getBandpassEnable(); + m_config.m_copyAudioToUDP = cfg.getCopyAudioToUDP(); + m_config.m_udpAddress = cfg.getUDPAddress(); + m_config.m_udpPort = cfg.getUDPPort(); - apply(); + apply(cfg.getForce()); qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:" << " m_rfBandwidth: " << m_config.m_rfBandwidth << " m_volume: " << m_config.m_volume << " m_squelch: " << m_config.m_squelch << " m_audioMute: " << m_config.m_audioMute - << " m_bandpassEnable: " << m_config.m_bandpassEnable; + << " m_bandpassEnable: " << m_config.m_bandpassEnable + << " m_copyAudioToUDP: " << m_config.m_copyAudioToUDP + << " m_udpAddress: " << m_config.m_udpAddress + << " m_udpPort: " << m_config.m_udpPort; return true; } @@ -176,11 +205,11 @@ bool AMDemod::handleMessage(const Message& cmd) } } -void AMDemod::apply() +void AMDemod::apply(bool force) { - if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || - (m_config.m_inputSampleRate != m_running.m_inputSampleRate)) + if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || + (m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force) { m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate); } @@ -188,7 +217,7 @@ void AMDemod::apply() if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || (m_config.m_audioSampleRate != m_running.m_audioSampleRate) || - (m_config.m_bandpassEnable != m_running.m_bandpassEnable)) + (m_config.m_bandpassEnable != m_running.m_bandpassEnable) || force) { m_settingsMutex.lock(); m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2f); @@ -198,18 +227,18 @@ void AMDemod::apply() m_settingsMutex.unlock(); } - if(m_config.m_squelch != m_running.m_squelch) + if ((m_config.m_squelch != m_running.m_squelch) || force) { m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0); m_squelchLevel *= m_squelchLevel; } - m_running.m_inputSampleRate = m_config.m_inputSampleRate; - m_running.m_inputFrequencyOffset = m_config.m_inputFrequencyOffset; - m_running.m_rfBandwidth = m_config.m_rfBandwidth; - m_running.m_squelch = m_config.m_squelch; - m_running.m_volume = m_config.m_volume; - m_running.m_audioSampleRate = m_config.m_audioSampleRate; - m_running.m_audioMute = m_config.m_audioMute; - m_running.m_bandpassEnable = m_config.m_bandpassEnable; + if ((m_config.m_udpAddress != m_running.m_udpAddress) + || (m_config.m_udpPort != m_running.m_udpPort) || force) + { + m_udpBufferAudio->setAddress(m_config.m_udpAddress); + m_udpBufferAudio->setPort(m_config.m_udpPort); + } + + m_running = m_config; } diff --git a/plugins/channelrx/demodam/amdemod.h b/plugins/channelrx/demodam/amdemod.h index ef4a7d80e..0d3025614 100644 --- a/plugins/channelrx/demodam/amdemod.h +++ b/plugins/channelrx/demodam/amdemod.h @@ -34,7 +34,16 @@ public: AMDemod(); ~AMDemod(); - void configure(MessageQueue* messageQueue, Real rfBandwidth, Real volume, Real squelch, bool audioMute, bool bandpassEnable); + void configure(MessageQueue* messageQueue, + Real rfBandwidth, + Real volume, + Real squelch, + bool audioMute, + bool bandpassEnable, + bool copyAudioToUDP, + const QString& udpAddress, + quint16 udpPort, + bool force); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void start(); @@ -64,10 +73,30 @@ private: Real getSquelch() const { return m_squelch; } bool getAudioMute() const { return m_audioMute; } bool getBandpassEnable() const { return m_bandpassEnable; } + bool getCopyAudioToUDP() const { return m_copyAudioToUDP; } + const QString& getUDPAddress() const { return m_udpAddress; } + quint16 getUDPPort() const { return m_udpPort; } + bool getForce() const { return m_force; } - static MsgConfigureAMDemod* create(Real rfBandwidth, Real volume, Real squelch, bool audioMute, bool bandpassEnable) + static MsgConfigureAMDemod* create(Real rfBandwidth, + Real volume, + Real squelch, + bool audioMute, + bool bandpassEnable, + bool copyAudioToUDP, + const QString& udpAddress, + quint16 udpPort, + bool force) { - return new MsgConfigureAMDemod(rfBandwidth, volume, squelch, audioMute, bandpassEnable); + return new MsgConfigureAMDemod(rfBandwidth, + volume, + squelch, + audioMute, + bandpassEnable, + copyAudioToUDP, + udpAddress, + udpPort, + force); } private: @@ -76,14 +105,30 @@ private: Real m_squelch; bool m_audioMute; bool m_bandpassEnable; + bool m_copyAudioToUDP; + QString m_udpAddress; + quint16 m_udpPort; + bool m_force; - MsgConfigureAMDemod(Real rfBandwidth, Real volume, Real squelch, bool audioMute, bool bandpassEnable) : + MsgConfigureAMDemod(Real rfBandwidth, + Real volume, + Real squelch, + bool audioMute, + bool bandpassEnable, + bool copyAudioToUDP, + const QString& udpAddress, + quint16 udpPort, + bool force) : Message(), m_rfBandwidth(rfBandwidth), m_volume(volume), m_squelch(squelch), m_audioMute(audioMute), - m_bandpassEnable(bandpassEnable) + m_bandpassEnable(bandpassEnable), + m_copyAudioToUDP(copyAudioToUDP), + m_udpAddress(udpAddress), + m_udpPort(udpPort), + m_force(force) { } }; @@ -101,6 +146,9 @@ private: quint32 m_audioSampleRate; bool m_audioMute; bool m_bandpassEnable; + bool m_copyAudioToUDP; + QString m_udpAddress; + quint16 m_udpPort; Config() : m_inputSampleRate(-1), @@ -110,7 +158,10 @@ private: m_volume(0), m_audioSampleRate(0), m_audioMute(false), - m_bandpassEnable(false) + m_bandpassEnable(false), + m_copyAudioToUDP(false), + m_udpAddress("127.0.0.1"), + m_udpPort(9999) { } }; @@ -135,12 +186,15 @@ private: Bandpass m_bandpass; AudioVector m_audioBuffer; - uint m_audioBufferFill; - + uint32_t m_audioBufferFill; AudioFifo m_audioFifo; + UDPSink *m_udpBufferAudio; + + static const int m_udpBlockSize; + QMutex m_settingsMutex; - void apply(); + void apply(bool force = false); void processOneSample(Complex &ci) { @@ -191,7 +245,7 @@ private: } Real attack = (m_squelchCount - 0.05f * m_running.m_audioSampleRate) / (0.05f * m_running.m_audioSampleRate); - sample = (0.5 - demod) * attack * 2048 * m_running.m_volume; + sample = demod * attack * 2048 * m_running.m_volume; m_squelchOpen = true; } @@ -203,6 +257,7 @@ private: m_audioBuffer[m_audioBufferFill].l = sample; m_audioBuffer[m_audioBufferFill].r = sample; + m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); ++m_audioBufferFill; if (m_audioBufferFill >= m_audioBuffer.size()) diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index e6dbd745c..0f1ff31c0 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -27,7 +27,7 @@ #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" -#include "gui/basicchannelsettingswidget.h" +#include "gui/basicchannelsettingsdialog.h" #include "dsp/dspengine.h" #include "mainwindow.h" @@ -84,11 +84,14 @@ QByteArray AMDemodGUI::serialize() const SimpleSerializer s(1); s.writeS32(1, m_channelMarker.getCenterFrequency()); s.writeS32(2, ui->rfBW->value()); - //s.writeS32(3, ui->afBW->value()); s.writeS32(4, ui->volume->value()); s.writeS32(5, ui->squelch->value()); s.writeU32(7, m_channelMarker.getColor().rgb()); s.writeBool(8, ui->bandpassEnable->isChecked()); + s.writeString(9, m_channelMarker.getTitle()); + s.writeString(10, m_channelMarker.getUDPAddress()); + s.writeU32(11, (quint32) m_channelMarker.getUDPReceivePort()); + s.writeU32(12, (quint32) m_channelMarker.getUDPSendPort()); return s.final(); } @@ -108,6 +111,7 @@ bool AMDemodGUI::deserialize(const QByteArray& data) quint32 u32tmp; qint32 tmp; bool boolTmp; + QString strtmp; blockApplySettings(true); m_channelMarker.blockSignals(true); @@ -122,19 +126,27 @@ bool AMDemodGUI::deserialize(const QByteArray& data) ui->volume->setValue(tmp); d.readS32(5, &tmp, -40); ui->squelch->setValue(tmp); - - if(d.readU32(7, &u32tmp)) - { + if(d.readU32(7, &u32tmp)) { m_channelMarker.setColor(u32tmp); } - d.readBool(8, &boolTmp, false); ui->bandpassEnable->setChecked(boolTmp); + d.readString(11, &strtmp, "AM Demodulator"); + m_channelMarker.setTitle(strtmp); + this->setWindowTitle(m_channelMarker.getTitle()); + d.readString(12, &strtmp, "127.0.0.1"); + m_channelMarker.setUDPAddress(strtmp); + d.readU32(13, &u32tmp, 9999); + m_channelMarker.setUDPReceivePort(u32tmp); + d.readU32(14, &u32tmp, 9999); + m_channelMarker.setUDPSendPort(u32tmp); + + displayUDPAddress(); blockApplySettings(false); m_channelMarker.blockSignals(false); - applySettings(); + applySettings(true); return true; } else @@ -149,8 +161,10 @@ bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused))) return false; } -void AMDemodGUI::viewChanged() +void AMDemodGUI::channelMarkerChanged() { + this->setWindowTitle(m_channelMarker.getTitle()); + displayUDPAddress(); applySettings(); } @@ -188,6 +202,11 @@ void AMDemodGUI::on_audioMute_toggled(bool checked __attribute__((unused))) applySettings(); } +void AMDemodGUI::on_copyAudioToUDP_toggled(bool checked __attribute__((unused))) +{ + applySettings(); +} + void AMDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) { /* @@ -196,13 +215,11 @@ void AMDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool ro */ } -void AMDemodGUI::onMenuDoubleClicked() +void AMDemodGUI::onMenuDialogCalled(const QPoint &p) { - if(!m_basicSettingsShown) { - m_basicSettingsShown = true; - BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(&m_channelMarker, this); - bcsw->show(); - } + BasicChannelSettingsDialog dialog(&m_channelMarker, this); + dialog.move(p); + dialog.exec(); } AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent) : @@ -211,7 +228,6 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget m_pluginAPI(pluginAPI), m_deviceAPI(deviceAPI), m_channelMarker(this), - m_basicSettingsShown(false), m_doApplySettings(true), m_squelchOpen(false), m_tickCount(0) @@ -219,7 +235,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_amDemod = new AMDemod(); m_channelizer = new DownChannelizer(m_amDemod); @@ -238,15 +254,19 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget m_channelMarker.setColor(Qt::yellow); m_channelMarker.setBandwidth(5000); m_channelMarker.setCenterFrequency(0); - m_channelMarker.setVisible(true); + m_channelMarker.setTitle("AM Demodulator"); + m_channelMarker.setUDPAddress("127.0.0.1"); + m_channelMarker.setUDPSendPort(9999); + m_channelMarker.setVisible(true); + setTitleColor(m_channelMarker.getColor()); - connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); + connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); m_deviceAPI->registerChannelInstance(m_channelID, this); m_deviceAPI->addChannelMarker(&m_channelMarker); m_deviceAPI->addRollupWidget(this); - applySettings(); + applySettings(true); } AMDemodGUI::~AMDemodGUI() @@ -265,7 +285,7 @@ void AMDemodGUI::blockApplySettings(bool block) m_doApplySettings = !block; } -void AMDemodGUI::applySettings() +void AMDemodGUI::applySettings(bool force) { if (m_doApplySettings) { @@ -282,10 +302,19 @@ void AMDemodGUI::applySettings() ui->volume->value() / 10.0, ui->squelch->value(), ui->audioMute->isChecked(), - ui->bandpassEnable->isChecked()); + ui->bandpassEnable->isChecked(), + ui->copyAudioToUDP->isChecked(), + m_channelMarker.getUDPAddress(), + m_channelMarker.getUDPSendPort(), + force); } } +void AMDemodGUI::displayUDPAddress() +{ + ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); +} + void AMDemodGUI::leaveEvent(QEvent*) { blockApplySettings(true); diff --git a/plugins/channelrx/demodam/amdemodgui.h b/plugins/channelrx/demodam/amdemodgui.h index f5f3e794a..81541b7f6 100644 --- a/plugins/channelrx/demodam/amdemodgui.h +++ b/plugins/channelrx/demodam/amdemodgui.h @@ -38,15 +38,16 @@ public: static const QString m_channelID; private slots: - void viewChanged(); + void channelMarkerChanged(); void on_deltaFrequency_changed(qint64 value); void on_bandpassEnable_toggled(bool checked); void on_rfBW_valueChanged(int value); void on_volume_valueChanged(int value); void on_squelch_valueChanged(int value); void on_audioMute_toggled(bool checked); + void on_copyAudioToUDP_toggled(bool copy); void onWidgetRolled(QWidget* widget, bool rollDown); - void onMenuDoubleClicked(); + void onMenuDialogCalled(const QPoint& p); void tick(); private: @@ -54,7 +55,6 @@ private: PluginAPI* m_pluginAPI; DeviceSourceAPI* m_deviceAPI; ChannelMarker m_channelMarker; - bool m_basicSettingsShown; bool m_doApplySettings; ThreadedBasebandSampleSink* m_threadedChannelizer; @@ -67,7 +67,8 @@ private: virtual ~AMDemodGUI(); void blockApplySettings(bool block); - void applySettings(); + void applySettings(bool force = false); + void displayUDPAddress(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodam/amdemodgui.ui b/plugins/channelrx/demodam/amdemodgui.ui index 32e54120e..bccc9f7ae 100644 --- a/plugins/channelrx/demodam/amdemodgui.ui +++ b/plugins/channelrx/demodam/amdemodgui.ui @@ -6,7 +6,7 @@ 0 0 - 302 + 352 170 @@ -18,7 +18,7 @@ - 302 + 352 0 @@ -34,18 +34,21 @@ AM Demodulator + + AM Demodulator + 0 0 - 300 + 350 131 - 300 + 350 0 @@ -183,6 +186,19 @@ + + + + Copy audio to UDP + + + U + + + true + + + diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index a19bc71df..f6dd35444 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -28,7 +28,7 @@ #include -#include "../../channelrx/demodbfm/rdsparser.h" +#include "rdsparser.h" MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message) @@ -82,6 +82,7 @@ BFMDemod::~BFMDemod() } DSPEngine::instance()->removeAudioSink(&m_audioFifo); + delete m_udpBufferAudio; } void BFMDemod::configure(MessageQueue* messageQueue, diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index 16274672c..55cd78957 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -186,7 +186,7 @@ bool BFMDemodGUI::deserialize(const QByteArray& data) d.readBool(10, &booltmp, false); ui->lsbStereo->setChecked(booltmp); - d.readString(11, &strtmp, "DSD Demodulator"); + d.readString(11, &strtmp, "Broadcast FM Demod"); m_channelMarker.setTitle(strtmp); this->setWindowTitle(m_channelMarker.getTitle()); d.readString(12, &strtmp, "127.0.0.1"); diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index 8a333fe18..d1bf7df5c 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -84,10 +84,10 @@ DSDDemod::DSDDemod(BasebandSampleSink* sampleSink) : DSDDemod::~DSDDemod() { - delete m_udpBufferAudio; delete[] m_sampleBuffer; DSPEngine::instance()->removeAudioSink(&m_audioFifo1); DSPEngine::instance()->removeAudioSink(&m_audioFifo2); + delete m_udpBufferAudio; } void DSDDemod::configure(MessageQueue* messageQueue,