diff --git a/plugins/channelrx/localsink/localsink.cpp b/plugins/channelrx/localsink/localsink.cpp index f5978e751..4953c9ace 100644 --- a/plugins/channelrx/localsink/localsink.cpp +++ b/plugins/channelrx/localsink/localsink.cpp @@ -60,7 +60,7 @@ LocalSink::LocalSink(DeviceAPI *deviceAPI) : m_basebandSampleRate(48000) { setObjectName(m_channelId); - applySettings(m_settings, true); + applySettings(m_settings, QList(), true); m_deviceAPI->addChannelSink(this); m_deviceAPI->addChannelSinkAPI(this); @@ -162,7 +162,7 @@ void LocalSink::startProcessing() LocalSinkBaseband::MsgConfigureLocalDeviceSampleSource::create(deviceSource); m_basebandSink->getInputMessageQueue()->push(msgDevice); - LocalSinkBaseband::MsgConfigureLocalSinkBaseband *msgConfig = LocalSinkBaseband::MsgConfigureLocalSinkBaseband::create(m_settings, true); + LocalSinkBaseband::MsgConfigureLocalSinkBaseband *msgConfig = LocalSinkBaseband::MsgConfigureLocalSinkBaseband::create(m_settings, QList(), true); m_basebandSink->getInputMessageQueue()->push(msgConfig); LocalSinkBaseband::MsgSetSpectrumSampleRateAndFrequency *msgSpectrum = LocalSinkBaseband::MsgSetSpectrumSampleRateAndFrequency::create( @@ -224,7 +224,7 @@ bool LocalSink::handleMessage(const Message& cmd) { MsgConfigureLocalSink& cfg = (MsgConfigureLocalSink&) cmd; qDebug() << "LocalSink::handleMessage: MsgConfigureLocalSink"; - applySettings(cfg.getSettings(), cfg.getForce()); + applySettings(cfg.getSettings(), cfg.getSettingsKeys(), cfg.getForce()); return true; } @@ -244,14 +244,14 @@ bool LocalSink::deserialize(const QByteArray& data) (void) data; if (m_settings.deserialize(data)) { - MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, true); + MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, QList(), true); m_inputMessageQueue.push(msg); return true; } else { m_settings.resetToDefaults(); - MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, true); + MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, QList(), true); m_inputMessageQueue.push(msg); return false; } @@ -314,28 +314,12 @@ void LocalSink::propagateSampleRateAndFrequency(int index, uint32_t log2Decim) } } -void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) +void LocalSink::applySettings(const LocalSinkSettings& settings, const QList& settingsKeys, bool force) { - qDebug() << "LocalSink::applySettings:" - << "m_localDeviceIndex: " << settings.m_localDeviceIndex - << "m_streamIndex: " << settings.m_streamIndex - << "m_play:" << settings.m_play - << "m_dsp:" << settings.m_dsp - << "m_gaindB:" << settings.m_gaindB - << "force: " << force; + qDebug() << "LocalSink::applySettings:" << settings.getDebugString(settingsKeys, force) << "force: " << force; - QList reverseAPIKeys; - - if ((settings.m_log2Decim != m_settings.m_log2Decim) || force) { - reverseAPIKeys.append("log2Decim"); - } - if ((settings.m_filterChainHash != m_settings.m_filterChainHash) || force) { - reverseAPIKeys.append("filterChainHash"); - } - - if ((settings.m_localDeviceIndex != m_settings.m_localDeviceIndex) || force) + if (settingsKeys.contains("localDeviceIndex") || force) { - reverseAPIKeys.append("localDeviceIndex"); propagateSampleRateAndFrequency(settings.m_localDeviceIndex, settings.m_log2Decim); if (m_running) @@ -347,8 +331,8 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) } } - if ((settings.m_log2Decim != m_settings.m_log2Decim) - || (settings.m_filterChainHash != m_settings.m_filterChainHash) || force) + if (settingsKeys.contains("log2Decim") + || settingsKeys.contains("filterChainHash") || force) { calculateFrequencyOffset(settings.m_log2Decim, settings.m_filterChainHash); propagateSampleRateAndFrequency(m_settings.m_localDeviceIndex, settings.m_log2Decim); @@ -364,10 +348,8 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) } } - if ((settings.m_play != m_settings.m_play) || force) + if (settingsKeys.contains("play") || force) { - reverseAPIKeys.append("play"); - if (settings.m_play) { startProcessing(); } else { @@ -375,7 +357,7 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) } } - if (m_settings.m_streamIndex != settings.m_streamIndex) + if (settingsKeys.contains("streamIndex")) { if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only { @@ -384,31 +366,29 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) m_deviceAPI->addChannelSink(this, settings.m_streamIndex); m_deviceAPI->addChannelSinkAPI(this); } - - reverseAPIKeys.append("streamIndex"); } if (m_running) { - LocalSinkBaseband::MsgConfigureLocalSinkBaseband *msg = LocalSinkBaseband::MsgConfigureLocalSinkBaseband::create(settings, force); + LocalSinkBaseband::MsgConfigureLocalSinkBaseband *msg = LocalSinkBaseband::MsgConfigureLocalSinkBaseband::create(settings, settingsKeys, force); m_basebandSink->getInputMessageQueue()->push(msg); } - if ((settings.m_useReverseAPI) && (reverseAPIKeys.size() != 0)) + if (settingsKeys.contains("useReverseAPI")) { - bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || - (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) || - (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) || - (m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex) || - (m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex); - webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + bool fullUpdate = (settingsKeys.contains("useReverseAPI") && settings.m_useReverseAPI) || + settingsKeys.contains("reverseAPIAddress") || + settingsKeys.contains("reverseAPIPort") || + settingsKeys.contains("reverseAPIFeatureSetIndex") || + settingsKeys.contains("m_reverseAPIFeatureIndex"); + webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force); } QList pipes; MainCore::instance()->getMessagePipes().getMessagePipes(this, "settings", pipes); if (pipes.size() > 0) { - sendChannelSettings(pipes, reverseAPIKeys, settings, force); + sendChannelSettings(pipes, settingsKeys, settings, force); } m_settings = settings; @@ -461,13 +441,13 @@ int LocalSink::webapiSettingsPutPatch( LocalSinkSettings settings = m_settings; webapiUpdateChannelSettings(settings, channelSettingsKeys, response); - MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(settings, force); + MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(settings, channelSettingsKeys, force); m_inputMessageQueue.push(msg); qDebug("LocalSink::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); if (m_guiMessageQueue) // forward to GUI if any { - MsgConfigureLocalSink *msgToGUI = MsgConfigureLocalSink::create(settings, force); + MsgConfigureLocalSink *msgToGUI = MsgConfigureLocalSink::create(settings, channelSettingsKeys, force); m_guiMessageQueue->push(msgToGUI); } @@ -585,7 +565,7 @@ void LocalSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res } } -void LocalSink::webapiReverseSendSettings(QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force) +void LocalSink::webapiReverseSendSettings(const QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); @@ -612,7 +592,7 @@ void LocalSink::webapiReverseSendSettings(QList& channelSettingsKeys, c void LocalSink::sendChannelSettings( const QList& pipes, - QList& channelSettingsKeys, + const QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force) { @@ -636,7 +616,7 @@ void LocalSink::sendChannelSettings( } void LocalSink::webapiFormatChannelSettings( - QList& channelSettingsKeys, + const QList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings *swgChannelSettings, const LocalSinkSettings& settings, bool force @@ -777,11 +757,11 @@ void LocalSink::updateDeviceSetList() } qDebug("LocalSink::updateDeviceSetLists: new device index: %d device: %d", newIndexInList, settings.m_localDeviceIndex); - applySettings(settings); + applySettings(settings, QList{"localDeviceIndex"}); if (m_guiMessageQueue) { - MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, false); + MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, QList{"localDeviceIndex"}, false); m_guiMessageQueue->push(msg); } } diff --git a/plugins/channelrx/localsink/localsink.h b/plugins/channelrx/localsink/localsink.h index d59d04e54..69306133c 100644 --- a/plugins/channelrx/localsink/localsink.h +++ b/plugins/channelrx/localsink/localsink.h @@ -44,19 +44,22 @@ public: public: const LocalSinkSettings& getSettings() const { return m_settings; } + const QList& getSettingsKeys() const { return m_settingsKeys; } bool getForce() const { return m_force; } - static MsgConfigureLocalSink* create(const LocalSinkSettings& settings, bool force) { - return new MsgConfigureLocalSink(settings, force); + static MsgConfigureLocalSink* create(const LocalSinkSettings& settings, const QList& settingsKeys, bool force) { + return new MsgConfigureLocalSink(settings, settingsKeys, force); } private: LocalSinkSettings m_settings; + QList m_settingsKeys; bool m_force; - MsgConfigureLocalSink(const LocalSinkSettings& settings, bool force) : + MsgConfigureLocalSink(const LocalSinkSettings& settings, const QList& settingsKeys, bool force) : Message(), m_settings(settings), + m_settingsKeys(settingsKeys), m_force(force) { } }; @@ -158,7 +161,7 @@ private: QNetworkRequest m_networkRequest; virtual bool handleMessage(const Message& cmd); - void applySettings(const LocalSinkSettings& settings, bool force = false); + void applySettings(const LocalSinkSettings& settings, const QList& settingsKeys, bool force = false); void propagateSampleRateAndFrequency(int index, uint32_t log2Decim); static void validateFilterChainHash(LocalSinkSettings& settings); void calculateFrequencyOffset(uint32_t log2Decim, uint32_t filterChainHash); @@ -167,15 +170,15 @@ private: void startProcessing(); void stopProcessing(); - void webapiReverseSendSettings(QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force); + void webapiReverseSendSettings(const QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force); void sendChannelSettings( const QList& pipes, - QList& channelSettingsKeys, + const QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force ); void webapiFormatChannelSettings( - QList& channelSettingsKeys, + const QList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings *swgChannelSettings, const LocalSinkSettings& settings, bool force diff --git a/plugins/channelrx/localsink/localsinkbaseband.cpp b/plugins/channelrx/localsink/localsinkbaseband.cpp index fa60d46b8..3a273a7f0 100644 --- a/plugins/channelrx/localsink/localsinkbaseband.cpp +++ b/plugins/channelrx/localsink/localsinkbaseband.cpp @@ -112,7 +112,7 @@ bool LocalSinkBaseband::handleMessage(const Message& cmd) MsgConfigureLocalSinkBaseband& cfg = (MsgConfigureLocalSinkBaseband&) cmd; qDebug() << "LocalSinkBaseband::handleMessage: MsgConfigureLocalSinkBaseband"; - applySettings(cfg.getSettings(), cfg.getForce()); + applySettings(cfg.getSettings(), cfg.getSettingsKeys(), cfg.getForce()); return true; } @@ -158,22 +158,18 @@ bool LocalSinkBaseband::handleMessage(const Message& cmd) } } -void LocalSinkBaseband::applySettings(const LocalSinkSettings& settings, bool force) +void LocalSinkBaseband::applySettings(const LocalSinkSettings& settings, const QList& settingsKeys, bool force) { - qDebug() << "LocalSinkBaseband::applySettings:" - << "m_localDeviceIndex:" << settings.m_localDeviceIndex - << "m_log2Decim:" << settings.m_log2Decim - << "m_filterChainHash:" << settings.m_filterChainHash - << " force: " << force; + qDebug() << "LocalSinkBaseband::applySettings:" << settings.getDebugString(settingsKeys, force) << " force: " << force; - if ((settings.m_log2Decim != m_settings.m_log2Decim) - || (settings.m_filterChainHash != m_settings.m_filterChainHash) || force) + if (settingsKeys.contains("log2Decim") + || settingsKeys.contains("filterChainHash") || force) { m_channelizer->setDecimation(settings.m_log2Decim, settings.m_filterChainHash); m_sink.setSampleRate(getChannelSampleRate()); } - m_sink.applySettings(settings, force); + m_sink.applySettings(settings, settingsKeys, force); m_settings = settings; } diff --git a/plugins/channelrx/localsink/localsinkbaseband.h b/plugins/channelrx/localsink/localsinkbaseband.h index 95b5908d2..ae51daad0 100644 --- a/plugins/channelrx/localsink/localsinkbaseband.h +++ b/plugins/channelrx/localsink/localsinkbaseband.h @@ -39,20 +39,22 @@ public: public: const LocalSinkSettings& getSettings() const { return m_settings; } + const QList& getSettingsKeys() const { return m_settingsKeys; } bool getForce() const { return m_force; } - static MsgConfigureLocalSinkBaseband* create(const LocalSinkSettings& settings, bool force) - { - return new MsgConfigureLocalSinkBaseband(settings, force); + static MsgConfigureLocalSinkBaseband* create(const LocalSinkSettings& settings, const QList& settingsKeys, bool force) { + return new MsgConfigureLocalSinkBaseband(settings, settingsKeys, force); } private: LocalSinkSettings m_settings; + QList m_settingsKeys; bool m_force; - MsgConfigureLocalSinkBaseband(const LocalSinkSettings& settings, bool force) : + MsgConfigureLocalSinkBaseband(const LocalSinkSettings& settings, const QList& settingsKeys, bool force) : Message(), m_settings(settings), + m_settingsKeys(settingsKeys), m_force(force) { } }; @@ -121,7 +123,7 @@ private: QRecursiveMutex m_mutex; bool handleMessage(const Message& cmd); - void applySettings(const LocalSinkSettings& settings, bool force = false); + void applySettings(const LocalSinkSettings& settings, const QList& settingsKeys, bool force = false); private slots: void handleInputMessages(); diff --git a/plugins/channelrx/localsink/localsinkgui.cpp b/plugins/channelrx/localsink/localsinkgui.cpp index 08f520213..b3de4abe5 100644 --- a/plugins/channelrx/localsink/localsinkgui.cpp +++ b/plugins/channelrx/localsink/localsinkgui.cpp @@ -82,7 +82,13 @@ bool LocalSinkGUI::handleMessage(const Message& message) else if (LocalSink::MsgConfigureLocalSink::match(message)) { const LocalSink::MsgConfigureLocalSink& cfg = (LocalSink::MsgConfigureLocalSink&) message; - m_settings = cfg.getSettings(); + + if (cfg.getForce()) { + m_settings = cfg.getSettings(); + } else { + m_settings.applySettings(cfg.getSettingsKeys(), cfg.getSettings()); + } + blockApplySettings(true); ui->spectrumGUI->updateSettings(); m_channelMarker.updateSettings(static_cast(m_settings.m_channelMarker)); @@ -168,9 +174,11 @@ void LocalSinkGUI::applySettings(bool force) { setTitleColor(m_channelMarker.getColor()); - LocalSink::MsgConfigureLocalSink* message = LocalSink::MsgConfigureLocalSink::create(m_settings, force); + LocalSink::MsgConfigureLocalSink* message = LocalSink::MsgConfigureLocalSink::create(m_settings, m_settingsKeys, force); m_localSink->getInputMessageQueue()->push(message); } + + m_settingsKeys.clear(); } void LocalSinkGUI::displaySettings() @@ -312,7 +320,6 @@ void LocalSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) rollDown; getRollupContents()->saveState(m_rollupState); - applySettings(); } void LocalSinkGUI::onMenuDialogCalled(const QPoint &p) @@ -356,6 +363,14 @@ void LocalSinkGUI::onMenuDialogCalled(const QPoint &p) updateIndexLabel(); } + m_settingsKeys.append("title"); + m_settingsKeys.append("rgbColor"); + m_settingsKeys.append("useReverseAPI"); + m_settingsKeys.append("reverseAPIAddress"); + m_settingsKeys.append("reverseAPIPort"); + m_settingsKeys.append("reverseAPIFeatureSetIndex"); + m_settingsKeys.append("reverseAPIFeatureIndex"); + applySettings(); } @@ -387,6 +402,8 @@ void LocalSinkGUI::on_position_valueChanged(int value) { m_settings.m_filterChainHash = value; applyPosition(); + m_settingsKeys.append("filterChainHash"); + applySettings(); } void LocalSinkGUI::on_localDevice_currentIndexChanged(int index) @@ -394,6 +411,7 @@ void LocalSinkGUI::on_localDevice_currentIndexChanged(int index) if (index >= 0) { m_settings.m_localDeviceIndex = ui->localDevice->currentData().toInt(); + m_settingsKeys.append("localDeviceIndex"); applySettings(); } } @@ -401,12 +419,14 @@ void LocalSinkGUI::on_localDevice_currentIndexChanged(int index) void LocalSinkGUI::on_localDevicePlay_toggled(bool checked) { m_settings.m_play = checked; + m_settingsKeys.append("play"); applySettings(); } void LocalSinkGUI::on_dsp_toggled(bool checked) { m_settings.m_dsp = checked; + m_settingsKeys.append("dsp"); applySettings(); } @@ -414,12 +434,28 @@ void LocalSinkGUI::on_gain_valueChanged(int value) { m_settings.m_gaindB = value; ui->gainText->setText(tr("%1").arg(value)); + m_settingsKeys.append("gaindB"); applySettings(); } void LocalSinkGUI::on_fft_toggled(bool checked) { m_settings.m_fftOn = checked; + m_settingsKeys.append("fftOn"); + applySettings(); +} + +void LocalSinkGUI::on_fftSize_currentIndexChanged(int index) +{ + m_settings.m_log2FFT = index + 6; + m_settingsKeys.append("log2FFT"); + applySettings(); +} + +void LocalSinkGUI::on_fftWindow_currentIndexChanged(int index) +{ + m_settings.m_fftWindow = (FFTWindow::Function) index; + m_settingsKeys.append("fftWindow"); applySettings(); } @@ -432,6 +468,7 @@ void LocalSinkGUI::on_fftBandAdd_clicked() m_settings.m_fftBands.push_back(std::pair{-0.1f, 0.2f}); m_currentBandIndex = m_settings.m_fftBands.size()-1; displayFFTBand(); + m_settingsKeys.append("fftBands"); applySettings(); } @@ -440,6 +477,7 @@ void LocalSinkGUI::on_fftBandDel_clicked() m_settings.m_fftBands.erase(m_settings.m_fftBands.begin() + m_currentBandIndex); m_currentBandIndex--; displayFFTBand(); + m_settingsKeys.append("fftBands"); applySettings(); } @@ -461,6 +499,7 @@ void LocalSinkGUI::on_f1_valueChanged(int value) } displayFFTBand(); + m_settingsKeys.append("fftBands"); applySettings(); } @@ -477,6 +516,7 @@ void LocalSinkGUI::on_bandWidth_valueChanged(int value) } displayFFTBand(); + m_settingsKeys.append("fftBands"); applySettings(); } @@ -498,6 +538,8 @@ void LocalSinkGUI::applyDecimation() ui->position->setValue(m_settings.m_filterChainHash); m_settings.m_filterChainHash = ui->position->value(); applyPosition(); + m_settingsKeys.append("filterChainHash"); + applySettings(); } void LocalSinkGUI::applyPosition() @@ -510,7 +552,6 @@ void LocalSinkGUI::applyPosition() updateAbsoluteCenterFrequency(); displayRateAndShift(); displayFFTBand(); - applySettings(); } void LocalSinkGUI::tick() @@ -529,6 +570,8 @@ void LocalSinkGUI::makeUIConnections() QObject::connect(ui->dsp, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_dsp_toggled); QObject::connect(ui->gain, &QDial::valueChanged, this, &LocalSinkGUI::on_gain_valueChanged); QObject::connect(ui->fft, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_fft_toggled); + QObject::connect(ui->fftSize, QOverload::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_fftSize_currentIndexChanged); + QObject::connect(ui->fftWindow, QOverload::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_fftWindow_currentIndexChanged); QObject::connect(ui->fftBandAdd, &QPushButton::clicked, this, &LocalSinkGUI::on_fftBandAdd_clicked); QObject::connect(ui->fftBandDel, &QPushButton::clicked, this, &LocalSinkGUI::on_fftBandDel_clicked); QObject::connect(ui->bandIndex, &QSlider::valueChanged, this, &LocalSinkGUI::on_bandIndex_valueChanged); diff --git a/plugins/channelrx/localsink/localsinkgui.h b/plugins/channelrx/localsink/localsinkgui.h index f79a4cb41..39ba9d713 100644 --- a/plugins/channelrx/localsink/localsinkgui.h +++ b/plugins/channelrx/localsink/localsinkgui.h @@ -68,6 +68,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; LocalSinkSettings m_settings; + QList m_settingsKeys; int m_currentBandIndex; bool m_showFilterHighCut; qint64 m_deviceCenterFrequency; @@ -111,6 +112,8 @@ private slots: void on_dsp_toggled(bool checked); void on_gain_valueChanged(int value); void on_fft_toggled(bool checked); + void on_fftSize_currentIndexChanged(int index); + void on_fftWindow_currentIndexChanged(int index); void on_fftBandAdd_clicked(); void on_fftBandDel_clicked(); void on_bandIndex_valueChanged(int value); diff --git a/plugins/channelrx/localsink/localsinksettings.cpp b/plugins/channelrx/localsink/localsinksettings.cpp index d433fb6ee..e830e6b2a 100644 --- a/plugins/channelrx/localsink/localsinksettings.cpp +++ b/plugins/channelrx/localsink/localsinksettings.cpp @@ -42,7 +42,7 @@ void LocalSinkSettings::resetToDefaults() m_gaindB = 0; m_fftOn = false; m_log2FFT = 10; - m_fftWindow = FFTWindow::Function::Bartlett; + m_fftWindow = FFTWindow::Function::Rectangle; m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; @@ -197,7 +197,141 @@ bool LocalSinkSettings::deserialize(const QByteArray& data) } } +void LocalSinkSettings::applySettings(const QStringList& settingsKeys, const LocalSinkSettings& settings) +{ + if (settingsKeys.contains("localDeviceIndex")) { + m_localDeviceIndex = settings.m_localDeviceIndex; + } + if (settingsKeys.contains("rgbColor")) { + m_rgbColor = settings.m_rgbColor; + } + if (settingsKeys.contains("title")) { + m_title = settings.m_title; + } + if (settingsKeys.contains("log2Decim")) { + m_log2Decim = settings.m_log2Decim; + } + if (settingsKeys.contains("filterChainHash")) { + m_filterChainHash = settings.m_filterChainHash; + } + if (settingsKeys.contains("play")) { + m_play = settings.m_play; + } + if (settingsKeys.contains("dsp")) { + m_dsp = settings.m_dsp; + } + if (settingsKeys.contains("gaindB")) { + m_gaindB = settings.m_gaindB; + } + if (settingsKeys.contains("fftOn")) { + m_fftOn = settings.m_fftOn; + } + if (settingsKeys.contains("log2FFT")) { + m_log2FFT = settings.m_log2FFT; + } + if (settingsKeys.contains("fftWindow")) { + m_fftWindow = settings.m_fftWindow; + } + if (settingsKeys.contains("streamIndex")) { + m_streamIndex = settings.m_streamIndex; + } + if (settingsKeys.contains("useReverseAPI")) { + m_useReverseAPI = settings.m_useReverseAPI; + } + if (settingsKeys.contains("reverseAPIAddress")) { + m_reverseAPIAddress = settings.m_reverseAPIAddress; + } + if (settingsKeys.contains("reverseAPIPort")) { + m_reverseAPIPort = settings.m_reverseAPIPort; + } + if (settingsKeys.contains("reverseAPIDeviceIndex")) { + m_reverseAPIDeviceIndex = settings.m_reverseAPIDeviceIndex; + } + if (settingsKeys.contains("reverseAPIChannelIndex")) { + m_reverseAPIChannelIndex = settings.m_reverseAPIChannelIndex; + } + if (settingsKeys.contains("workspaceIndex")) { + m_workspaceIndex = settings.m_workspaceIndex; + } + if (settingsKeys.contains("hidden")) { + m_hidden = settings.m_hidden; + } + if (settingsKeys.contains("fftBands")) { + m_fftBands = settings.m_fftBands; + } +} +QString LocalSinkSettings::getDebugString(const QStringList& settingsKeys, bool force) const +{ + std::ostringstream ostr; + if (settingsKeys.contains("localDeviceIndex") || force) { + ostr << " m_localDeviceIndex: " << m_localDeviceIndex; + } + if (settingsKeys.contains("rgbColor") || force) { + ostr << " m_rgbColor: " << m_rgbColor; + } + if (settingsKeys.contains("title") || force) { + ostr << " m_title: " << m_title.toStdString(); + } + if (settingsKeys.contains("log2Decim") || force) { + ostr << " m_log2Decim: " << m_log2Decim; + } + if (settingsKeys.contains("play") || force) { + ostr << " m_play: " << m_play; + } + if (settingsKeys.contains("dsp") || force) { + ostr << " m_dsp: " << m_dsp; + } + if (settingsKeys.contains("gaindB") || force) { + ostr << " m_gaindB: " << m_gaindB; + } + if (settingsKeys.contains("fftOn") || force) { + ostr << " m_fftOn: " << m_fftOn; + } + if (settingsKeys.contains("log2FFT") || force) { + ostr << " m_log2FFT: " << m_log2FFT; + } + if (settingsKeys.contains("fftWindow") || force) { + ostr << " m_fftWindow: " << m_fftWindow; + } + if (settingsKeys.contains("streamIndex") || force) { + ostr << " m_streamIndex: " << m_streamIndex; + } + if (settingsKeys.contains("useReverseAPI") || force) { + ostr << " m_useReverseAPI: " << m_useReverseAPI; + } + if (settingsKeys.contains("reverseAPIAddress") || force) { + ostr << " m_reverseAPIAddress: " << m_reverseAPIAddress.toStdString(); + } + if (settingsKeys.contains("reverseAPIPort") || force) { + ostr << " m_reverseAPIPort: " << m_reverseAPIPort; + } + if (settingsKeys.contains("reverseAPIDeviceIndex") || force) { + ostr << " m_reverseAPIDeviceIndex: " << m_reverseAPIDeviceIndex; + } + if (settingsKeys.contains("reverseAPIChannelIndex") || force) { + ostr << " m_reverseAPIChannelIndex: " << m_reverseAPIChannelIndex; + } + if (settingsKeys.contains("workspaceIndex") || force) { + ostr << " m_workspaceIndex: " << m_workspaceIndex; + } + if (settingsKeys.contains("hidden") || force) { + ostr << " m_hidden: " << m_hidden; + } + if (settingsKeys.contains("fftBands") || force) + { + ostr << " m_fftBands: ["; + for (const auto& fftBand : m_fftBands) + { + ostr << fftBand.first; + ostr << ":" << fftBand.second << " "; + } + + ostr << "]"; + } + + return QString(ostr.str().c_str()); +} diff --git a/plugins/channelrx/localsink/localsinksettings.h b/plugins/channelrx/localsink/localsinksettings.h index eda4b8190..b03c8c839 100644 --- a/plugins/channelrx/localsink/localsinksettings.h +++ b/plugins/channelrx/localsink/localsinksettings.h @@ -61,6 +61,8 @@ struct LocalSinkSettings void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; } QByteArray serialize() const; bool deserialize(const QByteArray& data); + void applySettings(const QStringList& settingsKeys, const LocalSinkSettings& settings); + QString getDebugString(const QStringList& settingsKeys, bool force=false) const; }; #endif /* INCLUDE_LOCALSINKSETTINGS_H_ */ diff --git a/plugins/channelrx/localsink/localsinksink.cpp b/plugins/channelrx/localsink/localsinksink.cpp index 01e451abd..9ab7578b8 100644 --- a/plugins/channelrx/localsink/localsinksink.cpp +++ b/plugins/channelrx/localsink/localsinksink.cpp @@ -42,7 +42,7 @@ LocalSinkSink::LocalSinkSink() : m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(4000000)); // m_fftFilter = new fftfilt(0.1f, 0.4f, 1<(), true); } LocalSinkSink::~LocalSinkSink() @@ -60,7 +60,7 @@ void LocalSinkSink::feed(const SampleVector::const_iterator& begin, const Sample for (SampleVector::const_iterator it = begin; it != end; ++it) { Complex c(it->real(), it->imag()); - rf_out = m_fftFilter->runFilt(c, &rf); // filter RF + rf_out = m_fftFilter->runAsym(c, &rf, true); // filter RF if (rf_out > 0) { @@ -182,28 +182,33 @@ void LocalSinkSink::stopWorker() m_sinkWorkerThread.wait(); } -void LocalSinkSink::applySettings(const LocalSinkSettings& settings, bool force) +void LocalSinkSink::applySettings(const LocalSinkSettings& settings, const QList& settingsKeys, bool force) { - qDebug() << "LocalSinkSink::applySettings:" - << " m_localDeviceIndex: " << settings.m_localDeviceIndex - << " m_streamIndex: " << settings.m_streamIndex - << " m_dsp: " << settings.m_dsp - << " m_gaindB: " << settings.m_gaindB - << " m_fftOn: " << settings.m_fftOn - << " force: " << force; + qDebug() << "LocalSinkSink::applySettings:" << settings.getDebugString(settingsKeys, force) << " force: " << force; - if ((settings.m_gaindB != m_settings.m_gaindB) || force) { + if (settingsKeys.contains("gaindB") || force) { m_gain = CalcDb::powerFromdB(settings.m_gaindB/2.0); // Amplitude gain } - if ((settings.m_fftOn != m_settings.m_fftOn) || force) + if (settingsKeys.contains("log2FFT") || force) { - if (settings.m_fftOn) { - m_fftFilter->create_filter(m_settings.m_fftBands, true, FFTWindow::Function::Rectangle); - } + delete m_fftFilter; + m_fftFilter = new fftfilt(1<create_filter(m_settings.m_fftBands, true, m_settings.m_fftWindow); } - m_settings = settings; + if (settingsKeys.contains("fftWindow") + || settingsKeys.contains("fftBands") + || force) + { + m_fftFilter->create_filter(settings.m_fftBands, true, settings.m_fftWindow); + } + + if (force) { + m_settings = settings; + } else { + m_settings.applySettings(settingsKeys, settings); + } } void LocalSinkSink::setSampleRate(int sampleRate) diff --git a/plugins/channelrx/localsink/localsinksink.h b/plugins/channelrx/localsink/localsinksink.h index 741706efc..c673719c3 100644 --- a/plugins/channelrx/localsink/localsinksink.h +++ b/plugins/channelrx/localsink/localsinksink.h @@ -39,7 +39,7 @@ public: virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); void setSpectrumSink(SpectrumVis* spectrumSink) { m_spectrumSink = spectrumSink; } - void applySettings(const LocalSinkSettings& settings, bool force = false); + void applySettings(const LocalSinkSettings& settings, const QList& settingsKeys, bool force = false); void start(DeviceSampleSource *deviceSource); void stop(); bool isRunning() const { return m_running; } diff --git a/sdrbase/dsp/fftfilt.cpp b/sdrbase/dsp/fftfilt.cpp index 3fabae3be..11d2daee1 100644 --- a/sdrbase/dsp/fftfilt.cpp +++ b/sdrbase/dsp/fftfilt.cpp @@ -25,6 +25,9 @@ // // You should have received a copy of the GNU General Public License // along with fldigi. If not, see . +// +// Augmented with more filter types +// Copyright (C) 2015-2022 Edouard Griffiths, F4EXB // ---------------------------------------------------------------------------- #include @@ -38,7 +41,6 @@ #include #include -#include #include #include @@ -157,7 +159,7 @@ void fftfilt::create_filter(float f1, float f2, FFTWindow::Function wf) } } -void fftfilt::create_filter(const std::vector>& limits, bool pass, FFTWindow::Function wf) +void fftfilt::create_filter(const std::vector>& limits, bool pass) { // initialize the filter canvas std::vector canvas(flen, pass ? 0 : 1); @@ -186,58 +188,159 @@ void fftfilt::create_filter(const std::vector>& limits, } } - std::vector> indexes; - int c = 0; - - for (int i = 0; i < flen; i++) - { - if ((canvas[i] == 1) && (c == 0)) { - indexes.push_back(std::pair{i, 0}); - } - - if ((canvas[i] == 0) && (c == 1)) { - indexes.back().second = i; - } - + for (int i = 0; i < flen; i++) { xfilter[i] = cmplx(canvas[i], 0); - c = canvas[i]; - } - - // Apply window - for (const auto& wband : indexes) - { - FFTWindow fwin; - fwin.create(wf, wband.second - wband.first); - fwin.apply(&xfilter[wband.first]); } // Rearrange std::copy(&xfilter[flen2], &xfilter[flen-1], filter); std::copy(&xfilter[0], &xfilter[flen2-1], &filter[flen2]); - - // // normalize the output filter for unity gain - // float scale = 0, mag; - - // for (int i = 0; i < flen2; i++) - // { - // mag = abs(filter[i]); - - // if (mag > scale) { - // scale = mag; - // } - // } - - // if (scale != 0) - // { - // for (int i = 0; i < flen; i++) { - // filter[i] /= scale; - // } - // } - delete[] xfilter; } +void fftfilt::create_filter(const std::vector>& limits, bool pass, FFTWindow::Function wf) +{ + std::vector canvasNeg(flen2, pass ? 0 : 1); // initialize the negative frequencies filter canvas + std::vector canvasPos(flen2, pass ? 0 : 1); // initialize the positive frequencies filter canvas + std::fill(filter, filter + flen, cmplx{0, 0}); // initialize the positive filter to zero + std::fill(filterOpp, filterOpp + flen, cmplx{0, 0}); // initialize the negative filter to zero + + for (const auto& fs : limits) + { + const float& f1 = fs.first + 0.5; + const float& w = fs.second > 0.0 ? fs.second : 0.0; + const float& f2 = f1 + w; + + for (int i = 0; i < flen; i++) + { + if (pass) // pass + { + if ((i >= f1*flen) && (i <= f2*flen)) + { + if (i < flen2) { + canvasNeg[flen2-1-i] = 1; + } else { + canvasPos[i-flen2] = 1; + } + } + } + else // reject + { + if ((i >= f1*flen) && (i <= f2*flen)) { + if (i < flen2) { + canvasNeg[flen2-1-i] = 0; + } else { + canvasPos[i-flen2] = 0; + } + } + } + } + } + + std::vector> indexesNegList; + std::vector> indexesPosList; + int cn = 0; + int cp = 0; + + for (int i = 0; i < flen2; i++) + { + if ((canvasNeg[i] == 1) && (cn == 0)) { + indexesNegList.push_back(std::pair{i, 0}); + } + + if ((canvasNeg[i] == 0) && (cn == 1)) { + indexesNegList.back().second = i; + } + + if ((canvasPos[i] == 1) && (cp == 0)) { + indexesPosList.push_back(std::pair{i, 0}); + } + + if ((canvasPos[i] == 0) && (cp == 1)) { + indexesPosList.back().second = i; + } + + cn = canvasNeg[i]; + cp = canvasPos[i]; + } + + for (const auto& indexes : indexesPosList) + { + const float f1 = indexes.first / (float) flen; + const float f2 = indexes.second / (float) flen; + + for (int i = 0; i < flen2; i++) + { + if (f2 != 0) { + filter[i] += fsinc(f2, i, flen2); + } + if (f1 != 0) { + filter[i] -= fsinc(f1, i, flen2); + } + } + } + + for (const auto& indexes : indexesNegList) + { + const float f1 = indexes.first / (float) flen; + const float f2 = indexes.second / (float) flen; + + for (int i = 0; i < flen2; i++) + { + if (f2 != 0) { + filterOpp[i] += fsinc(f2, i, flen2); + } + if (f1 != 0) { + filterOpp[i] -= fsinc(f1, i, flen2); + } + } + } + + FFTWindow fwin; + fwin.create(wf, flen2); + fwin.apply(filter); + fwin.apply(filterOpp); + + fft->ComplexFFT(filter); // filter was expressed in the time domain (impulse response) + fft->ComplexFFT(filterOpp); // filter was expressed in the time domain (impulse response) + + float scalen = 0, scalep = 0, magn, magp; // normalize the output filter for unity gain + + for (int i = 0; i < flen2; i++) + { + magp = abs(filter[i]); + + if (magp > scalep) { + scalep = magp; + } + + magn = abs(filterOpp[i]); + + if (magn > scalen) { + scalen = magn; + } + } + + if (scalep != 0) + { + std::for_each( + filter, + filter + flen, + [scalep](fftfilt::cmplx& s) { s /= scalep; } + ); + } + + if (scalen != 0) + { + std::for_each( + filterOpp, + filterOpp + flen, + [scalen](fftfilt::cmplx& s) { s /= scalen; } + ); + } +} + // Double the size of FFT used for equivalent SSB filter or assume FFT is half the size of the one used for SSB void fftfilt::create_dsb_filter(float f2, FFTWindow::Function wf) { diff --git a/sdrbase/dsp/fftfilt.h b/sdrbase/dsp/fftfilt.h index 806c5f8c4..57b745eda 100644 --- a/sdrbase/dsp/fftfilt.h +++ b/sdrbase/dsp/fftfilt.h @@ -28,6 +28,7 @@ public: // f1 > f2 ==> band reject void create_filter(float f1, float f2, FFTWindow::Function wf = FFTWindow::Blackman); void create_filter(const std::vector>& limits, bool pass = true, FFTWindow::Function wf = FFTWindow::Blackman); + void create_filter(const std::vector>& limits, bool pass = true); //!< Windowless version void create_dsb_filter(float f2, FFTWindow::Function wf = FFTWindow::Blackman); void create_asym_filter(float fopp, float fin, FFTWindow::Function wf = FFTWindow::Blackman); //!< two different filters for in band and opposite band void create_rrc_filter(float fb, float a); //!< root raised cosine. fb is half the band pass