mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-10-01 01:06:35 -04:00
Audio modulators audio feedback: AM, NFM, SSB. Removed existing changes for FreeDV and WFM
This commit is contained in:
parent
68f6994f49
commit
6d3ab1a730
@ -57,7 +57,7 @@ AMMod::AMMod(DeviceAPI *deviceAPI) :
|
|||||||
m_outputSampleRate(48000),
|
m_outputSampleRate(48000),
|
||||||
m_inputFrequencyOffset(0),
|
m_inputFrequencyOffset(0),
|
||||||
m_audioFifo(4800),
|
m_audioFifo(4800),
|
||||||
m_feedbackAudioFifo(4800),
|
m_feedbackAudioFifo(48000),
|
||||||
m_settingsMutex(QMutex::Recursive),
|
m_settingsMutex(QMutex::Recursive),
|
||||||
m_fileSize(0),
|
m_fileSize(0),
|
||||||
m_recordLength(0),
|
m_recordLength(0),
|
||||||
@ -81,6 +81,7 @@ AMMod::AMMod(DeviceAPI *deviceAPI) :
|
|||||||
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
||||||
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
||||||
|
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
|
||||||
|
|
||||||
m_toneNco.setFreq(1000.0, m_audioSampleRate);
|
m_toneNco.setFreq(1000.0, m_audioSampleRate);
|
||||||
m_cwKeyer.setSampleRate(m_audioSampleRate);
|
m_cwKeyer.setSampleRate(m_audioSampleRate);
|
||||||
@ -174,6 +175,11 @@ void AMMod::modulateSample()
|
|||||||
Real t;
|
Real t;
|
||||||
|
|
||||||
pullAF(t);
|
pullAF(t);
|
||||||
|
|
||||||
|
if (m_settings.m_feedbackAudioEnable) {
|
||||||
|
pushFeedback(t * m_settings.m_feedbackVolumeFactor * 16384.0f);
|
||||||
|
}
|
||||||
|
|
||||||
calculateLevel(t);
|
calculateLevel(t);
|
||||||
m_audioBufferFill++;
|
m_audioBufferFill++;
|
||||||
|
|
||||||
@ -248,6 +254,50 @@ void AMMod::pullAF(Real& sample)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AMMod::pushFeedback(Real sample)
|
||||||
|
{
|
||||||
|
Complex c(sample, sample);
|
||||||
|
Complex ci;
|
||||||
|
|
||||||
|
if (m_feedbackInterpolatorDistance < 1.0f) // interpolate
|
||||||
|
{
|
||||||
|
while (!m_feedbackInterpolator.interpolate(&m_feedbackInterpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_feedbackInterpolatorDistanceRemain += m_feedbackInterpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // decimate
|
||||||
|
{
|
||||||
|
if (m_feedbackInterpolator.decimate(&m_feedbackInterpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_feedbackInterpolatorDistanceRemain += m_feedbackInterpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMMod::processOneSample(Complex& ci)
|
||||||
|
{
|
||||||
|
m_feedbackAudioBuffer[m_feedbackAudioBufferFill].l = ci.real();
|
||||||
|
m_feedbackAudioBuffer[m_feedbackAudioBufferFill].r = ci.imag();
|
||||||
|
++m_feedbackAudioBufferFill;
|
||||||
|
|
||||||
|
if (m_feedbackAudioBufferFill >= m_feedbackAudioBuffer.size())
|
||||||
|
{
|
||||||
|
uint res = m_feedbackAudioFifo.write((const quint8*)&m_feedbackAudioBuffer[0], m_feedbackAudioBufferFill);
|
||||||
|
|
||||||
|
if (res != m_feedbackAudioBufferFill)
|
||||||
|
{
|
||||||
|
qDebug("AMDemod::pushFeedback: %u/%u audio samples written m_feedbackInterpolatorDistance: %f",
|
||||||
|
res, m_feedbackAudioBufferFill, m_feedbackInterpolatorDistance);
|
||||||
|
m_feedbackAudioFifo.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_feedbackAudioBufferFill = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AMMod::calculateLevel(Real& sample)
|
void AMMod::calculateLevel(Real& sample)
|
||||||
{
|
{
|
||||||
if (m_levelCalcCount < m_levelNbSamples)
|
if (m_levelCalcCount < m_levelNbSamples)
|
||||||
@ -361,13 +411,24 @@ bool AMMod::handleMessage(const Message& cmd)
|
|||||||
{
|
{
|
||||||
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
||||||
uint32_t sampleRate = cfg.getSampleRate();
|
uint32_t sampleRate = cfg.getSampleRate();
|
||||||
|
DSPConfigureAudio::AudioType audioType = cfg.getAudioType();
|
||||||
|
|
||||||
qDebug() << "AMMod::handleMessage: DSPConfigureAudio:"
|
qDebug() << "AMMod::handleMessage: DSPConfigureAudio:"
|
||||||
<< " sampleRate: " << sampleRate;
|
<< " sampleRate: " << sampleRate
|
||||||
|
<< " audioType: " << audioType;
|
||||||
|
|
||||||
|
if (audioType == DSPConfigureAudio::AudioInput)
|
||||||
|
{
|
||||||
if (sampleRate != m_audioSampleRate) {
|
if (sampleRate != m_audioSampleRate) {
|
||||||
applyAudioSampleRate(sampleRate);
|
applyAudioSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (audioType == DSPConfigureAudio::AudioOutput)
|
||||||
|
{
|
||||||
|
if (sampleRate != m_audioSampleRate) {
|
||||||
|
applyFeedbackAudioSampleRate(sampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -436,6 +497,24 @@ void AMMod::applyAudioSampleRate(int sampleRate)
|
|||||||
m_settingsMutex.unlock();
|
m_settingsMutex.unlock();
|
||||||
|
|
||||||
m_audioSampleRate = sampleRate;
|
m_audioSampleRate = sampleRate;
|
||||||
|
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMMod::applyFeedbackAudioSampleRate(unsigned int sampleRate)
|
||||||
|
{
|
||||||
|
qDebug("AMMod::applyFeedbackAudioSampleRate: %u", sampleRate);
|
||||||
|
|
||||||
|
m_settingsMutex.lock();
|
||||||
|
|
||||||
|
m_feedbackInterpolatorDistanceRemain = 0;
|
||||||
|
m_feedbackInterpolatorConsumed = false;
|
||||||
|
m_feedbackInterpolatorDistance = (Real) sampleRate / (Real) m_audioSampleRate;
|
||||||
|
Real cutoff = std::min(sampleRate, m_audioSampleRate) / 2.2f;
|
||||||
|
m_feedbackInterpolator.create(48, sampleRate, cutoff, 3.0);
|
||||||
|
|
||||||
|
m_settingsMutex.unlock();
|
||||||
|
|
||||||
|
m_feedbackAudioSampleRate = sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AMMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
|
void AMMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
|
||||||
@ -546,6 +625,20 @@ void AMMod::applySettings(const AMModSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((settings.m_feedbackAudioDeviceName != m_settings.m_feedbackAudioDeviceName) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("feedbackAudioDeviceName");
|
||||||
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
|
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_feedbackAudioDeviceName);
|
||||||
|
audioDeviceManager->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue(), audioDeviceIndex);
|
||||||
|
uint32_t audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
|
||||||
|
|
||||||
|
if (m_feedbackAudioSampleRate != audioSampleRate) {
|
||||||
|
reverseAPIKeys.append("feedbackAudioSampleRate");
|
||||||
|
applyFeedbackAudioSampleRate(audioSampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (settings.m_useReverseAPI)
|
if (settings.m_useReverseAPI)
|
||||||
{
|
{
|
||||||
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||||
|
@ -277,11 +277,17 @@ private:
|
|||||||
NCO m_carrierNco;
|
NCO m_carrierNco;
|
||||||
NCOF m_toneNco;
|
NCOF m_toneNco;
|
||||||
Complex m_modSample;
|
Complex m_modSample;
|
||||||
|
|
||||||
Interpolator m_interpolator;
|
Interpolator m_interpolator;
|
||||||
Real m_interpolatorDistance;
|
Real m_interpolatorDistance;
|
||||||
Real m_interpolatorDistanceRemain;
|
Real m_interpolatorDistanceRemain;
|
||||||
bool m_interpolatorConsumed;
|
bool m_interpolatorConsumed;
|
||||||
|
|
||||||
|
Interpolator m_feedbackInterpolator;
|
||||||
|
Real m_feedbackInterpolatorDistance;
|
||||||
|
Real m_feedbackInterpolatorDistanceRemain;
|
||||||
|
bool m_feedbackInterpolatorConsumed;
|
||||||
|
|
||||||
double m_magsq;
|
double m_magsq;
|
||||||
MovingAverageUtil<double, double, 16> m_movingAverage;
|
MovingAverageUtil<double, double, 16> m_movingAverage;
|
||||||
|
|
||||||
@ -315,9 +321,12 @@ private:
|
|||||||
QNetworkRequest m_networkRequest;
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
|
void applyFeedbackAudioSampleRate(unsigned int sampleRate);
|
||||||
|
void processOneSample(Complex& ci);
|
||||||
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
|
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
|
||||||
void applySettings(const AMModSettings& settings, bool force = false);
|
void applySettings(const AMModSettings& settings, bool force = false);
|
||||||
void pullAF(Real& sample);
|
void pullAF(Real& sample);
|
||||||
|
void pushFeedback(Real sample);
|
||||||
void calculateLevel(Real& sample);
|
void calculateLevel(Real& sample);
|
||||||
void modulateSample();
|
void modulateSample();
|
||||||
void openFileStream();
|
void openFileStream();
|
||||||
|
@ -236,6 +236,19 @@ void AMModGUI::on_mic_toggled(bool checked)
|
|||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AMModGUI::on_feedbackEnable_toggled(bool checked)
|
||||||
|
{
|
||||||
|
m_settings.m_feedbackAudioEnable = checked;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMModGUI::on_feedbackVolume_valueChanged(int value)
|
||||||
|
{
|
||||||
|
ui->feedbackVolumeText->setText(QString("%1").arg(value / 100.0, 0, 'f', 2));
|
||||||
|
m_settings.m_feedbackVolumeFactor = value / 100.0;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
void AMModGUI::on_navTimeSlider_valueChanged(int value)
|
void AMModGUI::on_navTimeSlider_valueChanged(int value)
|
||||||
{
|
{
|
||||||
if (m_enableNavTime && ((value >= 0) && (value <= 100)))
|
if (m_enableNavTime && ((value >= 0) && (value <= 100)))
|
||||||
@ -440,6 +453,10 @@ void AMModGUI::displaySettings()
|
|||||||
ui->play->setChecked(m_settings.m_modAFInput == AMModSettings::AMModInputAF::AMModInputFile);
|
ui->play->setChecked(m_settings.m_modAFInput == AMModSettings::AMModInputAF::AMModInputFile);
|
||||||
ui->morseKeyer->setChecked(m_settings.m_modAFInput == AMModSettings::AMModInputAF::AMModInputCWTone);
|
ui->morseKeyer->setChecked(m_settings.m_modAFInput == AMModSettings::AMModInputAF::AMModInputCWTone);
|
||||||
|
|
||||||
|
ui->feedbackEnable->setChecked(m_settings.m_feedbackAudioEnable);
|
||||||
|
ui->feedbackVolume->setValue(roundf(m_settings.m_feedbackVolumeFactor * 100.0));
|
||||||
|
ui->feedbackVolumeText->setText(QString("%1").arg(m_settings.m_feedbackVolumeFactor, 0, 'f', 2));
|
||||||
|
|
||||||
blockApplySettings(false);
|
blockApplySettings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +107,9 @@ private slots:
|
|||||||
void on_navTimeSlider_valueChanged(int value);
|
void on_navTimeSlider_valueChanged(int value);
|
||||||
void on_showFileDialog_clicked(bool checked);
|
void on_showFileDialog_clicked(bool checked);
|
||||||
|
|
||||||
|
void on_feedbackEnable_toggled(bool checked);
|
||||||
|
void on_feedbackVolume_valueChanged(int value);
|
||||||
|
|
||||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||||
void onMenuDialogCalled(const QPoint& p);
|
void onMenuDialogCalled(const QPoint& p);
|
||||||
|
|
||||||
|
@ -56,7 +56,16 @@
|
|||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>3</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>2</number>
|
<number>2</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@ -436,17 +445,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="Line" name="line_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="ButtonSwitch" name="mic">
|
<widget class="ButtonSwitch" name="mic">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Left: Source audio input Right: Select audio input device</string>
|
<string>Left: source audio input - Right: select audio input device</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
@ -460,6 +462,75 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="feedbackEnable">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Left: enable / disable audio feedback - Right: select audio output device</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||||
|
<normaloff>:/sound_off.png</normaloff>
|
||||||
|
<normalon>:/sound_on.png</normalon>:/sound_off.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDial" name="feedbackVolume">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Audio feedback volume</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="pageStep">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>50</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="feedbackVolumeText">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>30</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Audio feedback volume</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>1.00</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_3">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
@ -43,7 +43,7 @@ void AMModSettings::resetToDefaults()
|
|||||||
m_modAFInput = AMModInputAF::AMModInputNone;
|
m_modAFInput = AMModInputAF::AMModInputNone;
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_feedbackVolumeFactor = 1.0f;
|
m_feedbackVolumeFactor = 0.5f;
|
||||||
m_feedbackAudioEnable = false;
|
m_feedbackAudioEnable = false;
|
||||||
m_useReverseAPI = false;
|
m_useReverseAPI = false;
|
||||||
m_reverseAPIAddress = "127.0.0.1";
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
@ -68,7 +68,6 @@ FreeDVMod::FreeDVMod(DeviceAPI *deviceAPI) :
|
|||||||
m_SSBFilterBufferIndex(0),
|
m_SSBFilterBufferIndex(0),
|
||||||
m_sampleSink(0),
|
m_sampleSink(0),
|
||||||
m_audioFifo(4800),
|
m_audioFifo(4800),
|
||||||
m_feedbackAudioFifo(4800),
|
|
||||||
m_settingsMutex(QMutex::Recursive),
|
m_settingsMutex(QMutex::Recursive),
|
||||||
m_fileSize(0),
|
m_fileSize(0),
|
||||||
m_recordLength(0),
|
m_recordLength(0),
|
||||||
@ -90,9 +89,6 @@ FreeDVMod::FreeDVMod(DeviceAPI *deviceAPI) :
|
|||||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
|
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
|
||||||
m_audioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getInputSampleRate();
|
m_audioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getInputSampleRate();
|
||||||
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
|
||||||
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
|
||||||
|
|
||||||
m_SSBFilter = new fftfilt(m_lowCutoff / m_audioSampleRate, m_hiCutoff / m_audioSampleRate, m_ssbFftLen);
|
m_SSBFilter = new fftfilt(m_lowCutoff / m_audioSampleRate, m_hiCutoff / m_audioSampleRate, m_ssbFftLen);
|
||||||
m_SSBFilterBuffer = new Complex[m_ssbFftLen>>1]; // filter returns data exactly half of its size
|
m_SSBFilterBuffer = new Complex[m_ssbFftLen>>1]; // filter returns data exactly half of its size
|
||||||
std::fill(m_SSBFilterBuffer, m_SSBFilterBuffer+(m_ssbFftLen>>1), Complex{0,0});
|
std::fill(m_SSBFilterBuffer, m_SSBFilterBuffer+(m_ssbFftLen>>1), Complex{0,0});
|
||||||
@ -100,9 +96,6 @@ FreeDVMod::FreeDVMod(DeviceAPI *deviceAPI) :
|
|||||||
m_audioBuffer.resize(1<<14);
|
m_audioBuffer.resize(1<<14);
|
||||||
m_audioBufferFill = 0;
|
m_audioBufferFill = 0;
|
||||||
|
|
||||||
m_feedbackAudioBuffer.resize(1<<14);
|
|
||||||
m_feedbackAudioBufferFill = 0;
|
|
||||||
|
|
||||||
m_sum.real(0.0f);
|
m_sum.real(0.0f);
|
||||||
m_sum.imag(0.0f);
|
m_sum.imag(0.0f);
|
||||||
m_undersampleCount = 0;
|
m_undersampleCount = 0;
|
||||||
@ -131,7 +124,6 @@ FreeDVMod::~FreeDVMod()
|
|||||||
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
delete m_networkManager;
|
delete m_networkManager;
|
||||||
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_feedbackAudioFifo);
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSource(&m_audioFifo);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSource(&m_audioFifo);
|
||||||
|
|
||||||
m_deviceAPI->removeChannelSourceAPI(this);
|
m_deviceAPI->removeChannelSourceAPI(this);
|
||||||
|
@ -314,11 +314,6 @@ private:
|
|||||||
uint m_audioBufferFill;
|
uint m_audioBufferFill;
|
||||||
AudioFifo m_audioFifo;
|
AudioFifo m_audioFifo;
|
||||||
|
|
||||||
quint32 m_feedbackAudioSampleRate;
|
|
||||||
AudioVector m_feedbackAudioBuffer;
|
|
||||||
uint m_feedbackAudioBufferFill;
|
|
||||||
AudioFifo m_feedbackAudioFifo;
|
|
||||||
|
|
||||||
QMutex m_settingsMutex;
|
QMutex m_settingsMutex;
|
||||||
|
|
||||||
std::ifstream m_ifstream;
|
std::ifstream m_ifstream;
|
||||||
|
@ -42,9 +42,6 @@ void FreeDVModSettings::resetToDefaults()
|
|||||||
m_title = "FreeDV Modulator";
|
m_title = "FreeDV Modulator";
|
||||||
m_modAFInput = FreeDVModInputAF::FreeDVModInputNone;
|
m_modAFInput = FreeDVModInputAF::FreeDVModInputNone;
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
|
||||||
m_feedbackVolumeFactor = 1.0f;
|
|
||||||
m_feedbackAudioEnable = false;
|
|
||||||
m_freeDVMode = FreeDVMode::FreeDVMode2400A;
|
m_freeDVMode = FreeDVMode::FreeDVMode2400A;
|
||||||
m_gaugeInputElseModem = false;
|
m_gaugeInputElseModem = false;
|
||||||
m_useReverseAPI = false;
|
m_useReverseAPI = false;
|
||||||
@ -87,9 +84,6 @@ QByteArray FreeDVModSettings::serialize() const
|
|||||||
s.writeU32(24, m_reverseAPIPort);
|
s.writeU32(24, m_reverseAPIPort);
|
||||||
s.writeU32(25, m_reverseAPIDeviceIndex);
|
s.writeU32(25, m_reverseAPIDeviceIndex);
|
||||||
s.writeU32(26, m_reverseAPIChannelIndex);
|
s.writeU32(26, m_reverseAPIChannelIndex);
|
||||||
s.writeString(27, m_feedbackAudioDeviceName);
|
|
||||||
s.writeReal(28, m_feedbackVolumeFactor);
|
|
||||||
s.writeBool(29, m_feedbackAudioEnable);
|
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -168,9 +162,6 @@ bool FreeDVModSettings::deserialize(const QByteArray& data)
|
|||||||
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
d.readU32(26, &utmp, 0);
|
d.readU32(26, &utmp, 0);
|
||||||
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
d.readString(27, &m_feedbackAudioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
|
||||||
d.readReal(28, &m_feedbackVolumeFactor, 1.0);
|
|
||||||
d.readBool(29, &m_feedbackAudioEnable, false);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,6 @@ struct FreeDVModSettings
|
|||||||
QString m_title;
|
QString m_title;
|
||||||
FreeDVModInputAF m_modAFInput;
|
FreeDVModInputAF m_modAFInput;
|
||||||
QString m_audioDeviceName;
|
QString m_audioDeviceName;
|
||||||
QString m_feedbackAudioDeviceName; //!< This is the audio device you send the audio samples to for audio feedback
|
|
||||||
float m_feedbackVolumeFactor;
|
|
||||||
bool m_feedbackAudioEnable;
|
|
||||||
FreeDVMode m_freeDVMode;
|
FreeDVMode m_freeDVMode;
|
||||||
bool m_gaugeInputElseModem; //!< Volume gauge shows speech input level else modem level
|
bool m_gaugeInputElseModem; //!< Volume gauge shows speech input level else modem level
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ NFMMod::NFMMod(DeviceAPI *deviceAPI) :
|
|||||||
m_inputFrequencyOffset(0),
|
m_inputFrequencyOffset(0),
|
||||||
m_modPhasor(0.0f),
|
m_modPhasor(0.0f),
|
||||||
m_audioFifo(4800),
|
m_audioFifo(4800),
|
||||||
m_feedbackAudioFifo(4800),
|
m_feedbackAudioFifo(48000),
|
||||||
m_settingsMutex(QMutex::Recursive),
|
m_settingsMutex(QMutex::Recursive),
|
||||||
m_fileSize(0),
|
m_fileSize(0),
|
||||||
m_recordLength(0),
|
m_recordLength(0),
|
||||||
@ -84,6 +84,7 @@ NFMMod::NFMMod(DeviceAPI *deviceAPI) :
|
|||||||
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
||||||
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
||||||
|
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
|
||||||
|
|
||||||
m_lowpass.create(301, m_audioSampleRate, 250.0);
|
m_lowpass.create(301, m_audioSampleRate, 250.0);
|
||||||
m_toneNco.setFreq(1000.0, m_audioSampleRate);
|
m_toneNco.setFreq(1000.0, m_audioSampleRate);
|
||||||
@ -178,6 +179,11 @@ void NFMMod::modulateSample()
|
|||||||
Real t;
|
Real t;
|
||||||
|
|
||||||
pullAF(t);
|
pullAF(t);
|
||||||
|
|
||||||
|
if (m_settings.m_feedbackAudioEnable) {
|
||||||
|
pushFeedback(t * m_settings.m_feedbackVolumeFactor * 16384.0f);
|
||||||
|
}
|
||||||
|
|
||||||
calculateLevel(t);
|
calculateLevel(t);
|
||||||
m_audioBufferFill++;
|
m_audioBufferFill++;
|
||||||
|
|
||||||
@ -262,6 +268,50 @@ void NFMMod::pullAF(Real& sample)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NFMMod::pushFeedback(Real sample)
|
||||||
|
{
|
||||||
|
Complex c(sample, sample);
|
||||||
|
Complex ci;
|
||||||
|
|
||||||
|
if (m_feedbackInterpolatorDistance < 1.0f) // interpolate
|
||||||
|
{
|
||||||
|
while (!m_feedbackInterpolator.interpolate(&m_feedbackInterpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_feedbackInterpolatorDistanceRemain += m_feedbackInterpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // decimate
|
||||||
|
{
|
||||||
|
if (m_feedbackInterpolator.decimate(&m_feedbackInterpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_feedbackInterpolatorDistanceRemain += m_feedbackInterpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFMMod::processOneSample(Complex& ci)
|
||||||
|
{
|
||||||
|
m_feedbackAudioBuffer[m_feedbackAudioBufferFill].l = ci.real();
|
||||||
|
m_feedbackAudioBuffer[m_feedbackAudioBufferFill].r = ci.imag();
|
||||||
|
++m_feedbackAudioBufferFill;
|
||||||
|
|
||||||
|
if (m_feedbackAudioBufferFill >= m_feedbackAudioBuffer.size())
|
||||||
|
{
|
||||||
|
uint res = m_feedbackAudioFifo.write((const quint8*)&m_feedbackAudioBuffer[0], m_feedbackAudioBufferFill);
|
||||||
|
|
||||||
|
if (res != m_feedbackAudioBufferFill)
|
||||||
|
{
|
||||||
|
qDebug("AMDemod::pushFeedback: %u/%u audio samples written m_feedbackInterpolatorDistance: %f",
|
||||||
|
res, m_feedbackAudioBufferFill, m_feedbackInterpolatorDistance);
|
||||||
|
m_feedbackAudioFifo.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_feedbackAudioBufferFill = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NFMMod::calculateLevel(Real& sample)
|
void NFMMod::calculateLevel(Real& sample)
|
||||||
{
|
{
|
||||||
if (m_levelCalcCount < m_levelNbSamples)
|
if (m_levelCalcCount < m_levelNbSamples)
|
||||||
@ -376,13 +426,24 @@ bool NFMMod::handleMessage(const Message& cmd)
|
|||||||
{
|
{
|
||||||
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
||||||
uint32_t sampleRate = cfg.getSampleRate();
|
uint32_t sampleRate = cfg.getSampleRate();
|
||||||
|
DSPConfigureAudio::AudioType audioType = cfg.getAudioType();
|
||||||
|
|
||||||
qDebug() << "NFMMod::handleMessage: DSPConfigureAudio:"
|
qDebug() << "NFMMod::handleMessage: DSPConfigureAudio:"
|
||||||
<< " sampleRate: " << sampleRate;
|
<< " sampleRate: " << sampleRate
|
||||||
|
<< " audioType: " << audioType;
|
||||||
|
|
||||||
|
if (audioType == DSPConfigureAudio::AudioInput)
|
||||||
|
{
|
||||||
if (sampleRate != m_audioSampleRate) {
|
if (sampleRate != m_audioSampleRate) {
|
||||||
applyAudioSampleRate(sampleRate);
|
applyAudioSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (audioType == DSPConfigureAudio::AudioOutput)
|
||||||
|
{
|
||||||
|
if (sampleRate != m_audioSampleRate) {
|
||||||
|
applyFeedbackAudioSampleRate(sampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -454,6 +515,24 @@ void NFMMod::applyAudioSampleRate(int sampleRate)
|
|||||||
m_settingsMutex.unlock();
|
m_settingsMutex.unlock();
|
||||||
|
|
||||||
m_audioSampleRate = sampleRate;
|
m_audioSampleRate = sampleRate;
|
||||||
|
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFMMod::applyFeedbackAudioSampleRate(unsigned int sampleRate)
|
||||||
|
{
|
||||||
|
qDebug("AMMod::applyFeedbackAudioSampleRate: %u", sampleRate);
|
||||||
|
|
||||||
|
m_settingsMutex.lock();
|
||||||
|
|
||||||
|
m_feedbackInterpolatorDistanceRemain = 0;
|
||||||
|
m_feedbackInterpolatorConsumed = false;
|
||||||
|
m_feedbackInterpolatorDistance = (Real) sampleRate / (Real) m_audioSampleRate;
|
||||||
|
Real cutoff = std::min(sampleRate, m_audioSampleRate) / 2.2f;
|
||||||
|
m_feedbackInterpolator.create(48, sampleRate, cutoff, 3.0);
|
||||||
|
|
||||||
|
m_settingsMutex.unlock();
|
||||||
|
|
||||||
|
m_feedbackAudioSampleRate = sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NFMMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
|
void NFMMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
|
||||||
@ -588,6 +667,20 @@ void NFMMod::applySettings(const NFMModSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((settings.m_feedbackAudioDeviceName != m_settings.m_feedbackAudioDeviceName) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("feedbackAudioDeviceName");
|
||||||
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
|
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_feedbackAudioDeviceName);
|
||||||
|
audioDeviceManager->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue(), audioDeviceIndex);
|
||||||
|
uint32_t audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
|
||||||
|
|
||||||
|
if (m_feedbackAudioSampleRate != audioSampleRate) {
|
||||||
|
reverseAPIKeys.append("feedbackAudioSampleRate");
|
||||||
|
applyFeedbackAudioSampleRate(audioSampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (settings.m_useReverseAPI)
|
if (settings.m_useReverseAPI)
|
||||||
{
|
{
|
||||||
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||||
|
@ -281,10 +281,17 @@ private:
|
|||||||
NCOF m_ctcssNco;
|
NCOF m_ctcssNco;
|
||||||
float m_modPhasor; //!< baseband modulator phasor
|
float m_modPhasor; //!< baseband modulator phasor
|
||||||
Complex m_modSample;
|
Complex m_modSample;
|
||||||
|
|
||||||
Interpolator m_interpolator;
|
Interpolator m_interpolator;
|
||||||
Real m_interpolatorDistance;
|
Real m_interpolatorDistance;
|
||||||
Real m_interpolatorDistanceRemain;
|
Real m_interpolatorDistanceRemain;
|
||||||
bool m_interpolatorConsumed;
|
bool m_interpolatorConsumed;
|
||||||
|
|
||||||
|
Interpolator m_feedbackInterpolator;
|
||||||
|
Real m_feedbackInterpolatorDistance;
|
||||||
|
Real m_feedbackInterpolatorDistanceRemain;
|
||||||
|
bool m_feedbackInterpolatorConsumed;
|
||||||
|
|
||||||
Lowpass<Real> m_lowpass;
|
Lowpass<Real> m_lowpass;
|
||||||
Bandpass<Real> m_bandpass;
|
Bandpass<Real> m_bandpass;
|
||||||
|
|
||||||
@ -322,9 +329,12 @@ private:
|
|||||||
static const int m_levelNbSamples;
|
static const int m_levelNbSamples;
|
||||||
|
|
||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
|
void applyFeedbackAudioSampleRate(unsigned int sampleRate);
|
||||||
|
void processOneSample(Complex& ci);
|
||||||
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
|
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
|
||||||
void applySettings(const NFMModSettings& settings, bool force = false);
|
void applySettings(const NFMModSettings& settings, bool force = false);
|
||||||
void pullAF(Real& sample);
|
void pullAF(Real& sample);
|
||||||
|
void pushFeedback(Real sample);
|
||||||
void calculateLevel(Real& sample);
|
void calculateLevel(Real& sample);
|
||||||
void modulateSample();
|
void modulateSample();
|
||||||
void openFileStream();
|
void openFileStream();
|
||||||
|
@ -240,6 +240,19 @@ void NFMModGUI::on_mic_toggled(bool checked)
|
|||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NFMModGUI::on_feedbackEnable_toggled(bool checked)
|
||||||
|
{
|
||||||
|
m_settings.m_feedbackAudioEnable = checked;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFMModGUI::on_feedbackVolume_valueChanged(int value)
|
||||||
|
{
|
||||||
|
ui->feedbackVolumeText->setText(QString("%1").arg(value / 100.0, 0, 'f', 2));
|
||||||
|
m_settings.m_feedbackVolumeFactor = value / 100.0;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
void NFMModGUI::on_navTimeSlider_valueChanged(int value)
|
void NFMModGUI::on_navTimeSlider_valueChanged(int value)
|
||||||
{
|
{
|
||||||
if (m_enableNavTime && ((value >= 0) && (value <= 100)))
|
if (m_enableNavTime && ((value >= 0) && (value <= 100)))
|
||||||
@ -474,6 +487,10 @@ void NFMModGUI::displaySettings()
|
|||||||
ui->play->setChecked(m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputFile);
|
ui->play->setChecked(m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputFile);
|
||||||
ui->morseKeyer->setChecked(m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputCWTone);
|
ui->morseKeyer->setChecked(m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputCWTone);
|
||||||
|
|
||||||
|
ui->feedbackEnable->setChecked(m_settings.m_feedbackAudioEnable);
|
||||||
|
ui->feedbackVolume->setValue(roundf(m_settings.m_feedbackVolumeFactor * 100.0));
|
||||||
|
ui->feedbackVolumeText->setText(QString("%1").arg(m_settings.m_feedbackVolumeFactor, 0, 'f', 2));
|
||||||
|
|
||||||
blockApplySettings(false);
|
blockApplySettings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,9 @@ private slots:
|
|||||||
void on_ctcss_currentIndexChanged(int index);
|
void on_ctcss_currentIndexChanged(int index);
|
||||||
void on_ctcssOn_toggled(bool checked);
|
void on_ctcssOn_toggled(bool checked);
|
||||||
|
|
||||||
|
void on_feedbackEnable_toggled(bool checked);
|
||||||
|
void on_feedbackVolume_valueChanged(int value);
|
||||||
|
|
||||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||||
void onMenuDialogCalled(const QPoint& p);
|
void onMenuDialogCalled(const QPoint& p);
|
||||||
|
|
||||||
|
@ -56,7 +56,16 @@
|
|||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>3</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>2</number>
|
<number>2</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@ -476,13 +485,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="Line" name="line_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="ButtonSwitch" name="mic">
|
<widget class="ButtonSwitch" name="mic">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
@ -500,6 +502,75 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="feedbackEnable">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Left: enable / disable audio feedback - Right: select audio output device</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||||
|
<normaloff>:/sound_off.png</normaloff>
|
||||||
|
<normalon>:/sound_on.png</normalon>:/sound_off.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDial" name="feedbackVolume">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Audio feedback volume</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="pageStep">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>50</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="feedbackVolumeText">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>30</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Audio feedback volume</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>1.00</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_3">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@ -520,6 +591,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="ctcssLayer">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="ctcssLabel">
|
<widget class="QLabel" name="ctcssLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -550,6 +625,19 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -61,7 +61,7 @@ void NFMModSettings::resetToDefaults()
|
|||||||
m_modAFInput = NFMModInputAF::NFMModInputNone;
|
m_modAFInput = NFMModInputAF::NFMModInputNone;
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_feedbackVolumeFactor = 1.0f;
|
m_feedbackVolumeFactor = 0.5f;
|
||||||
m_feedbackAudioEnable = false;
|
m_feedbackAudioEnable = false;
|
||||||
m_useReverseAPI = false;
|
m_useReverseAPI = false;
|
||||||
m_reverseAPIAddress = "127.0.0.1";
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
@ -66,7 +66,7 @@ SSBMod::SSBMod(DeviceAPI *deviceAPI) :
|
|||||||
m_DSBFilterBufferIndex(0),
|
m_DSBFilterBufferIndex(0),
|
||||||
m_sampleSink(0),
|
m_sampleSink(0),
|
||||||
m_audioFifo(4800),
|
m_audioFifo(4800),
|
||||||
m_feedbackAudioFifo(4800),
|
m_feedbackAudioFifo(48000),
|
||||||
m_settingsMutex(QMutex::Recursive),
|
m_settingsMutex(QMutex::Recursive),
|
||||||
m_fileSize(0),
|
m_fileSize(0),
|
||||||
m_recordLength(0),
|
m_recordLength(0),
|
||||||
@ -83,6 +83,7 @@ SSBMod::SSBMod(DeviceAPI *deviceAPI) :
|
|||||||
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
||||||
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
||||||
|
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
|
||||||
|
|
||||||
m_SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_audioSampleRate, m_settings.m_bandwidth / m_audioSampleRate, m_ssbFftLen);
|
m_SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_audioSampleRate, m_settings.m_bandwidth / m_audioSampleRate, m_ssbFftLen);
|
||||||
m_DSBFilter = new fftfilt((2.0f * m_settings.m_bandwidth) / m_audioSampleRate, 2 * m_ssbFftLen);
|
m_DSBFilter = new fftfilt((2.0f * m_settings.m_bandwidth) / m_audioSampleRate, 2 * m_ssbFftLen);
|
||||||
@ -206,6 +207,11 @@ void SSBMod::pullAudio(int nbSamples)
|
|||||||
void SSBMod::modulateSample()
|
void SSBMod::modulateSample()
|
||||||
{
|
{
|
||||||
pullAF(m_modSample);
|
pullAF(m_modSample);
|
||||||
|
|
||||||
|
if (m_settings.m_feedbackAudioEnable) {
|
||||||
|
pushFeedback(m_modSample * m_settings.m_feedbackVolumeFactor * 16384.0f);
|
||||||
|
}
|
||||||
|
|
||||||
calculateLevel(m_modSample);
|
calculateLevel(m_modSample);
|
||||||
m_audioBufferFill++;
|
m_audioBufferFill++;
|
||||||
}
|
}
|
||||||
@ -503,6 +509,49 @@ void SSBMod::pullAF(Complex& sample)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSBMod::pushFeedback(Complex c)
|
||||||
|
{
|
||||||
|
Complex ci;
|
||||||
|
|
||||||
|
if (m_feedbackInterpolatorDistance < 1.0f) // interpolate
|
||||||
|
{
|
||||||
|
while (!m_feedbackInterpolator.interpolate(&m_feedbackInterpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_feedbackInterpolatorDistanceRemain += m_feedbackInterpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // decimate
|
||||||
|
{
|
||||||
|
if (m_feedbackInterpolator.decimate(&m_feedbackInterpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_feedbackInterpolatorDistanceRemain += m_feedbackInterpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSBMod::processOneSample(Complex& ci)
|
||||||
|
{
|
||||||
|
m_feedbackAudioBuffer[m_feedbackAudioBufferFill].l = ci.real();
|
||||||
|
m_feedbackAudioBuffer[m_feedbackAudioBufferFill].r = ci.imag();
|
||||||
|
++m_feedbackAudioBufferFill;
|
||||||
|
|
||||||
|
if (m_feedbackAudioBufferFill >= m_feedbackAudioBuffer.size())
|
||||||
|
{
|
||||||
|
uint res = m_feedbackAudioFifo.write((const quint8*)&m_feedbackAudioBuffer[0], m_feedbackAudioBufferFill);
|
||||||
|
|
||||||
|
if (res != m_feedbackAudioBufferFill)
|
||||||
|
{
|
||||||
|
qDebug("AMDemod::pushFeedback: %u/%u audio samples written m_feedbackInterpolatorDistance: %f",
|
||||||
|
res, m_feedbackAudioBufferFill, m_feedbackInterpolatorDistance);
|
||||||
|
m_feedbackAudioFifo.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_feedbackAudioBufferFill = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SSBMod::calculateLevel(Complex& sample)
|
void SSBMod::calculateLevel(Complex& sample)
|
||||||
{
|
{
|
||||||
Real t = sample.real(); // TODO: possibly adjust depending on sample type
|
Real t = sample.real(); // TODO: possibly adjust depending on sample type
|
||||||
@ -617,13 +666,24 @@ bool SSBMod::handleMessage(const Message& cmd)
|
|||||||
{
|
{
|
||||||
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
||||||
uint32_t sampleRate = cfg.getSampleRate();
|
uint32_t sampleRate = cfg.getSampleRate();
|
||||||
|
DSPConfigureAudio::AudioType audioType = cfg.getAudioType();
|
||||||
|
|
||||||
qDebug() << "SSBMod::handleMessage: DSPConfigureAudio:"
|
qDebug() << "SSBMod::handleMessage: DSPConfigureAudio:"
|
||||||
<< " sampleRate: " << sampleRate;
|
<< " sampleRate: " << sampleRate
|
||||||
|
<< " audioType: " << audioType;
|
||||||
|
|
||||||
|
if (audioType == DSPConfigureAudio::AudioInput)
|
||||||
|
{
|
||||||
if (sampleRate != m_audioSampleRate) {
|
if (sampleRate != m_audioSampleRate) {
|
||||||
applyAudioSampleRate(sampleRate);
|
applyAudioSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (audioType == DSPConfigureAudio::AudioOutput)
|
||||||
|
{
|
||||||
|
if (sampleRate != m_audioSampleRate) {
|
||||||
|
applyFeedbackAudioSampleRate(sampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -727,6 +787,25 @@ void SSBMod::applyAudioSampleRate(int sampleRate)
|
|||||||
DSPConfigureAudio *cfg = new DSPConfigureAudio(m_audioSampleRate, DSPConfigureAudio::AudioInput);
|
DSPConfigureAudio *cfg = new DSPConfigureAudio(m_audioSampleRate, DSPConfigureAudio::AudioInput);
|
||||||
getMessageQueueToGUI()->push(cfg);
|
getMessageQueueToGUI()->push(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSBMod::applyFeedbackAudioSampleRate(unsigned int sampleRate)
|
||||||
|
{
|
||||||
|
qDebug("AMMod::applyFeedbackAudioSampleRate: %u", sampleRate);
|
||||||
|
|
||||||
|
m_settingsMutex.lock();
|
||||||
|
|
||||||
|
m_feedbackInterpolatorDistanceRemain = 0;
|
||||||
|
m_feedbackInterpolatorConsumed = false;
|
||||||
|
m_feedbackInterpolatorDistance = (Real) sampleRate / (Real) m_audioSampleRate;
|
||||||
|
Real cutoff = std::min(sampleRate, m_audioSampleRate) / 2.2f;
|
||||||
|
m_feedbackInterpolator.create(48, sampleRate, cutoff, 3.0);
|
||||||
|
|
||||||
|
m_settingsMutex.unlock();
|
||||||
|
|
||||||
|
m_feedbackAudioSampleRate = sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSBMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
|
void SSBMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
|
||||||
@ -876,6 +955,20 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((settings.m_feedbackAudioDeviceName != m_settings.m_feedbackAudioDeviceName) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("feedbackAudioDeviceName");
|
||||||
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
|
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_feedbackAudioDeviceName);
|
||||||
|
audioDeviceManager->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue(), audioDeviceIndex);
|
||||||
|
uint32_t audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
|
||||||
|
|
||||||
|
if (m_feedbackAudioSampleRate != audioSampleRate) {
|
||||||
|
reverseAPIKeys.append("feedbackAudioSampleRate");
|
||||||
|
applyFeedbackAudioSampleRate(audioSampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (settings.m_useReverseAPI)
|
if (settings.m_useReverseAPI)
|
||||||
{
|
{
|
||||||
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||||
|
@ -282,10 +282,17 @@ private:
|
|||||||
NCOF m_carrierNco;
|
NCOF m_carrierNco;
|
||||||
NCOF m_toneNco;
|
NCOF m_toneNco;
|
||||||
Complex m_modSample;
|
Complex m_modSample;
|
||||||
|
|
||||||
Interpolator m_interpolator;
|
Interpolator m_interpolator;
|
||||||
Real m_interpolatorDistance;
|
Real m_interpolatorDistance;
|
||||||
Real m_interpolatorDistanceRemain;
|
Real m_interpolatorDistanceRemain;
|
||||||
bool m_interpolatorConsumed;
|
bool m_interpolatorConsumed;
|
||||||
|
|
||||||
|
Interpolator m_feedbackInterpolator;
|
||||||
|
Real m_feedbackInterpolatorDistance;
|
||||||
|
Real m_feedbackInterpolatorDistanceRemain;
|
||||||
|
bool m_feedbackInterpolatorConsumed;
|
||||||
|
|
||||||
fftfilt* m_SSBFilter;
|
fftfilt* m_SSBFilter;
|
||||||
fftfilt* m_DSBFilter;
|
fftfilt* m_DSBFilter;
|
||||||
Complex* m_SSBFilterBuffer;
|
Complex* m_SSBFilterBuffer;
|
||||||
@ -336,9 +343,12 @@ private:
|
|||||||
static const int m_levelNbSamples;
|
static const int m_levelNbSamples;
|
||||||
|
|
||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
|
void applyFeedbackAudioSampleRate(unsigned int sampleRate);
|
||||||
|
void processOneSample(Complex& ci);
|
||||||
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
|
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
|
||||||
void applySettings(const SSBModSettings& settings, bool force = false);
|
void applySettings(const SSBModSettings& settings, bool force = false);
|
||||||
void pullAF(Complex& sample);
|
void pullAF(Complex& sample);
|
||||||
|
void pushFeedback(Complex sample);
|
||||||
void calculateLevel(Complex& sample);
|
void calculateLevel(Complex& sample);
|
||||||
void modulateSample();
|
void modulateSample();
|
||||||
void openFileStream();
|
void openFileStream();
|
||||||
|
@ -292,6 +292,19 @@ void SSBModGUI::on_mic_toggled(bool checked)
|
|||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSBModGUI::on_feedbackEnable_toggled(bool checked)
|
||||||
|
{
|
||||||
|
m_settings.m_feedbackAudioEnable = checked;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSBModGUI::on_feedbackVolume_valueChanged(int value)
|
||||||
|
{
|
||||||
|
ui->feedbackVolumeText->setText(QString("%1").arg(value / 100.0, 0, 'f', 2));
|
||||||
|
m_settings.m_feedbackVolumeFactor = value / 100.0;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
void SSBModGUI::on_agc_toggled(bool checked)
|
void SSBModGUI::on_agc_toggled(bool checked)
|
||||||
{
|
{
|
||||||
m_settings.m_agc = checked;
|
m_settings.m_agc = checked;
|
||||||
@ -679,6 +692,10 @@ void SSBModGUI::displaySettings()
|
|||||||
ui->play->setChecked(m_settings.m_modAFInput == SSBModSettings::SSBModInputAF::SSBModInputFile);
|
ui->play->setChecked(m_settings.m_modAFInput == SSBModSettings::SSBModInputAF::SSBModInputFile);
|
||||||
ui->morseKeyer->setChecked(m_settings.m_modAFInput == SSBModSettings::SSBModInputAF::SSBModInputCWTone);
|
ui->morseKeyer->setChecked(m_settings.m_modAFInput == SSBModSettings::SSBModInputAF::SSBModInputCWTone);
|
||||||
|
|
||||||
|
ui->feedbackEnable->setChecked(m_settings.m_feedbackAudioEnable);
|
||||||
|
ui->feedbackVolume->setValue(roundf(m_settings.m_feedbackVolumeFactor * 100.0));
|
||||||
|
ui->feedbackVolumeText->setText(QString("%1").arg(m_settings.m_feedbackVolumeFactor, 0, 'f', 2));
|
||||||
|
|
||||||
blockApplySettings(false);
|
blockApplySettings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +120,9 @@ private slots:
|
|||||||
void on_navTimeSlider_valueChanged(int value);
|
void on_navTimeSlider_valueChanged(int value);
|
||||||
void on_showFileDialog_clicked(bool checked);
|
void on_showFileDialog_clicked(bool checked);
|
||||||
|
|
||||||
|
void on_feedbackEnable_toggled(bool checked);
|
||||||
|
void on_feedbackVolume_valueChanged(int value);
|
||||||
|
|
||||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||||
void onMenuDialogCalled(const QPoint& p);
|
void onMenuDialogCalled(const QPoint& p);
|
||||||
|
|
||||||
|
@ -811,13 +811,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="Line" name="line_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="ButtonSwitch" name="mic">
|
<widget class="ButtonSwitch" name="mic">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
@ -835,6 +828,75 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="feedbackEnable">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Left: enable / disable audio feedback - Right: select audio output device</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||||
|
<normaloff>:/sound_off.png</normaloff>
|
||||||
|
<normalon>:/sound_on.png</normalon>:/sound_off.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDial" name="feedbackVolume">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Audio feedback volume</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="pageStep">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>50</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="feedbackVolumeText">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>30</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Audio feedback volume</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>1.00</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_3">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
@ -64,7 +64,7 @@ void SSBModSettings::resetToDefaults()
|
|||||||
m_modAFInput = SSBModInputAF::SSBModInputNone;
|
m_modAFInput = SSBModInputAF::SSBModInputNone;
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_feedbackVolumeFactor = 1.0f;
|
m_feedbackVolumeFactor = 0.5f;
|
||||||
m_feedbackAudioEnable = false;
|
m_feedbackAudioEnable = false;
|
||||||
m_useReverseAPI = false;
|
m_useReverseAPI = false;
|
||||||
m_reverseAPIAddress = "127.0.0.1";
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
@ -60,7 +60,6 @@ WFMMod::WFMMod(DeviceAPI *deviceAPI) :
|
|||||||
m_inputFrequencyOffset(0),
|
m_inputFrequencyOffset(0),
|
||||||
m_modPhasor(0.0f),
|
m_modPhasor(0.0f),
|
||||||
m_audioFifo(4800),
|
m_audioFifo(4800),
|
||||||
m_feedbackAudioFifo(4800),
|
|
||||||
m_settingsMutex(QMutex::Recursive),
|
m_settingsMutex(QMutex::Recursive),
|
||||||
m_fileSize(0),
|
m_fileSize(0),
|
||||||
m_recordLength(0),
|
m_recordLength(0),
|
||||||
@ -80,17 +79,11 @@ WFMMod::WFMMod(DeviceAPI *deviceAPI) :
|
|||||||
m_audioBuffer.resize(1<<14);
|
m_audioBuffer.resize(1<<14);
|
||||||
m_audioBufferFill = 0;
|
m_audioBufferFill = 0;
|
||||||
|
|
||||||
m_feedbackAudioBuffer.resize(1<<14);
|
|
||||||
m_feedbackAudioBufferFill = 0;
|
|
||||||
|
|
||||||
m_magsq = 0.0;
|
m_magsq = 0.0;
|
||||||
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
|
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
|
||||||
m_audioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getInputSampleRate();
|
m_audioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getInputSampleRate();
|
||||||
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
|
||||||
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
|
||||||
|
|
||||||
m_toneNcoRF.setFreq(1000.0, m_outputSampleRate);
|
m_toneNcoRF.setFreq(1000.0, m_outputSampleRate);
|
||||||
m_cwKeyer.setSampleRate(m_outputSampleRate);
|
m_cwKeyer.setSampleRate(m_outputSampleRate);
|
||||||
m_cwKeyer.reset();
|
m_cwKeyer.reset();
|
||||||
@ -111,7 +104,6 @@ WFMMod::~WFMMod()
|
|||||||
{
|
{
|
||||||
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
delete m_networkManager;
|
delete m_networkManager;
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_feedbackAudioFifo);
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSource(&m_audioFifo);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSource(&m_audioFifo);
|
||||||
m_deviceAPI->removeChannelSourceAPI(this);
|
m_deviceAPI->removeChannelSourceAPI(this);
|
||||||
m_deviceAPI->removeChannelSource(m_threadedChannelizer);
|
m_deviceAPI->removeChannelSource(m_threadedChannelizer);
|
||||||
|
@ -297,11 +297,6 @@ private:
|
|||||||
uint m_audioBufferFill;
|
uint m_audioBufferFill;
|
||||||
AudioFifo m_audioFifo;
|
AudioFifo m_audioFifo;
|
||||||
|
|
||||||
quint32 m_feedbackAudioSampleRate;
|
|
||||||
AudioVector m_feedbackAudioBuffer;
|
|
||||||
uint m_feedbackAudioBufferFill;
|
|
||||||
AudioFifo m_feedbackAudioFifo;
|
|
||||||
|
|
||||||
SampleVector m_sampleBuffer;
|
SampleVector m_sampleBuffer;
|
||||||
QMutex m_settingsMutex;
|
QMutex m_settingsMutex;
|
||||||
|
|
||||||
|
@ -50,9 +50,6 @@ void WFMModSettings::resetToDefaults()
|
|||||||
m_title = "WFM Modulator";
|
m_title = "WFM Modulator";
|
||||||
m_modAFInput = WFMModInputNone;
|
m_modAFInput = WFMModInputNone;
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
|
||||||
m_feedbackVolumeFactor = 1.0f;
|
|
||||||
m_feedbackAudioEnable = false;
|
|
||||||
m_useReverseAPI = false;
|
m_useReverseAPI = false;
|
||||||
m_reverseAPIAddress = "127.0.0.1";
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
m_reverseAPIPort = 8888;
|
m_reverseAPIPort = 8888;
|
||||||
@ -88,9 +85,6 @@ QByteArray WFMModSettings::serialize() const
|
|||||||
s.writeU32(15, m_reverseAPIPort);
|
s.writeU32(15, m_reverseAPIPort);
|
||||||
s.writeU32(16, m_reverseAPIDeviceIndex);
|
s.writeU32(16, m_reverseAPIDeviceIndex);
|
||||||
s.writeU32(17, m_reverseAPIChannelIndex);
|
s.writeU32(17, m_reverseAPIChannelIndex);
|
||||||
s.writeString(18, m_feedbackAudioDeviceName);
|
|
||||||
s.writeReal(19, m_feedbackVolumeFactor);
|
|
||||||
s.writeBool(20, m_feedbackAudioEnable);
|
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -154,9 +148,6 @@ bool WFMModSettings::deserialize(const QByteArray& data)
|
|||||||
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
d.readU32(17, &utmp, 0);
|
d.readU32(17, &utmp, 0);
|
||||||
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
d.readString(18, &m_feedbackAudioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
|
||||||
d.readReal(19, &m_feedbackVolumeFactor, 1.0);
|
|
||||||
d.readBool(20, &m_feedbackAudioEnable, false);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -48,9 +48,6 @@ struct WFMModSettings
|
|||||||
QString m_title;
|
QString m_title;
|
||||||
WFMModInputAF m_modAFInput;
|
WFMModInputAF m_modAFInput;
|
||||||
QString m_audioDeviceName; //!< This is the audio device you get the audio samples from
|
QString m_audioDeviceName; //!< This is the audio device you get the audio samples from
|
||||||
QString m_feedbackAudioDeviceName; //!< This is the audio device you send the audio samples to for audio feedback
|
|
||||||
float m_feedbackVolumeFactor;
|
|
||||||
bool m_feedbackAudioEnable;
|
|
||||||
bool m_useReverseAPI;
|
bool m_useReverseAPI;
|
||||||
QString m_reverseAPIAddress;
|
QString m_reverseAPIAddress;
|
||||||
uint16_t m_reverseAPIPort;
|
uint16_t m_reverseAPIPort;
|
||||||
|
@ -388,7 +388,7 @@ public:
|
|||||||
{ }
|
{ }
|
||||||
|
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
bool getAudioType() const { return m_autioType; }
|
AudioType getAudioType() const { return m_autioType; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_sampleRate;
|
int m_sampleRate;
|
||||||
|
Loading…
Reference in New Issue
Block a user