major rewrite
This commit is contained in:
parent
7820104666
commit
5864e48bd8
|
@ -39,7 +39,6 @@ endif()
|
||||||
set(sdrbase_SOURCES
|
set(sdrbase_SOURCES
|
||||||
sdrbase/mainwindow.cpp
|
sdrbase/mainwindow.cpp
|
||||||
|
|
||||||
sdrbase/audio/audiodeviceinfo.cpp
|
|
||||||
sdrbase/audio/audiofifo.cpp
|
sdrbase/audio/audiofifo.cpp
|
||||||
sdrbase/audio/audiooutput.cpp
|
sdrbase/audio/audiooutput.cpp
|
||||||
|
|
||||||
|
@ -100,7 +99,6 @@ set(sdrbase_SOURCES
|
||||||
set(sdrbase_HEADERS
|
set(sdrbase_HEADERS
|
||||||
include-gpl/mainwindow.h
|
include-gpl/mainwindow.h
|
||||||
|
|
||||||
include-gpl/audio/audiodeviceinfo.h
|
|
||||||
include-gpl/audio/audiofifo.h
|
include-gpl/audio/audiofifo.h
|
||||||
include-gpl/audio/audiooutput.h
|
include-gpl/audio/audiooutput.h
|
||||||
|
|
||||||
|
@ -119,7 +117,7 @@ set(sdrbase_HEADERS
|
||||||
include-gpl/dsp/lowpass.h
|
include-gpl/dsp/lowpass.h
|
||||||
include-gpl/dsp/movingaverage.h
|
include-gpl/dsp/movingaverage.h
|
||||||
include-gpl/dsp/nco.h
|
include-gpl/dsp/nco.h
|
||||||
sdrbase/dsp/pidcontroller.h
|
include-gpl/dsp/pidcontroller.h
|
||||||
include/dsp/samplefifo.h
|
include/dsp/samplefifo.h
|
||||||
include/dsp/samplesink.h
|
include/dsp/samplesink.h
|
||||||
include-gpl/dsp/scopevis.h
|
include-gpl/dsp/scopevis.h
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
|
||||||
// written by Christian Daniel //
|
|
||||||
// //
|
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
|
||||||
// it under the terms of the GNU General Public License as published by //
|
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
|
||||||
// //
|
|
||||||
// This program is distributed in the hope that it will be useful, //
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
||||||
// GNU General Public License V3 for more details. //
|
|
||||||
// //
|
|
||||||
// You should have received a copy of the GNU General Public License //
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef INCLUDE_AUDIODEVICEINFO_H
|
|
||||||
#define INCLUDE_AUDIODEVICEINFO_H
|
|
||||||
|
|
||||||
#include <QStringList>
|
|
||||||
#include "util/export.h"
|
|
||||||
|
|
||||||
class SDRANGELOVE_API AudioDeviceInfo {
|
|
||||||
public:
|
|
||||||
struct Device {
|
|
||||||
QString name;
|
|
||||||
QString api;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
Device(const QString& _name, const QString& _api, int _id) :
|
|
||||||
name(_name),
|
|
||||||
api(_api),
|
|
||||||
id(_id)
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
typedef QList<Device> Devices;
|
|
||||||
|
|
||||||
AudioDeviceInfo();
|
|
||||||
|
|
||||||
int match(const QString& api, const QString device) const;
|
|
||||||
|
|
||||||
const Devices& getDevices() const { return m_devices; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Devices m_devices;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // INCLUDE_AUDIODEVICEINFO_H
|
|
|
@ -36,11 +36,17 @@ public:
|
||||||
uint drain(uint numSamples);
|
uint drain(uint numSamples);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
inline uint flush() { return drain(m_fill); }
|
uint flush() { return drain(m_fill); }
|
||||||
inline uint fill() const { return m_fill; }
|
uint fill() const { return m_fill; }
|
||||||
inline bool isEmpty() const { return m_fill == 0; }
|
bool isEmpty() const { return m_fill == 0; }
|
||||||
inline bool isFull() const { return m_fill == m_size; }
|
bool isFull() const { return m_fill == m_size; }
|
||||||
inline uint size() const { return m_size; }
|
uint size() const { return m_size; }
|
||||||
|
|
||||||
|
quint32 getSampleRate() const { return m_sampleRate; }
|
||||||
|
void setSampleRate(quint32 rate) { m_sampleRate = rate; }
|
||||||
|
|
||||||
|
bool isStopped() const { return m_stopped; }
|
||||||
|
void setStopped(bool stopped) { m_stopped = stopped; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
|
@ -59,6 +65,9 @@ private:
|
||||||
QWaitCondition m_writeWaitCondition;
|
QWaitCondition m_writeWaitCondition;
|
||||||
QWaitCondition m_readWaitCondition;
|
QWaitCondition m_readWaitCondition;
|
||||||
|
|
||||||
|
quint32 m_sampleRate;
|
||||||
|
bool m_stopped;
|
||||||
|
|
||||||
bool create(uint sampleSize, uint numSamples);
|
bool create(uint sampleSize, uint numSamples);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,14 +33,25 @@ public:
|
||||||
AudioOutput();
|
AudioOutput();
|
||||||
~AudioOutput();
|
~AudioOutput();
|
||||||
|
|
||||||
bool start(int device, int rate);
|
void configure(const QString& deviceName, uint rate);
|
||||||
|
|
||||||
|
bool start();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void addFifo(AudioFifo* audioFifo);
|
void addFifo(AudioFifo* audioFifo);
|
||||||
void removeFifo(AudioFifo* audioFifo);
|
void removeFifo(AudioFifo* audioFifo);
|
||||||
|
|
||||||
|
uint getCurrentRate();
|
||||||
|
|
||||||
|
const QString& getError() const { return m_error; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
|
QString m_error;
|
||||||
|
|
||||||
|
QString m_deviceName;
|
||||||
|
quint32 m_rate;
|
||||||
|
|
||||||
QAudioOutput* m_audioOutput;
|
QAudioOutput* m_audioOutput;
|
||||||
|
|
||||||
typedef std::list<AudioFifo*> AudioFifos;
|
typedef std::list<AudioFifo*> AudioFifos;
|
||||||
|
|
|
@ -57,53 +57,3 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_CHANNELIZER_H
|
#endif // INCLUDE_CHANNELIZER_H
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
#ifndef INCLUDE_CHANNELIZER_H
|
|
||||||
#define INCLUDE_CHANNELIZER_H
|
|
||||||
|
|
||||||
#include "samplesink.h"
|
|
||||||
#include "spectrum.h"
|
|
||||||
#include "nco.h"
|
|
||||||
#include "interpolator.h"
|
|
||||||
#include "pidcontroller.h"
|
|
||||||
#include "hardware/audiofifo.h"
|
|
||||||
|
|
||||||
class AudioOutput;
|
|
||||||
|
|
||||||
class Channelizer : public SampleSink {
|
|
||||||
public:
|
|
||||||
Channelizer();
|
|
||||||
~Channelizer();
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void setGLSpectrum(GLSpectrum* glSpectrum);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t workUnitSize();
|
|
||||||
size_t work(SampleVector::const_iterator begin, SampleVector::const_iterator end);
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if 0
|
|
||||||
NCO m_nco;
|
|
||||||
Interpolator m_interpolator;
|
|
||||||
Real m_distance;
|
|
||||||
Interpolator m_interpolator2;
|
|
||||||
Real m_distance2;
|
|
||||||
|
|
||||||
SampleVector m_buffer;
|
|
||||||
size_t m_bufferFill;
|
|
||||||
Complex m_lastSample;
|
|
||||||
|
|
||||||
AudioOutput* m_audioOutput;
|
|
||||||
AudioFifo m_audioFifo;
|
|
||||||
Real m_resampler;
|
|
||||||
PIDController m_resamplerCtrl;
|
|
||||||
|
|
||||||
Spectrum m_spectrum;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // INCLUDE_CHANNELIZER_H
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -11,23 +11,23 @@ class SampleSink;
|
||||||
class AudioFifo;
|
class AudioFifo;
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPPing : public Message {
|
class SDRANGELOVE_API DSPPing : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPPing)
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPExit : public Message {
|
class SDRANGELOVE_API DSPExit : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPExit)
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPAcquisitionStart : public Message {
|
class SDRANGELOVE_API DSPAcquisitionStart : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPAcquisitionStart)
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPAcquisitionStop : public Message {
|
class SDRANGELOVE_API DSPAcquisitionStop : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPAcquisitionStop)
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPGetDeviceDescription : public Message {
|
class SDRANGELOVE_API DSPGetDeviceDescription : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPGetDeviceDescription)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setDeviceDescription(const QString& text) { m_deviceDescription = text; }
|
void setDeviceDescription(const QString& text) { m_deviceDescription = text; }
|
||||||
|
@ -38,7 +38,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPGetErrorMessage : public Message {
|
class SDRANGELOVE_API DSPGetErrorMessage : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPGetErrorMessage)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setErrorMessage(const QString& text) { m_errorMessage = text; }
|
void setErrorMessage(const QString& text) { m_errorMessage = text; }
|
||||||
|
@ -49,7 +49,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPSetSource : public Message {
|
class SDRANGELOVE_API DSPSetSource : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPSetSource)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DSPSetSource(SampleSource* sampleSource) : Message(), m_sampleSource(sampleSource) { }
|
DSPSetSource(SampleSource* sampleSource) : Message(), m_sampleSource(sampleSource) { }
|
||||||
|
@ -61,7 +61,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPAddSink : public Message {
|
class SDRANGELOVE_API DSPAddSink : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPAddSink)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DSPAddSink(SampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
|
DSPAddSink(SampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
|
||||||
|
@ -73,7 +73,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPRemoveSink : public Message {
|
class SDRANGELOVE_API DSPRemoveSink : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPRemoveSink)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DSPRemoveSink(SampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
|
DSPRemoveSink(SampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
|
||||||
|
@ -85,7 +85,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPAddAudioSource : public Message {
|
class SDRANGELOVE_API DSPAddAudioSource : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPAddAudioSource)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DSPAddAudioSource(AudioFifo* audioFifo) : Message(), m_audioFifo(audioFifo) { }
|
DSPAddAudioSource(AudioFifo* audioFifo) : Message(), m_audioFifo(audioFifo) { }
|
||||||
|
@ -97,7 +97,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPRemoveAudioSource : public Message {
|
class SDRANGELOVE_API DSPRemoveAudioSource : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPRemoveAudioSource)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DSPRemoveAudioSource(AudioFifo* audioFifo) : Message(), m_audioFifo(audioFifo) { }
|
DSPRemoveAudioSource(AudioFifo* audioFifo) : Message(), m_audioFifo(audioFifo) { }
|
||||||
|
@ -109,7 +109,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPConfigureSpectrumVis : public Message {
|
class SDRANGELOVE_API DSPConfigureSpectrumVis : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPConfigureSpectrumVis)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getFFTSize() const { return m_fftSize; }
|
int getFFTSize() const { return m_fftSize; }
|
||||||
|
@ -135,7 +135,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPConfigureCorrection : public Message {
|
class SDRANGELOVE_API DSPConfigureCorrection : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPConfigureCorrection)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool getDCOffsetCorrection() const { return m_dcOffsetCorrection; }
|
bool getDCOffsetCorrection() const { return m_dcOffsetCorrection; }
|
||||||
|
@ -157,8 +157,31 @@ private:
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SDRANGELOVE_API DSPConfigureAudioOutput : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION(DSPConfigureAudioOutput)
|
||||||
|
|
||||||
|
public:
|
||||||
|
const QString& getAudioOutputDevice() const { return m_audioOutputDevice; }
|
||||||
|
uint getAudioOutputRate() const { return m_audioOutputRate; }
|
||||||
|
|
||||||
|
static DSPConfigureAudioOutput* create(const QString& audioOutputDevice, uint audioOutputRate)
|
||||||
|
{
|
||||||
|
return new DSPConfigureAudioOutput(audioOutputDevice, audioOutputRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_audioOutputDevice;
|
||||||
|
uint m_audioOutputRate;
|
||||||
|
|
||||||
|
DSPConfigureAudioOutput(const QString& audioOutputDevice, uint audioOutputRate) :
|
||||||
|
Message(),
|
||||||
|
m_audioOutputDevice(audioOutputDevice),
|
||||||
|
m_audioOutputRate(audioOutputRate)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPEngineReport : public Message {
|
class SDRANGELOVE_API DSPEngineReport : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPEngineReport)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
|
@ -181,7 +204,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPConfigureScopeVis : public Message {
|
class SDRANGELOVE_API DSPConfigureScopeVis : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPConfigureScopeVis)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getTriggerChannel() const { return m_triggerChannel; }
|
int getTriggerChannel() const { return m_triggerChannel; }
|
||||||
|
@ -207,7 +230,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPSignalNotification : public Message {
|
class SDRANGELOVE_API DSPSignalNotification : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPSignalNotification)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
|
@ -230,7 +253,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDRANGELOVE_API DSPConfigureChannelizer : public Message {
|
class SDRANGELOVE_API DSPConfigureChannelizer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(DSPConfigureChannelizer)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
|
|
|
@ -64,6 +64,7 @@ public:
|
||||||
void removeAudioSource(AudioFifo* audioFifo);
|
void removeAudioSource(AudioFifo* audioFifo);
|
||||||
|
|
||||||
void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection);
|
void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection);
|
||||||
|
void configureAudioOutput(const QString& audioOutput, quint32 audioOutputRate);
|
||||||
|
|
||||||
State state() const { return m_state; }
|
State state() const { return m_state; }
|
||||||
|
|
||||||
|
|
|
@ -281,7 +281,6 @@ protected:
|
||||||
#error unsupported filter order
|
#error unsupported filter order
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// init read-pointer
|
// init read-pointer
|
||||||
int a = (m_ptr + 1) % (HB_FILTERORDER + 1);
|
int a = (m_ptr + 1) % (HB_FILTERORDER + 1);
|
||||||
int b = (m_ptr + (HB_FILTERORDER - 1)) % (HB_FILTERORDER + 1);
|
int b = (m_ptr + (HB_FILTERORDER - 1)) % (HB_FILTERORDER + 1);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
class AudioDeviceInfo;
|
class Preferences;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PreferencesDialog;
|
class PreferencesDialog;
|
||||||
|
@ -13,19 +13,13 @@ class PreferencesDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PreferencesDialog(AudioDeviceInfo* audioDeviceInfo, QWidget* parent = NULL);
|
explicit PreferencesDialog(Preferences* preferences, QWidget* parent = NULL);
|
||||||
~PreferencesDialog();
|
~PreferencesDialog();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Audio {
|
|
||||||
ATDefault,
|
|
||||||
ATInterface,
|
|
||||||
ATDevice
|
|
||||||
};
|
|
||||||
|
|
||||||
Ui::PreferencesDialog* ui;
|
Ui::PreferencesDialog* ui;
|
||||||
|
|
||||||
AudioDeviceInfo* m_audioDeviceInfo;
|
Preferences* m_preferences;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void accept();
|
void accept();
|
||||||
|
|
|
@ -32,9 +32,10 @@ class SDRANGELOVE_API ScopeWindow : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ScopeWindow(DSPEngine* dspEngine, QWidget* parent = NULL);
|
explicit ScopeWindow(QWidget* parent = NULL);
|
||||||
~ScopeWindow();
|
~ScopeWindow();
|
||||||
|
|
||||||
|
void setDSPEngine(DSPEngine* dspEngine);
|
||||||
void setSampleRate(int sampleRate);
|
void setSampleRate(int sampleRate);
|
||||||
|
|
||||||
void resetToDefaults();
|
void resetToDefaults();
|
||||||
|
|
|
@ -27,7 +27,6 @@ class QLabel;
|
||||||
class QTreeWidgetItem;
|
class QTreeWidgetItem;
|
||||||
class QDir;
|
class QDir;
|
||||||
|
|
||||||
class AudioDeviceInfo;
|
|
||||||
class DSPEngine;
|
class DSPEngine;
|
||||||
class Indicator;
|
class Indicator;
|
||||||
class ScopeWindow;
|
class ScopeWindow;
|
||||||
|
@ -70,8 +69,6 @@ private:
|
||||||
|
|
||||||
Ui::MainWindow* ui;
|
Ui::MainWindow* ui;
|
||||||
|
|
||||||
AudioDeviceInfo* m_audioDeviceInfo;
|
|
||||||
|
|
||||||
MessageQueue* m_messageQueue;
|
MessageQueue* m_messageQueue;
|
||||||
|
|
||||||
Settings m_settings;
|
Settings m_settings;
|
||||||
|
@ -114,6 +111,7 @@ private:
|
||||||
private slots:
|
private slots:
|
||||||
void handleMessages();
|
void handleMessages();
|
||||||
void updateStatus();
|
void updateStatus();
|
||||||
|
void updateEnables(bool running);
|
||||||
void scopeWindowDestroyed();
|
void scopeWindowDestroyed();
|
||||||
void on_action_Start_triggered();
|
void on_action_Start_triggered();
|
||||||
void on_action_Stop_triggered();
|
void on_action_Stop_triggered();
|
||||||
|
|
|
@ -11,22 +11,15 @@ public:
|
||||||
QByteArray serialize() const;
|
QByteArray serialize() const;
|
||||||
bool deserialize(const QByteArray& data);
|
bool deserialize(const QByteArray& data);
|
||||||
|
|
||||||
void setSourceType(const QString& value) { m_sourceType = value; }
|
void setAudioOutput(const QString& value) { m_audioOutput = value; }
|
||||||
const QString& getSourceType() const { return m_sourceType; }
|
const QString& getAudioOutput() const { return m_audioOutput; }
|
||||||
void setSourceDevice(const QString& value) { m_sourceDevice= value; }
|
|
||||||
const QString& getSourceDevice() const { return m_sourceDevice; }
|
|
||||||
|
|
||||||
void setAudioType(const QString& value) { m_audioType = value; }
|
void setAudioOutputRate(quint32 value) { m_audioOutputRate = value; }
|
||||||
const QString& getAudioType() const { return m_audioType; }
|
uint getAudioOutputRate() const { return m_audioOutputRate; }
|
||||||
void setAudioDevice(const QString& value) { m_audioDevice= value; }
|
|
||||||
const QString& getAudioDevice() const { return m_audioDevice; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString m_sourceType;
|
QString m_audioOutput;
|
||||||
QString m_sourceDevice;
|
uint m_audioOutputRate;
|
||||||
|
|
||||||
QString m_audioType;
|
|
||||||
QString m_audioDevice;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_PREFERENCES_H
|
#endif // INCLUDE_PREFERENCES_H
|
||||||
|
|
|
@ -22,6 +22,8 @@ public:
|
||||||
|
|
||||||
Preset* getCurrent() { return &m_current; }
|
Preset* getCurrent() { return &m_current; }
|
||||||
|
|
||||||
|
Preferences* getPreferences() { return &m_preferences; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Preferences m_preferences;
|
Preferences m_preferences;
|
||||||
Preset m_current;
|
Preset m_current;
|
||||||
|
|
|
@ -38,11 +38,12 @@ protected:
|
||||||
int m_result;
|
int m_result;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MESSAGE_CLASS_DECLARATION \
|
#define MESSAGE_CLASS_DECLARATION(Name) \
|
||||||
public: \
|
public: \
|
||||||
const char* getIdentifier() const; \
|
const char* getIdentifier() const; \
|
||||||
bool matchIdentifier(const char* identifier) const; \
|
bool matchIdentifier(const char* identifier) const; \
|
||||||
static bool match(Message* message); \
|
static bool match(Message* message); \
|
||||||
|
static Name* cast(Message* message) { return match(message) ? (Name*)message : NULL; } \
|
||||||
protected: \
|
protected: \
|
||||||
static const char* m_identifier; \
|
static const char* m_identifier; \
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <complex.h>
|
||||||
#include "nfmdemod.h"
|
#include "nfmdemod.h"
|
||||||
#include "audio/audiooutput.h"
|
#include "audio/audiooutput.h"
|
||||||
#include "dsp/dspcommands.h"
|
#include "dsp/dspcommands.h"
|
||||||
|
#include "dsp/pidcontroller.h"
|
||||||
|
|
||||||
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureNFMDemod, Message)
|
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureNFMDemod, Message)
|
||||||
|
|
||||||
|
@ -27,20 +29,17 @@ NFMDemod::NFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
|
||||||
m_sampleSink(sampleSink),
|
m_sampleSink(sampleSink),
|
||||||
m_audioFifo(audioFifo)
|
m_audioFifo(audioFifo)
|
||||||
{
|
{
|
||||||
m_rfBandwidth = 12500;
|
m_config.m_inputSampleRate = 500000;
|
||||||
m_volume = 2.0;
|
m_config.m_inputFrequencyOffset = 0;
|
||||||
m_squelchLevel = pow(10.0, -40.0 / 20.0);
|
m_config.m_rfBandwidth = 12500;
|
||||||
m_sampleRate = 500000;
|
m_config.m_afBandwidth = 3000;
|
||||||
m_frequency = 0;
|
m_config.m_squelch = -40.0;
|
||||||
m_squelchLevel *= m_squelchLevel;
|
m_config.m_volume = 2.0;
|
||||||
|
m_config.m_audioSampleRate = 44100;
|
||||||
|
|
||||||
m_nco.setFreq(m_frequency, m_sampleRate);
|
apply();
|
||||||
m_interpolator.create(16, m_sampleRate, 12500);
|
|
||||||
m_sampleDistanceRemain = (Real)m_sampleRate / 44100.0;
|
|
||||||
|
|
||||||
m_lowpass.create(21, 44100, 3000);
|
m_audioBuffer.resize(16384);
|
||||||
|
|
||||||
m_audioBuffer.resize(256);
|
|
||||||
m_audioBufferFill = 0;
|
m_audioBufferFill = 0;
|
||||||
|
|
||||||
m_movingAverage.resize(16, 0);
|
m_movingAverage.resize(16, 0);
|
||||||
|
@ -56,52 +55,145 @@ void NFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBa
|
||||||
cmd->submit(messageQueue, this);
|
cmd->submit(messageQueue, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float arctan2(Real y, Real x)
|
||||||
|
{
|
||||||
|
Real coeff_1 = M_PI / 4;
|
||||||
|
Real coeff_2 = 3 * coeff_1;
|
||||||
|
Real abs_y = fabs(y) + 1e-10; // kludge to prevent 0/0 condition
|
||||||
|
Real angle;
|
||||||
|
if( x>= 0) {
|
||||||
|
Real r = (x - abs_y) / (x + abs_y);
|
||||||
|
angle = coeff_1 - coeff_1 * r;
|
||||||
|
} else {
|
||||||
|
Real r = (x + abs_y) / (abs_y - x);
|
||||||
|
angle = coeff_2 - coeff_1 * r;
|
||||||
|
}
|
||||||
|
if(y < 0)
|
||||||
|
return(-angle);
|
||||||
|
else return(angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Real angleDist(Real a, Real b)
|
||||||
|
{
|
||||||
|
Real dist = b - a;
|
||||||
|
|
||||||
|
while(dist <= M_PI)
|
||||||
|
dist += 2 * M_PI;
|
||||||
|
while(dist >= M_PI)
|
||||||
|
dist -= 2 * M_PI;
|
||||||
|
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
|
void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
|
||||||
{
|
{
|
||||||
Complex ci;
|
Complex ci;
|
||||||
bool consumed;
|
bool consumed;
|
||||||
|
|
||||||
for(SampleVector::const_iterator it = begin; it < end; ++it) {
|
if(m_audioFifo->size() <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(m_audioFifo->getSampleRate() != m_config.m_audioSampleRate) {
|
||||||
|
m_config.m_audioSampleRate = m_audioFifo->getSampleRate();
|
||||||
|
apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(firstOfBurst) {
|
||||||
|
if(m_audioFifo->isStopped()) {
|
||||||
|
if(m_audioFifo->fill() >= m_audioFifo->size() / 8.0) {
|
||||||
|
m_audioFifo->setStopped(false);
|
||||||
|
m_interpolatorRegulation = 0.9999;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Real err = (Real)m_audioFifo->fill() / ((Real)m_audioFifo->size() / 9.0);
|
||||||
|
if(err < 0.999)
|
||||||
|
err = 0.999;
|
||||||
|
else if(err > 1.001)
|
||||||
|
err = 1.001;
|
||||||
|
|
||||||
|
m_interpolatorRegulation = (m_interpolatorRegulation * 400.0 + err * 1.0) / 401.0;
|
||||||
|
|
||||||
|
if(m_interpolatorRegulation < 0.99)
|
||||||
|
m_interpolatorRegulation = 0.99;
|
||||||
|
else if(m_interpolatorRegulation > 1.01)
|
||||||
|
m_interpolatorRegulation = 1.01;
|
||||||
|
}
|
||||||
|
m_interpolatorDistance = m_interpolatorRegulation * (Real)m_running.m_inputSampleRate / (Real)m_running.m_audioSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
consumed = false;
|
consumed = false;
|
||||||
if(m_interpolator.interpolate(&m_sampleDistanceRemain, c, &consumed, &ci)) {
|
while(!consumed) {
|
||||||
m_sampleBuffer.push_back(Sample(ci.real() * 32768.0, ci.imag() * 32768.0));
|
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &consumed, &ci)) {
|
||||||
|
m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0));
|
||||||
|
|
||||||
m_movingAverage.feed(ci.real() * ci.real() + ci.imag() * ci.imag());
|
m_movingAverage.feed(ci.real() * ci.real() + ci.imag() * ci.imag());
|
||||||
|
if(m_movingAverage.average() >= m_squelchLevel)
|
||||||
|
m_squelchState = m_running.m_audioSampleRate/ 20;
|
||||||
|
|
||||||
if(m_movingAverage.average() >= m_squelchLevel)
|
qint16 sample;
|
||||||
m_squelchState = m_sampleRate / 50;
|
|
||||||
|
|
||||||
if(m_squelchState > 0) {
|
m_squelchState = 999;
|
||||||
m_squelchState--;
|
if(m_squelchState > 0) {
|
||||||
Complex d = ci * conj(m_lastSample);
|
m_squelchState--;
|
||||||
m_lastSample = ci;
|
/*
|
||||||
Real demod = atan2(d.imag(), d.real()) / M_PI;
|
Real argument = arg(ci);
|
||||||
demod = m_lowpass.filter(demod);
|
Real demod = argument - m_lastArgument;
|
||||||
demod *= m_volume;
|
m_lastArgument = argument;
|
||||||
qint16 sample = demod * 32767;
|
*/
|
||||||
|
|
||||||
|
Complex d = conj(m_lastSample) * ci;
|
||||||
|
m_lastSample = ci;
|
||||||
|
Real demod = atan2(d.imag(), d.real());
|
||||||
|
//Real demod = arctan2(d.imag(), d.real());
|
||||||
|
/*
|
||||||
|
Real argument1 = arg(ci);//atan2(ci.imag(), ci.real());
|
||||||
|
Real argument2 = m_lastSample.real();
|
||||||
|
Real demod = angleDist(argument2, argument1);
|
||||||
|
m_lastSample = Complex(argument1, 0);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
demod /= M_PI;
|
||||||
|
|
||||||
|
demod = m_lowpass.filter(demod);
|
||||||
|
|
||||||
|
if(demod < -1)
|
||||||
|
demod = -1;
|
||||||
|
else if(demod > 1)
|
||||||
|
demod = 1;
|
||||||
|
|
||||||
|
demod *= m_running.m_volume;
|
||||||
|
sample = demod * 32700;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
sample = 0;
|
||||||
|
qDebug("!!!");
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
if(res != m_audioBufferFill)
|
||||||
qDebug("lost %u samples", m_audioBufferFill - res);
|
qDebug("lost %u audio samples", m_audioBufferFill - res);
|
||||||
*/
|
|
||||||
m_audioBufferFill = 0;
|
m_audioBufferFill = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
m_sampleDistanceRemain += (Real)m_sampleRate / 44100.0;
|
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 0) != m_audioBufferFill)
|
if(m_audioBufferFill > 0) {
|
||||||
;//qDebug("lost samples");
|
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
|
||||||
m_audioBufferFill = 0;
|
if(res != m_audioBufferFill)
|
||||||
|
qDebug("lost %u samples", m_audioBufferFill - res);
|
||||||
|
m_audioBufferFill = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(m_sampleSink != NULL)
|
if(m_sampleSink != NULL)
|
||||||
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), firstOfBurst);
|
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), firstOfBurst);
|
||||||
|
@ -111,6 +203,12 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
|
||||||
void NFMDemod::start()
|
void NFMDemod::start()
|
||||||
{
|
{
|
||||||
m_squelchState = 0;
|
m_squelchState = 0;
|
||||||
|
m_audioFifo->clear();
|
||||||
|
m_audioFifo->setStopped(true);
|
||||||
|
m_interpolatorRegulation = 0.9999;
|
||||||
|
m_interpolatorDistance = 1.0;
|
||||||
|
m_interpolatorDistanceRemain = 0.0;
|
||||||
|
m_lastSample = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NFMDemod::stop()
|
void NFMDemod::stop()
|
||||||
|
@ -120,24 +218,20 @@ void NFMDemod::stop()
|
||||||
bool NFMDemod::handleMessage(Message* cmd)
|
bool NFMDemod::handleMessage(Message* cmd)
|
||||||
{
|
{
|
||||||
if(DSPSignalNotification::match(cmd)) {
|
if(DSPSignalNotification::match(cmd)) {
|
||||||
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
|
DSPSignalNotification* signal = DSPSignalNotification::cast(cmd);
|
||||||
qDebug("%d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset());
|
|
||||||
m_sampleRate = signal->getSampleRate();
|
m_config.m_inputSampleRate = signal->getSampleRate();
|
||||||
m_nco.setFreq(-signal->getFrequencyOffset(), m_sampleRate);
|
m_config.m_inputFrequencyOffset = signal->getFrequencyOffset();
|
||||||
m_interpolator.create(16, m_sampleRate, m_rfBandwidth / 2.1);
|
apply();
|
||||||
m_sampleDistanceRemain = m_sampleRate / 44100.0;
|
|
||||||
m_squelchState = 0;
|
|
||||||
cmd->completed();
|
cmd->completed();
|
||||||
return true;
|
return true;
|
||||||
} else if(MsgConfigureNFMDemod::match(cmd)) {
|
} else if(MsgConfigureNFMDemod::match(cmd)) {
|
||||||
MsgConfigureNFMDemod* cfg = (MsgConfigureNFMDemod*)cmd;
|
MsgConfigureNFMDemod* cfg = MsgConfigureNFMDemod::cast(cmd);
|
||||||
m_rfBandwidth = cfg->getRFBandwidth();
|
m_config.m_rfBandwidth = cfg->getRFBandwidth();
|
||||||
m_interpolator.create(16, m_sampleRate, m_rfBandwidth / 2.1);
|
m_config.m_afBandwidth = cfg->getAFBandwidth();
|
||||||
m_lowpass.create(21, 44100, cfg->getAFBandwidth());
|
m_config.m_volume = cfg->getVolume();
|
||||||
m_squelchLevel = pow(10.0, cfg->getSquelch() / 20.0);
|
m_config.m_squelch = cfg->getSquelch();
|
||||||
m_squelchLevel *= m_squelchLevel;
|
apply();
|
||||||
m_volume = cfg->getVolume();
|
|
||||||
cmd->completed();
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if(m_sampleSink != NULL)
|
if(m_sampleSink != NULL)
|
||||||
|
@ -145,3 +239,36 @@ bool NFMDemod::handleMessage(Message* cmd)
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NFMDemod::apply()
|
||||||
|
{
|
||||||
|
|
||||||
|
if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
|
||||||
|
(m_config.m_inputSampleRate != m_running.m_inputSampleRate)) {
|
||||||
|
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
|
||||||
|
(m_config.m_rfBandwidth != m_running.m_rfBandwidth)) {
|
||||||
|
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2);
|
||||||
|
m_interpolatorDistanceRemain = 0;
|
||||||
|
m_interpolatorDistance = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((m_config.m_afBandwidth != m_running.m_afBandwidth) ||
|
||||||
|
(m_config.m_audioSampleRate != m_running.m_audioSampleRate)) {
|
||||||
|
m_lowpass.create(21, m_config.m_audioSampleRate, m_config.m_afBandwidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_config.m_squelch != m_running.m_squelch) {
|
||||||
|
m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0);
|
||||||
|
m_squelchLevel *= m_squelchLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_running.m_inputSampleRate = m_config.m_inputSampleRate;
|
||||||
|
m_running.m_inputFrequencyOffset = m_config.m_inputFrequencyOffset;
|
||||||
|
m_running.m_rfBandwidth = m_config.m_rfBandwidth;
|
||||||
|
m_running.m_squelch = m_config.m_squelch;
|
||||||
|
m_running.m_volume = m_config.m_volume;
|
||||||
|
m_running.m_audioSampleRate = m_config.m_audioSampleRate;
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class MsgConfigureNFMDemod : public Message {
|
class MsgConfigureNFMDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgConfigureNFMDemod)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Real getRFBandwidth() const { return m_rfBandwidth; }
|
Real getRFBandwidth() const { return m_rfBandwidth; }
|
||||||
|
@ -77,19 +77,45 @@ private:
|
||||||
};
|
};
|
||||||
typedef std::vector<AudioSample> AudioVector;
|
typedef std::vector<AudioSample> AudioVector;
|
||||||
|
|
||||||
Real m_rfBandwidth;
|
enum RateState {
|
||||||
Real m_volume;
|
RSInitialFill,
|
||||||
Real m_squelchLevel;
|
RSRunning
|
||||||
int m_sampleRate;
|
};
|
||||||
int m_frequency;
|
|
||||||
|
struct Config {
|
||||||
|
int m_inputSampleRate;
|
||||||
|
qint64 m_inputFrequencyOffset;
|
||||||
|
Real m_rfBandwidth;
|
||||||
|
Real m_afBandwidth;
|
||||||
|
Real m_squelch;
|
||||||
|
Real m_volume;
|
||||||
|
quint32 m_audioSampleRate;
|
||||||
|
|
||||||
|
Config() :
|
||||||
|
m_inputSampleRate(-1),
|
||||||
|
m_inputFrequencyOffset(0),
|
||||||
|
m_rfBandwidth(-1),
|
||||||
|
m_afBandwidth(-1),
|
||||||
|
m_squelch(0),
|
||||||
|
m_volume(0),
|
||||||
|
m_audioSampleRate(0)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
Config m_config;
|
||||||
|
Config m_running;
|
||||||
|
|
||||||
NCO m_nco;
|
NCO m_nco;
|
||||||
|
Real m_interpolatorRegulation;
|
||||||
Interpolator m_interpolator;
|
Interpolator m_interpolator;
|
||||||
Real m_sampleDistanceRemain;
|
Real m_interpolatorDistance;
|
||||||
|
Real m_interpolatorDistanceRemain;
|
||||||
Lowpass<Real> m_lowpass;
|
Lowpass<Real> m_lowpass;
|
||||||
|
|
||||||
|
Real m_squelchLevel;
|
||||||
int m_squelchState;
|
int m_squelchState;
|
||||||
|
|
||||||
|
Real m_lastArgument;
|
||||||
Complex m_lastSample;
|
Complex m_lastSample;
|
||||||
MovingAverage m_movingAverage;
|
MovingAverage m_movingAverage;
|
||||||
|
|
||||||
|
@ -99,6 +125,8 @@ private:
|
||||||
|
|
||||||
SampleSink* m_sampleSink;
|
SampleSink* m_sampleSink;
|
||||||
SampleVector m_sampleBuffer;
|
SampleVector m_sampleBuffer;
|
||||||
|
|
||||||
|
void apply();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_NFMDEMOD_H
|
#endif // INCLUDE_NFMDEMOD_H
|
||||||
|
|
|
@ -155,7 +155,7 @@ NFMDemodGUI::NFMDemodGUI(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, 44100 / 4);
|
m_audioFifo = new AudioFifo(4, 48000);
|
||||||
m_spectrumVis = new SpectrumVis(ui->glSpectrum);
|
m_spectrumVis = new SpectrumVis(ui->glSpectrum);
|
||||||
m_nfmDemod = new NFMDemod(m_audioFifo, m_spectrumVis);
|
m_nfmDemod = new NFMDemod(m_audioFifo, m_spectrumVis);
|
||||||
m_channelizer = new Channelizer(m_nfmDemod);
|
m_channelizer = new Channelizer(m_nfmDemod);
|
||||||
|
@ -164,7 +164,7 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
|
||||||
m_pluginAPI->addSampleSink(m_threadedSampleSink);
|
m_pluginAPI->addSampleSink(m_threadedSampleSink);
|
||||||
|
|
||||||
ui->glSpectrum->setCenterFrequency(0);
|
ui->glSpectrum->setCenterFrequency(0);
|
||||||
ui->glSpectrum->setSampleRate(44100);
|
ui->glSpectrum->setSampleRate(48000);
|
||||||
ui->glSpectrum->setDisplayWaterfall(true);
|
ui->glSpectrum->setDisplayWaterfall(true);
|
||||||
ui->glSpectrum->setDisplayMaxHold(true);
|
ui->glSpectrum->setDisplayMaxHold(true);
|
||||||
m_spectrumVis->configure(m_threadedSampleSink->getMessageQueue(), 64, 10, FFTWindow::BlackmanHarris);
|
m_spectrumVis->configure(m_threadedSampleSink->getMessageQueue(), 64, 10, FFTWindow::BlackmanHarris);
|
||||||
|
@ -200,7 +200,7 @@ void NFMDemodGUI::applySettings()
|
||||||
{
|
{
|
||||||
setTitleColor(m_channelMarker->getColor());
|
setTitleColor(m_channelMarker->getColor());
|
||||||
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
|
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
|
||||||
44100,
|
48000,
|
||||||
m_channelMarker->getCenterFrequency());
|
m_channelMarker->getCenterFrequency());
|
||||||
m_nfmDemod->configure(m_threadedSampleSink->getMessageQueue(),
|
m_nfmDemod->configure(m_threadedSampleSink->getMessageQueue(),
|
||||||
m_rfBW[ui->rfBW->value()],
|
m_rfBW[ui->rfBW->value()],
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
bool handleMessage(Message* cmd);
|
bool handleMessage(Message* cmd);
|
||||||
|
|
||||||
class MsgTCPSrcConnection : public Message {
|
class MsgTCPSrcConnection : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgTCPSrcConnection)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool getConnect() const { return m_connect; }
|
bool getConnect() const { return m_connect; }
|
||||||
|
@ -62,7 +62,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class MsgTCPSrcConfigure : public Message {
|
class MsgTCPSrcConfigure : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgTCPSrcConfigure)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SampleFormat getSampleFormat() const { return m_sampleFormat; }
|
SampleFormat getSampleFormat() const { return m_sampleFormat; }
|
||||||
|
@ -90,7 +90,7 @@ protected:
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
class MsgTCPSrcSpectrum : public Message {
|
class MsgTCPSrcSpectrum : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgTCPSrcSpectrum)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool getEnabled() const { return m_enabled; }
|
bool getEnabled() const { return m_enabled; }
|
||||||
|
|
|
@ -281,7 +281,8 @@ bool GNURadioInput::applySettings(const GeneralSettings& generalSettings,
|
||||||
|
|
||||||
if((m_settings.m_sampRate != settings.m_sampRate) || force) {
|
if((m_settings.m_sampRate != settings.m_sampRate) || force) {
|
||||||
m_settings.m_sampRate = settings.m_sampRate;
|
m_settings.m_sampRate = settings.m_sampRate;
|
||||||
radio->set_sample_rate( m_settings.m_sampRate );
|
if(m_settings.m_sampRate != 0)
|
||||||
|
radio->set_sample_rate( m_settings.m_sampRate );
|
||||||
}
|
}
|
||||||
|
|
||||||
if((m_settings.m_antenna != settings.m_antenna) || force) {
|
if((m_settings.m_antenna != settings.m_antenna) || force) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureGNURadio : public Message {
|
class MsgConfigureGNURadio : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgConfigureGNURadio)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
|
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
|
||||||
|
@ -69,7 +69,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgReportGNURadio : public Message {
|
class MsgReportGNURadio : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgReportGNURadio)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const std::vector< std::pair< QString, std::vector<double> > >& getNamedGains() const { return m_namedGains; }
|
const std::vector< std::pair< QString, std::vector<double> > >& getNamedGains() const { return m_namedGains; }
|
||||||
|
|
|
@ -122,108 +122,7 @@ bool OsmoSDRInput::Settings::deserialize(const QByteArray& data)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
OsmoSDRInput::Settings::Settings() :
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OsmoSDRInput::Settings::serialize() const
|
|
||||||
{
|
|
||||||
return QString("osmosdr:a:%1:%2:%3:%4:%5:%6:%7:%8:%9:%10:%11:%12:%13:%14:%15:%16:%17:%18")
|
|
||||||
.arg(centerFrequency)
|
|
||||||
.arg(swapIQ ? 1 : 0)
|
|
||||||
.arg(decimation)
|
|
||||||
.arg(lnaGain)
|
|
||||||
.arg(mixerGain)
|
|
||||||
.arg(mixerEnhancement)
|
|
||||||
.arg(if1gain)
|
|
||||||
.arg(if2gain)
|
|
||||||
.arg(if3gain)
|
|
||||||
.arg(if4gain)
|
|
||||||
.arg(if5gain)
|
|
||||||
.arg(if6gain)
|
|
||||||
.arg(opAmpI1)
|
|
||||||
.arg(opAmpI2)
|
|
||||||
.arg(opAmpQ1)
|
|
||||||
.arg(opAmpQ2)
|
|
||||||
.arg(dcOfsI)
|
|
||||||
.arg(dcOfsQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OsmoSDRInput::Settings::deserialize(const QString& settings)
|
|
||||||
{
|
|
||||||
QStringList list = settings.split(":");
|
|
||||||
if(list.size() < 2)
|
|
||||||
return false;
|
|
||||||
if(list[0] != "osmosdr")
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(list[1] == "a") {
|
|
||||||
bool ok;
|
|
||||||
if(list.size() != 20)
|
|
||||||
return false;
|
|
||||||
centerFrequency = list[2].toLongLong(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
swapIQ = (list[3].toInt(&ok) != 0) ? true : false;
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
decimation = list[4].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
lnaGain = list[5].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
mixerGain = list[6].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
mixerEnhancement = list[7].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
if1gain = list[8].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
if2gain = list[9].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
if3gain = list[10].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
if4gain = list[11].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
if5gain = list[12].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
if6gain = list[13].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
opAmpI1 = list[14].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
opAmpI2 = list[15].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
opAmpQ1 = list[16].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
opAmpQ2 = list[17].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
dcOfsI = list[18].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
dcOfsQ = list[19].toInt(&ok);
|
|
||||||
if(!ok)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageRegistrator OsmoSDRInput::MsgConfigureSourceOsmoSDR::ID("MsgConfigureSourceOsmoSDR");
|
|
||||||
#endif
|
|
||||||
OsmoSDRInput::OsmoSDRInput(MessageQueue* msgQueueToGUI) :
|
OsmoSDRInput::OsmoSDRInput(MessageQueue* msgQueueToGUI) :
|
||||||
SampleSource(msgQueueToGUI),
|
SampleSource(msgQueueToGUI),
|
||||||
m_settings(),
|
m_settings(),
|
||||||
|
@ -250,7 +149,7 @@ bool OsmoSDRInput::startInput(int device)
|
||||||
char serial[256];
|
char serial[256];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if(!m_sampleFifo.setSize(524288)) {
|
if(!m_sampleFifo.setSize(128 * 1024)) {
|
||||||
qCritical("Could not allocate SampleFifo");
|
qCritical("Could not allocate SampleFifo");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -341,14 +240,6 @@ bool OsmoSDRInput::handleMessage(Message* message)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if(cmd->sourceType() != DSPCmdConfigureSourceOsmoSDR::SourceType)
|
|
||||||
return false;
|
|
||||||
if(!applySettings(((DSPCmdConfigureSourceOsmoSDR*)cmd)->getSettings(), false))
|
|
||||||
qDebug("OsmoSDR config error");
|
|
||||||
cmd->completed();
|
|
||||||
return true;
|
|
||||||
*/
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureOsmoSDR : public Message {
|
class MsgConfigureOsmoSDR : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgConfigureOsmoSDR)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
|
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
|
||||||
|
|
|
@ -52,13 +52,13 @@ void OsmoSDRThread::run()
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
m_sampleFifo->readCommit(m_sampleFifo->fill());
|
||||||
|
|
||||||
m_running = true;
|
m_running = true;
|
||||||
m_startWaiter.wakeAll();
|
m_startWaiter.wakeAll();
|
||||||
|
|
||||||
//m_f = fopen("/tmp/samples.bin", "wb");
|
|
||||||
|
|
||||||
while(m_running) {
|
while(m_running) {
|
||||||
if((res = osmosdr_read_async(m_dev, &OsmoSDRThread::callbackHelper, this, 16, sizeof(Sample) * 8192 * 2)) < 0) {
|
if((res = osmosdr_read_async(m_dev, &OsmoSDRThread::callbackHelper, this, 16, sizeof(Sample) * 16384)) < 0) {
|
||||||
qCritical("OsmoSDRThread: async error: %s", strerror(errno));
|
qCritical("OsmoSDRThread: async error: %s", strerror(errno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -90,18 +90,6 @@ void OsmoSDRThread::checkData(const quint8* buf, qint32 len)
|
||||||
|
|
||||||
void OsmoSDRThread::callback(const quint8* buf, qint32 len)
|
void OsmoSDRThread::callback(const quint8* buf, qint32 len)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
qDebug("%d", len);
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
for(int i = 0; i < len / 2; i += 2) {
|
|
||||||
((qint16*)buf)[i] = sin((float)(cntr) * 1024* 2.0 * M_PI / 65536.0) * 32000.0;
|
|
||||||
((qint16*)buf)[i + 1] = -cos((float)(cntr++) * 1024*2.0 * M_PI / 65536.0) * 32000.0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
//m_sampleFifo->write((SampleVector::const_iterator)((Sample*)buf), (SampleVector::const_iterator)((Sample*)(buf + len)));
|
|
||||||
//fwrite(buf, 1, len, m_f);
|
|
||||||
//checkData(buf, len);
|
//checkData(buf, len);
|
||||||
|
|
||||||
m_sampleFifo->write(buf, len);
|
m_sampleFifo->write(buf, len);
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureRTLSDR : public Message {
|
class MsgConfigureRTLSDR : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgConfigureRTLSDR)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
|
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
|
||||||
|
@ -60,7 +60,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgReportRTLSDR : public Message {
|
class MsgReportRTLSDR : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION(MsgReportRTLSDR)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const std::vector<int>& getGains() const { return m_gains; }
|
const std::vector<int>& getGains() const { return m_gains; }
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
|
||||||
// written by Christian Daniel //
|
|
||||||
// //
|
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
|
||||||
// it under the terms of the GNU General Public License as published by //
|
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
|
||||||
// //
|
|
||||||
// This program is distributed in the hope that it will be useful, //
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
||||||
// GNU General Public License V3 for more details. //
|
|
||||||
// //
|
|
||||||
// You should have received a copy of the GNU General Public License //
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include "audio/audiodeviceinfo.h"
|
|
||||||
|
|
||||||
AudioDeviceInfo::AudioDeviceInfo()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioDeviceInfo::match(const QString& api, const QString device) const
|
|
||||||
{
|
|
||||||
// nothing found - fall back to default
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -22,7 +22,9 @@
|
||||||
#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(NULL),
|
||||||
|
m_sampleRate(0),
|
||||||
|
m_stopped(true)
|
||||||
{
|
{
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
m_fill = 0;
|
m_fill = 0;
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
|
|
||||||
AudioOutput::AudioOutput() :
|
AudioOutput::AudioOutput() :
|
||||||
m_mutex(),
|
m_mutex(),
|
||||||
|
m_error(),
|
||||||
|
m_deviceName(),
|
||||||
|
m_rate(0),
|
||||||
m_audioOutput(NULL),
|
m_audioOutput(NULL),
|
||||||
m_audioFifos()
|
m_audioFifos()
|
||||||
{
|
{
|
||||||
|
@ -39,17 +42,38 @@ AudioOutput::~AudioOutput()
|
||||||
m_audioFifos.clear();
|
m_audioFifos.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioOutput::start(int device, int rate)
|
void AudioOutput::configure(const QString& deviceName, uint rate)
|
||||||
{
|
{
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
Q_UNUSED(device);
|
m_deviceName = deviceName;
|
||||||
Q_UNUSED(rate);
|
m_rate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioOutput::start()
|
||||||
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
QAudioFormat format;
|
QAudioFormat format;
|
||||||
QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice());
|
QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice());
|
||||||
|
|
||||||
format.setSampleRate(41000);
|
if(!m_deviceName.isEmpty()) {
|
||||||
|
QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
|
||||||
|
bool found = false;
|
||||||
|
for(int i = 0; i < devices.count(); ++i) {
|
||||||
|
if(devices[i].deviceName() == m_deviceName) {
|
||||||
|
devInfo = devices[i];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found) {
|
||||||
|
m_error = tr("Audio output device %1 not available").arg(m_deviceName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format.setSampleRate(m_rate);
|
||||||
format.setChannelCount(2);
|
format.setChannelCount(2);
|
||||||
format.setSampleSize(16);
|
format.setSampleSize(16);
|
||||||
format.setCodec("audio/pcm");
|
format.setCodec("audio/pcm");
|
||||||
|
@ -60,26 +84,33 @@ bool AudioOutput::start(int device, int rate)
|
||||||
qDebug("default format not supported - try to use nearest");
|
qDebug("default format not supported - try to use nearest");
|
||||||
format = devInfo.nearestFormat(format);
|
format = devInfo.nearestFormat(format);
|
||||||
}
|
}
|
||||||
|
qDebug("Audio output %s using samplerate %d", qPrintable(devInfo.deviceName()), format.sampleRate());
|
||||||
|
|
||||||
if(format.sampleSize() != 16) {
|
if(format.sampleSize() != 16) {
|
||||||
qDebug("audio device doesn't support 16 bit samples (%s)", qPrintable(devInfo.defaultOutputDevice().deviceName()));
|
m_error = tr("Audio output %1 doesn't support 16 bit samples").arg(devInfo.deviceName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_audioOutput = new QAudioOutput(format);
|
m_audioOutput = new QAudioOutput(devInfo, format);
|
||||||
|
|
||||||
QIODevice::open(QIODevice::ReadOnly);
|
QIODevice::open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
//m_audioOutput->setBufferSize(3 * 4096);
|
||||||
m_audioOutput->start(this);
|
m_audioOutput->start(this);
|
||||||
|
|
||||||
return true;
|
for(AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
|
||||||
|
(*it)->setSampleRate(m_audioOutput->format().sampleRate());
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioOutput::stop()
|
void AudioOutput::stop()
|
||||||
{
|
{
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
|
for(AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
|
||||||
|
(*it)->setSampleRate(0);
|
||||||
|
|
||||||
if(m_audioOutput != NULL) {
|
if(m_audioOutput != NULL) {
|
||||||
m_audioOutput->stop();
|
m_audioOutput->stop();
|
||||||
delete m_audioOutput;
|
delete m_audioOutput;
|
||||||
|
@ -92,6 +123,10 @@ void AudioOutput::addFifo(AudioFifo* audioFifo)
|
||||||
{
|
{
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
|
if(m_audioOutput == NULL)
|
||||||
|
audioFifo->setSampleRate(0);
|
||||||
|
else audioFifo->setSampleRate(m_audioOutput->format().sampleRate());
|
||||||
|
|
||||||
m_audioFifos.push_back(audioFifo);
|
m_audioFifos.push_back(audioFifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,9 +134,19 @@ void AudioOutput::removeFifo(AudioFifo* audioFifo)
|
||||||
{
|
{
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
|
audioFifo->setSampleRate(0);
|
||||||
m_audioFifos.remove(audioFifo);
|
m_audioFifos.remove(audioFifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint32 AudioOutput::getCurrentRate()
|
||||||
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
|
if(m_audioOutput == NULL)
|
||||||
|
return 0;
|
||||||
|
else return m_audioOutput->format().sampleRate();
|
||||||
|
}
|
||||||
|
|
||||||
bool AudioOutput::open(OpenMode mode)
|
bool AudioOutput::open(OpenMode mode)
|
||||||
{
|
{
|
||||||
Q_UNUSED(mode);
|
Q_UNUSED(mode);
|
||||||
|
@ -110,9 +155,6 @@ bool AudioOutput::open(OpenMode mode)
|
||||||
|
|
||||||
qint64 AudioOutput::readData(char* data, qint64 maxLen)
|
qint64 AudioOutput::readData(char* data, qint64 maxLen)
|
||||||
{
|
{
|
||||||
if(maxLen == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
maxLen -= maxLen % 4;
|
maxLen -= maxLen % 4;
|
||||||
|
@ -120,13 +162,18 @@ qint64 AudioOutput::readData(char* data, qint64 maxLen)
|
||||||
|
|
||||||
if((int)m_mixBuffer.size() < framesPerBuffer * 2) {
|
if((int)m_mixBuffer.size() < framesPerBuffer * 2) {
|
||||||
m_mixBuffer.resize(framesPerBuffer * 2); // allocate 2 qint32 per frame (stereo)
|
m_mixBuffer.resize(framesPerBuffer * 2); // allocate 2 qint32 per frame (stereo)
|
||||||
if(m_mixBuffer.size() != framesPerBuffer * 2)
|
if(m_mixBuffer.size() != framesPerBuffer * 2) {
|
||||||
|
qDebug("KAPUTT");
|
||||||
return 0;
|
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) {
|
||||||
|
if((*it)->isStopped())
|
||||||
|
continue;
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -141,7 +188,7 @@ qint64 AudioOutput::readData(char* data, qint64 maxLen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert to int16
|
// convert to int16 and do saturation
|
||||||
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(int i = 0; i < framesPerBuffer; ++i) {
|
for(int i = 0; i < framesPerBuffer; ++i) {
|
||||||
|
|
|
@ -27,13 +27,15 @@ void Channelizer::feed(SampleVector::const_iterator begin, SampleVector::const_i
|
||||||
{
|
{
|
||||||
for(SampleVector::const_iterator sample = begin; sample != end; ++sample) {
|
for(SampleVector::const_iterator sample = begin; sample != end; ++sample) {
|
||||||
Sample s(*sample);
|
Sample s(*sample);
|
||||||
|
bool haveSample = true;
|
||||||
FilterStages::iterator stage = m_filterStages.begin();
|
FilterStages::iterator stage = m_filterStages.begin();
|
||||||
while(stage != m_filterStages.end()) {
|
while(stage != m_filterStages.end()) {
|
||||||
if(!(*stage)->work(&s))
|
haveSample = (*stage)->work(&s);
|
||||||
|
if(!haveSample)
|
||||||
break;
|
break;
|
||||||
++stage;
|
++stage;
|
||||||
}
|
}
|
||||||
if(stage == m_filterStages.end())
|
if((stage == m_filterStages.end()) && haveSample)
|
||||||
m_sampleBuffer.push_back(s);
|
m_sampleBuffer.push_back(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +60,7 @@ void Channelizer::stop()
|
||||||
bool Channelizer::handleMessage(Message* cmd)
|
bool Channelizer::handleMessage(Message* cmd)
|
||||||
{
|
{
|
||||||
if(DSPSignalNotification::match(cmd)) {
|
if(DSPSignalNotification::match(cmd)) {
|
||||||
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
|
DSPSignalNotification* signal = DSPSignalNotification::cast(cmd);
|
||||||
m_inputSampleRate = signal->getSampleRate();
|
m_inputSampleRate = signal->getSampleRate();
|
||||||
applyConfiguration();
|
applyConfiguration();
|
||||||
cmd->completed();
|
cmd->completed();
|
||||||
|
@ -69,7 +71,7 @@ bool Channelizer::handleMessage(Message* cmd)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if(DSPConfigureChannelizer::match(cmd)) {
|
} else if(DSPConfigureChannelizer::match(cmd)) {
|
||||||
DSPConfigureChannelizer* chan = (DSPConfigureChannelizer*)cmd;
|
DSPConfigureChannelizer* chan = DSPConfigureChannelizer::cast(cmd);
|
||||||
m_requestedOutputSampleRate = chan->getSampleRate();
|
m_requestedOutputSampleRate = chan->getSampleRate();
|
||||||
m_requestedCenterFrequency = chan->getCenterFrequency();
|
m_requestedCenterFrequency = chan->getCenterFrequency();
|
||||||
applyConfiguration();
|
applyConfiguration();
|
||||||
|
@ -172,157 +174,3 @@ void Channelizer::freeFilterChain()
|
||||||
delete *it;
|
delete *it;
|
||||||
m_filterStages.clear();
|
m_filterStages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
|
||||||
// written by Christian Daniel //
|
|
||||||
// //
|
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
|
||||||
// it under the terms of the GNU General Public License as published by //
|
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
|
||||||
// //
|
|
||||||
// This program is distributed in the hope that it will be useful, //
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
||||||
// GNU General Public License V3 for more details. //
|
|
||||||
// //
|
|
||||||
// You should have received a copy of the GNU General Public License //
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include <QTime>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "channelizer.h"
|
|
||||||
#include "hardware/audiooutput.h"
|
|
||||||
|
|
||||||
Channelizer::Channelizer()
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
m_spectrum.configure(128 , 25, FFTWindow::Bartlett);
|
|
||||||
m_buffer.resize(2048);
|
|
||||||
m_bufferFill = 0;
|
|
||||||
m_nco.setFreq(-100000, 500000);
|
|
||||||
m_interpolator.create(51, 32, 32 * 500000, 150000 / 2);
|
|
||||||
m_distance = 500000.0 / 176400.0;
|
|
||||||
|
|
||||||
m_interpolator2.create(19, 8, 8 * 176400, 15000 / 2);
|
|
||||||
m_distance2 = 4;
|
|
||||||
|
|
||||||
m_audioFifo.setSize(4, 44100 / 2 * 4);
|
|
||||||
m_audioOutput = new AudioOutput;
|
|
||||||
m_audioOutput->start(0, 44100, &m_audioFifo);
|
|
||||||
m_resampler = 1.0;
|
|
||||||
|
|
||||||
m_resamplerCtrl.setup(0.00001, 0, -0.00001);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Channelizer::~Channelizer()
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
m_audioOutput->stop();
|
|
||||||
delete m_audioOutput;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void Channelizer::setGLSpectrum(GLSpectrum* glSpectrum)
|
|
||||||
{
|
|
||||||
m_spectrum.setGLSpectrum(glSpectrum);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t Channelizer::workUnitSize()
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
return m_buffer.size();
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Channelizer::work(SampleVector::const_iterator begin, SampleVector::const_iterator end)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
int buffered = m_audioOutput->bufferedSamples();
|
|
||||||
|
|
||||||
if(m_audioFifo.fill() < (m_audioFifo.size() / 6)) {
|
|
||||||
while(m_audioFifo.fill() < (m_audioFifo.size() / 2)) {
|
|
||||||
quint32 d = 0;
|
|
||||||
m_audioFifo.write((quint8*)&d, 4);
|
|
||||||
}
|
|
||||||
qDebug("underflow - fill %d (vs %d)", m_audioFifo.fill(), m_audioFifo.size() / 4 / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffered = m_audioOutput->bufferedSamples();
|
|
||||||
int fill = m_audioFifo.fill() / 4 + buffered;
|
|
||||||
float err = (float)fill / ((m_audioFifo.size() / 4) / 2);
|
|
||||||
|
|
||||||
float ctrl = m_resamplerCtrl.feed(err);
|
|
||||||
//float resamplerRate = (ctrl / 1.0);
|
|
||||||
float resamplerRate = err;
|
|
||||||
|
|
||||||
if(resamplerRate < 0.9999)
|
|
||||||
resamplerRate = 0.9999;
|
|
||||||
else if(resamplerRate > 1.0001)
|
|
||||||
resamplerRate = 1.0001;
|
|
||||||
m_resampler = m_resampler * 0.99 + resamplerRate * 0.01;
|
|
||||||
//m_resampler = resamplerRate;
|
|
||||||
|
|
||||||
if(m_resampler < 0.995)
|
|
||||||
m_resampler = 0.995;
|
|
||||||
else if(m_resampler > 1.005)
|
|
||||||
m_resampler = 1.005;
|
|
||||||
|
|
||||||
//qDebug("%lld %5d %f %f %f", QDateTime::currentMSecsSinceEpoch(), fill, ctrl, m_resampler, err);
|
|
||||||
|
|
||||||
struct AudioSample {
|
|
||||||
qint16 l;
|
|
||||||
qint16 r;
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t count = end - begin;
|
|
||||||
Complex ci;
|
|
||||||
bool consumed;
|
|
||||||
bool consumed2;
|
|
||||||
|
|
||||||
for(SampleVector::const_iterator it = begin; it < end; it++) {
|
|
||||||
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
|
|
||||||
c *= m_nco.nextIQ();
|
|
||||||
|
|
||||||
consumed = false;
|
|
||||||
if(m_interpolator.interpolate(&m_distance, c, &consumed, &ci)) {
|
|
||||||
|
|
||||||
Complex d = ci * conj(m_lastSample);
|
|
||||||
m_lastSample = ci;
|
|
||||||
//Complex demod(atan2(d.imag(), d.real()) * 0.5, 0);
|
|
||||||
Real demod = atan2(d.imag(), d.real()) / M_PI;
|
|
||||||
|
|
||||||
consumed2 = false;
|
|
||||||
c = Complex(demod, 0);
|
|
||||||
while(!consumed2) {
|
|
||||||
if(m_interpolator2.interpolate(&m_distance2, c, &consumed2, &ci)) {
|
|
||||||
m_buffer[m_bufferFill++] = Sample(ci.real() * 32767.0, 0.0);
|
|
||||||
|
|
||||||
AudioSample s;
|
|
||||||
s.l = ci.real() * 32767.0;
|
|
||||||
s.r = s.l;
|
|
||||||
m_audioFifo.write((quint8*)&s, 4, 1);
|
|
||||||
|
|
||||||
if(m_bufferFill >= m_buffer.size()) {
|
|
||||||
m_spectrum.feed(m_buffer.begin(), m_buffer.end());
|
|
||||||
m_bufferFill = 0;
|
|
||||||
}
|
|
||||||
m_distance2 += 4.0 * m_resampler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_distance += 500000 / 176400.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ MESSAGE_CLASS_DEFINITION(DSPAddAudioSource, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(DSPRemoveAudioSource, Message)
|
MESSAGE_CLASS_DEFINITION(DSPRemoveAudioSource, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(DSPConfigureSpectrumVis, Message)
|
MESSAGE_CLASS_DEFINITION(DSPConfigureSpectrumVis, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(DSPConfigureCorrection, Message)
|
MESSAGE_CLASS_DEFINITION(DSPConfigureCorrection, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DSPConfigureAudioOutput, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(DSPEngineReport, Message)
|
MESSAGE_CLASS_DEFINITION(DSPEngineReport, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(DSPConfigureScopeVis, Message)
|
MESSAGE_CLASS_DEFINITION(DSPConfigureScopeVis, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(DSPSignalNotification, Message)
|
MESSAGE_CLASS_DEFINITION(DSPSignalNotification, Message)
|
||||||
|
|
|
@ -109,6 +109,12 @@ void DSPEngine::configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCo
|
||||||
cmd->submit(&m_messageQueue);
|
cmd->submit(&m_messageQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSPEngine::configureAudioOutput(const QString& audioOutput, quint32 audioOutputRate)
|
||||||
|
{
|
||||||
|
Message* cmd = DSPConfigureAudioOutput::create(audioOutput, audioOutputRate);
|
||||||
|
cmd->submit(&m_messageQueue);
|
||||||
|
}
|
||||||
|
|
||||||
QString DSPEngine::errorMessage()
|
QString DSPEngine::errorMessage()
|
||||||
{
|
{
|
||||||
DSPGetErrorMessage cmd;
|
DSPGetErrorMessage cmd;
|
||||||
|
@ -174,7 +180,6 @@ void DSPEngine::imbalance(SampleVector::iterator begin, SampleVector::iterator e
|
||||||
qMin = it->imag();
|
qMin = it->imag();
|
||||||
else if(it->imag() > qMax)
|
else if(it->imag() > qMax)
|
||||||
qMax = it->imag();
|
qMax = it->imag();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
iMin = it->real();
|
iMin = it->real();
|
||||||
iMax = it->real();
|
iMax = it->real();
|
||||||
|
@ -202,7 +207,7 @@ void DSPEngine::work()
|
||||||
size_t samplesDone = 0;
|
size_t samplesDone = 0;
|
||||||
bool firstOfBurst = true;
|
bool firstOfBurst = true;
|
||||||
|
|
||||||
while((sampleFifo->fill() > 0) && (m_messageQueue.countPending() == 0) && (samplesDone < m_sampleRate)) {
|
while((sampleFifo->fill() > 0) && (m_messageQueue.countPending() == 0) && (samplesDone < m_sampleRate / 2)) {
|
||||||
SampleVector::iterator part1begin;
|
SampleVector::iterator part1begin;
|
||||||
SampleVector::iterator part1end;
|
SampleVector::iterator part1end;
|
||||||
SampleVector::iterator part2begin;
|
SampleVector::iterator part2begin;
|
||||||
|
@ -218,7 +223,7 @@ void DSPEngine::work()
|
||||||
if(m_iqImbalanceCorrection)
|
if(m_iqImbalanceCorrection)
|
||||||
imbalance(part1begin, part1end);
|
imbalance(part1begin, part1end);
|
||||||
// feed data to handlers
|
// feed data to handlers
|
||||||
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, firstOfBurst);
|
(*it)->feed(part1begin, part1end, firstOfBurst);
|
||||||
firstOfBurst = false;
|
firstOfBurst = false;
|
||||||
}
|
}
|
||||||
|
@ -230,7 +235,7 @@ void DSPEngine::work()
|
||||||
if(m_iqImbalanceCorrection)
|
if(m_iqImbalanceCorrection)
|
||||||
imbalance(part2begin, part2end);
|
imbalance(part2begin, part2end);
|
||||||
// feed data to handlers
|
// feed data to handlers
|
||||||
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, firstOfBurst);
|
(*it)->feed(part2begin, part2end, firstOfBurst);
|
||||||
firstOfBurst = false;
|
firstOfBurst = false;
|
||||||
}
|
}
|
||||||
|
@ -239,69 +244,6 @@ void DSPEngine::work()
|
||||||
sampleFifo->readCommit(count);
|
sampleFifo->readCommit(count);
|
||||||
samplesDone += count;
|
samplesDone += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
size_t wus;
|
|
||||||
size_t maxWorkUnitSize = 0;
|
|
||||||
size_t samplesDone = 0;
|
|
||||||
|
|
||||||
wus = m_spectrum.workUnitSize();
|
|
||||||
if(wus > maxWorkUnitSize)
|
|
||||||
maxWorkUnitSize = wus;
|
|
||||||
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) {
|
|
||||||
wus = (*it)->workUnitSize();
|
|
||||||
if(wus > maxWorkUnitSize)
|
|
||||||
maxWorkUnitSize = wus;
|
|
||||||
}
|
|
||||||
|
|
||||||
while((m_sampleFifo.fill() > maxWorkUnitSize) && (m_commandQueue.countPending() == 0) && (samplesDone < m_sampleRate)) {
|
|
||||||
SampleVector::iterator part1begin;
|
|
||||||
SampleVector::iterator part1end;
|
|
||||||
SampleVector::iterator part2begin;
|
|
||||||
SampleVector::iterator part2end;
|
|
||||||
|
|
||||||
size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end);
|
|
||||||
|
|
||||||
// first part of FIFO data
|
|
||||||
if(part1begin != part1end) {
|
|
||||||
// correct stuff
|
|
||||||
if(m_settings.dcOffsetCorrection())
|
|
||||||
dcOffset(part1begin, part1end);
|
|
||||||
if(m_settings.iqImbalanceCorrection())
|
|
||||||
imbalance(part1begin, part1end);
|
|
||||||
// feed data to handlers
|
|
||||||
m_spectrum.feed(part1begin, part1end);
|
|
||||||
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++)
|
|
||||||
(*it)->feed(part1begin, part1end);
|
|
||||||
}
|
|
||||||
// second part of FIFO data (used when block wraps around)
|
|
||||||
if(part2begin != part2end) {
|
|
||||||
// correct stuff
|
|
||||||
if(m_settings.dcOffsetCorrection())
|
|
||||||
dcOffset(part2begin, part2end);
|
|
||||||
if(m_settings.iqImbalanceCorrection())
|
|
||||||
imbalance(part2begin, part2end);
|
|
||||||
// feed data to handlers
|
|
||||||
m_spectrum.feed(part2begin, part2end);
|
|
||||||
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++)
|
|
||||||
(*it)->feed(part1begin, part1end);
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust FIFO pointers
|
|
||||||
m_sampleFifo.readCommit(count);
|
|
||||||
samplesDone += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the center frequency has changed (has to be responsive)
|
|
||||||
if(m_settings.isModifiedCenterFreq())
|
|
||||||
m_sampleSource->setCenterFrequency(m_settings.centerFreq());
|
|
||||||
// check if decimation has changed (needed to be done here, because to high a sample rate can clog the switch)
|
|
||||||
if(m_settings.isModifiedDecimation()) {
|
|
||||||
m_sampleSource->setDecimation(m_settings.decimation());
|
|
||||||
m_sampleRate = 4000000 / (1 << m_settings.decimation());
|
|
||||||
qDebug("New rate: %d", m_sampleRate);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DSPEngine::State DSPEngine::gotoIdle()
|
DSPEngine::State DSPEngine::gotoIdle()
|
||||||
|
@ -357,7 +299,11 @@ DSPEngine::State DSPEngine::gotoRunning()
|
||||||
return gotoError("Could not start sample source");
|
return gotoError("Could not start sample source");
|
||||||
m_deviceDescription = m_sampleSource->getDeviceDescription();
|
m_deviceDescription = m_sampleSource->getDeviceDescription();
|
||||||
|
|
||||||
m_audioOutput.start(0, 44100);
|
if(!m_audioOutput.start()) {
|
||||||
|
m_sampleSource->stopInput();
|
||||||
|
return gotoError(m_audioOutput.getError());
|
||||||
|
}
|
||||||
|
|
||||||
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)->start();
|
(*it)->start();
|
||||||
m_sampleRate = 0; // make sure, report is sent
|
m_sampleRate = 0; // make sure, report is sent
|
||||||
|
@ -447,7 +393,7 @@ void DSPEngine::handleMessages()
|
||||||
{
|
{
|
||||||
Message* message;
|
Message* message;
|
||||||
while((message = m_messageQueue.accept()) != NULL) {
|
while((message = m_messageQueue.accept()) != NULL) {
|
||||||
qDebug("Message: %s", message->getIdentifier());
|
//qDebug("Message: %s", message->getIdentifier());
|
||||||
|
|
||||||
if(DSPPing::match(message)) {
|
if(DSPPing::match(message)) {
|
||||||
message->completed(m_state);
|
message->completed(m_state);
|
||||||
|
@ -465,16 +411,16 @@ void DSPEngine::handleMessages()
|
||||||
m_state = gotoIdle();
|
m_state = gotoIdle();
|
||||||
message->completed(m_state);
|
message->completed(m_state);
|
||||||
} else if(DSPGetDeviceDescription::match(message)) {
|
} else if(DSPGetDeviceDescription::match(message)) {
|
||||||
((DSPGetDeviceDescription*)message)->setDeviceDescription(m_deviceDescription);
|
DSPGetDeviceDescription::cast(message)->setDeviceDescription(m_deviceDescription);
|
||||||
message->completed();
|
message->completed();
|
||||||
} else if(DSPGetErrorMessage::match(message)) {
|
} else if(DSPGetErrorMessage::match(message)) {
|
||||||
((DSPGetErrorMessage*)message)->setErrorMessage(m_errorMessage);
|
((DSPGetErrorMessage*)message)->setErrorMessage(m_errorMessage);
|
||||||
message->completed();
|
message->completed();
|
||||||
} else if(DSPSetSource::match(message)) {
|
} else if(DSPSetSource::match(message)) {
|
||||||
handleSetSource(((DSPSetSource*)message)->getSampleSource());
|
handleSetSource(DSPSetSource::cast(message)->getSampleSource());
|
||||||
message->completed();
|
message->completed();
|
||||||
} else if(DSPAddSink::match(message)) {
|
} else if(DSPAddSink::match(message)) {
|
||||||
SampleSink* sink = ((DSPAddSink*)message)->getSampleSink();
|
SampleSink* sink = DSPAddSink::cast(message)->getSampleSink();
|
||||||
if(m_state == StRunning) {
|
if(m_state == StRunning) {
|
||||||
DSPSignalNotification* signal = DSPSignalNotification::create(m_sampleRate, 0);
|
DSPSignalNotification* signal = DSPSignalNotification::create(m_sampleRate, 0);
|
||||||
signal->submit(&m_messageQueue, sink);
|
signal->submit(&m_messageQueue, sink);
|
||||||
|
@ -489,13 +435,16 @@ void DSPEngine::handleMessages()
|
||||||
m_sampleSinks.remove(sink);
|
m_sampleSinks.remove(sink);
|
||||||
message->completed();
|
message->completed();
|
||||||
} else if(DSPAddAudioSource::match(message)) {
|
} else if(DSPAddAudioSource::match(message)) {
|
||||||
m_audioOutput.addFifo(((DSPAddAudioSource*)message)->getAudioFifo());
|
m_audioOutput.addFifo(DSPAddAudioSource::cast(message)->getAudioFifo());
|
||||||
message->completed();
|
message->completed();
|
||||||
} else if(DSPRemoveAudioSource::match(message)) {
|
} else if(DSPRemoveAudioSource::match(message)) {
|
||||||
m_audioOutput.removeFifo(((DSPAddAudioSource*)message)->getAudioFifo());
|
m_audioOutput.removeFifo(((DSPAddAudioSource*)message)->getAudioFifo());
|
||||||
message->completed();
|
message->completed();
|
||||||
|
} else if(DSPConfigureAudioOutput::match(message)) {
|
||||||
|
DSPConfigureAudioOutput* conf = DSPConfigureAudioOutput::cast(message);
|
||||||
|
m_audioOutput.configure(conf->getAudioOutputDevice(), conf->getAudioOutputRate());
|
||||||
} else if(DSPConfigureCorrection::match(message)) {
|
} else if(DSPConfigureCorrection::match(message)) {
|
||||||
DSPConfigureCorrection* conf = (DSPConfigureCorrection*)message;
|
DSPConfigureCorrection* conf = DSPConfigureCorrection::cast(message);
|
||||||
m_iqImbalanceCorrection = conf->getIQImbalanceCorrection();
|
m_iqImbalanceCorrection = conf->getIQImbalanceCorrection();
|
||||||
if(m_dcOffsetCorrection != conf->getDCOffsetCorrection()) {
|
if(m_dcOffsetCorrection != conf->getDCOffsetCorrection()) {
|
||||||
m_dcOffsetCorrection = conf->getDCOffsetCorrection();
|
m_dcOffsetCorrection = conf->getDCOffsetCorrection();
|
||||||
|
|
|
@ -21,6 +21,7 @@ void FFTWEngine::configure(int n, bool inverse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_globalPlanMutex.lock();
|
||||||
m_currentPlan = new Plan;
|
m_currentPlan = new Plan;
|
||||||
m_currentPlan->n = n;
|
m_currentPlan->n = n;
|
||||||
m_currentPlan->inverse = inverse;
|
m_currentPlan->inverse = inverse;
|
||||||
|
@ -28,7 +29,6 @@ void FFTWEngine::configure(int n, bool inverse)
|
||||||
m_currentPlan->out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * n);
|
m_currentPlan->out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * n);
|
||||||
QTime t;
|
QTime t;
|
||||||
t.start();
|
t.start();
|
||||||
m_globalPlanMutex.lock();
|
|
||||||
m_currentPlan->plan = fftwf_plan_dft_1d(n, m_currentPlan->in, m_currentPlan->out, inverse ? FFTW_BACKWARD : FFTW_FORWARD, FFTW_PATIENT);
|
m_currentPlan->plan = fftwf_plan_dft_1d(n, m_currentPlan->in, m_currentPlan->out, inverse ? FFTW_BACKWARD : FFTW_FORWARD, FFTW_PATIENT);
|
||||||
m_globalPlanMutex.unlock();
|
m_globalPlanMutex.unlock();
|
||||||
qDebug("FFT: creating FFTW plan (n=%d,%s) took %dms", n, inverse ? "inverse" : "forward", t.elapsed());
|
qDebug("FFT: creating FFTW plan (n=%d,%s) took %dms", n, inverse ? "inverse" : "forward", t.elapsed());
|
||||||
|
|
|
@ -30,7 +30,7 @@ void NCO::initTable()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for(int i = 0; i < TableSize; i++)
|
for(int i = 0; i < TableSize; i++)
|
||||||
m_table[i] = cos((2.0 * M_PI * i) / TableSize);
|
m_table[i] = cos((2.0 * M_PI * (Real)i) / ((Real)TableSize));
|
||||||
|
|
||||||
m_tableInitialized = true;
|
m_tableInitialized = true;
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,15 @@ NCO::NCO()
|
||||||
|
|
||||||
void NCO::setFreq(Real freq, Real sampleRate)
|
void NCO::setFreq(Real freq, Real sampleRate)
|
||||||
{
|
{
|
||||||
m_phaseIncrement = (freq * TableSize) / sampleRate;
|
if(sampleRate > 0) {
|
||||||
qDebug("NCO phase inc %d", m_phaseIncrement);
|
m_phaseIncrement = (freq * TableSize) / sampleRate;
|
||||||
|
if(m_phaseIncrement != 0)
|
||||||
|
qDebug("NCO phase inc %d (period %f)", m_phaseIncrement, (Real)TableSize / (Real)m_phaseIncrement);
|
||||||
|
else qDebug("NCO phase inc %d (period oo)", m_phaseIncrement);
|
||||||
|
} else {
|
||||||
|
qDebug("cannot calculate NCO phase increment since samplerate is 0");
|
||||||
|
m_phaseIncrement = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float NCO::next()
|
float NCO::next()
|
||||||
|
@ -66,5 +73,7 @@ Complex NCO::nextIQ()
|
||||||
while(m_phase < 0)
|
while(m_phase < 0)
|
||||||
m_phase += TableSize;
|
m_phase += TableSize;
|
||||||
|
|
||||||
return Complex(m_table[m_phase], -m_table[(m_phase + TableSize / 4) % TableSize]);
|
int idxQuad = (m_phase + (TableSize / 4) + (TableSize / 2)) % TableSize;
|
||||||
|
|
||||||
|
return Complex(m_table[m_phase], m_table[idxQuad]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pidcontroller.h"
|
#include "dsp/pidcontroller.h"
|
||||||
|
|
||||||
PIDController::PIDController() :
|
PIDController::PIDController() :
|
||||||
m_p(0.0),
|
m_p(0.0),
|
||||||
|
|
|
@ -64,17 +64,21 @@ bool SampleFifo::setSize(int size)
|
||||||
{
|
{
|
||||||
create(size);
|
create(size);
|
||||||
|
|
||||||
return m_data.size() == (uint)size;
|
return m_size == (uint)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint SampleFifo::write(const quint8* data, uint count)
|
uint SampleFifo::write(const quint8* data, uint count)
|
||||||
{
|
{
|
||||||
|
return write(SampleVector::const_iterator((Sample*)data), SampleVector::const_iterator((Sample*)(data + count)));
|
||||||
|
#if 0
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
uint total;
|
uint total;
|
||||||
uint remaining;
|
uint remaining;
|
||||||
uint len;
|
uint len;
|
||||||
const Sample* begin = (const Sample*)data;
|
const Sample* begin = (const Sample*)data;
|
||||||
count /= 4;
|
count /= sizeof(Sample);
|
||||||
|
|
||||||
|
//qDebug("write pre count %d %u", count, m_fill);
|
||||||
|
|
||||||
total = MIN(count, m_size - m_fill);
|
total = MIN(count, m_size - m_fill);
|
||||||
if(total < count) {
|
if(total < count) {
|
||||||
|
@ -96,6 +100,7 @@ uint SampleFifo::write(const quint8* data, uint count)
|
||||||
remaining = total;
|
remaining = total;
|
||||||
while(remaining > 0) {
|
while(remaining > 0) {
|
||||||
len = MIN(remaining, m_size - m_tail);
|
len = MIN(remaining, m_size - m_tail);
|
||||||
|
//qDebug("write remaining %u, len %u", remaining, len);
|
||||||
std::copy(begin, begin + len, m_data.begin() + m_tail);
|
std::copy(begin, begin + len, m_data.begin() + m_tail);
|
||||||
m_tail += len;
|
m_tail += len;
|
||||||
m_tail %= m_size;
|
m_tail %= m_size;
|
||||||
|
@ -104,10 +109,13 @@ uint SampleFifo::write(const quint8* data, uint count)
|
||||||
remaining -= len;
|
remaining -= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//qDebug("write post count %d %u [%u;%u]", count, m_fill, m_head, m_tail);
|
||||||
|
|
||||||
if(m_fill > 0)
|
if(m_fill > 0)
|
||||||
emit dataReady();
|
emit dataReady();
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint SampleFifo::write(SampleVector::const_iterator begin, SampleVector::const_iterator end)
|
uint SampleFifo::write(SampleVector::const_iterator begin, SampleVector::const_iterator end)
|
||||||
|
@ -139,8 +147,7 @@ uint SampleFifo::write(SampleVector::const_iterator begin, SampleVector::const_i
|
||||||
while(remaining > 0) {
|
while(remaining > 0) {
|
||||||
len = MIN(remaining, m_size - m_tail);
|
len = MIN(remaining, m_size - m_tail);
|
||||||
std::copy(begin, begin + len, m_data.begin() + m_tail);
|
std::copy(begin, begin + len, m_data.begin() + m_tail);
|
||||||
m_tail += len;
|
m_tail = (m_tail + len) % m_size;
|
||||||
m_tail %= m_size;
|
|
||||||
m_fill += len;
|
m_fill += len;
|
||||||
begin += len;
|
begin += len;
|
||||||
remaining -= len;
|
remaining -= len;
|
||||||
|
@ -151,7 +158,7 @@ uint SampleFifo::write(SampleVector::const_iterator begin, SampleVector::const_i
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
uint SampleFifo::read(SampleVector::iterator begin, SampleVector::iterator end)
|
uint SampleFifo::read(SampleVector::iterator begin, SampleVector::iterator end)
|
||||||
{
|
{
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
@ -177,13 +184,14 @@ uint SampleFifo::read(SampleVector::iterator begin, SampleVector::iterator end)
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
uint SampleFifo::readBegin(uint count,
|
uint SampleFifo::readBegin(uint count,
|
||||||
SampleVector::iterator* part1Begin, SampleVector::iterator* part1End,
|
SampleVector::iterator* part1Begin, SampleVector::iterator* part1End,
|
||||||
SampleVector::iterator* part2Begin, SampleVector::iterator* part2End)
|
SampleVector::iterator* part2Begin, SampleVector::iterator* part2End)
|
||||||
{
|
{
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
uint total;
|
uint total;
|
||||||
|
uint done = 0;
|
||||||
uint remaining;
|
uint remaining;
|
||||||
uint len;
|
uint len;
|
||||||
uint head = m_head;
|
uint head = m_head;
|
||||||
|
@ -196,10 +204,10 @@ uint SampleFifo::readBegin(uint count,
|
||||||
if(remaining > 0) {
|
if(remaining > 0) {
|
||||||
len = MIN(remaining, m_size - head);
|
len = MIN(remaining, m_size - head);
|
||||||
*part1Begin = m_data.begin() + head;
|
*part1Begin = m_data.begin() + head;
|
||||||
*part1End = m_data.begin() + head + len;
|
*part1End = *part1Begin + len;
|
||||||
head += len;
|
head = (head + len) % m_size;
|
||||||
head %= m_size;
|
|
||||||
remaining -= len;
|
remaining -= len;
|
||||||
|
done += len;
|
||||||
} else {
|
} else {
|
||||||
*part1Begin = m_data.end();
|
*part1Begin = m_data.end();
|
||||||
*part1End = m_data.end();
|
*part1End = m_data.end();
|
||||||
|
@ -207,13 +215,14 @@ uint SampleFifo::readBegin(uint count,
|
||||||
if(remaining > 0) {
|
if(remaining > 0) {
|
||||||
len = MIN(remaining, m_size - head);
|
len = MIN(remaining, m_size - head);
|
||||||
*part2Begin = m_data.begin() + head;
|
*part2Begin = m_data.begin() + head;
|
||||||
*part2End = m_data.begin() + head + len;
|
*part2End = *part2Begin + len;
|
||||||
|
done += len;
|
||||||
} else {
|
} else {
|
||||||
*part2Begin = m_data.end();
|
*part2Begin = m_data.end();
|
||||||
*part2End = m_data.end();
|
*part2End = m_data.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint SampleFifo::readCommit(uint count)
|
uint SampleFifo::readCommit(uint count)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "dsp/dspcommands.h"
|
#include "dsp/dspcommands.h"
|
||||||
#include "util/messagequeue.h"
|
#include "util/messagequeue.h"
|
||||||
|
|
||||||
#define MAX_FFT_SIZE 4096
|
#define MAX_FFT_SIZE 8192
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
double log2f(double n)
|
double log2f(double n)
|
||||||
|
|
|
@ -15,7 +15,7 @@ ThreadedSampleSink::ThreadedSampleSink(SampleSink* sampleSink) :
|
||||||
|
|
||||||
m_sampleFifo.moveToThread(m_thread);
|
m_sampleFifo.moveToThread(m_thread);
|
||||||
connect(&m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleData()));
|
connect(&m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleData()));
|
||||||
m_sampleFifo.setSize(262144);
|
m_sampleFifo.setSize(128 * 1024);
|
||||||
|
|
||||||
sampleSink->moveToThread(m_thread);
|
sampleSink->moveToThread(m_thread);
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,11 @@ bool ThreadedSampleSink::handleMessage(Message* cmd)
|
||||||
void ThreadedSampleSink::handleData()
|
void ThreadedSampleSink::handleData()
|
||||||
{
|
{
|
||||||
bool firstOfBurst = true;
|
bool firstOfBurst = true;
|
||||||
|
QTime time;
|
||||||
|
|
||||||
while((m_sampleFifo.fill() > 0) && (m_messageQueue.countPending() == 0)) {
|
time.start();
|
||||||
|
|
||||||
|
while((m_sampleFifo.fill() > 0) && (m_messageQueue.countPending() == 0) && (time.elapsed() < 250)) {
|
||||||
SampleVector::iterator part1begin;
|
SampleVector::iterator part1begin;
|
||||||
SampleVector::iterator part1end;
|
SampleVector::iterator part1end;
|
||||||
SampleVector::iterator part2begin;
|
SampleVector::iterator part2begin;
|
||||||
|
@ -64,19 +67,19 @@ void ThreadedSampleSink::handleData()
|
||||||
|
|
||||||
size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end);
|
size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end);
|
||||||
|
|
||||||
// first part of FIFO data
|
if(m_sampleSink != NULL) {
|
||||||
if(part1begin != part1end) {
|
// first part of FIFO data
|
||||||
// handle data
|
if(part1begin != part1end) {
|
||||||
if(m_sampleSink != NULL)
|
// handle data
|
||||||
m_sampleSink->feed(part1begin, part1end, firstOfBurst);
|
m_sampleSink->feed(part1begin, part1end, firstOfBurst);
|
||||||
firstOfBurst = false;
|
firstOfBurst = false;
|
||||||
}
|
}
|
||||||
// second part of FIFO data (used when block wraps around)
|
// second part of FIFO data (used when block wraps around)
|
||||||
if(part2begin != part2end) {
|
if(part2begin != part2end) {
|
||||||
// handle data
|
// handle data
|
||||||
if(m_sampleSink != NULL)
|
m_sampleSink->feed(part2begin, part2end, firstOfBurst);
|
||||||
m_sampleSink->feed(part1begin, part1end, firstOfBurst);
|
firstOfBurst = false;
|
||||||
firstOfBurst = false;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust FIFO pointers
|
// adjust FIFO pointers
|
||||||
|
@ -88,7 +91,7 @@ void ThreadedSampleSink::handleMessages()
|
||||||
{
|
{
|
||||||
Message* message;
|
Message* message;
|
||||||
while((message = m_messageQueue.accept()) != NULL) {
|
while((message = m_messageQueue.accept()) != NULL) {
|
||||||
qDebug("CMD: %s", message->getIdentifier());
|
//qDebug("CMD: %s", message->getIdentifier());
|
||||||
if(m_sampleSink != NULL) {
|
if(m_sampleSink != NULL) {
|
||||||
if(!m_sampleSink->handleMessage(message))
|
if(!m_sampleSink->handleMessage(message))
|
||||||
message->completed();
|
message->completed();
|
||||||
|
|
|
@ -112,7 +112,7 @@ bool GLSpectrumGUI::deserialize(const QByteArray& data)
|
||||||
void GLSpectrumGUI::applySettings()
|
void GLSpectrumGUI::applySettings()
|
||||||
{
|
{
|
||||||
ui->fftWindow->setCurrentIndex(m_fftWindow);
|
ui->fftWindow->setCurrentIndex(m_fftWindow);
|
||||||
for(int i = 0; i < 6; i++) {
|
for(int i = 0; i < 7; i++) {
|
||||||
if(m_fftSize == (1 << (i + 7))) {
|
if(m_fftSize == (1 << (i + 7))) {
|
||||||
ui->fftSize->setCurrentIndex(i);
|
ui->fftSize->setCurrentIndex(i);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -14,7 +14,16 @@
|
||||||
<string>Oscilloscope</string>
|
<string>Oscilloscope</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout" columnstretch="1,1,1,1">
|
<layout class="QGridLayout" name="gridLayout" columnstretch="1,1,1,1">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>2</number>
|
<number>2</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
|
@ -162,6 +171,11 @@
|
||||||
<string>4096</string>
|
<string>4096</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>8192</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="2">
|
<item row="1" column="2">
|
||||||
|
|
|
@ -1,47 +1,61 @@
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
|
#include <QAudioDeviceInfo>
|
||||||
#include "gui/preferencesdialog.h"
|
#include "gui/preferencesdialog.h"
|
||||||
#include "ui_preferencesdialog.h"
|
#include "ui_preferencesdialog.h"
|
||||||
#include "audio/audiodeviceinfo.h"
|
#include "settings/preferences.h"
|
||||||
|
|
||||||
PreferencesDialog::PreferencesDialog(AudioDeviceInfo* audioDeviceInfo, QWidget* parent) :
|
PreferencesDialog::PreferencesDialog(Preferences* preferences, QWidget* parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::PreferencesDialog),
|
ui(new Ui::PreferencesDialog),
|
||||||
m_audioDeviceInfo(audioDeviceInfo)
|
m_preferences(preferences)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
const AudioDeviceInfo::Devices& devices = audioDeviceInfo->getDevices();
|
|
||||||
|
|
||||||
QTreeWidgetItem* api;
|
|
||||||
QStringList sl;
|
QStringList sl;
|
||||||
sl.append(tr("Default (use first suitable device)"));
|
bool found;
|
||||||
api = new QTreeWidgetItem(ui->audioTree, sl, ATDefault);
|
|
||||||
api->setFirstColumnSpanned(true);
|
QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
|
||||||
for(AudioDeviceInfo::Devices::const_iterator it = devices.begin(); it != devices.end(); ++it) {
|
|
||||||
int apiIndex;
|
sl.clear();
|
||||||
|
sl.append(tr("Default output device (use first suitable)"));
|
||||||
|
QTreeWidgetItem* dev = new QTreeWidgetItem(ui->audioTree, sl);
|
||||||
|
dev->setFirstColumnSpanned(true);
|
||||||
|
dev->setData(0, Qt::UserRole, "");
|
||||||
|
for(QList<QAudioDeviceInfo>::ConstIterator it = devices.begin(); it != devices.end(); ++it) {
|
||||||
sl.clear();
|
sl.clear();
|
||||||
|
sl.append(it->deviceName());
|
||||||
for(apiIndex = 0; apiIndex < ui->audioTree->topLevelItemCount(); ++apiIndex) {
|
QTreeWidgetItem* dev = new QTreeWidgetItem(ui->audioTree, sl);
|
||||||
if(ui->audioTree->topLevelItem(apiIndex)->text(0) == it->api)
|
dev->setFirstColumnSpanned(true);
|
||||||
break;
|
dev->setData(0, Qt::UserRole, it->deviceName());
|
||||||
}
|
|
||||||
if(apiIndex >= ui->audioTree->topLevelItemCount()) {
|
|
||||||
sl.append(it->api);
|
|
||||||
api = new QTreeWidgetItem(ui->audioTree, sl, ATInterface);
|
|
||||||
api->setExpanded(true);
|
|
||||||
api->setFirstColumnSpanned(true);
|
|
||||||
sl.clear();
|
|
||||||
} else {
|
|
||||||
api = ui->audioTree->topLevelItem(apiIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
sl.append(it->name);
|
|
||||||
new QTreeWidgetItem(api, sl, ATDevice);
|
|
||||||
}
|
}
|
||||||
if(ui->audioTree->currentItem() == NULL)
|
found = false;
|
||||||
|
for(int i = 0; i < ui->audioTree->topLevelItemCount(); ++i) {
|
||||||
|
if(ui->audioTree->topLevelItem(i)->data(0, Qt::UserRole).toString() == m_preferences->getAudioOutput()) {
|
||||||
|
ui->audioTree->setCurrentItem(ui->audioTree->topLevelItem(i));
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
ui->audioTree->setCurrentItem(ui->audioTree->topLevelItem(0));
|
ui->audioTree->setCurrentItem(ui->audioTree->topLevelItem(0));
|
||||||
|
|
||||||
ui->tabWidget->setCurrentIndex(0);
|
ui->audioRate->addItem(tr("48000 Hz"), 48000);
|
||||||
|
ui->audioRate->addItem(tr("44100 Hz"), 44100);
|
||||||
|
ui->audioRate->addItem(tr("24000 Hz"), 24000);
|
||||||
|
ui->audioRate->addItem(tr("22050 Hz"), 22050);
|
||||||
|
found = false;
|
||||||
|
for(int i = 0; i < ui->audioRate->count(); ++i) {
|
||||||
|
if(ui->audioRate->itemData(i).toInt() == m_preferences->getAudioOutputRate()) {
|
||||||
|
ui->audioRate->setCurrentIndex(i);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
|
ui->audioRate->setCurrentIndex(1);
|
||||||
|
|
||||||
|
ui->stackedWidget->setCurrentIndex(0);
|
||||||
|
ui->configTree->setCurrentItem(ui->configTree->topLevelItem(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferencesDialog::~PreferencesDialog()
|
PreferencesDialog::~PreferencesDialog()
|
||||||
|
@ -51,5 +65,10 @@ PreferencesDialog::~PreferencesDialog()
|
||||||
|
|
||||||
void PreferencesDialog::accept()
|
void PreferencesDialog::accept()
|
||||||
{
|
{
|
||||||
|
if(ui->audioTree->currentItem() != NULL)
|
||||||
|
m_preferences->setAudioOutput(ui->audioTree->currentItem()->data(0, Qt::UserRole).toString());
|
||||||
|
else m_preferences->setAudioOutput(QString());
|
||||||
|
m_preferences->setAudioOutputRate(ui->audioRate->itemData(ui->audioRate->currentIndex()).toInt());
|
||||||
|
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,42 +6,55 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>454</width>
|
||||||
<height>300</height>
|
<height>435</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Dialog</string>
|
<string>Dialog</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QGridLayout" name="gridLayout" columnstretch="1,3">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTreeWidget" name="configTree">
|
||||||
<property name="currentIndex">
|
<property name="rootIsDecorated">
|
||||||
<number>0</number>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="tab">
|
<attribute name="headerVisible">
|
||||||
<attribute name="title">
|
<bool>false</bool>
|
||||||
<string>Receiver Hardware</string>
|
</attribute>
|
||||||
</attribute>
|
<column>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<property name="text">
|
||||||
<item>
|
<string notr="true">Section</string>
|
||||||
<widget class="QTreeWidget" name="treeWidget">
|
</property>
|
||||||
<column>
|
</column>
|
||||||
<property name="text">
|
<item>
|
||||||
<string notr="true">1</string>
|
<property name="text">
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="tab_2">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Audio Output</string>
|
<string>Audio Output</string>
|
||||||
</attribute>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<property name="flags">
|
||||||
|
<set>ItemIsSelectable|ItemIsEnabled</set>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QStackedWidget" name="stackedWidget">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="page">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTreeWidget" name="audioTree">
|
<widget class="QTreeWidget" name="audioTree">
|
||||||
|
<property name="rootIsDecorated">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<column>
|
<column>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">Device</string>
|
<string notr="true">Device</string>
|
||||||
|
@ -49,11 +62,49 @@
|
||||||
</column>
|
</column>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sample rate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="audioRate">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="page_2"/>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="0" colspan="2">
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
|
@ -67,9 +118,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>buttonBox</tabstop>
|
<tabstop>buttonBox</tabstop>
|
||||||
<tabstop>tabWidget</tabstop>
|
|
||||||
<tabstop>treeWidget</tabstop>
|
|
||||||
<tabstop>audioTree</tabstop>
|
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
|
|
|
@ -19,14 +19,13 @@
|
||||||
#include "ui_scopewindow.h"
|
#include "ui_scopewindow.h"
|
||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
|
|
||||||
ScopeWindow::ScopeWindow(DSPEngine* dspEngine, QWidget* parent) :
|
ScopeWindow::ScopeWindow(QWidget* parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
ui(new Ui::ScopeWindow),
|
ui(new Ui::ScopeWindow),
|
||||||
m_sampleRate(0),
|
m_sampleRate(0),
|
||||||
m_timeBase(1)
|
m_timeBase(1)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->scope->setDSPEngine(dspEngine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeWindow::~ScopeWindow()
|
ScopeWindow::~ScopeWindow()
|
||||||
|
@ -34,6 +33,11 @@ ScopeWindow::~ScopeWindow()
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScopeWindow::setDSPEngine(DSPEngine* dspEngine)
|
||||||
|
{
|
||||||
|
ui->scope->setDSPEngine(dspEngine);
|
||||||
|
}
|
||||||
|
|
||||||
void ScopeWindow::setSampleRate(int sampleRate)
|
void ScopeWindow::setSampleRate(int sampleRate)
|
||||||
{
|
{
|
||||||
m_sampleRate = sampleRate;
|
m_sampleRate = sampleRate;
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "audio/audiodeviceinfo.h"
|
|
||||||
#include "gui/indicator.h"
|
#include "gui/indicator.h"
|
||||||
#include "gui/presetitem.h"
|
#include "gui/presetitem.h"
|
||||||
#include "gui/scopewindow.h"
|
#include "gui/scopewindow.h"
|
||||||
|
@ -39,7 +38,6 @@
|
||||||
MainWindow::MainWindow(QWidget* parent) :
|
MainWindow::MainWindow(QWidget* parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
ui(new Ui::MainWindow),
|
ui(new Ui::MainWindow),
|
||||||
m_audioDeviceInfo(new AudioDeviceInfo),
|
|
||||||
m_messageQueue(new MessageQueue),
|
m_messageQueue(new MessageQueue),
|
||||||
m_settings(),
|
m_settings(),
|
||||||
m_dspEngine(new DSPEngine(m_messageQueue)),
|
m_dspEngine(new DSPEngine(m_messageQueue)),
|
||||||
|
@ -196,6 +194,8 @@ void MainWindow::loadSettings(const Preset* preset)
|
||||||
|
|
||||||
m_pluginManager->loadSettings(preset);
|
m_pluginManager->loadSettings(preset);
|
||||||
|
|
||||||
|
m_dspEngine->configureAudioOutput(m_settings.getPreferences()->getAudioOutput(), m_settings.getPreferences()->getAudioOutputRate());
|
||||||
|
|
||||||
// has to be last step
|
// has to be last step
|
||||||
restoreState(preset->getLayout());
|
restoreState(preset->getLayout());
|
||||||
}
|
}
|
||||||
|
@ -306,12 +306,12 @@ void MainWindow::handleMessages()
|
||||||
{
|
{
|
||||||
Message* message;
|
Message* message;
|
||||||
while((message = m_messageQueue->accept()) != NULL) {
|
while((message = m_messageQueue->accept()) != NULL) {
|
||||||
qDebug("Message: %s", message->getIdentifier());
|
//qDebug("Message: %s", message->getIdentifier());
|
||||||
if(DSPEngineReport::match(message)) {
|
if(DSPEngineReport::match(message)) {
|
||||||
DSPEngineReport* rep = (DSPEngineReport*)message;
|
DSPEngineReport* rep = DSPEngineReport::cast(message);
|
||||||
m_sampleRate = rep->getSampleRate();
|
m_sampleRate = rep->getSampleRate();
|
||||||
m_centerFrequency = rep->getCenterFrequency();
|
m_centerFrequency = rep->getCenterFrequency();
|
||||||
qDebug("SampleRate:%d, CenterFrequency:%llu", rep->getSampleRate(), rep->getCenterFrequency());
|
//qDebug("SampleRate:%d, CenterFrequency:%llu", rep->getSampleRate(), rep->getCenterFrequency());
|
||||||
updateCenterFreqDisplay();
|
updateCenterFreqDisplay();
|
||||||
updateSampleRate();
|
updateSampleRate();
|
||||||
message->completed();
|
message->completed();
|
||||||
|
@ -332,6 +332,7 @@ void MainWindow::updateStatus()
|
||||||
m_engineRunning->setColor(Qt::gray);
|
m_engineRunning->setColor(Qt::gray);
|
||||||
m_engineError->setColor(Qt::gray);
|
m_engineError->setColor(Qt::gray);
|
||||||
statusBar()->clearMessage();
|
statusBar()->clearMessage();
|
||||||
|
updateEnables(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSPEngine::StIdle:
|
case DSPEngine::StIdle:
|
||||||
|
@ -339,6 +340,7 @@ void MainWindow::updateStatus()
|
||||||
m_engineRunning->setColor(Qt::gray);
|
m_engineRunning->setColor(Qt::gray);
|
||||||
m_engineError->setColor(Qt::gray);
|
m_engineError->setColor(Qt::gray);
|
||||||
statusBar()->clearMessage();
|
statusBar()->clearMessage();
|
||||||
|
updateEnables(false);
|
||||||
if(m_startOsmoSDRUpdateAfterStop)
|
if(m_startOsmoSDRUpdateAfterStop)
|
||||||
on_actionOsmoSDR_Firmware_Upgrade_triggered();
|
on_actionOsmoSDR_Firmware_Upgrade_triggered();
|
||||||
break;
|
break;
|
||||||
|
@ -348,6 +350,7 @@ void MainWindow::updateStatus()
|
||||||
m_engineRunning->setColor(Qt::green);
|
m_engineRunning->setColor(Qt::green);
|
||||||
m_engineError->setColor(Qt::gray);
|
m_engineError->setColor(Qt::gray);
|
||||||
statusBar()->showMessage(tr("Sampling from %1").arg(m_dspEngine->deviceDescription()));
|
statusBar()->showMessage(tr("Sampling from %1").arg(m_dspEngine->deviceDescription()));
|
||||||
|
updateEnables(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSPEngine::StError:
|
case DSPEngine::StError:
|
||||||
|
@ -355,6 +358,8 @@ void MainWindow::updateStatus()
|
||||||
m_engineRunning->setColor(Qt::gray);
|
m_engineRunning->setColor(Qt::gray);
|
||||||
m_engineError->setColor(Qt::red);
|
m_engineError->setColor(Qt::red);
|
||||||
statusBar()->showMessage(tr("Error: %1").arg(m_dspEngine->errorMessage()));
|
statusBar()->showMessage(tr("Error: %1").arg(m_dspEngine->errorMessage()));
|
||||||
|
QMessageBox::critical(this, tr("Engine Error"), tr("%1").arg(m_dspEngine->errorMessage()), QMessageBox::Ok);
|
||||||
|
updateEnables(false);
|
||||||
if(m_startOsmoSDRUpdateAfterStop)
|
if(m_startOsmoSDRUpdateAfterStop)
|
||||||
on_actionOsmoSDR_Firmware_Upgrade_triggered();
|
on_actionOsmoSDR_Firmware_Upgrade_triggered();
|
||||||
break;
|
break;
|
||||||
|
@ -363,6 +368,15 @@ void MainWindow::updateStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateEnables(bool running)
|
||||||
|
{
|
||||||
|
if(running) {
|
||||||
|
ui->action_Preferences->setEnabled(false);
|
||||||
|
} else {
|
||||||
|
ui->action_Preferences->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::scopeWindowDestroyed()
|
void MainWindow::scopeWindowDestroyed()
|
||||||
{
|
{
|
||||||
ui->action_Oscilloscope->setChecked(false);
|
ui->action_Oscilloscope->setChecked(false);
|
||||||
|
@ -490,7 +504,9 @@ void MainWindow::on_action_Oscilloscope_triggered()
|
||||||
|
|
||||||
QDockWidget* dock = new QDockWidget(tr("Signalscope"), this);
|
QDockWidget* dock = new QDockWidget(tr("Signalscope"), this);
|
||||||
dock->setObjectName(QString::fromUtf8("scopeDock"));
|
dock->setObjectName(QString::fromUtf8("scopeDock"));
|
||||||
m_scopeWindow = new ScopeWindow(m_dspEngine);
|
|
||||||
|
m_scopeWindow = new ScopeWindow();
|
||||||
|
m_scopeWindow->setDSPEngine(m_dspEngine);
|
||||||
connect(m_scopeWindow, SIGNAL(destroyed()), this, SLOT(scopeWindowDestroyed()));
|
connect(m_scopeWindow, SIGNAL(destroyed()), this, SLOT(scopeWindowDestroyed()));
|
||||||
m_scopeWindow->setSampleRate(m_sampleRate);
|
m_scopeWindow->setSampleRate(m_sampleRate);
|
||||||
dock->setWidget(m_scopeWindow);
|
dock->setWidget(m_scopeWindow);
|
||||||
|
@ -509,9 +525,11 @@ void MainWindow::on_action_Loaded_Plugins_triggered()
|
||||||
|
|
||||||
void MainWindow::on_action_Preferences_triggered()
|
void MainWindow::on_action_Preferences_triggered()
|
||||||
{
|
{
|
||||||
PreferencesDialog preferencesDialog(m_audioDeviceInfo, this);
|
PreferencesDialog preferencesDialog(m_settings.getPreferences(), this);
|
||||||
|
|
||||||
preferencesDialog.exec();
|
if(preferencesDialog.exec() == QDialog::Accepted) {
|
||||||
|
m_dspEngine->configureAudioOutput(m_settings.getPreferences()->getAudioOutput(), m_settings.getPreferences()->getAudioOutputRate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_sampleSource_currentIndexChanged(int index)
|
void MainWindow::on_sampleSource_currentIndexChanged(int index)
|
||||||
|
|
|
@ -72,7 +72,7 @@ void PluginManager::registerSampleSource(const QString& sourceName, PluginInterf
|
||||||
|
|
||||||
void PluginManager::loadSettings(const Preset* preset)
|
void PluginManager::loadSettings(const Preset* preset)
|
||||||
{
|
{
|
||||||
qDebug("-------- [%s | %s] --------", qPrintable(preset->getGroup()), qPrintable(preset->getDescription()));
|
//qDebug("-------- [%s | %s] --------", qPrintable(preset->getGroup()), qPrintable(preset->getDescription()));
|
||||||
|
|
||||||
// copy currently open channels and clear list
|
// copy currently open channels and clear list
|
||||||
ChannelInstanceRegistrations openChannels = m_channelInstanceRegistrations;
|
ChannelInstanceRegistrations openChannels = m_channelInstanceRegistrations;
|
||||||
|
@ -83,7 +83,7 @@ void PluginManager::loadSettings(const Preset* preset)
|
||||||
ChannelInstanceRegistration reg;
|
ChannelInstanceRegistration reg;
|
||||||
// if we have one instance available already, use it
|
// if we have one instance available already, use it
|
||||||
for(int i = 0; i < openChannels.count(); i++) {
|
for(int i = 0; i < openChannels.count(); i++) {
|
||||||
qDebug("compare [%s] vs [%s]", qPrintable(openChannels[i].m_channelName), qPrintable(channelConfig.m_channel));
|
//qDebug("compare [%s] vs [%s]", qPrintable(openChannels[i].m_channelName), qPrintable(channelConfig.m_channel));
|
||||||
if(openChannels[i].m_channelName == channelConfig.m_channel) {
|
if(openChannels[i].m_channelName == channelConfig.m_channel) {
|
||||||
qDebug("channel [%s] found", qPrintable(openChannels[i].m_channelName));
|
qDebug("channel [%s] found", qPrintable(openChannels[i].m_channelName));
|
||||||
reg = openChannels.takeAt(i);
|
reg = openChannels.takeAt(i);
|
||||||
|
@ -235,7 +235,7 @@ int PluginManager::selectSampleSource(const QString& source)
|
||||||
|
|
||||||
qDebug("finding sample source [%s]", qPrintable(source));
|
qDebug("finding sample source [%s]", qPrintable(source));
|
||||||
for(int i = 0; i < m_sampleSourceDevices.count(); i++) {
|
for(int i = 0; i < m_sampleSourceDevices.count(); i++) {
|
||||||
qDebug("*** %s vs %s", qPrintable(m_sampleSourceDevices[i].m_sourceName), qPrintable(source));
|
//qDebug("*** %s vs %s", qPrintable(m_sampleSourceDevices[i].m_sourceName), qPrintable(source));
|
||||||
if(m_sampleSourceDevices[i].m_sourceName == source) {
|
if(m_sampleSourceDevices[i].m_sourceName == source) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -8,19 +8,15 @@ Preferences::Preferences()
|
||||||
|
|
||||||
void Preferences::resetToDefaults()
|
void Preferences::resetToDefaults()
|
||||||
{
|
{
|
||||||
m_sourceType.clear();
|
m_audioOutput.clear();
|
||||||
m_sourceDevice.clear();
|
m_audioOutputRate = 44100;
|
||||||
m_audioType.clear();
|
|
||||||
m_audioDevice.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Preferences::serialize() const
|
QByteArray Preferences::serialize() const
|
||||||
{
|
{
|
||||||
SimpleSerializer s(1);
|
SimpleSerializer s(1);
|
||||||
s.writeString(1, m_sourceType);
|
s.writeString(1, m_audioOutput);
|
||||||
s.writeString(2, m_sourceDevice);
|
s.writeU32(2, m_audioOutputRate);
|
||||||
s.writeString(3, m_audioType);
|
|
||||||
s.writeString(4, m_audioDevice);
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,10 +30,10 @@ bool Preferences::deserialize(const QByteArray& data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(d.getVersion() == 1) {
|
if(d.getVersion() == 1) {
|
||||||
d.readString(1, &m_sourceType);
|
d.readString(1, &m_audioOutput);
|
||||||
d.readString(2, &m_sourceDevice);
|
quint32 tmp;
|
||||||
d.readString(3, &m_audioType);
|
d.readU32(2, &tmp, 44100);
|
||||||
d.readString(4, &m_audioDevice);
|
m_audioOutputRate = tmp;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
resetToDefaults();
|
resetToDefaults();
|
||||||
|
|
|
@ -29,6 +29,8 @@ const char* Message::getIdentifier() const
|
||||||
|
|
||||||
bool Message::matchIdentifier(const char* identifier) const
|
bool Message::matchIdentifier(const char* identifier) const
|
||||||
{
|
{
|
||||||
|
// Warning: this compares POINTERS - make sure, that each message has a unique name
|
||||||
|
// otherwise the linker might "optimize" stuff
|
||||||
return m_identifier == identifier;
|
return m_identifier == identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue