mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-02-03 09:44:01 -05:00
FreeDV mod: reworked input audio. Implements #495
This commit is contained in:
parent
f19431ac5c
commit
49cceb40cc
@ -35,7 +35,7 @@ FreeDVModSource::FreeDVModSource() :
|
|||||||
m_SSBFilterBuffer(0),
|
m_SSBFilterBuffer(0),
|
||||||
m_SSBFilterBufferIndex(0),
|
m_SSBFilterBufferIndex(0),
|
||||||
m_audioSampleRate(48000),
|
m_audioSampleRate(48000),
|
||||||
m_audioFifo(4800),
|
m_audioFifo(12000),
|
||||||
m_levelCalcCount(0),
|
m_levelCalcCount(0),
|
||||||
m_peakLevel(0.0f),
|
m_peakLevel(0.0f),
|
||||||
m_levelSum(0.0f),
|
m_levelSum(0.0f),
|
||||||
@ -46,14 +46,17 @@ FreeDVModSource::FreeDVModSource() :
|
|||||||
m_iModem(0),
|
m_iModem(0),
|
||||||
m_speechIn(nullptr),
|
m_speechIn(nullptr),
|
||||||
m_modOut(0),
|
m_modOut(0),
|
||||||
m_scaleFactor(SDR_TX_SCALEF)
|
m_scaleFactor(SDR_TX_SCALEF),
|
||||||
|
m_mutex(QMutex::Recursive)
|
||||||
{
|
{
|
||||||
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});
|
||||||
|
|
||||||
m_audioBuffer.resize(1<<14);
|
m_audioBuffer.resize(24000);
|
||||||
m_audioBufferFill = 0;
|
m_audioBufferFill = 0;
|
||||||
|
m_audioReadBuffer.resize(24000);
|
||||||
|
m_audioReadBufferFill = 0;
|
||||||
|
|
||||||
m_sum.real(0.0f);
|
m_sum.real(0.0f);
|
||||||
m_sum.imag(0.0f);
|
m_sum.imag(0.0f);
|
||||||
@ -131,15 +134,40 @@ void FreeDVModSource::prefetch(unsigned int nbSamples)
|
|||||||
|
|
||||||
void FreeDVModSource::pullAudio(unsigned int nbSamples)
|
void FreeDVModSource::pullAudio(unsigned int nbSamples)
|
||||||
{
|
{
|
||||||
|
QMutexLocker mlock(&m_mutex);
|
||||||
unsigned int nbSamplesAudio = nbSamples * ((Real) m_audioSampleRate / (Real) m_modemSampleRate);
|
unsigned int nbSamplesAudio = nbSamples * ((Real) m_audioSampleRate / (Real) m_modemSampleRate);
|
||||||
|
|
||||||
if (nbSamplesAudio > m_audioBuffer.size())
|
if (nbSamplesAudio > m_audioBuffer.size()) {
|
||||||
{
|
|
||||||
m_audioBuffer.resize(nbSamplesAudio);
|
m_audioBuffer.resize(nbSamplesAudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_audioFifo.read(reinterpret_cast<quint8*>(&m_audioBuffer[0]), nbSamplesAudio);
|
std::copy(&m_audioReadBuffer[0], &m_audioReadBuffer[nbSamplesAudio], &m_audioBuffer[0]);
|
||||||
m_audioBufferFill = 0;
|
m_audioBufferFill = 0;
|
||||||
|
|
||||||
|
if (m_audioReadBufferFill > nbSamplesAudio) // copy back remaining samples at the start of the read buffer
|
||||||
|
{
|
||||||
|
std::copy(&m_audioReadBuffer[nbSamplesAudio], &m_audioReadBuffer[m_audioReadBufferFill], &m_audioReadBuffer[0]);
|
||||||
|
m_audioReadBufferFill = m_audioReadBufferFill - nbSamplesAudio; // adjust current read buffer fill pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qint16 FreeDVModSource::getAudioSample()
|
||||||
|
{
|
||||||
|
qint16 sample;
|
||||||
|
|
||||||
|
if (m_audioBufferFill < m_audioBuffer.size())
|
||||||
|
{
|
||||||
|
sample = (m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) * (m_settings.m_volumeFactor / 2.0f);
|
||||||
|
m_audioBufferFill++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int size = m_audioBuffer.size();
|
||||||
|
qDebug("FreeDVModSource::getAudioSample: starve audio samples: size: %u", size);
|
||||||
|
sample = (m_audioBuffer[size-1].l + m_audioBuffer[size-1].r) * (m_settings.m_volumeFactor / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeDVModSource::modulateSample()
|
void FreeDVModSource::modulateSample()
|
||||||
@ -148,7 +176,6 @@ void FreeDVModSource::modulateSample()
|
|||||||
if (!m_settings.m_gaugeInputElseModem) {
|
if (!m_settings.m_gaugeInputElseModem) {
|
||||||
calculateLevel(m_modSample);
|
calculateLevel(m_modSample);
|
||||||
}
|
}
|
||||||
m_audioBufferFill++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeDVModSource::pullAF(Complex& sample)
|
void FreeDVModSource::pullAF(Complex& sample)
|
||||||
@ -231,13 +258,11 @@ void FreeDVModSource::pullAF(Complex& sample)
|
|||||||
case FreeDVModSettings::FreeDVModInputAudio:
|
case FreeDVModSettings::FreeDVModInputAudio:
|
||||||
for (int i = 0; i < m_nSpeechSamples; i++)
|
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);
|
qint16 audioSample = getAudioSample();
|
||||||
m_audioBufferFill++;
|
|
||||||
|
|
||||||
while (!m_audioResampler.downSample(audioSample, m_speechIn[i]))
|
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);
|
audioSample = getAudioSample();
|
||||||
m_audioBufferFill++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_settings.m_gaugeInputElseModem) {
|
if (m_settings.m_gaugeInputElseModem) {
|
||||||
@ -518,5 +543,27 @@ void FreeDVModSource::applySettings(const FreeDVModSettings& settings, bool forc
|
|||||||
m_toneNco.setFreq(settings.m_toneFrequency, m_channelSampleRate);
|
m_toneNco.setFreq(settings.m_toneFrequency, m_channelSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((settings.m_modAFInput != m_settings.m_modAFInput) || force)
|
||||||
|
{
|
||||||
|
if (settings.m_modAFInput == FreeDVModSettings::FreeDVModInputAudio) {
|
||||||
|
connect(&m_audioFifo, SIGNAL(dataReady()), this, SLOT(handleAudio()));
|
||||||
|
} else {
|
||||||
|
disconnect(&m_audioFifo, SIGNAL(dataReady()), this, SLOT(handleAudio()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_settings = settings;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FreeDVModSource::handleAudio()
|
||||||
|
{
|
||||||
|
QMutexLocker mlock(&m_mutex);
|
||||||
|
unsigned int nbRead;
|
||||||
|
|
||||||
|
while ((nbRead = m_audioFifo.read(reinterpret_cast<quint8*>(&m_audioReadBuffer[m_audioReadBufferFill]), 4096)) != 0)
|
||||||
|
{
|
||||||
|
if (m_audioReadBufferFill + nbRead + 4096 < m_audioReadBuffer.size()) {
|
||||||
|
m_audioReadBufferFill += nbRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#ifndef INCLUDE_FREEDVMODSOURCE_H
|
#ifndef INCLUDE_FREEDVMODSOURCE_H
|
||||||
#define INCLUDE_FREEDVMODSOURCE_H
|
#define INCLUDE_FREEDVMODSOURCE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -37,8 +38,9 @@
|
|||||||
|
|
||||||
class BasebandSampleSink;
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class FreeDVModSource : public ChannelSampleSource
|
class FreeDVModSource : public QObject, public ChannelSampleSource
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
FreeDVModSource();
|
FreeDVModSource();
|
||||||
virtual ~FreeDVModSource();
|
virtual ~FreeDVModSource();
|
||||||
@ -102,7 +104,9 @@ private:
|
|||||||
|
|
||||||
int m_audioSampleRate;
|
int m_audioSampleRate;
|
||||||
AudioVector m_audioBuffer;
|
AudioVector m_audioBuffer;
|
||||||
uint m_audioBufferFill;
|
unsigned int m_audioBufferFill;
|
||||||
|
AudioVector m_audioReadBuffer;
|
||||||
|
unsigned int m_audioReadBufferFill;
|
||||||
AudioFifo m_audioFifo;
|
AudioFifo m_audioFifo;
|
||||||
|
|
||||||
quint32 m_levelCalcCount;
|
quint32 m_levelCalcCount;
|
||||||
@ -124,15 +128,21 @@ private:
|
|||||||
float m_scaleFactor; //!< divide by this amount to scale from int16 to float in [-1.0, 1.0] interval
|
float m_scaleFactor; //!< divide by this amount to scale from int16 to float in [-1.0, 1.0] interval
|
||||||
AudioResampler m_audioResampler;
|
AudioResampler m_audioResampler;
|
||||||
|
|
||||||
|
QMutex m_mutex;
|
||||||
|
|
||||||
static const int m_levelNbSamples;
|
static const int m_levelNbSamples;
|
||||||
|
|
||||||
void processOneSample(Complex& ci);
|
void processOneSample(Complex& ci);
|
||||||
void pullAF(Complex& sample);
|
void pullAF(Complex& sample);
|
||||||
void pullAudio(unsigned int nbSamples);
|
void pullAudio(unsigned int nbSamples);
|
||||||
|
qint16 getAudioSample();
|
||||||
void pushFeedback(Real sample);
|
void pushFeedback(Real sample);
|
||||||
void calculateLevel(Complex& sample);
|
void calculateLevel(Complex& sample);
|
||||||
void calculateLevel(qint16& sample);
|
void calculateLevel(qint16& sample);
|
||||||
void modulateSample();
|
void modulateSample();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleAudio();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user