diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index 67106ec72..9ae2b047a 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -57,20 +57,13 @@ const char* const SSBMod::m_channelId = "SSBMod"; SSBMod::SSBMod(DeviceAPI *deviceAPI) : ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource), m_deviceAPI(deviceAPI), + m_running(false), m_spectrumVis(SDR_TX_SCALEF), m_fileSize(0), m_recordLength(0), m_sampleRate(48000) { setObjectName(m_channelId); - - m_thread = new QThread(this); - m_basebandSource = new SSBModBaseband(); - m_basebandSource->setSpectrumSink(&m_spectrumVis); - m_basebandSource->setInputFileStream(&m_ifstream); - m_basebandSource->setChannel(this); - m_basebandSource->moveToThread(m_thread); - applySettings(m_settings, true); m_deviceAPI->addChannelSource(this); @@ -96,8 +89,8 @@ SSBMod::~SSBMod() delete m_networkManager; m_deviceAPI->removeChannelSourceAPI(this); m_deviceAPI->removeChannelSource(this); - delete m_basebandSource; - delete m_thread; + + stop(); } void SSBMod::setDeviceAPI(DeviceAPI *deviceAPI) @@ -114,21 +107,62 @@ void SSBMod::setDeviceAPI(DeviceAPI *deviceAPI) void SSBMod::start() { + if (m_running) { + return; + } + qDebug("SSBMod::start"); + m_thread = new QThread(this); + m_basebandSource = new SSBModBaseband(); + m_basebandSource->setSpectrumSink(&m_spectrumVis); + 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(); + + SSBModBaseband::MsgConfigureSSBModBaseband *msg = SSBModBaseband::MsgConfigureSSBModBaseband::create(m_settings, true); + m_basebandSource->getInputMessageQueue()->push(msg); + + if (m_levelMeter) { + connect(m_basebandSource, SIGNAL(levelChanged(qreal, qreal, int)), m_levelMeter, SLOT(levelChanged(qreal, qreal, int))); + } + + m_running = true; } void SSBMod::stop() { + if (!m_running) { + return; + } + qDebug("SSBMod::stop"); + m_running = false; m_thread->exit(); m_thread->wait(); } void SSBMod::pull(SampleVector::iterator& begin, unsigned int nbSamples) { - m_basebandSource->pull(begin, nbSamples); + if (m_running) { + m_basebandSource->pull(begin, nbSamples); + } } void SSBMod::setCenterFrequency(qint64 frequency) @@ -201,11 +235,14 @@ bool SSBMod::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() << "SSBMod::handleMessage: DSPSignalNotification"; - m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to the source + if (m_running) + { + DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy + qDebug() << "SSBMod::handleMessage: DSPSignalNotification"; + m_basebandSource->getInputMessageQueue()->push(rep); + } // Forward to GUI if any if (getMessageQueueToGUI()) { getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); @@ -360,8 +397,11 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force) m_spectrumVis.getInputMessageQueue()->push(msg); } - SSBModBaseband::MsgConfigureSSBModBaseband *msg = SSBModBaseband::MsgConfigureSSBModBaseband::create(settings, force); - m_basebandSource->getInputMessageQueue()->push(msg); + if (m_running) + { + SSBModBaseband::MsgConfigureSSBModBaseband *msg = SSBModBaseband::MsgConfigureSSBModBaseband::create(settings, force); + m_basebandSource->getInputMessageQueue()->push(msg); + } if (settings.m_useReverseAPI) { @@ -437,7 +477,7 @@ int SSBMod::webapiSettingsGet( webapiFormatChannelSettings(response, m_settings); SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getSsbModSettings()->getCwKeyer(); - const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); + const CWKeyerSettings& cwKeyerSettings = m_cwKeyer.getSettings(); CWKeyer::webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); return 200; @@ -465,11 +505,11 @@ int SSBMod::webapiSettingsPutPatch( if (channelSettingsKeys.contains("cwKeyer")) { SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getSsbModSettings()->getCwKeyer(); - CWKeyerSettings cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); + CWKeyerSettings cwKeyerSettings = m_cwKeyer.getSettings(); CWKeyer::webapiSettingsPutPatch(channelSettingsKeys, cwKeyerSettings, apiCwKeyerSettings); CWKeyer::MsgConfigureCWKeyer *msgCwKeyer = CWKeyer::MsgConfigureCWKeyer::create(cwKeyerSettings, force); - m_basebandSource->getCWKeyer().getInputMessageQueue()->push(msgCwKeyer); + m_cwKeyer.getInputMessageQueue()->push(msgCwKeyer); if (m_guiMessageQueue) // forward to GUI if any { @@ -689,8 +729,12 @@ void SSBMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respon void SSBMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) { response.getSsbModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq())); - response.getSsbModReport()->setAudioSampleRate(m_basebandSource->getAudioSampleRate()); - response.getSsbModReport()->setChannelSampleRate(m_basebandSource->getChannelSampleRate()); + + if (m_running) + { + response.getSsbModReport()->setAudioSampleRate(m_basebandSource->getAudioSampleRate()); + response.getSsbModReport()->setChannelSampleRate(m_basebandSource->getChannelSampleRate()); + } } void SSBMod::webapiReverseSendSettings(QList& channelSettingsKeys, const SSBModSettings& settings, bool force) @@ -728,7 +772,7 @@ void SSBMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) swgSSBModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + m_cwKeyer.webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(m_settings.m_reverseAPIAddress) @@ -875,10 +919,10 @@ void SSBMod::webapiFormatChannelSettings( if (force) { - const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); + const CWKeyerSettings& cwKeyerSettings = m_cwKeyer.getSettings(); swgSSBModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + m_cwKeyer.webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); } } @@ -905,27 +949,34 @@ void SSBMod::networkManagerFinished(QNetworkReply *reply) double SSBMod::getMagSq() const { - return m_basebandSource->getMagSq(); + if (m_running) { + return m_basebandSource->getMagSq(); + } + + return 0; } CWKeyer *SSBMod::getCWKeyer() { - return &m_basebandSource->getCWKeyer(); -} - -void SSBMod::setLevelMeter(QObject *levelMeter) -{ - connect(m_basebandSource, SIGNAL(levelChanged(qreal, qreal, int)), levelMeter, SLOT(levelChanged(qreal, qreal, int))); + return &m_cwKeyer; } int SSBMod::getAudioSampleRate() const { - return m_basebandSource->getAudioSampleRate(); + if (m_running) { + return m_basebandSource->getAudioSampleRate(); + } + + return 0; } int SSBMod::getFeedbackAudioSampleRate() const { - return m_basebandSource->getFeedbackAudioSampleRate(); + if (m_running) { + return m_basebandSource->getFeedbackAudioSampleRate(); + } + + return 0; } uint32_t SSBMod::getNumberOfDeviceStreams() const diff --git a/plugins/channeltx/modssb/ssbmod.h b/plugins/channeltx/modssb/ssbmod.h index 549221c14..166086428 100644 --- a/plugins/channeltx/modssb/ssbmod.h +++ b/plugins/channeltx/modssb/ssbmod.h @@ -29,6 +29,7 @@ #include "dsp/basebandsamplesource.h" #include "dsp/spectrumvis.h" +#include "dsp/cwkeyer.h" #include "channel/channelapi.h" #include "util/message.h" @@ -236,7 +237,7 @@ public: SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } double getMagSq() const; CWKeyer *getCWKeyer(); - void setLevelMeter(QObject *levelMeter); + void setLevelMeter(QObject *levelMeter) { m_levelMeter = levelMeter; } int getAudioSampleRate() const; int getFeedbackAudioSampleRate() const; uint32_t getNumberOfDeviceStreams() const; @@ -252,6 +253,7 @@ private: DeviceAPI* m_deviceAPI; QThread *m_thread; + bool m_running; SSBModBaseband* m_basebandSource; SSBModSettings m_settings; SpectrumVis m_spectrumVis; @@ -267,6 +269,8 @@ private: QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; + CWKeyer m_cwKeyer; + QObject *m_levelMeter; virtual bool handleMessage(const Message& cmd); void applySettings(const SSBModSettings& settings, bool force = false); diff --git a/plugins/channeltx/modssb/ssbmodbaseband.cpp b/plugins/channeltx/modssb/ssbmodbaseband.cpp index d45b49699..c58d7f926 100644 --- a/plugins/channeltx/modssb/ssbmodbaseband.cpp +++ b/plugins/channeltx/modssb/ssbmodbaseband.cpp @@ -171,8 +171,8 @@ bool SSBModBaseband::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/modssb/ssbmodbaseband.h b/plugins/channeltx/modssb/ssbmodbaseband.h index 57db8e3b5..96688f2a5 100644 --- a/plugins/channeltx/modssb/ssbmodbaseband.h +++ b/plugins/channeltx/modssb/ssbmodbaseband.h @@ -65,7 +65,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/modssb/ssbmodsource.cpp b/plugins/channeltx/modssb/ssbmodsource.cpp index 6310ca9a0..b829b3701 100644 --- a/plugins/channeltx/modssb/ssbmodsource.cpp +++ b/plugins/channeltx/modssb/ssbmodsource.cpp @@ -39,7 +39,8 @@ SSBModSource::SSBModSource() : m_levelCalcCount(0), m_peakLevel(0.0f), m_levelSum(0.0f), - m_ifstream(nullptr) + m_ifstream(nullptr), + m_cwKeyer(nullptr) { m_audioFifo.setLabel("SSBModSource.m_audioFifo"); m_feedbackAudioFifo.setLabel("SSBModSource.m_feedbackAudioFifo"); @@ -69,9 +70,6 @@ SSBModSource::SSBModSource() : m_magsq = 0.0; m_toneNco.setFreq(1000.0, m_audioSampleRate); - m_cwKeyer.setSampleRate(m_audioSampleRate); - m_cwKeyer.reset(); - m_audioCompressor.initSimple( m_audioSampleRate, m_settings.m_cmpPreGainDB, // pregain (dB) @@ -354,11 +352,15 @@ void SSBModSource::pullAF(Complex& sample) break; case SSBModSettings::SSBModInputCWTone: + if (!m_cwKeyer) { + break; + } + Real fadeFactor; - if (m_cwKeyer.getSample()) + if (m_cwKeyer->getSample()) { - m_cwKeyer.getCWSmoother().getFadeSample(true, fadeFactor); + m_cwKeyer->getCWSmoother().getFadeSample(true, fadeFactor); if (m_settings.m_dsb) { @@ -377,7 +379,7 @@ void SSBModSource::pullAF(Complex& sample) } else { - if (m_cwKeyer.getCWSmoother().getFadeSample(false, fadeFactor)) + if (m_cwKeyer->getCWSmoother().getFadeSample(false, fadeFactor)) { if (m_settings.m_dsb) { @@ -623,8 +625,12 @@ void SSBModSource::applyAudioSampleRate(int sampleRate) m_settings.m_usb = usb; m_toneNco.setFreq(m_settings.m_toneFrequency, sampleRate); - m_cwKeyer.setSampleRate(sampleRate); - m_cwKeyer.reset(); + + if (m_cwKeyer) + { + m_cwKeyer->setSampleRate(sampleRate); + m_cwKeyer->reset(); + } m_audioCompressor.m_rate = sampleRate; m_audioCompressor.initState(); diff --git a/plugins/channeltx/modssb/ssbmodsource.h b/plugins/channeltx/modssb/ssbmodsource.h index 164ca1225..1eb4cb348 100644 --- a/plugins/channeltx/modssb/ssbmodsource.h +++ b/plugins/channeltx/modssb/ssbmodsource.h @@ -39,6 +39,7 @@ class ChannelAPI; class SpectrumVis; +class CWKeyer; class SSBModSource : public QObject, public ChannelSampleSource { @@ -59,7 +60,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; } + CWKeyer* getCWKeyer() { return m_cwKeyer; } + void setCWKeyer(CWKeyer *cwKeyer) { m_cwKeyer = cwKeyer; } double getMagSq() const { return m_magsq; } void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const { @@ -131,7 +133,7 @@ private: Real m_levelSum; std::ifstream *m_ifstream; - CWKeyer m_cwKeyer; + CWKeyer *m_cwKeyer; AudioCompressorSnd m_audioCompressor; int m_agcStepLength;