summaryrefslogtreecommitdiffstats
path: root/include-gpl
diff options
context:
space:
mode:
authorChristian Daniel <cd@maintech.de>2013-03-22 11:18:30 +0100
committerChristian Daniel <cd@maintech.de>2013-03-22 11:18:30 +0100
commiteca56e35be841396f6c57bab540a3e1503253d56 (patch)
tree4a0a29cd53a84339e56754c32bf67391c83494fe /include-gpl
parent2c8c930b39fe069b36d81caa00401d9ac182a9d8 (diff)
monster rework
- pluginify whole project - reorganize directory structure - fix PortAudio detection script - implement generic channelizer - fix several OpenGL problems - rework presets - add audio mixing - too many more
Diffstat (limited to 'include-gpl')
-rw-r--r--include-gpl/audio/audiodeviceinfo.h48
-rw-r--r--include-gpl/audio/audiofifo.h64
-rw-r--r--include-gpl/audio/audiooutput.h68
-rw-r--r--include-gpl/audio/portaudioholder.h13
-rw-r--r--include-gpl/dsp/channelizer.h108
-rw-r--r--include-gpl/dsp/dspcommands.h270
-rw-r--r--include-gpl/dsp/dspengine.h118
-rw-r--r--include-gpl/dsp/fftengine.h19
-rw-r--r--include-gpl/dsp/fftwengine.h34
-rw-r--r--include-gpl/dsp/fftwindow.h81
-rw-r--r--include-gpl/dsp/interpolator.h64
-rw-r--r--include-gpl/dsp/inthalfbandfilter.h306
-rw-r--r--include-gpl/dsp/kissengine.h23
-rw-r--r--include-gpl/dsp/lowpass.h86
-rw-r--r--include-gpl/dsp/nco.h44
-rw-r--r--include-gpl/dsp/scopevis.h43
-rw-r--r--include-gpl/dsp/spectrumvis.h41
-rw-r--r--include-gpl/gui/addpresetdialog.h30
-rw-r--r--include-gpl/gui/glscope.h108
-rw-r--r--include-gpl/gui/glspectrum.h149
-rw-r--r--include-gpl/gui/glspectrumgui.h58
-rw-r--r--include-gpl/gui/indicator.h40
-rw-r--r--include-gpl/gui/physicalunit.h35
-rw-r--r--include-gpl/gui/pluginsdialog.h22
-rw-r--r--include-gpl/gui/preferencesdialog.h34
-rw-r--r--include-gpl/gui/presetitem.h27
-rw-r--r--include-gpl/gui/scale.h36
-rw-r--r--include-gpl/gui/scaleengine.h89
-rw-r--r--include-gpl/gui/scopewindow.h66
-rw-r--r--include-gpl/gui/valuedial.h71
-rw-r--r--include-gpl/mainwindow.h135
-rw-r--r--include-gpl/plugin/pluginmanager.h127
-rw-r--r--include-gpl/settings/preferences.h32
-rw-r--r--include-gpl/settings/preset.h98
-rw-r--r--include-gpl/settings/settings.h32
35 files changed, 2619 insertions, 0 deletions
diff --git a/include-gpl/audio/audiodeviceinfo.h b/include-gpl/audio/audiodeviceinfo.h
new file mode 100644
index 0000000..7b88870
--- /dev/null
+++ b/include-gpl/audio/audiodeviceinfo.h
@@ -0,0 +1,48 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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>
+
+class 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
diff --git a/include-gpl/audio/audiofifo.h b/include-gpl/audio/audiofifo.h
new file mode 100644
index 0000000..8a06e99
--- /dev/null
+++ b/include-gpl/audio/audiofifo.h
@@ -0,0 +1,64 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_AUDIOFIFO_H
+#define INCLUDE_AUDIOFIFO_H
+
+#include <QMutex>
+#include <QWaitCondition>
+
+class AudioFifo {
+public:
+ AudioFifo();
+ AudioFifo(uint sampleSize, uint numSamples);
+ ~AudioFifo();
+
+ bool setSize(uint sampleSize, uint numSamples);
+
+ uint write(const quint8* data, uint numSamples, int timeout = INT_MAX);
+ uint read(quint8* data, uint numSamples, int timeout = INT_MAX);
+
+ uint drain(uint numSamples);
+ void clear();
+
+ inline uint flush() { return drain(m_fill); }
+ inline uint fill() const { return m_fill; }
+ inline bool isEmpty() const { return m_fill == 0; }
+ inline bool isFull() const { return m_fill == m_size; }
+ inline uint size() const { return m_size; }
+
+private:
+ QMutex m_mutex;
+
+ qint8* m_fifo;
+
+ uint m_sampleSize;
+
+ uint m_size;
+ uint m_fill;
+ uint m_head;
+ uint m_tail;
+
+ QMutex m_writeWaitLock;
+ QMutex m_readWaitLock;
+ QWaitCondition m_writeWaitCondition;
+ QWaitCondition m_readWaitCondition;
+
+ bool create(uint sampleSize, uint numSamples);
+};
+
+#endif // INCLUDE_AUDIOFIFO_H
diff --git a/include-gpl/audio/audiooutput.h b/include-gpl/audio/audiooutput.h
new file mode 100644
index 0000000..347c246
--- /dev/null
+++ b/include-gpl/audio/audiooutput.h
@@ -0,0 +1,68 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_AUDIOOUTPUT_H
+#define INCLUDE_AUDIOOUTPUT_H
+
+#include <QMutex>
+#include <list>
+#include <vector>
+#include "portaudio.h"
+
+class AudioFifo;
+
+class AudioOutput {
+public:
+ AudioOutput();
+ ~AudioOutput();
+
+ bool start(int device, int rate);
+ void stop();
+
+ void addFifo(AudioFifo* audioFifo);
+ void removeFifo(AudioFifo* audioFifo);
+
+ //int bufferedSamples();
+
+private:
+ QMutex m_mutex;
+ PaStream* m_stream;
+ //AudioFifo* m_audioFifo;
+ typedef std::list<AudioFifo*> AudioFifos;
+ AudioFifos m_audioFifos;
+ std::vector<qint32> m_mixBuffer;
+
+ int m_sampleRate;
+ //PaTime m_streamStartTime;
+
+ static int callbackHelper(
+ const void* inputBuffer,
+ void* outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void* userData);
+
+ int callback(
+ const void* inputBuffer,
+ void* outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags);
+};
+
+#endif // INCLUDE_AUDIOOUTPUT_H
diff --git a/include-gpl/audio/portaudioholder.h b/include-gpl/audio/portaudioholder.h
new file mode 100644
index 0000000..9f6bd50
--- /dev/null
+++ b/include-gpl/audio/portaudioholder.h
@@ -0,0 +1,13 @@
+#ifndef INCLUDE_PORTAUDIOHOLDER_H
+#define INCLUDE_PORTAUDIOHOLDER_H
+
+class PortAudioHolder {
+public:
+ PortAudioHolder();
+ ~PortAudioHolder();
+
+private:
+ bool m_initialized;
+};
+
+#endif // INCLUDE_PORTAUDIOHOLDER_H
diff --git a/include-gpl/dsp/channelizer.h b/include-gpl/dsp/channelizer.h
new file mode 100644
index 0000000..223625e
--- /dev/null
+++ b/include-gpl/dsp/channelizer.h
@@ -0,0 +1,108 @@
+#ifndef INCLUDE_CHANNELIZER_H
+#define INCLUDE_CHANNELIZER_H
+
+#include <list>
+#include "dsp/samplesink.h"
+
+class MessageQueue;
+class IntHalfbandFilter;
+
+class Channelizer : public SampleSink {
+public:
+ Channelizer(SampleSink* sampleSink);
+ ~Channelizer();
+
+ void configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency);
+
+ void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst);
+ void start();
+ void stop();
+ bool handleMessage(Message* cmd);
+
+protected:
+ struct FilterStage {
+ enum Mode {
+ ModeCenter,
+ ModeLowerHalf,
+ ModeUpperHalf
+ };
+
+ typedef bool (IntHalfbandFilter::*WorkFunction)(Sample* s);
+ IntHalfbandFilter* m_filter;
+ WorkFunction m_workFunction;
+
+ FilterStage(Mode mode);
+ ~FilterStage();
+
+ bool work(Sample* sample)
+ {
+ return (m_filter->*m_workFunction)(sample);
+ }
+ };
+ typedef std::list<FilterStage*> FilterStages;
+ FilterStages m_filterStages;
+ SampleSink* m_sampleSink;
+ int m_inputSampleRate;
+ int m_requestedOutputSampleRate;
+ int m_requestedCenterFrequency;
+ int m_currentOutputSampleRate;
+ int m_currentCenterFrequency;
+ SampleVector m_sampleBuffer;
+
+ void applyConfiguration();
+ bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const;
+ Real createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd);
+ void freeFilterChain();
+};
+
+#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
diff --git a/include-gpl/dsp/dspcommands.h b/include-gpl/dsp/dspcommands.h
new file mode 100644
index 0000000..7377324
--- /dev/null
+++ b/include-gpl/dsp/dspcommands.h
@@ -0,0 +1,270 @@
+#ifndef INCLUDE_DSPCOMMANDS_H
+#define INCLUDE_DSPCOMMANDS_H
+
+#include <QString>
+#include "util/message.h"
+#include "fftwindow.h"
+
+class SampleSource;
+class SampleSink;
+class AudioFifo;
+
+class DSPPing : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPPing() : Message(ID()) { }
+};
+
+class DSPExit : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPExit() : Message(ID()) { }
+};
+
+class DSPAcquisitionStart : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPAcquisitionStart() : Message(ID()) { }
+};
+
+class DSPAcquisitionStop : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPAcquisitionStop() : Message(ID()) { }
+};
+
+class DSPGetDeviceDescription : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPGetDeviceDescription() : Message(ID()) { }
+
+ void setDeviceDescription(const QString& text) { m_deviceDescription = text; }
+ const QString& getDeviceDescription() const { return m_deviceDescription; }
+
+private:
+ QString m_deviceDescription;
+};
+
+class DSPGetErrorMessage : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPGetErrorMessage() : Message(ID()) { }
+
+ void setErrorMessage(const QString& text) { m_errorMessage = text; }
+ const QString& getErrorMessage() const { return m_errorMessage; }
+
+private:
+ QString m_errorMessage;
+};
+
+class DSPSetSource : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPSetSource(SampleSource* sampleSource) : Message(ID()), m_sampleSource(sampleSource) { }
+
+ SampleSource* getSampleSource() const { return m_sampleSource; }
+
+private:
+ SampleSource* m_sampleSource;
+};
+
+class DSPAddSink : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPAddSink(SampleSink* sampleSink) : Message(ID()), m_sampleSink(sampleSink) { }
+
+ SampleSink* getSampleSink() const { return m_sampleSink; }
+
+private:
+ SampleSink* m_sampleSink;
+};
+
+class DSPRemoveSink : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPRemoveSink(SampleSink* sampleSink) : Message(ID()), m_sampleSink(sampleSink) { }
+
+ SampleSink* getSampleSink() const { return m_sampleSink; }
+
+private:
+ SampleSink* m_sampleSink;
+};
+
+class DSPAddAudioSource : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPAddAudioSource(AudioFifo* audioFifo) : Message(ID()), m_audioFifo(audioFifo) { }
+
+ AudioFifo* getAudioFifo() const { return m_audioFifo; }
+
+private:
+ AudioFifo* m_audioFifo;
+};
+
+class DSPRemoveAudioSource : public Message {
+public:
+ static MessageRegistrator ID;
+
+ DSPRemoveAudioSource(AudioFifo* audioFifo) : Message(ID()), m_audioFifo(audioFifo) { }
+
+ AudioFifo* getAudioFifo() const { return m_audioFifo; }
+
+private:
+ AudioFifo* m_audioFifo;
+};
+
+class DSPConfigureSpectrumVis : public Message {
+public:
+ static MessageRegistrator ID;
+
+ int getFFTSize() const { return m_fftSize; }
+ int getOverlapPercent() const { return m_overlapPercent; }
+ FFTWindow::Function getWindow() const { return m_window; }
+
+ static DSPConfigureSpectrumVis* create(int fftSize, int overlapPercent, FFTWindow::Function window)
+ {
+ return new DSPConfigureSpectrumVis(fftSize, overlapPercent, window);
+ }
+
+private:
+ int m_fftSize;
+ int m_overlapPercent;
+ FFTWindow::Function m_window;
+
+ DSPConfigureSpectrumVis(int fftSize, int overlapPercent, FFTWindow::Function window) :
+ Message(ID()),
+ m_fftSize(fftSize),
+ m_overlapPercent(overlapPercent),
+ m_window(window)
+ { }
+};
+
+class DSPConfigureCorrection : public Message {
+public:
+ static MessageRegistrator ID;
+
+ bool getDCOffsetCorrection() const { return m_dcOffsetCorrection; }
+ bool getIQImbalanceCorrection() const { return m_iqImbalanceCorrection; }
+
+ static DSPConfigureCorrection* create(bool dcOffsetCorrection, bool iqImbalanceCorrection)
+ {
+ return new DSPConfigureCorrection(dcOffsetCorrection, iqImbalanceCorrection);
+ }
+
+private:
+ bool m_dcOffsetCorrection;
+ bool m_iqImbalanceCorrection;
+
+ DSPConfigureCorrection(bool dcOffsetCorrection, bool iqImbalanceCorrection) :
+ Message(ID()),
+ m_dcOffsetCorrection(dcOffsetCorrection),
+ m_iqImbalanceCorrection(iqImbalanceCorrection)
+ { }
+};
+
+class DSPEngineReport : public Message {
+public:
+ static MessageRegistrator ID;
+
+ int getSampleRate() const { return m_sampleRate; }
+ quint64 getCenterFrequency() const { return m_centerFrequency; }
+
+ static DSPEngineReport* create(int sampleRate, quint64 centerFrequency)
+ {
+ return new DSPEngineReport(sampleRate, centerFrequency);
+ }
+
+private:
+ int m_sampleRate;
+ quint64 m_centerFrequency;
+
+ DSPEngineReport(int sampleRate, quint64 centerFrequency) :
+ Message(ID()),
+ m_sampleRate(sampleRate),
+ m_centerFrequency(centerFrequency)
+ { }
+};
+
+class DSPConfigureScopeVis : public Message {
+public:
+ static MessageRegistrator ID;
+
+ int getTriggerChannel() const { return m_triggerChannel; }
+ Real getTriggerLevelHigh() const { return m_triggerLevelHigh; }
+ Real getTriggerLevelLow() const { return m_triggerLevelLow; }
+
+ static DSPConfigureScopeVis* create(int triggerChannel, Real triggerLevelHigh, Real triggerLevelLow)
+ {
+ return new DSPConfigureScopeVis(triggerChannel, triggerLevelHigh, triggerLevelLow);
+ }
+
+private:
+ int m_triggerChannel;
+ Real m_triggerLevelHigh;
+ Real m_triggerLevelLow;
+
+ DSPConfigureScopeVis(int triggerChannel, Real triggerLevelHigh, Real triggerLevelLow) :
+ Message(ID()),
+ m_triggerChannel(triggerChannel),
+ m_triggerLevelHigh(triggerLevelHigh),
+ m_triggerLevelLow(triggerLevelLow)
+ { }
+};
+
+class DSPSignalNotification : public Message {
+public:
+ static MessageRegistrator ID;
+
+ int getSampleRate() const { return m_sampleRate; }
+ qint64 getFrequencyOffset() const { return m_frequencyOffset; }
+
+ static DSPSignalNotification* create(int sampleRate, quint64 frequencyOffset)
+ {
+ return new DSPSignalNotification(sampleRate, frequencyOffset);
+ }
+
+private:
+ int m_sampleRate;
+ qint64 m_frequencyOffset;
+
+ DSPSignalNotification(int samplerate, qint64 frequencyOffset) :
+ Message(ID()),
+ m_sampleRate(samplerate),
+ m_frequencyOffset(frequencyOffset)
+ { }
+};
+
+class DSPConfigureChannelizer : public Message {
+public:
+ static MessageRegistrator ID;
+
+ int getSampleRate() const { return m_sampleRate; }
+ int getCenterFrequency() const { return m_centerFrequency; }
+
+ static DSPConfigureChannelizer* create(int sampleRate, int centerFrequency)
+ {
+ return new DSPConfigureChannelizer(sampleRate, centerFrequency);
+ }
+
+private:
+ int m_sampleRate;
+ int m_centerFrequency;
+
+ DSPConfigureChannelizer(int sampleRate, int centerFrequency) :
+ Message(ID()),
+ m_sampleRate(sampleRate),
+ m_centerFrequency(centerFrequency)
+ { }
+};
+
+#endif // INCLUDE_DSPCOMMANDS_H
diff --git a/include-gpl/dsp/dspengine.h b/include-gpl/dsp/dspengine.h
new file mode 100644
index 0000000..1c3fd42
--- /dev/null
+++ b/include-gpl/dsp/dspengine.h
@@ -0,0 +1,118 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_DSPENGINE_H
+#define INCLUDE_DSPENGINE_H
+
+#include <QThread>
+#include <QTimer>
+#include <QMutex>
+#include <QWaitCondition>
+#include "dsp/dsptypes.h"
+#include "dsp/fftwindow.h"
+#include "dsp/samplefifo.h"
+#include "audio/audiooutput.h"
+#include "util/messagequeue.h"
+
+class SampleSource;
+class SampleSink;
+class AudioFifo;
+
+class DSPEngine : public QThread {
+ Q_OBJECT
+
+public:
+ enum State {
+ StNotStarted,
+ StIdle,
+ StRunning,
+ StError
+ };
+
+ DSPEngine(MessageQueue* reportQueue, QObject* parent = NULL);
+ ~DSPEngine();
+
+ MessageQueue* getMessageQueue() { return &m_messageQueue; }
+
+ void start();
+ void stop();
+
+ bool startAcquisition();
+ void stopAcquistion();
+
+ void setSource(SampleSource* source);
+
+ void addSink(SampleSink* sink);
+ void removeSink(SampleSink* sink);
+
+ void addAudioSource(AudioFifo* audioFifo);
+ void removeAudioSource(AudioFifo* audioFifo);
+
+ void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection);
+
+ State state() const { return m_state; }
+
+ QString errorMessage();
+ QString deviceDescription();
+
+private:
+ MessageQueue m_messageQueue;
+ MessageQueue* m_reportQueue;
+
+ State m_state;
+
+ QString m_errorMessage;
+ QString m_deviceDescription;
+
+ SampleSource* m_sampleSource;
+
+ typedef std::list<SampleSink*> SampleSinks;
+ SampleSinks m_sampleSinks;
+
+ AudioOutput m_audioOutput;
+
+ int m_sampleRate;
+ quint64 m_centerFrequency;
+
+ bool m_dcOffsetCorrection;
+ bool m_iqImbalanceCorrection;
+ qint32 m_iOffset;
+ qint32 m_qOffset;
+ qint32 m_iRange;
+ qint32 m_qRange;
+ qint32 m_imbalance;
+
+ void run();
+
+ void dcOffset(SampleVector::iterator begin, SampleVector::iterator end);
+ void imbalance(SampleVector::iterator begin, SampleVector::iterator end);
+ void work();
+
+ State gotoIdle();
+ State gotoRunning();
+ State gotoError(const QString& errorMsg);
+
+ void handleSetSource(SampleSource* source);
+ void generateReport();
+ bool distributeMessage(Message* message);
+
+private slots:
+ void handleData();
+ void handleMessages();
+};
+
+#endif // INCLUDE_DSPENGINE_H
diff --git a/include-gpl/dsp/fftengine.h b/include-gpl/dsp/fftengine.h
new file mode 100644
index 0000000..1139059
--- /dev/null
+++ b/include-gpl/dsp/fftengine.h
@@ -0,0 +1,19 @@
+#ifndef INCLUDE_FFTENGINE_H
+#define INCLUDE_FFTENGINE_H
+
+#include "dsp/dsptypes.h"
+
+class FFTEngine {
+public:
+ virtual ~FFTEngine();
+
+ virtual void configure(int n, bool inverse) = 0;
+ virtual void transform() = 0;
+
+ virtual Complex* in() = 0;
+ virtual Complex* out() = 0;
+
+ static FFTEngine* create();
+};
+
+#endif // INCLUDE_FFTENGINE_H
diff --git a/include-gpl/dsp/fftwengine.h b/include-gpl/dsp/fftwengine.h
new file mode 100644
index 0000000..2da5317
--- /dev/null
+++ b/include-gpl/dsp/fftwengine.h
@@ -0,0 +1,34 @@
+#ifndef INCLUDE_FFTWENGINE_H
+#define INCLUDE_FFTWENGINE_H
+
+#include <fftw3.h>
+#include <list>
+#include "dsp/fftengine.h"
+
+class FFTWEngine : public FFTEngine {
+public:
+ FFTWEngine();
+ ~FFTWEngine();
+
+ void configure(int n, bool inverse);
+ void transform();
+
+ Complex* in();
+ Complex* out();
+
+protected:
+ struct Plan {
+ int n;
+ bool inverse;
+ fftwf_plan plan;
+ fftwf_complex* in;
+ fftwf_complex* out;
+ };
+ typedef std::list<Plan*> Plans;
+ Plans m_plans;
+ Plan* m_currentPlan;
+
+ void freeAll();
+};
+
+#endif // INCLUDE_FFTWENGINE_H
diff --git a/include-gpl/dsp/fftwindow.h b/include-gpl/dsp/fftwindow.h
new file mode 100644
index 0000000..179a0b7
--- /dev/null
+++ b/include-gpl/dsp/fftwindow.h
@@ -0,0 +1,81 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_FFTWINDOW_H
+#define INCLUDE_FFTWINDOW_H
+
+#include <vector>
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include "dsp/dsptypes.h"
+
+class FFTWindow {
+public:
+ enum Function {
+ Bartlett,
+ BlackmanHarris,
+ Flattop,
+ Hamming,
+ Hanning,
+ Rectangle
+ };
+
+ void create(Function function, int n);
+ void apply(const std::vector<Real>& in, std::vector<Real>* out);
+ void apply(const std::vector<Complex>& in, std::vector<Complex>* out);
+ void apply(const Complex* in, Complex* out);
+
+private:
+ std::vector<float> m_window;
+
+ static inline Real flatTop(Real n, Real i)
+ {
+ // correction ?
+ return 1.0 - 1.93 * cos((2.0 * M_PI * i) / n) + 1.29 * cos((4.0 * M_PI * i) / n) - 0.388 * cos((6.0 * M_PI * i) / n) + 0.03222 * cos((8.0 * M_PI * i) / n);
+ }
+
+ static inline Real bartlett(Real n, Real i)
+ {
+ // amplitude correction = 2.0
+ return (2.0 / (n - 1.0)) * ( (n - 1.0) / 2.0 - fabs(i - (n - 1.0) / 2.0)) * 2.0;
+ }
+
+ static inline Real blackmanHarris(Real n, Real i)
+ {
+ // amplitude correction = 2.79
+ return (0.35875 - 0.48829 * cos((2.0 * M_PI * i) / n) + 0.14128 * cos((4.0 * M_PI * i) / n) - 0.01168 * cos((6.0 * M_PI * i) / n)) * 2.79;
+ }
+
+ static inline Real hamming(Real n, Real i)
+ {
+ // amplitude correction = 1.855, energy correction = 1.586
+ return (0.54 - 0.46 * cos((2.0 * M_PI * i) / n)) * 1.855;
+ }
+
+ static inline Real hanning(Real n, Real i)
+ {
+ // amplitude correction = 2.0, energy correction = 1.633
+ return (0.5 - 0.5 * cos((2.0 * M_PI * i) / n)) * 2.0;
+ }
+
+ static inline Real rectangle(Real, Real)
+ {
+ return 1.0;
+ }
+};
+
+#endif // INCLUDE_FFTWINDOWS_H
diff --git a/include-gpl/dsp/interpolator.h b/include-gpl/dsp/interpolator.h
new file mode 100644
index 0000000..22541cb
--- /dev/null
+++ b/include-gpl/dsp/interpolator.h
@@ -0,0 +1,64 @@
+#ifndef INCLUDE_INTERPOLATOR_H
+#define INCLUDE_INTERPOLATOR_H
+
+#include "dsp/dsptypes.h"
+
+class Interpolator {
+public:
+ Interpolator();
+
+ void create(int nTaps, int phaseSteps, double sampleRate, double cutoff);
+
+ bool interpolate(Real* distance, const Complex& next, bool* consumed, Complex* result)
+ {
+ while(*distance >= 1.0) {
+ if(!(*consumed)) {
+ advanceFilter(next);
+ *distance -= 1.0;
+ *consumed = true;
+ } else {
+ return false;
+ }
+ }
+ doInterpolate((int)floor(*distance * (Real)m_phaseSteps), result);
+ return true;
+ }
+
+
+private:
+ std::vector<Real> m_taps;
+ std::vector<Complex> m_samples;
+ int m_ptr;
+ int m_phaseSteps;
+ int m_nTaps;
+
+ void createTaps(int nTaps, double sampleRate, double cutoff, std::vector<Real>* taps);
+
+ void advanceFilter(const Complex& next)
+ {
+ m_ptr--;
+ if(m_ptr < 0)
+ m_ptr = m_nTaps;
+ m_samples[m_ptr] = next;
+ }
+
+ void doInterpolate(int phase, Complex* result)
+ {
+ int sample = m_ptr;
+ const Real* coeff = &m_taps[phase * m_nTaps];
+ Real rAcc = 0;
+ Real iAcc = 0;
+
+ for(int i = 0; i < m_nTaps; i++) {
+ rAcc += *coeff * m_samples[sample].real();
+ iAcc += *coeff * m_samples[sample].imag();
+ sample++;
+ if(sample >= m_nTaps)
+ sample = 0;
+ coeff++;
+ }
+ *result = Complex(rAcc, iAcc);
+ }
+};
+
+#endif // INCLUDE_INTERPOLATOR_H
diff --git a/include-gpl/dsp/inthalfbandfilter.h b/include-gpl/dsp/inthalfbandfilter.h
new file mode 100644
index 0000000..ae49793
--- /dev/null
+++ b/include-gpl/dsp/inthalfbandfilter.h
@@ -0,0 +1,306 @@
+#ifndef INCLUDE_INTHALFBANDFILTER_H
+#define INCLUDE_INTHALFBANDFILTER_H
+
+#include <QtGlobal>
+#include "dsp/dsptypes.h"
+
+// uses Q1.14 format internally, input and output are S16
+
+/*
+ * supported filter orders: 64, 48, 32
+ */
+#define HB_FILTERORDER 48
+#define HB_SHIFT 14
+
+class IntHalfbandFilter {
+public:
+ IntHalfbandFilter();
+
+ // downsample by 2, return center part of original spectrum
+ bool workDecimateCenter(Sample* sample)
+ {
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = sample->real();
+ m_samples[m_ptr][1] = sample->imag();
+
+ switch(m_state) {
+ case 0:
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 1;
+
+ // tell caller we don't have a new sample
+ return false;
+
+ default:
+ // save result
+ doFIR(sample);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 0;
+
+ // tell caller we have a new sample
+ return true;
+ }
+ }
+
+ // downsample by 2, return lower half of original spectrum
+ bool workDecimateLowerHalf(Sample* sample)
+ {
+ switch(m_state) {
+ case 0:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = -sample->imag();
+ m_samples[m_ptr][1] = sample->real();
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 1;
+
+ // tell caller we don't have a new sample
+ return false;
+
+ case 1:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = -sample->real();
+ m_samples[m_ptr][1] = -sample->imag();
+
+ // save result
+ doFIR(sample);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 2;
+
+ // tell caller we have a new sample
+ return true;
+
+ case 2:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = sample->imag();
+ m_samples[m_ptr][1] = -sample->real();
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 3;
+
+ // tell caller we don't have a new sample
+ return false;
+
+ default:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = sample->real();
+ m_samples[m_ptr][1] = sample->imag();
+
+ // save result
+ doFIR(sample);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 0;
+
+ // tell caller we have a new sample
+ return true;
+ }
+ }
+
+ // downsample by 2, return upper half of original spectrum
+ bool workDecimateUpperHalf(Sample* sample)
+ {
+ switch(m_state) {
+ case 0:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = sample->imag();
+ m_samples[m_ptr][1] = -sample->real();
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 1;
+
+ // tell caller we don't have a new sample
+ return false;
+
+ case 1:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = -sample->real();
+ m_samples[m_ptr][1] = -sample->imag();
+
+ // save result
+ doFIR(sample);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 2;
+
+ // tell caller we have a new sample
+ return true;
+
+ case 2:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = -sample->imag();
+ m_samples[m_ptr][1] = sample->real();
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 3;
+
+ // tell caller we don't have a new sample
+ return false;
+
+ default:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = sample->real();
+ m_samples[m_ptr][1] = sample->imag();
+
+ // save result
+ doFIR(sample);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER);
+ if(m_ptr >= (HB_FILTERORDER + 1))
+ m_ptr -= (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 0;
+
+ // tell caller we have a new sample
+ return true;
+ }
+ }
+
+protected:
+ qint16 m_samples[HB_FILTERORDER + 1][2];
+ int m_ptr;
+ int m_state;
+
+ void doFIR(Sample* sample)
+ {
+ // coefficents
+
+#if HB_FILTERORDER == 64
+ static const qint32 COEFF[16] = {
+ -0.001114417441601693505720538368564120901 * (1 << HB_SHIFT),
+ 0.001268007827185253051302527005361753254 * (1 << HB_SHIFT),
+ -0.001959831378850490895410230152151598304 * (1 << HB_SHIFT),
+ 0.002878308307661380308073439948657323839 * (1 << HB_SHIFT),
+ -0.004071361818258721100571850826099762344 * (1 << HB_SHIFT),
+ 0.005597288494657440618973431867289036745 * (1 << HB_SHIFT),
+ -0.007532345003308904551886371336877346039 * (1 << HB_SHIFT),
+ 0.009980346844667375288961963519795972388 * (1 << HB_SHIFT),
+ -0.013092614174300500062830820979797863401 * (1 << HB_SHIFT),
+ 0.01710934914871829748417297878404497169 * (1 << HB_SHIFT),
+ -0.022443558692997273018576720460259821266 * (1 << HB_SHIFT),
+ 0.029875811511593811098386197500076377764 * (1 << HB_SHIFT),
+ -0.041086352085710403647667021687084343284 * (1 << HB_SHIFT),
+ 0.060465467462665789533104998554335907102 * (1 << HB_SHIFT),
+ -0.104159517495977321788203084906854201108 * (1 << HB_SHIFT),
+ 0.317657589850154464805598308885237202048 * (1 << HB_SHIFT),
+ };
+#elif HB_FILTERORDER == 48
+ static const qint32 COEFF[12] = {
+ -0.004102576237611492253332112767338912818 * (1 << HB_SHIFT),
+ 0.003950551047979387886410762575906119309 * (1 << HB_SHIFT),
+ -0.005807875789391703583164350277456833282 * (1 << HB_SHIFT),
+ 0.00823497890520805998770814682075069868 * (1 << HB_SHIFT),
+ -0.011372226513199541059195851744334504474 * (1 << HB_SHIFT),
+ 0.015471557140973646315984524335362948477 * (1 << HB_SHIFT),
+ -0.020944996398689276484450516591095947661 * (1 << HB_SHIFT),
+ 0.028568078132034283034279553703527199104 * (1 << HB_SHIFT),
+ -0.040015143905614086738964374490024056286 * (1 << HB_SHIFT),
+ 0.059669519431831075095828964549582451582 * (1 << HB_SHIFT),
+ -0.103669138691865420076609893840213771909 * (1 << HB_SHIFT),
+ 0.317491986549921390015072120149852707982 * (1 << HB_SHIFT)
+ };
+#elif HB_FILTERORDER == 32
+ static const qint32 COEFF[8] = {
+ -0.015956912844043127236437484839370881673 * (1 << HB_SHIFT),
+ 0.013023031678944928940522274274371739011 * (1 << HB_SHIFT),
+ -0.01866942273717486777684371190844103694 * (1 << HB_SHIFT),
+ 0.026550887571157304190005987720724078827 * (1 << HB_SHIFT),
+ -0.038350314277854319344740474662103224546 * (1 << HB_SHIFT),
+ 0.058429248652825838128421764849917963147 * (1 << HB_SHIFT),
+ -0.102889802028955756885153505209018476307 * (1 << HB_SHIFT),
+ 0.317237706405931241260276465254719369113 * (1 << HB_SHIFT)
+ };
+#else
+#error unsupported filter order
+#endif
+
+
+ // init read-pointer
+ int a = (m_ptr + 1);
+ if(a >= (HB_FILTERORDER + 1))
+ a -= (HB_FILTERORDER + 1);
+ int b = (m_ptr + (HB_FILTERORDER - 1));
+ if(b >= (HB_FILTERORDER + 1))
+ b -= (HB_FILTERORDER + 1);
+
+ // go through samples in buffer
+ qint32 iAcc = 0;
+ qint32 qAcc = 0;
+ for(int i = 0; i < HB_FILTERORDER / 4; i++) {
+ // do multiply-accumulate
+ qint32 iTmp = m_samples[a][0] + m_samples[b][0];
+ qint32 qTmp = m_samples[a][1] + m_samples[b][1];
+ iAcc += iTmp * COEFF[i];
+ qAcc += qTmp * COEFF[i];
+
+ // update read-pointer
+ a = (a + 2);
+ if(a >= (HB_FILTERORDER + 1))
+ a -= (HB_FILTERORDER + 1);
+ b = b + (HB_FILTERORDER - 1);
+ if(b >= (HB_FILTERORDER + 1))
+ b -= (HB_FILTERORDER + 1);
+ }
+
+ a = (a + HB_FILTERORDER);
+ if(a >= (HB_FILTERORDER + 1))
+ a -= (HB_FILTERORDER + 1);
+ iAcc += m_samples[a][0] * (qint32)(0.5 * (1 << HB_SHIFT));
+ qAcc += m_samples[a][1] * (qint32)(0.5 * (1 << HB_SHIFT));
+
+ // done, save result
+ sample->setReal((iAcc + (qint32)(0.5 * (1 << HB_SHIFT))) >> HB_SHIFT);
+ sample->setImag((qAcc + (qint32)(0.5 * (1 << HB_SHIFT))) >> HB_SHIFT);
+ }
+};
+
+#endif // INCLUDE_INTHALFBANDFILTER_H
diff --git a/include-gpl/dsp/kissengine.h b/include-gpl/dsp/kissengine.h
new file mode 100644
index 0000000..ad8e53c
--- /dev/null
+++ b/include-gpl/dsp/kissengine.h
@@ -0,0 +1,23 @@
+#ifndef INCLUDE_KISSENGINE_H
+#define INCLUDE_KISSENGINE_H
+
+#include "dsp/fftengine.h"
+#include "dsp/kissfft.h"
+
+class KissEngine : public FFTEngine {
+public:
+ void configure(int n, bool inverse);
+ void transform();
+
+ Complex* in();
+ Complex* out();
+
+protected:
+ typedef kissfft<Real, Complex> KissFFT;
+ KissFFT m_fft;
+
+ std::vector<Complex> m_in;
+ std::vector<Complex> m_out;
+};
+
+#endif // INCLUDE_KISSENGINE_H
diff --git a/include-gpl/dsp/lowpass.h b/include-gpl/dsp/lowpass.h
new file mode 100644
index 0000000..a9ed168
--- /dev/null
+++ b/include-gpl/dsp/lowpass.h
@@ -0,0 +1,86 @@
+#ifndef INCLUDE_LOWPASS_H
+#define INCLUDE_LOWPASS_H
+
+#include "dsp/dsptypes.h"
+
+template <class Type> class Lowpass {
+public:
+ Lowpass() { }
+
+ void create(int nTaps, double sampleRate, double cutoff)
+ {
+ double wc = 2.0 * M_PI * cutoff;
+ double Wc = wc / sampleRate;
+ int i;
+
+ // check constraints
+ if(!(nTaps & 1)) {
+ qDebug("Lowpass filter has to have an odd number of taps");
+ nTaps++;
+ }
+
+ // make room
+ m_samples.resize(nTaps);
+ for(int i = 0; i < nTaps; i++)
+ m_samples[i] = 0;
+ m_ptr = 0;
+ m_taps.resize(nTaps / 2 + 1);
+
+ // generate Sinc filter core
+ for(i = 0; i < nTaps / 2 + 1; i++) {
+ if(i == (nTaps - 1) / 2)
+ m_taps[i] = Wc / M_PI;
+ else
+ m_taps[i] = sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wc) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI);
+ }
+
+ // apply Hamming window
+ for(i = 0; i < nTaps / 2 + 1; i++)
+ m_taps[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps);
+
+ // normalize
+ Real sum = 0;
+ for(i = 0; i < (int)m_taps.size() - 1; i++)
+ sum += m_taps[i] * 2;
+ sum += m_taps[i];
+ for(i = 0; i < (int)m_taps.size(); i++)
+ m_taps[i] /= sum;
+ }
+
+ Type filter(Type sample)
+ {
+ Type acc = 0;
+ int a = m_ptr;
+ int b = a - 1;
+ int i;
+
+ m_samples[m_ptr] = sample;
+
+ while(b < 0)
+ b += m_samples.size();
+
+ for(i = 0; i < (int)m_taps.size() - 1; i++) {
+ acc += (m_samples[a] + m_samples[b]) * m_taps[i];
+ a++;
+ while(a >= (int)m_samples.size())
+ a -= m_samples.size();
+ b--;
+ while(b < 0)
+ b += m_samples.size();
+ }
+ acc += m_samples[a] * m_taps[i];
+
+ m_ptr++;
+ while(m_ptr >= (int)m_samples.size())
+ m_ptr -= m_samples.size();
+
+ return acc;
+ }
+
+private:
+ std::vector<Real> m_taps;
+ std::vector<Type> m_samples;
+ int m_ptr;
+};
+
+#endif // INCLUDE_LOWPASS_H
diff --git a/include-gpl/dsp/nco.h b/include-gpl/dsp/nco.h
new file mode 100644
index 0000000..7bc9f01
--- /dev/null
+++ b/include-gpl/dsp/nco.h
@@ -0,0 +1,44 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_NCO_H
+#define INCLUDE_NCO_H
+
+#include "dsp/dsptypes.h"
+
+class NCO {
+private:
+ enum {
+ TableSize = (1 << 12),
+ };
+ static Real m_table[TableSize];
+ static bool m_tableInitialized;
+
+ static void initTable();
+
+ int m_phaseIncrement;
+ int m_phase;
+
+public:
+ NCO();
+
+ void setFreq(Real freq, Real sampleRate);
+ Real next();
+ Complex nextIQ();
+};
+
+#endif // INCLUDE_NCO_H
diff --git a/include-gpl/dsp/scopevis.h b/include-gpl/dsp/scopevis.h
new file mode 100644
index 0000000..5631a58
--- /dev/null
+++ b/include-gpl/dsp/scopevis.h
@@ -0,0 +1,43 @@
+#ifndef INCLUDE_SCOPEVIS_H
+#define INCLUDE_SCOPEVIS_H
+
+#include "dsp/samplesink.h"
+
+class GLScope;
+class MessageQueue;
+
+class ScopeVis : public SampleSink {
+public:
+ enum TriggerChannel {
+ TriggerFreeRun,
+ TriggerChannelI,
+ TriggerChannelQ
+ };
+
+ ScopeVis(GLScope* glScope = NULL);
+
+ void configure(MessageQueue* msgQueue, TriggerChannel triggerChannel, Real triggerLevelHigh, Real triggerLevelLow);
+
+ void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst);
+ void start();
+ void stop();
+ bool handleMessage(Message* message);
+
+private:
+ enum TriggerState {
+ Untriggered,
+ Triggered,
+ WaitForReset
+ };
+
+ GLScope* m_glScope;
+ std::vector<Complex> m_trace;
+ int m_fill;
+ TriggerState m_triggerState;
+ TriggerChannel m_triggerChannel;
+ FixReal m_triggerLevelHigh;
+ FixReal m_triggerLevelLow;
+ int m_sampleRate;
+};
+
+#endif // INCLUDE_SCOPEVIS_H
diff --git a/include-gpl/dsp/spectrumvis.h b/include-gpl/dsp/spectrumvis.h
new file mode 100644
index 0000000..0b13c6c
--- /dev/null
+++ b/include-gpl/dsp/spectrumvis.h
@@ -0,0 +1,41 @@
+#ifndef INCLUDE_SPECTRUMVIS_H
+#define INCLUDE_SPECTRUMVIS_H
+
+#include "dsp/samplesink.h"
+#include "dsp/fftengine.h"
+#include "fftwindow.h"
+
+class GLSpectrum;
+class MessageQueue;
+
+class SpectrumVis : public SampleSink {
+public:
+ SpectrumVis(GLSpectrum* glSpectrum = NULL);
+ ~SpectrumVis();
+
+ void configure(MessageQueue* msgQueue, int fftSize, int overlapPercent, FFTWindow::Function window);
+
+ void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst);
+ void start();
+ void stop();
+ bool handleMessage(Message* message);
+
+private:
+ FFTEngine* m_fft;
+ FFTWindow m_window;
+
+ std::vector<Complex> m_fftBuffer;
+ std::vector<Real> m_logPowerSpectrum;
+
+ size_t m_fftSize;
+ size_t m_overlapPercent;
+ size_t m_overlapSize;
+ size_t m_refillSize;
+ size_t m_fftBufferFill;
+
+ GLSpectrum* m_glSpectrum;
+
+ void handleConfigure(int fftSize, int overlapPercent, FFTWindow::Function window);
+};
+
+#endif // INCLUDE_SPECTRUMVIS_H
diff --git a/include-gpl/gui/addpresetdialog.h b/include-gpl/gui/addpresetdialog.h
new file mode 100644
index 0000000..8d3a7ee
--- /dev/null
+++ b/include-gpl/gui/addpresetdialog.h
@@ -0,0 +1,30 @@
+#ifndef INCLUDE_ADDPRESETDIALOG_H
+#define INCLUDE_ADDPRESETDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+ class AddPresetDialog;
+}
+
+class AddPresetDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit AddPresetDialog(const QStringList& groups, const QString& group, QWidget* parent = NULL);
+ ~AddPresetDialog();
+
+ QString group() const;
+ QString description() const;
+
+private:
+ enum Audio {
+ ATDefault,
+ ATInterface,
+ ATDevice
+ };
+
+ Ui::AddPresetDialog* ui;
+};
+
+#endif // INCLUDE_ADDPRESETDIALOG_H
diff --git a/include-gpl/gui/glscope.h b/include-gpl/gui/glscope.h
new file mode 100644
index 0000000..00a3acb
--- /dev/null
+++ b/include-gpl/gui/glscope.h
@@ -0,0 +1,108 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_GLSCOPE_H
+#define INCLUDE_GLSCOPE_H
+
+#include <QGLWidget>
+#include <QPen>
+#include <QTimer>
+#include <QMutex>
+#include "dsp/dsptypes.h"
+#include "dsp/scopevis.h"
+
+class DSPEngine;
+class ScopeVis;
+
+class GLScope: public QGLWidget {
+ Q_OBJECT
+
+public:
+ enum Mode {
+ ModeIQ,
+ ModeMagLinPha,
+ ModeMagdBPha,
+ ModeDerived12
+ };
+
+ GLScope(QWidget* parent = NULL);
+ ~GLScope();
+
+ void setDSPEngine(DSPEngine* dspEngine);
+ void setAmp(Real amp);
+ void setTimeBase(int timeBase);
+ void setTimeOfsProMill(int timeOfsProMill);
+ void setMode(Mode mode);
+ void setOrientation(Qt::Orientation orientation);
+
+ void newTrace(const std::vector<Complex>& trace, int sampleRate);
+
+ int getTraceSize() const { return m_rawTrace.size(); }
+
+signals:
+ void traceSizeChanged(int);
+
+private:
+ // state
+ QTimer m_timer;
+ QMutex m_mutex;
+ bool m_dataChanged;
+ bool m_configChanged;
+ Mode m_mode;
+ Qt::Orientation m_orientation;
+
+ // traces
+ std::vector<Complex> m_rawTrace;
+ std::vector<Complex> m_mathTrace;
+ std::vector<Complex>* m_displayTrace;
+ int m_oldTraceSize;
+ int m_sampleRate;
+ Real m_amp1;
+ Real m_amp2;
+ Real m_ofs1;
+ Real m_ofs2;
+
+ // sample sink
+ DSPEngine* m_dspEngine;
+ ScopeVis* m_scopeVis;
+
+ // config
+ Real m_amp;
+ int m_timeBase;
+ int m_timeOfsProMill;
+ ScopeVis::TriggerChannel m_triggerChannel;
+ Real m_triggerLevelHigh;
+ Real m_triggerLevelLow;
+
+ // graphics stuff
+ QRectF m_glScopeRect1;
+ QRectF m_glScopeRect2;
+
+ void initializeGL();
+ void resizeGL(int width, int height);
+ void paintGL();
+
+ void mousePressEvent(QMouseEvent*);
+
+ void handleMode();
+ void applyConfig();
+
+protected slots:
+ void tick();
+};
+
+#endif // INCLUDE_GLSCOPE_H
diff --git a/include-gpl/gui/glspectrum.h b/include-gpl/gui/glspectrum.h
new file mode 100644
index 0000000..d1b07f5
--- /dev/null
+++ b/include-gpl/gui/glspectrum.h
@@ -0,0 +1,149 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_GLSPECTRUM_H
+#define INCLUDE_GLSPECTRUM_H
+
+#include <QGLWidget>
+#include <QTimer>
+#include <QMutex>
+#include "dsp/dsptypes.h"
+#include "gui/scaleengine.h"
+#include "dsp/channelmarker.h"
+
+class GLSpectrum : public QGLWidget {
+ Q_OBJECT
+
+public:
+ GLSpectrum(QWidget* parent = NULL);
+ ~GLSpectrum();
+
+ void setCenterFrequency(quint64 frequency);
+ void setSampleRate(qint32 sampleRate);
+ void setReferenceLevel(Real referenceLevel);
+ void setPowerRange(Real powerRange);
+ void setDisplayWaterfall(bool display);
+ void setInvertedWaterfall(bool inv);
+ void setDisplayLiveSpectrum(bool display);
+ void setDisplayHistogram(bool display);
+
+ void addChannelMarker(ChannelMarker* channelMarker);
+ void removeChannelMarker(ChannelMarker* channelMarker);
+
+ void newSpectrum(const std::vector<Real>& spectrum, int fftSize);
+
+private:
+ struct ChannelMarkerState {
+ ChannelMarker* m_channelMarker;
+ QRectF m_glRect;
+ QRect m_rect;
+
+ ChannelMarkerState(ChannelMarker* channelMarker) :
+ m_channelMarker(channelMarker),
+ m_glRect()
+ { }
+ };
+ QList<ChannelMarkerState*> m_channelMarkerStates;
+
+ enum CursorState {
+ CSNormal,
+ CSSplitter,
+ CSSplitterMoving,
+ CSChannel,
+ CSChannelMoving
+ };
+
+ CursorState m_cursorState;
+ int m_cursorChannel;
+
+ QTimer m_timer;
+ QMutex m_mutex;
+ bool m_changesPending;
+
+ qint64 m_centerFrequency;
+ Real m_referenceLevel;
+ Real m_powerRange;
+ quint32 m_sampleRate;
+
+ int m_fftSize;
+
+ bool m_invertedWaterfall;
+
+ std::vector<Real> m_liveSpectrum;
+ bool m_displayLiveSpectrum;
+ bool m_liveSpectrumChanged;
+
+ Real m_waterfallShare;
+
+ QPixmap m_leftMarginPixmap;
+ bool m_leftMarginTextureAllocated;
+ GLuint m_leftMarginTexture;
+ QPixmap m_frequencyPixmap;
+ bool m_frequencyTextureAllocated;
+ GLuint m_frequencyTexture;
+ ScaleEngine m_timeScale;
+ ScaleEngine m_powerScale;
+ ScaleEngine m_frequencyScale;
+ QRectF m_glLeftScaleRect;
+ QRectF m_glFrequencyScaleRect;
+ QRect m_frequencyScaleRect;
+
+ QRgb m_waterfallPalette[240];
+ QImage* m_waterfallBuffer;
+ int m_waterfallBufferPos;
+ bool m_waterfallTextureAllocated;
+ GLuint m_waterfallTexture;
+ int m_waterfallTextureHeight;
+ int m_waterfallTexturePos;
+ QRectF m_glWaterfallRect;
+ bool m_displayWaterfall;
+
+ QRgb m_histogramPalette[240];
+ QImage* m_histogramBuffer;
+ quint8* m_histogram;
+ quint8* m_histogramHoldoff;
+ bool m_histogramTextureAllocated;
+ GLuint m_histogramTexture;
+ int m_histogramHoldoffBase;
+ int m_histogramHoldoffCount;
+ int m_histogramLateHoldoff;
+ QRectF m_glHistogramRect;
+ bool m_displayHistogram;
+
+ bool m_displayChanged;
+
+ void updateWaterfall(const std::vector<Real>& spectrum);
+ void updateHistogram(const std::vector<Real>& spectrum);
+
+ void initializeGL();
+ void resizeGL(int width, int height);
+ void paintGL();
+
+ void stopDrag();
+ void applyChanges();
+
+ void mouseMoveEvent(QMouseEvent* event);
+ void mousePressEvent(QMouseEvent* event);
+ void mouseReleaseEvent(QMouseEvent* event);
+
+private slots:
+ void tick();
+ void channelMarkerChanged();
+ void channelMarkerDestroyed(QObject* object);
+};
+
+#endif // INCLUDE_GLSPECTRUM_H
diff --git a/include-gpl/gui/glspectrumgui.h b/include-gpl/gui/glspectrumgui.h
new file mode 100644
index 0000000..0a274dc
--- /dev/null
+++ b/include-gpl/gui/glspectrumgui.h
@@ -0,0 +1,58 @@
+#ifndef INCLUDE_GLSPECTRUMGUI_H
+#define INCLUDE_GLSPECTRUMGUI_H
+
+#include <QWidget>
+#include "dsp/dsptypes.h"
+
+namespace Ui {
+ class GLSpectrumGUI;
+}
+
+class MessageQueue;
+class SpectrumVis;
+class GLSpectrum;
+
+class GLSpectrumGUI : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit GLSpectrumGUI(QWidget* parent = NULL);
+ ~GLSpectrumGUI();
+
+ void setBuddies(MessageQueue* messageQueue, SpectrumVis* spectrumVis, GLSpectrum* glSpectrum);
+
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+
+private:
+ Ui::GLSpectrumGUI* ui;
+
+ MessageQueue* m_messageQueue;
+ SpectrumVis* m_spectrumVis;
+ GLSpectrum* m_glSpectrum;
+
+ qint32 m_fftSize;
+ qint32 m_fftOverlap;
+ qint32 m_fftWindow;
+ Real m_refLevel;
+ Real m_powerRange;
+ bool m_displayWaterfall;
+ bool m_invertedWaterfall;
+ bool m_displayLiveSpectrum;
+ bool m_displayHistogram;
+
+ void applySettings();
+
+private slots:
+ void on_fftSize_valueChanged(int value);
+ void on_fftWindow_currentIndexChanged(int index);
+ void on_refLevel_valueChanged(int value);
+ void on_levelRange_valueChanged(int value);
+ void on_decay_valueChanged(int value);
+ void on_waterfall_toggled(bool checked);
+ void on_histogram_toggled(bool checked);
+ void on_liveSpectrum_toggled(bool checked);
+};
+
+#endif // INCLUDE_GLSPECTRUMGUI_H
diff --git a/include-gpl/gui/indicator.h b/include-gpl/gui/indicator.h
new file mode 100644
index 0000000..a451469
--- /dev/null
+++ b/include-gpl/gui/indicator.h
@@ -0,0 +1,40 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_INDICATOR_H
+#define INCLUDE_INDICATOR_H
+
+#include <QWidget>
+
+class Indicator : public QWidget {
+private:
+ Q_OBJECT;
+
+ QColor m_color;
+ QString m_text;
+
+protected:
+ void paintEvent(QPaintEvent* event);
+ QSize sizeHint() const;
+
+public:
+ Indicator(const QString& text, QWidget* parent = NULL);
+
+ void setColor(const QColor& color);
+};
+
+#endif // INCLUDE_INDICATOR_H
diff --git a/include-gpl/gui/physicalunit.h b/include-gpl/gui/physicalunit.h
new file mode 100644
index 0000000..e8eda2b
--- /dev/null
+++ b/include-gpl/gui/physicalunit.h
@@ -0,0 +1,35 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_PHYSICALUNIT_H
+#define INCLUDE_PHYSICALUNIT_H
+
+namespace Unit {
+ enum Physical {
+ None,
+ Frequency,
+ Information,
+ Percent,
+ Decibel,
+ DecibelMilliWatt,
+ DecibelMicroVolt,
+ AngleDegrees,
+ Time
+ };
+};
+
+#endif // INCLUDE_PHYSICALUNIT_H
diff --git a/include-gpl/gui/pluginsdialog.h b/include-gpl/gui/pluginsdialog.h
new file mode 100644
index 0000000..d0f7305
--- /dev/null
+++ b/include-gpl/gui/pluginsdialog.h
@@ -0,0 +1,22 @@
+#ifndef INCLUDE_PLUGINSDIALOG_H
+#define INCLUDE_PLUGINSDIALOG_H
+
+#include <QDialog>
+#include "plugin/pluginmanager.h"
+
+namespace Ui {
+ class PluginsDialog;
+}
+
+class PluginsDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit PluginsDialog(PluginManager* pluginManager, QWidget* parent = NULL);
+ ~PluginsDialog();
+
+private:
+ Ui::PluginsDialog* ui;
+};
+
+#endif // INCLUDE_PLUGINSDIALOG_H
diff --git a/include-gpl/gui/preferencesdialog.h b/include-gpl/gui/preferencesdialog.h
new file mode 100644
index 0000000..86247f3
--- /dev/null
+++ b/include-gpl/gui/preferencesdialog.h
@@ -0,0 +1,34 @@
+#ifndef INCLUDE_PREFERENCESDIALOG_H
+#define INCLUDE_PREFERENCESDIALOG_H
+
+#include <QDialog>
+
+class AudioDeviceInfo;
+
+namespace Ui {
+ class PreferencesDialog;
+}
+
+class PreferencesDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit PreferencesDialog(AudioDeviceInfo* audioDeviceInfo, QWidget* parent = NULL);
+ ~PreferencesDialog();
+
+private:
+ enum Audio {
+ ATDefault,
+ ATInterface,
+ ATDevice
+ };
+
+ Ui::PreferencesDialog* ui;
+
+ AudioDeviceInfo* m_audioDeviceInfo;
+
+private slots:
+ void accept();
+};
+
+#endif // INCLUDE_PREFERENCESDIALOG_H
diff --git a/include-gpl/gui/presetitem.h b/include-gpl/gui/presetitem.h
new file mode 100644
index 0000000..fa45543
--- /dev/null
+++ b/include-gpl/gui/presetitem.h
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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 <QTreeWidgetItem>
+
+class PresetItem : public QTreeWidgetItem {
+public:
+ PresetItem(QTreeWidgetItem* parent, const QStringList& strings, quint64 frequency, int type);
+ bool operator<(const QTreeWidgetItem& other) const;
+
+private:
+ quint64 m_frequency;
+};
diff --git a/include-gpl/gui/scale.h b/include-gpl/gui/scale.h
new file mode 100644
index 0000000..b9c3b34
--- /dev/null
+++ b/include-gpl/gui/scale.h
@@ -0,0 +1,36 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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 <QWidget>
+#include "gui/scaleengine.h"
+
+class Scale : public QWidget {
+ Q_OBJECT
+
+public:
+ Scale(QWidget* parent = NULL);
+
+ void setOrientation(Qt::Orientation orientation);
+ void setRange(Unit::Physical physicalUnit, float rangeMin, float rangeMax);
+
+private:
+ Qt::Orientation m_orientation;
+ ScaleEngine m_scaleEngine;
+
+ void paintEvent(QPaintEvent*);
+ void resizeEvent(QResizeEvent*);
+};
diff --git a/include-gpl/gui/scaleengine.h b/include-gpl/gui/scaleengine.h
new file mode 100644
index 0000000..3774116
--- /dev/null
+++ b/include-gpl/gui/scaleengine.h
@@ -0,0 +1,89 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_SCALEENGINE_H
+#define INCLUDE_SCALEENGINE_H
+
+#include <QFont>
+#include <QString>
+#include <QList>
+#include "physicalunit.h"
+
+class ScaleEngine {
+public:
+ struct Tick {
+ float pos;
+ bool major;
+ float textPos;
+ float textSize;
+ QString text;
+ };
+ typedef QList<Tick> TickList;
+
+private:
+ // base configuration
+ Qt::Orientation m_orientation;
+ QFont m_font;
+ float m_charSize;
+
+ // graph configuration
+ float m_size;
+ Unit::Physical m_physicalUnit;
+ float m_rangeMin;
+ float m_rangeMax;
+
+ // calculated values
+ bool m_recalc;
+ double m_scale;
+ QString m_unitStr;
+ TickList m_tickList;
+ double m_majorTickValueDistance;
+ double m_firstMajorTickValue;
+ int m_numMinorTicks;
+ int m_decimalPlaces;
+
+ QString formatTick(double value, int decimalPlaces, bool fancyTime = true);
+ void calcCharSize();
+ void calcScaleFactor();
+ double calcMajorTickUnits(double distance, int* retDecimalPlaces);
+ int calcTickTextSize();
+ void forceTwoTicks();
+ void reCalc();
+
+ double majorTickValue(int tick);
+ double minorTickValue(int tick);
+
+public:
+ ScaleEngine();
+
+ void setOrientation(Qt::Orientation orientation);
+ void setFont(const QFont& font);
+ void setSize(float size);
+ float getSize() { return m_size; }
+ void setRange(Unit::Physical physicalUnit, float rangeMin, float rangeMax);
+
+ float getPosFromValue(double value);
+ float getValueFromPos(double pos);
+ const TickList& getTickList();
+
+ QString getRangeMinStr();
+ QString getRangeMaxStr();
+
+ float getScaleWidth();
+};
+
+#endif // INCLUDE_SCALEENGINE_H
diff --git a/include-gpl/gui/scopewindow.h b/include-gpl/gui/scopewindow.h
new file mode 100644
index 0000000..281a848
--- /dev/null
+++ b/include-gpl/gui/scopewindow.h
@@ -0,0 +1,66 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_SCOPEWINDOW_H
+#define INCLUDE_SCOPEWINDOW_H
+
+#include <QWidget>
+#include "dsp/dsptypes.h"
+
+class DSPEngine;
+
+namespace Ui {
+ class ScopeWindow;
+}
+
+class ScopeWindow : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ScopeWindow(DSPEngine* dspEngine, QWidget* parent = NULL);
+ ~ScopeWindow();
+
+ void setSampleRate(int sampleRate);
+
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+
+private slots:
+ void on_amp_valueChanged(int value);
+ void on_scope_traceSizeChanged(int value);
+ void on_time_valueChanged(int value);
+ void on_timeOfs_valueChanged(int value);
+ void on_displayMode_currentIndexChanged(int index);
+
+ void on_horizView_clicked();
+ void on_vertView_clicked();
+
+private:
+ Ui::ScopeWindow *ui;
+ int m_sampleRate;
+
+ qint32 m_displayData;
+ qint32 m_displayOrientation;
+ qint32 m_timeBase;
+ qint32 m_timeOffset;
+ qint32 m_amplification;
+
+ void applySettings();
+};
+
+#endif // INCLUDE_SCOPEWINDOW_H
diff --git a/include-gpl/gui/valuedial.h b/include-gpl/gui/valuedial.h
new file mode 100644
index 0000000..8e660b9
--- /dev/null
+++ b/include-gpl/gui/valuedial.h
@@ -0,0 +1,71 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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 <QWidget>
+#include <QTimer>
+
+class ValueDial : public QWidget {
+ Q_OBJECT
+
+public:
+ ValueDial(QWidget* parent = NULL);
+
+ void setValue(quint64 value);
+ void setValueRange(uint numDigits, quint64 min, quint64 max);
+ void setFont(const QFont& font);
+
+signals:
+ void changed(quint64 value);
+
+private:
+ QLinearGradient m_background;
+ int m_numDigits;
+ int m_numDecimalPoints;
+ int m_digitWidth;
+ int m_digitHeight;
+ int m_hightlightedDigit;
+ int m_cursor;
+ bool m_cursorState;
+ quint64 m_value;
+ quint64 m_valueMax;
+ quint64 m_valueMin;
+ QString m_text;
+
+ quint64 m_valueNew;
+ QString m_textNew;
+ int m_animationState;
+ QTimer m_animationTimer;
+ QTimer m_blinkTimer;
+
+ quint64 findExponent(int digit);
+ QChar digitNeigh(QChar c, bool dir);
+ QString formatText(quint64 value);
+
+ void paintEvent(QPaintEvent*);
+
+ void mousePressEvent(QMouseEvent*);
+ void mouseMoveEvent(QMouseEvent*);
+ void wheelEvent(QWheelEvent*);
+ void leaveEvent(QEvent*);
+ void keyPressEvent(QKeyEvent*);
+ void focusInEvent(QFocusEvent*);
+ void focusOutEvent(QFocusEvent*);
+
+private slots:
+ void animate();
+ void blink();
+};
diff --git a/include-gpl/mainwindow.h b/include-gpl/mainwindow.h
new file mode 100644
index 0000000..9848962
--- /dev/null
+++ b/include-gpl/mainwindow.h
@@ -0,0 +1,135 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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_MAINWINDOW_H
+#define INCLUDE_MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QTimer>
+#include "audio/portaudioholder.h"
+#include "settings/settings.h"
+
+class QLabel;
+class QTreeWidgetItem;
+class QDir;
+
+class AudioDeviceInfo;
+class DSPEngine;
+class Indicator;
+class ScopeWindow;
+class SpectrumVis;
+class SampleSource;
+class PluginAPI;
+class PluginGUI;
+class ChannelMarker;
+class MessageQueue;
+class PluginManager;
+class PluginInterface;
+
+namespace Ui {
+ class MainWindow;
+}
+
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget* parent = NULL);
+ ~MainWindow();
+
+ MessageQueue* getMessageQueue() { return m_messageQueue; }
+
+ void addDemodCreateAction(QAction* action);
+ void addViewAction(QAction* action);
+
+ void addChannelMarker(ChannelMarker* channelMarker);
+ void removeChannelMarker(ChannelMarker* channelMarker);
+
+ void setInputGUI(QWidget* gui);
+
+private:
+ enum {
+ PGroup,
+ PItem
+ };
+
+ Ui::MainWindow *ui;
+
+ PortAudioHolder m_portAudioHolder;
+ AudioDeviceInfo* m_audioDeviceInfo;
+
+ MessageQueue* m_messageQueue;
+
+ Settings m_settings;
+
+ SpectrumVis* m_spectrumVis;
+
+ DSPEngine* m_dspEngine;
+
+ QTimer m_statusTimer;
+ int m_lastEngineState;
+
+ QLabel* m_sampleRateWidget;
+ Indicator* m_engineIdle;
+ Indicator* m_engineRunning;
+ Indicator* m_engineError;
+
+ bool m_startOsmoSDRUpdateAfterStop;
+
+ ScopeWindow* m_scopeWindow;
+ QWidget* m_inputGUI;
+
+ int m_sampleRate;
+ quint64 m_centerFrequency;
+
+ PluginManager* m_pluginManager;
+
+ void loadSettings();
+ void loadSettings(const Preset* preset);
+ void saveSettings(Preset* preset);
+ void saveSettings();
+
+ void createStatusBar();
+ void closeEvent(QCloseEvent*);
+ void updateCenterFreqDisplay();
+ void updateSampleRate();
+ void updatePresets();
+ QTreeWidgetItem* addPresetToTree(const Preset* preset);
+ void applySettings();
+
+private slots:
+ void handleMessages();
+ void updateStatus();
+ void scopeWindowDestroyed();
+ void on_action_Start_triggered();
+ void on_action_Stop_triggered();
+ void on_dcOffset_toggled(bool checked);
+ void on_iqImbalance_toggled(bool checked);
+ void on_action_View_Fullscreen_toggled(bool checked);
+ void on_actionOsmoSDR_Firmware_Upgrade_triggered();
+ void on_presetSave_clicked();
+ void on_presetLoad_clicked();
+ void on_presetDelete_clicked();
+ void on_presetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
+ void on_presetTree_itemActivated(QTreeWidgetItem *item, int column);
+ void on_action_Oscilloscope_triggered();
+ void on_action_Loaded_Plugins_triggered();
+ void on_action_Preferences_triggered();
+ void on_sampleSource_currentIndexChanged(int index);
+};
+
+#endif // INCLUDE_MAINWINDOW_H
diff --git a/include-gpl/plugin/pluginmanager.h b/include-gpl/plugin/pluginmanager.h
new file mode 100644
index 0000000..50f39f3
--- /dev/null
+++ b/include-gpl/plugin/pluginmanager.h
@@ -0,0 +1,127 @@
+#ifndef INCLUDE_PLUGINMANAGER_H
+#define INCLUDE_PLUGINMANAGER_H
+
+#include <QObject>
+#include <QDir>
+#include "plugin/plugininterface.h"
+#include "plugin/pluginapi.h"
+
+class QAction;
+class QComboBox;
+class Preset;
+class MainWindow;
+class SampleSource;
+class Message;
+
+class PluginManager : public QObject {
+ Q_OBJECT
+
+public:
+ struct Plugin {
+ QString filename;
+ PluginInterface* plugin;
+ Plugin(const QString& _filename, PluginInterface* _plugin) :
+ filename(_filename),
+ plugin(_plugin)
+ { }
+ };
+ typedef QList<Plugin> Plugins;
+
+ explicit PluginManager(MainWindow* mainWindow, DSPEngine* dspEngine, QObject* parent = NULL);
+ ~PluginManager();
+ void loadPlugins();
+
+ const Plugins& getPlugins() const { return m_plugins; }
+
+ void registerDemodulator(const QString& demodName, PluginInterface* plugin, QAction* action);
+ void registerDemodulatorInstance(const QString& demodName, PluginGUI* pluginGUI);
+
+ void registerSampleSource(const QString& sourceName, PluginInterface* plugin);
+
+ void loadSettings(const Preset* preset);
+ void saveSettings(Preset* preset) const;
+
+ void freeAll();
+
+ bool handleMessage(Message* message);
+
+ void updateSampleSourceDevices();
+ void fillSampleSourceSelector(QComboBox* comboBox);
+ int selectSampleSource(int index);
+
+private slots:
+ void demodInstanceDestroyed(QObject* object);
+
+private:
+ struct DemodRegistration {
+ QString m_demodName;
+ PluginInterface* m_plugin;
+ DemodRegistration(const QString& demodName, PluginInterface* plugin) :
+ m_demodName(demodName),
+ m_plugin(plugin)
+ { }
+ };
+ typedef QList<DemodRegistration> DemodRegistrations;
+
+ struct DemodInstanceRegistration {
+ QString m_demodName;
+ PluginGUI* m_gui;
+ DemodInstanceRegistration() :
+ m_demodName(),
+ m_gui(NULL)
+ { }
+ DemodInstanceRegistration(const QString& demodName, PluginGUI* pluginGUI) :
+ m_demodName(demodName),
+ m_gui(pluginGUI)
+ { }
+ };
+ typedef QList<DemodInstanceRegistration> DemodInstanceRegistrations;
+
+ struct SampleSourceRegistration {
+ QString m_sourceName;
+ PluginInterface* m_plugin;
+ SampleSourceRegistration(const QString& sourceName, PluginInterface* plugin) :
+ m_sourceName(sourceName),
+ m_plugin(plugin)
+ { }
+ };
+ typedef QList<SampleSourceRegistration> SampleSourceRegistrations;
+
+ struct SampleSourceDevice {
+ PluginInterface* m_plugin;
+ QString m_displayName;
+ QString m_sourceName;
+ QByteArray m_address;
+
+ SampleSourceDevice(PluginInterface* plugin, const QString& displayName, const QString& sourceName, const QByteArray& address) :
+ m_plugin(plugin),
+ m_displayName(displayName),
+ m_sourceName(sourceName),
+ m_address(address)
+ { }
+ };
+ typedef QList<SampleSourceDevice> SampleSourceDevices;
+
+ PluginAPI m_pluginAPI;
+ MainWindow* m_mainWindow;
+ DSPEngine* m_dspEngine;
+ Plugins m_plugins;
+
+ DemodRegistrations m_demodRegistrations;
+ DemodInstanceRegistrations m_demodInstanceRegistrations;
+ SampleSourceRegistrations m_sampleSourceRegistrations;
+ SampleSourceDevices m_sampleSourceDevices;
+
+ QString m_sampleSource;
+ PluginGUI* m_sampleSourceInstance;
+
+ void loadPlugins(const QDir& dir);
+ void renameDemodInstances();
+};
+
+static inline bool operator<(const PluginManager::Plugin& a, const PluginManager::Plugin& b)
+{
+ return a.plugin->getPluginDescriptor().displayedName < b.plugin->getPluginDescriptor().displayedName;
+}
+
+#endif // INCLUDE_PLUGINMANAGER_H
diff --git a/include-gpl/settings/preferences.h b/include-gpl/settings/preferences.h
new file mode 100644
index 0000000..74de287
--- /dev/null
+++ b/include-gpl/settings/preferences.h
@@ -0,0 +1,32 @@
+#ifndef INCLUDE_PREFERENCES_H
+#define INCLUDE_PREFERENCES_H
+
+#include <QString>
+
+class Preferences {
+public:
+ Preferences();
+
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+
+ void setSourceType(const QString& value) { m_sourceType = value; }
+ const QString& getSourceType() const { return m_sourceType; }
+ void setSourceDevice(const QString& value) { m_sourceDevice= value; }
+ const QString& getSourceDevice() const { return m_sourceDevice; }
+
+ void setAudioType(const QString& value) { m_audioType = value; }
+ const QString& getAudioType() const { return m_audioType; }
+ void setAudioDevice(const QString& value) { m_audioDevice= value; }
+ const QString& getAudioDevice() const { return m_audioDevice; }
+
+protected:
+ QString m_sourceType;
+ QString m_sourceDevice;
+
+ QString m_audioType;
+ QString m_audioDevice;
+};
+
+#endif // INCLUDE_PREFERENCES_H
diff --git a/include-gpl/settings/preset.h b/include-gpl/settings/preset.h
new file mode 100644
index 0000000..f872941
--- /dev/null
+++ b/include-gpl/settings/preset.h
@@ -0,0 +1,98 @@
+#ifndef INCLUDE_PRESET_H
+#define INCLUDE_PRESET_H
+
+#include <QString>
+#include <QList>
+#include <QMetaType>
+
+class Preset {
+public:
+ struct DemodConfig {
+ QString m_demod;
+ QByteArray m_config;
+
+ DemodConfig(const QString& demod, const QByteArray& config) :
+ m_demod(demod),
+ m_config(config)
+ { }
+ };
+ typedef QList<DemodConfig> DemodConfigs;
+
+ Preset();
+
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+
+ void setGroup(const QString& group) { m_group = group; }
+ const QString& getGroup() const { return m_group; }
+ void setDescription(const QString& description) { m_description = description; }
+ const QString& getDescription() const { return m_description; }
+ void setCenterFrequency(const quint64 centerFrequency) { m_centerFrequency = centerFrequency; }
+ quint64 getCenterFrequency() const { return m_centerFrequency; }
+
+ void setSpectrumConfig(const QByteArray& data) { m_spectrumConfig = data; }
+ const QByteArray& getSpectrumConfig() const { return m_spectrumConfig; }
+
+ void setShowScope(bool value) { m_showScope = value; }
+ bool getShowScope() const { return m_showScope; }
+
+ void setLayout(const QByteArray& data) { m_layout = data; }
+ const QByteArray& getLayout() const { return m_layout; }
+
+ void setDCOffsetCorrection(bool value) { m_dcOffsetCorrection = value; }
+ bool getDCOffsetCorrection() const { return m_dcOffsetCorrection; }
+
+ void setIQImbalanceCorrection(bool value) { m_iqImbalanceCorrection = value; }
+ bool getIQImbalanceCorrection() const { return m_iqImbalanceCorrection; }
+
+ void setScopeConfig(const QByteArray& data) { m_scopeConfig = data; }
+ const QByteArray& getScopeConfig() const { return m_scopeConfig; }
+
+ void clearDemods() { m_demodConfigs.clear(); }
+ void addDemod(const QString& demod, const QByteArray& config) { m_demodConfigs.append(DemodConfig(demod, config)); }
+ int getDemodCount() const { return m_demodConfigs.count(); }
+ const DemodConfig& getDemodConfig(int index) const { return m_demodConfigs.at(index); }
+
+ void setSourceConfig(const QString& source, const QByteArray& generalConfig, const QByteArray& config)
+ {
+ m_source = source;
+ m_sourceGeneralConfig = generalConfig;
+ m_sourceConfig = config;
+ }
+ const QString& getSource() const { return m_source; }
+ const QByteArray& getSourceGeneralConfig() const { return m_sourceGeneralConfig; }
+ const QByteArray& getSourceConfig() const { return m_sourceConfig; }
+
+protected:
+ // group and preset description
+ QString m_group;
+ QString m_description;
+ quint64 m_centerFrequency;
+
+ // general configuration
+ QByteArray m_spectrumConfig;
+ QByteArray m_scopeConfig;
+
+ // dc offset and i/q imbalance correction
+ bool m_dcOffsetCorrection;
+ bool m_iqImbalanceCorrection;
+
+ // display scope dock
+ bool m_showScope;
+
+ // sample source and sample source configuration
+ QString m_source;
+ QByteArray m_sourceGeneralConfig;
+ QByteArray m_sourceConfig;
+
+ // demodulators and configurations
+ DemodConfigs m_demodConfigs;
+
+ // screen and dock layout
+ QByteArray m_layout;
+};
+
+Q_DECLARE_METATYPE(const Preset*)
+
+#endif // INCLUDE_PRESET_H
diff --git a/include-gpl/settings/settings.h b/include-gpl/settings/settings.h
new file mode 100644
index 0000000..a6cf04f
--- /dev/null
+++ b/include-gpl/settings/settings.h
@@ -0,0 +1,32 @@
+#ifndef INCLUDE_SETTINGS_H
+#define INCLUDE_SETTINGS_H
+
+#include <QString>
+#include "preferences.h"
+#include "preset.h"
+
+class Settings {
+public:
+ Settings();
+ ~Settings();
+
+ void load();
+ void save() const;
+
+ void resetToDefaults();
+
+ Preset* newPreset(const QString& group, const QString& description);
+ void deletePreset(const Preset* preset);
+ int getPresetCount() const { return m_presets.count(); }
+ const Preset* getPreset(int index) const { return m_presets[index]; }
+
+ Preset* getCurrent() { return &m_current; }
+
+protected:
+ Preferences m_preferences;
+ Preset m_current;
+ typedef QList<Preset*> Presets;
+ Presets m_presets;
+};
+
+#endif // INCLUDE_SETTINGS_H