mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -04:00 
			
		
		
		
	Local Sink: added FFT filter bands
This commit is contained in:
		
							parent
							
								
									bf765a00ec
								
							
						
					
					
						commit
						c42d163d3b
					
				| @ -60,7 +60,7 @@ LocalSink::LocalSink(DeviceAPI *deviceAPI) : | |||||||
|         m_basebandSampleRate(48000) |         m_basebandSampleRate(48000) | ||||||
| { | { | ||||||
|     setObjectName(m_channelId); |     setObjectName(m_channelId); | ||||||
|     applySettings(m_settings, true); |     applySettings(m_settings, QList<QString>(), true); | ||||||
| 
 | 
 | ||||||
|     m_deviceAPI->addChannelSink(this); |     m_deviceAPI->addChannelSink(this); | ||||||
|     m_deviceAPI->addChannelSinkAPI(this); |     m_deviceAPI->addChannelSinkAPI(this); | ||||||
| @ -162,7 +162,7 @@ void LocalSink::startProcessing() | |||||||
|         LocalSinkBaseband::MsgConfigureLocalDeviceSampleSource::create(deviceSource); |         LocalSinkBaseband::MsgConfigureLocalDeviceSampleSource::create(deviceSource); | ||||||
|     m_basebandSink->getInputMessageQueue()->push(msgDevice); |     m_basebandSink->getInputMessageQueue()->push(msgDevice); | ||||||
| 
 | 
 | ||||||
|     LocalSinkBaseband::MsgConfigureLocalSinkBaseband *msgConfig = LocalSinkBaseband::MsgConfigureLocalSinkBaseband::create(m_settings, true); |     LocalSinkBaseband::MsgConfigureLocalSinkBaseband *msgConfig = LocalSinkBaseband::MsgConfigureLocalSinkBaseband::create(m_settings, QList<QString>(), true); | ||||||
|     m_basebandSink->getInputMessageQueue()->push(msgConfig); |     m_basebandSink->getInputMessageQueue()->push(msgConfig); | ||||||
| 
 | 
 | ||||||
|     LocalSinkBaseband::MsgSetSpectrumSampleRateAndFrequency *msgSpectrum = LocalSinkBaseband::MsgSetSpectrumSampleRateAndFrequency::create( |     LocalSinkBaseband::MsgSetSpectrumSampleRateAndFrequency *msgSpectrum = LocalSinkBaseband::MsgSetSpectrumSampleRateAndFrequency::create( | ||||||
| @ -224,7 +224,7 @@ bool LocalSink::handleMessage(const Message& cmd) | |||||||
|     { |     { | ||||||
|         MsgConfigureLocalSink& cfg = (MsgConfigureLocalSink&) cmd; |         MsgConfigureLocalSink& cfg = (MsgConfigureLocalSink&) cmd; | ||||||
|         qDebug() << "LocalSink::handleMessage: MsgConfigureLocalSink"; |         qDebug() << "LocalSink::handleMessage: MsgConfigureLocalSink"; | ||||||
|         applySettings(cfg.getSettings(), cfg.getForce()); |         applySettings(cfg.getSettings(), cfg.getSettingsKeys(), cfg.getForce()); | ||||||
| 
 | 
 | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @ -244,14 +244,14 @@ bool LocalSink::deserialize(const QByteArray& data) | |||||||
|     (void) data; |     (void) data; | ||||||
|     if (m_settings.deserialize(data)) |     if (m_settings.deserialize(data)) | ||||||
|     { |     { | ||||||
|         MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, true); |         MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, QList<QString>(), true); | ||||||
|         m_inputMessageQueue.push(msg); |         m_inputMessageQueue.push(msg); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         m_settings.resetToDefaults(); |         m_settings.resetToDefaults(); | ||||||
|         MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, true); |         MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, QList<QString>(), true); | ||||||
|         m_inputMessageQueue.push(msg); |         m_inputMessageQueue.push(msg); | ||||||
|         return false; |         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<QString>& settingsKeys, bool force) | ||||||
| { | { | ||||||
|     qDebug() << "LocalSink::applySettings:" |     qDebug() << "LocalSink::applySettings:" << settings.getDebugString(settingsKeys, force) << "force: " << force; | ||||||
|             << "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; |  | ||||||
| 
 | 
 | ||||||
|     QList<QString> reverseAPIKeys; |     if (settingsKeys.contains("localDeviceIndex") || force) | ||||||
| 
 |  | ||||||
|     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) |  | ||||||
|     { |     { | ||||||
|         reverseAPIKeys.append("localDeviceIndex"); |  | ||||||
|         propagateSampleRateAndFrequency(settings.m_localDeviceIndex, settings.m_log2Decim); |         propagateSampleRateAndFrequency(settings.m_localDeviceIndex, settings.m_log2Decim); | ||||||
| 
 | 
 | ||||||
|         if (m_running) |         if (m_running) | ||||||
| @ -347,8 +331,8 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if ((settings.m_log2Decim != m_settings.m_log2Decim) |     if (settingsKeys.contains("log2Decim") | ||||||
|      || (settings.m_filterChainHash != m_settings.m_filterChainHash) || force) |      || settingsKeys.contains("filterChainHash") || force) | ||||||
|     { |     { | ||||||
|         calculateFrequencyOffset(settings.m_log2Decim, settings.m_filterChainHash); |         calculateFrequencyOffset(settings.m_log2Decim, settings.m_filterChainHash); | ||||||
|         propagateSampleRateAndFrequency(m_settings.m_localDeviceIndex, settings.m_log2Decim); |         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) { |         if (settings.m_play) { | ||||||
|             startProcessing(); |             startProcessing(); | ||||||
|         } else { |         } 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
 |         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->addChannelSink(this, settings.m_streamIndex); | ||||||
|             m_deviceAPI->addChannelSinkAPI(this); |             m_deviceAPI->addChannelSinkAPI(this); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         reverseAPIKeys.append("streamIndex"); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (m_running) |     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); |         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) || |         bool fullUpdate = (settingsKeys.contains("useReverseAPI") && settings.m_useReverseAPI) || | ||||||
|                 (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) || |                 settingsKeys.contains("reverseAPIAddress") || | ||||||
|                 (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) || |                 settingsKeys.contains("reverseAPIPort") || | ||||||
|                 (m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex) || |                 settingsKeys.contains("reverseAPIFeatureSetIndex") || | ||||||
|                 (m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex); |                 settingsKeys.contains("m_reverseAPIFeatureIndex"); | ||||||
|         webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); |         webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     QList<ObjectPipe*> pipes; |     QList<ObjectPipe*> pipes; | ||||||
|     MainCore::instance()->getMessagePipes().getMessagePipes(this, "settings", pipes); |     MainCore::instance()->getMessagePipes().getMessagePipes(this, "settings", pipes); | ||||||
| 
 | 
 | ||||||
|     if (pipes.size() > 0) { |     if (pipes.size() > 0) { | ||||||
|         sendChannelSettings(pipes, reverseAPIKeys, settings, force); |         sendChannelSettings(pipes, settingsKeys, settings, force); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     m_settings = settings; |     m_settings = settings; | ||||||
| @ -461,13 +441,13 @@ int LocalSink::webapiSettingsPutPatch( | |||||||
|     LocalSinkSettings settings = m_settings; |     LocalSinkSettings settings = m_settings; | ||||||
|     webapiUpdateChannelSettings(settings, channelSettingsKeys, response); |     webapiUpdateChannelSettings(settings, channelSettingsKeys, response); | ||||||
| 
 | 
 | ||||||
|     MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(settings, force); |     MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(settings, channelSettingsKeys, force); | ||||||
|     m_inputMessageQueue.push(msg); |     m_inputMessageQueue.push(msg); | ||||||
| 
 | 
 | ||||||
|     qDebug("LocalSink::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); |     qDebug("LocalSink::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); | ||||||
|     if (m_guiMessageQueue) // forward to GUI if any
 |     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); |         m_guiMessageQueue->push(msgToGUI); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -585,7 +565,7 @@ void LocalSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force) | void LocalSink::webapiReverseSendSettings(const QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force) | ||||||
| { | { | ||||||
|     SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); |     SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); | ||||||
|     webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); |     webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); | ||||||
| @ -612,7 +592,7 @@ void LocalSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c | |||||||
| 
 | 
 | ||||||
| void LocalSink::sendChannelSettings( | void LocalSink::sendChannelSettings( | ||||||
|     const QList<ObjectPipe*>& pipes, |     const QList<ObjectPipe*>& pipes, | ||||||
|     QList<QString>& channelSettingsKeys, |     const QList<QString>& channelSettingsKeys, | ||||||
|     const LocalSinkSettings& settings, |     const LocalSinkSettings& settings, | ||||||
|     bool force) |     bool force) | ||||||
| { | { | ||||||
| @ -636,7 +616,7 @@ void LocalSink::sendChannelSettings( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSink::webapiFormatChannelSettings( | void LocalSink::webapiFormatChannelSettings( | ||||||
|         QList<QString>& channelSettingsKeys, |         const QList<QString>& channelSettingsKeys, | ||||||
|         SWGSDRangel::SWGChannelSettings *swgChannelSettings, |         SWGSDRangel::SWGChannelSettings *swgChannelSettings, | ||||||
|         const LocalSinkSettings& settings, |         const LocalSinkSettings& settings, | ||||||
|         bool force |         bool force | ||||||
| @ -777,11 +757,11 @@ void LocalSink::updateDeviceSetList() | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     qDebug("LocalSink::updateDeviceSetLists: new device index: %d device: %d", newIndexInList, settings.m_localDeviceIndex); |     qDebug("LocalSink::updateDeviceSetLists: new device index: %d device: %d", newIndexInList, settings.m_localDeviceIndex); | ||||||
|     applySettings(settings); |     applySettings(settings, QList<QString>{"localDeviceIndex"}); | ||||||
| 
 | 
 | ||||||
|     if (m_guiMessageQueue) |     if (m_guiMessageQueue) | ||||||
|     { |     { | ||||||
|         MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, false); |         MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, QList<QString>{"localDeviceIndex"}, false); | ||||||
|         m_guiMessageQueue->push(msg); |         m_guiMessageQueue->push(msg); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,19 +44,22 @@ public: | |||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
|         const LocalSinkSettings& getSettings() const { return m_settings; } |         const LocalSinkSettings& getSettings() const { return m_settings; } | ||||||
|  |         const QList<QString>& getSettingsKeys() const { return m_settingsKeys; } | ||||||
|         bool getForce() const { return m_force; } |         bool getForce() const { return m_force; } | ||||||
| 
 | 
 | ||||||
|         static MsgConfigureLocalSink* create(const LocalSinkSettings& settings, bool force) { |         static MsgConfigureLocalSink* create(const LocalSinkSettings& settings, const QList<QString>& settingsKeys, bool force) { | ||||||
|             return new MsgConfigureLocalSink(settings, force); |             return new MsgConfigureLocalSink(settings, settingsKeys, force); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     private: |     private: | ||||||
|         LocalSinkSettings m_settings; |         LocalSinkSettings m_settings; | ||||||
|  |         QList<QString> m_settingsKeys; | ||||||
|         bool m_force; |         bool m_force; | ||||||
| 
 | 
 | ||||||
|         MsgConfigureLocalSink(const LocalSinkSettings& settings, bool force) : |         MsgConfigureLocalSink(const LocalSinkSettings& settings, const QList<QString>& settingsKeys, bool force) : | ||||||
|             Message(), |             Message(), | ||||||
|             m_settings(settings), |             m_settings(settings), | ||||||
|  |             m_settingsKeys(settingsKeys), | ||||||
|             m_force(force) |             m_force(force) | ||||||
|         { } |         { } | ||||||
|     }; |     }; | ||||||
| @ -158,7 +161,7 @@ private: | |||||||
|     QNetworkRequest m_networkRequest; |     QNetworkRequest m_networkRequest; | ||||||
| 
 | 
 | ||||||
|     virtual bool handleMessage(const Message& cmd); |     virtual bool handleMessage(const Message& cmd); | ||||||
|     void applySettings(const LocalSinkSettings& settings, bool force = false); |     void applySettings(const LocalSinkSettings& settings, const QList<QString>& settingsKeys, bool force = false); | ||||||
|     void propagateSampleRateAndFrequency(int index, uint32_t log2Decim); |     void propagateSampleRateAndFrequency(int index, uint32_t log2Decim); | ||||||
|     static void validateFilterChainHash(LocalSinkSettings& settings); |     static void validateFilterChainHash(LocalSinkSettings& settings); | ||||||
|     void calculateFrequencyOffset(uint32_t log2Decim, uint32_t filterChainHash); |     void calculateFrequencyOffset(uint32_t log2Decim, uint32_t filterChainHash); | ||||||
| @ -167,15 +170,15 @@ private: | |||||||
|     void startProcessing(); |     void startProcessing(); | ||||||
|     void stopProcessing(); |     void stopProcessing(); | ||||||
| 
 | 
 | ||||||
|     void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force); |     void webapiReverseSendSettings(const QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force); | ||||||
|     void sendChannelSettings( |     void sendChannelSettings( | ||||||
|         const QList<ObjectPipe*>& pipes, |         const QList<ObjectPipe*>& pipes, | ||||||
|         QList<QString>& channelSettingsKeys, |         const QList<QString>& channelSettingsKeys, | ||||||
|         const LocalSinkSettings& settings, |         const LocalSinkSettings& settings, | ||||||
|         bool force |         bool force | ||||||
|     ); |     ); | ||||||
|     void webapiFormatChannelSettings( |     void webapiFormatChannelSettings( | ||||||
|         QList<QString>& channelSettingsKeys, |         const QList<QString>& channelSettingsKeys, | ||||||
|         SWGSDRangel::SWGChannelSettings *swgChannelSettings, |         SWGSDRangel::SWGChannelSettings *swgChannelSettings, | ||||||
|         const LocalSinkSettings& settings, |         const LocalSinkSettings& settings, | ||||||
|         bool force |         bool force | ||||||
|  | |||||||
| @ -112,7 +112,7 @@ bool LocalSinkBaseband::handleMessage(const Message& cmd) | |||||||
|         MsgConfigureLocalSinkBaseband& cfg = (MsgConfigureLocalSinkBaseband&) cmd; |         MsgConfigureLocalSinkBaseband& cfg = (MsgConfigureLocalSinkBaseband&) cmd; | ||||||
|         qDebug() << "LocalSinkBaseband::handleMessage: MsgConfigureLocalSinkBaseband"; |         qDebug() << "LocalSinkBaseband::handleMessage: MsgConfigureLocalSinkBaseband"; | ||||||
| 
 | 
 | ||||||
|         applySettings(cfg.getSettings(), cfg.getForce()); |         applySettings(cfg.getSettings(), cfg.getSettingsKeys(), cfg.getForce()); | ||||||
| 
 | 
 | ||||||
|         return true; |         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<QString>& settingsKeys, bool force) | ||||||
| { | { | ||||||
|     qDebug() << "LocalSinkBaseband::applySettings:" |     qDebug() << "LocalSinkBaseband::applySettings:" << settings.getDebugString(settingsKeys, force) << " force: " << force; | ||||||
|         << "m_localDeviceIndex:" << settings.m_localDeviceIndex |  | ||||||
|         << "m_log2Decim:" << settings.m_log2Decim |  | ||||||
|         << "m_filterChainHash:" << settings.m_filterChainHash |  | ||||||
|         << " force: " << force; |  | ||||||
| 
 | 
 | ||||||
|     if ((settings.m_log2Decim != m_settings.m_log2Decim) |     if (settingsKeys.contains("log2Decim") | ||||||
|      || (settings.m_filterChainHash != m_settings.m_filterChainHash) || force) |      || settingsKeys.contains("filterChainHash") || force) | ||||||
|     { |     { | ||||||
|         m_channelizer->setDecimation(settings.m_log2Decim, settings.m_filterChainHash); |         m_channelizer->setDecimation(settings.m_log2Decim, settings.m_filterChainHash); | ||||||
|         m_sink.setSampleRate(getChannelSampleRate()); |         m_sink.setSampleRate(getChannelSampleRate()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     m_sink.applySettings(settings, force); |     m_sink.applySettings(settings, settingsKeys, force); | ||||||
|     m_settings = settings; |     m_settings = settings; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,20 +39,22 @@ public: | |||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
|         const LocalSinkSettings& getSettings() const { return m_settings; } |         const LocalSinkSettings& getSettings() const { return m_settings; } | ||||||
|  |         const QList<QString>& getSettingsKeys() const { return m_settingsKeys; } | ||||||
|         bool getForce() const { return m_force; } |         bool getForce() const { return m_force; } | ||||||
| 
 | 
 | ||||||
|         static MsgConfigureLocalSinkBaseband* create(const LocalSinkSettings& settings, bool force) |         static MsgConfigureLocalSinkBaseband* create(const LocalSinkSettings& settings, const QList<QString>& settingsKeys, bool force) { | ||||||
|         { |             return new MsgConfigureLocalSinkBaseband(settings, settingsKeys, force); | ||||||
|             return new MsgConfigureLocalSinkBaseband(settings, force); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     private: |     private: | ||||||
|         LocalSinkSettings m_settings; |         LocalSinkSettings m_settings; | ||||||
|  |         QList<QString> m_settingsKeys; | ||||||
|         bool m_force; |         bool m_force; | ||||||
| 
 | 
 | ||||||
|         MsgConfigureLocalSinkBaseband(const LocalSinkSettings& settings, bool force) : |         MsgConfigureLocalSinkBaseband(const LocalSinkSettings& settings, const QList<QString>& settingsKeys, bool force) : | ||||||
|             Message(), |             Message(), | ||||||
|             m_settings(settings), |             m_settings(settings), | ||||||
|  |             m_settingsKeys(settingsKeys), | ||||||
|             m_force(force) |             m_force(force) | ||||||
|         { } |         { } | ||||||
|     }; |     }; | ||||||
| @ -121,7 +123,7 @@ private: | |||||||
|     QRecursiveMutex m_mutex; |     QRecursiveMutex m_mutex; | ||||||
| 
 | 
 | ||||||
|     bool handleMessage(const Message& cmd); |     bool handleMessage(const Message& cmd); | ||||||
|     void applySettings(const LocalSinkSettings& settings, bool force = false); |     void applySettings(const LocalSinkSettings& settings, const QList<QString>& settingsKeys, bool force = false); | ||||||
| 
 | 
 | ||||||
| private slots: | private slots: | ||||||
|     void handleInputMessages(); |     void handleInputMessages(); | ||||||
|  | |||||||
| @ -82,7 +82,13 @@ bool LocalSinkGUI::handleMessage(const Message& message) | |||||||
|     else if (LocalSink::MsgConfigureLocalSink::match(message)) |     else if (LocalSink::MsgConfigureLocalSink::match(message)) | ||||||
|     { |     { | ||||||
|         const LocalSink::MsgConfigureLocalSink& cfg = (LocalSink::MsgConfigureLocalSink&) message; |         const LocalSink::MsgConfigureLocalSink& cfg = (LocalSink::MsgConfigureLocalSink&) message; | ||||||
|  | 
 | ||||||
|  |         if (cfg.getForce()) { | ||||||
|             m_settings = cfg.getSettings(); |             m_settings = cfg.getSettings(); | ||||||
|  |         } else { | ||||||
|  |             m_settings.applySettings(cfg.getSettingsKeys(), cfg.getSettings()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         blockApplySettings(true); |         blockApplySettings(true); | ||||||
|         ui->spectrumGUI->updateSettings(); |         ui->spectrumGUI->updateSettings(); | ||||||
|         m_channelMarker.updateSettings(static_cast<const ChannelMarker*>(m_settings.m_channelMarker)); |         m_channelMarker.updateSettings(static_cast<const ChannelMarker*>(m_settings.m_channelMarker)); | ||||||
| @ -168,9 +174,11 @@ void LocalSinkGUI::applySettings(bool force) | |||||||
|     { |     { | ||||||
|         setTitleColor(m_channelMarker.getColor()); |         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_localSink->getInputMessageQueue()->push(message); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     m_settingsKeys.clear(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkGUI::displaySettings() | void LocalSinkGUI::displaySettings() | ||||||
| @ -312,7 +320,6 @@ void LocalSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown) | |||||||
|     (void) rollDown; |     (void) rollDown; | ||||||
| 
 | 
 | ||||||
|     getRollupContents()->saveState(m_rollupState); |     getRollupContents()->saveState(m_rollupState); | ||||||
|     applySettings(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkGUI::onMenuDialogCalled(const QPoint &p) | void LocalSinkGUI::onMenuDialogCalled(const QPoint &p) | ||||||
| @ -356,6 +363,14 @@ void LocalSinkGUI::onMenuDialogCalled(const QPoint &p) | |||||||
|             updateIndexLabel(); |             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(); |         applySettings(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -387,6 +402,8 @@ void LocalSinkGUI::on_position_valueChanged(int value) | |||||||
| { | { | ||||||
|     m_settings.m_filterChainHash = value; |     m_settings.m_filterChainHash = value; | ||||||
|     applyPosition(); |     applyPosition(); | ||||||
|  |     m_settingsKeys.append("filterChainHash"); | ||||||
|  |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkGUI::on_localDevice_currentIndexChanged(int index) | void LocalSinkGUI::on_localDevice_currentIndexChanged(int index) | ||||||
| @ -394,6 +411,7 @@ void LocalSinkGUI::on_localDevice_currentIndexChanged(int index) | |||||||
|     if (index >= 0) |     if (index >= 0) | ||||||
|     { |     { | ||||||
|         m_settings.m_localDeviceIndex = ui->localDevice->currentData().toInt(); |         m_settings.m_localDeviceIndex = ui->localDevice->currentData().toInt(); | ||||||
|  |         m_settingsKeys.append("localDeviceIndex"); | ||||||
|         applySettings(); |         applySettings(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -401,12 +419,14 @@ void LocalSinkGUI::on_localDevice_currentIndexChanged(int index) | |||||||
| void LocalSinkGUI::on_localDevicePlay_toggled(bool checked) | void LocalSinkGUI::on_localDevicePlay_toggled(bool checked) | ||||||
| { | { | ||||||
|     m_settings.m_play = checked; |     m_settings.m_play = checked; | ||||||
|  |     m_settingsKeys.append("play"); | ||||||
|     applySettings(); |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkGUI::on_dsp_toggled(bool checked) | void LocalSinkGUI::on_dsp_toggled(bool checked) | ||||||
| { | { | ||||||
|     m_settings.m_dsp = checked; |     m_settings.m_dsp = checked; | ||||||
|  |     m_settingsKeys.append("dsp"); | ||||||
|     applySettings(); |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -414,12 +434,28 @@ void LocalSinkGUI::on_gain_valueChanged(int value) | |||||||
| { | { | ||||||
|     m_settings.m_gaindB = value; |     m_settings.m_gaindB = value; | ||||||
|     ui->gainText->setText(tr("%1").arg(value)); |     ui->gainText->setText(tr("%1").arg(value)); | ||||||
|  |     m_settingsKeys.append("gaindB"); | ||||||
|     applySettings(); |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkGUI::on_fft_toggled(bool checked) | void LocalSinkGUI::on_fft_toggled(bool checked) | ||||||
| { | { | ||||||
|     m_settings.m_fftOn = 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(); |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -432,6 +468,7 @@ void LocalSinkGUI::on_fftBandAdd_clicked() | |||||||
|     m_settings.m_fftBands.push_back(std::pair<float,float>{-0.1f, 0.2f}); |     m_settings.m_fftBands.push_back(std::pair<float,float>{-0.1f, 0.2f}); | ||||||
|     m_currentBandIndex = m_settings.m_fftBands.size()-1; |     m_currentBandIndex = m_settings.m_fftBands.size()-1; | ||||||
|     displayFFTBand(); |     displayFFTBand(); | ||||||
|  |     m_settingsKeys.append("fftBands"); | ||||||
|     applySettings(); |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -440,6 +477,7 @@ void LocalSinkGUI::on_fftBandDel_clicked() | |||||||
|     m_settings.m_fftBands.erase(m_settings.m_fftBands.begin() + m_currentBandIndex); |     m_settings.m_fftBands.erase(m_settings.m_fftBands.begin() + m_currentBandIndex); | ||||||
|     m_currentBandIndex--; |     m_currentBandIndex--; | ||||||
|     displayFFTBand(); |     displayFFTBand(); | ||||||
|  |     m_settingsKeys.append("fftBands"); | ||||||
|     applySettings(); |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -461,6 +499,7 @@ void LocalSinkGUI::on_f1_valueChanged(int value) | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     displayFFTBand(); |     displayFFTBand(); | ||||||
|  |     m_settingsKeys.append("fftBands"); | ||||||
|     applySettings(); |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -477,6 +516,7 @@ void LocalSinkGUI::on_bandWidth_valueChanged(int value) | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     displayFFTBand(); |     displayFFTBand(); | ||||||
|  |     m_settingsKeys.append("fftBands"); | ||||||
|     applySettings(); |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -498,6 +538,8 @@ void LocalSinkGUI::applyDecimation() | |||||||
|     ui->position->setValue(m_settings.m_filterChainHash); |     ui->position->setValue(m_settings.m_filterChainHash); | ||||||
|     m_settings.m_filterChainHash = ui->position->value(); |     m_settings.m_filterChainHash = ui->position->value(); | ||||||
|     applyPosition(); |     applyPosition(); | ||||||
|  |     m_settingsKeys.append("filterChainHash"); | ||||||
|  |     applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkGUI::applyPosition() | void LocalSinkGUI::applyPosition() | ||||||
| @ -510,7 +552,6 @@ void LocalSinkGUI::applyPosition() | |||||||
|     updateAbsoluteCenterFrequency(); |     updateAbsoluteCenterFrequency(); | ||||||
|     displayRateAndShift(); |     displayRateAndShift(); | ||||||
|     displayFFTBand(); |     displayFFTBand(); | ||||||
|     applySettings(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkGUI::tick() | void LocalSinkGUI::tick() | ||||||
| @ -529,6 +570,8 @@ void LocalSinkGUI::makeUIConnections() | |||||||
|     QObject::connect(ui->dsp, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_dsp_toggled); |     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->gain, &QDial::valueChanged, this, &LocalSinkGUI::on_gain_valueChanged); | ||||||
|     QObject::connect(ui->fft, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_fft_toggled); |     QObject::connect(ui->fft, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_fft_toggled); | ||||||
|  |     QObject::connect(ui->fftSize, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_fftSize_currentIndexChanged); | ||||||
|  |     QObject::connect(ui->fftWindow, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_fftWindow_currentIndexChanged); | ||||||
|     QObject::connect(ui->fftBandAdd, &QPushButton::clicked, this, &LocalSinkGUI::on_fftBandAdd_clicked); |     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->fftBandDel, &QPushButton::clicked, this, &LocalSinkGUI::on_fftBandDel_clicked); | ||||||
|     QObject::connect(ui->bandIndex, &QSlider::valueChanged, this, &LocalSinkGUI::on_bandIndex_valueChanged); |     QObject::connect(ui->bandIndex, &QSlider::valueChanged, this, &LocalSinkGUI::on_bandIndex_valueChanged); | ||||||
|  | |||||||
| @ -68,6 +68,7 @@ private: | |||||||
|     ChannelMarker m_channelMarker; |     ChannelMarker m_channelMarker; | ||||||
|     RollupState m_rollupState; |     RollupState m_rollupState; | ||||||
|     LocalSinkSettings m_settings; |     LocalSinkSettings m_settings; | ||||||
|  |     QList<QString> m_settingsKeys; | ||||||
|     int m_currentBandIndex; |     int m_currentBandIndex; | ||||||
|     bool m_showFilterHighCut; |     bool m_showFilterHighCut; | ||||||
|     qint64 m_deviceCenterFrequency; |     qint64 m_deviceCenterFrequency; | ||||||
| @ -111,6 +112,8 @@ private slots: | |||||||
|     void on_dsp_toggled(bool checked); |     void on_dsp_toggled(bool checked); | ||||||
|     void on_gain_valueChanged(int value); |     void on_gain_valueChanged(int value); | ||||||
|     void on_fft_toggled(bool checked); |     void on_fft_toggled(bool checked); | ||||||
|  |     void on_fftSize_currentIndexChanged(int index); | ||||||
|  |     void on_fftWindow_currentIndexChanged(int index); | ||||||
|     void on_fftBandAdd_clicked(); |     void on_fftBandAdd_clicked(); | ||||||
|     void on_fftBandDel_clicked(); |     void on_fftBandDel_clicked(); | ||||||
|     void on_bandIndex_valueChanged(int value); |     void on_bandIndex_valueChanged(int value); | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ void LocalSinkSettings::resetToDefaults() | |||||||
|     m_gaindB = 0; |     m_gaindB = 0; | ||||||
|     m_fftOn = false; |     m_fftOn = false; | ||||||
|     m_log2FFT = 10; |     m_log2FFT = 10; | ||||||
|     m_fftWindow = FFTWindow::Function::Bartlett; |     m_fftWindow = FFTWindow::Function::Rectangle; | ||||||
|     m_streamIndex = 0; |     m_streamIndex = 0; | ||||||
|     m_useReverseAPI = false; |     m_useReverseAPI = false; | ||||||
|     m_reverseAPIAddress = "127.0.0.1"; |     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()); | ||||||
|  | } | ||||||
|  | |||||||
| @ -61,6 +61,8 @@ struct LocalSinkSettings | |||||||
|     void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; } |     void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; } | ||||||
|     QByteArray serialize() const; |     QByteArray serialize() const; | ||||||
|     bool deserialize(const QByteArray& data); |     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_ */ | #endif /* INCLUDE_LOCALSINKSETTINGS_H_ */ | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ LocalSinkSink::LocalSinkSink() : | |||||||
|     m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(4000000)); |     m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(4000000)); | ||||||
|     // m_fftFilter = new fftfilt(0.1f, 0.4f, 1<<m_settings.m_log2FFT);
 |     // m_fftFilter = new fftfilt(0.1f, 0.4f, 1<<m_settings.m_log2FFT);
 | ||||||
|     m_fftFilter = new fftfilt(1<<m_settings.m_log2FFT); |     m_fftFilter = new fftfilt(1<<m_settings.m_log2FFT); | ||||||
|     applySettings(m_settings, true); |     applySettings(m_settings, QList<QString>(), true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| LocalSinkSink::~LocalSinkSink() | 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) |         for (SampleVector::const_iterator it = begin; it != end; ++it) | ||||||
|         { |         { | ||||||
|             Complex c(it->real(), it->imag()); |             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) |             if (rf_out > 0) | ||||||
|             { |             { | ||||||
| @ -182,28 +182,33 @@ void LocalSinkSink::stopWorker() | |||||||
| 	m_sinkWorkerThread.wait(); | 	m_sinkWorkerThread.wait(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkSink::applySettings(const LocalSinkSettings& settings, bool force) | void LocalSinkSink::applySettings(const LocalSinkSettings& settings, const QList<QString>& settingsKeys, bool force) | ||||||
| { | { | ||||||
|     qDebug() << "LocalSinkSink::applySettings:" |     qDebug() << "LocalSinkSink::applySettings:" << settings.getDebugString(settingsKeys, force) << " force: " << force; | ||||||
|             << " 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; |  | ||||||
| 
 | 
 | ||||||
|     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
 |         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) { |         delete m_fftFilter; | ||||||
|             m_fftFilter->create_filter(m_settings.m_fftBands, true, FFTWindow::Function::Rectangle); |         m_fftFilter = new fftfilt(1<<settings.m_log2FFT); | ||||||
|         } |         m_fftFilter->create_filter(m_settings.m_fftBands, true, m_settings.m_fftWindow); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (settingsKeys.contains("fftWindow") | ||||||
|  |      || settingsKeys.contains("fftBands") | ||||||
|  |      || force) | ||||||
|  |     { | ||||||
|  |         m_fftFilter->create_filter(settings.m_fftBands, true, settings.m_fftWindow); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (force) { | ||||||
|         m_settings = settings; |         m_settings = settings; | ||||||
|  |     } else { | ||||||
|  |         m_settings.applySettings(settingsKeys, settings); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSinkSink::setSampleRate(int sampleRate) | void LocalSinkSink::setSampleRate(int sampleRate) | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ public: | |||||||
| 	virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); | 	virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); | ||||||
| 
 | 
 | ||||||
|     void setSpectrumSink(SpectrumVis* spectrumSink) { m_spectrumSink = spectrumSink; } |     void setSpectrumSink(SpectrumVis* spectrumSink) { m_spectrumSink = spectrumSink; } | ||||||
|     void applySettings(const LocalSinkSettings& settings, bool force = false); |     void applySettings(const LocalSinkSettings& settings, const QList<QString>& settingsKeys, bool force = false); | ||||||
|     void start(DeviceSampleSource *deviceSource); |     void start(DeviceSampleSource *deviceSource); | ||||||
|     void stop(); |     void stop(); | ||||||
|     bool isRunning() const { return m_running; } |     bool isRunning() const { return m_running; } | ||||||
|  | |||||||
| @ -25,6 +25,9 @@ | |||||||
| //
 | //
 | ||||||
| // You should have received a copy of the GNU General Public License
 | // You should have received a copy of the GNU General Public License
 | ||||||
| // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
 | // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | //
 | ||||||
|  | // Augmented with more filter types
 | ||||||
|  | // Copyright (C) 2015-2022 Edouard Griffiths, F4EXB
 | ||||||
| // ----------------------------------------------------------------------------
 | // ----------------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| #include <memory.h> | #include <memory.h> | ||||||
| @ -38,7 +41,6 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <memory.h> |  | ||||||
| 
 | 
 | ||||||
| #include <dsp/misc.h> | #include <dsp/misc.h> | ||||||
| #include <dsp/fftfilt.h> | #include <dsp/fftfilt.h> | ||||||
| @ -157,7 +159,7 @@ void fftfilt::create_filter(float f1, float f2, FFTWindow::Function wf) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void fftfilt::create_filter(const std::vector<std::pair<float, float>>& limits, bool pass, FFTWindow::Function wf) | void fftfilt::create_filter(const std::vector<std::pair<float, float>>& limits, bool pass) | ||||||
| { | { | ||||||
| 	// initialize the filter canvas
 | 	// initialize the filter canvas
 | ||||||
|     std::vector<int> canvas(flen, pass ? 0 : 1); |     std::vector<int> canvas(flen, pass ? 0 : 1); | ||||||
| @ -186,58 +188,159 @@ void fftfilt::create_filter(const std::vector<std::pair<float, float>>& limits, | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::vector<std::pair<int,int>> indexes; |     for (int i = 0; i < flen; i++) { | ||||||
|     int c = 0; |  | ||||||
| 
 |  | ||||||
|     for (int i = 0; i < flen; i++) |  | ||||||
|     { |  | ||||||
|         if ((canvas[i] == 1) && (c == 0)) { |  | ||||||
|             indexes.push_back(std::pair<int,int>{i, 0}); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if ((canvas[i] == 0) && (c == 1)) { |  | ||||||
|             indexes.back().second = i; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         xfilter[i] = cmplx(canvas[i], 0); |         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
 |     // Rearrange
 | ||||||
|     std::copy(&xfilter[flen2], &xfilter[flen-1], filter); |     std::copy(&xfilter[flen2], &xfilter[flen-1], filter); | ||||||
|     std::copy(&xfilter[0], &xfilter[flen2-1], &filter[flen2]); |     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; |     delete[] xfilter; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void fftfilt::create_filter(const std::vector<std::pair<float, float>>& limits, bool pass, FFTWindow::Function wf) | ||||||
|  | { | ||||||
|  |     std::vector<int> canvasNeg(flen2, pass ? 0 : 1); // initialize the negative frequencies filter canvas
 | ||||||
|  |     std::vector<int> 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<std::pair<int,int>> indexesNegList; | ||||||
|  |     std::vector<std::pair<int,int>> 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<int,int>{i, 0}); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if ((canvasNeg[i] == 0) && (cn == 1)) { | ||||||
|  |             indexesNegList.back().second = i; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if ((canvasPos[i] == 1) && (cp == 0)) { | ||||||
|  |             indexesPosList.push_back(std::pair<int,int>{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
 | // 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) | void fftfilt::create_dsb_filter(float f2, FFTWindow::Function wf) | ||||||
| { | { | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ public: | |||||||
| // f1 > f2 ==> band reject
 | // f1 > f2 ==> band reject
 | ||||||
| 	void create_filter(float f1, float f2, FFTWindow::Function wf = FFTWindow::Blackman); | 	void create_filter(float f1, float f2, FFTWindow::Function wf = FFTWindow::Blackman); | ||||||
|     void create_filter(const std::vector<std::pair<float, float>>& limits, bool pass = true, FFTWindow::Function wf = FFTWindow::Blackman); |     void create_filter(const std::vector<std::pair<float, float>>& limits, bool pass = true, FFTWindow::Function wf = FFTWindow::Blackman); | ||||||
|  |     void create_filter(const std::vector<std::pair<float, float>>& limits, bool pass = true); //!< Windowless version
 | ||||||
| 	void create_dsb_filter(float f2, FFTWindow::Function wf = FFTWindow::Blackman); | 	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_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
 |     void create_rrc_filter(float fb, float a); //!< root raised cosine. fb is half the band pass
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user