mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -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) | ||||
| { | ||||
|     setObjectName(m_channelId); | ||||
|     applySettings(m_settings, true); | ||||
|     applySettings(m_settings, QList<QString>(), 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<QString>(), 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<QString>(), 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<QString>(), 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<QString>& 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<QString> 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<ObjectPipe*> 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<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(); | ||||
|     webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); | ||||
| @ -612,7 +592,7 @@ void LocalSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c | ||||
| 
 | ||||
| void LocalSink::sendChannelSettings( | ||||
|     const QList<ObjectPipe*>& pipes, | ||||
|     QList<QString>& channelSettingsKeys, | ||||
|     const QList<QString>& channelSettingsKeys, | ||||
|     const LocalSinkSettings& settings, | ||||
|     bool force) | ||||
| { | ||||
| @ -636,7 +616,7 @@ void LocalSink::sendChannelSettings( | ||||
| } | ||||
| 
 | ||||
| void LocalSink::webapiFormatChannelSettings( | ||||
|         QList<QString>& channelSettingsKeys, | ||||
|         const QList<QString>& 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<QString>{"localDeviceIndex"}); | ||||
| 
 | ||||
|     if (m_guiMessageQueue) | ||||
|     { | ||||
|         MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, false); | ||||
|         MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, QList<QString>{"localDeviceIndex"}, false); | ||||
|         m_guiMessageQueue->push(msg); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -44,19 +44,22 @@ public: | ||||
| 
 | ||||
|     public: | ||||
|         const LocalSinkSettings& getSettings() const { return m_settings; } | ||||
|         const QList<QString>& 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<QString>& settingsKeys, bool force) { | ||||
|             return new MsgConfigureLocalSink(settings, settingsKeys, force); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         LocalSinkSettings m_settings; | ||||
|         QList<QString> m_settingsKeys; | ||||
|         bool m_force; | ||||
| 
 | ||||
|         MsgConfigureLocalSink(const LocalSinkSettings& settings, bool force) : | ||||
|         MsgConfigureLocalSink(const LocalSinkSettings& settings, const QList<QString>& 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<QString>& 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<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force); | ||||
|     void webapiReverseSendSettings(const QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force); | ||||
|     void sendChannelSettings( | ||||
|         const QList<ObjectPipe*>& pipes, | ||||
|         QList<QString>& channelSettingsKeys, | ||||
|         const QList<QString>& channelSettingsKeys, | ||||
|         const LocalSinkSettings& settings, | ||||
|         bool force | ||||
|     ); | ||||
|     void webapiFormatChannelSettings( | ||||
|         QList<QString>& channelSettingsKeys, | ||||
|         const QList<QString>& channelSettingsKeys, | ||||
|         SWGSDRangel::SWGChannelSettings *swgChannelSettings, | ||||
|         const LocalSinkSettings& settings, | ||||
|         bool force | ||||
|  | ||||
| @ -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<QString>& 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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -39,20 +39,22 @@ public: | ||||
| 
 | ||||
|     public: | ||||
|         const LocalSinkSettings& getSettings() const { return m_settings; } | ||||
|         const QList<QString>& 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<QString>& settingsKeys, bool force) { | ||||
|             return new MsgConfigureLocalSinkBaseband(settings, settingsKeys, force); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         LocalSinkSettings m_settings; | ||||
|         QList<QString> m_settingsKeys; | ||||
|         bool m_force; | ||||
| 
 | ||||
|         MsgConfigureLocalSinkBaseband(const LocalSinkSettings& settings, bool force) : | ||||
|         MsgConfigureLocalSinkBaseband(const LocalSinkSettings& settings, const QList<QString>& 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<QString>& settingsKeys, bool force = false); | ||||
| 
 | ||||
| private slots: | ||||
|     void handleInputMessages(); | ||||
|  | ||||
| @ -82,7 +82,13 @@ bool LocalSinkGUI::handleMessage(const Message& message) | ||||
|     else if (LocalSink::MsgConfigureLocalSink::match(message)) | ||||
|     { | ||||
|         const LocalSink::MsgConfigureLocalSink& cfg = (LocalSink::MsgConfigureLocalSink&) message; | ||||
| 
 | ||||
|         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<const ChannelMarker*>(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<float,float>{-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<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->fftBandDel, &QPushButton::clicked, this, &LocalSinkGUI::on_fftBandDel_clicked); | ||||
|     QObject::connect(ui->bandIndex, &QSlider::valueChanged, this, &LocalSinkGUI::on_bandIndex_valueChanged); | ||||
|  | ||||
| @ -68,6 +68,7 @@ private: | ||||
|     ChannelMarker m_channelMarker; | ||||
|     RollupState m_rollupState; | ||||
|     LocalSinkSettings m_settings; | ||||
|     QList<QString> 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); | ||||
|  | ||||
| @ -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()); | ||||
| } | ||||
|  | ||||
| @ -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_ */ | ||||
|  | ||||
| @ -42,7 +42,7 @@ LocalSinkSink::LocalSinkSink() : | ||||
|     m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(4000000)); | ||||
|     // m_fftFilter = new fftfilt(0.1f, 0.4f, 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() | ||||
| @ -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<QString>& 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<<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; | ||||
|     } else { | ||||
|         m_settings.applySettings(settingsKeys, settings); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void LocalSinkSink::setSampleRate(int sampleRate) | ||||
|  | ||||
| @ -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<QString>& settingsKeys, bool force = false); | ||||
|     void start(DeviceSampleSource *deviceSource); | ||||
|     void stop(); | ||||
|     bool isRunning() const { return m_running; } | ||||
|  | ||||
| @ -25,6 +25,9 @@ | ||||
| //
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // 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> | ||||
| @ -38,7 +41,6 @@ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <sys/types.h> | ||||
| #include <memory.h> | ||||
| 
 | ||||
| #include <dsp/misc.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
 | ||||
|     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; | ||||
|     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; | ||||
|         } | ||||
| 
 | ||||
|     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<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
 | ||||
| void fftfilt::create_dsb_filter(float f2, FFTWindow::Function wf) | ||||
| { | ||||
|  | ||||
| @ -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<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_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
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user