mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-03-22 04:08:29 -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_inputFrequencyOffset(0),
|
||||
m_audioFifo(4800),
|
||||
m_feedbackAudioFifo(4800),
|
||||
m_feedbackAudioFifo(48000),
|
||||
m_settingsMutex(QMutex::Recursive),
|
||||
m_fileSize(0),
|
||||
m_recordLength(0),
|
||||
@ -81,6 +81,7 @@ AMMod::AMMod(DeviceAPI *deviceAPI) :
|
||||
|
||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
||||
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
||||
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
|
||||
|
||||
m_toneNco.setFreq(1000.0, m_audioSampleRate);
|
||||
m_cwKeyer.setSampleRate(m_audioSampleRate);
|
||||
@ -174,6 +175,11 @@ void AMMod::modulateSample()
|
||||
Real t;
|
||||
|
||||
pullAF(t);
|
||||
|
||||
if (m_settings.m_feedbackAudioEnable) {
|
||||
pushFeedback(t * m_settings.m_feedbackVolumeFactor * 16384.0f);
|
||||
}
|
||||
|
||||
calculateLevel(t);
|
||||
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)
|
||||
{
|
||||
if (m_levelCalcCount < m_levelNbSamples)
|
||||
@ -361,12 +411,23 @@ bool AMMod::handleMessage(const Message& cmd)
|
||||
{
|
||||
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
||||
uint32_t sampleRate = cfg.getSampleRate();
|
||||
DSPConfigureAudio::AudioType audioType = cfg.getAudioType();
|
||||
|
||||
qDebug() << "AMMod::handleMessage: DSPConfigureAudio:"
|
||||
<< " sampleRate: " << sampleRate;
|
||||
<< " sampleRate: " << sampleRate
|
||||
<< " audioType: " << audioType;
|
||||
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyAudioSampleRate(sampleRate);
|
||||
if (audioType == DSPConfigureAudio::AudioInput)
|
||||
{
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyAudioSampleRate(sampleRate);
|
||||
}
|
||||
}
|
||||
else if (audioType == DSPConfigureAudio::AudioOutput)
|
||||
{
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyFeedbackAudioSampleRate(sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -436,6 +497,24 @@ void AMMod::applyAudioSampleRate(int sampleRate)
|
||||
m_settingsMutex.unlock();
|
||||
|
||||
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)
|
||||
@ -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)
|
||||
{
|
||||
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||
|
@ -277,11 +277,17 @@ private:
|
||||
NCO m_carrierNco;
|
||||
NCOF m_toneNco;
|
||||
Complex m_modSample;
|
||||
|
||||
Interpolator m_interpolator;
|
||||
Real m_interpolatorDistance;
|
||||
Real m_interpolatorDistanceRemain;
|
||||
bool m_interpolatorConsumed;
|
||||
|
||||
Interpolator m_feedbackInterpolator;
|
||||
Real m_feedbackInterpolatorDistance;
|
||||
Real m_feedbackInterpolatorDistanceRemain;
|
||||
bool m_feedbackInterpolatorConsumed;
|
||||
|
||||
double m_magsq;
|
||||
MovingAverageUtil<double, double, 16> m_movingAverage;
|
||||
|
||||
@ -315,9 +321,12 @@ private:
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
||||
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 applySettings(const AMModSettings& settings, bool force = false);
|
||||
void pullAF(Real& sample);
|
||||
void pushFeedback(Real sample);
|
||||
void calculateLevel(Real& sample);
|
||||
void modulateSample();
|
||||
void openFileStream();
|
||||
|
@ -236,6 +236,19 @@ void AMModGUI::on_mic_toggled(bool checked)
|
||||
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)
|
||||
{
|
||||
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->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);
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,9 @@ private slots:
|
||||
void on_navTimeSlider_valueChanged(int value);
|
||||
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 onMenuDialogCalled(const QPoint& p);
|
||||
|
||||
|
@ -56,7 +56,16 @@
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</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>
|
||||
</property>
|
||||
<item>
|
||||
@ -436,17 +445,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="mic">
|
||||
<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 name="text">
|
||||
<string>...</string>
|
||||
@ -460,6 +462,75 @@
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
|
@ -43,7 +43,7 @@ void AMModSettings::resetToDefaults()
|
||||
m_modAFInput = AMModInputAF::AMModInputNone;
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackVolumeFactor = 1.0f;
|
||||
m_feedbackVolumeFactor = 0.5f;
|
||||
m_feedbackAudioEnable = false;
|
||||
m_useReverseAPI = false;
|
||||
m_reverseAPIAddress = "127.0.0.1";
|
||||
|
@ -68,7 +68,6 @@ FreeDVMod::FreeDVMod(DeviceAPI *deviceAPI) :
|
||||
m_SSBFilterBufferIndex(0),
|
||||
m_sampleSink(0),
|
||||
m_audioFifo(4800),
|
||||
m_feedbackAudioFifo(4800),
|
||||
m_settingsMutex(QMutex::Recursive),
|
||||
m_fileSize(0),
|
||||
m_recordLength(0),
|
||||
@ -90,9 +89,6 @@ FreeDVMod::FreeDVMod(DeviceAPI *deviceAPI) :
|
||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
|
||||
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_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});
|
||||
@ -100,9 +96,6 @@ FreeDVMod::FreeDVMod(DeviceAPI *deviceAPI) :
|
||||
m_audioBuffer.resize(1<<14);
|
||||
m_audioBufferFill = 0;
|
||||
|
||||
m_feedbackAudioBuffer.resize(1<<14);
|
||||
m_feedbackAudioBufferFill = 0;
|
||||
|
||||
m_sum.real(0.0f);
|
||||
m_sum.imag(0.0f);
|
||||
m_undersampleCount = 0;
|
||||
@ -131,7 +124,6 @@ FreeDVMod::~FreeDVMod()
|
||||
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||
delete m_networkManager;
|
||||
|
||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_feedbackAudioFifo);
|
||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSource(&m_audioFifo);
|
||||
|
||||
m_deviceAPI->removeChannelSourceAPI(this);
|
||||
|
@ -314,11 +314,6 @@ private:
|
||||
uint m_audioBufferFill;
|
||||
AudioFifo m_audioFifo;
|
||||
|
||||
quint32 m_feedbackAudioSampleRate;
|
||||
AudioVector m_feedbackAudioBuffer;
|
||||
uint m_feedbackAudioBufferFill;
|
||||
AudioFifo m_feedbackAudioFifo;
|
||||
|
||||
QMutex m_settingsMutex;
|
||||
|
||||
std::ifstream m_ifstream;
|
||||
|
@ -42,9 +42,6 @@ void FreeDVModSettings::resetToDefaults()
|
||||
m_title = "FreeDV Modulator";
|
||||
m_modAFInput = FreeDVModInputAF::FreeDVModInputNone;
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackVolumeFactor = 1.0f;
|
||||
m_feedbackAudioEnable = false;
|
||||
m_freeDVMode = FreeDVMode::FreeDVMode2400A;
|
||||
m_gaugeInputElseModem = false;
|
||||
m_useReverseAPI = false;
|
||||
@ -87,9 +84,6 @@ QByteArray FreeDVModSettings::serialize() const
|
||||
s.writeU32(24, m_reverseAPIPort);
|
||||
s.writeU32(25, m_reverseAPIDeviceIndex);
|
||||
s.writeU32(26, m_reverseAPIChannelIndex);
|
||||
s.writeString(27, m_feedbackAudioDeviceName);
|
||||
s.writeReal(28, m_feedbackVolumeFactor);
|
||||
s.writeBool(29, m_feedbackAudioEnable);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -168,9 +162,6 @@ bool FreeDVModSettings::deserialize(const QByteArray& data)
|
||||
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||
d.readU32(26, &utmp, 0);
|
||||
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;
|
||||
}
|
||||
|
@ -55,9 +55,6 @@ struct FreeDVModSettings
|
||||
QString m_title;
|
||||
FreeDVModInputAF m_modAFInput;
|
||||
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;
|
||||
bool m_gaugeInputElseModem; //!< Volume gauge shows speech input level else modem level
|
||||
|
||||
|
@ -60,7 +60,7 @@ NFMMod::NFMMod(DeviceAPI *deviceAPI) :
|
||||
m_inputFrequencyOffset(0),
|
||||
m_modPhasor(0.0f),
|
||||
m_audioFifo(4800),
|
||||
m_feedbackAudioFifo(4800),
|
||||
m_feedbackAudioFifo(48000),
|
||||
m_settingsMutex(QMutex::Recursive),
|
||||
m_fileSize(0),
|
||||
m_recordLength(0),
|
||||
@ -84,6 +84,7 @@ NFMMod::NFMMod(DeviceAPI *deviceAPI) :
|
||||
|
||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
||||
m_feedbackAudioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
||||
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
|
||||
|
||||
m_lowpass.create(301, m_audioSampleRate, 250.0);
|
||||
m_toneNco.setFreq(1000.0, m_audioSampleRate);
|
||||
@ -178,6 +179,11 @@ void NFMMod::modulateSample()
|
||||
Real t;
|
||||
|
||||
pullAF(t);
|
||||
|
||||
if (m_settings.m_feedbackAudioEnable) {
|
||||
pushFeedback(t * m_settings.m_feedbackVolumeFactor * 16384.0f);
|
||||
}
|
||||
|
||||
calculateLevel(t);
|
||||
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)
|
||||
{
|
||||
if (m_levelCalcCount < m_levelNbSamples)
|
||||
@ -376,12 +426,23 @@ bool NFMMod::handleMessage(const Message& cmd)
|
||||
{
|
||||
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
||||
uint32_t sampleRate = cfg.getSampleRate();
|
||||
DSPConfigureAudio::AudioType audioType = cfg.getAudioType();
|
||||
|
||||
qDebug() << "NFMMod::handleMessage: DSPConfigureAudio:"
|
||||
<< " sampleRate: " << sampleRate;
|
||||
<< " sampleRate: " << sampleRate
|
||||
<< " audioType: " << audioType;
|
||||
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyAudioSampleRate(sampleRate);
|
||||
if (audioType == DSPConfigureAudio::AudioInput)
|
||||
{
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyAudioSampleRate(sampleRate);
|
||||
}
|
||||
}
|
||||
else if (audioType == DSPConfigureAudio::AudioOutput)
|
||||
{
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyFeedbackAudioSampleRate(sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -454,6 +515,24 @@ void NFMMod::applyAudioSampleRate(int sampleRate)
|
||||
m_settingsMutex.unlock();
|
||||
|
||||
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)
|
||||
@ -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)
|
||||
{
|
||||
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||
|
@ -281,10 +281,17 @@ private:
|
||||
NCOF m_ctcssNco;
|
||||
float m_modPhasor; //!< baseband modulator phasor
|
||||
Complex m_modSample;
|
||||
|
||||
Interpolator m_interpolator;
|
||||
Real m_interpolatorDistance;
|
||||
Real m_interpolatorDistanceRemain;
|
||||
bool m_interpolatorConsumed;
|
||||
|
||||
Interpolator m_feedbackInterpolator;
|
||||
Real m_feedbackInterpolatorDistance;
|
||||
Real m_feedbackInterpolatorDistanceRemain;
|
||||
bool m_feedbackInterpolatorConsumed;
|
||||
|
||||
Lowpass<Real> m_lowpass;
|
||||
Bandpass<Real> m_bandpass;
|
||||
|
||||
@ -322,9 +329,12 @@ private:
|
||||
static const int m_levelNbSamples;
|
||||
|
||||
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 applySettings(const NFMModSettings& settings, bool force = false);
|
||||
void pullAF(Real& sample);
|
||||
void pushFeedback(Real sample);
|
||||
void calculateLevel(Real& sample);
|
||||
void modulateSample();
|
||||
void openFileStream();
|
||||
|
@ -240,6 +240,19 @@ void NFMModGUI::on_mic_toggled(bool checked)
|
||||
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)
|
||||
{
|
||||
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->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);
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,9 @@ private slots:
|
||||
void on_ctcss_currentIndexChanged(int index);
|
||||
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 onMenuDialogCalled(const QPoint& p);
|
||||
|
||||
|
@ -56,7 +56,16 @@
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</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>
|
||||
</property>
|
||||
<item>
|
||||
@ -476,13 +485,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="mic">
|
||||
<property name="toolTip">
|
||||
@ -500,6 +502,75 @@
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
@ -520,6 +591,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="ctcssLayer">
|
||||
<item>
|
||||
<widget class="QLabel" name="ctcssLabel">
|
||||
<property name="text">
|
||||
@ -550,6 +625,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -61,7 +61,7 @@ void NFMModSettings::resetToDefaults()
|
||||
m_modAFInput = NFMModInputAF::NFMModInputNone;
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackVolumeFactor = 1.0f;
|
||||
m_feedbackVolumeFactor = 0.5f;
|
||||
m_feedbackAudioEnable = false;
|
||||
m_useReverseAPI = false;
|
||||
m_reverseAPIAddress = "127.0.0.1";
|
||||
|
@ -66,7 +66,7 @@ SSBMod::SSBMod(DeviceAPI *deviceAPI) :
|
||||
m_DSBFilterBufferIndex(0),
|
||||
m_sampleSink(0),
|
||||
m_audioFifo(4800),
|
||||
m_feedbackAudioFifo(4800),
|
||||
m_feedbackAudioFifo(48000),
|
||||
m_settingsMutex(QMutex::Recursive),
|
||||
m_fileSize(0),
|
||||
m_recordLength(0),
|
||||
@ -83,6 +83,7 @@ SSBMod::SSBMod(DeviceAPI *deviceAPI) :
|
||||
|
||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue());
|
||||
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_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()
|
||||
{
|
||||
pullAF(m_modSample);
|
||||
|
||||
if (m_settings.m_feedbackAudioEnable) {
|
||||
pushFeedback(m_modSample * m_settings.m_feedbackVolumeFactor * 16384.0f);
|
||||
}
|
||||
|
||||
calculateLevel(m_modSample);
|
||||
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)
|
||||
{
|
||||
Real t = sample.real(); // TODO: possibly adjust depending on sample type
|
||||
@ -617,12 +666,23 @@ bool SSBMod::handleMessage(const Message& cmd)
|
||||
{
|
||||
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
||||
uint32_t sampleRate = cfg.getSampleRate();
|
||||
DSPConfigureAudio::AudioType audioType = cfg.getAudioType();
|
||||
|
||||
qDebug() << "SSBMod::handleMessage: DSPConfigureAudio:"
|
||||
<< " sampleRate: " << sampleRate;
|
||||
<< " sampleRate: " << sampleRate
|
||||
<< " audioType: " << audioType;
|
||||
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyAudioSampleRate(sampleRate);
|
||||
if (audioType == DSPConfigureAudio::AudioInput)
|
||||
{
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyAudioSampleRate(sampleRate);
|
||||
}
|
||||
}
|
||||
else if (audioType == DSPConfigureAudio::AudioOutput)
|
||||
{
|
||||
if (sampleRate != m_audioSampleRate) {
|
||||
applyFeedbackAudioSampleRate(sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -727,6 +787,25 @@ void SSBMod::applyAudioSampleRate(int sampleRate)
|
||||
DSPConfigureAudio *cfg = new DSPConfigureAudio(m_audioSampleRate, DSPConfigureAudio::AudioInput);
|
||||
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)
|
||||
@ -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)
|
||||
{
|
||||
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||
|
@ -282,11 +282,18 @@ private:
|
||||
NCOF m_carrierNco;
|
||||
NCOF m_toneNco;
|
||||
Complex m_modSample;
|
||||
|
||||
Interpolator m_interpolator;
|
||||
Real m_interpolatorDistance;
|
||||
Real m_interpolatorDistanceRemain;
|
||||
bool m_interpolatorConsumed;
|
||||
fftfilt* m_SSBFilter;
|
||||
|
||||
Interpolator m_feedbackInterpolator;
|
||||
Real m_feedbackInterpolatorDistance;
|
||||
Real m_feedbackInterpolatorDistanceRemain;
|
||||
bool m_feedbackInterpolatorConsumed;
|
||||
|
||||
fftfilt* m_SSBFilter;
|
||||
fftfilt* m_DSBFilter;
|
||||
Complex* m_SSBFilterBuffer;
|
||||
Complex* m_DSBFilterBuffer;
|
||||
@ -336,9 +343,12 @@ private:
|
||||
static const int m_levelNbSamples;
|
||||
|
||||
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 applySettings(const SSBModSettings& settings, bool force = false);
|
||||
void pullAF(Complex& sample);
|
||||
void pushFeedback(Complex sample);
|
||||
void calculateLevel(Complex& sample);
|
||||
void modulateSample();
|
||||
void openFileStream();
|
||||
|
@ -292,6 +292,19 @@ void SSBModGUI::on_mic_toggled(bool checked)
|
||||
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)
|
||||
{
|
||||
m_settings.m_agc = checked;
|
||||
@ -679,6 +692,10 @@ void SSBModGUI::displaySettings()
|
||||
ui->play->setChecked(m_settings.m_modAFInput == SSBModSettings::SSBModInputAF::SSBModInputFile);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,9 @@ private slots:
|
||||
void on_navTimeSlider_valueChanged(int value);
|
||||
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 onMenuDialogCalled(const QPoint& p);
|
||||
|
||||
|
@ -811,13 +811,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="mic">
|
||||
<property name="toolTip">
|
||||
@ -835,6 +828,75 @@
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
|
@ -64,7 +64,7 @@ void SSBModSettings::resetToDefaults()
|
||||
m_modAFInput = SSBModInputAF::SSBModInputNone;
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackVolumeFactor = 1.0f;
|
||||
m_feedbackVolumeFactor = 0.5f;
|
||||
m_feedbackAudioEnable = false;
|
||||
m_useReverseAPI = false;
|
||||
m_reverseAPIAddress = "127.0.0.1";
|
||||
|
@ -60,7 +60,6 @@ WFMMod::WFMMod(DeviceAPI *deviceAPI) :
|
||||
m_inputFrequencyOffset(0),
|
||||
m_modPhasor(0.0f),
|
||||
m_audioFifo(4800),
|
||||
m_feedbackAudioFifo(4800),
|
||||
m_settingsMutex(QMutex::Recursive),
|
||||
m_fileSize(0),
|
||||
m_recordLength(0),
|
||||
@ -80,17 +79,11 @@ WFMMod::WFMMod(DeviceAPI *deviceAPI) :
|
||||
m_audioBuffer.resize(1<<14);
|
||||
m_audioBufferFill = 0;
|
||||
|
||||
m_feedbackAudioBuffer.resize(1<<14);
|
||||
m_feedbackAudioBufferFill = 0;
|
||||
|
||||
m_magsq = 0.0;
|
||||
|
||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
|
||||
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_cwKeyer.setSampleRate(m_outputSampleRate);
|
||||
m_cwKeyer.reset();
|
||||
@ -111,7 +104,6 @@ WFMMod::~WFMMod()
|
||||
{
|
||||
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||
delete m_networkManager;
|
||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_feedbackAudioFifo);
|
||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSource(&m_audioFifo);
|
||||
m_deviceAPI->removeChannelSourceAPI(this);
|
||||
m_deviceAPI->removeChannelSource(m_threadedChannelizer);
|
||||
|
@ -297,11 +297,6 @@ private:
|
||||
uint m_audioBufferFill;
|
||||
AudioFifo m_audioFifo;
|
||||
|
||||
quint32 m_feedbackAudioSampleRate;
|
||||
AudioVector m_feedbackAudioBuffer;
|
||||
uint m_feedbackAudioBufferFill;
|
||||
AudioFifo m_feedbackAudioFifo;
|
||||
|
||||
SampleVector m_sampleBuffer;
|
||||
QMutex m_settingsMutex;
|
||||
|
||||
|
@ -50,9 +50,6 @@ void WFMModSettings::resetToDefaults()
|
||||
m_title = "WFM Modulator";
|
||||
m_modAFInput = WFMModInputNone;
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_feedbackVolumeFactor = 1.0f;
|
||||
m_feedbackAudioEnable = false;
|
||||
m_useReverseAPI = false;
|
||||
m_reverseAPIAddress = "127.0.0.1";
|
||||
m_reverseAPIPort = 8888;
|
||||
@ -88,9 +85,6 @@ QByteArray WFMModSettings::serialize() const
|
||||
s.writeU32(15, m_reverseAPIPort);
|
||||
s.writeU32(16, m_reverseAPIDeviceIndex);
|
||||
s.writeU32(17, m_reverseAPIChannelIndex);
|
||||
s.writeString(18, m_feedbackAudioDeviceName);
|
||||
s.writeReal(19, m_feedbackVolumeFactor);
|
||||
s.writeBool(20, m_feedbackAudioEnable);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -154,9 +148,6 @@ bool WFMModSettings::deserialize(const QByteArray& data)
|
||||
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||
d.readU32(17, &utmp, 0);
|
||||
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;
|
||||
}
|
||||
|
@ -48,9 +48,6 @@ struct WFMModSettings
|
||||
QString m_title;
|
||||
WFMModInputAF m_modAFInput;
|
||||
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;
|
||||
QString m_reverseAPIAddress;
|
||||
uint16_t m_reverseAPIPort;
|
||||
|
@ -388,7 +388,7 @@ public:
|
||||
{ }
|
||||
|
||||
int getSampleRate() const { return m_sampleRate; }
|
||||
bool getAudioType() const { return m_autioType; }
|
||||
AudioType getAudioType() const { return m_autioType; }
|
||||
|
||||
private:
|
||||
int m_sampleRate;
|
||||
|
Loading…
Reference in New Issue
Block a user