From e02ac85e504f61e384d4df836165941a9c3cd7ba Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 26 Dec 2016 01:39:34 +0100 Subject: [PATCH] All modulators: use buffer for input audio that is always in use while generation is running. This fixes lockup problem reported in issue #11 --- plugins/channeltx/modam/ammod.cpp | 23 ++++++-- plugins/channeltx/modam/ammod.h | 5 +- plugins/channeltx/modnfm/nfmmod.cpp | 21 +++++-- plugins/channeltx/modnfm/nfmmod.h | 5 +- plugins/channeltx/modssb/ssbmod.cpp | 29 +++++---- plugins/channeltx/modssb/ssbmod.h | 5 +- plugins/channeltx/modwfm/wfmmod.cpp | 23 +++++--- plugins/channeltx/modwfm/wfmmod.h | 5 +- sdrbase/dsp/basebandsamplesource.h | 2 + sdrbase/dsp/dspdevicesinkengine.cpp | 91 ++++++++++++++++------------- sdrbase/dsp/upchannelizer.h | 1 + 11 files changed, 131 insertions(+), 79 deletions(-) diff --git a/plugins/channeltx/modam/ammod.cpp b/plugins/channeltx/modam/ammod.cpp index de57a690f..4cb60acb9 100644 --- a/plugins/channeltx/modam/ammod.cpp +++ b/plugins/channeltx/modam/ammod.cpp @@ -57,8 +57,8 @@ AMMod::AMMod() : apply(); - //m_audioBuffer.resize(1<<14); - //m_audioBufferFill = 0; + m_audioBuffer.resize(1<<14); + m_audioBufferFill = 0; m_movingAverage.resize(16, 0); m_volumeAGC.resize(4096, 0.003, 0); @@ -121,6 +121,7 @@ void AMMod::pull(Sample& sample) } } + m_audioBufferFill++; m_interpolatorDistanceRemain += m_interpolatorDistance; ci *= m_carrierNco.nextIQ(); // shift to carrier frequency @@ -136,6 +137,19 @@ void AMMod::pull(Sample& sample) sample.m_imag = (FixReal) ci.imag(); } +void AMMod::pullAudio(int nbSamples) +{ +// qDebug("AMMod::pullAudio: %d", nbSamples); + + if (nbSamples > m_audioBuffer.size()) + { + m_audioBuffer.resize(nbSamples); + } + + m_audioFifo.read(reinterpret_cast(&m_audioBuffer[0]), nbSamples*sizeof(AudioSample), 10); + m_audioBufferFill = 0; +} + void AMMod::modulateSample() { Real t; @@ -149,8 +163,6 @@ void AMMod::modulateSample() void AMMod::pullAF(Real& sample) { - int16_t audioSample[2]; - switch (m_afInput) { case AMModInputTone: @@ -186,8 +198,7 @@ void AMMod::pullAF(Real& sample) } break; case AMModInputAudio: - m_audioFifo.read(reinterpret_cast(audioSample), 1, 10); - sample = ((audioSample[0] + audioSample[1]) / 65536.0f) * m_running.m_volumeFactor; + sample = ((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f) * m_running.m_volumeFactor; break; case AMModInputCWTone: Real fadeFactor; diff --git a/plugins/channeltx/modam/ammod.h b/plugins/channeltx/modam/ammod.h index 0e16320f2..06baec852 100644 --- a/plugins/channeltx/modam/ammod.h +++ b/plugins/channeltx/modam/ammod.h @@ -185,6 +185,7 @@ public: bool playLoop); virtual void pull(Sample& sample); + virtual void pullAudio(int nbSamples); virtual void start(); virtual void stop(); virtual bool handleMessage(const Message& cmd); @@ -294,8 +295,8 @@ private: MovingAverage m_movingAverage; SimpleAGC m_volumeAGC; - //AudioVector m_audioBuffer; - //uint m_audioBufferFill; + AudioVector m_audioBuffer; + uint m_audioBufferFill; AudioFifo m_audioFifo; SampleVector m_sampleBuffer; diff --git a/plugins/channeltx/modnfm/nfmmod.cpp b/plugins/channeltx/modnfm/nfmmod.cpp index 64fda354e..ce6f4a75d 100644 --- a/plugins/channeltx/modnfm/nfmmod.cpp +++ b/plugins/channeltx/modnfm/nfmmod.cpp @@ -59,8 +59,8 @@ NFMMod::NFMMod() : apply(); - //m_audioBuffer.resize(1<<14); - //m_audioBufferFill = 0; + m_audioBuffer.resize(1<<14); + m_audioBufferFill = 0; m_movingAverage.resize(16, 0); m_volumeAGC.resize(4096, 0.003, 0); @@ -136,6 +136,7 @@ void NFMMod::pull(Sample& sample) } } + m_audioBufferFill++; m_interpolatorDistanceRemain += m_interpolatorDistance; ci *= m_carrierNco.nextIQ(); // shift to carrier frequency @@ -151,6 +152,17 @@ void NFMMod::pull(Sample& sample) sample.m_imag = (FixReal) ci.imag(); } +void NFMMod::pullAudio(int nbSamples) +{ + if (nbSamples > m_audioBuffer.size()) + { + m_audioBuffer.resize(nbSamples); + } + + m_audioFifo.read(reinterpret_cast(&m_audioBuffer[0]), nbSamples*sizeof(AudioSample), 10); + m_audioBufferFill = 0; +} + void NFMMod::modulateSample() { Real t; @@ -174,8 +186,6 @@ void NFMMod::modulateSample() void NFMMod::pullAF(Real& sample) { - int16_t audioSample[2]; - switch (m_afInput) { case NFMModInputTone: @@ -211,8 +221,7 @@ void NFMMod::pullAF(Real& sample) } break; case NFMModInputAudio: - m_audioFifo.read(reinterpret_cast(audioSample), 1, 10); - sample = ((audioSample[0] + audioSample[1]) / 65536.0f) * m_running.m_volumeFactor; + sample = ((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f) * m_running.m_volumeFactor; break; case NFMModInputCWTone: Real fadeFactor; diff --git a/plugins/channeltx/modnfm/nfmmod.h b/plugins/channeltx/modnfm/nfmmod.h index eb6e2978d..192455110 100644 --- a/plugins/channeltx/modnfm/nfmmod.h +++ b/plugins/channeltx/modnfm/nfmmod.h @@ -190,6 +190,7 @@ public: float ctcssFrequency); virtual void pull(Sample& sample); + virtual void pullAudio(int nbSamples); virtual void start(); virtual void stop(); virtual bool handleMessage(const Message& cmd); @@ -342,8 +343,8 @@ private: MovingAverage m_movingAverage; SimpleAGC m_volumeAGC; - //AudioVector m_audioBuffer; - //uint m_audioBufferFill; + AudioVector m_audioBuffer; + uint m_audioBufferFill; AudioFifo m_audioFifo; SampleVector m_sampleBuffer; diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index 98ff21b6c..9e2cebcc4 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -69,8 +69,8 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) : m_config.m_toneFrequency = 1000.0f; m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); - //m_audioBuffer.resize(1<<14); - //m_audioBufferFill = 0; + m_audioBuffer.resize(1<<14); + m_audioBufferFill = 0; // m_magsqSpectrum = 0.0f; // m_magsqSum = 0.0f; @@ -166,6 +166,7 @@ void SSBMod::pull(Sample& sample) } } + m_audioBufferFill++; m_interpolatorDistanceRemain += m_interpolatorDistance; ci *= m_carrierNco.nextIQ(); // shift to carrier frequency @@ -182,6 +183,17 @@ void SSBMod::pull(Sample& sample) sample.m_imag = (FixReal) ci.imag(); } +void SSBMod::pullAudio(int nbSamples) +{ + if (nbSamples > m_audioBuffer.size()) + { + m_audioBuffer.resize(nbSamples); + } + + m_audioFifo.read(reinterpret_cast(&m_audioBuffer[0]), nbSamples*sizeof(AudioSample), 10); + m_audioBufferFill = 0; +} + void SSBMod::modulateSample() { pullAF(m_modSample); @@ -197,7 +209,6 @@ void SSBMod::pullAF(Complex& sample) return; } - int16_t audioSample[2]; Complex ci; fftfilt::cmplx *filtered; int n_out = 0; @@ -279,24 +290,22 @@ void SSBMod::pullAF(Complex& sample) } break; case SSBModInputAudio: - m_audioFifo.read(reinterpret_cast(audioSample), 1, 10); - if (m_running.m_audioBinaural) { if (m_running.m_audioFlipChannels) { - ci.real((audioSample[1] / 32768.0f) * m_running.m_volumeFactor); - ci.imag((audioSample[0] / 32768.0f) * m_running.m_volumeFactor); + ci.real((m_audioBuffer[m_audioBufferFill].r / 32768.0f) * m_running.m_volumeFactor); + ci.imag((m_audioBuffer[m_audioBufferFill].l / 32768.0f) * m_running.m_volumeFactor); } else { - ci.real((audioSample[0] / 32768.0f) * m_running.m_volumeFactor); - ci.imag((audioSample[1] / 32768.0f) * m_running.m_volumeFactor); + ci.real((m_audioBuffer[m_audioBufferFill].l / 32768.0f) * m_running.m_volumeFactor); + ci.imag((m_audioBuffer[m_audioBufferFill].r / 32768.0f) * m_running.m_volumeFactor); } } else { - ci.real(((audioSample[0] + audioSample[1]) / 65536.0f) * m_running.m_volumeFactor); + ci.real(((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f) * m_running.m_volumeFactor); ci.imag(0.0f); } diff --git a/plugins/channeltx/modssb/ssbmod.h b/plugins/channeltx/modssb/ssbmod.h index c420fceaa..735800259 100644 --- a/plugins/channeltx/modssb/ssbmod.h +++ b/plugins/channeltx/modssb/ssbmod.h @@ -190,6 +190,7 @@ public: bool playLoop); virtual void pull(Sample& sample); + virtual void pullAudio(int nbSamples); virtual void start(); virtual void stop(); virtual bool handleMessage(const Message& cmd); @@ -366,8 +367,8 @@ private: MovingAverage m_movingAverage; SimpleAGC m_volumeAGC; - //AudioVector m_audioBuffer; - //uint m_audioBufferFill; + AudioVector m_audioBuffer; + uint m_audioBufferFill; AudioFifo m_audioFifo; QMutex m_settingsMutex; diff --git a/plugins/channeltx/modwfm/wfmmod.cpp b/plugins/channeltx/modwfm/wfmmod.cpp index 2c296713c..0c45a7ec7 100644 --- a/plugins/channeltx/modwfm/wfmmod.cpp +++ b/plugins/channeltx/modwfm/wfmmod.cpp @@ -62,8 +62,8 @@ WFMMod::WFMMod() : apply(); - //m_audioBuffer.resize(1<<14); - //m_audioBufferFill = 0; + m_audioBuffer.resize(1<<14); + m_audioBufferFill = 0; m_movingAverage.resize(16, 0); m_volumeAGC.resize(4096, 0.003, 0); @@ -116,8 +116,10 @@ void WFMMod::pull(Sample& sample) { pullAF(m_modSample); calculateLevel(m_modSample.real()); + m_audioBufferFill++; } + m_audioBufferFill++; m_interpolatorDistanceRemain += m_interpolatorDistance; m_modPhasor += (m_running.m_fmDeviation / (float) m_running.m_outputSampleRate) * ri.real() * M_PI; @@ -139,10 +141,19 @@ void WFMMod::pull(Sample& sample) sample.m_imag = (FixReal) ci.imag(); } +void WFMMod::pullAudio(int nbSamples) +{ + if (nbSamples > m_audioBuffer.size()) + { + m_audioBuffer.resize(nbSamples); + } + + m_audioFifo.read(reinterpret_cast(&m_audioBuffer[0]), nbSamples*sizeof(AudioSample), 10); + m_audioBufferFill = 0; +} + void WFMMod::pullAF(Complex& sample) { - int16_t audioSample[2]; - switch (m_afInput) { case WFMModInputTone: @@ -184,9 +195,7 @@ void WFMMod::pullAF(Complex& sample) break; case WFMModInputAudio: { - Real s = (audioSample[0] + audioSample[1]) / 65536.0f; - m_audioFifo.read(reinterpret_cast(audioSample), 1, 10); - sample.real(s * m_running.m_volumeFactor); + sample.real(((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f) * m_running.m_volumeFactor); sample.imag(0.0f); } break; diff --git a/plugins/channeltx/modwfm/wfmmod.h b/plugins/channeltx/modwfm/wfmmod.h index 0d7e2eb2c..940c2f02a 100644 --- a/plugins/channeltx/modwfm/wfmmod.h +++ b/plugins/channeltx/modwfm/wfmmod.h @@ -187,6 +187,7 @@ public: bool playLoop); virtual void pull(Sample& sample); + virtual void pullAudio(int nbSamples); virtual void start(); virtual void stop(); virtual bool handleMessage(const Message& cmd); @@ -322,8 +323,8 @@ private: MovingAverage m_movingAverage; SimpleAGC m_volumeAGC; - //AudioVector m_audioBuffer; - //uint m_audioBufferFill; + AudioVector m_audioBuffer; + uint m_audioBufferFill; AudioFifo m_audioFifo; SampleVector m_sampleBuffer; diff --git a/sdrbase/dsp/basebandsamplesource.h b/sdrbase/dsp/basebandsamplesource.h index f0cd3a060..3564c06f4 100644 --- a/sdrbase/dsp/basebandsamplesource.h +++ b/sdrbase/dsp/basebandsamplesource.h @@ -35,12 +35,14 @@ public: virtual void start() = 0; virtual void stop() = 0; virtual void pull(Sample& sample) = 0; + virtual void pullAudio(int nbSamples) {} /** direct feeding of sample source FIFO */ void feed(SampleSourceFifo* sampleFifo, int nbSamples) { SampleVector::iterator writeAt; sampleFifo->getWriteIterator(writeAt); + pullAudio(nbSamples); // Pre-fetch input audio samples this is mandatory to keep things running smoothly for (int i = 0; i < nbSamples; i++) { diff --git a/sdrbase/dsp/dspdevicesinkengine.cpp b/sdrbase/dsp/dspdevicesinkengine.cpp index a9abc40be..c9000a1df 100644 --- a/sdrbase/dsp/dspdevicesinkengine.cpp +++ b/sdrbase/dsp/dspdevicesinkengine.cpp @@ -176,7 +176,9 @@ void DSPDeviceSinkEngine::work(int nbWriteSamples) // single channel source handling if ((m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size()) == 1) { - for (ThreadedBasebandSampleSources::iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); ++it) + qDebug("DSPDeviceSinkEngine::work: single channel source handling"); + + for (ThreadedBasebandSampleSources::iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); ++it) { (*it)->feed(sampleFifo, nbWriteSamples); } @@ -189,47 +191,52 @@ void DSPDeviceSinkEngine::work(int nbWriteSamples) else if ((m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size()) > 1) { qDebug("DSPDeviceSinkEngine::work: multiple channel sources handling"); - SampleVector::iterator writeBegin; - sampleFifo->getWriteIterator(writeBegin); - SampleVector::iterator writeAt = writeBegin; - Sample s; - int sourceOccurence = 0; - - for (int is = 0; is < nbWriteSamples; is++) - { - // pull data from threaded sources and merge them in the device sample FIFO - for (ThreadedBasebandSampleSources::iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); ++it) - { - (*it)->pull(s); - s /= (m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size()); - - if (sourceOccurence == 0) { - (*writeAt) = s; - } else { - (*writeAt) += s; - } - - sourceOccurence++; - } - - // pull data from direct sources and merge them in the device sample FIFO - for (BasebandSampleSources::iterator it = m_basebandSampleSources.begin(); it != m_basebandSampleSources.end(); ++it) - { - (*it)->pull(s); - s /= (m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size()); - - if (sourceOccurence == 0) { - (*writeAt) = s; - } else { - (*writeAt) += s; - } - - sourceOccurence++; - } - - sampleFifo->bumpIndex(writeAt); - sourceOccurence = 0; - } + // TODO properly + if (m_threadedBasebandSampleSources.size() > 0) + { + (*m_threadedBasebandSampleSources.begin())->feed(sampleFifo, nbWriteSamples); + } +// SampleVector::iterator writeBegin; +// sampleFifo->getWriteIterator(writeBegin); +// SampleVector::iterator writeAt = writeBegin; +// Sample s; +// int sourceOccurence = 0; +// +// for (int is = 0; is < nbWriteSamples; is++) +// { +// // pull data from threaded sources and merge them in the device sample FIFO +// for (ThreadedBasebandSampleSources::iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); ++it) +// { +// (*it)->pull(s); +// s /= (m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size()); +// +// if (sourceOccurence == 0) { +// (*writeAt) = s; +// } else { +// (*writeAt) += s; +// } +// +// sourceOccurence++; +// } +// +// // pull data from direct sources and merge them in the device sample FIFO +// for (BasebandSampleSources::iterator it = m_basebandSampleSources.begin(); it != m_basebandSampleSources.end(); ++it) +// { +// (*it)->pull(s); +// s /= (m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size()); +// +// if (sourceOccurence == 0) { +// (*writeAt) = s; +// } else { +// (*writeAt) += s; +// } +// +// sourceOccurence++; +// } +// +// sampleFifo->bumpIndex(writeAt); +// sourceOccurence = 0; +// } // feed the mix to the main spectrum sink // if (m_spectrumSink) diff --git a/sdrbase/dsp/upchannelizer.h b/sdrbase/dsp/upchannelizer.h index 5037e6e74..55e34d5f4 100644 --- a/sdrbase/dsp/upchannelizer.h +++ b/sdrbase/dsp/upchannelizer.h @@ -63,6 +63,7 @@ public: virtual void start(); virtual void stop(); virtual void pull(Sample& sample); + virtual void pullAudio(int nbSamples) { if (m_sampleSource) m_sampleSource->pullAudio(nbSamples); } virtual bool handleMessage(const Message& cmd);