1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-22 08:04:49 -05:00

Merge pull request #2214 from f4exb/feature-wdsp

Feature wdsp
This commit is contained in:
Edouard Griffiths 2024-07-21 04:11:52 +02:00 committed by GitHub
commit 02babd5ff8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 574 additions and 390 deletions

View File

@ -41,6 +41,8 @@ if(NOT SERVER_MODE)
wdsprxeqdialog.ui wdsprxeqdialog.ui
wdsprxfmdialog.cpp wdsprxfmdialog.cpp
wdsprxfmdialog.ui wdsprxfmdialog.ui
wdsprxpandialog.cpp
wdsprxpandialog.ui
wdsprxsquelchdialog.cpp wdsprxsquelchdialog.cpp
wdsprxsquelchdialog.ui wdsprxsquelchdialog.ui
wdsprxgui.cpp wdsprxgui.cpp
@ -56,6 +58,7 @@ if(NOT SERVER_MODE)
wdsprxdnrdialog.h wdsprxdnrdialog.h
wdsprxeqdialog.h wdsprxeqdialog.h
wdsprxfmdialog.h wdsprxfmdialog.h
wdsprxpandialog.h
wdsprxsquelchdialog.h wdsprxsquelchdialog.h
) )
set(TARGET_NAME wdsprx) set(TARGET_NAME wdsprx)

View File

@ -35,7 +35,7 @@ public:
}; };
explicit WDSPRxCWPeakDialog(QWidget* parent = nullptr); explicit WDSPRxCWPeakDialog(QWidget* parent = nullptr);
~WDSPRxCWPeakDialog(); ~WDSPRxCWPeakDialog() override;
void setCWPeakFrequency(double cwPeakFrequency); void setCWPeakFrequency(double cwPeakFrequency);
void setCWBandwidth(double cwBandwidth); void setCWBandwidth(double cwBandwidth);

View File

@ -39,7 +39,7 @@ public:
}; };
explicit WDSPRxDNBDialog(QWidget* parent = nullptr); explicit WDSPRxDNBDialog(QWidget* parent = nullptr);
~WDSPRxDNBDialog(); ~WDSPRxDNBDialog() override;
void setNBScheme(WDSPRxProfile::WDSPRxNBScheme scheme); void setNBScheme(WDSPRxProfile::WDSPRxNBScheme scheme);
void setNB2Mode(WDSPRxProfile::WDSPRxNB2Mode mode); void setNB2Mode(WDSPRxProfile::WDSPRxNB2Mode mode);

View File

@ -38,14 +38,6 @@ void WDSPRxDNRDialog::setSNB(bool snb)
m_snb = snb; m_snb = snb;
} }
void WDSPRxDNRDialog::setANF(bool anf)
{
ui->anf->blockSignals(true);
ui->anf->setChecked(anf);
ui->anf->blockSignals(false);
m_anf = anf;
}
void WDSPRxDNRDialog::setNRScheme(WDSPRxProfile::WDSPRxNRScheme scheme) void WDSPRxDNRDialog::setNRScheme(WDSPRxProfile::WDSPRxNRScheme scheme)
{ {
ui->nr->blockSignals(true); ui->nr->blockSignals(true);
@ -92,12 +84,6 @@ void WDSPRxDNRDialog::on_snb_clicked(bool checked)
emit valueChanged(ChangedSNB); emit valueChanged(ChangedSNB);
} }
void WDSPRxDNRDialog::on_anf_clicked(bool checked)
{
m_anf = checked;
emit valueChanged(ChangedANF);
}
void WDSPRxDNRDialog::on_nr_currentIndexChanged(int index) void WDSPRxDNRDialog::on_nr_currentIndexChanged(int index)
{ {
m_nrScheme = (WDSPRxProfile::WDSPRxNRScheme) index; m_nrScheme = (WDSPRxProfile::WDSPRxNRScheme) index;

View File

@ -30,7 +30,6 @@ class WDSPRxDNRDialog : public QDialog {
public: public:
enum ValueChanged { enum ValueChanged {
ChangedSNB, ChangedSNB,
ChangedANF,
ChangedNR, ChangedNR,
ChangedNR2Gain, ChangedNR2Gain,
ChangedNR2NPE, ChangedNR2NPE,
@ -39,10 +38,9 @@ public:
}; };
explicit WDSPRxDNRDialog(QWidget* parent = nullptr); explicit WDSPRxDNRDialog(QWidget* parent = nullptr);
~WDSPRxDNRDialog(); ~WDSPRxDNRDialog() override;
void setSNB(bool snb); void setSNB(bool snb);
void setANF(bool anf);
void setNRScheme(WDSPRxProfile::WDSPRxNRScheme scheme); void setNRScheme(WDSPRxProfile::WDSPRxNRScheme scheme);
void setNR2Gain(WDSPRxProfile::WDSPRxNR2Gain gain); void setNR2Gain(WDSPRxProfile::WDSPRxNR2Gain gain);
void setNR2NPE(WDSPRxProfile::WDSPRxNR2NPE nr2NPE); void setNR2NPE(WDSPRxProfile::WDSPRxNR2NPE nr2NPE);
@ -50,7 +48,6 @@ public:
void setNR2ArtifactReduction(bool nr2ArtifactReducion); void setNR2ArtifactReduction(bool nr2ArtifactReducion);
bool getSNB() const { return m_snb; } bool getSNB() const { return m_snb; }
bool getANF() const { return m_anf; }
WDSPRxProfile::WDSPRxNRScheme getNRScheme() const { return m_nrScheme; } WDSPRxProfile::WDSPRxNRScheme getNRScheme() const { return m_nrScheme; }
WDSPRxProfile::WDSPRxNR2Gain getNR2Gain() const { return m_nr2Gain; } WDSPRxProfile::WDSPRxNR2Gain getNR2Gain() const { return m_nr2Gain; }
WDSPRxProfile::WDSPRxNR2NPE getNR2NPE() const { return m_nr2NPE; } WDSPRxProfile::WDSPRxNR2NPE getNR2NPE() const { return m_nr2NPE; }
@ -63,7 +60,6 @@ signals:
private: private:
Ui::WDSPRxDNRDialog *ui; Ui::WDSPRxDNRDialog *ui;
bool m_snb; bool m_snb;
bool m_anf;
WDSPRxProfile::WDSPRxNRScheme m_nrScheme; WDSPRxProfile::WDSPRxNRScheme m_nrScheme;
WDSPRxProfile::WDSPRxNR2Gain m_nr2Gain; WDSPRxProfile::WDSPRxNR2Gain m_nr2Gain;
WDSPRxProfile::WDSPRxNR2NPE m_nr2NPE; WDSPRxProfile::WDSPRxNR2NPE m_nr2NPE;
@ -72,7 +68,6 @@ private:
private slots: private slots:
void on_snb_clicked(bool checked); void on_snb_clicked(bool checked);
void on_anf_clicked(bool checked);
void on_nr_currentIndexChanged(int index); void on_nr_currentIndexChanged(int index);
void on_nr2Gain_currentIndexChanged(int index); void on_nr2Gain_currentIndexChanged(int index);
void on_nr2NPE_currentIndexChanged(int index); void on_nr2NPE_currentIndexChanged(int index);

View File

@ -53,16 +53,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="anf">
<property name="toolTip">
<string>Automatic Notch Filter</string>
</property>
<property name="text">
<string>ANF</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">

View File

@ -35,7 +35,7 @@ public:
}; };
explicit WDSPRxEqDialog(QWidget* parent = nullptr); explicit WDSPRxEqDialog(QWidget* parent = nullptr);
~WDSPRxEqDialog(); ~WDSPRxEqDialog() override;
void setEqF(const std::array<float, 11>& eqF); void setEqF(const std::array<float, 11>& eqF);
void setEqG(const std::array<float, 11>& eqG); void setEqG(const std::array<float, 11>& eqG);

View File

@ -39,7 +39,7 @@ public:
}; };
explicit WDSPRxFMDialog(QWidget* parent = nullptr); explicit WDSPRxFMDialog(QWidget* parent = nullptr);
~WDSPRxFMDialog(); ~WDSPRxFMDialog() override;
void setDeviation(double deviation); void setDeviation(double deviation);
void setAFLow(double afLow); void setAFLow(double afLow);

View File

@ -45,6 +45,7 @@
#include "wdsprxcwpeakdialog.h" #include "wdsprxcwpeakdialog.h"
#include "wdsprxsquelchdialog.h" #include "wdsprxsquelchdialog.h"
#include "wdsprxeqdialog.h" #include "wdsprxeqdialog.h"
#include "wdsprxpandialog.h"
WDSPRxGUI* WDSPRxGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) WDSPRxGUI* WDSPRxGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel)
{ {
@ -238,6 +239,13 @@ void WDSPRxGUI::on_dnb_toggled(bool checked)
applySettings(); applySettings();
} }
void WDSPRxGUI::on_anf_toggled(bool checked)
{
m_settings.m_anf = checked;
m_settings.m_profiles[m_settings.m_profileIndex].m_anf = m_settings.m_anf;
applySettings();
}
void WDSPRxGUI::on_cwPeaking_toggled(bool checked) void WDSPRxGUI::on_cwPeaking_toggled(bool checked)
{ {
m_settings.m_cwPeaking = checked; m_settings.m_cwPeaking = checked;
@ -278,6 +286,7 @@ void WDSPRxGUI::on_rit_toggled(bool checked)
void WDSPRxGUI::on_ritFrequency_valueChanged(int value) void WDSPRxGUI::on_ritFrequency_valueChanged(int value)
{ {
m_settings.m_ritFrequency = value; m_settings.m_ritFrequency = value;
m_settings.m_profiles[m_settings.m_profileIndex].m_ritFrequency = m_settings.m_ritFrequency;
ui->ritFrequencyText->setText(tr("%1").arg(value)); ui->ritFrequencyText->setText(tr("%1").arg(value));
m_channelMarker.setShift(m_settings.m_rit ? value: 0); m_channelMarker.setShift(m_settings.m_rit ? value: 0);
applySettings(); applySettings();
@ -330,7 +339,7 @@ void WDSPRxGUI::on_profileIndex_valueChanged(int value)
return; return;
} }
ui->filterIndexText->setText(tr("%1").arg(value)); ui->profileIndexText->setText(tr("%1").arg(value));
m_settings.m_profileIndex = value; m_settings.m_profileIndex = value;
// Bandwidth setup // Bandwidth setup
ui->BW->setMaximum(480); ui->BW->setMaximum(480);
@ -517,29 +526,32 @@ WDSPRxGUI::WDSPRxGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam
m_spectrumVis->setGLSpectrum(ui->glSpectrum); m_spectrumVis->setGLSpectrum(ui->glSpectrum);
m_wdspRx->setMessageQueueToGUI(getInputMessageQueue()); m_wdspRx->setMessageQueueToGUI(getInputMessageQueue());
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute); m_audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect(const QPoint &))); connect(m_audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect(const QPoint &)));
CRightClickEnabler *agcRightClickEnabler = new CRightClickEnabler(ui->agc); m_agcRightClickEnabler = new CRightClickEnabler(ui->agc);
connect(agcRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(agcSetupDialog(const QPoint &))); connect(m_agcRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(agcSetupDialog(const QPoint &)));
CRightClickEnabler *dnbRightClickEnabler = new CRightClickEnabler(ui->dnb); m_dnbRightClickEnabler = new CRightClickEnabler(ui->dnb);
connect(dnbRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(dnbSetupDialog(const QPoint &))); connect(m_dnbRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(dnbSetupDialog(const QPoint &)));
CRightClickEnabler *dnrRightClickEnabler = new CRightClickEnabler(ui->dnr); m_dnrRightClickEnabler = new CRightClickEnabler(ui->dnr);
connect(dnrRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(dnrSetupDialog(const QPoint &))); connect(m_dnrRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(dnrSetupDialog(const QPoint &)));
CRightClickEnabler *cwPeakRightClickEnabler = new CRightClickEnabler(ui->cwPeaking); m_cwPeakRightClickEnabler = new CRightClickEnabler(ui->cwPeaking);
connect(cwPeakRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(cwPeakSetupDialog(const QPoint &))); connect(m_cwPeakRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(cwPeakSetupDialog(const QPoint &)));
CRightClickEnabler *squelchRightClickEnabler = new CRightClickEnabler(ui->squelch); m_squelchRightClickEnabler = new CRightClickEnabler(ui->squelch);
connect(squelchRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(squelchSetupDialog(const QPoint &))); connect(m_squelchRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(squelchSetupDialog(const QPoint &)));
CRightClickEnabler *equalizerRightClickEnabler = new CRightClickEnabler(ui->equalizer); m_equalizerRightClickEnabler = new CRightClickEnabler(ui->equalizer);
connect(equalizerRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(equalizerSetupDialog(const QPoint &))); connect(m_equalizerRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(equalizerSetupDialog(const QPoint &)));
CRightClickEnabler *demodRightClickEnabler = new CRightClickEnabler(ui->demod); m_panRightClickEnabler = new CRightClickEnabler(ui->audioBinaural);
connect(demodRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(demodSetupDialog(const QPoint &))); connect(m_panRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(panSetupDialog(const QPoint &)));
m_demodRightClickEnabler = new CRightClickEnabler(ui->demod);
connect(m_demodRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(demodSetupDialog(const QPoint &)));
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
@ -599,6 +611,15 @@ WDSPRxGUI::WDSPRxGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam
WDSPRxGUI::~WDSPRxGUI() WDSPRxGUI::~WDSPRxGUI()
{ {
delete ui; delete ui;
delete m_audioMuteRightClickEnabler;
delete m_agcRightClickEnabler;
delete m_dnbRightClickEnabler;
delete m_dnrRightClickEnabler;
delete m_cwPeakRightClickEnabler;
delete m_squelchRightClickEnabler;
delete m_equalizerRightClickEnabler;
delete m_panRightClickEnabler;
delete m_demodRightClickEnabler;
} }
bool WDSPRxGUI::blockApplySettings(bool block) bool WDSPRxGUI::blockApplySettings(bool block)
@ -816,6 +837,7 @@ void WDSPRxGUI::displaySettings()
ui->agcGainText->setText(s); ui->agcGainText->setText(s);
ui->dnr->setChecked(m_settings.m_dnr); ui->dnr->setChecked(m_settings.m_dnr);
ui->dnb->setChecked(m_settings.m_dnb); ui->dnb->setChecked(m_settings.m_dnb);
ui->anf->setChecked(m_settings.m_anf);
ui->cwPeaking->setChecked(m_settings.m_cwPeaking); ui->cwPeaking->setChecked(m_settings.m_cwPeaking);
ui->squelch->setChecked(m_settings.m_squelch); ui->squelch->setChecked(m_settings.m_squelch);
ui->squelchThreshold->setValue(m_settings.m_squelchThreshold); ui->squelchThreshold->setValue(m_settings.m_squelchThreshold);
@ -850,10 +872,10 @@ void WDSPRxGUI::displaySettings()
ui->spanLog2->blockSignals(true); ui->spanLog2->blockSignals(true);
ui->dsb->blockSignals(true); ui->dsb->blockSignals(true);
ui->BW->blockSignals(true); ui->BW->blockSignals(true);
ui->filterIndex->blockSignals(true); ui->profileIndex->blockSignals(true);
ui->filterIndex->setValue(m_settings.m_profileIndex); ui->profileIndex->setValue(m_settings.m_profileIndex);
ui->filterIndexText->setText(tr("%1").arg(m_settings.m_profileIndex)); ui->profileIndexText->setText(tr("%1").arg(m_settings.m_profileIndex));
ui->dsb->setChecked(m_settings.m_dsb); ui->dsb->setChecked(m_settings.m_dsb);
ui->spanLog2->setValue(1 + ui->spanLog2->maximum() - m_settings.m_profiles[m_settings.m_profileIndex].m_spanLog2); ui->spanLog2->setValue(1 + ui->spanLog2->maximum() - m_settings.m_profiles[m_settings.m_profileIndex].m_spanLog2);
@ -873,7 +895,7 @@ void WDSPRxGUI::displaySettings()
ui->spanLog2->blockSignals(false); ui->spanLog2->blockSignals(false);
ui->dsb->blockSignals(false); ui->dsb->blockSignals(false);
ui->BW->blockSignals(false); ui->BW->blockSignals(false);
ui->filterIndex->blockSignals(false); ui->profileIndex->blockSignals(false);
// The only one of the four signals triggering applyBandwidths will trigger it once only with all other values // The only one of the four signals triggering applyBandwidths will trigger it once only with all other values
// set correctly and therefore validate the settings and apply them to dependent widgets // set correctly and therefore validate the settings and apply them to dependent widgets
@ -938,7 +960,7 @@ void WDSPRxGUI::agcSetup(int iValueChanged)
return; return;
} }
WDSPRxAGCDialog::ValueChanged valueChanged = (WDSPRxAGCDialog::ValueChanged) iValueChanged; auto valueChanged = (WDSPRxAGCDialog::ValueChanged) iValueChanged;
switch (valueChanged) switch (valueChanged)
{ {
@ -986,7 +1008,7 @@ void WDSPRxGUI::dnbSetup(int32_t iValueChanged)
return; return;
} }
WDSPRxDNBDialog::ValueChanged valueChanged = (WDSPRxDNBDialog::ValueChanged) iValueChanged; auto valueChanged = (WDSPRxDNBDialog::ValueChanged) iValueChanged;
switch (valueChanged) switch (valueChanged)
{ {
@ -1035,7 +1057,6 @@ void WDSPRxGUI::dnrSetupDialog(const QPoint& p)
m_dnrDialog = new WDSPRxDNRDialog(); m_dnrDialog = new WDSPRxDNRDialog();
m_dnrDialog->move(p); m_dnrDialog->move(p);
m_dnrDialog->setSNB(m_settings.m_snb); m_dnrDialog->setSNB(m_settings.m_snb);
m_dnrDialog->setANF(m_settings.m_anf);
m_dnrDialog->setNRScheme(m_settings.m_nrScheme); m_dnrDialog->setNRScheme(m_settings.m_nrScheme);
m_dnrDialog->setNR2Gain(m_settings.m_nr2Gain); m_dnrDialog->setNR2Gain(m_settings.m_nr2Gain);
m_dnrDialog->setNR2NPE(m_settings.m_nr2NPE); m_dnrDialog->setNR2NPE(m_settings.m_nr2NPE);
@ -1054,7 +1075,7 @@ void WDSPRxGUI::dnrSetup(int32_t iValueChanged)
return; return;
} }
WDSPRxDNRDialog::ValueChanged valueChanged = (WDSPRxDNRDialog::ValueChanged) iValueChanged; auto valueChanged = (WDSPRxDNRDialog::ValueChanged) iValueChanged;
switch (valueChanged) switch (valueChanged)
{ {
@ -1063,11 +1084,6 @@ void WDSPRxGUI::dnrSetup(int32_t iValueChanged)
m_settings.m_profiles[m_settings.m_profileIndex].m_snb = m_settings.m_snb; m_settings.m_profiles[m_settings.m_profileIndex].m_snb = m_settings.m_snb;
applySettings(); applySettings();
break; break;
case WDSPRxDNRDialog::ValueChanged::ChangedANF:
m_settings.m_anf = m_dnrDialog->getANF();
m_settings.m_profiles[m_settings.m_profileIndex].m_anf = m_settings.m_anf;
applySettings();
break;
case WDSPRxDNRDialog::ValueChanged::ChangedNR: case WDSPRxDNRDialog::ValueChanged::ChangedNR:
m_settings.m_nrScheme = m_dnrDialog->getNRScheme(); m_settings.m_nrScheme = m_dnrDialog->getNRScheme();
m_settings.m_profiles[m_settings.m_profileIndex].m_nrScheme = m_settings.m_nrScheme; m_settings.m_profiles[m_settings.m_profileIndex].m_nrScheme = m_settings.m_nrScheme;
@ -1118,7 +1134,7 @@ void WDSPRxGUI::cwPeakSetup(int iValueChanged)
return; return;
} }
WDSPRxCWPeakDialog::ValueChanged valueChanged = (WDSPRxCWPeakDialog::ValueChanged) iValueChanged; auto valueChanged = (WDSPRxCWPeakDialog::ValueChanged) iValueChanged;
switch (valueChanged) switch (valueChanged)
{ {
@ -1181,7 +1197,7 @@ void WDSPRxGUI::amSetup(int iValueChanged)
return; return;
} }
WDSPRxAMDialog::ValueChanged valueChanged = (WDSPRxAMDialog::ValueChanged) iValueChanged; auto valueChanged = (WDSPRxAMDialog::ValueChanged) iValueChanged;
switch (valueChanged) switch (valueChanged)
{ {
@ -1201,7 +1217,7 @@ void WDSPRxGUI::fmSetup(int iValueChanged)
return; return;
} }
WDSPRxFMDialog::ValueChanged valueChanged = (WDSPRxFMDialog::ValueChanged) iValueChanged; auto valueChanged = (WDSPRxFMDialog::ValueChanged) iValueChanged;
switch (valueChanged) switch (valueChanged)
{ {
@ -1266,7 +1282,7 @@ void WDSPRxGUI::squelchSetup(int iValueChanged)
return; return;
} }
WDSPRxSquelchDialog::ValueChanged valueChanged = (WDSPRxSquelchDialog::ValueChanged) iValueChanged; auto valueChanged = (WDSPRxSquelchDialog::ValueChanged) iValueChanged;
switch (valueChanged) switch (valueChanged)
{ {
@ -1314,7 +1330,7 @@ void WDSPRxGUI::equalizerSetup(int iValueChanged)
return; return;
} }
WDSPRxEqDialog::ValueChanged valueChanged = (WDSPRxEqDialog::ValueChanged) iValueChanged; auto valueChanged = (WDSPRxEqDialog::ValueChanged) iValueChanged;
switch (valueChanged) switch (valueChanged)
{ {
@ -1333,6 +1349,38 @@ void WDSPRxGUI::equalizerSetup(int iValueChanged)
} }
} }
void WDSPRxGUI::panSetupDialog(const QPoint& p)
{
m_panDialog = new WDSPRxPanDialog();
m_panDialog->move(p);
m_panDialog->setPan(m_settings.m_audioPan);
QObject::connect(m_panDialog, &WDSPRxPanDialog::valueChanged, this, &WDSPRxGUI::panSetup);
m_panDialog->exec();
QObject::disconnect(m_panDialog, &WDSPRxPanDialog::valueChanged, this, &WDSPRxGUI::panSetup);
m_panDialog->deleteLater();
m_panDialog = nullptr;
}
void WDSPRxGUI::panSetup(int iValueChanged)
{
if (!m_panDialog) {
return;
}
auto valueChanged = (WDSPRxPanDialog::ValueChanged) iValueChanged;
switch (valueChanged)
{
case WDSPRxPanDialog::ChangedPan:
m_settings.m_audioPan = m_panDialog->getPan();
m_settings.m_profiles[m_settings.m_profileIndex].m_audioPan = m_settings.m_audioPan;
applySettings();
break;
default:
break;
}
}
void WDSPRxGUI::tick() void WDSPRxGUI::tick()
{ {
double powDbAvg, powDbPeak; double powDbAvg, powDbPeak;
@ -1379,12 +1427,14 @@ void WDSPRxGUI::makeUIConnections()
QObject::connect(ui->volume, &QDial::valueChanged, this, &WDSPRxGUI::on_volume_valueChanged); QObject::connect(ui->volume, &QDial::valueChanged, this, &WDSPRxGUI::on_volume_valueChanged);
QObject::connect(ui->agc, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_agc_toggled); QObject::connect(ui->agc, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_agc_toggled);
QObject::connect(ui->dnr, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_dnr_toggled); QObject::connect(ui->dnr, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_dnr_toggled);
QObject::connect(ui->dnb, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_dnb_toggled);
QObject::connect(ui->anf, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_anf_toggled);
QObject::connect(ui->agcGain, &QDial::valueChanged, this, &WDSPRxGUI::on_agcGain_valueChanged); QObject::connect(ui->agcGain, &QDial::valueChanged, this, &WDSPRxGUI::on_agcGain_valueChanged);
QObject::connect(ui->audioMute, &QToolButton::toggled, this, &WDSPRxGUI::on_audioMute_toggled); QObject::connect(ui->audioMute, &QToolButton::toggled, this, &WDSPRxGUI::on_audioMute_toggled);
QObject::connect(ui->spanLog2, &QSlider::valueChanged, this, &WDSPRxGUI::on_spanLog2_valueChanged); QObject::connect(ui->spanLog2, &QSlider::valueChanged, this, &WDSPRxGUI::on_spanLog2_valueChanged);
QObject::connect(ui->flipSidebands, &QPushButton::clicked, this, &WDSPRxGUI::on_flipSidebands_clicked); QObject::connect(ui->flipSidebands, &QPushButton::clicked, this, &WDSPRxGUI::on_flipSidebands_clicked);
QObject::connect(ui->fftWindow, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &WDSPRxGUI::on_fftWindow_currentIndexChanged); QObject::connect(ui->fftWindow, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &WDSPRxGUI::on_fftWindow_currentIndexChanged);
QObject::connect(ui->filterIndex, &QDial::valueChanged, this, &WDSPRxGUI::on_profileIndex_valueChanged); QObject::connect(ui->profileIndex, &QDial::valueChanged, this, &WDSPRxGUI::on_profileIndex_valueChanged);
QObject::connect(ui->demod, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &WDSPRxGUI::on_demod_currentIndexChanged); QObject::connect(ui->demod, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &WDSPRxGUI::on_demod_currentIndexChanged);
QObject::connect(ui->cwPeaking, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_cwPeaking_toggled); QObject::connect(ui->cwPeaking, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_cwPeaking_toggled);
QObject::connect(ui->squelch, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_squelch_toggled); QObject::connect(ui->squelch, &ButtonSwitch::toggled, this, &WDSPRxGUI::on_squelch_toggled);

View File

@ -42,8 +42,10 @@ class WDSPRxFMDialog;
class WDSPRxCWPeakDialog; class WDSPRxCWPeakDialog;
class WDSPRxSquelchDialog; class WDSPRxSquelchDialog;
class WDSPRxEqDialog; class WDSPRxEqDialog;
class WDSPRxPanDialog;
class SpectrumVis; class SpectrumVis;
class BasebandSampleSink; class BasebandSampleSink;
class CRightClickEnabler;
namespace Ui { namespace Ui {
class WDSPRxGUI; class WDSPRxGUI;
@ -105,6 +107,17 @@ private:
WDSPRxCWPeakDialog* m_cwPeakDialog; WDSPRxCWPeakDialog* m_cwPeakDialog;
WDSPRxSquelchDialog* m_squelchDialog; WDSPRxSquelchDialog* m_squelchDialog;
WDSPRxEqDialog* m_equalizerDialog; WDSPRxEqDialog* m_equalizerDialog;
WDSPRxPanDialog* m_panDialog;
CRightClickEnabler *m_audioMuteRightClickEnabler;
CRightClickEnabler *m_agcRightClickEnabler;
CRightClickEnabler *m_dnbRightClickEnabler;
CRightClickEnabler *m_dnrRightClickEnabler;
CRightClickEnabler *m_cwPeakRightClickEnabler;
CRightClickEnabler *m_squelchRightClickEnabler;
CRightClickEnabler *m_equalizerRightClickEnabler;
CRightClickEnabler *m_panRightClickEnabler;
CRightClickEnabler *m_demodRightClickEnabler;
QIcon m_iconDSBUSB; QIcon m_iconDSBUSB;
QIcon m_iconDSBLSB; QIcon m_iconDSBLSB;
@ -136,6 +149,7 @@ private slots:
void on_agc_toggled(bool checked); void on_agc_toggled(bool checked);
void on_dnr_toggled(bool checked); void on_dnr_toggled(bool checked);
void on_dnb_toggled(bool checked); void on_dnb_toggled(bool checked);
void on_anf_toggled(bool checked);
void on_agcGain_valueChanged(int value); void on_agcGain_valueChanged(int value);
void on_audioMute_toggled(bool checked); void on_audioMute_toggled(bool checked);
void on_spanLog2_valueChanged(int value); void on_spanLog2_valueChanged(int value);
@ -169,6 +183,8 @@ private slots:
void squelchSetup(int valueChanged); void squelchSetup(int valueChanged);
void equalizerSetupDialog(const QPoint& p); void equalizerSetupDialog(const QPoint& p);
void equalizerSetup(int valueChanged); void equalizerSetup(int valueChanged);
void panSetupDialog(const QPoint& p);
void panSetup(int valueChanged);
void tick(); void tick();
}; };

View File

@ -278,7 +278,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QDial" name="filterIndex"> <widget class="QDial" name="profileIndex">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>24</width> <width>24</width>
@ -303,7 +303,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="filterIndexText"> <widget class="QLabel" name="profileIndexText">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>10</width> <width>10</width>
@ -559,7 +559,7 @@
</size> </size>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Highpass filter cutoff frequency (SSB)</string> <string>Bandpass filter near (to 0) cutoff frequency (SSB)</string>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>-60</number> <number>-60</number>
@ -641,7 +641,7 @@
</size> </size>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Lowpass filter cutoff frequency</string> <string>Bandpass filter far (from 0) cutoff frequency</string>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>-60</number> <number>-60</number>
@ -989,6 +989,19 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="ButtonSwitch" name="anf">
<property name="toolTip">
<string>Toggle Automatic Notch Filter</string>
</property>
<property name="text">
<string>ANF</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item> <item>
<widget class="ButtonSwitch" name="cwPeaking"> <widget class="ButtonSwitch" name="cwPeaking">
<property name="toolTip"> <property name="toolTip">

View File

@ -0,0 +1,55 @@
///////////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2024 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////////
#include "wdsprxpandialog.h"
#include "ui_wdsprxpandialog.h"
WDSPRxPanDialog::WDSPRxPanDialog(QWidget* parent) :
QDialog(parent),
ui(new Ui::WDSPRxPanDialog)
{
ui->setupUi(this);
}
WDSPRxPanDialog::~WDSPRxPanDialog()
{
delete ui;
}
void WDSPRxPanDialog::setPan(double pan)
{
ui->pan->blockSignals(true);
ui->pan->setValue((int) ((pan - 0.5)*200.0));
ui->pan->blockSignals(false);
ui->panText->setText(tr("%1").arg(ui->pan->value()));
m_pan = pan;
}
void WDSPRxPanDialog::on_zero_clicked()
{
ui->pan->setValue(0);
ui->panText->setText(tr("%1").arg(ui->pan->value()));
m_pan = 0.5;
emit valueChanged(ChangedPan);
}
void WDSPRxPanDialog::on_pan_valueChanged(int value)
{
ui->panText->setText(tr("%1").arg(ui->pan->value()));
m_pan = 0.5 + (value / 200.0);
emit valueChanged(ChangedPan);
}

View File

@ -0,0 +1,53 @@
///////////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2024 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_WDSPRXPANDIALOG_H
#define INCLUDE_WDSPRXPANDIALOG_H
#include <QDialog>
#include "wdsprxsettings.h"
namespace Ui {
class WDSPRxPanDialog;
}
class WDSPRxPanDialog : public QDialog {
Q_OBJECT
public:
enum ValueChanged {
ChangedPan,
};
explicit WDSPRxPanDialog(QWidget* parent = nullptr);
~WDSPRxPanDialog() override;
void setPan(double pan);
double getPan() const { return m_pan; }
signals:
void valueChanged(int valueChanged);
private:
Ui::WDSPRxPanDialog *ui;
double m_pan;
private slots:
void on_zero_clicked();
void on_pan_valueChanged(int value);
};
#endif

View File

@ -0,0 +1,210 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WDSPRxPanDialog</class>
<widget class="QDialog" name="WDSPRxPanDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>385</width>
<height>111</height>
</rect>
</property>
<property name="windowTitle">
<string>Audio Pan</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="panLayout">
<item>
<widget class="QPushButton" name="zero">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Reset to 0 (center)</string>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="TickedSlider" name="pan">
<property name="toolTip">
<string>Pan value (%) negative: left positive: right</string>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>5</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="panText">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>-100</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="scaleLayout">
<item>
<widget class="QLabel" name="leftPad">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="leftText">
<property name="text">
<string>L</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="zeroText">
<property name="maximumSize">
<size>
<width>12</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rightText">
<property name="text">
<string>R</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rightPad">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>32</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>TickedSlider</class>
<extends>QSlider</extends>
<header>gui/tickedslider.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>WDSPRxPanDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>WDSPRxPanDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -44,6 +44,7 @@ void WDSPRxSettings::resetToDefaults()
m_demod = WDSPRxProfile::DemodSSB; m_demod = WDSPRxProfile::DemodSSB;
m_audioBinaural = false; m_audioBinaural = false;
m_audioFlipChannels = false; m_audioFlipChannels = false;
m_audioPan = 0.5;
m_dsb = false; m_dsb = false;
m_audioMute = false; m_audioMute = false;
m_dbOrS = true; m_dbOrS = true;
@ -127,6 +128,7 @@ QByteArray WDSPRxSettings::serialize() const
} }
s.writeU32( 5, m_rgbColor); s.writeU32( 5, m_rgbColor);
s.writeDouble( 6, m_audioPan);
s.writeBool( 7, m_dbOrS); s.writeBool( 7, m_dbOrS);
s.writeBool( 8, m_audioBinaural); s.writeBool( 8, m_audioBinaural);
s.writeBool( 9, m_audioFlipChannels); s.writeBool( 9, m_audioFlipChannels);
@ -227,6 +229,7 @@ QByteArray WDSPRxSettings::serialize() const
s.writeBool (106 + 100*i, (int) m_profiles[i].m_audioFlipChannels); s.writeBool (106 + 100*i, (int) m_profiles[i].m_audioFlipChannels);
s.writeBool (107 + 100*i, (int) m_profiles[i].m_dsb); s.writeBool (107 + 100*i, (int) m_profiles[i].m_dsb);
s.writeBool (108 + 100*i, (int) m_profiles[i].m_dbOrS); s.writeBool (108 + 100*i, (int) m_profiles[i].m_dbOrS);
s.writeDouble(109 + 100*i, m_profiles[i].m_audioPan);
// Filter // Filter
s.writeS32 (100 + 100*i, m_profiles[i].m_spanLog2); s.writeS32 (100 + 100*i, m_profiles[i].m_spanLog2);
s.writeS32 (101 + 100*i, m_profiles[i].m_highCutoff / 100.0); s.writeS32 (101 + 100*i, m_profiles[i].m_highCutoff / 100.0);
@ -335,6 +338,7 @@ bool WDSPRxSettings::deserialize(const QByteArray& data)
} }
d.readU32( 5, &m_rgbColor); d.readU32( 5, &m_rgbColor);
d.readDouble( 6, &m_audioPan, 0.5);
d.readBool( 7, &m_dbOrS, true); d.readBool( 7, &m_dbOrS, true);
d.readBool( 8, &m_audioBinaural, false); d.readBool( 8, &m_audioBinaural, false);
d.readBool( 9, &m_audioFlipChannels, false); d.readBool( 9, &m_audioFlipChannels, false);
@ -456,6 +460,7 @@ bool WDSPRxSettings::deserialize(const QByteArray& data)
d.readBool( 106 + 100*i, &m_profiles[i].m_audioFlipChannels, false); d.readBool( 106 + 100*i, &m_profiles[i].m_audioFlipChannels, false);
d.readBool( 107 + 100*i, &m_profiles[i].m_dsb, false); d.readBool( 107 + 100*i, &m_profiles[i].m_dsb, false);
d.readBool( 108 + 100*i, &m_profiles[i].m_dbOrS, true); d.readBool( 108 + 100*i, &m_profiles[i].m_dbOrS, true);
d.readDouble(109 + 100*i, &m_profiles[i].m_audioPan, 0.5);
// Filter // Filter
d.readS32 (100 + 100*i, &m_profiles[i].m_spanLog2, 3); d.readS32 (100 + 100*i, &m_profiles[i].m_spanLog2, 3);
d.readS32 (101 + 100*i, &tmp, 30); d.readS32 (101 + 100*i, &tmp, 30);

View File

@ -88,6 +88,7 @@ struct WDSPRxProfile
WDSPRxDemod m_demod; WDSPRxDemod m_demod;
bool m_audioBinaural; bool m_audioBinaural;
bool m_audioFlipChannels; bool m_audioFlipChannels;
double m_audioPan;
bool m_dsb; bool m_dsb;
bool m_dbOrS; bool m_dbOrS;
// Filter // Filter
@ -151,6 +152,7 @@ struct WDSPRxProfile
m_demod(DemodSSB), m_demod(DemodSSB),
m_audioBinaural(false), m_audioBinaural(false),
m_audioFlipChannels(false), m_audioFlipChannels(false),
m_audioPan(0.5),
m_dsb(false), m_dsb(false),
m_dbOrS(true), m_dbOrS(true),
m_spanLog2(3), m_spanLog2(3),
@ -214,6 +216,7 @@ struct WDSPRxSettings
// int m_spanLog2; // int m_spanLog2;
bool m_audioBinaural; bool m_audioBinaural;
bool m_audioFlipChannels; bool m_audioFlipChannels;
double m_audioPan;
bool m_dsb; bool m_dsb;
bool m_audioMute; bool m_audioMute;
bool m_dbOrS; bool m_dbOrS;

View File

@ -747,12 +747,18 @@ void WDSPRxSink::applySettings(const WDSPRxSettings& settings, bool force)
} }
if ((m_settings.m_audioBinaural != settings.m_audioBinaural) if ((m_settings.m_audioBinaural != settings.m_audioBinaural)
|| (m_settings.m_audioPan != settings.m_audioPan)
|| (m_settings.m_audioFlipChannels != settings.m_audioFlipChannels) || force) || (m_settings.m_audioFlipChannels != settings.m_audioFlipChannels) || force)
{ {
if (settings.m_audioBinaural) { if (settings.m_audioBinaural)
{
WDSP::PANEL::SetPanelCopy(*m_rxa, settings.m_audioFlipChannels ? 3 : 0); WDSP::PANEL::SetPanelCopy(*m_rxa, settings.m_audioFlipChannels ? 3 : 0);
} else { WDSP::PANEL::SetPanelPan(*m_rxa, settings.m_audioPan);
}
else
{
WDSP::PANEL::SetPanelCopy(*m_rxa, settings.m_audioFlipChannels ? 2 : 1); WDSP::PANEL::SetPanelCopy(*m_rxa, settings.m_audioFlipChannels ? 2 : 1);
WDSP::PANEL::SetPanelPan(*m_rxa, 0.5);
} }
} }

View File

@ -36,7 +36,7 @@ public:
}; };
explicit WDSPRxSquelchDialog(QWidget* parent = nullptr); explicit WDSPRxSquelchDialog(QWidget* parent = nullptr);
~WDSPRxSquelchDialog(); ~WDSPRxSquelchDialog() override;
void setMode(WDSPRxProfile::WDSPRxSquelchMode mode); void setMode(WDSPRxProfile::WDSPRxSquelchMode mode);
void setSSQLTauMute(double value); void setSSQLTauMute(double value);

View File

@ -134,14 +134,3 @@ if (MSVC)
endif() endif()
install(TARGETS wdsp DESTINATION ${INSTALL_LIB_DIR}) install(TARGETS wdsp DESTINATION ${INSTALL_LIB_DIR})
if (LINUX)
add_executable(wdsp_make_interface
make_interface.cpp
)
add_executable(wdsp_make_calculus
make_calculus.cpp
)
install(TARGETS wdsp_make_interface wdsp_make_calculus DESTINATION ${INSTALL_BIN_DIR})
endif()

View File

@ -437,7 +437,7 @@ void CFCOMP::SetCFCOMPPosition (TXA& txa, int pos)
void CFCOMP::SetCFCOMPprofile (TXA& txa, int nfreqs, float* F, float* G, float *E) void CFCOMP::SetCFCOMPprofile (TXA& txa, int nfreqs, float* F, float* G, float *E)
{ {
CFCOMP *a = txa.cfcomp.p; CFCOMP *a = txa.cfcomp.p;
a->nfreqs = nfreqs; a->nfreqs = nfreqs < 1 ? 1 : nfreqs;
delete[] (a->E); delete[] (a->E);
delete[] (a->F); delete[] (a->F);
delete[] (a->G); delete[] (a->G);
@ -450,9 +450,9 @@ void CFCOMP::SetCFCOMPprofile (TXA& txa, int nfreqs, float* F, float* G, float *
delete[] (a->ep); delete[] (a->ep);
delete[] (a->gp); delete[] (a->gp);
delete[] (a->fp); delete[] (a->fp);
a->fp = new float[a->nfreqs]; // (float *) malloc0 ((a->nfreqs + 2) * sizeof (float)); a->fp = new float[a->nfreqs + 2]; // (float *) malloc0 ((a->nfreqs + 2) * sizeof (float));
a->gp = new float[a->nfreqs]; // (float *) malloc0 ((a->nfreqs + 2) * sizeof (float)); a->gp = new float[a->nfreqs + 2]; // (float *) malloc0 ((a->nfreqs + 2) * sizeof (float));
a->ep = new float[a->nfreqs]; // (float *) malloc0 ((a->nfreqs + 2) * sizeof (float)); a->ep = new float[a->nfreqs + 2]; // (float *) malloc0 ((a->nfreqs + 2) * sizeof (float));
calc_comp(a); calc_comp(a);
} }

View File

@ -46,8 +46,23 @@ void CFIR::decalc_cfir (CFIR *a)
FIRCORE::destroy_fircore (a->p); FIRCORE::destroy_fircore (a->p);
} }
CFIR* CFIR::create_cfir (int run, int size, int nc, int mp, float* in, float* out, int runrate, int cicrate, CFIR* CFIR::create_cfir (
int DD, int R, int Pairs, float cutoff, int xtype, float xbw, int wintype) int run,
int size,
int nc,
int mp,
float* in,
float* out,
int runrate,
int cicrate,
int DD,
int R,
int Pairs,
double cutoff,
int xtype,
double xbw,
int wintype
)
// run: 0 - no action; 1 - operate // run: 0 - no action; 1 - operate
// size: number of complex samples in an input buffer to the CFIR filter // size: number of complex samples in an input buffer to the CFIR filter
// nc: number of filter coefficients // nc: number of filter coefficients
@ -130,7 +145,20 @@ void CFIR::setOutRate_cfir (CFIR *a, int rate)
calc_cfir (a); calc_cfir (a);
} }
float* CFIR::cfir_impulse (int N, int DD, int R, int Pairs, float runrate, float cicrate, float cutoff, int xtype, float xbw, int rtype, float scale, int wintype) float* CFIR::cfir_impulse (
int N,
int DD,
int R,
int Pairs,
double runrate,
double cicrate,
double cutoff,
int xtype,
double xbw,
int rtype,
double scale,
int wintype
)
{ {
// N: number of impulse response samples // N: number of impulse response samples
// DD: differential delay used in the CIC filter // DD: differential delay used in the CIC filter
@ -144,18 +172,18 @@ float* CFIR::cfir_impulse (int N, int DD, int R, int Pairs, float runrate, float
// rtype: 0 for real output, 1 for complex output // rtype: 0 for real output, 1 for complex output
// scale: scale factor to be applied to the output // scale: scale factor to be applied to the output
int i, j; int i, j;
float tmp, local_scale, ri, mag, fn; double tmp, local_scale, ri, mag, fn;
float* impulse; float* impulse;
float* A = new float[N]; // (float *) malloc0 (N * sizeof (float)); float* A = new float[N]; // (float *) malloc0 (N * sizeof (float));
float ft = cutoff / cicrate; // normalized cutoff frequency double ft = cutoff / cicrate; // normalized cutoff frequency
int u_samps = (N + 1) / 2; // number of unique samples, OK for odd or even N int u_samps = (N + 1) / 2; // number of unique samples, OK for odd or even N
int c_samps = (int)(cutoff / runrate * N) + (N + 1) / 2 - N / 2; // number of unique samples within bandpass, OK for odd or even N int c_samps = (int)(cutoff / runrate * N) + (N + 1) / 2 - N / 2; // number of unique samples within bandpass, OK for odd or even N
int x_samps = (int)(xbw / runrate * N); // number of unique samples in transition region, OK for odd or even N int x_samps = (int)(xbw / runrate * N); // number of unique samples in transition region, OK for odd or even N
float offset = 0.5 - 0.5 * (float)((N + 1) / 2 - N / 2); // sample offset from center, OK for odd or even N double offset = 0.5 - 0.5 * (float)((N + 1) / 2 - N / 2); // sample offset from center, OK for odd or even N
float* xistion = new float[x_samps + 1]; // (float *) malloc0 ((x_samps + 1) * sizeof (float)); double* xistion = new double[x_samps + 1]; // (float *) malloc0 ((x_samps + 1) * sizeof (float));
float delta = PI / (float)x_samps; double delta = PI / (float)x_samps;
float L = cicrate / runrate; double L = cicrate / runrate;
float phs = 0.0; double phs = 0.0;
for (i = 0; i <= x_samps; i++) for (i = 0; i <= x_samps; i++)
{ {
xistion[i] = 0.5 * (cos (phs) + 1.0); xistion[i] = 0.5 * (cos (phs) + 1.0);
@ -171,7 +199,8 @@ float* CFIR::cfir_impulse (int N, int DD, int R, int Pairs, float runrate, float
fn = ri / (L * (float)N); fn = ri / (L * (float)N);
if (fn <= ft) if (fn <= ft)
{ {
if (fn == 0.0) tmp = 1.0; if (fn == 0.0)
tmp = 1.0;
else if ((tmp = DD * R * sin (PI * fn / R) / sin (PI * DD * fn)) < 0.0) else if ((tmp = DD * R * sin (PI * fn / R) / sin (PI * DD * fn)) < 0.0)
tmp = -tmp; tmp = -tmp;
mag = pow (tmp, Pairs) * local_scale; mag = pow (tmp, Pairs) * local_scale;
@ -225,7 +254,8 @@ float* CFIR::cfir_impulse (int N, int DD, int R, int Pairs, float runrate, float
A[i] = A[u_samps - j]; A[i] = A[u_samps - j];
impulse = FIR::fir_fsamp (N, A, rtype, 1.0, wintype); impulse = FIR::fir_fsamp (N, A, rtype, 1.0, wintype);
// print_impulse ("cfirImpulse.txt", N, impulse, 1, 0); // print_impulse ("cfirImpulse.txt", N, impulse, 1, 0);
delete[] (A); delete[] A;
delete[] xistion;
return impulse; return impulse;
} }

View File

@ -49,10 +49,10 @@ public:
int DD; int DD;
int R; int R;
int Pairs; int Pairs;
float cutoff; double cutoff;
float scale; double scale;
int xtype; int xtype;
float xbw; double xbw;
int wintype; int wintype;
FIRCORE *p; FIRCORE *p;
@ -68,9 +68,9 @@ public:
int DD, int DD,
int R, int R,
int Pairs, int Pairs,
float cutoff, double cutoff,
int xtype, int xtype,
float xbw, double xbw,
int wintype int wintype
); );
static void destroy_cfir (CFIR *a); static void destroy_cfir (CFIR *a);
@ -85,13 +85,13 @@ public:
int DD, int DD,
int R, int R,
int Pairs, int Pairs,
float runrate, double runrate,
float cicrate, double cicrate,
float cutoff, double cutoff,
int xtype, int xtype,
float xbw, double xbw,
int rtype, int rtype,
float scale, double scale,
int wintype int wintype
); );
// TXA Properties // TXA Properties

View File

@ -1,90 +0,0 @@
/* channel.h
This file is part of a program that implements a Software-Defined Radio.
Copyright (C) 2013 Warren Pratt, NR0V
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
The author can be reached by email at
warren@wpratt.com
*/
#ifndef wdsp_channel_h
#define wdsp_channel_h
#include <QThread>
#include "export.h"
class WDSP_API Channel
{
public:
int type;
bool run; // thread running
int in_rate; // input samplerate
int out_rate; // output samplerate
int in_size; // input buffsize (complex samples) in a fexchange() operation
int dsp_rate; // sample rate for mainstream dsp processing
int dsp_size; // number complex samples processed per buffer in mainstream dsp processing
int dsp_insize; // size (complex samples) of the output of the r1 (input) buffer
int dsp_outsize; // size (complex samples) of the input of the r2 (output) buffer
int out_size; // output buffsize (complex samples) in a fexchange() operation
int state; // 0 for channel OFF; 1 for channel ON
float tdelayup;
float tslewup;
float tdelaydown;
float tslewdown;
int bfo; // 'block_for_output', block fexchange until output is available
volatile long flushflag;
QThread channelThread;
long upslew;
// struct //io buffers
// {
// IOB pc, pd, pe, pf; // copies for console calls, dsp, exchange, and flush thread
// volatile long ch_upslew;
// } iob;
static void create_channel (
int channel,
int in_size,
int dsp_size,
int input_samplerate,
int dsp_rate,
int output_samplerate,
int type,
int state,
float tdelayup,
float tslewup,
float tdelaydown,
float tslewdown,
int bfo
);
static void destroy_channel (int channel);
static void flush_channel (int channel);
// static void set_type (int channel, int type);
// static void SetInputBuffsize (int channel, int in_size);
// static void SetDSPBuffsize (int channel, int dsp_size);
// static void SetInputSamplerate (int channel, int samplerate);
// static void SetDSPSamplerate (int channel, int samplerate);
// static void SetOutputSamplerate (int channel, int samplerate);
// static void SetAllRates (int channel, int in_rate, int dsp_rate, int out_rate);
// static int SetChannelState (int channel, int state, int dmode);
};
#endif

View File

@ -233,7 +233,7 @@ void EMNR::interpM (double* res, double x, int nvals, double* xvals, double* yva
int idx = 0; int idx = 0;
double xllow, xlhigh, frac; double xllow, xlhigh, frac;
while (x >= xvals[idx]) while ((x >= xvals[idx]) && (idx < nvals - 1))
idx++; idx++;
xllow = log10 (xvals[idx - 1]); xllow = log10 (xvals[idx - 1]);

View File

@ -44,46 +44,60 @@ int EQP::fEQcompare (const void * a, const void * b)
return 1; return 1;
} }
float* EQP::eq_impulse (int N, int nfreqs, float* F, float* G, float samplerate, float scale, int ctfmode, int wintype) float* EQP::eq_impulse (int N, int nfreqs, float* F, float* G, double samplerate, double scale, int ctfmode, int wintype)
{ {
float* fp = new float[nfreqs + 2]; // (float *) malloc0 ((nfreqs + 2) * sizeof (float)); float* fp = new float[nfreqs + 2]; // (float *) malloc0 ((nfreqs + 2) * sizeof (float));
float* gp = new float[nfreqs + 2]; // (float *) malloc0 ((nfreqs + 2) * sizeof (float)); float* gp = new float[nfreqs + 2]; // (float *) malloc0 ((nfreqs + 2) * sizeof (float));
float* A = new float[N / 2 + 1]; // (float *) malloc0 ((N / 2 + 1) * sizeof (float)); float* A = new float[N / 2 + 1]; // (float *) malloc0 ((N / 2 + 1) * sizeof (float));
float* sary = new float[2 * nfreqs]; // (float *) malloc0 (2 * nfreqs * sizeof (float)); float* sary = new float[2 * nfreqs]; // (float *) malloc0 (2 * nfreqs * sizeof (float));
float gpreamp, f, frac; double gpreamp, f, frac;
float* impulse; float* impulse;
int i, j, mid; int i, j, mid;
fp[0] = 0.0; fp[0] = 0.0;
fp[nfreqs + 1] = 1.0; fp[nfreqs + 1] = 1.0;
gpreamp = G[0]; gpreamp = G[0];
for (i = 1; i <= nfreqs; i++) for (i = 1; i <= nfreqs; i++)
{ {
fp[i] = 2.0 * F[i] / samplerate; fp[i] = 2.0 * F[i] / samplerate;
if (fp[i] < 0.0) fp[i] = 0.0;
if (fp[i] > 1.0) fp[i] = 1.0; if (fp[i] < 0.0)
fp[i] = 0.0;
if (fp[i] > 1.0)
fp[i] = 1.0;
gp[i] = G[i]; gp[i] = G[i];
} }
for (i = 1, j = 0; i <= nfreqs; i++, j+=2) for (i = 1, j = 0; i <= nfreqs; i++, j+=2)
{ {
sary[j + 0] = fp[i]; sary[j + 0] = fp[i];
sary[j + 1] = gp[i]; sary[j + 1] = gp[i];
} }
qsort (sary, nfreqs, 2 * sizeof (float), fEQcompare); qsort (sary, nfreqs, 2 * sizeof (float), fEQcompare);
for (i = 1, j = 0; i <= nfreqs; i++, j+=2) for (i = 1, j = 0; i <= nfreqs; i++, j+=2)
{ {
fp[i] = sary[j + 0]; fp[i] = sary[j + 0];
gp[i] = sary[j + 1]; gp[i] = sary[j + 1];
} }
gp[0] = gp[1]; gp[0] = gp[1];
gp[nfreqs + 1] = gp[nfreqs]; gp[nfreqs + 1] = gp[nfreqs];
mid = N / 2; mid = N / 2;
j = 0; j = 0;
if (N & 1) if (N & 1)
{ {
for (i = 0; i <= mid; i++) for (i = 0; i <= mid; i++)
{ {
f = (float)i / (float)mid; f = (double)i / (double)mid;
while (f > fp[j + 1]) j++;
while ((f > fp[j + 1]) && (j < nfreqs))
j++;
frac = (f - fp[j]) / (fp[j + 1] - fp[j]); frac = (f - fp[j]) / (fp[j + 1] - fp[j]);
A[i] = pow (10.0, 0.05 * (frac * gp[j + 1] + (1.0 - frac) * gp[j] + gpreamp)) * scale; A[i] = pow (10.0, 0.05 * (frac * gp[j + 1] + (1.0 - frac) * gp[j] + gpreamp)) * scale;
} }
@ -92,36 +106,44 @@ float* EQP::eq_impulse (int N, int nfreqs, float* F, float* G, float samplerate,
{ {
for (i = 0; i < mid; i++) for (i = 0; i < mid; i++)
{ {
f = ((float)i + 0.5) / (float)mid; f = ((double)i + 0.5) / (double)mid;
while (f > fp[j + 1]) j++;
while ((f > fp[j + 1]) && (j < nfreqs))
j++;
frac = (f - fp[j]) / (fp[j + 1] - fp[j]); frac = (f - fp[j]) / (fp[j + 1] - fp[j]);
A[i] = pow (10.0, 0.05 * (frac * gp[j + 1] + (1.0 - frac) * gp[j] + gpreamp)) * scale; A[i] = pow (10.0, 0.05 * (frac * gp[j + 1] + (1.0 - frac) * gp[j] + gpreamp)) * scale;
} }
} }
if (ctfmode == 0) if (ctfmode == 0)
{ {
int k, low, high; int k, low, high;
float lowmag, highmag, flow4, fhigh4; double lowmag, highmag, flow4, fhigh4;
if (N & 1) if (N & 1)
{ {
low = (int)(fp[1] * mid); low = (int)(fp[1] * mid);
high = (int)(fp[nfreqs] * mid + 0.5); high = (int)(fp[nfreqs] * mid + 0.5);
lowmag = A[low]; lowmag = A[low];
highmag = A[high]; highmag = A[high];
flow4 = pow((float)low / (float)mid, 4.0); flow4 = pow((double)low / (double)mid, 4.0);
fhigh4 = pow((float)high / (float)mid, 4.0); fhigh4 = pow((double)high / (double)mid, 4.0);
k = low; k = low;
while (--k >= 0) while (--k >= 0)
{ {
f = (float)k / (float)mid; f = (double)k / (double)mid;
lowmag *= (f * f * f * f) / flow4; lowmag *= (f * f * f * f) / flow4;
if (lowmag < 1.0e-20) lowmag = 1.0e-20; if (lowmag < 1.0e-20) lowmag = 1.0e-20;
A[k] = lowmag; A[k] = lowmag;
} }
k = high; k = high;
while (++k <= mid) while (++k <= mid)
{ {
f = (float)k / (float)mid; f = (double)k / (double)mid;
highmag *= fhigh4 / (f * f * f * f); highmag *= fhigh4 / (f * f * f * f);
if (highmag < 1.0e-20) highmag = 1.0e-20; if (highmag < 1.0e-20) highmag = 1.0e-20;
A[k] = highmag; A[k] = highmag;
@ -133,30 +155,35 @@ float* EQP::eq_impulse (int N, int nfreqs, float* F, float* G, float samplerate,
high = (int)(fp[nfreqs] * mid - 0.5); high = (int)(fp[nfreqs] * mid - 0.5);
lowmag = A[low]; lowmag = A[low];
highmag = A[high]; highmag = A[high];
flow4 = pow((float)low / (float)mid, 4.0); flow4 = pow((double)low / (double)mid, 4.0);
fhigh4 = pow((float)high / (float)mid, 4.0); fhigh4 = pow((double)high / (double)mid, 4.0);
k = low; k = low;
while (--k >= 0) while (--k >= 0)
{ {
f = (float)k / (float)mid; f = (double)k / (double)mid;
lowmag *= (f * f * f * f) / flow4; lowmag *= (f * f * f * f) / flow4;
if (lowmag < 1.0e-20) lowmag = 1.0e-20; if (lowmag < 1.0e-20) lowmag = 1.0e-20;
A[k] = lowmag; A[k] = lowmag;
} }
k = high; k = high;
while (++k < mid) while (++k < mid)
{ {
f = (float)k / (float)mid; f = (double)k / (double)mid;
highmag *= fhigh4 / (f * f * f * f); highmag *= fhigh4 / (f * f * f * f);
if (highmag < 1.0e-20) highmag = 1.0e-20; if (highmag < 1.0e-20) highmag = 1.0e-20;
A[k] = highmag; A[k] = highmag;
} }
} }
} }
if (N & 1) if (N & 1)
impulse = FIR::fir_fsamp_odd(N, A, 1, 1.0, wintype); impulse = FIR::fir_fsamp_odd(N, A, 1, 1.0, wintype);
else else
impulse = FIR::fir_fsamp(N, A, 1, 1.0, wintype); impulse = FIR::fir_fsamp(N, A, 1, 1.0, wintype);
// print_impulse("eq.txt", N, impulse, 1, 0); // print_impulse("eq.txt", N, impulse, 1, 0);
delete[] (sary); delete[] (sary);
delete[] (A); delete[] (A);

View File

@ -56,7 +56,7 @@ public:
float* G; float* G;
int ctfmode; int ctfmode;
int wintype; int wintype;
float samplerate; double samplerate;
FIRCORE *p; FIRCORE *p;
static EQP* create_eqp ( static EQP* create_eqp (
@ -73,7 +73,7 @@ public:
int wintype, int wintype,
int samplerate int samplerate
); );
static float* eq_impulse (int N, int nfreqs, float* F, float* G, float samplerate, float scale, int ctfmode, int wintype); static float* eq_impulse (int N, int nfreqs, float* F, float* G, double samplerate, double scale, int ctfmode, int wintype);
static void destroy_eqp (EQP *a); static void destroy_eqp (EQP *a);
static void flush_eqp (EQP *a); static void flush_eqp (EQP *a);
static void xeqp (EQP *a); static void xeqp (EQP *a);

View File

@ -318,8 +318,8 @@ float *FIR::fir_read (int N, const char *filename, int rtype, float scale)
void FIR::analytic (int N, float* in, float* out) void FIR::analytic (int N, float* in, float* out)
{ {
int i; int i;
float inv_N = 1.0 / (float) N; double inv_N = 1.0 / (double) N;
float two_inv_N = 2.0 * inv_N; double two_inv_N = 2.0 * inv_N;
float* x = new float[N * 2]; // (float *) malloc0 (N * sizeof (complex)); float* x = new float[N * 2]; // (float *) malloc0 (N * sizeof (complex));
fftwf_plan pfor = fftwf_plan_dft_1d ( fftwf_plan pfor = fftwf_plan_dft_1d (
N, N,

View File

@ -1,63 +0,0 @@
/*
* make_calculus
*
* This program reads the contents of the binary WDSP file "calculus"
* and dumps the data as two arrays of floating-point numbers
*
* The output is intended to be part of the file "calculus.c" which
* initializes these arrays (static data) for use with "memcpy"
* in emnr.c.
*
* Should the WDSP file "calculus" be changed, "calculus.c" should
* be re-generated using this program.
*
* return values of main()
*
* 0 all OK
* -1 sizeof(float) is not 8
* -2 error opening file "calculus"
* -3 read error
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd;
int i,j;
float d;
if (sizeof(float) != 8) {
printf("Data type DOUBLE is not 8-byte. Please check!\n");
return -1;
}
fd=open ("calculus", O_RDONLY);
if (fd < 0) {
printf("Could not open file 'calculus'\n");
return -2;
}
for (j=0; j<2; j++) {
switch (j) {
case 0:
printf("float GG[241*241]={\n");
break;
case 1:
printf("float GGS[241*241]={\n");
break;
}
for (i=0; i< 241*241; i++) {
if (read(fd, &d, 8) != 8) {
printf("READ ERROR\n");
return -3;
}
if (i == 241*241 -1) {
printf("%30.25f};\n", d);
} else {
printf("%30.25f,\n", d);
}
}
return 0;
}
}

View File

@ -1,101 +0,0 @@
/*
The purpose of this file is to extract interfaces from the WDSP source code.
The interfaces have the following form:
PORT blabla
firstline
secondline
{
where there may be an arbitrary number of lines between the line
containing "PORT" and the line starting with "{". This has to be
converted to
extern blabla firstline
secondline;
That is, the first line is prepended by "extern", and the last line is closed
with a semicolon. Comments starting with '//' are omitted, and lines starting
with '//' are ignored.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void trimm(char *line, size_t maxlen);
int main(int argc, char **argv)
{
FILE *infile;
int i;
int first_in_file;
int first_in_decl;
char line[1000];
size_t linesize=999;
char *buffer=line;
for (i=1; i<argc; i++) {
infile=fopen(argv[i],"r");
if (infile == NULL) continue;
first_in_file=1;
for (;;) {
if (getline(&buffer, &linesize, infile) < 0) break;
trimm(line, linesize);
if (strncmp(line,"PORT", 4) != 0) continue;
// found an interface
if (first_in_file) {
printf("\n//\n// Interfaces from %s\n//\n\n", argv[i]);
first_in_file=0;
}
if (strlen(line) >4) {
printf("extern %s ", line+4);
} else {
printf("extern ");
}
first_in_decl=1;
for (;;) {
if (getline(&buffer, &linesize, infile) < 0) {
fprintf(stderr,"! Found a PORT but found EOF while scanning interface.\n");
return 8;
}
trimm(line, linesize);
if (line[0] == 0) continue;
if (line[0] == '{') {
printf(";\n");
break;
} else {
if (first_in_decl) {
printf("%s", line);
first_in_decl=0;
} else {
printf("\n%s", line);
}
}
}
}
fclose(infile);
}
return 0;
}
void trimm(char *line, size_t maxlen) {
int len;
//
// Remove comments starting with '//'
//
len=strnlen(line,maxlen);
for (int i=0; i< len-1; i++) {
if (line[i] == '/' && line[i+1] == '/') line[i]=0;
}
//
// Remove trailing white space and newlines
//
len=strnlen(line,maxlen);
line[len--]=0;
while (len >= 0 && (line[len] == ' ' || line[len] == '\t' || line[len]== '\n')) line[len--]=0;
}

View File

@ -132,6 +132,7 @@ int NBP::make_nbp (
else else
{ {
nbp = 0; nbp = 0;
delete[] del;
return nbp; return nbp;
} }
*havnotch = 0; *havnotch = 0;

View File

@ -60,6 +60,9 @@ void RESAMPLE::calc_resample (RESAMPLE *a)
a->L = a->out_rate / x; a->L = a->out_rate / x;
a->M = a->in_rate / x; a->M = a->in_rate / x;
a->L <= 0 ? 1 : a->L;
a->M <= 0 ? 1 : a->M;
if (a->in_rate < a->out_rate) if (a->in_rate < a->out_rate)
min_rate = a->in_rate; min_rate = a->in_rate;
else else

View File

@ -64,6 +64,9 @@ RESAMPLEF* RESAMPLEF::create_resampleF ( int run, int size, float* in, float* ou
a->L = out_rate / x; a->L = out_rate / x;
a->M = in_rate / x; a->M = in_rate / x;
a->L <= 0 ? 1 : a->L;
a->M <= 0 ? 1 : a->M;
if (in_rate < out_rate) if (in_rate < out_rate)
min_rate = in_rate; min_rate = in_rate;
else else