1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-06-05 15:34:57 -04:00

git clone git://git.osmocom.org/sdrangelove.git

This commit is contained in:
Hexameron
2014-05-18 16:52:39 +01:00
commit 7d3bfb26fc
203 changed files with 27958 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// 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
+65
View File
@@ -0,0 +1,65 @@
///////////////////////////////////////////////////////////////////////////////////
// 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>
#include "util/export.h"
class SDRANGELOVE_API 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
+57
View File
@@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <QIODevice>
#include <list>
#include <vector>
#include "util/export.h"
class QAudioOutput;
class AudioFifo;
class AudioOutputPipe;
class SDRANGELOVE_API AudioOutput : QIODevice {
public:
AudioOutput();
~AudioOutput();
bool start(int device, int rate);
void stop();
void addFifo(AudioFifo* audioFifo);
void removeFifo(AudioFifo* audioFifo);
private:
QMutex m_mutex;
QAudioOutput* m_audioOutput;
typedef std::list<AudioFifo*> AudioFifos;
AudioFifos m_audioFifos;
std::vector<qint32> m_mixBuffer;
bool open(OpenMode mode);
qint64 readData(char* data, qint64 maxLen);
qint64 writeData(const char* data, qint64 len);
friend class AudioOutputPipe;
};
#endif // INCLUDE_AUDIOOUTPUT_H
+109
View File
@@ -0,0 +1,109 @@
#ifndef INCLUDE_CHANNELIZER_H
#define INCLUDE_CHANNELIZER_H
#include <list>
#include "dsp/samplesink.h"
#include "util/export.h"
class MessageQueue;
class IntHalfbandFilter;
class SDRANGELOVE_API 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
+255
View File
@@ -0,0 +1,255 @@
#ifndef INCLUDE_DSPCOMMANDS_H
#define INCLUDE_DSPCOMMANDS_H
#include <QString>
#include "util/message.h"
#include "fftwindow.h"
#include "util/export.h"
class SampleSource;
class SampleSink;
class AudioFifo;
class SDRANGELOVE_API DSPPing : public Message {
MESSAGE_CLASS_DECLARATION
};
class SDRANGELOVE_API DSPExit : public Message {
MESSAGE_CLASS_DECLARATION
};
class SDRANGELOVE_API DSPAcquisitionStart : public Message {
MESSAGE_CLASS_DECLARATION
};
class SDRANGELOVE_API DSPAcquisitionStop : public Message {
MESSAGE_CLASS_DECLARATION
};
class SDRANGELOVE_API DSPGetDeviceDescription : public Message {
MESSAGE_CLASS_DECLARATION
public:
void setDeviceDescription(const QString& text) { m_deviceDescription = text; }
const QString& getDeviceDescription() const { return m_deviceDescription; }
private:
QString m_deviceDescription;
};
class SDRANGELOVE_API DSPGetErrorMessage : public Message {
MESSAGE_CLASS_DECLARATION
public:
void setErrorMessage(const QString& text) { m_errorMessage = text; }
const QString& getErrorMessage() const { return m_errorMessage; }
private:
QString m_errorMessage;
};
class SDRANGELOVE_API DSPSetSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPSetSource(SampleSource* sampleSource) : Message(), m_sampleSource(sampleSource) { }
SampleSource* getSampleSource() const { return m_sampleSource; }
private:
SampleSource* m_sampleSource;
};
class SDRANGELOVE_API DSPAddSink : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPAddSink(SampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
SampleSink* getSampleSink() const { return m_sampleSink; }
private:
SampleSink* m_sampleSink;
};
class SDRANGELOVE_API DSPRemoveSink : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPRemoveSink(SampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
SampleSink* getSampleSink() const { return m_sampleSink; }
private:
SampleSink* m_sampleSink;
};
class SDRANGELOVE_API DSPAddAudioSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPAddAudioSource(AudioFifo* audioFifo) : Message(), m_audioFifo(audioFifo) { }
AudioFifo* getAudioFifo() const { return m_audioFifo; }
private:
AudioFifo* m_audioFifo;
};
class SDRANGELOVE_API DSPRemoveAudioSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPRemoveAudioSource(AudioFifo* audioFifo) : Message(), m_audioFifo(audioFifo) { }
AudioFifo* getAudioFifo() const { return m_audioFifo; }
private:
AudioFifo* m_audioFifo;
};
class SDRANGELOVE_API DSPConfigureSpectrumVis : public Message {
MESSAGE_CLASS_DECLARATION
public:
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(),
m_fftSize(fftSize),
m_overlapPercent(overlapPercent),
m_window(window)
{ }
};
class SDRANGELOVE_API DSPConfigureCorrection : public Message {
MESSAGE_CLASS_DECLARATION
public:
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(),
m_dcOffsetCorrection(dcOffsetCorrection),
m_iqImbalanceCorrection(iqImbalanceCorrection)
{ }
};
class SDRANGELOVE_API DSPEngineReport : public Message {
MESSAGE_CLASS_DECLARATION
public:
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(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
class SDRANGELOVE_API DSPConfigureScopeVis : public Message {
MESSAGE_CLASS_DECLARATION
public:
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(),
m_triggerChannel(triggerChannel),
m_triggerLevelHigh(triggerLevelHigh),
m_triggerLevelLow(triggerLevelLow)
{ }
};
class SDRANGELOVE_API DSPSignalNotification : public Message {
MESSAGE_CLASS_DECLARATION
public:
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(),
m_sampleRate(samplerate),
m_frequencyOffset(frequencyOffset)
{ }
};
class SDRANGELOVE_API DSPConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
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(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
#endif // INCLUDE_DSPCOMMANDS_H
+119
View File
@@ -0,0 +1,119 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
#include "util/export.h"
class SampleSource;
class SampleSink;
class AudioFifo;
class SDRANGELOVE_API 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;
uint 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
+20
View File
@@ -0,0 +1,20 @@
#ifndef INCLUDE_FFTENGINE_H
#define INCLUDE_FFTENGINE_H
#include "dsp/dsptypes.h"
#include "util/export.h"
class SDRANGELOVE_API 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
+37
View File
@@ -0,0 +1,37 @@
#ifndef INCLUDE_FFTWENGINE_H
#define INCLUDE_FFTWENGINE_H
#include <QMutex>
#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:
static QMutex m_globalPlanMutex;
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
+82
View File
@@ -0,0 +1,82 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
#include "util/export.h"
class SDRANGELOVE_API 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
+130
View File
@@ -0,0 +1,130 @@
#ifndef INCLUDE_INTERPOLATOR_H
#define INCLUDE_INTERPOLATOR_H
#include <immintrin.h>
#include "dsp/dsptypes.h"
#include "util/export.h"
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#endif
class SDRANGELOVE_API Interpolator {
public:
Interpolator();
~Interpolator();
void create(int phaseSteps, double sampleRate, double cutoff);
void free();
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:
float* m_taps;
float* m_alignedTaps;
float* m_taps2;
float* m_alignedTaps2;
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 - 1;
m_samples[m_ptr] = next;
}
void doInterpolate(int phase, Complex* result)
{
#if 1
// beware of the ringbuffer
if(m_ptr == 0) {
// only one straight block
const float* src = (const float*)&m_samples[0];
const __m128* filter = (const __m128*)&m_alignedTaps[phase * m_nTaps * 2];
__m128 sum = _mm_setzero_ps();
int todo = m_nTaps / 2;
for(int i = 0; i < todo; i++) {
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(src), *filter));
src += 4;
filter += 1;
}
// add upper half to lower half and store
_mm_storel_pi((__m64*)result, _mm_add_ps(sum, _mm_shuffle_ps(sum, _mm_setzero_ps(), _MM_SHUFFLE(1, 0, 3, 2))));
} else {
// two blocks
const float* src = (const float*)&m_samples[m_ptr];
const __m128* filter = (const __m128*)&m_alignedTaps[phase * m_nTaps * 2];
__m128 sum = _mm_setzero_ps();
// first block
int block = m_nTaps - m_ptr;
int todo = block / 2;
if(block & 1)
todo++;
for(int i = 0; i < todo; i++) {
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(src), *filter));
src += 4;
filter += 1;
}
if(block & 1) {
// one sample beyond the end -> switch coefficient table
filter = (const __m128*)&m_alignedTaps2[phase * m_nTaps * 2 + todo * 4 - 4];
}
// second block
src = (const float*)&m_samples[0];
block = m_ptr;
todo = block / 2;
for(int i = 0; i < todo; i++) {
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(src), *filter));
src += 4;
filter += 1;
}
if(block & 1) {
// one sample remaining
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadl_pi(_mm_setzero_ps(), (const __m64*)src), filter[0]));
}
// add upper half to lower half and store
_mm_storel_pi((__m64*)result, _mm_add_ps(sum, _mm_shuffle_ps(sum, _mm_setzero_ps(), _MM_SHUFFLE(1, 0, 3, 2))));
}
#else
int sample = m_ptr;
const Real* coeff = &m_alignedTaps[phase * m_nTaps * 2];
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 = (sample + 1) % m_nTaps;
coeff += 2;
}
*result = Complex(rAcc, iAcc);
#endif
}
};
#endif // INCLUDE_INTERPOLATOR_H
+314
View File
@@ -0,0 +1,314 @@
#ifndef INCLUDE_INTHALFBANDFILTER_H
#define INCLUDE_INTHALFBANDFILTER_H
#include <QtGlobal>
#include "dsp/dsptypes.h"
#include "util/export.h"
// uses Q1.14 format internally, input and output are S16
/*
* supported filter orders: 64, 48, 32
*/
#define HB_FILTERORDER 32
#define HB_SHIFT 14
class SDRANGELOVE_API 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) % (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) % (HB_FILTERORDER + 1);
// next state
m_state = 0;
// tell caller we have a new sample
return true;
}
}
// downsample by 2, return edges of spectrum rotated into center
bool workDecimateFullRotate(Sample* sample)
{
switch(m_state) {
case 0:
// insert sample into ring-buffer
m_samples[m_ptr][0] = sample->real();
m_samples[m_ptr][1] = sample->imag();
// advance write-pointer
m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
// next state
m_state = 1;
// 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) % (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) % (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) % (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) % (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) % (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) % (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) % (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) % (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) % (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) % (HB_FILTERORDER + 1);
int b = (m_ptr + (HB_FILTERORDER - 1)) % (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) % (HB_FILTERORDER + 1);
b = (b + (HB_FILTERORDER - 1)) % (HB_FILTERORDER + 1);
}
a = (a + HB_FILTERORDER) % (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
+23
View File
@@ -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
+88
View File
@@ -0,0 +1,88 @@
#ifndef INCLUDE_LOWPASS_H
#define INCLUDE_LOWPASS_H
#define _USE_MATH_DEFINES
#include <math.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
+53
View File
@@ -0,0 +1,53 @@
#ifndef INCLUDE_MOVINGAVERAGE_H
#define INCLUDE_MOVINGAVERAGE_H
#include <vector>
#include "dsp/dsptypes.h"
class MovingAverage {
public:
MovingAverage() :
m_history(),
m_sum(0),
m_ptr(0)
{
}
MovingAverage(int historySize, Real initial) :
m_history(historySize, initial),
m_sum(historySize * initial),
m_ptr(0)
{
}
void resize(int historySize, Real initial)
{
m_history.resize(historySize);
for(size_t i = 0; i < m_history.size(); i++)
m_history[i] = initial;
m_sum = m_history.size() * initial;
m_ptr = 0;
}
void feed(Real value)
{
m_sum -= m_history[m_ptr];
m_history[m_ptr] = value;
m_sum += value;
m_ptr++;
if(m_ptr >= m_history.size())
m_ptr = 0;
}
Real average() const
{
return m_sum / (Real)m_history.size();
}
protected:
std::vector<Real> m_history;
Real m_sum;
uint m_ptr;
};
#endif // INCLUDE_MOVINGAVERAGE_H
+45
View File
@@ -0,0 +1,45 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
#include "util/export.h"
class SDRANGELOVE_API 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
+44
View File
@@ -0,0 +1,44 @@
#ifndef INCLUDE_SCOPEVIS_H
#define INCLUDE_SCOPEVIS_H
#include "dsp/samplesink.h"
#include "util/export.h"
class GLScope;
class MessageQueue;
class SDRANGELOVE_API 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;
uint m_fill;
TriggerState m_triggerState;
TriggerChannel m_triggerChannel;
FixReal m_triggerLevelHigh;
FixReal m_triggerLevelLow;
int m_sampleRate;
};
#endif // INCLUDE_SCOPEVIS_H
+42
View File
@@ -0,0 +1,42 @@
#ifndef INCLUDE_SPECTRUMVIS_H
#define INCLUDE_SPECTRUMVIS_H
#include "dsp/samplesink.h"
#include "dsp/fftengine.h"
#include "fftwindow.h"
#include "util/export.h"
class GLSpectrum;
class MessageQueue;
class SDRANGELOVE_API 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
+21
View File
@@ -0,0 +1,21 @@
#ifndef INCLUDE_ABOUTDIALOG_H
#define INCLUDE_ABOUTDIALOG_H
#include <QDialog>
namespace Ui {
class AboutDialog;
}
class AboutDialog : public QDialog {
Q_OBJECT
public:
explicit AboutDialog(QWidget* parent = NULL);
~AboutDialog();
private:
Ui::AboutDialog* ui;
};
#endif // INCLUDE_ABOUTDIALOG_H
+30
View File
@@ -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
+19
View File
@@ -0,0 +1,19 @@
#ifndef INCLUDE_BUTTONSWITCH_H
#define INCLUDE_BUTTONSWITCH_H
#include <QToolButton>
class ButtonSwitch : public QToolButton {
Q_OBJECT
public:
ButtonSwitch(QWidget* parent = NULL);
private slots:
void onToggled(bool checked);
private:
QPalette m_originalPalette;
};
#endif // INCLUDE_BUTTONSWITCH_H
+25
View File
@@ -0,0 +1,25 @@
#ifndef INCLUDE_CHANNELWINDOW_H
#define INCLUDE_CHANNELWINDOW_H
#include <QScrollArea>
class QBoxLayout;
class QSpacerItem;
class RollupWidget;
class ChannelWindow : public QScrollArea {
Q_OBJECT
public:
ChannelWindow(QWidget* parent = NULL);
void addRollupWidget(QWidget* rollupWidget);
protected:
QWidget* m_container;
QBoxLayout* m_layout;
void resizeEvent(QResizeEvent* event);
};
#endif // INCLUDE_CHANNELWINDOW_H
+110
View File
@@ -0,0 +1,110 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
#include "util/export.h"
class DSPEngine;
class ScopeVis;
class SDRANGELOVE_API GLScope: public QGLWidget {
Q_OBJECT
public:
enum Mode {
ModeIQ,
ModeMagLinPha,
ModeMagdBPha,
ModeDerived12,
ModeCyclostationary
};
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
+157
View File
@@ -0,0 +1,157 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
#include "util/export.h"
class SDRANGELOVE_API 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 setDecay(int decay);
void setDisplayWaterfall(bool display);
void setInvertedWaterfall(bool inv);
void setDisplayMaxHold(bool display);
void setDisplayHistogram(bool display);
void setDisplayGrid(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_mouseInside;
bool m_changesPending;
qint64 m_centerFrequency;
Real m_referenceLevel;
Real m_powerRange;
int m_decay;
quint32 m_sampleRate;
int m_fftSize;
bool m_displayGrid;
bool m_invertedWaterfall;
std::vector<Real> m_maxHold;
bool m_displayMaxHold;
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);
void enterEvent(QEvent* event);
void leaveEvent(QEvent* event);
private slots:
void tick();
void channelMarkerChanged();
void channelMarkerDestroyed(QObject* object);
};
#endif // INCLUDE_GLSPECTRUM_H
+65
View File
@@ -0,0 +1,65 @@
#ifndef INCLUDE_GLSPECTRUMGUI_H
#define INCLUDE_GLSPECTRUMGUI_H
#include <QWidget>
#include "dsp/dsptypes.h"
#include "util/export.h"
namespace Ui {
class GLSpectrumGUI;
}
class MessageQueue;
class SpectrumVis;
class GLSpectrum;
class SDRANGELOVE_API 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;
int m_decay;
bool m_displayWaterfall;
bool m_invertedWaterfall;
bool m_displayMaxHold;
bool m_displayHistogram;
bool m_displayGrid;
bool m_invert;
void applySettings();
private slots:
void on_fftWindow_currentIndexChanged(int index);
void on_fftSize_currentIndexChanged(int index);
void on_refLevel_currentIndexChanged(int index);
void on_levelRange_currentIndexChanged(int index);
void on_decay_currentIndexChanged(int index);
void on_waterfall_toggled(bool checked);
void on_histogram_toggled(bool checked);
void on_maxHold_toggled(bool checked);
void on_invert_toggled(bool checked);
void on_grid_toggled(bool checked);
};
#endif // INCLUDE_GLSPECTRUMGUI_H
+41
View File
@@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////////
// 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>
#include "util/export.h"
class SDRANGELOVE_API 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
+35
View File
@@ -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
+22
View File
@@ -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
+34
View File
@@ -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
+27
View File
@@ -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;
};
+37
View File
@@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
#include "util/export.h"
class SDRANGELOVE_API 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*);
};
+90
View File
@@ -0,0 +1,90 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
#include "util/export.h"
class SDRANGELOVE_API 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
+67
View File
@@ -0,0 +1,67 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
#include "util/export.h"
class DSPEngine;
namespace Ui {
class ScopeWindow;
}
class SDRANGELOVE_API 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
+72
View File
@@ -0,0 +1,72 @@
///////////////////////////////////////////////////////////////////////////////////
// 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>
#include "util/export.h"
class SDRANGELOVE_API 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();
};
+136
View File
@@ -0,0 +1,136 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 "settings/settings.h"
#include "util/export.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 SDRANGELOVE_API MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = NULL);
~MainWindow();
MessageQueue* getMessageQueue() { return m_messageQueue; }
void addChannelCreateAction(QAction* action);
void addChannelRollup(QWidget* widget);
void addViewAction(QAction* action);
void addChannelMarker(ChannelMarker* channelMarker);
void removeChannelMarker(ChannelMarker* channelMarker);
void setInputGUI(QWidget* gui);
private:
enum {
PGroup,
PItem
};
Ui::MainWindow* ui;
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);
void on_action_About_triggered();
};
#endif // INCLUDE_MAINWINDOW_H
+131
View File
@@ -0,0 +1,131 @@
#ifndef INCLUDE_PLUGINMANAGER_H
#define INCLUDE_PLUGINMANAGER_H
#include <QObject>
#include <QDir>
#include "plugin/plugininterface.h"
#include "plugin/pluginapi.h"
#include "util/export.h"
class QAction;
class QComboBox;
class QPluginLoader;
class Preset;
class MainWindow;
class SampleSource;
class Message;
class SDRANGELOVE_API PluginManager : public QObject {
Q_OBJECT
public:
struct Plugin {
QString filename;
QPluginLoader* loader;
PluginInterface* plugin;
Plugin(const QString& _filename, QPluginLoader* pluginLoader, PluginInterface* _plugin) :
filename(_filename),
loader(pluginLoader),
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 registerChannel(const QString& channelName, PluginInterface* plugin, QAction* action);
void registerChannelInstance(const QString& channelName, PluginGUI* pluginGUI);
void addChannelRollup(QWidget* pluginGUI);
void removeChannelInstance(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);
int selectSampleSource(const QString& source);
private:
struct ChannelRegistration {
QString m_channelName;
PluginInterface* m_plugin;
ChannelRegistration(const QString& channelName, PluginInterface* plugin) :
m_channelName(channelName),
m_plugin(plugin)
{ }
};
typedef QList<ChannelRegistration> ChannelRegistrations;
struct ChannelInstanceRegistration {
QString m_channelName;
PluginGUI* m_gui;
ChannelInstanceRegistration() :
m_channelName(),
m_gui(NULL)
{ }
ChannelInstanceRegistration(const QString& channelName, PluginGUI* pluginGUI) :
m_channelName(channelName),
m_gui(pluginGUI)
{ }
};
typedef QList<ChannelInstanceRegistration> ChannelInstanceRegistrations;
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;
ChannelRegistrations m_channelRegistrations;
ChannelInstanceRegistrations m_channelInstanceRegistrations;
SampleSourceRegistrations m_sampleSourceRegistrations;
SampleSourceDevices m_sampleSourceDevices;
QString m_sampleSource;
PluginGUI* m_sampleSourceInstance;
void loadPlugins(const QDir& dir);
void renameChannelInstances();
};
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
+32
View File
@@ -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
+98
View File
@@ -0,0 +1,98 @@
#ifndef INCLUDE_PRESET_H
#define INCLUDE_PRESET_H
#include <QString>
#include <QList>
#include <QMetaType>
class Preset {
public:
struct ChannelConfig {
QString m_channel;
QByteArray m_config;
ChannelConfig(const QString& channel, const QByteArray& config) :
m_channel(channel),
m_config(config)
{ }
};
typedef QList<ChannelConfig> ChannelConfigs;
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 clearChannels() { m_channelConfigs.clear(); }
void addChannel(const QString& channel, const QByteArray& config) { m_channelConfigs.append(ChannelConfig(channel, config)); }
int getChannelCount() const { return m_channelConfigs.count(); }
const ChannelConfig& getChannelConfig(int index) const { return m_channelConfigs.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;
// channels and configurations
ChannelConfigs m_channelConfigs;
// screen and dock layout
QByteArray m_layout;
};
Q_DECLARE_METATYPE(const Preset*)
#endif // INCLUDE_PRESET_H
+32
View File
@@ -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