1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-06-05 15:34:57 -04:00

FreeDV modulator: implemented audio input with possible resampling

This commit is contained in:
f4exb
2019-02-24 20:59:09 +01:00
parent 951e0243f2
commit cc4604f6d8
18 changed files with 290 additions and 24 deletions
+80 -15
View File
@@ -182,7 +182,7 @@ void FreeDVMod::pull(Sample& sample)
void FreeDVMod::pullAudio(int nbSamples)
{
unsigned int nbSamplesAudio = nbSamples * ((Real) m_audioSampleRate / (Real) m_basebandSampleRate);
unsigned int nbSamplesAudio = nbSamples * ((Real) m_audioSampleRate / (Real) m_modemSampleRate);
if (nbSamplesAudio > m_audioBuffer.size())
{
@@ -196,7 +196,9 @@ void FreeDVMod::pullAudio(int nbSamples)
void FreeDVMod::modulateSample()
{
pullAF(m_modSample);
calculateLevel(m_modSample);
if (!m_settings.m_gaugeInputElseModem) {
calculateLevel(m_modSample);
}
m_audioBufferFill++;
}
@@ -221,8 +223,12 @@ void FreeDVMod::pullAF(Complex& sample)
switch (m_settings.m_modAFInput)
{
case FreeDVModSettings::FreeDVModInputTone:
for (int i = 0; i < m_nSpeechSamples; i++) {
for (int i = 0; i < m_nSpeechSamples; i++)
{
m_speechIn[i] = m_toneNco.next() * 32768.0f * m_settings.m_volumeFactor;
if (m_settings.m_gaugeInputElseModem) {
calculateLevel(m_speechIn[i]);
}
}
freedv_tx(m_freeDV, m_modOut, m_speechIn);
break;
@@ -251,10 +257,16 @@ void FreeDVMod::pullAF(Complex& sample)
m_ifstream.read(reinterpret_cast<char*>(m_speechIn), sizeof(int16_t) * m_nSpeechSamples);
if (m_settings.m_volumeFactor != 1.0)
if ((m_settings.m_volumeFactor != 1.0) || m_settings.m_gaugeInputElseModem)
{
for (int i = 0; i < m_nSpeechSamples; i++) {
m_speechIn[i] *= m_settings.m_volumeFactor;
for (int i = 0; i < m_nSpeechSamples; i++)
{
if (m_settings.m_volumeFactor != 1.0) {
m_speechIn[i] *= m_settings.m_volumeFactor;
}
if (m_settings.m_gaugeInputElseModem) {
calculateLevel(m_speechIn[i]);
}
}
}
@@ -268,8 +280,20 @@ void FreeDVMod::pullAF(Complex& sample)
}
break;
case FreeDVModSettings::FreeDVModInputAudio:
for (int i = 0; i < m_nSpeechSamples; i++) {
m_speechIn[i] = (m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) * (m_settings.m_volumeFactor / 2);
for (int i = 0; i < m_nSpeechSamples; i++)
{
qint16 audioSample = (m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) * (m_settings.m_volumeFactor / 2.0f);
m_audioBufferFill++;
while (!m_audioResampler.downSample(audioSample, m_speechIn[i]))
{
audioSample = (m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) * (m_settings.m_volumeFactor / 2.0f);
m_audioBufferFill++;
}
if (m_settings.m_gaugeInputElseModem) {
calculateLevel(m_speechIn[i]);
}
}
freedv_tx(m_freeDV, m_modOut, m_speechIn);
break;
@@ -295,6 +319,10 @@ void FreeDVMod::pullAF(Complex& sample)
m_toneNco.setPhase(0);
}
}
if (m_settings.m_gaugeInputElseModem) {
calculateLevel(m_speechIn[i]);
}
}
freedv_tx(m_freeDV, m_modOut, m_speechIn);
break;
@@ -367,6 +395,27 @@ void FreeDVMod::calculateLevel(Complex& sample)
}
}
void FreeDVMod::calculateLevel(qint16& sample)
{
Real t = sample / SDR_TX_SCALEF;
if (m_levelCalcCount < m_levelNbSamples)
{
m_peakLevel = std::max(std::fabs(m_peakLevel), t);
m_levelSum += t * t;
m_levelCalcCount++;
}
else
{
qreal rmsLevel = sqrt(m_levelSum / m_levelNbSamples);
//qDebug("FreeDVMod::calculateLevel: %f %f", rmsLevel, m_peakLevel);
emit levelChanged(rmsLevel, m_peakLevel, m_levelNbSamples);
m_peakLevel = 0.0f;
m_levelSum = 0.0f;
m_levelCalcCount = 0;
}
}
void FreeDVMod::start()
{
qDebug() << "FreeDVMod::start: m_outputSampleRate: " << m_outputSampleRate
@@ -522,6 +571,12 @@ void FreeDVMod::applyAudioSampleRate(int sampleRate)
{
qDebug("FreeDVMod::applyAudioSampleRate: %d", sampleRate);
// TODO: put up simple IIR interpolator when sampleRate < m_modemSampleRate
m_settingsMutex.lock();
m_audioResampler.setDecimation(sampleRate / m_inputSampleRate);
m_audioResampler.setAudioFilters(sampleRate, m_inputSampleRate, 250, 3300);
m_settingsMutex.unlock();
m_audioSampleRate = sampleRate;
}
@@ -686,6 +741,9 @@ void FreeDVMod::applySettings(const FreeDVModSettings& settings, bool force)
if ((settings.m_playLoop != m_settings.m_playLoop) || force) {
reverseAPIKeys.append("playLoop");
}
if ((settings.m_playLoop != m_settings.m_gaugeInputElseModem) || force) {
reverseAPIKeys.append("gaugeInputElseModem");
}
if ((settings.m_rgbColor != m_settings.m_rgbColor) || force) {
reverseAPIKeys.append("rgbColor");
}
@@ -801,6 +859,9 @@ int FreeDVMod::webapiSettingsPutPatch(
if (channelSettingsKeys.contains("playLoop")) {
settings.m_playLoop = response.getFreeDvModSettings()->getPlayLoop() != 0;
}
if (channelSettingsKeys.contains("gaugeInputElseModem")) {
settings.m_gaugeInputElseModem = response.getFreeDvModSettings()->getGaugeInputElseModem() != 0;
}
if (channelSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getFreeDvModSettings()->getRgbColor();
}
@@ -907,6 +968,7 @@ void FreeDVMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res
response.getFreeDvModSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
response.getFreeDvModSettings()->setPlayLoop(settings.m_playLoop ? 1 : 0);
response.getFreeDvModSettings()->setRgbColor(settings.m_rgbColor);
response.getFreeDvModSettings()->setGaugeInputElseModem(settings.m_gaugeInputElseModem ? 1 : 0);
if (response.getFreeDvModSettings()->getTitle()) {
*response.getFreeDvModSettings()->getTitle() = settings.m_title;
@@ -940,17 +1002,17 @@ void FreeDVMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res
apiCwKeyerSettings->setWpm(cwKeyerSettings.m_wpm);
response.getAmModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
response.getFreeDvModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getAmModSettings()->getReverseApiAddress()) {
*response.getAmModSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
if (response.getFreeDvModSettings()->getReverseApiAddress()) {
*response.getFreeDvModSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getAmModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
response.getFreeDvModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getAmModSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getAmModSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
response.getAmModSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
response.getFreeDvModSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getFreeDvModSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
response.getFreeDvModSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
}
void FreeDVMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
@@ -988,6 +1050,9 @@ void FreeDVMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c
if (channelSettingsKeys.contains("playLoop") || force) {
swgFreeDVModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0);
}
if (channelSettingsKeys.contains("gaugeInputElseModem") || force) {
swgFreeDVModSettings->setPlayLoop(settings.m_gaugeInputElseModem ? 1 : 0);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgFreeDVModSettings->setRgbColor(settings.m_rgbColor);
}
+3
View File
@@ -34,6 +34,7 @@
#include "dsp/fftfilt.h"
#include "dsp/cwkeyer.h"
#include "audio/audiofifo.h"
#include "audio/audioresampler.h"
#include "util/message.h"
#include "freedvmodsettings.h"
@@ -325,6 +326,7 @@ private:
int16_t *m_speechIn;
int16_t *m_modOut;
float m_scaleFactor; //!< divide by this amount to scale from int16 to float in [-1.0, 1.0] interval
AudioResampler m_audioResampler;
static const int m_levelNbSamples;
@@ -334,6 +336,7 @@ private:
void applyFreeDVMode(FreeDVModSettings::FreeDVMode mode);
void pullAF(Complex& sample);
void calculateLevel(Complex& sample);
void calculateLevel(qint16& sample);
void modulateSample();
void openFileStream();
void seekFileStream(int seekPercentage);
@@ -182,6 +182,12 @@ void FreeDVModGUI::on_spanLog2_valueChanged(int value)
applyBandwidths(5 - value);
}
void FreeDVModGUI::on_gaugeInput_toggled(bool checked)
{
m_settings.m_gaugeInputElseModem = checked;
applySettings();
}
void FreeDVModGUI::on_toneFrequency_valueChanged(int value)
{
ui->toneFrequencyText->setText(QString("%1k").arg(value / 100.0, 0, 'f', 2));
@@ -463,6 +469,7 @@ void FreeDVModGUI::displaySettings()
ui->spanLog2->blockSignals(true);
ui->spanLog2->setValue(5 - m_settings.m_spanLog2);
ui->gaugeInput->setChecked(m_settings.m_gaugeInputElseModem);
QString s = QString::number(m_freeDVMod->getHiCutoff()/1000.0, 'f', 1);
@@ -97,6 +97,7 @@ private slots:
void handleSourceMessages();
void on_deltaFrequency_changed(qint64 value);
void on_spanLog2_valueChanged(int value);
void on_gaugeInput_toggled(bool checked);
void on_volume_valueChanged(int value);
void on_audioMute_toggled(bool checked);
void on_freeDVMode_currentIndexChanged(int index);
@@ -167,6 +167,16 @@
</item>
<item>
<layout class="QHBoxLayout" name="volumeLayout">
<item>
<widget class="QCheckBox" name="gaugeInput">
<property name="toolTip">
<string>Check to see input level else shows modem level</string>
</property>
<property name="text">
<string>In</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="volLabel">
<property name="text">
@@ -42,6 +42,7 @@ void FreeDVModSettings::resetToDefaults()
m_modAFInput = FreeDVModInputAF::FreeDVModInputNone;
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
m_freeDVMode = FreeDVMode::FreeDVMode2400A;
m_gaugeInputElseModem = false;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
@@ -66,6 +67,7 @@ QByteArray FreeDVModSettings::serialize() const
s.writeBlob(6, m_cwKeyerGUI->serialize());
}
s.writeBool(7, m_gaugeInputElseModem);
s.writeS32(8, m_spanLog2);
s.writeS32(10, (int) m_freeDVMode);
@@ -120,6 +122,7 @@ bool FreeDVModSettings::deserialize(const QByteArray& data)
m_cwKeyerGUI->deserialize(bytetmp);
}
d.readBool(7, &m_gaugeInputElseModem, false);
d.readS32(8, &m_spanLog2, 3);
d.readS32(10, &tmp, 0);
@@ -54,6 +54,7 @@ struct FreeDVModSettings
FreeDVModInputAF m_modAFInput;
QString m_audioDeviceName;
FreeDVMode m_freeDVMode;
bool m_gaugeInputElseModem; //!< Volume gauge shows speech input level else modem level
bool m_useReverseAPI;
QString m_reverseAPIAddress;
+7 -7
View File
@@ -1199,17 +1199,17 @@ void SSBMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respon
apiCwKeyerSettings->setWpm(cwKeyerSettings.m_wpm);
response.getAmModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
response.getSsbModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getAmModSettings()->getReverseApiAddress()) {
*response.getAmModSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
if (response.getSsbModSettings()->getReverseApiAddress()) {
*response.getSsbModSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getAmModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
response.getSsbModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getAmModSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getAmModSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
response.getAmModSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
response.getSsbModSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getSsbModSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
response.getSsbModSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
}
void SSBMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)