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:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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*);
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user