1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-05-27 12:42:25 -04:00

Local Sink: added FFT filter bands

This commit is contained in:
f4exb 2022-12-12 07:50:35 +01:00
parent bf765a00ec
commit c42d163d3b
12 changed files with 408 additions and 136 deletions

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -82,7 +82,13 @@ bool LocalSinkGUI::handleMessage(const Message& message)
else if (LocalSink::MsgConfigureLocalSink::match(message))
{
const LocalSink::MsgConfigureLocalSink& cfg = (LocalSink::MsgConfigureLocalSink&) message;
m_settings = cfg.getSettings();
if (cfg.getForce()) {
m_settings = cfg.getSettings();
} else {
m_settings.applySettings(cfg.getSettingsKeys(), cfg.getSettings());
}
blockApplySettings(true);
ui->spectrumGUI->updateSettings();
m_channelMarker.updateSettings(static_cast<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);

View File

@ -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);

View File

@ -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());
}

View File

@ -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_ */

View File

@ -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);
}
m_settings = settings;
if (settingsKeys.contains("fftWindow")
|| settingsKeys.contains("fftBands")
|| force)
{
m_fftFilter->create_filter(settings.m_fftBands, true, settings.m_fftWindow);
}
if (force) {
m_settings = settings;
} else {
m_settings.applySettings(settingsKeys, settings);
}
}
void LocalSinkSink::setSampleRate(int sampleRate)

View File

@ -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; }

View File

@ -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)
{

View File

@ -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