1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-05-29 13:32:26 -04:00

Deep redesign: debug AM demod removing extraneous interpolator init in start method

This commit is contained in:
f4exb 2015-08-24 00:51:27 +02:00
parent bc287a4c33
commit 19b234c4df
16 changed files with 181 additions and 124 deletions

View File

@ -18,11 +18,13 @@
#ifndef INCLUDE_AUDIOFIFO_H #ifndef INCLUDE_AUDIOFIFO_H
#define INCLUDE_AUDIOFIFO_H #define INCLUDE_AUDIOFIFO_H
#include <QObject>
#include <QMutex> #include <QMutex>
#include <QWaitCondition> #include <QWaitCondition>
#include "util/export.h" #include "util/export.h"
class SDRANGELOVE_API AudioFifo { class SDRANGELOVE_API AudioFifo : public QObject {
Q_OBJECT
public: public:
AudioFifo(); AudioFifo();
AudioFifo(uint sampleSize, uint numSamples); AudioFifo(uint sampleSize, uint numSamples);
@ -30,8 +32,8 @@ public:
bool setSize(uint sampleSize, uint numSamples); bool setSize(uint sampleSize, uint numSamples);
uint write(const quint8* data, uint numSamples, int timeout = INT_MAX); uint write(const quint8* data, uint numSamples, int timeout_ms = INT_MAX);
uint read(quint8* data, uint numSamples, int timeout = INT_MAX); uint read(quint8* data, uint numSamples, int timeout_ms = INT_MAX);
uint drain(uint numSamples); uint drain(uint numSamples);
void clear(); void clear();

View File

@ -20,6 +20,7 @@
#include <QMutex> #include <QMutex>
#include <QIODevice> #include <QIODevice>
#include <QAudioFormat>
#include <list> #include <list>
#include <vector> #include <vector>
#include "util/export.h" #include "util/export.h"
@ -39,6 +40,8 @@ public:
void addFifo(AudioFifo* audioFifo); void addFifo(AudioFifo* audioFifo);
void removeFifo(AudioFifo* audioFifo); void removeFifo(AudioFifo* audioFifo);
uint getRate() const { return m_audioFormat.sampleRate(); }
private: private:
QMutex m_mutex; QMutex m_mutex;
QAudioOutput* m_audioOutput; QAudioOutput* m_audioOutput;
@ -47,6 +50,8 @@ private:
AudioFifos m_audioFifos; AudioFifos m_audioFifos;
std::vector<qint32> m_mixBuffer; std::vector<qint32> m_mixBuffer;
QAudioFormat m_audioFormat;
//virtual bool open(OpenMode mode); //virtual bool open(OpenMode mode);
virtual qint64 readData(char* data, qint64 maxLen); virtual qint64 readData(char* data, qint64 maxLen);
virtual qint64 writeData(const char* data, qint64 len); virtual qint64 writeData(const char* data, qint64 len);

View File

@ -55,6 +55,9 @@ public:
MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; } MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; }
MessageQueue* getOutputMessageQueue() { return &m_outputMessageQueue; } MessageQueue* getOutputMessageQueue() { return &m_outputMessageQueue; }
uint getAudioSampleRate() const { return m_audioSampleRate; }
void setAudioSampleRate(uint rate);
void start(); //!< This thread start void start(); //!< This thread start
void stop(); //!< This thread stop void stop(); //!< This thread stop
@ -102,6 +105,7 @@ private:
uint m_sampleRate; uint m_sampleRate;
quint64 m_centerFrequency; quint64 m_centerFrequency;
uint m_audioSampleRate;
bool m_dcOffsetCorrection; bool m_dcOffsetCorrection;
bool m_iqImbalanceCorrection; bool m_iqImbalanceCorrection;

View File

@ -20,13 +20,18 @@ public:
void free(); void free();
// Original code allowed for upsampling, but was never used that way // Original code allowed for upsampling, but was never used that way
bool interpolate(Real* distance, const Complex& next, Complex* result) bool interpolate(Real *distance, const Complex& next, Complex* result)
{ {
advanceFilter(next); advanceFilter(next);
*distance -= 1.0; *distance -= 1.0;
if (*distance >= 1.0) if (*distance >= 1.0)
{
return false; return false;
doInterpolate((int)floor(*distance * (Real)m_phaseSteps), result); }
doInterpolate((int) floor(*distance * (Real)m_phaseSteps), result);
return true; return true;
} }

View File

@ -103,15 +103,15 @@ private:
PluginManager* m_pluginManager; PluginManager* m_pluginManager;
void loadSettings(); void loadSettings();
void loadSettings(const Preset* preset); void loadPresetSettings(const Preset* preset);
void saveSettings(Preset* preset); void savePresetSettings(Preset* preset);
void saveSettings(); void saveSettings();
void createStatusBar(); void createStatusBar();
void closeEvent(QCloseEvent*); void closeEvent(QCloseEvent*);
void updateCenterFreqDisplay(); void updateCenterFreqDisplay();
void updateSampleRate(); void updateSampleRate();
void updatePresets(); void updatePresetControls();
QTreeWidgetItem* addPresetToTree(const Preset* preset); QTreeWidgetItem* addPresetToTree(const Preset* preset);
void applySettings(); void applySettings();

View File

@ -23,11 +23,29 @@
#include "dsp/samplefifo.h" #include "dsp/samplefifo.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "util/export.h" #include "util/export.h"
#include "util/syncmessenger.h"
class SampleSink; class SampleSink;
class QThread; class QThread;
/**
* Because Qt is a piece of shit this class cannot be a nested protected class of ThreadedSampleSink
* So let's make everything public
*/
class ThreadedSampleFifo : public QObject {
Q_OBJECT
public:
ThreadedSampleFifo(SampleSink* sampleSink, std::size_t size = 1<<18);
~ThreadedSampleFifo();
void writeToFifo(SampleVector::const_iterator& begin, SampleVector::const_iterator& end);
SampleSink* m_sampleSink;
SampleFifo m_sampleFifo;
public slots:
void handleFifoData();
};
/** /**
* This class is a wrapper for SampleSink that runs the SampleSink object in its own thread * This class is a wrapper for SampleSink that runs the SampleSink object in its own thread
*/ */
@ -51,13 +69,10 @@ public:
QString getSampleSinkObjectName() const; QString getSampleSinkObjectName() const;
protected: protected:
QThread *m_thread; //!< The thead object
SyncMessenger m_syncMessenger; //!< Used to process messages synchronously with the thread
SampleSink* m_sampleSink;
SampleFifo m_sampleFifo;
protected slots: QThread *m_thread; //!< The thead object
void handleData(); ThreadedSampleFifo *m_threadedSampleFifo;
SampleSink* m_sampleSink;
}; };
#endif // INCLUDE_THREADEDSAMPLESINK_H #endif // INCLUDE_THREADEDSAMPLESINK_H

View File

@ -21,14 +21,15 @@
#include <stdio.h> #include <stdio.h>
#include <complex.h> #include <complex.h>
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "dsp/dspengine.h"
#include "dsp/channelizer.h" #include "dsp/channelizer.h"
#include "dsp/pidcontroller.h" #include "dsp/pidcontroller.h"
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message) MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message)
AMDemod::AMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) : AMDemod::AMDemod(SampleSink* sampleSink) :
m_sampleSink(sampleSink), m_sampleSink(sampleSink),
m_audioFifo(audioFifo) m_audioFifo(4, 48000)
{ {
setObjectName("AMDemod"); setObjectName("AMDemod");
@ -38,15 +39,17 @@ AMDemod::AMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
m_config.m_afBandwidth = 3000; m_config.m_afBandwidth = 3000;
m_config.m_squelch = -40.0; m_config.m_squelch = -40.0;
m_config.m_volume = 2.0; m_config.m_volume = 2.0;
m_config.m_audioSampleRate = 48000; m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
apply(); apply();
m_audioBuffer.resize(16384); m_audioBuffer.resize(1<<14);
m_audioBufferFill = 0; m_audioBufferFill = 0;
m_movingAverage.resize(16, 0); m_movingAverage.resize(16, 0);
m_volumeAGC.resize(4096, 0.003, 0); m_volumeAGC.resize(4096, 0.003, 0);
DSPEngine::instance()->addAudioSink(&m_audioFifo);
} }
AMDemod::~AMDemod() AMDemod::~AMDemod()
@ -63,7 +66,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;
} }
@ -82,7 +85,7 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
if (m_movingAverage.average() >= m_squelchLevel) if (m_movingAverage.average() >= m_squelchLevel)
{ {
m_squelchState = m_running.m_audioSampleRate/ 20; m_squelchState = m_running.m_audioSampleRate / 20;
} }
qint16 sample; qint16 sample;
@ -122,12 +125,11 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
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, 10);
// FIXME: Not necessarily bad, There is a race between threads but generally it works i.e. samples are not lost
if (res != m_audioBufferFill) if (res != m_audioBufferFill)
{ {
qDebug("AMDemod::feed: %u/%u audio samples lost", m_audioBufferFill - res, m_audioBufferFill); qDebug("AMDemod::feed: %u/%u audio samples written", res, m_audioBufferFill);
} }
m_audioBufferFill = 0; m_audioBufferFill = 0;
@ -139,14 +141,12 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
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, 10);
// Same remark as above
/*
if (res != m_audioBufferFill) if (res != m_audioBufferFill)
{ {
qDebug("AMDemod::feed: %u samples written vs %u requested", res, m_audioBufferFill); qDebug("AMDemod::feed: %u/%u tail samples written", res, m_audioBufferFill);
}*/ }
m_audioBufferFill = 0; m_audioBufferFill = 0;
} }
@ -161,12 +161,11 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
void AMDemod::start() void AMDemod::start()
{ {
qDebug() << "AMDemod::start: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
m_squelchState = 0; m_squelchState = 0;
m_audioFifo->clear(); m_audioFifo.clear();
m_interpolatorRegulation = 0.9999;
m_interpolatorDistance = 1.0;
m_interpolatorDistanceRemain = 0.0;
m_lastSample = 0;
} }
void AMDemod::stop() void AMDemod::stop()
@ -203,7 +202,7 @@ bool AMDemod::handleMessage(const Message& cmd)
apply(); apply();
qDebug() << " - MsgConfigureAMDemod:" qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:"
<< " m_rfBandwidth: " << m_config.m_rfBandwidth << " m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_afBandwidth: " << m_config.m_afBandwidth << " m_afBandwidth: " << m_config.m_afBandwidth
<< " m_volume: " << m_config.m_volume << " m_volume: " << m_config.m_volume
@ -239,6 +238,8 @@ void AMDemod::apply()
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2); m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2);
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
qDebug() << "AMDemod::apply: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_interpolatorDistance: " << m_interpolatorDistance;
} }
if((m_config.m_afBandwidth != m_running.m_afBandwidth) || if((m_config.m_afBandwidth != m_running.m_afBandwidth) ||

View File

@ -30,8 +30,9 @@
class AudioFifo; class AudioFifo;
class AMDemod : public SampleSink { class AMDemod : public SampleSink {
Q_OBJECT
public: public:
AMDemod(AudioFifo* audioFifo, SampleSink* sampleSink); AMDemod(SampleSink* sampleSink);
~AMDemod(); ~AMDemod();
void configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch); void configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch);
@ -106,7 +107,6 @@ private:
Config m_running; Config m_running;
NCO m_nco; NCO m_nco;
Real m_interpolatorRegulation;
Interpolator m_interpolator; Interpolator m_interpolator;
Real m_interpolatorDistance; Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain; Real m_interpolatorDistanceRemain;
@ -115,8 +115,6 @@ private:
Real m_squelchLevel; Real m_squelchLevel;
int m_squelchState; int m_squelchState;
Real m_lastArgument;
Complex m_lastSample;
MovingAverage<Real> m_movingAverage; MovingAverage<Real> m_movingAverage;
SimpleAGC m_volumeAGC; SimpleAGC m_volumeAGC;
@ -124,7 +122,7 @@ private:
uint m_audioBufferFill; uint m_audioBufferFill;
SampleSink* m_sampleSink; SampleSink* m_sampleSink;
AudioFifo* m_audioFifo; AudioFifo m_audioFifo;
SampleVector m_sampleBuffer; SampleVector m_sampleBuffer;
void apply(); void apply();

View File

@ -201,11 +201,9 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_audioFifo = new AudioFifo(4, 48000); m_amDemod = new AMDemod(0);
m_amDemod = new AMDemod(m_audioFifo, 0);
m_channelizer = new Channelizer(m_amDemod); m_channelizer = new Channelizer(m_amDemod);
m_threadedChannelizer = new ThreadedSampleSink(m_channelizer, this); m_threadedChannelizer = new ThreadedSampleSink(m_channelizer, this);
DSPEngine::instance()->addAudioSink(m_audioFifo);
DSPEngine::instance()->addThreadedSink(m_threadedChannelizer); DSPEngine::instance()->addThreadedSink(m_threadedChannelizer);
m_channelMarker = new ChannelMarker(this); m_channelMarker = new ChannelMarker(this);
@ -227,7 +225,6 @@ AMDemodGUI::~AMDemodGUI()
delete m_threadedChannelizer; delete m_threadedChannelizer;
delete m_channelizer; delete m_channelizer;
delete m_amDemod; delete m_amDemod;
delete m_audioFifo;
delete m_channelMarker; delete m_channelMarker;
delete ui; delete ui;
} }

View File

@ -62,7 +62,7 @@ bool AudioFifo::setSize(uint sampleSize, uint numSamples)
return create(sampleSize, numSamples); return create(sampleSize, numSamples);
} }
uint AudioFifo::write(const quint8* data, uint numSamples, int timeout) uint AudioFifo::write(const quint8* data, uint numSamples, int timeout_ms)
{ {
QTime time; QTime time;
uint total; uint total;
@ -77,7 +77,7 @@ uint AudioFifo::write(const quint8* data, uint numSamples, int timeout)
time.start(); time.start();
m_mutex.lock(); m_mutex.lock();
if(timeout == 0) if(timeout_ms == 0)
{ {
total = MIN(numSamples, m_size - m_fill); total = MIN(numSamples, m_size - m_fill);
} }
@ -92,11 +92,11 @@ uint AudioFifo::write(const quint8* data, uint numSamples, int timeout)
{ {
if (isFull()) if (isFull())
{ {
if (time.elapsed() < timeout) if (time.elapsed() < timeout_ms)
{ {
m_writeWaitLock.lock(); m_writeWaitLock.lock();
m_mutex.unlock(); m_mutex.unlock();
int ms = timeout - time.elapsed(); int ms = timeout_ms - time.elapsed();
if(ms < 1) if(ms < 1)
{ {
@ -141,7 +141,7 @@ uint AudioFifo::write(const quint8* data, uint numSamples, int timeout)
return total; return total;
} }
uint AudioFifo::read(quint8* data, uint numSamples, int timeout) uint AudioFifo::read(quint8* data, uint numSamples, int timeout_ms)
{ {
QTime time; QTime time;
uint total; uint total;
@ -156,7 +156,7 @@ uint AudioFifo::read(quint8* data, uint numSamples, int timeout)
time.start(); time.start();
m_mutex.lock(); m_mutex.lock();
if(timeout == 0) if(timeout_ms == 0)
{ {
total = MIN(numSamples, m_fill); total = MIN(numSamples, m_fill);
} }
@ -171,11 +171,11 @@ uint AudioFifo::read(quint8* data, uint numSamples, int timeout)
{ {
if(isEmpty()) if(isEmpty())
{ {
if(time.elapsed() < timeout) if(time.elapsed() < timeout_ms)
{ {
m_readWaitLock.lock(); m_readWaitLock.lock();
m_mutex.unlock(); m_mutex.unlock();
int ms = timeout - time.elapsed(); int ms = timeout_ms - time.elapsed();
if(ms < 1) if(ms < 1)
{ {

View File

@ -50,7 +50,6 @@ bool AudioOutput::start(int device, int rate)
//Q_UNUSED(device); //Q_UNUSED(device);
//Q_UNUSED(rate); //Q_UNUSED(rate);
QAudioFormat format;
QAudioDeviceInfo devInfo; QAudioDeviceInfo devInfo;
if (device < 0) if (device < 0)
@ -76,31 +75,36 @@ bool AudioOutput::start(int device, int rate)
//QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice()); //QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice());
format.setSampleRate(rate); m_audioFormat.setSampleRate(rate);
format.setChannelCount(2); m_audioFormat.setChannelCount(2);
format.setSampleSize(16); m_audioFormat.setSampleSize(16);
format.setCodec("audio/pcm"); m_audioFormat.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian); m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt); m_audioFormat.setSampleType(QAudioFormat::SignedInt);
if (!devInfo.isFormatSupported(format)) if (!devInfo.isFormatSupported(m_audioFormat))
{ {
qWarning("AudioOutput::start: %d Hz S16_LE audio format not supported", rate); m_audioFormat = devInfo.nearestFormat(m_audioFormat);
format = devInfo.nearestFormat(format); qWarning("AudioOutput::start: %d Hz S16_LE audio format not supported. New rate: %d", rate, m_audioFormat.sampleRate());
} }
if (format.sampleSize() != 16) if (m_audioFormat.sampleSize() != 16)
{ {
qWarning("AudioOutput::start: 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(devInfo, format); m_audioOutput = new QAudioOutput(devInfo, m_audioFormat);
QIODevice::open(QIODevice::ReadOnly); QIODevice::open(QIODevice::ReadOnly);
m_audioOutput->start(this); m_audioOutput->start(this);
if (m_audioOutput->state() != QAudio::ActiveState)
{
qWarning("AudioOutput::start: cannot start");
}
return true; return true;
} }

View File

@ -32,7 +32,7 @@ void Channelizer::configure(MessageQueue* messageQueue, int sampleRate, int cent
void Channelizer::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) void Channelizer::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
{ {
if(m_sampleSink == NULL) { if(m_sampleSink == 0) {
m_sampleBuffer.clear(); m_sampleBuffer.clear();
return; return;
} }
@ -55,16 +55,19 @@ void Channelizer::feed(SampleVector::const_iterator begin, SampleVector::const_i
void Channelizer::start() void Channelizer::start()
{ {
if(m_sampleSink != NULL) if(m_sampleSink != 0)
{ {
qDebug() << "Channelizer::start: thread: " << thread(); qDebug() << "Channelizer::start: thread: " << thread()
<< " m_inputSampleRate: " << m_inputSampleRate
<< " m_requestedOutputSampleRate: " << m_requestedOutputSampleRate
<< " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
m_sampleSink->start(); m_sampleSink->start();
} }
} }
void Channelizer::stop() void Channelizer::stop()
{ {
if(m_sampleSink != NULL) if(m_sampleSink != 0)
m_sampleSink->stop(); m_sampleSink->stop();
} }
@ -79,7 +82,7 @@ bool Channelizer::handleMessage(const Message& cmd)
qDebug() << "Channelizer::handleMessage: DSPSignalNotification: m_inputSampleRate: " << m_inputSampleRate; qDebug() << "Channelizer::handleMessage: DSPSignalNotification: m_inputSampleRate: " << m_inputSampleRate;
applyConfiguration(); applyConfiguration();
if (m_sampleSink != NULL) if (m_sampleSink != 0)
{ {
m_sampleSink->handleMessage(notif); m_sampleSink->handleMessage(notif);
} }
@ -99,17 +102,11 @@ bool Channelizer::handleMessage(const Message& cmd)
applyConfiguration(); applyConfiguration();
if (m_sampleSink != NULL)
{
MsgChannelizerNotification notif(m_currentOutputSampleRate, m_currentCenterFrequency);
m_sampleSink->handleMessage(notif);
}
return true; return true;
} }
else else
{ {
if (m_sampleSink != NULL) if (m_sampleSink != 0)
{ {
return m_sampleSink->handleMessage(cmd); return m_sampleSink->handleMessage(cmd);
} }
@ -132,11 +129,17 @@ void Channelizer::applyConfiguration()
<< ", req=" << m_requestedOutputSampleRate << ", req=" << m_requestedOutputSampleRate
<< ", out=" << m_currentOutputSampleRate << ", out=" << m_currentOutputSampleRate
<< ", fc=" << m_currentCenterFrequency; << ", fc=" << m_currentCenterFrequency;
if (m_sampleSink != 0)
{
MsgChannelizerNotification notif(m_currentOutputSampleRate, m_currentCenterFrequency);
m_sampleSink->handleMessage(notif);
}
} }
Channelizer::FilterStage::FilterStage(Mode mode) : Channelizer::FilterStage::FilterStage(Mode mode) :
m_filter(new IntHalfbandFilter), m_filter(new IntHalfbandFilter),
m_workFunction(NULL) m_workFunction(0)
{ {
switch(mode) { switch(mode) {
case ModeCenter: case ModeCenter:

View File

@ -32,6 +32,7 @@ DSPEngine::DSPEngine(QObject* parent) :
m_sampleSinks(), m_sampleSinks(),
m_sampleRate(0), m_sampleRate(0),
m_centerFrequency(0), m_centerFrequency(0),
m_audioSampleRate(48000),
m_dcOffsetCorrection(false), m_dcOffsetCorrection(false),
m_iqImbalanceCorrection(false), m_iqImbalanceCorrection(false),
m_iOffset(0), m_iOffset(0),
@ -411,13 +412,13 @@ DSPEngine::State DSPEngine::gotoInit()
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)
{ {
qDebug() << " - initializing " << (*it)->objectName().toStdString().c_str(); qDebug() << "DSPEngine::gotoInit: initializing " << (*it)->objectName().toStdString().c_str();
(*it)->handleMessage(notif); (*it)->handleMessage(notif);
} }
for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it) for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it)
{ {
qDebug() << " - initializing ThreadedSampleSink(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")"; qDebug() << "DSPEngine::gotoInit: initializing ThreadedSampleSink(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")";
(*it)->handleSinkMessage(notif); (*it)->handleSinkMessage(notif);
} }
@ -431,8 +432,8 @@ DSPEngine::State DSPEngine::gotoInit()
DSPEngine::State DSPEngine::gotoRunning() DSPEngine::State DSPEngine::gotoRunning()
{ {
qDebug() << "DSPEngine::gotoRunning"; qDebug() << "DSPEngine::gotoRunning";
switch(m_state) switch(m_state)
{ {
case StNotStarted: case StNotStarted:
@ -450,10 +451,10 @@ DSPEngine::State DSPEngine::gotoRunning()
} }
if(m_sampleSource == NULL) { if(m_sampleSource == NULL) {
return gotoError("No sample source configured"); return gotoError("DSPEngine::gotoRunning: No sample source configured");
} }
qDebug() << " - " << m_deviceDescription.toStdString().c_str() << " started"; qDebug() << "DSPEngine::gotoRunning: " << m_deviceDescription.toStdString().c_str() << " started";
// Start everything // Start everything
@ -463,20 +464,21 @@ DSPEngine::State DSPEngine::gotoRunning()
} }
m_audioOutput.start(-1, 48000); // Use default output device at 48 kHz m_audioOutput.start(-1, 48000); // Use default output device at 48 kHz
m_audioSampleRate = m_audioOutput.getRate();
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++)
{ {
qDebug() << " - starting " << (*it)->objectName().toStdString().c_str(); qDebug() << "DSPEngine::gotoRunning: starting " << (*it)->objectName().toStdString().c_str();
(*it)->start(); (*it)->start();
} }
for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it) for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it)
{ {
qDebug() << " - starting ThreadedSampleSink(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")"; qDebug() << "DSPEngine::gotoRunning: starting ThreadedSampleSink(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")";
(*it)->start(); (*it)->start();
} }
qDebug() << " - input message queue pending: " << m_inputMessageQueue.size(); qDebug() << "DSPEngine::gotoRunning:input message queue pending: " << m_inputMessageQueue.size();
return StRunning; return StRunning;
} }
@ -681,3 +683,8 @@ void DSPEngine::handleSourceMessages()
delete message; delete message;
} }
} }
void DSPEngine::setAudioSampleRate(uint rate)
{
m_audioSampleRate = rate;
}

View File

@ -90,7 +90,7 @@ bool FileSink::handleMessage(const Message& message)
DSPSignalNotification& notif = (DSPSignalNotification&) message; DSPSignalNotification& notif = (DSPSignalNotification&) message;
m_sampleRate = notif.getSampleRate(); m_sampleRate = notif.getSampleRate();
m_centerFrequency = notif.getCenterFrequency(); m_centerFrequency = notif.getCenterFrequency();
qDebug() << " - DSPSignalNotification: m_inputSampleRate: " << m_sampleRate qDebug() << "FileSink::handleMessage: DSPSignalNotification: m_inputSampleRate: " << m_sampleRate
<< " m_centerFrequency: " << m_centerFrequency; << " m_centerFrequency: " << m_centerFrequency;
return true; return true;
} }
@ -98,7 +98,7 @@ bool FileSink::handleMessage(const Message& message)
{ {
MsgConfigureFileSink& conf = (MsgConfigureFileSink&) message; MsgConfigureFileSink& conf = (MsgConfigureFileSink&) message;
handleConfigure(conf.getFileName()); handleConfigure(conf.getFileName());
qDebug() << " - MsgConfigureFileSink: fileName: " << m_fileName.c_str(); qDebug() << "FileSink::handleMessage: MsgConfigureFileSink: fileName: " << m_fileName.c_str();
return true; return true;
} }
else else

View File

@ -1,10 +1,26 @@
#include <QThread> #include <QThread>
#include <QDebug> #include <QDebug>
#include <QApplication>
#include "dsp/threadedsamplesink.h" #include "dsp/threadedsamplesink.h"
#include "dsp/dspcommands.h" #include "dsp/dspcommands.h"
#include "util/message.h" #include "util/message.h"
ThreadedSampleFifo::ThreadedSampleFifo(SampleSink *sampleSink, std::size_t size) :
m_sampleSink(sampleSink)
{
connect(&m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleFifoData()));
m_sampleFifo.setSize(size);
}
ThreadedSampleFifo::~ThreadedSampleFifo()
{
m_sampleFifo.readCommit(m_sampleFifo.fill());
}
void ThreadedSampleFifo::writeToFifo(SampleVector::const_iterator& begin, SampleVector::const_iterator& end)
{
m_sampleFifo.write(begin, end);
}
ThreadedSampleSink::ThreadedSampleSink(SampleSink* sampleSink, QObject *parent) : ThreadedSampleSink::ThreadedSampleSink(SampleSink* sampleSink, QObject *parent) :
m_sampleSink(sampleSink) m_sampleSink(sampleSink)
{ {
@ -14,11 +30,13 @@ ThreadedSampleSink::ThreadedSampleSink(SampleSink* sampleSink, QObject *parent)
qDebug() << "ThreadedSampleSink::ThreadedSampleSink: " << name; qDebug() << "ThreadedSampleSink::ThreadedSampleSink: " << name;
m_thread = new QThread(parent); m_thread = new QThread(parent);
moveToThread(m_thread); // FIXME: the intermediate FIFO should be handled within the sink. Define a new type of sink that is compatible with threading m_threadedSampleFifo = new ThreadedSampleFifo(m_sampleSink);
//moveToThread(m_thread); // FIXME: Fixed? the intermediate FIFO should be handled within the sink. Define a new type of sink that is compatible with threading
m_sampleSink->moveToThread(m_thread); m_sampleSink->moveToThread(m_thread);
m_sampleFifo.moveToThread(m_thread); m_threadedSampleFifo->moveToThread(m_thread);
connect(&m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleData())); //m_sampleFifo.moveToThread(m_thread);
m_sampleFifo.setSize(262144); //connect(&m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleData()));
//m_sampleFifo.setSize(262144);
qDebug() << "ThreadedSampleSink::ThreadedSampleSink: thread: " << thread() << " m_thread: " << m_thread; qDebug() << "ThreadedSampleSink::ThreadedSampleSink: thread: " << thread() << " m_thread: " << m_thread;
} }
@ -41,14 +59,13 @@ void ThreadedSampleSink::stop()
m_sampleSink->stop(); m_sampleSink->stop();
m_thread->exit(); m_thread->exit();
m_thread->wait(); m_thread->wait();
m_sampleFifo.readCommit(m_sampleFifo.fill());
} }
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);
m_sampleFifo.write(begin, end); //m_sampleFifo.write(begin, end);
m_threadedSampleFifo->writeToFifo(begin, end);
} }
bool ThreadedSampleSink::handleSinkMessage(Message& cmd) bool ThreadedSampleSink::handleSinkMessage(Message& cmd)
@ -62,7 +79,7 @@ QString ThreadedSampleSink::getSampleSinkObjectName() const
} }
void ThreadedSampleSink::handleData() // FIXME: Move it to the new threadable sink class void ThreadedSampleFifo::handleFifoData() // FIXME: Fixed? Move it to the new threadable sink class
{ {
bool positiveOnly = false; bool positiveOnly = false;

View File

@ -100,14 +100,13 @@ MainWindow::MainWindow(QWidget* parent) :
ui->sampleSource->blockSignals(sampleSourceSignalsBlocked); ui->sampleSource->blockSignals(sampleSourceSignalsBlocked);
m_spectrumVis = new SpectrumVis(ui->glSpectrum); m_spectrumVis = new SpectrumVis(ui->glSpectrum);
ui->glSpectrum->connectTimer(m_masterTimer);
ui->glSpectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
m_dspEngine->addSink(m_spectrumVis); m_dspEngine->addSink(m_spectrumVis);
m_fileSink = new FileSink(); m_fileSink = new FileSink();
m_dspEngine->addSink(m_fileSink); m_dspEngine->addSink(m_fileSink);
ui->glSpectrum->connectTimer(m_masterTimer);
ui->glSpectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
qDebug() << "MainWindow::MainWindow: loadSettings..."; qDebug() << "MainWindow::MainWindow: loadSettings...";
loadSettings(); loadSettings();
@ -123,17 +122,17 @@ MainWindow::MainWindow(QWidget* parent) :
ui->sampleSource->blockSignals(sampleSourceSignalsBlocked); ui->sampleSource->blockSignals(sampleSourceSignalsBlocked);
} }
qDebug() << "MainWindow::MainWindow: load current settings..."; qDebug() << "MainWindow::MainWindow: load current preset settings...";
loadSettings(m_settings.getCurrent()); loadPresetSettings(m_settings.getCurrent());
qDebug() << "MainWindow::MainWindow: apply settings..."; qDebug() << "MainWindow::MainWindow: apply settings...";
applySettings(); applySettings();
qDebug() << "MainWindow::MainWindow: update presets..."; qDebug() << "MainWindow::MainWindow: update preset controls...";
updatePresets(); updatePresetControls();
qDebug() << "MainWindow::MainWindow: end"; qDebug() << "MainWindow::MainWindow: end";
} }
@ -203,15 +202,11 @@ void MainWindow::loadSettings()
{ {
addPresetToTree(m_settings.getPreset(i)); addPresetToTree(m_settings.getPreset(i));
} }
Preset* current = m_settings.getCurrent();
//loadSettings(current);
} }
void MainWindow::loadSettings(const Preset* preset) void MainWindow::loadPresetSettings(const Preset* preset)
{ {
qDebug() << "MainWindow::loadSettings(preset): " << preset->getSource().toStdString().c_str(); qDebug() << "MainWindow::loadPresetSettings: preset: " << preset->getSource().toStdString().c_str();
ui->glSpectrumGUI->deserialize(preset->getSpectrumConfig()); ui->glSpectrumGUI->deserialize(preset->getSpectrumConfig());
ui->dcOffset->setChecked(preset->getDCOffsetCorrection()); ui->dcOffset->setChecked(preset->getDCOffsetCorrection());
@ -227,14 +222,14 @@ void MainWindow::saveSettings()
{ {
qDebug() << "MainWindow::saveSettings"; qDebug() << "MainWindow::saveSettings";
saveSettings(m_settings.getCurrent()); savePresetSettings(m_settings.getCurrent());
m_settings.save(); m_settings.save();
} }
void MainWindow::saveSettings(Preset* preset) void MainWindow::savePresetSettings(Preset* preset)
{ {
qDebug() << "MainWindow::saveSettings(preset): " << preset->getSource().toStdString().c_str(); qDebug() << "MainWindow::savePresetSettings: preset: " << preset->getSource().toStdString().c_str();
preset->setSpectrumConfig(ui->glSpectrumGUI->serialize()); preset->setSpectrumConfig(ui->glSpectrumGUI->serialize());
preset->clearChannels(); preset->clearChannels();
@ -281,13 +276,17 @@ void MainWindow::updateSampleRate()
m_sampleRateWidget->setText(tr("Rate: %1 kHz").arg((float)m_sampleRate / 1000)); m_sampleRateWidget->setText(tr("Rate: %1 kHz").arg((float)m_sampleRate / 1000));
} }
void MainWindow::updatePresets() void MainWindow::updatePresetControls()
{ {
ui->presetTree->resizeColumnToContents(0); ui->presetTree->resizeColumnToContents(0);
if(ui->presetTree->currentItem() != 0) {
if(ui->presetTree->currentItem() != 0)
{
ui->presetDelete->setEnabled(true); ui->presetDelete->setEnabled(true);
ui->presetLoad->setEnabled(true); ui->presetLoad->setEnabled(true);
} else { }
else
{
ui->presetDelete->setEnabled(false); ui->presetDelete->setEnabled(false);
ui->presetLoad->setEnabled(false); ui->presetLoad->setEnabled(false);
} }
@ -318,7 +317,7 @@ QTreeWidgetItem* MainWindow::addPresetToTree(const Preset* preset)
item->setData(0, Qt::UserRole, qVariantFromValue(preset)); item->setData(0, Qt::UserRole, qVariantFromValue(preset));
ui->presetTree->resizeColumnToContents(0); ui->presetTree->resizeColumnToContents(0);
updatePresets(); updatePresetControls();
return item; return item;
} }
@ -477,7 +476,7 @@ void MainWindow::on_presetSave_clicked()
if(dlg.exec() == QDialog::Accepted) { if(dlg.exec() == QDialog::Accepted) {
Preset* preset = m_settings.newPreset(dlg.group(), dlg.description()); Preset* preset = m_settings.newPreset(dlg.group(), dlg.description());
saveSettings(preset); savePresetSettings(preset);
ui->presetTree->setCurrentItem(addPresetToTree(preset)); ui->presetTree->setCurrentItem(addPresetToTree(preset));
} }
@ -492,7 +491,7 @@ void MainWindow::on_presetUpdate_clicked()
const Preset* preset = qvariant_cast<const Preset*>(item->data(0, Qt::UserRole)); const Preset* preset = qvariant_cast<const Preset*>(item->data(0, Qt::UserRole));
if (preset != 0) { if (preset != 0) {
Preset* preset_mod = const_cast<Preset*>(preset); Preset* preset_mod = const_cast<Preset*>(preset);
saveSettings(preset_mod); savePresetSettings(preset_mod);
} }
} }
} }
@ -504,7 +503,7 @@ void MainWindow::on_presetLoad_clicked()
QTreeWidgetItem* item = ui->presetTree->currentItem(); QTreeWidgetItem* item = ui->presetTree->currentItem();
if(item == 0) { if(item == 0) {
updatePresets(); updatePresetControls();
return; return;
} }
const Preset* preset = qvariant_cast<const Preset*>(item->data(0, Qt::UserRole)); const Preset* preset = qvariant_cast<const Preset*>(item->data(0, Qt::UserRole));
@ -512,7 +511,7 @@ void MainWindow::on_presetLoad_clicked()
return; return;
} }
loadSettings(preset); loadPresetSettings(preset);
applySettings(); applySettings();
} }
@ -520,7 +519,7 @@ void MainWindow::on_presetDelete_clicked()
{ {
QTreeWidgetItem* item = ui->presetTree->currentItem(); QTreeWidgetItem* item = ui->presetTree->currentItem();
if(item == 0) { if(item == 0) {
updatePresets(); updatePresetControls();
return; return;
} }
const Preset* preset = qvariant_cast<const Preset*>(item->data(0, Qt::UserRole)); const Preset* preset = qvariant_cast<const Preset*>(item->data(0, Qt::UserRole));
@ -535,7 +534,7 @@ void MainWindow::on_presetDelete_clicked()
void MainWindow::on_presetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) void MainWindow::on_presetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{ {
updatePresets(); updatePresetControls();
} }
void MainWindow::on_presetTree_itemActivated(QTreeWidgetItem *item, int column) void MainWindow::on_presetTree_itemActivated(QTreeWidgetItem *item, int column)