kopia lustrzana https://github.com/f4exb/sdrangel
				
				
				
			Local Sink: added FFT filter bands
							rodzic
							
								
									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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue