1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-09-04 06:07:49 -04:00

Deep redesign: debug session #2 phase #1

This commit is contained in:
f4exb 2015-08-20 03:38:31 +02:00
parent 582ce24c62
commit 38bc6563d4
9 changed files with 301 additions and 139 deletions

View File

@ -31,7 +31,7 @@ class AudioOutputPipe;
class SDRANGELOVE_API AudioOutput : QIODevice { class SDRANGELOVE_API AudioOutput : QIODevice {
public: public:
AudioOutput(); AudioOutput();
~AudioOutput(); virtual ~AudioOutput();
bool start(int device, int rate); bool start(int device, int rate);
void stop(); void stop();
@ -47,9 +47,9 @@ private:
AudioFifos m_audioFifos; AudioFifos m_audioFifos;
std::vector<qint32> m_mixBuffer; std::vector<qint32> m_mixBuffer;
bool open(OpenMode mode); //virtual bool open(OpenMode mode);
qint64 readData(char* data, qint64 maxLen); virtual qint64 readData(char* data, qint64 maxLen);
qint64 writeData(const char* data, qint64 len); virtual qint64 writeData(const char* data, qint64 len);
friend class AudioOutputPipe; friend class AudioOutputPipe;
}; };

View File

@ -98,7 +98,7 @@ private:
typedef std::list<ThreadedSampleSink*> ThreadedSampleSinks; typedef std::list<ThreadedSampleSink*> ThreadedSampleSinks;
ThreadedSampleSinks m_threadedSampleSinks; //!< sample sinks on their own threads (usually channels) ThreadedSampleSinks m_threadedSampleSinks; //!< sample sinks on their own threads (usually channels)
AudioOutput m_audioSink; AudioOutput m_audioOutput;
uint m_sampleRate; uint m_sampleRate;
quint64 m_centerFrequency; quint64 m_centerFrequency;

View File

@ -46,7 +46,7 @@ public:
void stop(); //!< this thread exit() and wait() void stop(); //!< this thread exit() and wait()
bool sendWaitSink(Message& cmd); //!< Send message to sink synchronously bool sendWaitSink(Message& cmd); //!< Send message to sink synchronously
void feed(SampleVector::const_iterator& begin, SampleVector::const_iterator& end, bool positiveOnly); //!< Feed sink with samples void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); //!< Feed sink with samples
QString getSampleSinkObjectName() const; QString getSampleSinkObjectName() const;

View File

@ -63,7 +63,7 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
{ {
Complex ci; Complex ci;
if (m_audioFifo->size() <= 0) if (m_audioFifo->size() == 0)
{ {
return; return;
} }
@ -73,68 +73,67 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
Complex c(it->real() / 32768.0, it->imag() / 32768.0); Complex c(it->real() / 32768.0, it->imag() / 32768.0);
c *= m_nco.nextIQ(); c *= m_nco.nextIQ();
if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
{ {
if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci)) m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0));
Real magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
m_movingAverage.feed(magsq);
if (m_movingAverage.average() >= m_squelchLevel)
{ {
m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0)); m_squelchState = m_running.m_audioSampleRate/ 20;
Real magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
m_movingAverage.feed(magsq);
if (m_movingAverage.average() >= m_squelchLevel)
{
m_squelchState = m_running.m_audioSampleRate/ 20;
}
qint16 sample;
if (m_squelchState > 0)
{
m_squelchState--;
Real demod = sqrt(magsq);
demod = m_lowpass.filter(demod);
if (demod < -1)
{
demod = -1;
}
else if (demod > 1)
{
demod = 1;
}
m_volumeAGC.feed(demod);
demod *= (0.003 / m_volumeAGC.getValue());
demod *= m_running.m_volume;
sample = demod * 32700 * 16;
}
else
{
m_volumeAGC.close();
sample = 0;
}
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill;
if (m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if (res != m_audioBufferFill)
{
qDebug("lost %u audio samples", m_audioBufferFill - res);
}
m_audioBufferFill = 0;
}
m_interpolatorDistanceRemain += m_interpolatorDistance;
} }
qint16 sample;
if (m_squelchState > 0)
{
m_squelchState--;
Real demod = sqrt(magsq);
demod = m_lowpass.filter(demod);
if (demod < -1)
{
demod = -1;
}
else if (demod > 1)
{
demod = 1;
}
m_volumeAGC.feed(demod);
demod *= (0.003 / m_volumeAGC.getValue());
demod *= m_running.m_volume;
sample = demod * 32700 * 16;
}
else
{
m_volumeAGC.close();
sample = 0;
}
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill;
if (m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
/* FIXME: Not necessarily bad, There is a race between threads but generally it works i.e. samples are not lost
if (res != m_audioBufferFill)
{
qDebug("AMDemod::feed: %u/%u audio samples lost", m_audioBufferFill - res, m_audioBufferFill);
}*/
m_audioBufferFill = 0;
}
m_interpolatorDistanceRemain += m_interpolatorDistance;
} }
} }
@ -142,10 +141,11 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
{ {
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1); uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
/* SAme remark as above
if (res != m_audioBufferFill) if (res != m_audioBufferFill)
{ {
qDebug("lost %u samples", m_audioBufferFill - res); qDebug("AMDemod::feed: %u samples written vs %u requested", res, m_audioBufferFill);
} }*/
m_audioBufferFill = 0; m_audioBufferFill = 0;
} }

View File

@ -107,15 +107,19 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
{ {
Complex ci; Complex ci;
if(m_audioFifo->size() <= 0) if (m_audioFifo->size() == 0)
{
return; return;
}
for(SampleVector::const_iterator it = begin; it != end; ++it) { for (SampleVector::const_iterator it = begin; it != end; ++it)
{
Complex c(it->real() / 32768.0, it->imag() / 32768.0); Complex c(it->real() / 32768.0, it->imag() / 32768.0);
c *= m_nco.nextIQ(); c *= m_nco.nextIQ();
{ {
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci)) { if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
{
m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0)); m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0));
qint16 sample; qint16 sample;
@ -160,7 +164,8 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
// AF processing // AF processing
if(m_afSquelch.analyze(&demod)) { if(m_afSquelch.analyze(&demod))
{
m_squelchOpen = m_afSquelch.open(); m_squelchOpen = m_afSquelch.open();
} }
@ -176,14 +181,16 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
if (m_ctcssDetector.getDetectedTone(maxToneIndex)) if (m_ctcssDetector.getDetectedTone(maxToneIndex))
{ {
if (maxToneIndex+1 != m_ctcssIndex) { if (maxToneIndex+1 != m_ctcssIndex)
{
m_nfmDemodGUI->setCtcssFreq(m_ctcssDetector.getToneSet()[maxToneIndex]); m_nfmDemodGUI->setCtcssFreq(m_ctcssDetector.getToneSet()[maxToneIndex]);
m_ctcssIndex = maxToneIndex+1; m_ctcssIndex = maxToneIndex+1;
} }
} }
else else
{ {
if (m_ctcssIndex != 0) { if (m_ctcssIndex != 0)
{
m_nfmDemodGUI->setCtcssFreq(0); m_nfmDemodGUI->setCtcssFreq(0);
m_ctcssIndex = 0; m_ctcssIndex = 0;
} }
@ -204,7 +211,8 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
} }
else else
{ {
if (m_ctcssIndex != 0) { if (m_ctcssIndex != 0)
{
m_nfmDemodGUI->setCtcssFreq(0); m_nfmDemodGUI->setCtcssFreq(0);
m_ctcssIndex = 0; m_ctcssIndex = 0;
} }
@ -216,10 +224,17 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
m_audioBuffer[m_audioBufferFill].l = sample; m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample; m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill; ++m_audioBufferFill;
if(m_audioBufferFill >= m_audioBuffer.size()) {
if (m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1); uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if(res != m_audioBufferFill)
/* FIXME: Not necessarily bad, There is a race between threads but generally it works i.e. samples are not lost
if (res != m_audioBufferFill)
{
qDebug("lost %u audio samples", m_audioBufferFill - res); qDebug("lost %u audio samples", m_audioBufferFill - res);
}*/
m_audioBufferFill = 0; m_audioBufferFill = 0;
} }
@ -227,10 +242,17 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
} }
} }
} }
if(m_audioBufferFill > 0) {
if (m_audioBufferFill > 0)
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1); uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if(res != m_audioBufferFill)
/* Same remark as above
if (res != m_audioBufferFill)
{
qDebug("lost %u samples", m_audioBufferFill - res); qDebug("lost %u samples", m_audioBufferFill - res);
}*/
m_audioBufferFill = 0; m_audioBufferFill = 0;
} }

View File

@ -22,16 +22,17 @@
#define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y))
AudioFifo::AudioFifo() : AudioFifo::AudioFifo() :
m_fifo(NULL) m_fifo(0)
{ {
m_size = 0; m_size = 0;
m_fill = 0; m_fill = 0;
m_head = 0; m_head = 0;
m_tail = 0; m_tail = 0;
m_sampleSize = 0;
} }
AudioFifo::AudioFifo(uint sampleSize, uint numSamples) : AudioFifo::AudioFifo(uint sampleSize, uint numSamples) :
m_fifo(NULL) m_fifo(0)
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
@ -42,9 +43,10 @@ AudioFifo::~AudioFifo()
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
if(m_fifo != NULL) { if (m_fifo != 0)
{
delete[] m_fifo; delete[] m_fifo;
m_fifo = NULL; m_fifo = 0;
} }
m_writeWaitCondition.wakeOne(); m_writeWaitCondition.wakeOne();
@ -67,39 +69,63 @@ uint AudioFifo::write(const quint8* data, uint numSamples, int timeout)
uint remaining; uint remaining;
uint copyLen; uint copyLen;
if(m_fifo == NULL) if(m_fifo == 0)
{
return 0; return 0;
}
time.start(); time.start();
m_mutex.lock(); m_mutex.lock();
if(timeout == 0) if(timeout == 0)
{
total = MIN(numSamples, m_size - m_fill); total = MIN(numSamples, m_size - m_fill);
else total = numSamples; }
else
{
total = numSamples;
}
remaining = total; remaining = total;
while(remaining > 0) {
if(isFull()) { while (remaining > 0)
if(time.elapsed() < timeout) { {
if (isFull())
{
if (time.elapsed() < timeout)
{
m_writeWaitLock.lock(); m_writeWaitLock.lock();
m_mutex.unlock(); m_mutex.unlock();
int ms = timeout - time.elapsed(); int ms = timeout - time.elapsed();
if(ms < 1) if(ms < 1)
{
ms = 1; ms = 1;
}
bool ok = m_writeWaitCondition.wait(&m_writeWaitLock, ms); bool ok = m_writeWaitCondition.wait(&m_writeWaitLock, ms);
m_writeWaitLock.unlock(); m_writeWaitLock.unlock();
if(!ok) if(!ok)
{
return total - remaining; return total - remaining;
}
m_mutex.lock(); m_mutex.lock();
if(m_fifo == NULL) {
if(m_fifo == 0)
{
m_mutex.unlock(); m_mutex.unlock();
return 0; return 0;
} }
} else { }
else
{
m_mutex.unlock(); m_mutex.unlock();
return total - remaining; return total - remaining;
} }
} }
copyLen = MIN(remaining, m_size - m_fill); copyLen = MIN(remaining, m_size - m_fill);
copyLen = MIN(copyLen, m_size - m_tail); copyLen = MIN(copyLen, m_size - m_tail);
memcpy(m_fifo + (m_tail * m_sampleSize), data, copyLen * m_sampleSize); memcpy(m_fifo + (m_tail * m_sampleSize), data, copyLen * m_sampleSize);
@ -122,35 +148,58 @@ uint AudioFifo::read(quint8* data, uint numSamples, int timeout)
uint remaining; uint remaining;
uint copyLen; uint copyLen;
if(m_fifo == NULL) if(m_fifo == 0)
{
return 0; return 0;
}
time.start(); time.start();
m_mutex.lock(); m_mutex.lock();
if(timeout == 0) if(timeout == 0)
{
total = MIN(numSamples, m_fill); total = MIN(numSamples, m_fill);
else total = numSamples; }
else
{
total = numSamples;
}
remaining = total; remaining = total;
while(remaining > 0) {
if(isEmpty()) { while(remaining > 0)
if(time.elapsed() < timeout) { {
if(isEmpty())
{
if(time.elapsed() < timeout)
{
m_readWaitLock.lock(); m_readWaitLock.lock();
m_mutex.unlock(); m_mutex.unlock();
int ms = timeout - time.elapsed(); int ms = timeout - time.elapsed();
if(ms < 1) if(ms < 1)
{
ms = 1; ms = 1;
}
bool ok = m_readWaitCondition.wait(&m_readWaitLock, ms); bool ok = m_readWaitCondition.wait(&m_readWaitLock, ms);
m_readWaitLock.unlock(); m_readWaitLock.unlock();
if(!ok) if(!ok)
{
return total - remaining; return total - remaining;
}
m_mutex.lock(); m_mutex.lock();
if(m_fifo == NULL) {
if(m_fifo == 0)
{
m_mutex.unlock(); m_mutex.unlock();
return 0; return 0;
} }
} else { }
else
{
m_mutex.unlock(); m_mutex.unlock();
return total - remaining; return total - remaining;
} }
@ -176,7 +225,10 @@ uint AudioFifo::drain(uint numSamples)
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
if(numSamples > m_fill) if(numSamples > m_fill)
{
numSamples = m_fill; numSamples = m_fill;
}
m_head = (m_head + numSamples) % m_size; m_head = (m_head + numSamples) % m_size;
m_fill -= numSamples; m_fill -= numSamples;
@ -197,7 +249,8 @@ void AudioFifo::clear()
bool AudioFifo::create(uint sampleSize, uint numSamples) bool AudioFifo::create(uint sampleSize, uint numSamples)
{ {
if(m_fifo != NULL) { if(m_fifo != 0)
{
delete[] m_fifo; delete[] m_fifo;
m_fifo = NULL; m_fifo = NULL;
} }
@ -208,7 +261,8 @@ bool AudioFifo::create(uint sampleSize, uint numSamples)
m_head = 0; m_head = 0;
m_tail = 0; m_tail = 0;
if((m_fifo = new qint8[numSamples * m_sampleSize]) == NULL) { if((m_fifo = new qint8[numSamples * m_sampleSize]) == 0)
{
qDebug("out of memory"); qDebug("out of memory");
return false; return false;
} }

View File

@ -34,8 +34,12 @@ AudioOutput::~AudioOutput()
stop(); stop();
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
for(AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
for (AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
{
delete *it; delete *it;
}
m_audioFifos.clear(); m_audioFifos.clear();
} }
@ -43,30 +47,55 @@ bool AudioOutput::start(int device, int rate)
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
Q_UNUSED(device); //Q_UNUSED(device);
Q_UNUSED(rate); //Q_UNUSED(rate);
QAudioFormat format; QAudioFormat format;
QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice()); QAudioDeviceInfo devInfo;
format.setSampleRate(48000); if (device < 0)
{
devInfo = QAudioDeviceInfo::defaultOutputDevice();
qWarning("AudioOutput::start: using default device %s", qPrintable(devInfo.defaultOutputDevice().deviceName()));
}
else
{
QList<QAudioDeviceInfo> devicesInfo = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
if (device < devicesInfo.size())
{
devInfo = devicesInfo[device];
qWarning("AudioOutput::start: using audio device #%d: %s", device, qPrintable(devInfo.defaultOutputDevice().deviceName()));
}
else
{
devInfo = QAudioDeviceInfo::defaultOutputDevice();
qWarning("AudioOutput::start: audio device #%d does not exist. Using default device %s", device, qPrintable(devInfo.defaultOutputDevice().deviceName()));
}
}
//QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice());
format.setSampleRate(rate);
format.setChannelCount(2); format.setChannelCount(2);
format.setSampleSize(16); format.setSampleSize(16);
format.setCodec("audio/pcm"); format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian); format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt); format.setSampleType(QAudioFormat::SignedInt);
if(!devInfo.isFormatSupported(format)) { if (!devInfo.isFormatSupported(format))
qWarning("48kHz S16_LE audio format not supported"); {
qWarning("AudioOutput::start: %d Hz S16_LE audio format not supported", rate);
format = devInfo.nearestFormat(format); format = devInfo.nearestFormat(format);
} }
if(format.sampleSize() != 16) { if (format.sampleSize() != 16)
qWarning("Audio device ( %s ) failed", qPrintable(devInfo.defaultOutputDevice().deviceName())); {
qWarning("AudioOutput::start: Audio device ( %s ) failed", qPrintable(devInfo.defaultOutputDevice().deviceName()));
return false; return false;
} }
m_audioOutput = new QAudioOutput(format); m_audioOutput = new QAudioOutput(devInfo, format);
QIODevice::open(QIODevice::ReadOnly); QIODevice::open(QIODevice::ReadOnly);
@ -80,11 +109,13 @@ void AudioOutput::stop()
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
if(m_audioOutput != NULL) { if (m_audioOutput != 0)
{
m_audioOutput->stop(); m_audioOutput->stop();
delete m_audioOutput; delete m_audioOutput;
m_audioOutput = NULL; m_audioOutput = 0;
} }
QIODevice::close(); QIODevice::close();
} }
@ -102,34 +133,53 @@ void AudioOutput::removeFifo(AudioFifo* audioFifo)
m_audioFifos.remove(audioFifo); m_audioFifos.remove(audioFifo);
} }
/*
bool AudioOutput::open(OpenMode mode) bool AudioOutput::open(OpenMode mode)
{ {
Q_UNUSED(mode); Q_UNUSED(mode);
return false; return false;
} }*/
qint64 AudioOutput::readData(char* data, qint64 maxLen) qint64 AudioOutput::readData(char* data, qint64 maxLen)
{ {
//qDebug("AudioOutput::readData: %lld", maxLen);
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
unsigned int framesPerBuffer = maxLen / 4; unsigned int framesPerBuffer = maxLen / 4;
if(framesPerBuffer == 0)
return 0;
if(m_mixBuffer.size() < framesPerBuffer * 2) { if (framesPerBuffer == 0)
m_mixBuffer.resize(framesPerBuffer * 2); // allocate 2 qint32 per frame (stereo) {
if(m_mixBuffer.size() != framesPerBuffer * 2) return 0;
return 0;
} }
if (m_mixBuffer.size() < framesPerBuffer * 2)
{
m_mixBuffer.resize(framesPerBuffer * 2); // allocate 2 qint32 per frame (stereo)
if (m_mixBuffer.size() != framesPerBuffer * 2)
{
return 0;
}
}
memset(&m_mixBuffer[0], 0x00, 2 * framesPerBuffer * sizeof(m_mixBuffer[0])); // start with silence memset(&m_mixBuffer[0], 0x00, 2 * framesPerBuffer * sizeof(m_mixBuffer[0])); // start with silence
// sum up a block from all fifos // sum up a block from all fifos
for(AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it) {
for (AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
{
// use outputBuffer as temp - yes, one memcpy could be saved // use outputBuffer as temp - yes, one memcpy could be saved
uint samples = (*it)->read((quint8*)data, framesPerBuffer, 1); uint samples = (*it)->read((quint8*) data, framesPerBuffer, 1);
const qint16* src = (const qint16*)data; const qint16* src = (const qint16*) data;
std::vector<qint32>::iterator dst = m_mixBuffer.begin(); std::vector<qint32>::iterator dst = m_mixBuffer.begin();
for(uint i = 0; i < samples; i++) {
if (samples != framesPerBuffer)
{
qDebug("AudioOutput::readData: read %d samples vs %d requested", samples, framesPerBuffer);
}
for (uint i = 0; i < samples; i++)
{
*dst += *src; *dst += *src;
++src; ++src;
++dst; ++dst;
@ -140,22 +190,40 @@ qint64 AudioOutput::readData(char* data, qint64 maxLen)
} }
// convert to int16 // convert to int16
std::vector<qint32>::const_iterator src = m_mixBuffer.begin(); std::vector<qint32>::const_iterator src = m_mixBuffer.begin();
qint16* dst = (qint16*)data; qint16* dst = (qint16*) data;
for(uint i = 0; i < framesPerBuffer; i++) {
for (uint i = 0; i < framesPerBuffer; i++)
{
// left channel // left channel
qint32 s = *src++; qint32 s = *src++;
if(s < -32768) if(s < -32768)
{
s = -32768; s = -32768;
else if(s > 32767) }
else if (s > 32767)
{
s = 32767; s = 32767;
}
*dst++ = s; *dst++ = s;
// right channel // right channel
s = *src++; s = *src++;
if(s < -32768) if(s < -32768)
{
s = -32768; s = -32768;
else if(s > 32767) }
else if (s > 32767)
{
s = 32767; s = 32767;
}
*dst++ = s; *dst++ = s;
} }

View File

@ -271,16 +271,25 @@ void DSPEngine::work()
if (part1begin != part1end) if (part1begin != part1end)
{ {
// correct stuff // correct stuff
if (m_dcOffsetCorrection) { if (m_dcOffsetCorrection)
{
dcOffset(part1begin, part1end); dcOffset(part1begin, part1end);
} }
if (m_iqImbalanceCorrection) { if (m_iqImbalanceCorrection)
{
imbalance(part1begin, part1end); imbalance(part1begin, part1end);
} }
// feed data to handlers // feed data to direct sinks
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) { for (SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); ++it)
{
(*it)->feed(part1begin, part1end, positiveOnly);
}
// feed data to threaded sinks
for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it)
{
(*it)->feed(part1begin, part1end, positiveOnly); (*it)->feed(part1begin, part1end, positiveOnly);
} }
} }
@ -289,16 +298,25 @@ void DSPEngine::work()
if(part2begin != part2end) if(part2begin != part2end)
{ {
// correct stuff // correct stuff
if(m_dcOffsetCorrection) { if (m_dcOffsetCorrection)
{
dcOffset(part2begin, part2end); dcOffset(part2begin, part2end);
} }
if(m_iqImbalanceCorrection) { if (m_iqImbalanceCorrection)
{
imbalance(part2begin, part2end); imbalance(part2begin, part2end);
} }
// feed data to handlers // feed data to direct sinks
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) { for (SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++)
{
(*it)->feed(part2begin, part2end, positiveOnly);
}
// feed data to threaded sinks
for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it)
{
(*it)->feed(part2begin, part2end, positiveOnly); (*it)->feed(part2begin, part2end, positiveOnly);
} }
} }
@ -344,7 +362,7 @@ DSPEngine::State DSPEngine::gotoIdle()
m_sampleSource->stop(); m_sampleSource->stop();
m_deviceDescription.clear(); m_deviceDescription.clear();
m_audioSink.stop(); m_audioOutput.stop();
m_sampleRate = 0; m_sampleRate = 0;
return StIdle; return StIdle;
@ -444,7 +462,7 @@ DSPEngine::State DSPEngine::gotoRunning()
return gotoError("Could not start sample source"); return gotoError("Could not start sample source");
} }
m_audioSink.start(0, 48000); m_audioOutput.start(-1, 48000); // Use default output device at 48 kHz
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++)
{ {
@ -591,11 +609,11 @@ void DSPEngine::handleSynchronousMessages()
} }
else if (DSPAddAudioSink::match(*message)) else if (DSPAddAudioSink::match(*message))
{ {
m_audioSink.addFifo(((DSPAddAudioSink*) message)->getAudioFifo()); m_audioOutput.addFifo(((DSPAddAudioSink*) message)->getAudioFifo());
} }
else if (DSPRemoveAudioSink::match(*message)) else if (DSPRemoveAudioSink::match(*message))
{ {
m_audioSink.removeFifo(((DSPRemoveAudioSink*) message)->getAudioFifo()); m_audioOutput.removeFifo(((DSPRemoveAudioSink*) message)->getAudioFifo());
} }
m_syncMessenger.done(m_state); m_syncMessenger.done(m_state);

View File

@ -38,7 +38,7 @@ void ThreadedSampleSink::run()
exec(); exec();
} }
void ThreadedSampleSink::feed(SampleVector::const_iterator& begin, SampleVector::const_iterator& end, bool positiveOnly) void ThreadedSampleSink::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
{ {
m_sampleSink->feed(begin, end, positiveOnly); m_sampleSink->feed(begin, end, positiveOnly);
} }