1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-06-16 05:22:54 -04:00

NFMMod: revised thread processing

This commit is contained in:
f4exb 2024-08-17 22:33:30 +02:00 committed by Edouard Griffiths
parent 290023183c
commit 2219fcd809
6 changed files with 120 additions and 54 deletions

View File

@ -57,18 +57,14 @@ const char* const NFMMod::m_channelId = "NFMMod";
NFMMod::NFMMod(DeviceAPI *deviceAPI) : NFMMod::NFMMod(DeviceAPI *deviceAPI) :
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource), ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource),
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_running(false),
m_fileSize(0), m_fileSize(0),
m_recordLength(0), m_recordLength(0),
m_sampleRate(48000) m_sampleRate(48000),
m_levelMeter(nullptr)
{ {
setObjectName(m_channelId); 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); applySettings(m_settings, true);
m_deviceAPI->addChannelSource(this); m_deviceAPI->addChannelSource(this);
@ -94,8 +90,8 @@ NFMMod::~NFMMod()
delete m_networkManager; delete m_networkManager;
m_deviceAPI->removeChannelSourceAPI(this); m_deviceAPI->removeChannelSourceAPI(this);
m_deviceAPI->removeChannelSource(this); m_deviceAPI->removeChannelSource(this);
delete m_basebandSource;
delete m_thread; stop();
} }
void NFMMod::setDeviceAPI(DeviceAPI *deviceAPI) void NFMMod::setDeviceAPI(DeviceAPI *deviceAPI)
@ -112,22 +108,62 @@ void NFMMod::setDeviceAPI(DeviceAPI *deviceAPI)
void NFMMod::start() void NFMMod::start()
{ {
if (m_running) {
return;
}
qDebug("NFMMod::start"); 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->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(); 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() void NFMMod::stop()
{ {
if (!m_running) {
return;
}
qDebug("NFMMod::stop"); qDebug("NFMMod::stop");
m_thread->exit(); m_running = false;
m_thread->quit();
m_thread->wait(); m_thread->wait();
} }
void NFMMod::pull(SampleVector::iterator& begin, unsigned int nbSamples) void NFMMod::pull(SampleVector::iterator& begin, unsigned int nbSamples)
{ {
if (m_running) {
m_basebandSource->pull(begin, nbSamples); m_basebandSource->pull(begin, nbSamples);
} }
}
void NFMMod::setCenterFrequency(qint64 frequency) void NFMMod::setCenterFrequency(qint64 frequency)
{ {
@ -236,6 +272,8 @@ bool NFMMod::handleMessage(const Message& cmd)
else if (DSPSignalNotification::match(cmd)) else if (DSPSignalNotification::match(cmd))
{ {
// Forward to the source // Forward to the source
if (m_running)
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd; DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy
qDebug() << "NFMMod::handleMessage: DSPSignalNotification"; qDebug() << "NFMMod::handleMessage: DSPSignalNotification";
@ -244,6 +282,7 @@ bool NFMMod::handleMessage(const Message& cmd)
if (getMessageQueueToGUI()) { if (getMessageQueueToGUI()) {
getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); getMessageQueueToGUI()->push(new DSPSignalNotification(notif));
} }
}
return true; return true;
} }
@ -386,8 +425,11 @@ void NFMMod::applySettings(const NFMModSettings& settings, bool force)
reverseAPIKeys.append("streamIndex"); reverseAPIKeys.append("streamIndex");
} }
if (m_running)
{
NFMModBaseband::MsgConfigureNFMModBaseband *msg = NFMModBaseband::MsgConfigureNFMModBaseband::create(settings, force); NFMModBaseband::MsgConfigureNFMModBaseband *msg = NFMModBaseband::MsgConfigureNFMModBaseband::create(settings, force);
m_basebandSource->getInputMessageQueue()->push(msg); m_basebandSource->getInputMessageQueue()->push(msg);
}
if (settings.m_useReverseAPI) if (settings.m_useReverseAPI)
{ {
@ -459,7 +501,7 @@ int NFMMod::webapiSettingsGet(
webapiFormatChannelSettings(response, m_settings); webapiFormatChannelSettings(response, m_settings);
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getNfmModSettings()->getCwKeyer(); SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getNfmModSettings()->getCwKeyer();
const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); const CWKeyerSettings& cwKeyerSettings = getCWKeyer()->getSettings();
CWKeyer::webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); CWKeyer::webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
return 200; return 200;
@ -487,11 +529,11 @@ int NFMMod::webapiSettingsPutPatch(
if (channelSettingsKeys.contains("cwKeyer")) if (channelSettingsKeys.contains("cwKeyer"))
{ {
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getNfmModSettings()->getCwKeyer(); SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getNfmModSettings()->getCwKeyer();
CWKeyerSettings cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); CWKeyerSettings cwKeyerSettings = getCWKeyer()->getSettings();
CWKeyer::webapiSettingsPutPatch(channelSettingsKeys, cwKeyerSettings, apiCwKeyerSettings); CWKeyer::webapiSettingsPutPatch(channelSettingsKeys, cwKeyerSettings, apiCwKeyerSettings);
CWKeyer::MsgConfigureCWKeyer *msgCwKeyer = CWKeyer::MsgConfigureCWKeyer::create(cwKeyerSettings, force); 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 if (m_guiMessageQueue) // forward to GUI if any
{ {
@ -691,9 +733,13 @@ void NFMMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respon
void NFMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) void NFMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
{ {
response.getNfmModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq())); response.getNfmModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq()));
if (m_running)
{
response.getNfmModReport()->setAudioSampleRate(m_basebandSource->getAudioSampleRate()); response.getNfmModReport()->setAudioSampleRate(m_basebandSource->getAudioSampleRate());
response.getNfmModReport()->setChannelSampleRate(m_basebandSource->getChannelSampleRate()); response.getNfmModReport()->setChannelSampleRate(m_basebandSource->getChannelSampleRate());
} }
}
void NFMMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const NFMModSettings& settings, bool force) void NFMMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const NFMModSettings& settings, bool force)
{ {
@ -730,7 +776,7 @@ void NFMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
swgNFModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); swgNFModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFModSettings->getCwKeyer(); 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") QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_reverseAPIAddress) .arg(m_settings.m_reverseAPIAddress)
@ -870,10 +916,10 @@ void NFMMod::webapiFormatChannelSettings(
if (force) if (force)
{ {
const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); const CWKeyerSettings& cwKeyerSettings = getCWKeyer()->getSettings();
swgNFMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); swgNFMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFMModSettings->getCwKeyer(); 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 double NFMMod::getMagSq() const
{ {
if (m_running) {
return m_basebandSource->getMagSq(); return m_basebandSource->getMagSq();
} }
CWKeyer *NFMMod::getCWKeyer() return 0;
{
return &m_basebandSource->getCWKeyer();
}
void NFMMod::setLevelMeter(QObject *levelMeter)
{
connect(m_basebandSource, SIGNAL(levelChanged(qreal, qreal, int)), levelMeter, SLOT(levelChanged(qreal, qreal, int)));
} }
uint32_t NFMMod::getNumberOfDeviceStreams() const uint32_t NFMMod::getNumberOfDeviceStreams() const
@ -920,10 +960,18 @@ uint32_t NFMMod::getNumberOfDeviceStreams() const
int NFMMod::getAudioSampleRate() const int NFMMod::getAudioSampleRate() const
{ {
if (m_running) {
return m_basebandSource->getAudioSampleRate(); return m_basebandSource->getAudioSampleRate();
} }
return 0;
}
int NFMMod::getFeedbackAudioSampleRate() const int NFMMod::getFeedbackAudioSampleRate() const
{ {
if (m_running) {
return m_basebandSource->getFeedbackAudioSampleRate(); return m_basebandSource->getFeedbackAudioSampleRate();
} }
return 0;
}

View File

@ -28,6 +28,7 @@
#include <QNetworkRequest> #include <QNetworkRequest>
#include "dsp/basebandsamplesource.h" #include "dsp/basebandsamplesource.h"
#include "dsp/cwkeyer.h"
#include "channel/channelapi.h" #include "channel/channelapi.h"
#include "util/message.h" #include "util/message.h"
@ -233,8 +234,8 @@ public:
SWGSDRangel::SWGChannelSettings& response); SWGSDRangel::SWGChannelSettings& response);
double getMagSq() const; double getMagSq() const;
CWKeyer *getCWKeyer(); CWKeyer *getCWKeyer() { return &m_cwKeyer; }
void setLevelMeter(QObject *levelMeter); void setLevelMeter(QObject *levelMeter) { m_levelMeter = levelMeter; }
uint32_t getNumberOfDeviceStreams() const; uint32_t getNumberOfDeviceStreams() const;
int getAudioSampleRate() const; int getAudioSampleRate() const;
int getFeedbackAudioSampleRate() const; int getFeedbackAudioSampleRate() const;
@ -250,6 +251,7 @@ private:
DeviceAPI* m_deviceAPI; DeviceAPI* m_deviceAPI;
QThread *m_thread; QThread *m_thread;
bool m_running;
NFMModBaseband* m_basebandSource; NFMModBaseband* m_basebandSource;
NFMModSettings m_settings; NFMModSettings m_settings;
@ -265,6 +267,9 @@ private:
QNetworkAccessManager *m_networkManager; QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest; QNetworkRequest m_networkRequest;
CWKeyer m_cwKeyer;
QObject *m_levelMeter;
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
void applySettings(const NFMModSettings& settings, bool force = false); void applySettings(const NFMModSettings& settings, bool force = false);
void sendSampleRateToDemodAnalyzer(); void sendSampleRateToDemodAnalyzer();

View File

@ -21,6 +21,7 @@
#include "dsp/upchannelizer.h" #include "dsp/upchannelizer.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "dsp/dspcommands.h" #include "dsp/dspcommands.h"
#include "dsp/cwkeyer.h"
#include "nfmmodbaseband.h" #include "nfmmodbaseband.h"
@ -170,8 +171,8 @@ bool NFMModBaseband::handleMessage(const Message& cmd)
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
const CWKeyer::MsgConfigureCWKeyer& cfg = (CWKeyer::MsgConfigureCWKeyer&) cmd; const CWKeyer::MsgConfigureCWKeyer& cfg = (CWKeyer::MsgConfigureCWKeyer&) cmd;
CWKeyer::MsgConfigureCWKeyer *notif = new CWKeyer::MsgConfigureCWKeyer(cfg); CWKeyer::MsgConfigureCWKeyer *notif = new CWKeyer::MsgConfigureCWKeyer(cfg);
CWKeyer& cwKeyer = m_source.getCWKeyer(); CWKeyer *cwKeyer = m_source.getCWKeyer();
cwKeyer.getInputMessageQueue()->push(notif); cwKeyer->getInputMessageQueue()->push(notif);
return true; return true;
} }

View File

@ -63,7 +63,7 @@ public:
void reset(); void reset();
void pull(const SampleVector::iterator& begin, unsigned int nbSamples); void pull(const SampleVector::iterator& begin, unsigned int nbSamples);
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication 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(); } double getMagSq() const { return m_source.getMagSq(); }
int getAudioSampleRate() const { return m_source.getAudioSampleRate(); } int getAudioSampleRate() const { return m_source.getAudioSampleRate(); }
int getFeedbackAudioSampleRate() const { return m_source.getFeedbackAudioSampleRate(); } int getFeedbackAudioSampleRate() const { return m_source.getFeedbackAudioSampleRate(); }

View File

@ -20,6 +20,7 @@
#include "dsp/datafifo.h" #include "dsp/datafifo.h"
#include "dsp/misc.h" #include "dsp/misc.h"
#include "dsp/cwkeyer.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "maincore.h" #include "maincore.h"
@ -39,7 +40,8 @@ NFMModSource::NFMModSource() :
m_levelCalcCount(0), m_levelCalcCount(0),
m_peakLevel(0.0f), m_peakLevel(0.0f),
m_levelSum(0.0f), m_levelSum(0.0f),
m_ifstream(nullptr) m_ifstream(nullptr),
m_cwKeyer(nullptr)
{ {
m_audioFifo.setLabel("NFMModSource.m_audioFifo"); m_audioFifo.setLabel("NFMModSource.m_audioFifo");
m_feedbackAudioFifo.setLabel("NFMModSource.m_feedbackAudioFifo"); m_feedbackAudioFifo.setLabel("NFMModSource.m_feedbackAudioFifo");
@ -276,14 +278,18 @@ void NFMModSource::pullAF(Real& sample)
case NFMModSettings::NFMModInputCWTone: case NFMModSettings::NFMModInputCWTone:
Real fadeFactor; 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; sample = m_toneNco.next() * fadeFactor;
} }
else else
{ {
if (m_cwKeyer.getCWSmoother().getFadeSample(false, fadeFactor)) if (m_cwKeyer->getCWSmoother().getFadeSample(false, fadeFactor))
{ {
sample = m_toneNco.next() * fadeFactor; sample = m_toneNco.next() * fadeFactor;
} }
@ -382,8 +388,13 @@ void NFMModSource::applyAudioSampleRate(int sampleRate)
m_toneNco.setFreq(m_settings.m_toneFrequency, sampleRate); m_toneNco.setFreq(m_settings.m_toneFrequency, sampleRate);
m_ctcssNco.setFreq(NFMModSettings::getCTCSSFreq(m_settings.m_ctcssIndex), sampleRate); m_ctcssNco.setFreq(NFMModSettings::getCTCSSFreq(m_settings.m_ctcssIndex), sampleRate);
m_dcsMod.setSampleRate(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_preemphasisFilter.configure(m_preemphasis*sampleRate);
m_audioCompressor.m_rate = sampleRate; m_audioCompressor.m_rate = sampleRate;
m_audioCompressor.initState(); m_audioCompressor.initState();

View File

@ -33,7 +33,6 @@
#include "dsp/firfilter.h" #include "dsp/firfilter.h"
#include "dsp/filterrc.h" #include "dsp/filterrc.h"
#include "util/movingaverage.h" #include "util/movingaverage.h"
#include "dsp/cwkeyer.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "audio/audiocompressorsnd.h" #include "audio/audiocompressorsnd.h"
@ -41,6 +40,7 @@
#include "nfmmoddcs.h" #include "nfmmoddcs.h"
class ChannelAPI; class ChannelAPI;
class CWKeyer;
class NFMModSource : public QObject, public ChannelSampleSource class NFMModSource : public QObject, public ChannelSampleSource
{ {
@ -61,7 +61,8 @@ public:
int getAudioSampleRate() const { return m_audioSampleRate; } int getAudioSampleRate() const { return m_audioSampleRate; }
int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; } int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; } 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; } double getMagSq() const { return m_magsq; }
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
{ {
@ -124,7 +125,7 @@ private:
Real m_levelSum; Real m_levelSum;
std::ifstream *m_ifstream; std::ifstream *m_ifstream;
CWKeyer m_cwKeyer; CWKeyer *m_cwKeyer;
AudioCompressorSnd m_audioCompressor; AudioCompressorSnd m_audioCompressor;