From 2219fcd8097c6905e91760ef6bf9f7500e2b786f Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 17 Aug 2024 22:33:30 +0200 Subject: [PATCH] NFMMod: revised thread processing --- plugins/channeltx/modnfm/nfmmod.cpp | 128 ++++++++++++++------ plugins/channeltx/modnfm/nfmmod.h | 9 +- plugins/channeltx/modnfm/nfmmodbaseband.cpp | 5 +- plugins/channeltx/modnfm/nfmmodbaseband.h | 2 +- plugins/channeltx/modnfm/nfmmodsource.cpp | 23 +++- plugins/channeltx/modnfm/nfmmodsource.h | 7 +- 6 files changed, 120 insertions(+), 54 deletions(-) diff --git a/plugins/channeltx/modnfm/nfmmod.cpp b/plugins/channeltx/modnfm/nfmmod.cpp index 78940acd3..dc4b0d549 100644 --- a/plugins/channeltx/modnfm/nfmmod.cpp +++ b/plugins/channeltx/modnfm/nfmmod.cpp @@ -57,18 +57,14 @@ const char* const NFMMod::m_channelId = "NFMMod"; NFMMod::NFMMod(DeviceAPI *deviceAPI) : ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource), m_deviceAPI(deviceAPI), + m_running(false), m_fileSize(0), m_recordLength(0), - m_sampleRate(48000) + m_sampleRate(48000), + m_levelMeter(nullptr) { setObjectName(m_channelId); - m_thread = new QThread(this); - m_basebandSource = new NFMModBaseband(); - m_basebandSource->setInputFileStream(&m_ifstream); - m_basebandSource->setChannel(this); - m_basebandSource->moveToThread(m_thread); - applySettings(m_settings, true); m_deviceAPI->addChannelSource(this); @@ -94,8 +90,8 @@ NFMMod::~NFMMod() delete m_networkManager; m_deviceAPI->removeChannelSourceAPI(this); m_deviceAPI->removeChannelSource(this); - delete m_basebandSource; - delete m_thread; + + stop(); } void NFMMod::setDeviceAPI(DeviceAPI *deviceAPI) @@ -112,21 +108,61 @@ void NFMMod::setDeviceAPI(DeviceAPI *deviceAPI) void NFMMod::start() { + if (m_running) { + return; + } + qDebug("NFMMod::start"); + m_thread = new QThread(this); + m_basebandSource = new NFMModBaseband(); + m_basebandSource->setInputFileStream(&m_ifstream); + m_basebandSource->setChannel(this); m_basebandSource->reset(); + m_basebandSource->setCWKeyer(&m_cwKeyer); + m_basebandSource->moveToThread(m_thread); + + QObject::connect( + m_thread, + &QThread::finished, + m_basebandSource, + &QObject::deleteLater + ); + QObject::connect( + m_thread, + &QThread::finished, + m_thread, + &QThread::deleteLater + ); + m_thread->start(); + + if (m_levelMeter) { + connect(m_basebandSource, SIGNAL(levelChanged(qreal, qreal, int)), m_levelMeter, SLOT(levelChanged(qreal, qreal, int))); + } + + NFMModBaseband::MsgConfigureNFMModBaseband *msg = NFMModBaseband::MsgConfigureNFMModBaseband::create(m_settings, true); + m_basebandSource->getInputMessageQueue()->push(msg); + + m_running = true; } void NFMMod::stop() { + if (!m_running) { + return; + } + qDebug("NFMMod::stop"); - m_thread->exit(); + m_running = false; + m_thread->quit(); m_thread->wait(); } void NFMMod::pull(SampleVector::iterator& begin, unsigned int nbSamples) { - m_basebandSource->pull(begin, nbSamples); + if (m_running) { + m_basebandSource->pull(begin, nbSamples); + } } void NFMMod::setCenterFrequency(qint64 frequency) @@ -236,13 +272,16 @@ bool NFMMod::handleMessage(const Message& cmd) else if (DSPSignalNotification::match(cmd)) { // Forward to the source - DSPSignalNotification& notif = (DSPSignalNotification&) cmd; - DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy - qDebug() << "NFMMod::handleMessage: DSPSignalNotification"; - m_basebandSource->getInputMessageQueue()->push(rep); - // Forward to GUI if any - if (getMessageQueueToGUI()) { - getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + if (m_running) + { + DSPSignalNotification& notif = (DSPSignalNotification&) cmd; + DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy + qDebug() << "NFMMod::handleMessage: DSPSignalNotification"; + m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } } return true; @@ -386,8 +425,11 @@ void NFMMod::applySettings(const NFMModSettings& settings, bool force) reverseAPIKeys.append("streamIndex"); } - NFMModBaseband::MsgConfigureNFMModBaseband *msg = NFMModBaseband::MsgConfigureNFMModBaseband::create(settings, force); - m_basebandSource->getInputMessageQueue()->push(msg); + if (m_running) + { + NFMModBaseband::MsgConfigureNFMModBaseband *msg = NFMModBaseband::MsgConfigureNFMModBaseband::create(settings, force); + m_basebandSource->getInputMessageQueue()->push(msg); + } if (settings.m_useReverseAPI) { @@ -459,7 +501,7 @@ int NFMMod::webapiSettingsGet( webapiFormatChannelSettings(response, m_settings); SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getNfmModSettings()->getCwKeyer(); - const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); + const CWKeyerSettings& cwKeyerSettings = getCWKeyer()->getSettings(); CWKeyer::webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); return 200; @@ -487,11 +529,11 @@ int NFMMod::webapiSettingsPutPatch( if (channelSettingsKeys.contains("cwKeyer")) { SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getNfmModSettings()->getCwKeyer(); - CWKeyerSettings cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); + CWKeyerSettings cwKeyerSettings = getCWKeyer()->getSettings(); CWKeyer::webapiSettingsPutPatch(channelSettingsKeys, cwKeyerSettings, apiCwKeyerSettings); CWKeyer::MsgConfigureCWKeyer *msgCwKeyer = CWKeyer::MsgConfigureCWKeyer::create(cwKeyerSettings, force); - m_basebandSource->getCWKeyer().getInputMessageQueue()->push(msgCwKeyer); + getCWKeyer()->getInputMessageQueue()->push(msgCwKeyer); if (m_guiMessageQueue) // forward to GUI if any { @@ -691,8 +733,12 @@ void NFMMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respon void NFMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) { response.getNfmModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq())); - response.getNfmModReport()->setAudioSampleRate(m_basebandSource->getAudioSampleRate()); - response.getNfmModReport()->setChannelSampleRate(m_basebandSource->getChannelSampleRate()); + + if (m_running) + { + response.getNfmModReport()->setAudioSampleRate(m_basebandSource->getAudioSampleRate()); + response.getNfmModReport()->setChannelSampleRate(m_basebandSource->getChannelSampleRate()); + } } void NFMMod::webapiReverseSendSettings(QList& channelSettingsKeys, const NFMModSettings& settings, bool force) @@ -730,7 +776,7 @@ void NFMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) swgNFModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + getCWKeyer()->webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(m_settings.m_reverseAPIAddress) @@ -870,10 +916,10 @@ void NFMMod::webapiFormatChannelSettings( if (force) { - const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); + const CWKeyerSettings& cwKeyerSettings = getCWKeyer()->getSettings(); swgNFMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFMModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + getCWKeyer()->webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); } } @@ -900,17 +946,11 @@ void NFMMod::networkManagerFinished(QNetworkReply *reply) double NFMMod::getMagSq() const { - return m_basebandSource->getMagSq(); -} + if (m_running) { + return m_basebandSource->getMagSq(); + } -CWKeyer *NFMMod::getCWKeyer() -{ - return &m_basebandSource->getCWKeyer(); -} - -void NFMMod::setLevelMeter(QObject *levelMeter) -{ - connect(m_basebandSource, SIGNAL(levelChanged(qreal, qreal, int)), levelMeter, SLOT(levelChanged(qreal, qreal, int))); + return 0; } uint32_t NFMMod::getNumberOfDeviceStreams() const @@ -920,10 +960,18 @@ uint32_t NFMMod::getNumberOfDeviceStreams() const int NFMMod::getAudioSampleRate() const { - return m_basebandSource->getAudioSampleRate(); + if (m_running) { + return m_basebandSource->getAudioSampleRate(); + } + + return 0; } int NFMMod::getFeedbackAudioSampleRate() const { - return m_basebandSource->getFeedbackAudioSampleRate(); + if (m_running) { + return m_basebandSource->getFeedbackAudioSampleRate(); + } + + return 0; } diff --git a/plugins/channeltx/modnfm/nfmmod.h b/plugins/channeltx/modnfm/nfmmod.h index 36478dbac..de0ad0c8b 100644 --- a/plugins/channeltx/modnfm/nfmmod.h +++ b/plugins/channeltx/modnfm/nfmmod.h @@ -28,6 +28,7 @@ #include #include "dsp/basebandsamplesource.h" +#include "dsp/cwkeyer.h" #include "channel/channelapi.h" #include "util/message.h" @@ -233,8 +234,8 @@ public: SWGSDRangel::SWGChannelSettings& response); double getMagSq() const; - CWKeyer *getCWKeyer(); - void setLevelMeter(QObject *levelMeter); + CWKeyer *getCWKeyer() { return &m_cwKeyer; } + void setLevelMeter(QObject *levelMeter) { m_levelMeter = levelMeter; } uint32_t getNumberOfDeviceStreams() const; int getAudioSampleRate() const; int getFeedbackAudioSampleRate() const; @@ -250,6 +251,7 @@ private: DeviceAPI* m_deviceAPI; QThread *m_thread; + bool m_running; NFMModBaseband* m_basebandSource; NFMModSettings m_settings; @@ -265,6 +267,9 @@ private: QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; + CWKeyer m_cwKeyer; + QObject *m_levelMeter; + virtual bool handleMessage(const Message& cmd); void applySettings(const NFMModSettings& settings, bool force = false); void sendSampleRateToDemodAnalyzer(); diff --git a/plugins/channeltx/modnfm/nfmmodbaseband.cpp b/plugins/channeltx/modnfm/nfmmodbaseband.cpp index 8bfbc0833..ca7d35def 100644 --- a/plugins/channeltx/modnfm/nfmmodbaseband.cpp +++ b/plugins/channeltx/modnfm/nfmmodbaseband.cpp @@ -21,6 +21,7 @@ #include "dsp/upchannelizer.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" +#include "dsp/cwkeyer.h" #include "nfmmodbaseband.h" @@ -170,8 +171,8 @@ bool NFMModBaseband::handleMessage(const Message& cmd) QMutexLocker mutexLocker(&m_mutex); const CWKeyer::MsgConfigureCWKeyer& cfg = (CWKeyer::MsgConfigureCWKeyer&) cmd; CWKeyer::MsgConfigureCWKeyer *notif = new CWKeyer::MsgConfigureCWKeyer(cfg); - CWKeyer& cwKeyer = m_source.getCWKeyer(); - cwKeyer.getInputMessageQueue()->push(notif); + CWKeyer *cwKeyer = m_source.getCWKeyer(); + cwKeyer->getInputMessageQueue()->push(notif); return true; } diff --git a/plugins/channeltx/modnfm/nfmmodbaseband.h b/plugins/channeltx/modnfm/nfmmodbaseband.h index d37973d42..69a1480c4 100644 --- a/plugins/channeltx/modnfm/nfmmodbaseband.h +++ b/plugins/channeltx/modnfm/nfmmodbaseband.h @@ -63,7 +63,7 @@ public: void reset(); void pull(const SampleVector::iterator& begin, unsigned int nbSamples); MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication - CWKeyer& getCWKeyer() { return m_source.getCWKeyer(); } + void setCWKeyer(CWKeyer *cwKeyer) { m_source.setCWKeyer(cwKeyer); } double getMagSq() const { return m_source.getMagSq(); } int getAudioSampleRate() const { return m_source.getAudioSampleRate(); } int getFeedbackAudioSampleRate() const { return m_source.getFeedbackAudioSampleRate(); } diff --git a/plugins/channeltx/modnfm/nfmmodsource.cpp b/plugins/channeltx/modnfm/nfmmodsource.cpp index 5db3b2f52..39d758f1b 100644 --- a/plugins/channeltx/modnfm/nfmmodsource.cpp +++ b/plugins/channeltx/modnfm/nfmmodsource.cpp @@ -20,6 +20,7 @@ #include "dsp/datafifo.h" #include "dsp/misc.h" +#include "dsp/cwkeyer.h" #include "util/messagequeue.h" #include "maincore.h" @@ -39,7 +40,8 @@ NFMModSource::NFMModSource() : m_levelCalcCount(0), m_peakLevel(0.0f), m_levelSum(0.0f), - m_ifstream(nullptr) + m_ifstream(nullptr), + m_cwKeyer(nullptr) { m_audioFifo.setLabel("NFMModSource.m_audioFifo"); m_feedbackAudioFifo.setLabel("NFMModSource.m_feedbackAudioFifo"); @@ -276,14 +278,18 @@ void NFMModSource::pullAF(Real& sample) case NFMModSettings::NFMModInputCWTone: Real fadeFactor; - if (m_cwKeyer.getSample()) + if (!m_cwKeyer) { + break; + } + + if (m_cwKeyer->getSample()) { - m_cwKeyer.getCWSmoother().getFadeSample(true, fadeFactor); + m_cwKeyer->getCWSmoother().getFadeSample(true, fadeFactor); sample = m_toneNco.next() * fadeFactor; } else { - if (m_cwKeyer.getCWSmoother().getFadeSample(false, fadeFactor)) + if (m_cwKeyer->getCWSmoother().getFadeSample(false, fadeFactor)) { sample = m_toneNco.next() * fadeFactor; } @@ -382,8 +388,13 @@ void NFMModSource::applyAudioSampleRate(int sampleRate) m_toneNco.setFreq(m_settings.m_toneFrequency, sampleRate); m_ctcssNco.setFreq(NFMModSettings::getCTCSSFreq(m_settings.m_ctcssIndex), sampleRate); m_dcsMod.setSampleRate(sampleRate); - m_cwKeyer.setSampleRate(sampleRate); - m_cwKeyer.reset(); + + if (m_cwKeyer) + { + m_cwKeyer->setSampleRate(sampleRate); + m_cwKeyer->reset(); + } + m_preemphasisFilter.configure(m_preemphasis*sampleRate); m_audioCompressor.m_rate = sampleRate; m_audioCompressor.initState(); diff --git a/plugins/channeltx/modnfm/nfmmodsource.h b/plugins/channeltx/modnfm/nfmmodsource.h index ac15b5639..9a6d31ed9 100644 --- a/plugins/channeltx/modnfm/nfmmodsource.h +++ b/plugins/channeltx/modnfm/nfmmodsource.h @@ -33,7 +33,6 @@ #include "dsp/firfilter.h" #include "dsp/filterrc.h" #include "util/movingaverage.h" -#include "dsp/cwkeyer.h" #include "audio/audiofifo.h" #include "audio/audiocompressorsnd.h" @@ -41,6 +40,7 @@ #include "nfmmoddcs.h" class ChannelAPI; +class CWKeyer; class NFMModSource : public QObject, public ChannelSampleSource { @@ -61,7 +61,8 @@ public: int getAudioSampleRate() const { return m_audioSampleRate; } int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; } void setChannel(ChannelAPI *channel) { m_channel = channel; } - CWKeyer& getCWKeyer() { return m_cwKeyer; } + void setCWKeyer(CWKeyer *cwKeyer) { m_cwKeyer = cwKeyer; } + CWKeyer *getCWKeyer() { return m_cwKeyer; } double getMagSq() const { return m_magsq; } void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const { @@ -124,7 +125,7 @@ private: Real m_levelSum; std::ifstream *m_ifstream; - CWKeyer m_cwKeyer; + CWKeyer *m_cwKeyer; AudioCompressorSnd m_audioCompressor;