first commit

This commit is contained in:
n1gp
2015-04-04 16:53:58 -04:00
commit 805637d104
232 changed files with 95906 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+442
View File
@@ -0,0 +1,442 @@
/**
* @file cusdr_audio_engine.h
* @brief cuSDR audio engine header file
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _CUSDR_AUDIOENGINE_H
#define _CUSDR_AUDIOENGINE_H
#include "cusdr_audio_spectrum.h"
#include "cusdr_audio_spectrumanalyser.h"
#include "cusdr_audio_wavfile.h"
#include "cusdr_audio_settingsdialog.h"
//#include <QObject>
//#include <QByteArray>
//#include <QBuffer>
//#include <QVector>
//#include <QFile>
#ifdef LOG_AUDIO_ENGINE
# define AUDIO_ENGINE_DEBUG qDebug().nospace() << "AudioEngine::\t"
#else
# define AUDIO_ENGINE_DEBUG nullDebug()
#endif
#ifdef DUMP_CAPTURED_AUDIO
#define DUMP_DATA
#endif
#ifdef DUMP_SPECTRUM
#define DUMP_DATA
#endif
#ifdef DUMP_DATA
#include <QDir>
#endif
#define AUDIO_SAMPLE_TYPE short
//class SettingsDialog;
class FrequencySpectrum;
QT_FORWARD_DECLARE_CLASS(QAudioInput)
QT_FORWARD_DECLARE_CLASS(QAudioOutput)
QT_FORWARD_DECLARE_CLASS(QFile)
class AudiofileBuffer;
typedef AUDIO_SAMPLE_TYPE(*SAMPLE_FUNCTION_TYPE)(AudiofileBuffer *abuffer, int pos, int channel);
/**
* This class interfaces with the QtMultimedia audio classes. Its role is
* to manage the capture and playback of audio data.
*/
class AudioEngine : public QWidget {
Q_OBJECT
public:
//AudioEngine(QObject *parent = 0);
AudioEngine(QWidget *parent = 0);
~AudioEngine();
const QList<QAudioDeviceInfo>& availableAudioInputDevices() const
{ return m_availableAudioInputDevices; }
const QList<QAudioDeviceInfo>& availableAudioOutputDevices() const
{ return m_availableAudioOutputDevices; }
QAudio::Mode mode() const { return m_mode; }
QAudio::State state() const { return m_state; }
/**
* \return Current audio format
* \note May be QAudioFormat() if engine is not initialized
*/
const QAudioFormat& format() const { return m_format; }
/**
* Stop any ongoing recording or playback, and reset to ground state.
*/
void reset();
/**
* Load data from WAV file
*/
bool loadFile(const QString &fileName);
/**
* Generate tone
*/
bool generateTone(const Tone &tone);
/**
* Generate tone
*/
//bool generateSweptTone(qreal amplitude);
bool generateSweptTone();
/**
* Generate local chirp signal
*/
bool generateLocalChirp();
/**
* Initialize for recording
*/
bool initializeRecord();
/**
* Position of the audio input device.
* \return Position in bytes.
*/
qint64 recordPosition() const { return m_recordPosition; }
/**
* RMS level of the most recently processed set of audio samples.
* \return Level in range (0.0, 1.0)
*/
qreal rmsLevel() const { return m_rmsLevel; }
/**
* Peak level of the most recently processed set of audio samples.
* \return Level in range (0.0, 1.0)
*/
qreal peakLevel() const { return m_peakLevel; }
/**
* Position of the audio output device.
* \return Position in bytes.
*/
qint64 playPosition() const { return m_playPosition; }
/**
* Length of the internal engine buffer.
* \return Buffer length in bytes.
*/
qint64 bufferLength() const;
/**
* Amount of data held in the buffer.
* \return Data length in bytes.
*/
qint64 dataLength() const { return m_dataLength; }
/**
* Set window function applied to audio data before spectral analysis.
*/
void setWindowFunction(WindowFunction type);
public slots:
void startRecording();
void startPlayback();
void showSettingsDialog();
void suspend();
void setAudioInputDevice(const QAudioDeviceInfo &device);
void setAudioOutputDevice(const QAudioDeviceInfo &device);
void setSystemState(
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state);
/**
* set Chirp tone parameters
*/
void setChirpSignalMode(QObject *);
//void generateChirpSignal(const SweptTone &tone);
void generateAudioChirpSignal(const SweptTone &tone, const QAudioFormat &format, QByteArray &buffer);
void setChirpLowerFrequency(QObject *sender, int lo);
void setChirpUpperFrequency(QObject *sender, int lo);
void setChirpAmplitude(QObject *sender, qreal amp);
void setChirpBufferDurationUs(QObject *sender, qint64 value);
void setChirpRepetitionTimes(QObject *sender, int value);
void sampleRateChanged(QObject *sender, int value);
signals:
void stateChanged(QAudio::Mode mode, QAudio::State state);
/**
* Informational message for non-modal display
*/
void messageEvent(QString msg);
void infoMessage(const QString &message, int durationMs);
/**
* Error message for modal display
*/
void errorMessage(const QString &heading, const QString &detail);
/**
* Format of audio data has changed
*/
void formatChanged(QObject *sender, const QAudioFormat &format);
/**
* Length of buffer has changed.
* \param duration Duration in microseconds
*/
void bufferLengthChanged(qint64 duration);
/**
* Amount of data in buffer has changed.
* \param Length of data in bytes
*/
void dataLengthChanged(qint64 duration);
/**
* Position of the audio input device has changed.
* \param position Position in bytes
*/
void recordPositionChanged(qint64 position);
/**
* Position of the audio output device has changed.
* \param position Position in bytes
*/
void playPositionChanged(QObject *sender, qint64 position);
/**
* Level changed
* \param rmsLevel RMS level in range 0.0 - 1.0
* \param peakLevel Peak level in range 0.0 - 1.0
* \param numSamples Number of audio samples analyzed
*/
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
/**
* Spectrum has changed.
* \param position Position of start of window in bytes
* \param length Length of window in bytes
* \param spectrum Resulting frequency spectrum
*/
void spectrumChanged(qint64 position, qint64 length, const FrequencySpectrum &spectrum);
/**
* Buffer containing audio data has changed.
* \param position Position of start of buffer in bytes
* \param buffer Buffer
*/
void bufferChanged(QObject *sender, qint64 position, qint64 length, const QByteArray &buffer);
//void chirpBufferChanged(qint64 length, const QList<qreal> &buffer);
void chirpSignalChanged();
void audiofileBufferChanged(const QList<qreal> &buffer);
private slots:
void audioNotify();
void audioStateChanged(QAudio::State state);
void audioDataReady();
void spectrumChanged(const FrequencySpectrum &spectrum);
void spectrumListChanged(const QList<FrequencySpectrum> &spectrumList);
private:
void setupConnections();
void resetAudioDevices();
bool initializePCMS16LE();
bool initializePCMS32LE();
bool selectFormat();
void stopRecording();
void stopPlayback();
void setAudioState(QAudio::State state);
void setAudioState(QAudio::Mode mode, QAudio::State state);
void setFormat(const QAudioFormat &format);
void setRecordPosition(qint64 position, bool forceEmit = false);
void setPlayPosition(qint64 position, bool forceEmit = false);
void calculateLevel(qint64 position, qint64 length);
void calculateSpectrum(qint64 position);
void calculateTotalSpectrum();
void setLevel(qreal rmsLevel, qreal peakLevel, int numSamples);
#ifdef DUMP_DATA
void createOutputDir();
QString outputPath() const { return m_outputDir.path(); }
#endif
#ifdef DUMP_CAPTURED_AUDIO
void dumpData();
#endif
private:
Settings *set;
QAudio::Mode m_mode;
QAudio::State m_state;
QSDR::_Error m_error;
QSDR::_ServerMode m_serverMode;
QSDR::_HWInterfaceMode m_hwInterface;
QSDR::_DataEngineState m_dataEngineState;
QString m_message;
bool m_generateTone;
bool m_generateLocalChirp;
SweptTone m_tone;
int m_lowerChirpFreq;
int m_upperChirpFreq;
qreal m_chirpAmplitude;
int m_chirpSamplingFreq;
int m_downRate;
qint64 m_chirpBufferDurationUs;
int m_chirpChannels;
int m_chirpRepetition;
WavFile *m_file;
// We need a second file handle via which to read data into m_buffer
// for analysis
WavFile *m_analysisFile;
QAudioFormat m_format;
const QList<QAudioDeviceInfo> m_availableAudioInputDevices;
QAudioDeviceInfo m_audioInputDevice;
QAudioInput* m_audioInput;
QIODevice* m_audioInputIODevice;
qint64 m_recordPosition;
const QList<QAudioDeviceInfo> m_availableAudioOutputDevices;
QAudioDeviceInfo m_audioOutputDevice;
QAudioOutput* m_audioOutput;
qint64 m_playPosition;
QBuffer m_audioOutputIODevice;
QByteArray m_buffer;
qint64 m_bufferPosition;
qint64 m_bufferLength;
qint64 m_dataLength;
int m_levelBufferLength;
qreal m_rmsLevel;
qreal m_peakLevel;
int m_spectrumBufferLength;
QByteArray m_spectrumBuffer;
SpectrumAnalyser m_spectrumAnalyser;
qint64 m_spectrumPosition;
int m_count;
SettingsDialog* setDialog;
int m_sampleRate;
AudiofileBuffer *m_audioFileBuffer;
#ifdef DUMP_DATA
QDir m_outputDir;
#endif
};
// *********************************************************************
// AudiofileBuffer Class
class AudiofileBuffer {
public:
AudiofileBuffer();
virtual ~AudiofileBuffer();
static AudiofileBuffer *loadWav(QString fileName);
//static AudiofileBuffer *loadWav( FILE *wavFile ); // support for stdio
void reallocate( int length );
inline void *getRawData() { return m_data; }
inline int getDataLength() { return m_dataLength; }
inline int getBytesPerSample() { return (m_bitsPerSample >> 3); }
inline int getBitsPerSample() { return m_bitsPerSample; }
inline int getSamplesPerSec() { return m_samplesPerSec; }
inline short getNofChannels() { return m_nofChannels; }
inline SAMPLE_FUNCTION_TYPE getSampleFunction() { return m_sampleFunction; }
// static implementations of sample functions
static AUDIO_SAMPLE_TYPE sampleFunction8bitMono(AudiofileBuffer *abuffer, int pos, int channel);
static AUDIO_SAMPLE_TYPE sampleFunction16bitMono(AudiofileBuffer *abuffer, int pos, int channel);
static AUDIO_SAMPLE_TYPE sampleFunction8bitStereo(AudiofileBuffer *abuffer, int pos, int channel);
static AUDIO_SAMPLE_TYPE sampleFunction16bitStereo(AudiofileBuffer *abuffer, int pos, int channel);
protected:
SAMPLE_FUNCTION_TYPE m_sampleFunction;
short m_nofChannels;
void *m_data;
int m_dataLength; // in bytes
short m_bitsPerSample;
bool m_signedData;
int m_samplesPerSec;
};
#endif // _CUSDR_AUDIOENGINE_H
@@ -0,0 +1,226 @@
/**
* @file cusdr_audio_settingsdialog.cpp
* @brief cuSDR audio settings dialogue class
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#include "cusdr_audio_settingsdialog.h"
#include "Util/cusdr_buttons.h"
#include <QComboBox>
#include <QDialogButtonBox>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QCheckBox>
#include <QSlider>
#include <QSpinBox>
#define btn_height 18
#define btn_width 74
SettingsDialog::SettingsDialog(
const QList<QAudioDeviceInfo> &availableInputDevices,
const QList<QAudioDeviceInfo> &availableOutputDevices,
QWidget *parent)
: QDialog(parent)
, set(Settings::instance())
, m_inputDeviceComboBox(new QComboBox(this))
, m_outputDeviceComboBox(new QComboBox(this))
//, m_windowFunction(DefaultWindowFunction)
//, m_windowFunctionComboBox(new QComboBox(this))
{
if (parent)
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
else
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
setWindowModality(Qt::NonModal);
setWindowOpacity(0.9);
setStyleSheet(set->getDialogStyle());
setMouseTracking(true);
m_titleFont.setStyleStrategy(QFont::PreferAntialias);
m_titleFont.setFixedPitch(true);
#ifdef Q_OS_MAC
m_titleFont.setPixelSize(10);
m_titleFont.setFamily("Arial");
//m_titleFont.setBold(true);
#endif
#ifdef Q_OS_WIN
m_titleFont.setPixelSize(13);
m_titleFont.setFamily("Arial");
m_titleFont.setBold(true);
//m_titleFont.setItalic(true);
#endif
QVBoxLayout *dialogLayout = new QVBoxLayout(this);
// Populate combo boxes
QAudioDeviceInfo device;
foreach (device, availableInputDevices)
m_inputDeviceComboBox->addItem(device.deviceName(),
qVariantFromValue(device));
foreach (device, availableOutputDevices)
m_outputDeviceComboBox->addItem(device.deviceName(),
qVariantFromValue(device));
//m_windowFunctionComboBox->addItem(tr("None"), qVariantFromValue(int(NoWindow)));
//m_windowFunctionComboBox->addItem("Hann", qVariantFromValue(int(HannWindow)));
//m_windowFunctionComboBox->setCurrentIndex(m_windowFunction);
m_inputDeviceComboBox->setStyleSheet(set->getComboBoxStyle());
m_inputDeviceComboBox->setMinimumContentsLength(30);
m_outputDeviceComboBox->setStyleSheet(set->getComboBoxStyle());
m_outputDeviceComboBox->setMinimumContentsLength(30);
// Initialize default devices
if (!availableInputDevices.empty())
m_inputDevice = availableInputDevices.front();
if (!availableOutputDevices.empty())
m_outputDevice = availableOutputDevices.front();
// Add widgets to layout
QScopedPointer<QHBoxLayout> titleLayout(new QHBoxLayout);
QLabel *titleLabel = new QLabel(tr("Audio Settings:"), this);
titleLabel->setFont(m_titleFont);
titleLabel->setStyleSheet(set->getLabelStyle());
titleLayout->addWidget(titleLabel);
dialogLayout->addLayout(titleLayout.data());
titleLayout.take(); // ownership transferred to dialogLayout
QScopedPointer<QHBoxLayout> inputDeviceLayout(new QHBoxLayout);
QLabel *inputDeviceLabel = new QLabel(tr("Input device"), this);
inputDeviceLabel->setStyleSheet(set->getLabelStyle());
inputDeviceLayout->addWidget(inputDeviceLabel);
inputDeviceLayout->addWidget(m_inputDeviceComboBox);
dialogLayout->addLayout(inputDeviceLayout.data());
inputDeviceLayout.take(); // ownership transferred to dialogLayout
QScopedPointer<QHBoxLayout> outputDeviceLayout(new QHBoxLayout);
QLabel *outputDeviceLabel = new QLabel(tr("Output device"), this);
outputDeviceLabel->setStyleSheet(set->getLabelStyle());
outputDeviceLayout->addWidget(outputDeviceLabel);
outputDeviceLayout->addWidget(m_outputDeviceComboBox);
dialogLayout->addLayout(outputDeviceLayout.data());
outputDeviceLayout.take(); // ownership transferred to dialogLayout
//QScopedPointer<QHBoxLayout> windowFunctionLayout(new QHBoxLayout);
//QLabel *windowFunctionLabel = new QLabel(tr("Window function"), this);
//windowFunctionLayout->addWidget(windowFunctionLabel);
//windowFunctionLayout->addWidget(m_windowFunctionComboBox);
//dialogLayout->addLayout(windowFunctionLayout.data());
//windowFunctionLayout.take(); // ownership transferred to dialogLayout
// Connect
CHECKED_CONNECT(
m_inputDeviceComboBox,
SIGNAL(activated(int)),
this,
SLOT(inputDeviceChanged(int)));
CHECKED_CONNECT(
m_outputDeviceComboBox,
SIGNAL(activated(int)),
this,
SLOT(outputDeviceChanged(int)));
/*CHECKED_CONNECT(
m_windowFunctionComboBox,
SIGNAL(activated(int)),
this,
SLOT(windowFunctionChanged(int)));*/
AeroButton* okBtn = new AeroButton("Ok", this);
okBtn->setRoundness(10);
okBtn->setFixedSize(btn_width, btn_height);
CHECKED_CONNECT(
okBtn,
SIGNAL(clicked()),
this,
SLOT(accept()));
AeroButton* cancelBtn = new AeroButton("Cancel", this);
cancelBtn->setRoundness(10);
cancelBtn->setFixedSize(btn_width, btn_height);
CHECKED_CONNECT(
cancelBtn,
SIGNAL(clicked()),
this,
SLOT(reject()));
QHBoxLayout *hbox = new QHBoxLayout;
hbox->setSpacing(1);
hbox->addWidget(okBtn);
hbox->addWidget(cancelBtn);
dialogLayout->addLayout(hbox);
setLayout(dialogLayout);
}
SettingsDialog::~SettingsDialog() {
}
//void SettingsDialog::windowFunctionChanged(int index)
//{
// m_windowFunction = static_cast<WindowFunction>(
// m_windowFunctionComboBox->itemData(index).value<int>());
//}
void SettingsDialog::inputDeviceChanged(int index) {
m_inputDevice = m_inputDeviceComboBox->itemData(index).value<QAudioDeviceInfo>();
}
void SettingsDialog::outputDeviceChanged(int index) {
m_outputDevice = m_outputDeviceComboBox->itemData(index).value<QAudioDeviceInfo>();
}
@@ -0,0 +1,100 @@
/**
* @file cusdr_audio_settingsdialog.h
* @brief cuSDR audio settings dialogue header file
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H
//#include "spectrum.h"
#include <QDialog>
#include <QAudioDeviceInfo>
#include "cusdr_settings.h"
QT_FORWARD_DECLARE_CLASS(QComboBox)
QT_FORWARD_DECLARE_CLASS(QCheckBox)
QT_FORWARD_DECLARE_CLASS(QSlider)
QT_FORWARD_DECLARE_CLASS(QSpinBox)
QT_FORWARD_DECLARE_CLASS(QGridLayout)
/**
* Dialog used to control settings such as the audio input / output device
* and the windowing function.
*/
class SettingsDialog : public QDialog {
Q_OBJECT
public:
SettingsDialog(const QList<QAudioDeviceInfo> &availableInputDevices,
const QList<QAudioDeviceInfo> &availableOutputDevices,
QWidget *parent = 0);
~SettingsDialog();
//WindowFunction windowFunction() const { return m_windowFunction; }
const QAudioDeviceInfo& inputDevice() const { return m_inputDevice; }
const QAudioDeviceInfo& outputDevice() const { return m_outputDevice; }
private slots:
//void windowFunctionChanged(int index);
void inputDeviceChanged(int index);
void outputDeviceChanged(int index);
private:
Settings* set;
QFont m_titleFont;
//WindowFunction m_windowFunction;
QAudioDeviceInfo m_inputDevice;
QAudioDeviceInfo m_outputDevice;
QComboBox* m_inputDeviceComboBox;
QComboBox* m_outputDeviceComboBox;
//QComboBox* m_windowFunctionComboBox;
};
#endif // SETTINGSDIALOG_H
@@ -0,0 +1,142 @@
/**
* @file cusdr_audio_spectrum.h
* @brief cuSDR audio engine spectrum header file
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _CUSDR_AUDIO_SPECTRUM_H
#define _CUSDR_AUDIO_SPECTRUM_H
#include <QtCore/qglobal.h>
#include "cusdr_audio_utils.h"
//#include "fftreal_wrapper.h" // For FFTLengthPowerOfTwo
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
// Number of audio samples used to calculate the frequency spectrum
//const int SpectrumLengthSamples = PowerOfTwo<FFTLengthPowerOfTwo>::Result;
const int SpectrumLengthSamples = 2048;//4096;//1024;//256;//512;//
// Number of bands in the frequency spectrum
const int SpectrumNumBands = 10;
// Lower bound of first band in the spectrum
const qreal SpectrumLowFreq = 0.0; // Hz
// Upper band of last band in the spectrum
const qreal SpectrumHighFreq = 1000.0; // Hz
// Waveform window size in microseconds
const qint64 WaveformWindowDuration = 500 * 1000;
// Length of waveform tiles in bytes
// Ideally, these would match the QAudio*::bufferSize(), but that isn't
// available until some time after QAudio*::start() has been called, and we
// need this value in order to initialize the waveform display.
// We therefore just choose a sensible value.
const int WaveformTileLength = 4096;
// Fudge factor used to calculate the spectrum bar heights
const qreal SpectrumAnalyserMultiplier = 0.15;
// Disable message timeout
const int NullMessageTimeout = -1;
//-----------------------------------------------------------------------------
// Types and data structures
//-----------------------------------------------------------------------------
enum WindowFunction {
NoWindow,
HannWindow,
BlackmanHarrisWindow
};
const WindowFunction DefaultWindowFunction = HannWindow;//NoWindow;//BlackmanHarrisWindow;//
struct Tone {
Tone(qreal freq = 0.0, qreal amp = 0.0, qint64 dur = 0)
: frequency(freq), amplitude(amp), duration(dur)
{ }
// Start and end frequencies for swept tone generation
qreal frequency;
// Amplitude in range [0.0, 1.0]
qreal amplitude;
// tone duration in micro seconds
qint64 duration;
};
struct SweptTone {
SweptTone(qreal start = 0.0, qreal end = 0.0, qreal amp = 0.0, qint64 dur = 0)
: startFreq(start), endFreq(end), amplitude(amp), duration(dur)
{ Q_ASSERT(end >= start); }
SweptTone(const Tone &tone)
: startFreq(tone.frequency), endFreq(tone.frequency), amplitude(tone.amplitude), duration(tone.duration)
{ }
// Start and end frequencies for swept tone generation
qreal startFreq;
qreal endFreq;
// Amplitude in range [0.0, 1.0]
qreal amplitude;
// tone duration in micro seconds
qint64 duration;
};
#ifdef DISABLE_WAVEFORM
#undef SUPERIMPOSE_PROGRESS_ON_WAVEFORM
#endif
#endif // _CUSDR_AUDIO_SPECTRUM_H
@@ -0,0 +1,422 @@
/**
* @file cusdr_audio_spectrumanalyser.cpp
* @brief cuSDR audio engine spectrumanalyser class
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
//#define LOG_SPECTRUMANALYSER
//#define DUMP_SPECTRUMANALYSER
#include "cusdr_audio_spectrumanalyser.h"
#include "cusdr_audio_utils.h"
#include "cusdr_settings.h"
#include <QtCore/qmath.h>
#include <QtCore/qmetatype.h>
#include <QThread>
SpectrumAnalyserThread::SpectrumAnalyserThread(QObject *parent)
: QObject(parent)
, set(Settings::instance())
, m_numSamples(SpectrumLengthSamples)
, m_windowFunction(DefaultWindowFunction)
, m_window(SpectrumLengthSamples, 0.0)
, m_input(SpectrumLengthSamples, 0.0)
, m_output(SpectrumLengthSamples, 0.0)
, m_spectrum(SpectrumLengthSamples)
#ifdef SPECTRUM_ANALYSER_SEPARATE_THREAD
, m_thread(new QThread(this))
#endif
{
#ifdef SPECTRUM_ANALYSER_SEPARATE_THREAD
// moveToThread() cannot be called on a QObject with a parent
setParent(0);
moveToThread(m_thread);
m_thread->start();
#endif
//m_cpxInput = mallocCPX(SpectrumLengthSamples);
m_cpxInput.resize(SpectrumLengthSamples);
//m_cpxOutput = mallocCPX(SpectrumLengthSamples);
m_cpxOutput.resize(SpectrumLengthSamples);
m_fft = new QFFT(SpectrumLengthSamples);
//memset(m_cpxInput, 0, SpectrumLengthSamples * sizeof(CPX));
//memset(m_cpxOutput, 0, SpectrumLengthSamples * sizeof(CPX));
calculateWindow();
}
SpectrumAnalyserThread::~SpectrumAnalyserThread() {
delete m_fft;
}
void SpectrumAnalyserThread::setWindowFunction(WindowFunction type) {
m_windowFunction = type;
calculateWindow();
}
void SpectrumAnalyserThread::calculateWindow() {
for (int i = 0; i < m_numSamples; ++i) {
DataType x = 0.0;
switch (m_windowFunction) {
case NoWindow:
x = 1.0;
break;
case HannWindow:
x = 0.5 * (1 - qCos((TWOPI * i) / (m_numSamples - 1)));
break;
case BlackmanHarrisWindow: {
float
a0 = 0.35875F,
a1 = 0.48829F,
a2 = 0.14128F,
a3 = 0.01168F;
x = a0 - a1* cos(TWOPI * (i + 0.5) / m_numSamples)
+ a2* cos(2.0 * TWOPI * (i + 0.5) / m_numSamples)
- a3* cos(3.0 * TWOPI * (i + 0.5) / m_numSamples);
}
break;
default:
Q_ASSERT(false);
}
m_window[i] = x;
}
}
void SpectrumAnalyserThread::calculateTotalSpectrum(const QByteArray &buffer, int inputFrequency, int bytesPerSample) {
if (m_spectrumList.count() > 0)
m_spectrumList.clear();
int samples = bytesPerSample * m_numSamples;
int buffers = qRound((float) buffer.size() / samples);
// cycle over all buffers
for (int i = 0; i < buffers; i++) {
//if (i == buffers-1 && overhead > 0)
m_tmp = QByteArray::fromRawData(buffer.constData() + i * samples, samples);
//Q_ASSERT(m_tmp.size() == m_numSamples * bytesPerSample);
// Initialize data array
const char *ptr = m_tmp.constData();
for (int j = 0; j < m_numSamples; ++j) {
const qint16 pcmSample = *reinterpret_cast<const qint16*>(ptr);
// Scale down to range [-1.0, 1.0]
const DataType realSample = pcmToReal(pcmSample);
const DataType windowedSample = realSample * m_window[j];
m_cpxInput[j].re = windowedSample;
m_cpxInput[j].im = 0.0f;
ptr += bytesPerSample;
}
// calculate the FFT
m_fft->DoFFTWForward(m_cpxInput, m_cpxOutput, SpectrumLengthSamples);
/*for (int i = 0; i < BUFFER_SIZE; i += 32) {
qDebug() << "m_cpxOutput.re =" << m_cpxOutput[i].re << "m_cpxOutput.im =" << m_cpxOutput[i].im;
}*/
// Analyze output to obtain amplitude and phase for each frequency
for (int i = 2; i <= m_numSamples / 2; ++i) {
// Calculate frequency of this complex sample
m_spectrum[i].frequency = qreal(i * inputFrequency) / (m_numSamples);
//const qreal real = m_output[i];
const qreal real = m_cpxOutput[i].re;
qreal imag = 0.0;
if (i > 0 && i < m_numSamples / 2)
imag = m_cpxOutput[m_numSamples/2 + i].re;
const qreal magnitude = sqrt(real*real + imag*imag);
qreal amplitude = SpectrumAnalyserMultiplier * log(magnitude);
// Bound amplitude to [0.0, 1.0]
m_spectrum[i].clipped = (amplitude > 1.0);
amplitude = qMax(qreal(0.0), amplitude);
amplitude = qMin(qreal(1.0), amplitude);
m_spectrum[i].amplitude = amplitude;
}
m_spectrumList.append(m_spectrum);
}
emit calculationTotalComplete(m_spectrumList);
}
void SpectrumAnalyserThread::calculateSpectrum(const QByteArray &buffer, int inputFrequency, int bytesPerSample) {
Q_ASSERT(buffer.size() == m_numSamples * bytesPerSample);
// Initialize data array
const char *ptr = buffer.constData();
for (int i = 0; i < m_numSamples; ++i) {
const qint16 pcmSample = *reinterpret_cast<const qint16*>(ptr);
// Scale down to range [-1.0, 1.0]
const DataType realSample = pcmToReal(pcmSample);
const DataType windowedSample = realSample * m_window[i];
m_input[i] = windowedSample;
m_cpxInput[i].re = windowedSample;
m_cpxInput[i].im = 0.0f;
ptr += bytesPerSample;
}
// Calculate the FFT
m_fft->DoFFTWForward(m_cpxInput, m_cpxOutput, SpectrumLengthSamples);
// Analyze output to obtain amplitude and phase for each frequency
for (int i = 2; i <= m_numSamples / 2; ++i) {
// Calculate frequency of this complex sample
m_spectrum[i].frequency = qreal(i * inputFrequency) / (m_numSamples);
//const qreal real = m_output[i];
const qreal real = m_cpxOutput[i].re;
qreal imag = 0.0;
if (i > 0 && i < m_numSamples / 2)
//imag = m_output[m_numSamples/2 + i];
imag = m_cpxOutput[m_numSamples/2 + i].re;
const qreal magnitude = sqrt(real*real + imag*imag);
qreal amplitude = SpectrumAnalyserMultiplier * log(magnitude);
// Bound amplitude to [0.0, 1.0]
m_spectrum[i].clipped = (amplitude > 1.0);
amplitude = qMax(qreal(0.0), amplitude);
amplitude = qMin(qreal(1.0), amplitude);
m_spectrum[i].amplitude = amplitude;
}
emit calculationComplete(m_spectrum);
}
//=============================================================================
// SpectrumAnalyser
//=============================================================================
SpectrumAnalyser::SpectrumAnalyser(QObject *parent)
: QObject(parent)
, m_thread(new SpectrumAnalyserThread(this))
, m_state(Idle)
#ifdef DUMP_SPECTRUMANALYSER
, m_count(0)
#endif
{
CHECKED_CONNECT(
m_thread,
SIGNAL(calculationComplete(FrequencySpectrum)),
this,
SLOT(calculationComplete(FrequencySpectrum)));
CHECKED_CONNECT(
m_thread,
SIGNAL(calculationTotalComplete(QList<FrequencySpectrum>)),
this,
SLOT(calculationTotalComplete(QList<FrequencySpectrum>)));
}
SpectrumAnalyser::~SpectrumAnalyser() {
}
#ifdef DUMP_SPECTRUMANALYSER
void SpectrumAnalyser::setOutputPath(const QString &outputDir)
{
m_outputDir.setPath(outputDir);
m_textFile.setFileName(m_outputDir.filePath("spectrum.txt"));
m_textFile.open(QIODevice::WriteOnly | QIODevice::Text);
m_textStream.setDevice(&m_textFile);
}
#endif
//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
void SpectrumAnalyser::setWindowFunction(WindowFunction type) {
const bool b = QMetaObject::invokeMethod(m_thread, "setWindowFunction",
Qt::AutoConnection,
Q_ARG(WindowFunction, type));
Q_ASSERT(b);
Q_UNUSED(b) // suppress warnings in release builds
}
void SpectrumAnalyser::calculateTotal(
qint64 position,
qint64 length,
const QAudioFormat &format,
const QByteArray &buffer
) {
Q_UNUSED(position)
Q_UNUSED(length)
SPECTRUMANALYSER_DEBUG << "SpectrumAnalyser::calculateTotal"
<< QThread::currentThread()
<< "state" << m_state;
SPECTRUMANALYSER_DEBUG << "buffer size =" << buffer.size();
if (isReady()) {
Q_ASSERT(isPCMS16LE(format));
const int bytesPerSample = format.sampleSize() * format.channelCount() / 8;
m_state = Busy;
// Invoke SpectrumAnalyserThread::calculateTotalSpectrum using QMetaObject.
// If m_thread is in a different thread from the current thread, the
// calculation will be done in the child thread.
// Once the calculation is finished, a calculationChanged signal will be
// emitted by m_thread.
const bool b = QMetaObject::invokeMethod(m_thread, "calculateTotalSpectrum",
Qt::AutoConnection,
Q_ARG(QByteArray, buffer),
Q_ARG(int, format.sampleRate()),
Q_ARG(int, bytesPerSample));
Q_ASSERT(b);
Q_UNUSED(b) // suppress warnings in release builds
}
}
void SpectrumAnalyser::calculate(const QByteArray &buffer,
const QAudioFormat &format)
{
// QThread::currentThread is marked 'for internal use only', but
// we're only using it for debug output here, so it's probably OK :)
SPECTRUMANALYSER_DEBUG << "SpectrumAnalyser::calculate"
<< QThread::currentThread()
<< "state" << m_state;
SPECTRUMANALYSER_DEBUG << "buffer size =" << buffer.size();
if (isReady()) {
Q_ASSERT(isPCMS16LE(format));
const int bytesPerSample = format.sampleSize() * format.channelCount() / 8;
m_state = Busy;
// Invoke SpectrumAnalyserThread::calculateSpectrum using QMetaObject. If
// m_thread is in a different thread from the current thread, the
// calculation will be done in the child thread.
// Once the calculation is finished, a calculationChanged signal will be
// emitted by m_thread.
const bool b = QMetaObject::invokeMethod(m_thread, "calculateSpectrum",
Qt::AutoConnection,
Q_ARG(QByteArray, buffer),
Q_ARG(int, format.sampleRate()),
Q_ARG(int, bytesPerSample));
Q_ASSERT(b);
Q_UNUSED(b) // suppress warnings in release builds
#ifdef DUMP_SPECTRUMANALYSER
m_textStream << "FrequencySpectrum " << m_count << "\n";
FrequencySpectrum::const_iterator x = m_spectrum.begin();
for (int i=0; i<m_numSamples; ++i, ++x)
m_textStream << i << "\t"
<< x->frequency << "\t"
<< x->amplitude<< "\t"
<< x->phase << "\n";
#endif
}
}
bool SpectrumAnalyser::isReady() const {
return (Idle == m_state);
}
void SpectrumAnalyser::cancelCalculation() {
if (Busy == m_state)
m_state = Cancelled;
}
//-----------------------------------------------------------------------------
// Private slots
//-----------------------------------------------------------------------------
void SpectrumAnalyser::calculationComplete(const FrequencySpectrum &spectrum) {
Q_ASSERT(Idle != m_state);
if (Busy == m_state)
emit spectrumChanged(spectrum);
m_state = Idle;
}
void SpectrumAnalyser::calculationTotalComplete(const QList<FrequencySpectrum> &m_spectrumList) {
Q_ASSERT(Idle != m_state);
if (Busy == m_state)
emit spectrumListChanged(m_spectrumList);
m_state = Idle;
}
@@ -0,0 +1,229 @@
/**
* @file cusdr_audio_spectrumanalyser.h
* @brief cuSDR audio engine spectrumanalyser header file
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _CUSDR_AUDIO_SPECTRUMANALYSER_H
#define _CUSDR_AUDIO_SPECTRUMANALYSER_H
#include <QByteArray>
#include <QObject>
#include <QVector>
#ifdef DUMP_SPECTRUMANALYSER
#include <QDir>
#include <QFile>
#include <QTextStream>
#endif
//#define SPECTRUM_ANALYSER_SEPARATE_THREAD
//#include "frequencyspectrum.h"
#include "cusdr_audio_spectrum.h"
#include "cusdr_settings.h"
#include "QtDSP/qtdsp_fft.h"
#include "QtDSP/qtdsp_qComplex.h"
//#include "cusdr_filter.h"
#ifdef LOG_SPECTRUMANALYSER
# define SPECTRUMANALYSER_DEBUG qDebug().nospace() << "SpectrumAnalyzer::\t"
#else
# define SPECTRUMANALYSER_DEBUG nullDebug()
#endif
QT_FORWARD_DECLARE_CLASS(QAudioFormat)
QT_FORWARD_DECLARE_CLASS(QThread)
//class SpectrumAnalyserThreadPrivate;
/**
* Implementation of the spectrum analysis which can be run in a
* separate thread.
*/
class SpectrumAnalyserThread : public QObject
{
Q_OBJECT
public:
SpectrumAnalyserThread(QObject *parent);
~SpectrumAnalyserThread();
public slots:
void setWindowFunction(WindowFunction type);
void calculateSpectrum(
const QByteArray &buffer,
int inputFrequency,
int bytesPerSample);
void calculateTotalSpectrum(
const QByteArray &buffer,
int inputFrequency,
int bytesPerSample);
signals:
void calculationComplete(const FrequencySpectrum &spectrum);
void calculationTotalComplete(const QList<FrequencySpectrum> &spectrumList);
private:
void calculateWindow();
private:
Settings* set;
int m_numSamples;
WindowFunction m_windowFunction;
//typedef qreal DataType;
typedef float DataType;
QVector<DataType> m_window;
QVector<DataType> m_input;
QVector<DataType> m_output;
CPX m_cpxInput;
CPX m_cpxOutput;
QFFT *m_fft;
QByteArray m_tmp;
FrequencySpectrum m_spectrum;
QList<FrequencySpectrum> m_spectrumList;
#ifdef SPECTRUM_ANALYSER_SEPARATE_THREAD
QThread* m_thread;
#endif
};
/**
* Class which performs frequency spectrum analysis on a window of
* audio samples, provided to it by the Engine.
*/
class SpectrumAnalyser : public QObject
{
Q_OBJECT
public:
SpectrumAnalyser(QObject *parent = 0);
~SpectrumAnalyser();
#ifdef DUMP_SPECTRUMANALYSER
void setOutputPath(const QString &outputPath);
#endif
public:
/*
* Set the windowing function which is applied before calculating the FFT
*/
void setWindowFunction(WindowFunction type);
/*
* Calculate a frequency spectrum
*
* \param buffer Audio data
* \param format Format of audio data
*
* Frequency spectrum is calculated asynchronously. The result is returned
* via the spectrumChanged signal.
*
* An ongoing calculation can be cancelled by calling cancelCalculation().
*
*/
void calculate(const QByteArray &buffer, const QAudioFormat &format);
void calculateTotal(
qint64 position,
qint64 length,
const QAudioFormat &format,
const QByteArray &buffer);
/*
* Check whether the object is ready to perform another calculation
*/
bool isReady() const;
/*
* Cancel an ongoing calculation
*
* Note that cancelling is asynchronous.
*/
void cancelCalculation();
signals:
void spectrumChanged(const FrequencySpectrum &spectrum);
void spectrumListChanged(const QList<FrequencySpectrum> &spectrumList);
private slots:
void calculationComplete(const FrequencySpectrum &spectrum);
void calculationTotalComplete(const QList<FrequencySpectrum> &m_spectrumList);
private:
void calculateWindow();
private:
SpectrumAnalyserThread* m_thread;
enum State {
Idle,
Busy,
Cancelled
};
State m_state;
#ifdef DUMP_SPECTRUMANALYSER
QDir m_outputDir;
int m_count;
QFile m_textFile;
QTextStream m_textStream;
#endif
};
#endif // _CUSDR_AUDIO_SPECTRUMANALYSER_H
@@ -0,0 +1,155 @@
/**
* @file cusdr_audio_utils.cpp
* @brief cuSDR audio utils class
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#include "cusdr_audio_utils.h"
qint64 audioDuration(const QAudioFormat &format, qint64 bytes) {
return (bytes * 1000000) /
(format.sampleRate() * format.channelCount() * (format.sampleSize() / 8));
}
qint64 audioLength(const QAudioFormat &format, qint64 microSeconds) {
qint64 result = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8))
* microSeconds / 1000000;
result -= result % (format.channelCount() * format.sampleSize());
return result;
}
qreal nyquistFrequency(const QAudioFormat &format) {
return format.sampleRate() / 2;
}
QString formatToString(const QAudioFormat &format) {
QString result;
if (QAudioFormat() != format) {
if (format.codec() == "audio/pcm") {
Q_ASSERT(format.sampleType() == QAudioFormat::SignedInt);
const QString formatEndian = (format.byteOrder() == QAudioFormat::LittleEndian)
? QString("LE") : QString("BE");
QString formatType;
switch(format.sampleType()) {
case QAudioFormat::SignedInt:
formatType = "signed";
break;
case QAudioFormat::UnSignedInt:
formatType = "unsigned";
break;
case QAudioFormat::Float:
formatType = "float";
break;
case QAudioFormat::Unknown:
formatType = "unknown";
break;
}
QString formatChannels = QString("%1 channels").arg(format.channelCount());
switch (format.channelCount()) {
case 1:
formatChannels = "mono";
break;
case 2:
formatChannels = "stereo";
break;
}
result = QString("%1 Hz %2 bit %3 %4 %5")
.arg(format.sampleRate())
.arg(format.sampleSize())
.arg(formatType)
.arg(formatEndian)
.arg(formatChannels);
} else {
result = format.codec();
}
}
return result;
}
bool isPCM(const QAudioFormat &format) {
return (format.codec() == "audio/pcm");
}
bool isPCMS16LE(const QAudioFormat &format) {
return (isPCM(format) &&
format.sampleType() == QAudioFormat::SignedInt &&
format.sampleSize() == 16 &&
format.byteOrder() == QAudioFormat::LittleEndian);
}
bool isPCMS32LE(const QAudioFormat &format) {
return (isPCM(format) &&
format.sampleType() == QAudioFormat::SignedInt &&
format.sampleSize() == 32 &&
format.byteOrder() == QAudioFormat::LittleEndian);
}
const qint16 PCMS16MaxValue = 32767;
const quint16 PCMS16MaxAmplitude = 32768; // because minimum is -32768
qreal pcmToReal(qint16 pcm) {
return qreal(pcm) / PCMS16MaxAmplitude;
}
qint16 realToPcm(qreal real) {
return real * PCMS16MaxValue;
}
@@ -0,0 +1,96 @@
/**
* @file cusdr_audio_utils.h
* @brief cuSDR audio utils header file
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _CUSDR_AUDIO_UTILS_H
#define _CUSDR_AUDIO_UTILS_H
#include <QtCore/qglobal.h>
#include <QDebug>
#include <QAudioFormat>
#if defined(Q_OS_WIN32)
QT_FORWARD_DECLARE_CLASS(QAudioFormat)
#endif
//-----------------------------------------------------------------------------
// Miscellaneous utility functions
//-----------------------------------------------------------------------------
qint64 audioDuration(const QAudioFormat &format, qint64 bytes);
qint64 audioLength(const QAudioFormat &format, qint64 microSeconds);
QString formatToString(const QAudioFormat &format);
qreal nyquistFrequency(const QAudioFormat &format);
// Scale PCM value to [-1.0, 1.0]
qreal pcmToReal(qint16 pcm);
// Scale real value in [-1.0, 1.0] to PCM
qint16 realToPcm(qreal real);
// Check whether the audio format is PCM
bool isPCM(const QAudioFormat &format);
// Check whether the audio format is signed, little-endian, 16-bit PCM
bool isPCMS16LE(const QAudioFormat &format);
// Check whether the audio format is float, little-endian, 32-bit PCM
bool isPCMS32LE(const QAudioFormat &format);
// Compile-time calculation of powers of two
template<int N> class PowerOfTwo
{ public: static const int Result = PowerOfTwo<N-1>::Result * 2; };
template<> class PowerOfTwo<0>
{ public: static const int Result = 1; };
#endif // _CUSDR_AUDIO_UTILS_H
@@ -0,0 +1,484 @@
/**
* @file cusdr_audio_waveform.cpp
* @brief cuSDR waveform graphics
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
//#define LOG_WAVEFORM
//#define LOG_PAINT_EVENT
#include "cusdr_audio_utils.h"
#include "cusdr_audio_waveform.h"
#include <QPainter>
#include <QResizeEvent>
#include <QDebug>
Waveform::Waveform(QObject *parent)
: QObject(parent)
, set(Settings::instance())
, m_bufferPosition(0)
, m_bufferLength(0)
, m_audioPosition(0)
, m_active(false)
, m_tileLength(0)
, m_tileArrayStart(0)
, m_windowPosition(0)
, m_windowLength(0)
, m_waveformDisplayWidth(0)
{
}
Waveform::~Waveform() {
deletePixmaps();
}
QImage* Waveform::createWaveformImage(const QRect &rect) {
if (!rect.isValid()) return NULL;
QImage *image = new QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
if (!image) return NULL;
m_waveformDisplayWidth = image->width();
image->fill(QColor(0, 0, 0, 255).rgba());
QPainter painter(image);
if (m_active) {
WAVEFORM_PAINT_DEBUG << "paintEvent"
<< "windowPosition" << m_windowPosition
<< "windowLength" << m_windowLength;
qint64 pos = m_windowPosition;
const qint64 windowEnd = m_windowPosition + m_windowLength;
int destLeft = 0;
int destRight = 0;
while (pos < windowEnd) {
const TilePoint point = tilePoint(pos);
WAVEFORM_PAINT_DEBUG << "paintEvent" << "pos" << pos
<< "tileIndex" << point.index
<< "positionOffset" << point.positionOffset
<< "pixelOffset" << point.pixelOffset;
if (point.index != NullIndex) {
const Tile &tile = m_tiles[point.index];
if (tile.painted) {
const qint64 sectionLength = qMin((m_tileLength - point.positionOffset),
(windowEnd - pos));
Q_ASSERT(sectionLength > 0);
const int sourceRight = tilePixelOffset(point.positionOffset + sectionLength);
//destRight = windowPixelOffset(pos - m_windowPosition + sectionLength);
destRight = windowPixelOffset(pos - m_windowPosition + sectionLength, rect);
QRect destRect = rect;//();
destRect.setTop(20);
destRect.setHeight(rect.height() - 20);
destRect.setLeft(destLeft);
destRect.setRight(destRight);
//destRect.setRect(0, 0, destLeft + destRight, rect.height());
QRect sourceRect(QPoint(), m_pixmapSize);
sourceRect.setLeft(point.pixelOffset);
sourceRect.setRight(sourceRight);
WAVEFORM_PAINT_DEBUG << "paintEvent" << "tileIndex" << point.index
<< "source" << point.pixelOffset << sourceRight
<< "dest" << destLeft << destRight;
//painter.drawPixmap(destRect, *tile.pixmap, sourceRect);
painter.drawPixmap(destRect, *tile.pixmap, sourceRect);
destLeft = destRight;
if (point.index < m_tiles.count()) {
pos = tilePosition(point.index + 1);
WAVEFORM_PAINT_DEBUG << "paintEvent" << "pos ->" << pos;
}
else {
// Reached end of tile array
WAVEFORM_PAINT_DEBUG << "paintEvent" << "reached end of tile array";
break;
}
}
else {
// Passed last tile which is painted
WAVEFORM_PAINT_DEBUG << "paintEvent" << "tile" << point.index << "not painted";
break;
}
}
else {
// pos is past end of tile array
WAVEFORM_PAINT_DEBUG << "paintEvent" << "pos" << pos << "past end of tile array";
break;
}
}
WAVEFORM_PAINT_DEBUG << "paintEvent" << "final pos" << pos << "final x" << destRight;
}
painter.end();
return image;
}
void Waveform::initialize(const QAudioFormat &format, qint64 audioBufferSize, qint64 windowDurationUs, const QRect &rect) {
WAVEFORM_DEBUG << "initialize"
<< "audioBufferSize" << audioBufferSize
<< "windowDurationUs" << windowDurationUs;
reset();
m_format = format;
m_audioRect = rect;
// Calculate tile size
m_tileLength = audioBufferSize;
// Calculate window size
m_windowLength = audioLength(m_format, windowDurationUs);
// Calculate number of tiles required
int nTiles;
if (m_tileLength > m_windowLength) {
nTiles = 2;
} else {
nTiles = m_windowLength / m_tileLength + 1;
if (m_windowLength % m_tileLength)
++nTiles;
}
WAVEFORM_DEBUG << "initialize"
<< "tileLength" << m_tileLength
<< "windowLength" << m_windowLength
<< "nTiles" << nTiles;
m_pixmaps.fill(0, nTiles);
m_tiles.resize(nTiles);
createPixmaps(m_audioRect.size());
m_active = true;
}
void Waveform::reset()
{
WAVEFORM_DEBUG << "reset";
m_bufferPosition = 0;
m_buffer = QByteArray();
m_audioPosition = 0;
m_format = QAudioFormat();
m_active = false;
deletePixmaps();
m_tiles.clear();
m_tileLength = 0;
m_tileArrayStart = 0;
m_windowPosition = 0;
m_windowLength = 0;
}
void Waveform::bufferChanged(QObject *sender, qint64 position, qint64 length, const QByteArray &buffer) {
Q_UNUSED (sender)
WAVEFORM_DEBUG << "bufferChanged"
<< "audioPosition" << m_audioPosition
<< "bufferPosition" << position
<< "bufferLength" << length;
m_bufferPosition = position;
m_bufferLength = length;
m_buffer = buffer;
paintTiles();
}
void Waveform::audioPositionChanged(QObject *sender, qint64 position)
{
Q_UNUSED (sender)
WAVEFORM_DEBUG << "audioPositionChanged"
<< "audioPosition" << position
<< "bufferPosition" << m_bufferPosition
<< "bufferLength" << m_bufferLength;
if (position >= m_bufferPosition) {
if (position + m_windowLength > m_bufferPosition + m_bufferLength)
position = qMax(qint64(0), m_bufferPosition + m_bufferLength - m_windowLength);
m_audioPosition = position;
setWindowPosition(position);
}
}
void Waveform::deletePixmaps()
{
QPixmap *pixmap;
foreach (pixmap, m_pixmaps)
delete pixmap;
m_pixmaps.clear();
}
void Waveform::createPixmaps(const QSize &rect) {
m_pixmapSize = rect;
if (m_windowLength > 0)
m_pixmapSize.setWidth(qreal(rect.width()) * m_tileLength / m_windowLength);
else
m_pixmapSize.setWidth(qreal(rect.width()));
WAVEFORM_DEBUG << "createPixmaps"
<< "rectSize" << rect
<< "pixmapSize" << m_pixmapSize;
Q_ASSERT(m_tiles.count() == m_pixmaps.count());
// (Re)create pixmaps
for (int i = 0; i < m_pixmaps.size(); ++i) {
delete m_pixmaps[i];
m_pixmaps[i] = 0;
m_pixmaps[i] = new QPixmap(m_pixmapSize);
}
// Update tile pixmap pointers, and mark for repainting
for (int i = 0; i < m_tiles.count(); ++i) {
m_tiles[i].pixmap = m_pixmaps[i];
m_tiles[i].painted = false;
}
}
void Waveform::setWindowPosition(qint64 position)
{
WAVEFORM_DEBUG << "setWindowPosition"
<< "old" << m_windowPosition << "new" << position
<< "tileArrayStart" << m_tileArrayStart;
const qint64 oldPosition = m_windowPosition;
m_windowPosition = position;
if((m_windowPosition >= oldPosition) &&
(m_windowPosition - m_tileArrayStart < (m_tiles.count() * m_tileLength))) {
// Work out how many tiles need to be shuffled
const qint64 offset = m_windowPosition - m_tileArrayStart;
const int nTiles = offset / m_tileLength;
shuffleTiles(nTiles);
} else {
resetTiles(m_windowPosition);
}
if(!paintTiles() && m_windowPosition != oldPosition)
emit waveformImageChanged(true);
// update();
}
qint64 Waveform::tilePosition(int index) const {
return m_tileArrayStart + index * m_tileLength;
}
Waveform::TilePoint Waveform::tilePoint(qint64 position) const {
TilePoint result;
if (position >= m_tileArrayStart) {
const qint64 tileArrayEnd = m_tileArrayStart + m_tiles.count() * m_tileLength;
if (position < tileArrayEnd) {
const qint64 offsetIntoTileArray = position - m_tileArrayStart;
result.index = offsetIntoTileArray / m_tileLength;
Q_ASSERT(result.index >= 0 && result.index <= m_tiles.count());
result.positionOffset = offsetIntoTileArray % m_tileLength;
result.pixelOffset = tilePixelOffset(result.positionOffset);
Q_ASSERT(result.pixelOffset >= 0 && result.pixelOffset <= m_pixmapSize.width());
}
}
return result;
}
int Waveform::tilePixelOffset(qint64 positionOffset) const {
Q_ASSERT(positionOffset >= 0 && positionOffset <= m_tileLength);
const int result = (qreal(positionOffset) / m_tileLength) * m_pixmapSize.width();
return result;
}
int Waveform::windowPixelOffset(qint64 positionOffset, const QRect &rect) const {
Q_ASSERT(positionOffset >= 0 && positionOffset <= m_windowLength);
const int result = (qreal(positionOffset) / m_windowLength) * rect.width();
return result;
}
bool Waveform::paintTiles() {
WAVEFORM_DEBUG << "paintTiles";
bool updateRequired = false;
for (int i = 0; i < m_tiles.count(); ++i) {
//for (int i = 0; i < 1; ++i) {
const Tile &tile = m_tiles[i];
if (!tile.painted) {
const qint64 tileStart = m_tileArrayStart + i * m_tileLength;
const qint64 tileEnd = tileStart + m_tileLength;
if (m_bufferPosition <= tileStart && m_bufferPosition + m_bufferLength >= tileEnd) {
paintTile(i);
updateRequired = true;
}
}
}
if (updateRequired)
emit waveformImageChanged(true);
return updateRequired;
}
void Waveform::paintTile(int index) {
const qint64 tileStart = m_tileArrayStart + index * m_tileLength;
WAVEFORM_DEBUG << "paintTile"
<< "index" << index
<< "bufferPosition" << m_bufferPosition
<< "bufferLength" << m_bufferLength
<< "start" << tileStart
<< "end" << tileStart + m_tileLength;
Q_ASSERT(m_bufferPosition <= tileStart);
Q_ASSERT(m_bufferPosition + m_bufferLength >= tileStart + m_tileLength);
Tile &tile = m_tiles[index];
Q_ASSERT(!tile.painted);
const qint16* base = reinterpret_cast<const qint16*>(m_buffer.constData());
const qint16* buffer = base + ((tileStart - m_bufferPosition) / 2);
const int numSamples = m_tileLength / (2 * m_format.channelCount());
QPainter painter(tile.pixmap);
painter.fillRect(tile.pixmap->rect(), Qt::black);
//painter.fillRect(tile.pixmap->rect(), QColor(60, 60, 60));
//QPen pen(Qt::white);
QPen pen(QColor(85, 210, 250));
painter.setPen(pen);
// Calculate initial PCM value
qint16 previousPcmValue = 0;
if (buffer > base)
previousPcmValue = *(buffer - m_format.channelCount());
// Calculate initial point
const qreal previousRealValue = pcmToReal(previousPcmValue);
const int originY = ((previousRealValue + 1.0) / 2) * m_pixmapSize.height();
const QPoint origin(0, originY);
QLine line(origin, origin);
for (int i = 0; i < numSamples; ++i) {
const qint16* ptr = buffer + i * m_format.channelCount();
Q_ASSERT((reinterpret_cast<const char*>(ptr) - m_buffer.constData()) >= 0);
Q_ASSERT((reinterpret_cast<const char*>(ptr) - m_buffer.constData()) < m_bufferLength);
const qint16 pcmValue = *ptr;
const qreal realValue = pcmToReal(pcmValue);
const int x = tilePixelOffset(i * 2 * m_format.channelCount());
const int y = ((realValue + 1.0) / 2) * m_pixmapSize.height();
line.setP2(QPoint(x, y));
painter.drawLine(line);
line.setP1(line.p2());
}
tile.painted = true;
}
void Waveform::shuffleTiles(int n)
{
WAVEFORM_DEBUG << "shuffleTiles" << "n" << n;
while (n--) {
Tile tile = m_tiles.first();
tile.painted = false;
m_tiles.erase(m_tiles.begin());
m_tiles += tile;
m_tileArrayStart += m_tileLength;
}
WAVEFORM_DEBUG << "shuffleTiles" << "tileArrayStart" << m_tileArrayStart;
}
void Waveform::resetTiles(qint64 newStartPos)
{
WAVEFORM_DEBUG << "resetTiles" << "newStartPos" << newStartPos;
QVector<Tile>::iterator i = m_tiles.begin();
for ( ; i != m_tiles.end(); ++i)
i->painted = false;
m_tileArrayStart = newStartPos;
}
@@ -0,0 +1,237 @@
/**
* @file cusdr_audio_waveform.h
* @brief cuSDR waveform graphics header file
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _CUSDR_WAVEFORM_H
#define _CUSDR_WAVEFORM_H
#include <QObject>
#include <QPixmap>
#include <QScopedPointer>
#include "cusdr_settings.h"
#ifdef LOG_WAVEFORM
# define WAVEFORM_DEBUG qDebug().nospace() << "WaveForm::\t"
#else
# define WAVEFORM_DEBUG nullDebug()
#endif
#ifdef LOG_PAINT_EVENT
# define WAVEFORM_PAINT_DEBUG qDebug().nospace() << "WaveFormPaint::\t"
#else
# define WAVEFORM_PAINT_DEBUG nullDebug()
#endif
QT_FORWARD_DECLARE_CLASS(QByteArray)
/**
* QObject which draws a section of the audio waveform.
*
* The waveform is rendered on a set of QPixmaps which form a group of tiles
* whose extent covers the widget. As the audio position is updated, these
* tiles are scrolled from left to right; when the left-most tile scrolls
* outside the widget, it is moved to the right end of the tile array and
* painted with the next section of the waveform.
*/
class Waveform : public QObject {
Q_OBJECT
public:
Waveform(QObject *parent = 0);
~Waveform();
void initialize(
const QAudioFormat &format,
qint64 audioBufferSize,
qint64 windowDurationUs,
const QRect &rect);
void reset();
void setAutoUpdatePosition(bool enabled);
public slots:
void bufferChanged(QObject *sender, qint64 position, qint64 length, const QByteArray &buffer);
void audioPositionChanged(QObject *sender, qint64 position);
QImage* createWaveformImage(const QRect &rect);
private:
static const int NullIndex = -1;
void deletePixmaps();
/*
* (Re)create all pixmaps, repaint and update the display.
* Triggers an update();
*/
void createPixmaps(const QSize &newSize);
/*
* Update window position.
* Triggers an update().
*/
void setWindowPosition(qint64 position);
/*
* Base position of tile
*/
qint64 tilePosition(int index) const;
/*
* Structure which identifies a point within a given
* tile.
*/
struct TilePoint
{
TilePoint(int idx = 0, qint64 pos = 0, qint64 pix = 0)
: index(idx), positionOffset(pos), pixelOffset(pix)
{ }
// Index of tile
int index;
// Number of bytes from start of tile
qint64 positionOffset;
// Number of pixels from left of corresponding pixmap
int pixelOffset;
};
/*
* Convert position in m_buffer into a tile index and an offset in pixels
* into the corresponding pixmap.
*
* \param position Offset into m_buffer, in bytes
* If position is outside the tile array, index is NullIndex and
* offset is zero.
*/
TilePoint tilePoint(qint64 position) const;
/*
* Convert offset in bytes into a tile into an offset in pixels
* within that tile.
*/
int tilePixelOffset(qint64 positionOffset) const;
/*
* Convert offset in bytes into the window into an offset in pixels
* within the widget rect().
*/
int windowPixelOffset(qint64 positionOffset, const QRect &rect) const;
/*
* Paint all tiles which can be painted.
* \return true iff update() was called
*/
bool paintTiles();
/*
* Paint the specified tile
*
* \pre Sufficient data is available to completely paint the tile, i.e.
* m_dataLength is greater than the upper bound of the tile.
*/
void paintTile(int index);
/*
* Move the first n tiles to the end of the array, and mark them as not
* painted.
*/
void shuffleTiles(int n);
/*
* Reset tile array
*/
void resetTiles(qint64 newStartPos);
private:
Settings* set;
QRect m_audioRect;
qint64 m_bufferPosition;
qint64 m_bufferLength;
QByteArray m_buffer;
qint64 m_audioPosition;
QAudioFormat m_format;
bool m_active;
QSize m_pixmapSize;
QVector<QPixmap*> m_pixmaps;
struct Tile {
// Pointer into parent m_pixmaps array
QPixmap* pixmap;
// Flag indicating whether this tile has been painted
bool painted;
};
QVector<Tile> m_tiles;
// Length of audio data in bytes depicted by each tile
qint64 m_tileLength;
// Position in bytes of the first tile, relative to m_buffer
qint64 m_tileArrayStart;
qint64 m_windowPosition;
qint64 m_windowLength;
int m_waveformDisplayWidth;
signals:
void waveformImageChanged(bool value);
};
#endif // _CUSDR_WAVEFORM_H
@@ -0,0 +1,165 @@
/**
* @file cusdr_audio_wavfile.cpp
* @brief cuSDR audio wav-file class
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
//#define LOG_AUDIO_WAVFILE
#include <QtCore/qendian.h>
#include <QVector>
#include <QDebug>
#include "cusdr_audio_utils.h"
#include "cusdr_audio_wavfile.h"
struct chunk {
char id[4];
quint32 size;
};
struct RIFFHeader {
chunk descriptor; // "RIFF"
char type[4]; // "WAVE"
};
struct WAVEHeader {
chunk descriptor;
quint16 audioFormat;
quint16 numChannels;
quint32 sampleRate;
quint32 byteRate;
quint16 blockAlign;
quint16 bitsPerSample;
};
struct DATAHeader {
chunk descriptor;
};
struct CombinedHeader {
RIFFHeader riff;
WAVEHeader wave;
};
WavFile::WavFile(QObject *parent)
: QFile(parent)
, m_headerLength(0)
{
}
bool WavFile::open(const QString &fileName) {
close();
setFileName(fileName);
return QFile::open(QIODevice::ReadOnly) && readHeader();
}
const QAudioFormat &WavFile::fileFormat() const {
return m_fileFormat;
}
qint64 WavFile::headerLength() const {
return m_headerLength;
}
bool WavFile::readHeader() {
seek(0);
CombinedHeader header;
bool result = read(reinterpret_cast<char *>(&header), sizeof(CombinedHeader)) == sizeof(CombinedHeader);
AUDIO_WAVFILE_DEBUG << "header.id" << header.riff.descriptor.id;
AUDIO_WAVFILE_DEBUG << "header.type" << header.riff.type;
AUDIO_WAVFILE_DEBUG << "header.descriptor.id" << header.wave.descriptor.id;
AUDIO_WAVFILE_DEBUG << "header.audioFormat" << header.wave.audioFormat;
if (result) {
if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0
|| memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0)
&& memcmp(&header.riff.type, "WAVE", 4) == 0
&& memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0
&& (header.wave.audioFormat == 1 || header.wave.audioFormat == 0 || header.wave.audioFormat == 3)) {
// Read off remaining header information
DATAHeader dataHeader;
if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader)) {
// Extended data available
quint16 extraFormatBytes;
if (peek((char*)&extraFormatBytes, sizeof(quint16)) != sizeof(quint16))
return false;
const qint64 throwAwayBytes = sizeof(quint16) + qFromLittleEndian<quint16>(extraFormatBytes);
if (read(throwAwayBytes).size() != throwAwayBytes)
return false;
}
if (read((char*)&dataHeader, sizeof(DATAHeader)) != sizeof(DATAHeader))
return false;
// Establish format
if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0)
m_fileFormat.setByteOrder(QAudioFormat::LittleEndian);
else
m_fileFormat.setByteOrder(QAudioFormat::BigEndian);
int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample);
m_fileFormat.setChannelCount(qFromLittleEndian<quint16>(header.wave.numChannels));
m_fileFormat.setCodec("audio/pcm");
m_fileFormat.setSampleRate(qFromLittleEndian<quint32>(header.wave.sampleRate));
m_fileFormat.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample));
m_fileFormat.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
} else {
result = false;
}
}
m_headerLength = pos();
return result;
}
@@ -0,0 +1,83 @@
/**
* @file cusdr_audio_wavfile.h
* @brief cuSDR audio wav file header file
* @author adaptation for cuSDR by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-04-02
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _CUSDR_AUDIO_WAVFILE_H
#define _CUSDR_AUDIO_WAVFILE_H
#include <QtCore/qobject.h>
#include <QtCore/qfile.h>
#include "cusdr_settings.h"
#ifdef LOG_AUDIO_WAVFILE
# define AUDIO_WAVFILE_DEBUG qDebug().nospace() << "AudioWavFile::\t"
#else
# define AUDIO_WAVFILE_DEBUG nullDebug()
#endif
class WavFile : public QFile
{
public:
WavFile(QObject *parent = 0);
bool open(const QString &fileName);
const QAudioFormat &fileFormat() const;
qint64 headerLength() const;
private:
bool readHeader();
private:
QAudioFormat m_fileFormat;
qint64 m_headerLength;
};
#endif // _CUSDR_AUDIO_WAVFILE_H
@@ -0,0 +1,94 @@
/**
* @file cusdr_fspectrum.cpp
* @brief audio frequency spectrum class for cuSDR
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#include "cusdr_fspectrum.h"
FrequencySpectrum::FrequencySpectrum(int numPoints)
: m_elements(numPoints)
{
}
void FrequencySpectrum::reset() {
iterator i = begin();
for ( ; i != end(); ++i)
*i = Element();
}
int FrequencySpectrum::count() const {
return m_elements.count();
}
FrequencySpectrum::Element& FrequencySpectrum::operator[](int index) {
return m_elements[index];
}
const FrequencySpectrum::Element& FrequencySpectrum::operator[](int index) const {
return m_elements[index];
}
FrequencySpectrum::iterator FrequencySpectrum::begin() {
return m_elements.begin();
}
FrequencySpectrum::iterator FrequencySpectrum::end() {
return m_elements.end();
}
FrequencySpectrum::const_iterator FrequencySpectrum::begin() const {
return m_elements.begin();
}
FrequencySpectrum::const_iterator FrequencySpectrum::end() const {
return m_elements.end();
}
+103
View File
@@ -0,0 +1,103 @@
/**
* @file cusdr_fspectrum.h
* @brief audio frequency spectrum header file for cuSDR
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef FREQUENCYSPECTRUM_H
#define FREQUENCYSPECTRUM_H
#include <QtCore/QVector>
/**
* Represents a frequency spectrum as a series of elements, each of which
* consists of a frequency, an amplitude and a phase.
*/
class FrequencySpectrum {
public:
FrequencySpectrum(int numPoints = 0);
struct Element {
Element()
: frequency(0.0), amplitude(0.0), phase(0.0), clipped(false)
{ }
/**
* Frequency in Hertz
*/
qreal frequency;
/**
* Amplitude in range [0.0, 1.0]
*/
qreal amplitude;
/**
* Phase in range [0.0, 2*PI]
*/
qreal phase;
/**
* Indicates whether value has been clipped during spectrum analysis
*/
bool clipped;
};
typedef QVector<Element>::iterator iterator;
typedef QVector<Element>::const_iterator const_iterator;
void reset();
int count() const;
Element& operator[](int index);
const Element& operator[](int index) const;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
private:
QVector<Element> m_elements;
};
#endif // FREQUENCYSPECTRUM_H
+167
View File
@@ -0,0 +1,167 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLBUFFER_H
#define QCLBUFFER_H
#include "qclmemoryobject.h"
#include "qclevent.h"
#include <QtCore/qrect.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLImage2D;
class QCLImage3D;
class Q_CL_EXPORT QCLBuffer : public QCLMemoryObject
{
public:
QCLBuffer() {}
QCLBuffer(QCLContext *context, cl_mem id)
: QCLMemoryObject(context, id) {}
QCLBuffer(const QCLBuffer &other)
: QCLMemoryObject() { setId(other.context(), other.memoryId()); }
QCLBuffer &operator=(const QCLBuffer &other)
{
setId(other.context(), other.memoryId());
return *this;
}
bool read(void *data, size_t size);
bool read(size_t offset, void *data, size_t size);
QCLEvent readAsync(size_t offset, void *data, size_t size,
const QCLEventList &after = QCLEventList());
bool readRect(const QRect &rect, void *data,
size_t bufferBytesPerLine, size_t hostBytesPerLine);
bool readRect(const size_t origin[3], const size_t size[3], void *data,
size_t bufferBytesPerLine, size_t bufferBytesPerSlice,
size_t hostBytesPerLine, size_t hostBytesPerSlice);
QCLEvent readRectAsync
(const QRect &rect, void *data,
size_t bufferBytesPerLine, size_t hostBytesPerLine,
const QCLEventList &after = QCLEventList());
QCLEvent readRectAsync
(const size_t origin[3], const size_t size[3], void *data,
size_t bufferBytesPerLine, size_t bufferBytesPerSlice,
size_t hostBytesPerLine, size_t hostBytesPerSlice,
const QCLEventList &after = QCLEventList());
bool write(const void *data, size_t size);
bool write(size_t offset, const void *data, size_t size);
QCLEvent writeAsync(size_t offset, const void *data, size_t size,
const QCLEventList &after = QCLEventList());
bool writeRect(const QRect &rect, const void *data,
size_t bufferBytesPerLine, size_t hostBytesPerLine);
bool writeRect(const size_t origin[3], const size_t size[3],
const void *data, size_t bufferBytesPerLine,
size_t bufferBytesPerSlice, size_t hostBytesPerLine,
size_t hostBytesPerSlice);
QCLEvent writeRectAsync
(const QRect &rect, const void *data,
size_t bufferBytesPerLine, size_t hostBytesPerLine,
const QCLEventList &after = QCLEventList());
QCLEvent writeRectAsync
(const size_t origin[3], const size_t size[3], const void *data,
size_t bufferBytesPerLine, size_t bufferBytesPerSlice,
size_t hostBytesPerLine, size_t hostBytesPerSlice,
const QCLEventList &after = QCLEventList());
bool copyTo(size_t offset, size_t size,
const QCLBuffer &dest, size_t destOffset);
bool copyTo(size_t offset, const QCLImage2D &dest, const QRect &rect);
bool copyTo(size_t offset, const QCLImage3D &dest,
const size_t origin[3], const size_t size[3]);
QCLEvent copyToAsync
(size_t offset, size_t size,
const QCLBuffer &dest, size_t destOffset,
const QCLEventList &after = QCLEventList());
QCLEvent copyToAsync
(size_t offset, const QCLImage2D &dest, const QRect &rect,
const QCLEventList &after = QCLEventList());
QCLEvent copyToAsync
(size_t offset, const QCLImage3D &dest,
const size_t origin[3], const size_t size[3],
const QCLEventList &after = QCLEventList());
bool copyToRect(const QRect &rect, const QCLBuffer &dest,
const QPoint &destPoint, size_t bufferBytesPerLine,
size_t destBytesPerLine);
bool copyToRect(const size_t origin[3], const size_t size[3],
const QCLBuffer &dest, const size_t destOrigin[3],
size_t bufferBytesPerLine, size_t bufferBytesPerSlice,
size_t destBytesPerLine, size_t destBytesPerSlice);
QCLEvent copyToRectAsync
(const QRect &rect, const QCLBuffer &dest, const QPoint &destPoint,
size_t bufferBytesPerLine, size_t destBytesPerLine,
const QCLEventList &after = QCLEventList());
QCLEvent copyToRectAsync
(const size_t origin[3], const size_t size[3],
const QCLBuffer &dest, const size_t destOrigin[3],
size_t bufferBytesPerLine, size_t bufferBytesPerSlice,
size_t destBytesPerLine, size_t destBytesPerSlice,
const QCLEventList &after = QCLEventList());
void *map(size_t offset, size_t size, QCLMemoryObject::Access access);
void *map(QCLMemoryObject::Access access);
QCLEvent mapAsync(void **ptr, size_t offset, size_t size,
QCLMemoryObject::Access access,
const QCLEventList &after = QCLEventList());
QCLBuffer createSubBuffer
(size_t offset, size_t size, QCLMemoryObject::Access access);
QCLBuffer parentBuffer() const;
size_t offset() const;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif
+120
View File
@@ -0,0 +1,120 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLCOMMANDQUEUE_H
#define QCLCOMMANDQUEUE_H
#include "qclglobal.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLContext;
class Q_CL_EXPORT QCLCommandQueue
{
public:
QCLCommandQueue() : m_id(0) {}
QCLCommandQueue(QCLContext *context, cl_command_queue id)
: m_context(context), m_id(id) {}
QCLCommandQueue(const QCLCommandQueue &other);
~QCLCommandQueue();
QCLCommandQueue &operator=(const QCLCommandQueue &other);
bool isNull() const { return m_id == 0; }
bool isOutOfOrder() const;
bool isProfilingEnabled() const;
cl_command_queue queueId() const { return m_id; }
QCLContext *context() const { return m_context; }
bool operator==(const QCLCommandQueue &other) const;
bool operator!=(const QCLCommandQueue &other) const;
private:
QCLContext *m_context;
cl_command_queue m_id;
};
inline QCLCommandQueue::QCLCommandQueue(const QCLCommandQueue &other)
: m_context(other.m_context), m_id(other.m_id)
{
if (m_id)
clRetainCommandQueue(m_id);
}
inline QCLCommandQueue::~QCLCommandQueue()
{
if (m_id)
clReleaseCommandQueue(m_id);
}
inline QCLCommandQueue &QCLCommandQueue::operator=(const QCLCommandQueue &other)
{
m_context = other.m_context;
if (other.m_id)
clRetainCommandQueue(other.m_id);
if (m_id)
clReleaseCommandQueue(m_id);
m_id = other.m_id;
return *this;
}
inline bool QCLCommandQueue::operator==(const QCLCommandQueue &other) const
{
return m_id == other.m_id;
}
inline bool QCLCommandQueue::operator!=(const QCLCommandQueue &other) const
{
return m_id != other.m_id;
}
QT_END_NAMESPACE
QT_END_HEADER
#endif
+202
View File
@@ -0,0 +1,202 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLCONTEXT_H
#define QCLCONTEXT_H
#include "qcldevice.h"
#include "qclcommandqueue.h"
#include "qclbuffer.h"
#include "qclvector.h"
#include "qclimage.h"
#include "qclsampler.h"
#include "qclprogram.h"
#include "qcluserevent.h"
#include <QtCore/qscopedpointer.h>
#include <QtCore/qsize.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qstring.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLContextPrivate;
class QCLKernel;
class QCLVectorBase;
class Q_CL_EXPORT QCLContext
{
public:
QCLContext();
virtual ~QCLContext();
bool isCreated() const;
bool create(QCLDevice::DeviceTypes type = QCLDevice::Default);
bool create(const QList<QCLDevice> &devices);
virtual void release();
cl_context contextId() const;
void setContextId(cl_context id);
QList<QCLDevice> devices() const;
QCLDevice defaultDevice() const;
cl_int lastError() const;
void setLastError(cl_int error);
static QString errorName(cl_int code);
QCLCommandQueue commandQueue();
void setCommandQueue(const QCLCommandQueue &queue);
QCLCommandQueue defaultCommandQueue();
QCLCommandQueue createCommandQueue
(cl_command_queue_properties properties,
const QCLDevice &device = QCLDevice());
QCLBuffer createBufferDevice
(size_t size, QCLMemoryObject::Access access);
QCLBuffer createBufferHost
(void *data, size_t size, QCLMemoryObject::Access access);
QCLBuffer createBufferCopy
(const void *data, size_t size, QCLMemoryObject::Access access);
template <typename T>
QCLVector<T> createVector(int size, QCLMemoryObject::Access access = QCLMemoryObject::ReadWrite);
QCLImage2D createImage2DDevice
(const QCLImageFormat &format, const QSize &size, QCLMemoryObject::Access access);
QCLImage2D createImage2DHost
(const QCLImageFormat &format, void *data, const QSize &size,
QCLMemoryObject::Access access, int bytesPerLine = 0);
QCLImage2D createImage2DHost(QImage *image, QCLMemoryObject::Access access);
QCLImage2D createImage2DCopy
(const QCLImageFormat &format, const void *data, const QSize &size,
QCLMemoryObject::Access access, int bytesPerLine = 0);
QCLImage2D createImage2DCopy
(const QImage &image, QCLMemoryObject::Access access);
QCLImage3D createImage3DDevice
(const QCLImageFormat &format, int width, int height, int depth,
QCLMemoryObject::Access access);
QCLImage3D createImage3DHost
(const QCLImageFormat &format, void *data,
int width, int height, int depth, QCLMemoryObject::Access access,
int bytesPerLine = 0, int bytesPerSlice = 0);
QCLImage3D createImage3DCopy
(const QCLImageFormat &format, const void *data,
int width, int height, int depth, QCLMemoryObject::Access access,
int bytesPerLine = 0, int bytesPerSlice = 0);
QCLProgram createProgramFromSourceCode(const QByteArray &sourceCode);
QCLProgram createProgramFromSourceFile(const QString &fileName);
QCLProgram createProgramFromBinaryCode(const QByteArray &binary);
QCLProgram createProgramFromBinaryFile(const QString &fileName);
QCLProgram createProgramFromBinaries
(const QList<QCLDevice> &devices, const QList<QByteArray> &binaries);
QCLProgram buildProgramFromSourceCode(const QByteArray &sourceCode);
QCLProgram buildProgramFromSourceFile(const QString &fileName);
QCLProgram buildProgramFromBinaryCode(const QByteArray &binary);
QCLProgram buildProgramFromBinaryFile(const QString &fileName);
QCLProgram buildProgramFromBinaries
(const QList<QCLDevice> &devices, const QList<QByteArray> &binaries);
QList<QCLImageFormat> supportedImage2DFormats(cl_mem_flags flags) const;
QList<QCLImageFormat> supportedImage3DFormats(cl_mem_flags flags) const;
QCLSampler createSampler
(bool normalizedCoordinates, QCLSampler::AddressingMode addressingMode,
QCLSampler::FilterMode filterMode);
QCLUserEvent createUserEvent();
void flush();
void finish();
QCLEvent marker();
void sync();
void barrier();
void barrier(const QCLEventList &events);
protected:
void setDefaultDevice(const QCLDevice &device);
private:
QScopedPointer<QCLContextPrivate> d_ptr;
Q_DISABLE_COPY(QCLContext)
Q_DECLARE_PRIVATE(QCLContext)
cl_command_queue activeQueue(); // For quicker access from friends.
friend class QCLMemoryObject;
friend class QCLBuffer;
friend class QCLImage2D;
friend class QCLImage3D;
friend class QCLKernel;
friend class QCLCommandQueue;
friend class QCLProgram;
friend class QCLVectorBase;
friend class QCLSampler;
void reportError(const char *name, cl_int error);
};
template <typename T>
Q_INLINE_TEMPLATE QCLVector<T> QCLContext::createVector
(int size, QCLMemoryObject::Access access)
{
Q_ASSERT(size >= 1);
return QCLVector<T>(this, size, access);
}
QT_END_NAMESPACE
QT_END_HEADER
#endif
+208
View File
@@ -0,0 +1,208 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLDEVICE_H
#define QCLDEVICE_H
#include "qclplatform.h"
#include "qclworksize.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class Q_CL_EXPORT QCLDevice
{
public:
QCLDevice() : m_id(0), m_flags(0) {}
QCLDevice(cl_device_id id) : m_id(id), m_flags(0) {}
enum DeviceType
{
Default = 0x00000001,
CPU = 0x00000002,
GPU = 0x00000004,
Accelerator = 0x00000008,
All = 0xFFFFFFFF
};
Q_DECLARE_FLAGS(DeviceTypes, DeviceType)
bool isNull() const { return m_id == 0; }
QCLDevice::DeviceTypes deviceType() const;
QCLPlatform platform() const;
uint vendorId() const;
bool isAvailable() const;
bool hasCompiler() const;
bool hasNativeKernels() const;
bool hasOutOfOrderExecution() const;
bool hasDouble() const;
bool hasHalfFloat() const;
bool hasErrorCorrectingMemory() const;
bool hasUnifiedMemory() const;
int computeUnits() const;
int clockFrequency() const;
int addressBits() const;
QSysInfo::Endian byteOrder() const;
QCLWorkSize maximumWorkItemSize() const;
size_t maximumWorkItemsPerGroup() const;
bool hasImage2D() const;
bool hasImage3D() const;
bool hasWritableImage3D() const;
QSize maximumImage2DSize() const;
QCLWorkSize maximumImage3DSize() const;
int maximumSamplers() const;
int maximumReadImages() const;
int maximumWriteImages() const;
int preferredCharVectorSize() const;
int preferredShortVectorSize() const;
int preferredIntVectorSize() const;
int preferredLongVectorSize() const;
int preferredFloatVectorSize() const;
int preferredDoubleVectorSize() const;
int preferredHalfFloatVectorSize() const;
int nativeCharVectorSize() const;
int nativeShortVectorSize() const;
int nativeIntVectorSize() const;
int nativeLongVectorSize() const;
int nativeFloatVectorSize() const;
int nativeDoubleVectorSize() const;
int nativeHalfFloatVectorSize() const;
enum FloatCapability
{
NotSupported = 0x0000,
Denorm = 0x0001,
InfinityNaN = 0x0002,
RoundNearest = 0x0004,
RoundZero = 0x0008,
RoundInfinity = 0x0010,
FusedMultiplyAdd = 0x0020
};
Q_DECLARE_FLAGS(FloatCapabilities, FloatCapability)
QCLDevice::FloatCapabilities floatCapabilities() const;
QCLDevice::FloatCapabilities doubleCapabilities() const;
QCLDevice::FloatCapabilities halfFloatCapabilities() const;
quint64 profilingTimerResolution() const;
enum CacheType
{
NoCache = 0,
ReadOnlyCache = 1,
ReadWriteCache = 2
};
quint64 maximumAllocationSize() const;
quint64 globalMemorySize() const;
QCLDevice::CacheType globalMemoryCacheType() const;
quint64 globalMemoryCacheSize() const;
int globalMemoryCacheLineSize() const;
quint64 localMemorySize() const;
bool isLocalMemorySeparate() const;
quint64 maximumConstantBufferSize() const;
int maximumConstantArguments() const;
int defaultAlignment() const;
int minimumAlignment() const;
int maximumParameterBytes() const;
bool isFullProfile() const;
bool isEmbeddedProfile() const;
QString profile() const;
QString version() const;
QString driverVersion() const;
QString name() const;
QString vendor() const;
QStringList extensions() const;
QString languageVersion() const;
bool hasExtension(const char *name) const;
QCLPlatform::VersionFlags versionFlags() const;
cl_device_id deviceId() const { return m_id; }
static QList<QCLDevice> allDevices();
static QList<QCLDevice> devices
(QCLDevice::DeviceTypes types,
const QCLPlatform &platform = QCLPlatform());
bool operator==(const QCLDevice &other) const;
bool operator!=(const QCLDevice &other) const;
private:
cl_device_id m_id;
mutable int m_flags;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QCLDevice::DeviceTypes)
Q_DECLARE_OPERATORS_FOR_FLAGS(QCLDevice::FloatCapabilities)
inline bool QCLDevice::operator==(const QCLDevice &other) const
{
return m_id == other.m_id;
}
inline bool QCLDevice::operator!=(const QCLDevice &other) const
{
return m_id != other.m_id;
}
#ifndef QT_NO_DEBUG_STREAM
Q_CL_EXPORT QDebug operator<<(QDebug, const QCLDevice &);
#endif
QT_END_NAMESPACE
QT_END_HEADER
#endif
+230
View File
@@ -0,0 +1,230 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLEVENT_H
#define QCLEVENT_H
#include "qclglobal.h"
#include <QtCore/qvector.h>
#include <QtCore/qfuture.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLUserEvent;
class Q_CL_EXPORT QCLEvent
{
public:
QCLEvent() : m_id(0) {}
QCLEvent(cl_event id) : m_id(id) {}
QCLEvent(const QCLEvent &other);
~QCLEvent();
QCLEvent &operator=(const QCLEvent &other);
bool isNull() const { return m_id == 0; }
cl_event eventId() const { return m_id; }
bool isQueued() const { return status() == CL_QUEUED; }
bool isSubmitted() const { return status() == CL_SUBMITTED; }
bool isRunning() const { return status() == CL_RUNNING; }
bool isFinished() const { return status() == CL_COMPLETE; }
bool isErrored() const { return status() < 0; }
cl_int status() const;
cl_command_type commandType() const;
void waitForFinished();
quint64 queueTime() const;
quint64 submitTime() const;
quint64 runTime() const;
quint64 finishTime() const;
bool operator==(const QCLEvent &other) const;
bool operator!=(const QCLEvent &other) const;
#if !defined(QT_NO_CONCURRENT)
QFuture<void> toFuture() const;
operator QFuture<void>() const;
#endif
private:
cl_event m_id;
friend class QCLUserEvent;
};
inline QCLEvent::QCLEvent(const QCLEvent &other)
: m_id(other.m_id)
{
if (m_id)
clRetainEvent(m_id);
}
inline QCLEvent::~QCLEvent()
{
if (m_id)
clReleaseEvent(m_id);
}
inline QCLEvent &QCLEvent::operator=(const QCLEvent &other)
{
if (other.m_id)
clRetainEvent(other.m_id);
if (m_id)
clReleaseEvent(m_id);
m_id = other.m_id;
return *this;
}
class Q_CL_EXPORT QCLEventList
{
public:
QCLEventList() {}
QCLEventList(const QCLEvent &event);
QCLEventList(const QCLEventList &other);
~QCLEventList();
QCLEventList &operator=(const QCLEventList &other);
bool isEmpty() const { return m_events.isEmpty(); }
int size() const { return m_events.size(); }
void append(const QCLEvent &event);
void append(const QCLEventList &other);
void remove(const QCLEvent &event);
QCLEvent at(int index) const;
bool contains(const QCLEvent &event) const;
const cl_event *eventData() const;
QCLEventList &operator+=(const QCLEvent &event);
QCLEventList &operator+=(const QCLEventList &other);
QCLEventList &operator<<(const QCLEvent &event);
QCLEventList &operator<<(const QCLEventList &other);
void waitForFinished();
#ifndef QT_NO_CONCURRENT
QFuture<void> toFuture() const;
operator QFuture<void>() const;
#endif
private:
QVector<cl_event> m_events;
};
inline bool QCLEvent::operator==(const QCLEvent &other) const
{
return m_id == other.m_id;
}
inline bool QCLEvent::operator!=(const QCLEvent &other) const
{
return m_id != other.m_id;
}
#ifndef QT_NO_CONCURRENT
inline QCLEvent::operator QFuture<void>() const
{
return toFuture();
}
#endif
inline bool QCLEventList::contains(const QCLEvent &event) const
{
return m_events.contains(event.eventId());
}
inline const cl_event *QCLEventList::eventData() const
{
return m_events.isEmpty() ? 0 : m_events.constData();
}
inline QCLEventList &QCLEventList::operator+=(const QCLEvent &event)
{
append(event);
return *this;
}
inline QCLEventList &QCLEventList::operator+=(const QCLEventList &other)
{
append(other);
return *this;
}
inline QCLEventList &QCLEventList::operator<<(const QCLEvent &event)
{
append(event);
return *this;
}
inline QCLEventList &QCLEventList::operator<<(const QCLEventList &other)
{
append(other);
return *this;
}
#ifndef QT_NO_CONCURRENT
inline QCLEventList::operator QFuture<void>() const
{
return toFuture();
}
#endif
#ifndef QT_NO_DEBUG_STREAM
Q_CL_EXPORT QDebug operator<<(QDebug, const QCLEvent &);
Q_CL_EXPORT QDebug operator<<(QDebug, const QCLEventList &);
#endif
QT_END_NAMESPACE
QT_END_HEADER
#endif
+131
View File
@@ -0,0 +1,131 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLEXT_P_H
#define QCLEXT_P_H
#include "qclglobal.h"
// This file provides standard and extension definitions
// that we cannot rely upon being present in the system headers.
// OpenCL 1.1
#ifndef CL_MISALIGNED_SUB_BUFFER_OFFSET
#define CL_MISALIGNED_SUB_BUFFER_OFFSET -13
#endif
#ifndef CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST
#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14
#endif
#ifndef CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF
#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034
#endif
#ifndef CL_DEVICE_HOST_UNIFIED_MEMORY
#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035
#endif
#ifndef CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR
#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036
#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037
#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038
#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039
#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A
#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B
#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C
#endif
#ifndef CL_DEVICE_OPENCL_C_VERSION
#define CL_DEVICE_OPENCL_C_VERSION 0x103D
#endif
#ifndef CL_COMMAND_READ_BUFFER_RECT
#define CL_COMMAND_READ_BUFFER_RECT 0x1201
#endif
#ifndef CL_COMMAND_WRITE_BUFFER_RECT
#define CL_COMMAND_WRITE_BUFFER_RECT 0x1202
#endif
#ifndef CL_COMMAND_COPY_BUFFER_RECT
#define CL_COMMAND_COPY_BUFFER_RECT 0x1203
#endif
#ifndef CL_COMMAND_USER
#define CL_COMMAND_USER 0x1204
#endif
#ifndef CL_MEM_ASSOCIATED_MEMOBJECT
#define CL_MEM_ASSOCIATED_MEMOBJECT 0x1107
#endif
#ifndef CL_MEM_OFFSET
#define CL_MEM_OFFSET 0x1108
#endif
#ifndef CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE
#define CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE 0x11B3
#endif
// OpenCL-OpenGL sharing.
#ifndef CL_INVALID_CL_SHAREGROUP_REFERENCE_KHR
#define CL_INVALID_CL_SHAREGROUP_REFERENCE_KHR -1000
#endif
// cl_khr_fp64
#ifndef CL_DEVICE_DOUBLE_FP_CONFIG
#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032
#endif
// cl_khr_fp16
#ifndef CL_DEVICE_HALF_FP_CONFIG
#define CL_DEVICE_HALF_FP_CONFIG 0x1033
#endif
// cl_khr_icd
#ifndef CL_PLATFORM_ICD_SUFFIX_KHR
#define CL_PLATFORM_ICD_SUFFIX_KHR 0x0920
#endif
#ifndef CL_PLATFORM_NOT_FOUND_KHR
#define CL_PLATFORM_NOT_FOUND_KHR -1001
#endif
// cl_ext_device_fission
#ifndef CL_DEVICE_PARTITION_FAILED_EXT
#define CL_DEVICE_PARTITION_FAILED_EXT -1057
#endif
#ifndef CL_INVALID_PARTITION_COUNT_EXT
#define CL_INVALID_PARTITION_COUNT_EXT -1058
#endif
#ifndef CL_INVALID_PARTITION_NAME_EXT
#define CL_INVALID_PARTITION_NAME_EXT -1059
#endif
#endif
+92
View File
@@ -0,0 +1,92 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLGLOBAL_H
#define QCLGLOBAL_H
#include <QtCore/qglobal.h>
// XXX: Move to qglobal.h eventually.
QT_LICENSED_MODULE(CL)
#if defined(Q_OS_WIN) && defined(QT_MAKEDLL)
# if defined(QT_BUILD_CL_LIB)
# define Q_CL_EXPORT Q_DECL_EXPORT
# else
# define Q_CL_EXPORT Q_DECL_IMPORT
# endif
#elif defined(Q_OS_WIN) && defined(QT_DLL)
# define Q_CL_EXPORT Q_DECL_IMPORT
#endif
#if !defined(Q_CL_EXPORT)
# if defined(QT_SHARED)
# define Q_CL_EXPORT Q_DECL_EXPORT
# else
# define Q_CL_EXPORT
# endif
#endif
QT_LICENSED_MODULE(CLGL)
#if defined(Q_OS_WIN) && defined(QT_MAKEDLL)
# if defined(QT_BUILD_CLGL_LIB)
# define Q_CLGL_EXPORT Q_DECL_EXPORT
# else
# define Q_CLGL_EXPORT Q_DECL_IMPORT
# endif
#elif defined(Q_OS_WIN) && defined(QT_DLL)
# define Q_CLGL_EXPORT Q_DECL_IMPORT
#endif
#if !defined(Q_CLGL_EXPORT)
# if defined(QT_SHARED)
# define Q_CLGL_EXPORT Q_DECL_EXPORT
# else
# define Q_CLGL_EXPORT
# endif
#endif
#if defined(__APPLE__) || defined(__MACOSX)
#include <OpenCL/cl_platform.h>
#include <OpenCL/cl.h>
#else
#include <CL/cl_platform.h>
#include <CL/cl.h>
#endif
#endif
+214
View File
@@ -0,0 +1,214 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLIMAGE_H
#define QCLIMAGE_H
#include "qclmemoryobject.h"
#include "qclimageformat.h"
#include "qclevent.h"
#include <QtCore/qrect.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLImage2DPrivate;
class QCLImage3D;
class QCLBuffer;
class QPainter;
class Q_CL_EXPORT QCLImage2D : public QCLMemoryObject
{
public:
QCLImage2D() : d_ptr(0) {}
QCLImage2D(QCLContext *context, cl_mem id)
: QCLMemoryObject(context, id), d_ptr(0) {}
QCLImage2D(const QCLImage2D &other);
~QCLImage2D();
QCLImage2D &operator=(const QCLImage2D &other);
QCLImageFormat format() const;
int width() const;
int height() const;
int bytesPerElement() const;
int bytesPerLine() const;
bool read(void *data, const QRect &rect, int bytesPerLine = 0);
bool read(QImage *image, const QRect &rect = QRect());
QCLEvent readAsync(void *data, const QRect &rect,
const QCLEventList &after = QCLEventList(),
int bytesPerLine = 0);
bool write(const void *data, const QRect &rect, int bytesPerLine = 0);
bool write(const QImage &image, const QRect &rect = QRect());
QCLEvent writeAsync
(const void *data, const QRect &rect,
const QCLEventList &after = QCLEventList(),
int bytesPerLine = 0);
bool copyTo(const QRect &rect, const QCLImage2D &dest,
const QPoint &destOffset);
bool copyTo(const QRect &rect, const QCLImage3D &dest,
const size_t destOffset[3]);
bool copyTo(const QRect &rect, const QCLBuffer &dest,
size_t destOffset);
QCLEvent copyToAsync
(const QRect &rect, const QCLImage2D &dest, const QPoint &destOffset,
const QCLEventList &after = QCLEventList());
QCLEvent copyToAsync
(const QRect &rect, const QCLImage3D &dest, const size_t destOffset[3],
const QCLEventList &after = QCLEventList());
QCLEvent copyToAsync
(const QRect &rect, const QCLBuffer &dest, size_t destOffset,
const QCLEventList &after = QCLEventList());
void *map(const QRect &rect, QCLMemoryObject::Access access,
int *bytesPerLine = 0);
QCLEvent mapAsync(void **ptr, const QRect &rect,
QCLMemoryObject::Access access,
const QCLEventList &after = QCLEventList(),
int *bytesPerLine = 0);
QImage toQImage(bool cached = true);
void drawImage(QPainter *painter, const QPoint &point,
const QRect &subRect = QRect(),
Qt::ImageConversionFlags flags = Qt::AutoColor);
void drawImage(QPainter *painter, const QRect &targetRect,
const QRect &subRect = QRect(),
Qt::ImageConversionFlags flags = Qt::AutoColor);
private:
mutable QCLImage2DPrivate *d_ptr;
Q_DECLARE_PRIVATE(QCLImage2D)
QCLImage2D(QCLContext *context, cl_mem id, const QCLImageFormat& format);
friend class QCLContext;
};
class Q_CL_EXPORT QCLImage3D : public QCLMemoryObject
{
public:
QCLImage3D() {}
QCLImage3D(QCLContext *context, cl_mem id)
: QCLMemoryObject(context, id) {}
QCLImage3D(const QCLImage3D &other)
: QCLMemoryObject() { setId(other.context(), other.memoryId()); }
QCLImage3D &operator=(const QCLImage3D &other)
{
setId(other.context(), other.memoryId());
return *this;
}
QCLImageFormat format() const;
int width() const;
int height() const;
int depth() const;
int bytesPerElement() const;
int bytesPerLine() const;
int bytesPerSlice() const;
bool read(void *data, const size_t origin[3], const size_t size[3],
int bytesPerLine = 0, int bytesPerSlice = 0);
QCLEvent readAsync
(void *data, const size_t origin[3], const size_t size[3],
const QCLEventList &after = QCLEventList(),
int bytesPerLine = 0, int bytesPerSlice = 0);
bool write(const void *data, const size_t origin[3], const size_t size[3],
int bytesPerLine = 0, int bytesPerSlice = 0);
QCLEvent writeAsync
(const void *data, const size_t origin[3], const size_t size[3],
const QCLEventList &after = QCLEventList(),
int bytesPerLine = 0, int bytesPerSlice = 0);
bool copyTo(const size_t origin[3], const size_t size[3],
const QCLImage3D &dest, const size_t destOffset[3]);
bool copyTo(const size_t origin[3], const QSize &size,
const QCLImage2D &dest, const QPoint &destOffset);
bool copyTo(const size_t origin[3], const size_t size[3],
const QCLBuffer &dest, size_t destOffset);
QCLEvent copyToAsync
(const size_t origin[3], const size_t size[3],
const QCLImage3D &dest, const size_t destOffset[3],
const QCLEventList &after = QCLEventList());
QCLEvent copyToAsync
(const size_t origin[3], const QSize &size,
const QCLImage2D &dest, const QPoint &destOffset,
const QCLEventList &after = QCLEventList());
QCLEvent copyToAsync
(const size_t origin[3], const size_t size[3],
const QCLBuffer &dest, size_t destOffset,
const QCLEventList &after = QCLEventList());
void *map(const size_t origin[3], const size_t size[3],
QCLMemoryObject::Access access,
int *bytesPerLine = 0, int *bytesPerSlice = 0);
QCLEvent mapAsync
(void **ptr, const size_t origin[3], const size_t size[3],
QCLMemoryObject::Access access,
const QCLEventList &after = QCLEventList(),
int *bytesPerLine = 0, int *bytesPerSlice = 0);
};
inline void QCLImage2D::drawImage
(QPainter *painter, const QPoint &point,
const QRect &subRect, Qt::ImageConversionFlags flags)
{
drawImage(painter, QRect(point.x(), point.y(), -1, -1), subRect, flags);
}
QT_END_NAMESPACE
QT_END_HEADER
#endif
+167
View File
@@ -0,0 +1,167 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLIMAGEFORMAT_H
#define QCLIMAGEFORMAT_H
#include "qclglobal.h"
#include <QtGui/qimage.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLContext;
class Q_CL_EXPORT QCLImageFormat
{
public:
enum ChannelOrder
{
Order_R = 0x10B0,
Order_A = 0x10B1,
Order_RG = 0x10B2,
Order_RA = 0x10B3,
Order_RGB = 0x10B4,
Order_RGBA = 0x10B5,
Order_BGRA = 0x10B6,
Order_ARGB = 0x10B7,
Order_Intensity = 0x10B8,
Order_Luminence = 0x10B9,
Order_Rx = 0x10BA, // OpenCL 1.1
Order_RGx = 0x10BB, // OpenCL 1.1
Order_RGBx = 0x10BC // OpenCL 1.1
};
enum ChannelType
{
Type_Normalized_Int8 = 0x10D0,
Type_Normalized_Int16 = 0x10D1,
Type_Normalized_UInt8 = 0x10D2,
Type_Normalized_UInt16 = 0x10D3,
Type_Normalized_565 = 0x10D4,
Type_Normalized_555 = 0x10D5,
Type_Normalized_101010 = 0x10D6,
Type_Unnormalized_Int8 = 0x10D7,
Type_Unnormalized_Int16 = 0x10D8,
Type_Unnormalized_Int32 = 0x10D9,
Type_Unnormalized_UInt8 = 0x10DA,
Type_Unnormalized_UInt16 = 0x10DB,
Type_Unnormalized_UInt32 = 0x10DC,
Type_Half_Float = 0x10DD,
Type_Float = 0x10DE
};
QCLImageFormat();
QCLImageFormat(QCLImageFormat::ChannelOrder order,
QCLImageFormat::ChannelType type);
QCLImageFormat(QImage::Format format);
bool isNull() const;
QCLImageFormat::ChannelOrder channelOrder() const;
QCLImageFormat::ChannelType channelType() const;
bool operator==(const QCLImageFormat &other);
bool operator!=(const QCLImageFormat &other);
QImage::Format toQImageFormat() const { return m_qformat; }
private:
cl_image_format m_format;
QImage::Format m_qformat;
friend class QCLContext;
};
inline QCLImageFormat::QCLImageFormat()
{
m_format.image_channel_order = 0;
m_format.image_channel_data_type = 0;
m_qformat = QImage::Format_Invalid;
}
inline bool QCLImageFormat::isNull() const
{
return m_format.image_channel_order == 0 &&
m_format.image_channel_data_type == 0 &&
m_qformat == QImage::Format_Invalid;
}
inline QCLImageFormat::ChannelOrder QCLImageFormat::channelOrder() const
{
return QCLImageFormat::ChannelOrder(m_format.image_channel_order);
}
inline QCLImageFormat::ChannelType QCLImageFormat::channelType() const
{
return QCLImageFormat::ChannelType(m_format.image_channel_data_type);
}
inline bool QCLImageFormat::operator==(const QCLImageFormat &other)
{
return m_format.image_channel_order ==
other.m_format.image_channel_order &&
m_format.image_channel_data_type ==
other.m_format.image_channel_data_type &&
m_qformat == other.m_qformat;
}
inline bool QCLImageFormat::operator!=(const QCLImageFormat &other)
{
return m_format.image_channel_order !=
other.m_format.image_channel_order ||
m_format.image_channel_data_type !=
other.m_format.image_channel_data_type ||
m_qformat != other.m_qformat;
}
#ifndef QT_NO_DEBUG_STREAM
Q_CL_EXPORT QDebug operator<<(QDebug, const QCLImageFormat &);
#endif
QT_END_NAMESPACE
QT_END_HEADER
#endif
+480
View File
@@ -0,0 +1,480 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLKERNEL_H
#define QCLKERNEL_H
#include "qclglobal.h"
#include "qclevent.h"
#include "qclworksize.h"
#include "qclmemoryobject.h"
#include "qclsampler.h"
#include "qclvector.h"
#include <QtCore/qstring.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qtconcurrentrun.h>
#include <QtCore/qpoint.h>
#include <QtGui/qvector2d.h>
#include <QtGui/qvector3d.h>
#include <QtGui/qvector4d.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLContext;
class QCLProgram;
class QCLVectorBase;
class QCLDevice;
class QMatrix4x4;
class QColor;
class QCLKernelPrivate;
class Q_CL_EXPORT QCLKernel
{
public:
QCLKernel();
QCLKernel(QCLContext *context, cl_kernel id);
QCLKernel(const QCLKernel &other);
~QCLKernel();
QCLKernel &operator=(const QCLKernel &other);
bool isNull() const;
bool operator==(const QCLKernel &other) const;
bool operator!=(const QCLKernel &other) const;
cl_kernel kernelId() const;
QCLContext *context() const;
QCLProgram program() const;
QString name() const;
int argCount() const;
QCLWorkSize declaredWorkGroupSize() const;
QCLWorkSize declaredWorkGroupSize(const QCLDevice &device) const;
QCLWorkSize globalWorkSize() const;
void setGlobalWorkSize(const QCLWorkSize &size);
void setGlobalWorkSize(size_t width, size_t height);
void setGlobalWorkSize(size_t width, size_t height, size_t depth);
void setRoundedGlobalWorkSize(const QCLWorkSize &size);
void setRoundedGlobalWorkSize(size_t width, size_t height);
void setRoundedGlobalWorkSize(size_t width, size_t height, size_t depth);
QCLWorkSize localWorkSize() const;
void setLocalWorkSize(const QCLWorkSize &size);
void setLocalWorkSize(size_t width, size_t height);
void setLocalWorkSize(size_t width, size_t height, size_t depth);
QCLWorkSize bestLocalWorkSizeImage2D() const;
QCLWorkSize bestLocalWorkSizeImage3D() const;
size_t preferredWorkSizeMultiple() const;
void setArg(int index, cl_int value);
void setArg(int index, cl_uint value);
void setArg(int index, cl_long value);
void setArg(int index, cl_ulong value);
void setArg(int index, float value);
void setArg(int index, const QVector2D &value);
void setArg(int index, const QVector3D &value);
void setArg(int index, const QVector4D &value);
void setArg(int index, const QColor &value);
void setArg(int index, Qt::GlobalColor value);
void setArg(int index, const QPoint &value);
void setArg(int index, const QPointF &value);
void setArg(int index, const QMatrix4x4 &value);
void setArg(int index, const QCLMemoryObject &value);
#if defined(qdoc)
void setArg(int index, const QCLVector<T> &value);
#else
void setArg(int index, const QCLVectorBase &value);
#endif
void setArg(int index, const QCLSampler &value);
void setArg(int index, const void *data, size_t size);
QCLEvent run();
QCLEvent run(const QCLEventList &after);
inline QCLEvent operator()() { return run(); }
template <typename T1>
inline QCLEvent operator()(const T1 &arg1)
{
setArg(0, arg1);
return run();
}
template <typename T1, typename T2>
inline QCLEvent operator()(const T1 &arg1, const T2 &arg2)
{
setArg(0, arg1);
setArg(1, arg2);
return run();
}
template <typename T1, typename T2, typename T3>
inline QCLEvent operator()
(const T1 &arg1, const T2 &arg2, const T3 &arg3)
{
setArg(0, arg1);
setArg(1, arg2);
setArg(2, arg3);
return run();
}
template <typename T1, typename T2, typename T3, typename T4>
inline QCLEvent operator()
(const T1 &arg1, const T2 &arg2, const T3 &arg3, const T4 &arg4)
{
setArg(0, arg1);
setArg(1, arg2);
setArg(2, arg3);
setArg(3, arg4);
return run();
}
template <typename T1, typename T2, typename T3, typename T4,
typename T5>
inline QCLEvent operator()
(const T1 &arg1, const T2 &arg2, const T3 &arg3, const T4 &arg4,
const T5 &arg5)
{
setArg(0, arg1);
setArg(1, arg2);
setArg(2, arg3);
setArg(3, arg4);
setArg(4, arg5);
return run();
}
template <typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6>
inline QCLEvent operator()
(const T1 &arg1, const T2 &arg2, const T3 &arg3, const T4 &arg4,
const T5 &arg5, const T6 &arg6)
{
setArg(0, arg1);
setArg(1, arg2);
setArg(2, arg3);
setArg(3, arg4);
setArg(4, arg5);
setArg(5, arg6);
return run();
}
template <typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7>
inline QCLEvent operator()
(const T1 &arg1, const T2 &arg2, const T3 &arg3, const T4 &arg4,
const T5 &arg5, const T6 &arg6, const T7 &arg7)
{
setArg(0, arg1);
setArg(1, arg2);
setArg(2, arg3);
setArg(3, arg4);
setArg(4, arg5);
setArg(5, arg6);
setArg(6, arg7);
return run();
}
template <typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8>
inline QCLEvent operator()
(const T1 &arg1, const T2 &arg2, const T3 &arg3, const T4 &arg4,
const T5 &arg5, const T6 &arg6, const T7 &arg7, const T8 &arg8)
{
setArg(0, arg1);
setArg(1, arg2);
setArg(2, arg3);
setArg(3, arg4);
setArg(4, arg5);
setArg(5, arg6);
setArg(6, arg7);
setArg(7, arg8);
return run();
}
template <typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9>
inline QCLEvent operator()
(const T1 &arg1, const T2 &arg2, const T3 &arg3, const T4 &arg4,
const T5 &arg5, const T6 &arg6, const T7 &arg7, const T8 &arg8,
const T9 &arg9)
{
setArg(0, arg1);
setArg(1, arg2);
setArg(2, arg3);
setArg(3, arg4);
setArg(4, arg5);
setArg(5, arg6);
setArg(6, arg7);
setArg(7, arg8);
setArg(8, arg9);
return run();
}
template <typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8,
typename T9, typename T10>
inline QCLEvent operator()
(const T1 &arg1, const T2 &arg2, const T3 &arg3, const T4 &arg4,
const T5 &arg5, const T6 &arg6, const T7 &arg7, const T8 &arg8,
const T9 &arg9, const T10 &arg10)
{
setArg(0, arg1);
setArg(1, arg2);
setArg(2, arg3);
setArg(3, arg4);
setArg(4, arg5);
setArg(5, arg6);
setArg(6, arg7);
setArg(7, arg8);
setArg(8, arg9);
setArg(9, arg10);
return run();
}
#ifndef QT_NO_CONCURRENT
QFuture<void> runInThread();
#endif
private:
QScopedPointer<QCLKernelPrivate> d_ptr;
cl_kernel m_kernelId;
Q_DECLARE_PRIVATE(QCLKernel)
};
inline void QCLKernel::setGlobalWorkSize(size_t width, size_t height)
{
setGlobalWorkSize(QCLWorkSize(width, height));
}
inline void QCLKernel::setGlobalWorkSize(size_t width, size_t height, size_t depth)
{
setGlobalWorkSize(QCLWorkSize(width, height, depth));
}
inline void QCLKernel::setRoundedGlobalWorkSize(const QCLWorkSize &size)
{
setGlobalWorkSize(size.roundTo(localWorkSize()));
}
inline void QCLKernel::setRoundedGlobalWorkSize(size_t width, size_t height)
{
setRoundedGlobalWorkSize(QCLWorkSize(width, height));
}
inline void QCLKernel::setRoundedGlobalWorkSize(size_t width, size_t height, size_t depth)
{
setRoundedGlobalWorkSize(QCLWorkSize(width, height, depth));
}
inline void QCLKernel::setLocalWorkSize(size_t width, size_t height)
{
setLocalWorkSize(QCLWorkSize(width, height));
}
inline void QCLKernel::setLocalWorkSize(size_t width, size_t height, size_t depth)
{
setLocalWorkSize(QCLWorkSize(width, height, depth));
}
inline void QCLKernel::setArg(int index, cl_int value)
{
clSetKernelArg(m_kernelId, index, sizeof(value), &value);
}
inline void QCLKernel::setArg(int index, cl_uint value)
{
clSetKernelArg(m_kernelId, index, sizeof(value), &value);
}
inline void QCLKernel::setArg(int index, cl_long value)
{
clSetKernelArg(m_kernelId, index, sizeof(value), &value);
}
inline void QCLKernel::setArg(int index, cl_ulong value)
{
clSetKernelArg(m_kernelId, index, sizeof(value), &value);
}
inline void QCLKernel::setArg(int index, float value)
{
clSetKernelArg(m_kernelId, index, sizeof(value), &value);
}
inline void QCLKernel::setArg(int index, const QVector2D &value)
{
if (sizeof(value) == (sizeof(float) * 2)) {
clSetKernelArg(m_kernelId, index, sizeof(value), &value);
} else {
float values[2] = {(float)value.x(), (float)value.y()};
clSetKernelArg(m_kernelId, index, sizeof(values), values);
}
}
inline void QCLKernel::setArg(int index, const QVector3D &value)
{
float values[4] = {(float)value.x(), (float)value.y(), (float)value.z(), 1.0f};
clSetKernelArg(m_kernelId, index, sizeof(values), values);
}
inline void QCLKernel::setArg(int index, const QVector4D &value)
{
if (sizeof(value) == (sizeof(float) * 4)) {
clSetKernelArg(m_kernelId, index, sizeof(value), &value);
} else {
float values[4] = {(float)value.x(), (float)value.y(), (float)value.z(), (float)value.w()};
clSetKernelArg(m_kernelId, index, sizeof(values), values);
}
}
inline void QCLKernel::setArg(int index, const QPoint &value)
{
cl_int values[2] = {value.x(), value.y()};
clSetKernelArg(m_kernelId, index, sizeof(values), values);
}
inline void QCLKernel::setArg(int index, const QPointF &value)
{
if (sizeof(value) == (sizeof(float) * 2)) {
clSetKernelArg(m_kernelId, index, sizeof(value), &value);
} else {
float values[2] = {(float)value.x(), (float)value.y()};
clSetKernelArg(m_kernelId, index, sizeof(values), values);
}
}
inline void QCLKernel::setArg(int index, const QCLMemoryObject &value)
{
cl_mem id = value.memoryId();
clSetKernelArg(m_kernelId, index, sizeof(id), &id);
}
inline void QCLKernel::setArg(int index, const QCLVectorBase &value)
{
cl_mem id = value.kernelArg();
clSetKernelArg(m_kernelId, index, sizeof(id), &id);
}
inline void QCLKernel::setArg(int index, const QCLSampler &value)
{
cl_sampler id = value.samplerId();
clSetKernelArg(m_kernelId, index, sizeof(id), &id);
}
inline void QCLKernel::setArg(int index, const void *data, size_t size)
{
clSetKernelArg(m_kernelId, index, size, data);
}
#ifndef QT_NO_CONCURRENT
// Convenience function definitions that make it possible to say
// QtConcurrent::run(kernel, ...) and have it do the right thing.
namespace QtConcurrent
{
inline QFuture<void> run(QCLKernel &kernel)
{
return kernel.runInThread();
}
template <typename Arg1>
inline QFuture<void> run(QCLKernel &kernel, const Arg1 &arg1)
{
kernel.setArg(0, arg1);
return kernel.runInThread();
}
template <typename Arg1, typename Arg2>
inline QFuture<void> run(QCLKernel &kernel, const Arg1 &arg1, const Arg2 &arg2)
{
kernel.setArg(0, arg1);
kernel.setArg(1, arg2);
return kernel.runInThread();
}
template <typename Arg1, typename Arg2, typename Arg3>
inline QFuture<void> run(QCLKernel &kernel, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
{
kernel.setArg(0, arg1);
kernel.setArg(1, arg2);
kernel.setArg(2, arg3);
return kernel.runInThread();
}
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
inline QFuture<void> run(QCLKernel &kernel, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
{
kernel.setArg(0, arg1);
kernel.setArg(1, arg2);
kernel.setArg(2, arg3);
kernel.setArg(3, arg4);
return kernel.runInThread();
}
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
inline QFuture<void> run(QCLKernel &kernel, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
{
kernel.setArg(0, arg1);
kernel.setArg(1, arg2);
kernel.setArg(2, arg3);
kernel.setArg(3, arg4);
kernel.setArg(4, arg5);
return kernel.runInThread();
}
} // namespace QtConcurrent
#endif // QT_NO_CONCURRENT
QT_END_NAMESPACE
QT_END_HEADER
#endif
+128
View File
@@ -0,0 +1,128 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLMEMORYOBJECT_H
#define QCLMEMORYOBJECT_H
#include "qclevent.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLContext;
class Q_CL_EXPORT QCLMemoryObject
{
protected:
QCLMemoryObject(QCLContext *context = 0) : m_context(context), m_id(0) {}
QCLMemoryObject(QCLContext *context, cl_mem id)
: m_context(context), m_id(id) {}
~QCLMemoryObject();
public:
enum Access
{
ReadWrite = 0x0001,
WriteOnly = 0x0002,
ReadOnly = 0x0004
};
bool isNull() const { return m_id == 0; }
cl_mem memoryId() const { return m_id; }
QCLContext *context() const { return m_context; }
QCLMemoryObject::Access access() const;
cl_mem_flags flags() const;
void *hostPointer() const;
size_t size() const;
void unmap(void *ptr);
QCLEvent unmapAsync
(void *ptr, const QCLEventList &after = QCLEventList());
bool operator==(const QCLMemoryObject &other) const;
bool operator!=(const QCLMemoryObject &other) const;
protected:
void setId(QCLContext *context, cl_mem id);
private:
QCLContext *m_context;
cl_mem m_id;
Q_DISABLE_COPY(QCLMemoryObject)
};
inline QCLMemoryObject::~QCLMemoryObject()
{
if (m_id)
clReleaseMemObject(m_id);
}
inline bool QCLMemoryObject::operator==(const QCLMemoryObject &other) const
{
return m_id == other.m_id;
}
inline bool QCLMemoryObject::operator!=(const QCLMemoryObject &other) const
{
return m_id != other.m_id;
}
inline void QCLMemoryObject::setId(QCLContext *context, cl_mem id)
{
m_context = context;
if (id)
clRetainMemObject(id);
if (m_id)
clReleaseMemObject(m_id);
m_id = id;
}
QT_END_NAMESPACE
QT_END_HEADER
#endif
+117
View File
@@ -0,0 +1,117 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLPLATFORM_H
#define QCLPLATFORM_H
#include "qclglobal.h"
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class Q_CL_EXPORT QCLPlatform
{
public:
QCLPlatform() : m_id(0), m_flags(0) {}
QCLPlatform(cl_platform_id id) : m_id(id), m_flags(0) {}
bool isNull() const { return m_id == 0; }
bool isFullProfile() const;
bool isEmbeddedProfile() const;
QString profile() const;
QString version() const;
QString name() const;
QString vendor() const;
QString extensionSuffix() const;
QStringList extensions() const;
bool hasExtension(const char *name) const;
enum VersionFlag
{
Version_1_0 = 0x0001,
Version_1_1 = 0x0002
};
Q_DECLARE_FLAGS(VersionFlags, VersionFlag)
QCLPlatform::VersionFlags versionFlags() const;
cl_platform_id platformId() const { return m_id; }
static QList<QCLPlatform> platforms();
bool operator==(const QCLPlatform &other) const;
bool operator!=(const QCLPlatform &other) const;
private:
cl_platform_id m_id;
mutable int m_flags;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QCLPlatform::VersionFlags)
inline bool QCLPlatform::operator==(const QCLPlatform &other) const
{
return m_id == other.m_id;
}
inline bool QCLPlatform::operator!=(const QCLPlatform &other) const
{
return m_id != other.m_id;
}
#ifndef QT_NO_DEBUG_STREAM
Q_CL_EXPORT QDebug operator<<(QDebug, const QCLPlatform &);
#endif
QT_END_NAMESPACE
QT_END_HEADER
#endif
+137
View File
@@ -0,0 +1,137 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLPROGRAM_H
#define QCLPROGRAM_H
#include "qcldevice.h"
#include "qclkernel.h"
#include <QtCore/qstring.h>
#include <QtCore/qbytearray.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLContext;
class Q_CL_EXPORT QCLProgram
{
public:
QCLProgram() : m_context(0), m_id(0) {}
QCLProgram(QCLContext *context, cl_program id)
: m_context(context), m_id(id) {}
QCLProgram(const QCLProgram &other);
~QCLProgram();
QCLProgram &operator=(const QCLProgram &other);
bool isNull() const { return m_id == 0; }
cl_program programId() const { return m_id; }
QCLContext *context() const { return m_context; }
bool build(const QString &options = QString());
bool build(const QList<QCLDevice> &devices, const QString &options = QString());
QString log() const;
QList<QCLDevice> devices() const;
QByteArray sourceCode() const;
QList<QByteArray> binaries() const;
QCLKernel createKernel(const char *name) const;
QCLKernel createKernel(const QByteArray &name) const;
QCLKernel createKernel(const QString &name) const;
QList<QCLKernel> createKernels() const;
static void unloadCompiler();
bool operator==(const QCLProgram &other) const;
bool operator!=(const QCLProgram &other) const;
private:
QCLContext *m_context;
cl_program m_id;
};
inline bool QCLProgram::operator==(const QCLProgram &other) const
{
return m_id == other.m_id;
}
inline QCLProgram::QCLProgram(const QCLProgram &other)
: m_context(other.m_context), m_id(other.m_id)
{
if (m_id)
clRetainProgram(m_id);
}
inline QCLProgram::~QCLProgram()
{
if (m_id)
clReleaseProgram(m_id);
}
inline QCLProgram &QCLProgram::operator=(const QCLProgram &other)
{
m_context = other.m_context;
if (other.m_id)
clRetainProgram(other.m_id);
if (m_id)
clReleaseProgram(m_id);
m_id = other.m_id;
return *this;
}
inline bool QCLProgram::operator!=(const QCLProgram &other) const
{
return m_id != other.m_id;
}
QT_END_NAMESPACE
QT_END_HEADER
#endif
+137
View File
@@ -0,0 +1,137 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLSAMPLER_H
#define QCLSAMPLER_H
#include "qclglobal.h"
#include <QtCore/qscopedpointer.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLSamplerPrivate;
class QCLContext;
class Q_CL_EXPORT QCLSampler
{
public:
QCLSampler() : m_context(0), m_id(0) {}
QCLSampler(QCLContext *context, cl_sampler id)
: m_context(context), m_id(id) {}
QCLSampler(const QCLSampler &other);
~QCLSampler();
QCLSampler &operator=(const QCLSampler &other);
enum AddressingMode
{
None = 0x1130, // CL_ADDRESS_NONE
ClampToEdge = 0x1131, // CL_ADDRESS_CLAMP_TO_EDGE
Clamp = 0x1132, // CL_ADDRESS_CLAMP
Repeat = 0x1133 // CL_ADDRESS_REPEAT
};
enum FilterMode
{
Nearest = 0x1140, // CL_FILTER_NEAREST
Linear = 0x1141 // CL_FILTER_LINEAR
};
bool isNull() const { return m_id == 0; }
bool normalizedCoordinates() const;
QCLSampler::AddressingMode addressingMode() const;
QCLSampler::FilterMode filterMode() const;
cl_sampler samplerId() const { return m_id; }
QCLContext *context() const { return m_context; }
bool operator==(const QCLSampler &other) const;
bool operator!=(const QCLSampler &other) const;
private:
QCLContext *m_context;
cl_sampler m_id;
};
inline QCLSampler::QCLSampler(const QCLSampler &other)
: m_context(other.m_context), m_id(other.m_id)
{
if (m_id)
clRetainSampler(m_id);
}
inline QCLSampler::~QCLSampler()
{
if (m_id)
clReleaseSampler(m_id);
}
inline QCLSampler &QCLSampler::operator=(const QCLSampler &other)
{
m_context = other.m_context;
if (other.m_id)
clRetainSampler(other.m_id);
if (m_id)
clReleaseSampler(m_id);
m_id = other.m_id;
return *this;
}
inline bool QCLSampler::operator==(const QCLSampler &other) const
{
return m_id == other.m_id;
}
inline bool QCLSampler::operator!=(const QCLSampler &other) const
{
return m_id != other.m_id;
}
QT_END_NAMESPACE
QT_END_HEADER
#endif
+87
View File
@@ -0,0 +1,87 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLUSEREVENT_H
#define QCLUSEREVENT_H
#include "qclevent.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLContext;
class Q_CL_EXPORT QCLUserEvent : public QCLEvent
{
public:
QCLUserEvent() : QCLEvent() {}
QCLUserEvent(cl_event id);
QCLUserEvent(const QCLEvent &other);
QCLUserEvent &operator=(const QCLEvent &other);
void setFinished();
void setStatus(cl_int status);
private:
void validateEvent();
// Used by QCLContext::createUserEvent() to avoid
// the overhead of validateEvent().
QCLUserEvent(cl_event id, bool dummy)
: QCLEvent(id) { Q_UNUSED(dummy); }
friend class QCLContext;
};
inline void QCLUserEvent::setFinished()
{
setStatus(CL_COMPLETE);
}
QT_END_NAMESPACE
QT_END_HEADER
#endif
+228
View File
@@ -0,0 +1,228 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLVECTOR_H
#define QCLVECTOR_H
#include "qclbuffer.h"
#include <QtCore/qscopedpointer.h>
#include <QtCore/qvector.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLContext;
class QCLKernel;
class QCLVectorBasePrivate;
class Q_CL_EXPORT QCLVectorBase
{
protected:
QCLVectorBase(size_t elemSize);
QCLVectorBase(size_t elemSize, const QCLVectorBase &other);
~QCLVectorBase();
QCLVectorBasePrivate *d_ptr;
size_t m_elemSize;
size_t m_size;
mutable void *m_mapped;
void assign(const QCLVectorBase &other);
void create(QCLContext *context, int size, QCLMemoryObject::Access access);
void release();
void map();
void unmap() const;
void read(void *data, int count, int offset);
void write(const void *data, int count, int offset);
cl_mem memoryId() const;
QCLContext *context() const;
cl_mem kernelArg() const;
friend class QCLKernel;
};
template <typename T>
class QCLVector : public QCLVectorBase
{
public:
QCLVector();
QCLVector(const QCLVector<T> &other);
~QCLVector();
QCLVector<T> &operator=(const QCLVector<T> &other);
bool isNull() const;
void release();
inline bool isEmpty() const { return m_size == 0; }
inline int size() const { return m_size; }
T &operator[](int index);
const T &operator[](int index) const;
void read(T *data, int count, int offset = 0);
void write(const T *data, int count, int offset = 0);
void write(const QVector<T> &data, int offset = 0);
QCLContext *context() const;
QCLBuffer toBuffer() const;
private:
QCLVector(QCLContext *context, int size, QCLMemoryObject::Access access);
friend class QCLContext;
};
template <typename T>
Q_INLINE_TEMPLATE QCLVector<T>::QCLVector()
: QCLVectorBase(sizeof(T)) {}
template <typename T>
Q_INLINE_TEMPLATE QCLVector<T>::QCLVector
(QCLContext *context, int size, QCLMemoryObject::Access access)
: QCLVectorBase(sizeof(T))
{
QCLVectorBase::create(context, size, access);
}
template <typename T>
Q_INLINE_TEMPLATE QCLVector<T>::QCLVector(const QCLVector<T> &other)
: QCLVectorBase(sizeof(T), other)
{
}
template <typename T>
Q_INLINE_TEMPLATE QCLVector<T>::~QCLVector() {}
template <typename T>
QCLVector<T> &QCLVector<T>::operator=(const QCLVector<T> &other)
{
assign(other);
return *this;
}
template <typename T>
Q_INLINE_TEMPLATE bool QCLVector<T>::isNull() const
{
return d_ptr == 0;
}
template <typename T>
Q_INLINE_TEMPLATE void QCLVector<T>::release()
{
QCLVectorBase::release();
}
template <typename T>
Q_INLINE_TEMPLATE T &QCLVector<T>::operator[](int index)
{
Q_ASSERT_X(index >= 0 && index < int(m_size), "QCLVector<T>::operator[]",
"index out of range");
if (!m_mapped)
map();
return (reinterpret_cast<T *>(m_mapped))[index];
}
template <typename T>
Q_INLINE_TEMPLATE const T &QCLVector<T>::operator[](int index) const
{
Q_ASSERT_X(index >= 0 && index < int(m_size), "QCLVector<T>::operator[]",
"index out of range");
if (!m_mapped)
const_cast<QCLVector<T> *>(this)->map();
return (reinterpret_cast<T *>(m_mapped))[index];
}
template <typename T>
Q_INLINE_TEMPLATE void QCLVector<T>::write
(const T *data, int count, int offset)
{
Q_ASSERT(count >= 0 && offset >= 0 && (offset + count) <= int(m_size));
QCLVectorBase::write(data, count * sizeof(T), offset * sizeof(T));
}
template <typename T>
Q_INLINE_TEMPLATE void QCLVector<T>::read
(T *data, int count, int offset)
{
Q_ASSERT(count >= 0 && offset >= 0 && (offset + count) <= int(m_size));
QCLVectorBase::read(data, count * sizeof(T), offset * sizeof(T));
}
template <typename T>
Q_INLINE_TEMPLATE void QCLVector<T>::write
(const QVector<T> &data, int offset)
{
write(data.constData(), data.size(), offset);
}
template <typename T>
Q_INLINE_TEMPLATE QCLContext *QCLVector<T>::context() const
{
return QCLVectorBase::context();
}
template <typename T>
Q_INLINE_TEMPLATE QCLBuffer QCLVector<T>::toBuffer() const
{
cl_mem id = QCLVectorBase::memoryId();
if (id) {
clRetainMemObject(id);
return QCLBuffer(context(), id);
} else {
return QCLBuffer();
}
}
QT_END_NAMESPACE
QT_END_HEADER
#endif
+126
View File
@@ -0,0 +1,126 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenCL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCLWORKSIZE_H
#define QCLWORKSIZE_H
#include "qclglobal.h"
#include <QtCore/qsize.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(CL)
class QCLDevice;
class Q_CL_EXPORT QCLWorkSize
{
public:
QCLWorkSize()
: m_dim(1) { m_sizes[0] = 1; m_sizes[1] = 1; m_sizes[2] = 1; }
QCLWorkSize(size_t size)
: m_dim(1) { m_sizes[0] = size; m_sizes[1] = 1; m_sizes[2] = 1; }
QCLWorkSize(size_t width, size_t height)
: m_dim(2) { m_sizes[0] = width; m_sizes[1] = height; m_sizes[2] = 1; }
QCLWorkSize(const QSize &size)
: m_dim(2) { m_sizes[0] = size.width(); m_sizes[1] = size.height(); m_sizes[2] = 1; }
QCLWorkSize(size_t width, size_t height, size_t depth)
: m_dim(3)
{ m_sizes[0] = width; m_sizes[1] = height; m_sizes[2] = depth; }
size_t dimensions() const { return m_dim; }
size_t width() const { return m_sizes[0]; }
size_t height() const { return m_sizes[1]; }
size_t depth() const { return m_sizes[2]; }
const size_t *sizes() const { return m_sizes; }
bool operator==(const QCLWorkSize &other) const;
bool operator!=(const QCLWorkSize &other) const;
QCLWorkSize toLocalWorkSize
(const QCLWorkSize &maxWorkItemSize, size_t maxItemsPerGroup) const;
QCLWorkSize toLocalWorkSize(const QCLDevice &device) const;
QCLWorkSize roundTo(const QCLWorkSize &size) const;
QString toString() const;
static QCLWorkSize fromString(const QString &str);
private:
size_t m_dim;
size_t m_sizes[3];
};
Q_DECLARE_TYPEINFO(QCLWorkSize, Q_MOVABLE_TYPE);
inline bool QCLWorkSize::operator==(const QCLWorkSize &other) const
{
return m_dim == other.m_dim &&
m_sizes[0] == other.m_sizes[0] &&
m_sizes[1] == other.m_sizes[1] &&
m_sizes[2] == other.m_sizes[2];
}
inline bool QCLWorkSize::operator!=(const QCLWorkSize &other) const
{
return m_dim != other.m_dim ||
m_sizes[0] != other.m_sizes[0] ||
m_sizes[1] != other.m_sizes[1] ||
m_sizes[2] != other.m_sizes[2];
}
#ifndef QT_NO_DATASTREAM
Q_CL_EXPORT QDataStream &operator<<(QDataStream &, const QCLWorkSize &);
Q_CL_EXPORT QDataStream &operator>>(QDataStream &, QCLWorkSize &);
#endif
#ifndef QT_NO_DEBUG_STREAM
Q_CL_EXPORT QDebug operator<<(QDebug, const QCLWorkSize &);
#endif
QT_END_NAMESPACE
QT_END_HEADER
#endif
@@ -0,0 +1,116 @@
/**
* @file audioReceiver.cpp
* @brief audio receiver class
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-10-02
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define LOG_AUDIO_RECEIVER
#include "cusdr_audioReceiver.h"
AudioReceiver::AudioReceiver(THPSDRParameter *ioData)
: QObject()
, set(Settings::instance())
, io(ioData)
, m_client(0)
{
}
AudioReceiver::~AudioReceiver() {
}
void AudioReceiver::displayAudioRcvrSocketError(QAbstractSocket::SocketError error) {
AUDIO_RECEIVER << "audio client socket error:" << error;
}
void AudioReceiver::initClient() {
quint16 port = (quint16) (set->getAudioPort() + (io->audio_rx * 2));
QUdpSocket *socket = new QUdpSocket();
socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
if (socket->bind(port, QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress)) {
CHECKED_CONNECT(
socket,
SIGNAL(error(QAbstractSocket::SocketError)),
this,
SLOT(displayAudioRcvrSocketError(QAbstractSocket::SocketError)));
CHECKED_CONNECT(
socket,
SIGNAL(readyRead()),
this,
SLOT(readPendingAudioRcvrData()));
clientConnections.append(socket);
AUDIO_RECEIVER << "client socket binding successful.";
m_message = tr("[server]: listening for rx %1 audio on port %2.");
emit messageEvent(m_message.arg(io->audio_rx).arg(port));
//m_dataEngine->clientConnected = true;
// need to implement connection in dataEngine !!!!
emit clientConnectedEvent(true);
//rcveIQ_toggle = false;
}
else {
m_message = tr("[server]: bind socket failed for socket on port %1.");
emit messageEvent(m_message.arg(port));
}
}
void AudioReceiver::readPendingAudioRcvrData() {
QUdpSocket *socket = qobject_cast<QUdpSocket *>(sender());
while (socket->hasPendingDatagrams()) {
m_datagram.resize(socket->pendingDatagramSize());
if (socket->readDatagram(m_datagram.data(), m_datagram.size()) < 0) {
AUDIO_RECEIVER << "read client" << m_client << "socket failed.";
if (io->rcveIQ_toggle) { // toggles the rcveIQ signal
emit rcveIQEvent(this, 2);
io->rcveIQ_toggle = false;
}
}
else {
io->au_queue.enqueue(m_datagram);
if (!io->rcveIQ_toggle) { // toggles the rcveIQ signal
emit rcveIQEvent(this, 1);
io->rcveIQ_toggle = true;
}
}
}
}
@@ -0,0 +1,87 @@
/**
* @file audioReceiver.h
* @brief audio receiver header file
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-10-02
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_AUDIORECEIVER_H
#define _CUSDR_AUDIORECEIVER_H
//#include <QObject>
//#include <QMutex>
//#include <QByteArray>
//#include <QBuffer>
//#include <QVector>
//#include <QList>
//#include <QWaitCondition>
//#include <QThread>
#include "cusdr_settings.h"
#ifdef LOG_AUDIO_RECEIVER
# define AUDIO_RECEIVER qDebug().nospace() << "AudioReceiver::\t"
#else
# define AUDIO_RECEIVER nullDebug()
#endif
class AudioReceiver : public QObject {
Q_OBJECT
public:
AudioReceiver(THPSDRParameter *ioData = 0);
~AudioReceiver();
//int id;
public slots:
void initClient();
private:
Settings* set;
QMutex m_mutex;
QList<QUdpSocket *> clientConnections;
QString m_message;
QByteArray m_datagram;
THPSDRParameter *io;
int m_client;
private slots:
void displayAudioRcvrSocketError(QAbstractSocket::SocketError error);
void readPendingAudioRcvrData();
signals:
void messageEvent(QString message);
void rcveIQEvent(QObject *sender, int value);
void outputBufferEvent(unsigned char* outbuffer);
void clientConnectedEvent(bool value);
void newData();
void newAudioData();
};
#endif // _CUSDR_AUDIORECEIVER_H
@@ -0,0 +1,576 @@
/**
* @file cusdr_chirpProcessor.cpp
* @brief chirp data processor class
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-09-22
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define LOG_CHIRP_PROCESSOR
#include "cusdr_chirpProcessor.h"
ChirpProcessor::ChirpProcessor(THPSDRParameter *ioData)
: QObject()
, set(Settings::instance())
, io(ioData)
, m_stopped(false)
, m_specMax(0.0f)
, m_specMin(0.0f)
, m_sampleRate(set->getSampleRate())
, m_downRate(set->getChirpDownSampleRate())
, m_specAvgLength(1)
, m_filterLowerFrequency((float)set->getChirpFilterLowerFrequency())
, m_filterUpperFrequency((float)set->getChirpFilterUpperFrequency())
, m_switch(false)
, m_showChirpFFT(false)
, m_chirpBufferLength(set->getChirpBufferLength())
, m_chirpSidebandFactor(1.0f)
{
/*m_QCPXin = initQCPX(BUFFERSIZE);
m_temp0 = initQCPX(BUFFERSIZE);
m_temp2 = initQCPX(BUFFERSIZE/m_downRate);
m_temp1 = initQCPX(FULL_BUFFERSIZE);
m_temp3 = initQCPX(FULL_BUFFERSIZE);*/
/*
m_cpxIn = mallocCPX(BUFFERSIZE);
m_tmp0 = mallocCPX(BUFFERSIZE);
m_tmp2 = mallocCPX(BUFFERSIZE/m_downRate);
m_cpxInFilt = mallocCPX(FULL_BUFFERSIZE);
m_cpxRxFFT = mallocCPX(FULL_BUFFERSIZE);
m_tmp1 = mallocCPX(FULL_BUFFERSIZE);
m_tmp3 = mallocCPX(FULL_BUFFERSIZE);
m_cpxChirpIn = mallocCPX(FULL_BUFFERSIZE);
m_cpxChirpOut = mallocCPX(FULL_BUFFERSIZE);
m_cpxChirpTmp = mallocCPX(FULL_BUFFERSIZE);
m_cpxOut = mallocCPX(FULL_BUFFERSIZE);
*/
m_cpxIn.resize(BUFFERSIZE);
m_tmp0.resize(BUFFERSIZE);
m_tmp2.resize(BUFFERSIZE/m_downRate);
m_cpxInFilt.resize(FULL_BUFFERSIZE);
m_cpxRxFFT.resize(FULL_BUFFERSIZE);
m_tmp1.resize(FULL_BUFFERSIZE);
m_tmp3.resize(FULL_BUFFERSIZE);
m_cpxChirpIn.resize(FULL_BUFFERSIZE);
m_cpxChirpOut.resize(FULL_BUFFERSIZE);
m_cpxChirpTmp.resize(FULL_BUFFERSIZE);
m_cpxOut.resize(FULL_BUFFERSIZE);
/*
memset(m_cpxIn, 0, BUFFERSIZE * sizeof(CPX));
memset(m_tmp0, 0, BUFFERSIZE * sizeof(CPX));
memset(m_tmp2, 0, (BUFFERSIZE/4) * sizeof(CPX));
memset(m_cpxInFilt, 0, FULL_BUFFERSIZE * sizeof(CPX));
memset(m_cpxRxFFT, 0, FULL_BUFFERSIZE * sizeof(CPX));
memset(m_tmp1, 0, FULL_BUFFERSIZE * sizeof(CPX));
memset(m_tmp3, 0, FULL_BUFFERSIZE * sizeof(CPX));
memset(m_cpxOut, 0, FULL_BUFFERSIZE * sizeof(CPX));
memset(m_cpxChirpIn, 0, FULL_BUFFERSIZE * sizeof(CPX));
memset(m_cpxChirpOut, 0, FULL_BUFFERSIZE * sizeof(CPX));
memset(m_cpxChirpTmp, 0, FULL_BUFFERSIZE * sizeof(CPX));
*/
// FFTs by fftw
m_chirpFFT = new QFFT(FULL_BUFFERSIZE);
m_matchedFFT = new QFFT(FULL_BUFFERSIZE);
// FIR band pass filter
//m_filter = new QFilter(this, FULL_BUFFERSIZE, 2);
// 2 = FIR Bandpass, 5 = Bartlett window
m_filter = new QFilter(this, BUFFERSIZE, 2, 2);
// set the BPF
m_filter->setFilter(500.0f, 2500.0f);
m_filter->setStreamMode(true);
setupConnections();
}
ChirpProcessor::~ChirpProcessor() {
while (average_queue.length() > 0)
average_queue.dequeue();
/*
freeCPX(m_cpxIn);
freeCPX(m_cpxOut);
freeCPX(m_cpxInFilt);
freeCPX(m_cpxRxFFT);
freeCPX(m_cpxChirpIn);
freeCPX(m_cpxChirpOut);
freeCPX(m_tmp0);
freeCPX(m_tmp1);
*/
/*
delete m_cpxIn;
delete m_cpxOut;
delete m_cpxInFilt;
delete m_cpxRxFFT;
delete m_cpxChirpIn;
delete m_cpxChirpOut;
delete m_tmp0;
delete m_tmp1;
*/
delete m_chirpFFT;
delete m_matchedFFT;
}
void ChirpProcessor::stop() {
m_stopped = true;
}
void ChirpProcessor::setupConnections() {
CHECKED_CONNECT(
set,
SIGNAL(sampleRateChanged(QObject *, int)),
this,
SLOT(samplingRateChanged(QObject *, int)));
CHECKED_CONNECT_OPT(
set,
SIGNAL(chirpFilterLowerFrequencyChanged(int)),
this,
SLOT(setFilterLowerFrequency(int)),
Qt::DirectConnection);
CHECKED_CONNECT_OPT(
set,
SIGNAL(chirpFilterUpperFrequencyChanged(int)),
this,
SLOT(setFilterUpperFrequency(int)),
Qt::DirectConnection);
CHECKED_CONNECT_OPT(
set,
SIGNAL(chirpAvgLengthChanged(int)),
this,
SLOT(setDistSpectrumAvgLength(int)),
Qt::DirectConnection);
CHECKED_CONNECT_OPT(
set,
SIGNAL(chirpFFTShowChanged(bool)),
this,
SLOT(setChirpFFTShow(bool)),
Qt::DirectConnection);
CHECKED_CONNECT_OPT(
set,
SIGNAL(chirpSidebandChanged(bool)),
this,
SLOT(setChirpSideband(bool)),
Qt::DirectConnection);
}
int ChirpProcessor::setSpectrumBufferSize(int size) {
int i = 1;
while (i < size) i *= 2;
return i;
}
void ChirpProcessor::processChirpData() {
forever {
//matchedFilter(io->chirp_queue.dequeue());
matchedFilterFIRFilter(io->chirp_queue.dequeue());
m_mutex.lock();
if (m_stopped) {
m_stopped = false;
m_mutex.unlock();
break;
}
m_mutex.unlock();
}
}
void ChirpProcessor::matchedFilterFIRFilter(QList<qreal> data) {
int dataLength = data.length();
int dataIdx = 0;
int buffer = 0;
int newsize = (int)(BUFFERSIZE / m_downRate);
CHIRP_PROCESSOR_DEBUG << "start matched filter - samples:" << dataLength;
// filtering to 2kHz by constant-overlap-add (COLA)
while (dataIdx < dataLength) {
dataIdx = 2 * buffer * BUFFERSIZE;
for (int i = 0; i < 2 * BUFFERSIZE; i += 2) {
if (dataIdx + i + 1 < dataLength) {
m_cpxIn[i/2].re = data.at(dataIdx + i);
m_cpxIn[i/2].im = data.at(dataIdx + i + 1);
}
else {
dataIdx = dataLength;
break;
}
}
// BPF 2.5 kHz
m_filter->ProcessFilter(m_cpxIn, m_tmp0, BUFFERSIZE);
// decimate by 4
decimate(m_tmp0, m_tmp2, BUFFERSIZE, m_downRate);
for (int i = 0; i < newsize; i++) {
m_cpxInFilt[buffer * newsize + i].re = m_tmp2[i].re;
m_cpxInFilt[buffer * newsize + i].im = m_tmp2[i].im;
}
buffer++;
}
// Due to the COLA method the filter output gets shifet by BUFFERSIZE/2 bytes.
// In order to have a buffer in full chirp length, we save the last newsize/2 bytes
// (due to decimation by downrate) and add it to the beginning of the newbuffer.
for (int i = 0; i < FULL_BUFFERSIZE - newsize/2; i++) {
if (i < newsize/2) {
m_cpxInFilt[i].re = m_tmp3[i].re;
m_cpxInFilt[i].im = m_tmp3[i].im;
}
else {
m_cpxInFilt[i].re = m_cpxInFilt[i + newsize/2].re;
m_cpxInFilt[i].im = m_cpxInFilt[i + newsize/2].im;
}
}
// save the last buffer
for (int i = 0; i < newsize/2; i++) {
m_tmp3[i].re = m_tmp2[i].re;
m_tmp3[i].im = m_tmp2[i].im;
}
// map rx signal to the frequency domain
m_matchedFFT->DoFFTWForward(m_cpxInFilt, m_cpxRxFFT, FULL_BUFFERSIZE);
// multiply the chirp signal with the complex conjugate of the received signal
for (int i = 0; i < FULL_BUFFERSIZE; i++) {
// f * ~g
m_tmp1[i].re = (m_cpxChirpOut[i].re * m_cpxRxFFT[i].re) + (m_cpxChirpOut[i].im * m_cpxRxFFT[i].im);
m_tmp1[i].im = (m_cpxChirpOut[i].im * m_cpxRxFFT[i].re) - (m_cpxChirpOut[i].re * m_cpxRxFFT[i].im);
// ~f * g
//m_tmp1[i].re = (m_cpxRxFFT[i].re * m_cpxChirpOut[i].re) + (m_cpxRxFFT[i].im * m_cpxChirpOut[i].im);
//m_tmp1[i].im = (m_cpxRxFFT[i].im * m_cpxChirpOut[i].re) - (m_cpxRxFFT[i].re * m_cpxChirpOut[i].im);
// f * g
//m_tmp1[i].re = (m_cpxChirpOut[i].re * m_cpxRxFFT[i].re) - (m_cpxChirpOut[i].im * m_cpxRxFFT[i].im);
//m_tmp1[i].im = (m_cpxChirpOut[i].re * m_cpxRxFFT[i].im) + (m_cpxChirpOut[i].im * m_cpxRxFFT[i].re);
}
// map back to time domain
m_matchedFFT->DoFFTWInverse(m_tmp1, m_cpxOut, FULL_BUFFERSIZE);
float max = -1000;
float min = 1000;
float mean = 0.0f;
float oneOverNorm = 1.0f / FULL_BUFFERSIZE;
for (int i = 0; i < FULL_BUFFERSIZE; i++) {
if (!m_showChirpFFT) {
m_spectrumBufferFull[i] = (float)(10.0 * log10(MagCPX(ScaleCPX(m_cpxOut[i], oneOverNorm)) + 1.5E-45));
if (m_spectrumBufferFull[i] > max) max = m_spectrumBufferFull[i];
if (m_spectrumBufferFull[i] < min) min = m_spectrumBufferFull[i];
mean += m_spectrumBufferFull[i];
}
else {
//m_spectrumBufferFull[i] = (float)(10.0 * log10(SqrMagCPX(m_tmp1[i]) + 1.5E-45));
//m_spectrumBufferFull[i] = (float)(10.0 * log10(SqrMagCPX(ScaleCPX(m_tmp1[i], oneOverNorm)) + 1.5E-45));
m_spectrumBufferFull[i] = (float)(10.0 * log10(MagCPX(m_cpxRxFFT[i]) + 1.5E-45));
//m_spectrumBufferFull[i] = (float)(10.0 * log10(SqrMagCPX(m_cpxChirpOut[i]) + 1.5E-45) + 50.0f);
//m_spectrumBufferFull[i] = (float)(10.0 * log10(SqrMagCPX(SubCPX(m_cpxChirpOut[i], m_cpxRxFFT[i])) + 1.5E-45) + 50.0f);
//m_spectrumBufferFull[i] = (float)(10.0 * log10(MagCPX(m_cpxInFilt[i]) + 1.5E-45));
//m_spectrumBufferFull[i] = (float)(10.0 * log10(MagCPX(m_cpxIn[i]) + 1.5E-45));
}
}
mean *= 1.0f/FULL_BUFFERSIZE;
CHIRP_PROCESSOR_DEBUG << "dist min" << min << "max" << max << "mean" << mean;
CHIRP_PROCESSOR_DEBUG << "dist delta" << max - mean;
// we take the first half of the matched filter output to display
memcpy(m_spectrumBuffer, m_spectrumBufferFull, (FULL_BUFFERSIZE/2) * sizeof(float));
// we take the full length for the frequency spectrum,
// because we want to see positive as well as negative spectras
if (m_showChirpFFT) {
int topsize = FULL_BUFFERSIZE - 1;
// reorder the RX FFT buffer
for (int i = 0; i < FULL_BUFFERSIZE/2; i++) {
m_fftSpectrumBuffer[topsize - i] = m_spectrumBufferFull[i + FULL_BUFFERSIZE/2];
m_fftSpectrumBuffer[FULL_BUFFERSIZE/2 - i] = m_spectrumBufferFull[i];
}
}
setSpectras(m_spectrumBuffer, m_fftSpectrumBuffer);
}
void ChirpProcessor::setSpectras(const float *distance, const float *chirpfft) {
if (m_showChirpFFT)
set->setChirpSpectrumBuffer(m_sampleRate/m_downRate, FULL_BUFFERSIZE, chirpfft);
else {
if (m_specAvgLength > 1)
//spectrumAveraging(FULL_BUFFERSIZE, distance);
spectrumAveraging(FULL_BUFFERSIZE/2, distance);
else
//set->setChirpSpectrumBuffer(m_sampleRate/m_downRate, FULL_BUFFERSIZE, distance);
set->setChirpSpectrumBuffer(m_sampleRate/m_downRate, FULL_BUFFERSIZE/2, distance);
}
}
void ChirpProcessor::spectrumAveraging(qint64 length, const float *buffer) {
QVector<float> m_specBuf(length);
m_mutex.lock();
memcpy(
(float *) m_specBuf.data(),
(float *) &buffer[0],
length * sizeof(float));
average_queue.enqueue(m_specBuf);
float specMax = 0.0f;
float specMin = 0.0f;
float specMean = 0.0f;
if (average_queue.size() <= m_specAvgLength) {
for (int i = 0; i < length; i++) {
m_tmpBuf[i] += average_queue.last().data()[i];
m_outBuf[i] = m_tmpBuf[i] * (1.0f/average_queue.size());
specMean += m_outBuf[i];
if (m_outBuf[i] > specMax) specMax = m_outBuf[i];
if (m_outBuf[i] < specMin) specMin = m_outBuf[i];
}
m_mutex.unlock();
specMean *= 1.0f/FULL_BUFFERSIZE;
CHIRP_PROCESSOR_DEBUG << "distance spectrum averaging size" << average_queue.size();
CHIRP_PROCESSOR_DEBUG << "specMin =" << specMin << "specMax =" << specMax;
CHIRP_PROCESSOR_DEBUG << "distance spectrum mean value" << specMean;
set->setChirpSpectrumBuffer(m_sampleRate, FULL_BUFFERSIZE, m_outBuf);
return;
}
for (int i = 0; i < length; i++) {
m_tmpBuf[i] -= average_queue.first().at(i);
m_tmpBuf[i] += average_queue.last().at(i);
m_outBuf[i] = m_tmpBuf[i] * m_scale;
specMean += m_outBuf[i];
}
//set->setChirpSpectrumBuffer(m_sampleRate, FULL_BUFFERSIZE, m_outBuf);
set->setChirpSpectrumBuffer(m_sampleRate, FULL_BUFFERSIZE/2, m_outBuf);
average_queue.dequeue();
m_mutex.unlock();
}
void ChirpProcessor::generateLocalChirp() {
const int sampleRate = m_sampleRate / m_downRate;
//memset(m_cpxChirpIn, 0, FULL_BUFFERSIZE * sizeof(CPX));
//memset(m_cpxChirpOut, 0, FULL_BUFFERSIZE * sizeof(CPX));
m_cpxChirpIn.resize(FULL_BUFFERSIZE);
m_cpxChirpOut.resize(FULL_BUFFERSIZE);
qreal time = set->getChirpBufferDurationUs() / 1.0E6;
qint64 length = (qint64)(sampleRate * time);
qreal a = ONEPI * (set->getUpperChirpFreq() - set->getLowerChirpFreq()) / time;
qreal b = TWOPI * set->getLowerChirpFreq();
for (int i = 0; i < length; i++) {
// forward chirp
qreal t = (qreal)(1.0f * i/length);
// backward chirp
//qreal t = (qreal)(1.0f * (length-i)/length);
// complex chirp signal
m_cpxChirpIn[i].re = qSin(a * t * t + b * t);
m_cpxChirpIn[i].im = qCos(a * t * t + b * t);
//m_cpxChirpTmp[i].re = qSin(a * t * t + b * t);
//m_cpxChirpTmp[i].im = qCos(a * t * t + b * t);
//m_cpxChirpIn[i].re = qCos(a * t * t + b * t);
//m_cpxChirpIn[i].im = qSin(a * t * t + b * t);
//m_cpxChirpIn[i].re = qSin(a * t * t + b * t);
//m_cpxChirpIn[i].im = -qCos(a * t * t + b * t);
}
//m_specBufferSize = setSpectrumBufferSize(length);
// BPF 2.5 kHz
//m_filter->ProcessFilter(m_cpxChirpTmp, m_cpxChirpIn, FULL_BUFFERSIZE);
// transform chirp signal to frequency domain
m_chirpFFT->DoFFTWForward(m_cpxChirpIn, m_cpxChirpOut, FULL_BUFFERSIZE);
float dur = set->getChirpBufferDurationUs() / 1000.0f;
CHIRP_PROCESSOR_DEBUG << "chirp buffer changed:";
CHIRP_PROCESSOR_DEBUG << " bufferLength" << length;
//CHIRP_PROCESSOR_DEBUG << " spectrum buffer size" << m_specBufferSize;
CHIRP_PROCESSOR_DEBUG << " start frequency (Hz)" << set->getLowerChirpFreq();
CHIRP_PROCESSOR_DEBUG << " end frequency (Hz)" << set->getUpperChirpFreq();
CHIRP_PROCESSOR_DEBUG << " duration (ms)" << dur;
}
//void ChirpProcessor::decimate(CPX *in, CPX *out, int size, int downrate) {
void ChirpProcessor::decimate(const CPX &in, CPX &out, int size, int downrate) {
int newsize = size / downrate;
//memset(out, 0, newsize * sizeof(CPX));
out.resize(newsize);
for (int j = 0; j < newsize; j++) {
for (int k = 0; k < downrate; k++) {
if (j * downrate + k < size) {
/*out[j].re += m_tmpDec[j * downrate + k].re;
out[j].im += m_tmpDec[j * downrate + k].im;*/
out[j].re += in[j * downrate + k].re;
out[j].im += in[j * downrate + k].im;
}
}
}
}
//void ChirpProcessor::decimate(QList<qreal> data, CPX *out, int downrate) {
void ChirpProcessor::decimate(const QList<qreal> &data, CPX &out, int downrate) {
//memset(out, 0, 16 * BUFFER_SIZE * sizeof(CPX));
out.resize(16 * BUFFER_SIZE);
for (int j = 0; j < data.length()/4; j += 2) {
for (int k = 0; k < downrate; k++) {
if (j * downrate + 2*k < data.length()) {
out[j/2].re += data.at(j * downrate + 2*k);
out[j/2].im += data.at(j * downrate + 2*k + 1);
}
}
}
}
void ChirpProcessor::samplingRateChanged(QObject *sender, int value) {
Q_UNUSED(sender)
m_sampleRate = value;
}
void ChirpProcessor::setDistSpectrumAvgLength(int value) {
m_mutex.lock();
//for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++) m_tmpBuf[i] = 0.0f;
memset(m_tmpBuf, 0, FULL_BUFFERSIZE * sizeof(float));
while (!average_queue.isEmpty())
average_queue.dequeue();
m_specAvgLength = value;
if (m_specAvgLength > 0)
m_scale = 1.0f / m_specAvgLength;
else
m_scale = 1.0f;
m_mutex.unlock();
}
void ChirpProcessor::setChirpFFTShow(bool value) {
m_showChirpFFT = value;
}
void ChirpProcessor::setChirpSideband(bool value) {
if (value)
m_chirpSidebandFactor = 1.0f;
else
m_chirpSidebandFactor = -1.0f;
generateLocalChirp();
}
void ChirpProcessor::setFilterLowerFrequency(int value) {
if ((int)m_filterLowerFrequency == value) return;
m_filterLowerFrequency = 1.0f * value;
m_filter->setFilter(m_filterLowerFrequency, m_filterUpperFrequency);
}
void ChirpProcessor::setFilterUpperFrequency(int value) {
if ((int)m_filterUpperFrequency == value) return;
m_filterUpperFrequency = 1.0f * value;
m_filter->setFilter(m_filterLowerFrequency, m_filterUpperFrequency);
}
@@ -0,0 +1,145 @@
/**
* @file cusdr_chirpProcessor.h
* @brief chirp processor header file
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-09-22
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_CHIRPPROCESSOR_H
#define _CUSDR_CHIRPPROCESSOR_H
//#include <QObject>
//#include <QMutex>
//#include <QByteArray>
//#include <QBuffer>
//#include <QVector>
//#include <QList>
//#include <QWaitCondition>
//#include <QThread>
#include "cusdr_settings.h"
#include "QtDSP/qtdsp_qComplex.h"
#include "QtDSP/qtdsp_filter.h"
#include "QtDSP/qtdsp_fft.h"
#ifdef LOG_CHIRP_PROCESSOR
# define CHIRP_PROCESSOR_DEBUG qDebug().nospace() << "ChirpProcessor::\t"
#else
# define CHIRP_PROCESSOR_DEBUG nullDebug()
#endif
#define FULL_BUFFERSIZE 16384//65536
#define HALF_BUFFERSIZE 32768
#define BUFFERSIZE 2048
class ChirpProcessor : public QObject {
Q_OBJECT
public:
ChirpProcessor(THPSDRParameter *ioData = 0);
~ChirpProcessor();
public slots:
void stop();
void processChirpData();
void generateLocalChirp();
private slots:
void matchedFilterFIRFilter(QList<qreal> data);
void samplingRateChanged(QObject *sender, int value);
void setSpectras(const float *distance, const float *chirpfft);
void setDistSpectrumAvgLength(int value);
void setChirpFFTShow(bool value);
void setChirpSideband(bool value);
void setFilterLowerFrequency(int value);
void setFilterUpperFrequency(int value);
private:
Settings *set;
QMutex m_mutex;
QString m_message;
QFFT *m_chirpFFT;
QFFT *m_matchedFFT;
QFilter *m_filter;
CPX m_tmp0;
CPX m_tmp1;
CPX m_tmp2;
CPX m_tmp3;
CPX m_tmpDec;
CPX m_cpxRxFFT;
CPX m_cpxChirpIn;
CPX m_cpxChirpTmp;
CPX m_cpxChirpOut;
CPX m_cpxIn;
CPX m_cpxInFilt;
CPX m_cpxOut;
THPSDRParameter *io;
QQueue<QVector<float> > average_queue;
float m_tmpBuf[FULL_BUFFERSIZE];
float m_outBuf[FULL_BUFFERSIZE];
float m_spectrumBuffer[FULL_BUFFERSIZE];
float m_fftSpectrumBuffer[FULL_BUFFERSIZE];
float m_spectrumBufferFull[FULL_BUFFERSIZE];
float *m_window;
volatile bool m_stopped;
float m_specMax;
float m_specMin;
float m_scale;
int m_sampleRate;
int m_downSampleRate;
int m_downRate;
int m_specBufferSize;
int m_specAvgLength;
float m_filterLowerFrequency;
float m_filterUpperFrequency;
bool m_switch;
bool m_showChirpFFT;
qint64 m_chirpBufferLength;
qreal m_chirpSidebandFactor;
void setupConnections();
void decimate(const CPX &in, CPX &out, int size, int downrate);
void decimate(const QList<qreal> &data, CPX &out, int downrate);
void spectrumAveraging(qint64 length, const float *buffer);
int setSpectrumBufferSize(int size);
signals:
void messageEvent(QString message);
};
#endif // _CUSDR_CHIRPPROCESSOR_H
File diff suppressed because it is too large Load Diff
+534
View File
@@ -0,0 +1,534 @@
/**
* @file cusdr_dataEngine.h
* @brief cuSDR data engine header file
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-02-02
*/
/*
*
* Copyright 2010 Hermann von Hasseln, DL3HVH
*
* using original C code by John Melton, G0ORX/N6LYT and Dave McMcQuate, WA8YWQ
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_DATA_ENGINE_H
#define _CUSDR_DATA_ENGINE_H
//#include <QObject>
//#include <QThread>
//#include <QMetaType>
//#include <QtNetwork>
//#include <QHostAddress>
//#include <QMutexLocker>
//#include <QMutex>
//#include <QWaitCondition>
//#include <QVariant>
//#include <QElapsedTimer>
//#include <QFuture>
//#include <qtconcurrentrun.h>
#include "cusdr_settings.h"
#include "cusdr_dataIO.h"
#include "cusdr_receiver.h"
#include "cusdr_chirpProcessor.h"
#include "cusdr_audioReceiver.h"
#include "cusdr_discoverer.h"
#include "Util/qcircularbuffer.h"
#include "QtDSP/qtdsp_fft.h"
#include "QtDSP/qtdsp_filter.h"
#include "QtDSP/qtdsp_dualModeAverager.h"
#include "AudioEngine/cusdr_audio_engine.h"
#ifdef LOG_DATA_ENGINE
# define DATA_ENGINE_DEBUG qDebug().nospace() << "DataEngine::\t"
#else
# define DATA_ENGINE_DEBUG nullDebug()
#endif
#ifdef LOG_DATA_PROCESSOR
# define DATA_PROCESSOR_DEBUG qDebug().nospace() << "DataProcessor::\t"
#else
# define DATA_PROCESSOR_DEBUG nullDebug()
#endif
#ifdef LOG_WIDEBAND_PROCESSOR
# define WIDEBAND_PROCESSOR_DEBUG qDebug().nospace() << "WidebandProcessor::\t"
#else
# define WIDEBAND_PROCESSOR_DEBUG nullDebug()
#endif
class DataProcessor;
class AudioOutProcessor;
class WideBandDataProcessor;
//Q_DECLARE_METATYPE (QAbstractSocket::SocketError)
// *********************************************************************
// data engine class
class DataEngine : public QObject {
Q_OBJECT
public:
DataEngine(QObject* parent = 0);
~DataEngine();
Settings* set;
THPSDRParameter io;
QList<Receiver *> RX;
QList<qreal> chirpData;
QUdpSocket* sendSocket;
DataIO* m_dataIO;
public slots:
bool initDataEngine();
void stop();
// set Server parameter
void setRxPeerAddress(int rx, QHostAddress address);
void setRxClient(int rx, int client);
void setRx(int rx);
void setRxSocketState(int rx, const char* prop, QString);
//void setSendIQSignal(QObject *sender, int value);
void setRcveIQSignal(QObject *sender, int value);
void setAudioReceiver(QObject *sender, int rx);
//void setAudioInProcessorRunning(bool value);
void setIQPort(int rx, int port);
void setRxConnectedStatus(QObject* sender, int rx, bool value);
void setClientConnected(QObject* sender, int rx);
void setClientConnected(bool value);
void setClientDisconnected(int client);
void setFramesPerSecond(QObject *sender, int rx, int value);
void createChirpDataProcessor();
// DSP processing
void processFileBuffer(const QList<qreal> data);
// change HPSDR hardware settings
void setPenelopeVersion(QObject *sender, int version);
void setHwIOVersion(QObject *sender, int version);
void setNumberOfRx(QObject *sender, int value);
void setSampleRate(QObject *sender, int value);
void setMercuryAttenuator(QObject *sender, HamBand band, int value);
void setDither(QObject *sender, int value);
void setRandom(QObject *sender, int value);
void setTimeStamp(QObject *sender, bool value);
void set10MhzSource(QObject *sender, int source);
void set122_88MhzSource(QObject *sender, int source);
void setMicSource(QObject *sender, int source);
void setMercuryClass(QObject *sender, int value);
void setMercuryTiming(QObject* sender, int value);
void setHamBand(QObject *sender, int rx, bool byBtn, HamBand band);
void setFrequency(QObject* sender, int mode, int rx, long frequency);
void loadWavFile(const QString &fileName);
void suspend();
void startPlayback();
void showSettingsDialog();
private:
void setSystemState(
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state);
void initAudioEngine();
void setupConnections();
void connectDSPSlots();
void disconnectDSPSlots();
void createDiscoverer();
void createDataIO();
void createDataProcessor();
void createAudioOutProcessor();
void createWideBandDataProcessor();
//void createChirpDataProcessor();
//void createAudioReceiver(int rx);
void createAudioReceiver();
bool initReceivers(int rx);
bool start();
bool startDataEngineWithoutConnection();
bool findHPSDRDevices();
bool getFirmwareVersions();
bool checkFirmwareVersions();
bool startDiscoverer(QThread::Priority prio);
bool startDataIO(QThread::Priority prio);
bool startDataProcessor(QThread::Priority prio);
void startAudioOutProcessor(QThread::Priority prio);
bool startWideBandDataProcessor(QThread::Priority prio);
bool startChirpDataProcessor(QThread::Priority prio);
void stopDiscoverer();
void stopDataIO();
void stopDataProcessor();
void stopAudioOutProcessor();
void stopWideBandDataProcessor();
void stopChirpDataProcessor();
void setHPSDRConfig();
private:
DataProcessor* m_dataProcessor;
WideBandDataProcessor* m_wbDataProcessor;
QDSPEngine* m_chirpDspEngine;
AudioReceiver* m_audioReceiver;
AudioEngine* m_audioEngine;
AudioOutProcessor* m_audioOutProcessor;
ChirpProcessor* m_chirpProcessor;
Discoverer* m_discoverer;
QThreadEx* m_discoveryThread;
QThreadEx* m_dataIOThread;
QThreadEx* m_dataProcThread;
QThreadEx* m_wbDataProcThread;
QThreadEx* m_chirpDataProcThread;
QThreadEx* m_AudioRcvrThread;
QThreadEx* m_audioInProcThread;
QThreadEx* m_audioOutProcThread;
QList<QThreadEx* > m_dspThreadList;
QMutex m_mutex;
QString m_message;
QString m_HPSDRDevice;
QByteArray m_commandDatagram;
QByteArray m_datagram;
QSDR::_Error m_error;
QSDR::_ServerMode m_serverMode;
QSDR::_HWInterfaceMode m_hwInterface;
QSDR::_DataEngineState m_dataEngineState;
QCircularBuffer<int> audioringbuffer;
TMeterType m_meterType;
CPX cpxIn;
CPX cpxOut;
bool m_restart;
bool m_networkDeviceRunning;
bool m_soundFileLoaded;
bool m_clientConnect;
//bool m_audioProcessorRunning;
bool m_chirpInititalized;
bool m_discoveryThreadRunning;
bool m_dataIOThreadRunning;
bool m_wbDataRcvrThreadRunning;
bool m_chirpDataProcThreadRunning;
bool m_dataProcThreadRunning;
bool m_audioRcvrThreadRunning;
bool m_audioInProcThreadRunning;
bool m_audioOutProcThreadRunning;
bool m_frequencyChange;
bool m_hamBandChanged;
bool m_chirpThreadStopped;
bool m_clientConnected;
float m_mainVolume;
int m_hpsdrDevices;
int m_fwCount;
int m_configure;
int m_timeout;
int m_txFrame;
int m_bytes;
int m_remainingTime;
int m_found;
int m_RxFrequencyChange;
int m_counter;
int m_forwardPower;
int m_maxSamples;
int m_offset;
int m_rxSamples;
int m_chirpSamples;
int m_leftSample;
int m_rightSample;
int m_micSample;
int m_spectrumSize;
int m_sendState;
float m_lsample;
float m_rsample;
float m_scale;
float m_sMeterValue;
float m_sMeterCalibrationOffset;
float m_micSample_float;
float m_spectrumBuffer[SAMPLE_BUFFER_SIZE];
qint64 m_audioFileBufferPosition;
qint64 m_audioFileBufferLength;
QByteArray m_audioFileBuffer;
float getFilterSizeCalibrationOffset();
private slots:
void systemStateChanged(
QObject *sender,
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state);
//void setCurrentNetworkDevice(TNetworkDevicecard card);
void setHPSDRDeviceNumber(int value);
void rxListChanged(QList<Receiver *> rxList);
void searchHpsdrNetworkDevices();
void setCurrentReceiver(QObject* sender, int rx);
void setMercuryAttenuators(QObject *sender, QList<int> attn);
void setAlexConfiguration(quint16 conf);
void setAlexStates(HamBand band, const QList<int> &states);
void setPennyOCEnabled(bool value);
void setRxJ6Pins(const QList<int> &list);
void setTxJ6Pins(const QList<int> &list);
void setAudioFileFormat(QObject *sender, const QAudioFormat &format);
void setAudioFilePosition(QObject *sender, qint64 position);
void setAudioFileBuffer(QObject *sender, qint64 position, qint64 length, const QByteArray &buffer);
void setAudioFileBuffer(const QList<qreal> &buffer);
signals:
void error(QUdpSocket::SocketError error);
void masterSwitchEvent(QObject *sender, bool power);
//void messageEvent(QString message);
void penelopeVersionInfoEvent(QObject *sender, int version);
void hwIOVersionInfoEvent(QObject *sender, int version);
void sendIQEvent(QObject *sender, int sendIQ);
void rcveIQEvent(QObject *sender, int value);
//void iqDataReady(int rx);
void chirpDataReady(int samples);
void audioDataReady();
void clientConnectedEvent(int rx);
void audioRxEvent(int rx);
void outMultiplierEvent(int value);
void systemMessageEvent(const QString &str, int time);
void clearSystemMessageEvent();
void DataProcessorReadyEvent();
void audioSenderReadyEvent(bool value);
};
// *********************************************************************
// Data processor class
class DataProcessor : public QObject {
Q_OBJECT
public:
DataProcessor(
DataEngine* de = 0,
QSDR::_ServerMode serverMode = QSDR::NoServerMode,
QSDR::_HWInterfaceMode hwMode = QSDR::NoInterfaceMode);
~DataProcessor();
public slots:
void stop();
void processData();
void processDeviceData();
void externalDspProcessing(int rx);
void externalDspProcessingBig(int rx);
private slots:
void initDataProcessorSocket();
void displayDataProcessorSocketError(QAbstractSocket::SocketError error);
void processInputBuffer(const QByteArray &buffer);
void processOutputBuffer(const CPX &buffer);
void decodeCCBytes(const QByteArray &buffer);
void encodeCCBytes();
void setOutputBuffer(int rx, const CPX &buffer);
void writeData();
private:
DataEngine* de;
Settings* set;
QUdpSocket* m_dataProcessorSocket;
QSDR::_Error m_error;
QSDR::_ServerMode m_serverMode;
QSDR::_HWInterfaceMode m_hwInterface;
QSDR::_DataEngineState m_dataEngineState;
QHostAddress m_deviceAddress;
QMutex m_mutex;
QMutex m_spectrumMutex;
QByteArray m_IQDatagram;
QByteArray m_outDatagram;
QByteArray m_deviceSendDataSignature;
QString m_message;
QTime m_SyncChangedTime;
QTime m_ADCChangedTime;
bool m_socketConnected;
bool m_setNetworkDeviceHeader;
bool m_chirpGateBit;
bool m_chirpBit;
bool m_chirpStart;
int m_leftSample;
int m_rightSample;
int m_micSample;
int m_bytes;
int m_maxSamples;
int m_rxSamples;
int m_chirpSamples;
int m_fwCount;
int m_idx;
int m_sendState;
int m_chirpStartSample;
float m_lsample;
float m_rsample;
float m_micSample_float;
unsigned long m_IQSequence;
unsigned long m_sequenceHi;
unsigned short m_offset;
unsigned short m_length;
long m_sendSequence;
long m_oldSendSequence;
volatile bool m_stopped;
uchar m_ibuffer[IO_BUFFER_SIZE * IO_BUFFERS];
signals:
void messageEvent(QString message);
void connectingEvent(QString addr, quint16 port);
void connectedEvent(QString addr, quint16 port);
void disconnectedEvent();
void serverVersionEvent(QString version);
};
// *********************************************************************
// Audio out processor class
class AudioOutProcessor : public QObject {
Q_OBJECT
public:
AudioOutProcessor(DataEngine* de = 0, QSDR::_ServerMode serverMode = QSDR::NoServerMode);
~AudioOutProcessor();
public slots:
void stop();
void processData();
void processDeviceData();
private slots:
private:
DataEngine* m_dataEngine;
QMutex m_mutex;
QByteArray m_IQDatagram;
QString m_message;
QSDR::_ServerMode m_serverMode;
/*int m_bytes;
unsigned long m_IQSequence;
unsigned long m_sequenceHi;
unsigned short m_offset;
unsigned short m_length;*/
volatile bool m_stopped;
signals:
//void connectingEvent(QString addr, quint16 port);
//void connectedEvent(QString addr, quint16 port);
//void disconnectedEvent();
//void serverVersionEvent(QString version);
////void metisVersionEvent(QObject *sender, int version);
//void newData();
//void newIQData(int rx);
//void newAudioDataEvent(float *lBuf, float *rBuf);
};
// *********************************************************************
// Wide band data processor class
class WideBandDataProcessor : public QObject {
Q_OBJECT
public:
WideBandDataProcessor(THPSDRParameter *ioData = 0, QSDR::_ServerMode serverMode = QSDR::NoServerMode, int size = 0);
~WideBandDataProcessor();
public slots:
void stop();
void processWideBandData();
void setWbSpectrumAveraging(QObject* sender, int rx, bool value);
private slots:
//void initDataProcessorSocket();
//void displayDataProcessorSocketError(QAbstractSocket::SocketError error);
void processWideBandInputBuffer(const QByteArray &buffer);
private:
THPSDRParameter* io;
Settings* set;
QFFT* wbFFT;
DualModeAverager* wbAverager;
CPX cpxWBIn;
CPX cpxWBOut;
QMutex m_mutex;
QByteArray m_WBDatagram;
QString m_message;
QSDR::_ServerMode m_serverMode;
int m_size;
int m_bytes;
bool m_wbSpectrumAveraging;
volatile bool m_stopped;
unsigned char m_ibuffer[IO_BUFFER_SIZE * IO_BUFFERS];
signals:
void messageEvent(QString message);
void wbSpectrumBufferChanged(const qVectorFloat &buffer);
};
#endif // _CUSDR_DATA_ENGINE_H
+661
View File
@@ -0,0 +1,661 @@
/**
* @file cusdr_dataIO.cpp
* @brief Data IO class
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-10-01
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define LOG_DATAIO
#include "cusdr_dataIO.h"
#include "soundout.h"
#if defined(Q_OS_WIN32)
#include <winsock2.h>
#endif
#include <iostream>
using namespace std;
DataIO::DataIO(THPSDRParameter *ioData)
: QObject()
, set(Settings::instance())
, io(ioData)
, m_dataIOSocketOn(false)
, m_setNetworkDeviceHeader(true)
, m_sequence(0)
, m_oldSequence(-1)
, m_sequenceWideBand(0)
, m_oldSequenceWideBand(-1)
, m_wbBuffers(set->getWidebandBuffers() - 1)
, m_wbCount(0)
, m_socketBufferSize(set->getSocketBufferSize())
, m_sendEP4(false)
, m_manualBufferSize(set->getManualSocketBufferSize())
, m_packetsToggle(true)
, m_firstFrame(true)
, m_stopped(false)
{
m_dataIOSocket = 0;
m_metisGetDataSignature.resize(3);
m_metisGetDataSignature[0] = (char)0xEF;
m_metisGetDataSignature[1] = (char)0xFE;
m_metisGetDataSignature[2] = (char)0x01;
//m_metisGetDataSignature[3] = (char)0x06;
m_datagram.resize(1032);
m_wbDatagram.resize(0);
m_twoFramesDatagram.resize(0);
m_sendSequence = 0L;
m_oldSendSequence = 0L;
m_deviceSendDataSignature.resize(4);
m_deviceSendDataSignature[0] = (char)0xEF;
m_deviceSendDataSignature[1] = (char)0xFE;
m_deviceSendDataSignature[2] = (char)0x01;
m_deviceSendDataSignature[3] = (char)0x02;
m_packetLossTime.start();
CHECKED_CONNECT(
set,
SIGNAL(sampleRateChanged(QObject *, int)),
this,
SLOT(setSampleRate(QObject *, int)));
CHECKED_CONNECT(
set,
SIGNAL(manualSocketBufferChanged(QObject*, bool)),
this,
SLOT(setManualSocketBufferSize(QObject*, bool)));
CHECKED_CONNECT(
set,
SIGNAL(socketBufferSizeChanged(QObject*, int)),
this,
SLOT(setSocketBufferSize(QObject*, int)));
m_message = "m_sendSequence = %1, bytes sent: %2";
m_pSoundCardOut = new CSoundOut(this);
//RRK pass -1 to get the systems "default" audio device
m_pSoundCardOut->Start(-1, true, 48000, false);
m_pSoundCardOut->SetVolume(80);
}
DataIO::~DataIO() {
if (m_dataIOSocketOn) {
m_dataIOSocket->close();
delete m_dataIOSocket;
m_dataIOSocket = 0;
}
}
void DataIO::stop() {
io->networkIOMutex.lock();
m_stopped = true;
io->networkIOMutex.unlock();
if(m_pSoundCardOut) {
m_pSoundCardOut->Stop();
delete m_pSoundCardOut;
}
}
void DataIO::initDataReceiverSocket() {
m_dataIOSocket = new QUdpSocket();
int newBufferSize;
if (m_manualBufferSize) {
newBufferSize = m_socketBufferSize * 1024;//m_socketBufferSize * 1032;
io->networkIOMutex.lock();
DATAIO_DEBUG << "initDataReceiverSocket socket buffer size set to " << m_socketBufferSize << " kB.";
io->networkIOMutex.unlock();
}
else {
if (io->samplerate == 384000) {
newBufferSize = 128*1024;//128 * 1032;
io->networkIOMutex.lock();
DATAIO_DEBUG << "socket buffer size set to 128 kB.";
io->networkIOMutex.unlock();
}
else if (io->samplerate == 192000) {
newBufferSize = 64*1024;//64 * 1032;
io->networkIOMutex.lock();
DATAIO_DEBUG << "socket buffer size set to 64 kB.";
io->networkIOMutex.unlock();
}
else if (io->samplerate == 96000) {
newBufferSize = 32*1024;//32 * 1032;
io->networkIOMutex.lock();
DATAIO_DEBUG << "socket buffer size set to 32 kB.";
io->networkIOMutex.unlock();
}
else if (io->samplerate == 48000) {
newBufferSize = 16*1024;//16 * 1032;
io->networkIOMutex.lock();
DATAIO_DEBUG << "socket buffer size set to 16 kB.";
io->networkIOMutex.unlock();
}
}
if (m_dataIOSocket->bind(QHostAddress(set->getHPSDRDeviceLocalAddr()),
set->getMetisPort(),
QUdpSocket::DontShareAddress))
//QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress))
{
#if defined(Q_OS_WIN32)
if (::setsockopt(m_dataIOSocket->socketDescriptor(), SOL_SOCKET,
SO_RCVBUF, (char *)&newBufferSize, sizeof(newBufferSize)) == -1) {
io->networkIOMutex.lock();
DATAIO_DEBUG << "dataIOSocket error!";
io->networkIOMutex.unlock();
}
#endif
//m_dataIOSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
//m_dataIOSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
CHECKED_CONNECT(
m_dataIOSocket,
SIGNAL(error(QAbstractSocket::SocketError)),
this,
SLOT(displayDataReceiverSocketError(QAbstractSocket::SocketError)));
/*CHECKED_CONNECT_OPT(
m_dataIOSocket,
SIGNAL(readyRead()),
this,
SLOT(readDeviceData()),
Qt::DirectConnection);*/
CHECKED_CONNECT(
m_dataIOSocket,
SIGNAL(readyRead()),
this,
SLOT(readDeviceData()));
io->networkIOMutex.lock();
DATAIO_DEBUG << "data receiver socket bound successful to local port " << m_dataIOSocket->localPort();
io->networkIOMutex.unlock();
m_dataIOSocketOn = true;
set->setPacketLoss(1);
}
else {
io->networkIOMutex.lock();
DATAIO_DEBUG << "data receiver socket binding failed.";
io->networkIOMutex.unlock();
m_dataIOSocketOn = false;
}
}
void DataIO::readDeviceData() {
while (m_dataIOSocket->hasPendingDatagrams()) {
QMutexLocker locker(&io->networkIOMutex);
if (m_dataIOSocket->readDatagram(m_datagram.data(), m_datagram.size()) == METIS_DATA_SIZE) {
if (m_datagram.left(3) == m_metisGetDataSignature) {
if (m_datagram[3] == (char)0x06) {
m_sequence = (m_datagram[4] & 0xFF) << 24;
m_sequence += (m_datagram[5] & 0xFF) << 16;
m_sequence += (m_datagram[6] & 0xFF) << 8;
m_sequence += (m_datagram[7] & 0xFF);
if (m_sequence != m_oldSequence + 1) {
//DATAIO_DEBUG << "readData missed " << m_sequence - m_oldSequence << " packages.";
//RRK cout << "readData missed " << m_sequence - m_oldSequence << " packages." << endl;
if (m_packetLossTime.elapsed() > 100) {
set->setPacketLoss(2);
m_packetLossTime.restart();
}
}
m_oldSequence = m_sequence;
//// enqueue first half of the HPSDR frame from the HPSDR device
//io->iq_queue.enqueue(m_datagram.mid(METIS_HEADER_SIZE, BUFFER_SIZE/2));
//// enqueue second half of the HPSDR frame from the HPSDR device
//io->iq_queue.enqueue(m_datagram.right(BUFFER_SIZE/2));
// enqueue one frame from the HPSDR device
if (!io->iq_queue.isFull()) {
io->iq_queue.enqueue(m_datagram.mid(METIS_HEADER_SIZE, BUFFER_SIZE));
}
// collect two HPSDR frames
//if (m_firstFrame) {
// m_twoFramesDatagram += m_datagram.mid(METIS_HEADER_SIZE, BUFFER_SIZE);
// m_firstFrame = false;
//}
//else {
// m_twoFramesDatagram += m_datagram.mid(METIS_HEADER_SIZE, BUFFER_SIZE);
// //enqueue the two frames
// io->iq_queue.enqueue(m_twoFramesDatagram);
// m_firstFrame = true;
// m_twoFramesDatagram.resize(0);
//}
}
else if (m_datagram[3] == (char)0x04) { // wide band data
//qDebug() << "wideband data received!";
m_sequenceWideBand = (m_datagram[4] & 0xFF) << 24;
m_sequenceWideBand += (m_datagram[5] & 0xFF) << 16;
m_sequenceWideBand += (m_datagram[6] & 0xFF) << 8;
m_sequenceWideBand += (m_datagram[7] & 0xFF);
if (m_sequenceWideBand != m_oldSequenceWideBand + 1) {
DATAIO_DEBUG << "wideband readData missed " << m_sequenceWideBand - m_oldSequenceWideBand << " packages.";
if (m_packetLossTime.elapsed() > 100) {
set->setPacketLoss(2);
m_packetLossTime.restart();
}
}
m_oldSequenceWideBand = m_sequenceWideBand;
// three 'if's from KISS Konsole
if ((m_wbBuffers & m_datagram[7]) == 0)
{
m_sendEP4 = true;
m_wbCount = 0;
}
if (m_sendEP4)
{
m_wbDatagram.append(m_datagram.mid(METIS_HEADER_SIZE, BUFFER_SIZE));
}
if (m_wbCount++ == m_wbBuffers)
{
// enqueue
m_sendEP4 = false;
io->wb_queue.enqueue(m_wbDatagram);
m_wbDatagram.resize(0);
}
}
}
//DATA_RECEIVER_DEBUG << "got wrong HPSDR device signature!";
}
//DATA_RECEIVER_DEBUG << "got wrong HPSDR device data size!";
}
//DATA_RECEIVER_DEBUG << "no more pending datagrams.";
}
void DataIO::readData() {
qint64 length = io->inputBuffer.length();
//int buffers = qRound(length/(2*BUFFER_SIZE));
int buffers = qRound((float) length/128);
DATAIO_DEBUG << "input buffer length " << length << " buffers " << buffers;
while (!m_stopped) {
for (int i = 0; i < buffers; i++) {
//io->data_queue.enqueue(io->inputBuffer.mid(i*2*BUFFER_SIZE, 2*BUFFER_SIZE));
io->data_queue.enqueue(io->inputBuffer.mid(i*128, 128));
if (m_stopped) break;
}
}
m_stopped = false;
}
void DataIO::sendInitFramesToNetworkDevice(int rx) {
QByteArray initDatagram;
initDatagram.resize(1032);
initDatagram[0] = (char)0xEF;
initDatagram[1] = (char)0xFE;
initDatagram[2] = (char)0x01;
initDatagram[3] = (char)0x02;
initDatagram[4] = (char)0x00;
initDatagram[5] = (char)0x00;
initDatagram[6] = (char)0x00;
initDatagram[7] = (char)0x00;
initDatagram[8] = SYNC;
initDatagram[9] = SYNC;
initDatagram[10] = SYNC;
for (int i = 0; i < 5; i++) {
initDatagram[i + 11] = io->control_out[i];
}
for (int i = 16; i < 520; i++) {
initDatagram[i] = 0x00;
}
initDatagram[520] = SYNC;
initDatagram[521] = SYNC;
initDatagram[522] = SYNC;
initDatagram[523] = io->control_out[0] | ((rx + 2) << 1);
initDatagram[524] = set->getCtrFrequencies().at(rx) >> 24;
initDatagram[525] = set->getCtrFrequencies().at(rx) >> 16;
initDatagram[526] = set->getCtrFrequencies().at(rx) >> 8;
initDatagram[527] = set->getCtrFrequencies().at(rx) ;
for (int i = 528; i < 1032; i++) initDatagram[i] = 0x00;
// for (int i = 0; i < 5; i++) {
//
// if (m_dataIOSocket->writeDatagram(initDatagram.data(), initDatagram.size(), io->hpsdrDeviceIPAddress, DEVICE_PORT) < 0) {
//
// io->networkIOMutex.lock();
// DATAIO_DEBUG << "error sending init data to device: " << qPrintable(m_dataIOSocket->errorString());
// io->networkIOMutex.unlock();
// }
// else {
//
// if (i == 0) {
//
// io->networkIOMutex.lock();
// DATAIO_DEBUG << "init frames sent to network device.";
// io->networkIOMutex.unlock();
// }
// }
// }
if (m_dataIOSocket->writeDatagram(initDatagram.data(), initDatagram.size(), io->hpsdrDeviceIPAddress, DEVICE_PORT) < 0) {
io->networkIOMutex.lock();
DATAIO_DEBUG << "error sending init data to device: " << qPrintable(m_dataIOSocket->errorString());
io->networkIOMutex.unlock();
}
else {
io->networkIOMutex.lock();
DATAIO_DEBUG << "init frames sent to network device.";
io->networkIOMutex.unlock();
}
SleeperThread::msleep(20);
if (m_dataIOSocket->writeDatagram(initDatagram.data(), initDatagram.size(), io->hpsdrDeviceIPAddress, DEVICE_PORT) < 0) {
io->networkIOMutex.lock();
DATAIO_DEBUG << "error sending init data to device: " << qPrintable(m_dataIOSocket->errorString());
io->networkIOMutex.unlock();
}
else {
io->networkIOMutex.lock();
DATAIO_DEBUG << "init frames sent to network device.";
io->networkIOMutex.unlock();
}
}
void DataIO::networkDeviceStartStop(char value) {
TNetworkDevicecard metis = set->getCurrentMetisCard();
//QUdpSocket socket;
// if (socket.bind(QHostAddress(set->getHPSDRDeviceLocalAddr()),
// set->getMetisPort(),
// //QUdpSocket::DefaultForPlatform))
// QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress))
// {
//DATAIO_DEBUG << "device start/stop: socket bound successful to local port " << set->getMetisPort();
m_commandDatagram.resize(64);
m_commandDatagram[0] = (char)0xEF;
m_commandDatagram[1] = (char)0xFE;
m_commandDatagram[2] = (char)0x04;
m_commandDatagram[3] = (char)value;
for (int i = 4; i < 64; i++) m_commandDatagram[i] = 0x00;
if (m_dataIOSocket->writeDatagram(m_commandDatagram, metis.ip_address, DEVICE_PORT) == 64) {
//if (value == 1) {
if (value != 0) {
io->networkIOMutex.lock();
DATAIO_DEBUG << "sent start command to device at: "<< qPrintable(metis.ip_address.toString());
io->networkIOMutex.unlock();
m_networkDeviceRunning = true;
}
else {
//DATA_ENGINE_DEBUG << "sent stop command to Metis at"<< m_metisCards[0].ip_address.toString();
io->networkIOMutex.lock();
DATAIO_DEBUG << "sent stop command to device at: "<< qPrintable(metis.ip_address.toString());
io->networkIOMutex.unlock();
m_networkDeviceRunning = false;
}
}
else
DATAIO_DEBUG << "device start/stop: sending command to device failed.";
//socket.close();
// }
// else {
//
// DATAIO_DEBUG << "device start/stop: socket binding failed.";
// }
// socket.close();
// DATAIO_DEBUG << "device start/stop: socket closed.";
}
void DataIO::sendAudio(u_char *buf) {
//RRK send audio bytes here
static TYPECPX cbuf[252];
int i, j;
short sample;
for(i = 8, j = 0; i < 512; i += 8, j++) {
//bytes are L,R,I,Q skip the I,Q
sample = buf[i] << 8 | buf[i+1]; //left
cbuf[j].re = (double)sample;
sample = buf[i+2] << 8 | buf[i+3]; //right
cbuf[j].im = (double)sample;
}
if(m_pSoundCardOut)
m_pSoundCardOut->PutOutQueue(63, cbuf);
}
void DataIO::writeData() {
if (m_setNetworkDeviceHeader) {
m_outDatagram.resize(0);
m_outDatagram += m_deviceSendDataSignature;
QByteArray seq(reinterpret_cast<const char*>(&m_sendSequence), sizeof(m_sendSequence));
m_outDatagram += seq;
m_outDatagram += io->audioDatagram;
m_sendSequence++;
m_setNetworkDeviceHeader = false;
}
else {
m_outDatagram += io->audioDatagram;
if (m_dataIOSocket->writeDatagram(m_outDatagram, set->getCurrentMetisCard().ip_address, DEVICE_PORT) < 0) {
DATAIO_DEBUG << "error sending data to device: " << m_dataIOSocket->errorString();
}
//if (m_sendSequence%100 == 0)
// DATAIO_DEBUG << m_sendSequence;
if (m_sendSequence != m_oldSendSequence + 1) {
DATAIO_DEBUG << "output sequence error: old = " << m_oldSendSequence << "; new =" << m_sendSequence;
}
m_oldSendSequence = m_sendSequence;
m_setNetworkDeviceHeader = true;
}
}
void DataIO::displayDataReceiverSocketError(QAbstractSocket::SocketError error) {
io->networkIOMutex.lock();
DATAIO_DEBUG << "data IO socket error: " << error;
io->networkIOMutex.unlock();
}
void DataIO::setManualSocketBufferSize(QObject *sender, bool value) {
Q_UNUSED (sender)
m_manualBufferSize = value;
DATAIO_DEBUG << "m_manualBufferSize to change = " << m_manualBufferSize;
int socketBufferSize = 1032 * set->getSocketBufferSize();
io->networkIOMutex.lock();
if (m_manualBufferSize) {
DATAIO_DEBUG << "set data IO socket BufferSize to " << m_socketBufferSize;
#if defined(Q_OS_WIN32)
if (::setsockopt(m_dataIOSocket->socketDescriptor(), SOL_SOCKET,
SO_RCVBUF, (char *)&socketBufferSize, sizeof(socketBufferSize)) == -1) {
io->networkIOMutex.lock();
DATAIO_DEBUG << "dataIOSocket error!";
io->networkIOMutex.unlock();
}
#endif
}
else {
DATAIO_DEBUG << "set data IO socket BufferSize to 32 kB.";
socketBufferSize = 1032 * 32;
#if defined(Q_OS_WIN32)
if (::setsockopt(m_dataIOSocket->socketDescriptor(), SOL_SOCKET,
SO_RCVBUF, (char *)&socketBufferSize, sizeof(socketBufferSize)) == -1) {
io->networkIOMutex.lock();
DATAIO_DEBUG << "dataIOSocket error!";
io->networkIOMutex.unlock();
}
#endif
}
io->networkIOMutex.unlock();
}
void DataIO::setSocketBufferSize(QObject *sender, int value) {
Q_UNUSED (sender)
int socketBufferSize = value * 1024;
DATAIO_DEBUG << "m_socketBufferSize = " << value;
io->networkIOMutex.lock();
#if defined(Q_OS_WIN32)
if (::setsockopt(m_dataIOSocket->socketDescriptor(), SOL_SOCKET,
SO_RCVBUF, (char *)&socketBufferSize, sizeof(socketBufferSize)) == -1) {
io->networkIOMutex.lock();
DATAIO_DEBUG << "dataIOSocket error!";
io->networkIOMutex.unlock();
}
#endif
io->networkIOMutex.unlock();
}
void DataIO::setSampleRate(QObject *sender, int value) {
Q_UNUSED(sender)
int bufferSize;
io->networkIOMutex.lock();
switch (value) {
case 48000:
bufferSize = 16*1024;//128 * 1032
DATAIO_DEBUG << "socket buffer size set to 16 kB.";
break;
case 96000:
bufferSize = 32*1024;//128 * 1032
DATAIO_DEBUG << "socket buffer size set to 32 kB.";
break;
case 192000:
bufferSize = 64*1024;//128 * 1032
DATAIO_DEBUG << "socket buffer size set to 64 kB.";
break;
case 384000:
bufferSize = 128*1024;//128 * 1032
DATAIO_DEBUG << "socket buffer size set to 128 kB.";
break;
default:
DATAIO_DEBUG << "invalid sample rate !\n";
break;
}
#if defined(Q_OS_WIN32)
if (::setsockopt(m_dataIOSocket->socketDescriptor(), SOL_SOCKET,
SO_RCVBUF, (char *)&bufferSize, sizeof(bufferSize)) == -1) {
DATAIO_DEBUG << "dataIOSocket error!";
}
#endif
io->networkIOMutex.unlock();
}
+120
View File
@@ -0,0 +1,120 @@
/**
* @file cusdr_dataIO.h
* @brief Data IO header file
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-10-01
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_DATAIO_H
#define _CUSDR_DATAIO_H
//#include <QObject>
//#include <QMutex>
//#include <QByteArray>
//#include <QBuffer>
//#include <QVector>
//#include <QList>
//#include <QWaitCondition>
//#include <QThread>
#include "cusdr_settings.h"
#include "soundout.h"
#ifdef LOG_DATAIO
# define DATAIO_DEBUG qDebug().nospace() << "DataIO::\t"
#else
# define DATAIO_DEBUG nullDebug()
#endif
class DataIO : public QObject {
Q_OBJECT
public:
DataIO(THPSDRParameter *ioData = 0);
~DataIO();
public slots:
void stop();
void initDataReceiverSocket();
void readData();
void writeData();
void sendAudio(u_char *buf);
void sendInitFramesToNetworkDevice(int rx);
void networkDeviceStartStop(char value);
//void setWidebandBuffers(int value);
private slots:
void setSampleRate(QObject *sender, int value);
void displayDataReceiverSocketError(QAbstractSocket::SocketError error);
void setManualSocketBufferSize(QObject *sender, bool value);
void setSocketBufferSize(QObject *sender, int value);
void readDeviceData();
private:
Settings* set;
QUdpSocket* m_dataIOSocket;
//QMutex m_mutex;
QByteArray m_commandDatagram;
QByteArray m_datagram;
QByteArray m_wbDatagram;
QByteArray m_twoFramesDatagram;
QByteArray m_metisGetDataSignature;
QByteArray m_outDatagram;
QByteArray m_deviceSendDataSignature;
QString m_message;
QTime m_packetLossTime;
THPSDRParameter* io;
//TNetworkDevicecard netDevice;
bool m_dataIOSocketOn;
bool m_networkDeviceRunning;
bool m_setNetworkDeviceHeader;
long m_sequence;
long m_oldSequence;
long m_sequenceWideBand;
long m_oldSequenceWideBand;
long m_sendSequence;
long m_oldSendSequence;
int m_wbBuffers;
int m_wbCount;
int m_socketBufferSize;
bool m_sendEP4;
bool m_manualBufferSize;
bool m_packetsToggle;
bool m_firstFrame;
volatile bool m_stopped;
CSoundOut* m_pSoundCardOut;
signals:
void messageEvent(QString message);
};
#endif // _CUSDR_DATAIO_H
+271
View File
@@ -0,0 +1,271 @@
/**
* @file cusdr_discoverer.cpp
* @brief HPSDR device discoverer class
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-05-19
*/
/*
*
* Copyright 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define LOG_DISCOVERER
#include "cusdr_discoverer.h"
#include "Util/cusdr_buttons.h"
//#include <QComboBox>
//#include <QDialogButtonBox>
//#include <QLabel>
//#include <QPushButton>
//#include <QVBoxLayout>
//#include <QCheckBox>
//#include <QSlider>
//#include <QSpinBox>
//#define btn_height 18
//#define btn_width 74
Discoverer::Discoverer(THPSDRParameter *ioData)
: QObject()
, set(Settings::instance())
, io(ioData)
{
m_deviceCards = set->getMetisCardsList();
}
Discoverer::~Discoverer() {
}
void Discoverer::initHPSDRDevice() {
m_searchTime.start();
int deviceNo = 0;
while (deviceNo == 0) {
deviceNo = findHPSDRDevices();
if (deviceNo > 1) {
set->setHPSDRDeviceNumber(deviceNo);
break;
}
if (deviceNo > 0) {
set->setHPSDRDeviceNumber(deviceNo);
break;
}
if (m_searchTime.elapsed() > 1000) {
set->setHPSDRDeviceNumber(0);
break;
}
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "no device found - trying again...";
io->networkIOMutex.unlock();
}
io->networkIOMutex.lock();
io->devicefound.wakeAll();
io->networkIOMutex.unlock();
}
int Discoverer::findHPSDRDevices() {
int devicesFound = 0;
m_findDatagram.resize(63);
m_findDatagram[0] = (char)0xEF;
m_findDatagram[1] = (char)0xFE;
m_findDatagram[2] = (char)0x02;
for (int i = 3; i < 63; i++)
m_findDatagram[i] = (char)0x00;
QUdpSocket socket;
CHECKED_CONNECT(
&socket,
SIGNAL(error(QAbstractSocket::SocketError)),
this,
SLOT(displayDiscoverySocketError(QAbstractSocket::SocketError)));
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "using " << qPrintable(QHostAddress(set->getHPSDRDeviceLocalAddr()).toString()) << " for discovery.";
io->networkIOMutex.unlock();
// clear comboBox entries in the network dialogue
set->clearNetworkIOComboBoxEntry();
#if defined(Q_OS_WIN32)
if (socket.bind(
QHostAddress(set->getHPSDRDeviceLocalAddr()), 0,
QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress))
//QUdpSocket::ReuseAddressHint))
{
set->setMetisPort(this, socket.localPort());
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "discovery_socket bound successfully to port " << socket.localPort();
io->networkIOMutex.unlock();
}
else {
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "discovery_socket bind failed.";
io->networkIOMutex.unlock();
socket.close();
return 0;
}
#elif defined(Q_OS_LINUX)
if (socket.bind(
QHostAddress(set->getHPSDRDeviceLocalAddr()),
QUdpSocket::DefaultForPlatform))
{
CHECKED_CONNECT(
&socket,
SIGNAL(error(QAbstractSocket::SocketError)),
this,
SLOT(displayDiscoverySocketError(QAbstractSocket::SocketError)));
set->setMetisPort(this, socket.localPort());
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "discovery_socket bound successfully to port " << socket.localPort();
io->networkIOMutex.unlock();
}
else {
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "discovery_socket bind failed.";
io->networkIOMutex.unlock();
socket.close();
return 0;
}
#endif
if (socket.writeDatagram(m_findDatagram, QHostAddress::Broadcast, DEVICE_PORT) == 63) {
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "discovery data sent.";
io->networkIOMutex.unlock();
}
else {
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "discovery data not sent.";
io->networkIOMutex.unlock();
}
// wait a little
//SleeperThread::msleep(30);
SleeperThread::msleep(500);
while (socket.hasPendingDatagrams()) {
TNetworkDevicecard mc;
quint16 port;
m_deviceDatagram.resize(socket.pendingDatagramSize());
socket.readDatagram(m_deviceDatagram.data(), m_deviceDatagram.size(), &mc.ip_address, &port);
if (m_deviceDatagram[0] == (char)0xEF && m_deviceDatagram[1] == (char)0xFE) {
if (m_deviceDatagram[2] == (char)0x02) {
sprintf(mc.mac_address, "%02X:%02X:%02X:%02X:%02X:%02X",
m_deviceDatagram[3] & 0xFF, m_deviceDatagram[4] & 0xFF, m_deviceDatagram[5] & 0xFF,
m_deviceDatagram[6] & 0xFF, m_deviceDatagram[7] & 0xFF, m_deviceDatagram[8] & 0xFF);
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "Device found at " << qPrintable(mc.ip_address.toString()) << ":" << port << "; Mac addr: [" << mc.mac_address << "]";
DISCOVERER_DEBUG << "Device code version: " << qPrintable(QString::number(m_deviceDatagram.at(9), 16));
io->networkIOMutex.unlock();
int no = m_deviceDatagram.at(10);
QString str;
if (no == 0)
str = "Metis";
else if (no == 1)
str = "Hermes";
else if (no == 2)
str = "Griffin";
else if (no == 4)
str = "Angelia";
mc.boardID = no;
mc.boardName = str;
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "Device board ID: " << no;
DISCOVERER_DEBUG << "Device is: " << qPrintable(str);
io->networkIOMutex.unlock();
m_deviceCards.append(mc);
str += " (";
str += mc.ip_address.toString();
str += ")";
set->addNetworkIOComboBoxEntry(str);
devicesFound++;
}
else if (m_deviceDatagram[2] == (char)0x03) {
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "Device already sending data!";
io->networkIOMutex.unlock();
}
}
}
set->setMetisCardList(m_deviceCards);
if (devicesFound == 1) {
set->setCurrentHPSDRDevice(m_deviceCards.at(0));
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "Device selected: " << qPrintable(m_deviceCards.at(0).ip_address.toString());
io->networkIOMutex.unlock();
}
socket.close();
return devicesFound;
}
void Discoverer::displayDiscoverySocketError(QAbstractSocket::SocketError error) {
io->networkIOMutex.lock();
DISCOVERER_DEBUG << "discovery socket error: " << error;
io->networkIOMutex.unlock();
}
void Discoverer::clear() {
//m_metisDeviceComboBox->clear();
m_deviceCards.clear();
}
+86
View File
@@ -0,0 +1,86 @@
/**
* @file cusdr_discoverer.h
* @brief HPSDR device discoverer header file
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-05-19
*/
/*
*
* Copyright 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_DISCOVERER_H
#define _CUSDR_DISCOVERER_H
//#include <QObject>
//#include <QComboBox>
//#include <QDialogButtonBox>
//#include <QLabel>
//#include <QPushButton>
//#include <QVBoxLayout>
//#include <QCheckBox>
//#include <QSlider>
//#include <QSpinBox>
//#include <QElapsedTimer>
#include "cusdr_settings.h"
#ifdef LOG_DISCOVERER
# define DISCOVERER_DEBUG qDebug().nospace() << "Discoverer::\t"
#else
# define DISCOVERER_DEBUG nullDebug()
#endif
class Discoverer : public QObject {
Q_OBJECT
public:
Discoverer(THPSDRParameter *ioData = 0);
~Discoverer();
int findHPSDRDevices();
void clear();
public slots:
void initHPSDRDevice();
private slots:
void displayDiscoverySocketError(QAbstractSocket::SocketError error);
private:
Settings* set;
THPSDRParameter* io;
QTime m_searchTime;
QByteArray m_findDatagram;
QByteArray m_deviceDatagram;
//QString m_deviceStr;
TNetworkDevicecard m_deviceCard;
QList<TNetworkDevicecard> m_deviceCards;
signals:
};
#endif // _CUSDR_DISCOVERER_H
+772
View File
@@ -0,0 +1,772 @@
/**
* @file cusdr_receiver.cpp
* @brief cuSDR receiver class
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2010-11-12
*/
/* Copyright (C)
*
* 2010 - Hermann von Hasseln, DL3HVH
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#define LOG_RECEIVER
// use: RECEIVER_DEBUG
#include "cusdr_receiver.h"
Receiver::Receiver(int rx)
: QObject()
, set(Settings::instance())
, m_filterMode(set->getCurrentFilterMode())
, m_stopped(false)
, m_receiver(rx)
, m_samplerate(set->getSampleRate())
, m_audioMode(1)
//, m_calOffset(63.0)
//, m_calOffset(33.0)
{
setReceiverData(set->getReceiverDataList().at(m_receiver));
InitCPX(inBuf, BUFFER_SIZE, 0.0f);
InitCPX(outBuf, BUFFER_SIZE, 0.0f);
newSpectrum.resize(BUFFER_SIZE*4);
qtdsp = 0;
setupConnections();
highResTimer = new HResTimer();
m_displayTime = (int)(1000000.0/set->getFramesPerSecond(m_receiver));
m_smeterTime.start();
}
Receiver::~Receiver() {
inBuf.clear();
outBuf.clear();
if (qtdsp) {
delete qtdsp;
qtdsp = 0;
}
if (highResTimer) {
delete highResTimer;
}
m_stopped = false;
}
void Receiver::setupConnections() {
CHECKED_CONNECT(
set,
SIGNAL(systemStateChanged(
QObject *,
QSDR::_Error,
QSDR::_HWInterfaceMode,
QSDR::_ServerMode,
QSDR::_DataEngineState)),
this,
SLOT(setSystemState(
QObject *,
QSDR::_Error,
QSDR::_HWInterfaceMode,
QSDR::_ServerMode,
QSDR::_DataEngineState)));
CHECKED_CONNECT(
set,
SIGNAL(mainVolumeChanged(QObject *, int, float)),
this,
SLOT(setAudioVolume(QObject *, int, float)));
CHECKED_CONNECT(
set,
SIGNAL(sampleRateChanged(QObject *, int)),
this,
SLOT(setSampleRate(QObject *, int)));
CHECKED_CONNECT(
set,
SIGNAL(dspModeChanged(QObject *, int, DSPMode)),
this,
SLOT(setDspMode(QObject *, int, DSPMode)));
CHECKED_CONNECT(
set,
SIGNAL(hamBandChanged(QObject *, int, bool, HamBand)),
this,
SLOT(setHamBand(QObject *, int, bool, HamBand)));
CHECKED_CONNECT(
set,
SIGNAL(agcModeChanged(QObject *, int, AGCMode, bool)),
this,
SLOT(setAGCMode(QObject *, int, AGCMode, bool)));
CHECKED_CONNECT(
set,
SIGNAL(agcGainChanged(QObject *, int, int)),
this,
SLOT(setAGCGain(QObject *, int, int)));
// CHECKED_CONNECT(
// set,
// SIGNAL(agcMaximumGain_dBmChanged(QObject *, int, int)),
// this,
// SLOT(setAGCMaximumGain_dBm(QObject *, int, int)));
CHECKED_CONNECT(
set,
SIGNAL(agcMaximumGainChanged_dB(QObject *, int, qreal)),
this,
SLOT(setAGCMaximumGain_dB(QObject *, int, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(agcFixedGainChanged_dB(QObject *, int, qreal)),
this,
SLOT(setAGCFixedGain_dB(QObject *, int, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(agcThresholdChanged_dB(QObject *, int, qreal)),
this,
SLOT(setAGCThreshold_dB(QObject *, int, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(agcHangThresholdChanged(QObject *, int, int)),
this,
SLOT(setAGCHangThreshold(QObject *, int, int)));
CHECKED_CONNECT(
set,
SIGNAL(agcHangLevelChanged_dB(QObject *, int, qreal)),
this,
SLOT(setAGCHangLevel_dB(QObject *, int, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(agcVariableGainChanged_dB(QObject *, int, qreal)),
this,
SLOT(setAGCVariableGain_dB(QObject *, int, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(agcAttackTimeChanged(QObject *, int, qreal)),
this,
SLOT(setAGCAttackTime(QObject *, int, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(agcDecayTimeChanged(QObject *, int, qreal)),
this,
SLOT(setAGCDecayTime(QObject *, int, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(agcHangTimeChanged(QObject *, int, qreal)),
this,
SLOT(setAGCHangTime(QObject *, int, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(filterFrequenciesChanged(QObject *, int, qreal, qreal)),
this,
SLOT(setFilterFrequencies(QObject *, int, qreal, qreal)));
CHECKED_CONNECT(
set,
SIGNAL(framesPerSecondChanged(QObject*, int, int)),
this,
SLOT(setFramesPerSecond(QObject*, int, int)));
/*CHECKED_CONNECT(
set,
SIGNAL(receiverDataReady()),
this,
SLOT(dspProcessing()));*/
}
void Receiver::setReceiverData(TReceiver data) {
m_receiverData = data;
//m_serverMode = m_receiverData.serverMode;
m_dspCore = m_receiverData.dspCore;
m_sampleRate = m_receiverData.sampleRate;
m_hamBand = m_receiverData.hamBand;
m_dspMode = m_receiverData.dspMode;
m_dspModeList = m_receiverData.dspModeList;
m_agcMode = m_receiverData.agcMode;
m_agcGain = m_receiverData.acgGain;
m_agcFixedGain_dB = m_receiverData.agcFixedGain_dB;
m_agcMaximumGain_dB = m_receiverData.agcMaximumGain_dB;
m_agcHangThreshold = m_receiverData.agcHangThreshold;
m_agcVariableGain = m_receiverData.agcVariableGain;
m_audioVolume = m_receiverData.audioVolume;
m_filterLo = m_receiverData.filterLo;
m_filterHi = m_receiverData.filterHi;
m_lastCtrFrequencyList = m_receiverData.lastCenterFrequencyList;
m_lastVfoFrequencyList = m_receiverData.lastVfoFrequencyList;
m_mercuryAttenuators = m_receiverData.mercuryAttenuators;
}
bool Receiver::initDSPInterface() {
if (m_dspCore == QSDR::QtDSP) {
if (!initQtDSPInterface()) return false;
}
return true;
}
bool Receiver::initQtDSPInterface() {
qtdsp = new QDSPEngine(this, m_receiver, BUFFER_SIZE);
if (qtdsp)
qtdsp->setQtDSPStatus(true);
else {
RECEIVER_DEBUG << "could not start QtDSP for receiver: " << m_receiver;
qtdsp = 0;
return false;
}
qtdsp->setVolume(m_audioVolume);
DSPMode mode = m_dspModeList.at(m_hamBand);
RECEIVER_DEBUG << "set DSP mode to: " << set->getDSPModeString(mode);
qtdsp->setDSPMode(mode);
qtdsp->filter->setFilter(
getFilterFromDSPMode(set->getDefaultFilterList(), mode).filterLo,
getFilterFromDSPMode(set->getDefaultFilterList(), mode).filterHi);
qtdsp->wpagc->setMode(m_agcMode);
qtdsp->wpagc->setAGCFixedGainDb(m_agcFixedGain_dB);
qtdsp->wpagc->setMaximumGainDb(m_agcMaximumGain_dB);
// if (m_agcMode == (AGCMode) agcOFF)
// set->setAGCFixedGain_dB(this, m_receiver, m_agcFixedGain_dB);
// else
// set->setAGCMaximumGain_dB(this, m_receiver, m_agcMaximumGain_dB);
RECEIVER_DEBUG << "QtDSP for receiver: " << m_receiver << " started.";
return true;
}
void Receiver::deleteDSPInterface() {
if (m_dspCore == QSDR::QtDSP)
deleteQtDSP();
}
void Receiver::deleteQtDSP() {
if (qtdsp) {
delete qtdsp;
qtdsp = 0;
}
}
void Receiver::enqueueData() {
inQueue.enqueue(inBuf);
if (inQueue.isFull()) {
RECEIVER_DEBUG << "inQueue full!";
}
}
void Receiver::stop() {
m_mutex.lock();
m_stopped = true;
m_mutex.unlock();
}
void Receiver::dspProcessing() {
//RECEIVER_DEBUG << "dspProcessing: " << this->thread();
//io.mutex.lock();
qtdsp->processDSP(inBuf, outBuf, BUFFER_SIZE);
//io.mutex.unlock();
// spectrum
qtdsp->getSpectrum(newSpectrum, set->getFFTMultiplicator());
if (highResTimer->getElapsedTimeInMicroSec() >= getDisplayDelay()) {
emit spectrumBufferChanged(m_receiver, newSpectrum);
highResTimer->start();
}
if (m_receiver == set->getCurrentReceiver()) {
// S-Meter
if (m_smeterTime.elapsed() > 20) {
m_sMeterValue = qtdsp->getSMeterInstValue();
emit sMeterValueChanged(m_receiver, m_sMeterValue);
m_smeterTime.restart();
}
// process output data
emit outputBufferSignal(m_receiver, outBuf);
}
}
void Receiver::setSampleRate(QObject *sender, int value) {
Q_UNUSED(sender)
if (m_samplerate == value) return;
switch (value) {
case 48000:
m_samplerate = value;
break;
case 96000:
m_samplerate = value;
break;
case 192000:
m_samplerate = value;
break;
case 384000:
m_samplerate = value;
break;
default:
RECEIVER_DEBUG << "invalid sample rate (possible values are: 48, 96, 192, or 384 kHz)!\n";
break;
}
if (qtdsp)
qtdsp->setSampleRate(this, m_samplerate);
else
RECEIVER_DEBUG << "qtdsp down: cannot set sample rate!\n";
}
void Receiver::setServerMode(QSDR::_ServerMode mode) {
m_serverMode = mode;
}
QSDR::_ServerMode Receiver::getServerMode() const {
return m_serverMode;
}
QSDR::_DSPCore Receiver::getDSPCoreMode() const {
return m_dspCore;
}
//void Receiver::setSocketState(SocketState state) {
//
// m_socketState = state;
//}
//Receiver::SocketState Receiver::socketState() const {
//
// return m_socketState;
//}
void Receiver::setSystemState(
QObject *sender,
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state)
{
Q_UNUSED (sender)
Q_UNUSED (err)
if (m_hwInterface != hwmode)
m_hwInterface = hwmode;
if (m_serverMode != mode)
m_serverMode = mode;
if (m_dataEngineState != state)
m_dataEngineState = state;
}
void Receiver::setAudioMode(QObject* sender, int mode) {
if (sender != this && m_audioMode == mode) return;
m_audioMode = mode;
}
//void Receiver::setID(int value) {
//
// m_receiverID = value;
// RECEIVER_DEBUG << "This is receiver " << m_receiverID;
//}
void Receiver::setReceiver(int value) {
m_receiver = value;
}
void Receiver::setSampleRate(int value) {
m_sampleRate = value;
}
void Receiver::setHamBand(QObject *sender, int rx, bool byBtn, HamBand band) {
Q_UNUSED(sender)
Q_UNUSED(byBtn)
if (m_receiver == rx) {
if (m_hamBand == band) return;
m_hamBand = band;
}
}
void Receiver::setDspMode(QObject *sender, int rx, DSPMode mode) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_dspMode == mode) return;
m_dspMode = mode;
if (qtdsp) {
qtdsp->setDSPMode(mode);
qtdsp->filter->setFilter(
getFilterFromDSPMode(set->getDefaultFilterList(), mode).filterLo,
getFilterFromDSPMode(set->getDefaultFilterList(), mode).filterHi);
}
//QString msg = "[receiver]: set mode for receiver %1 to %2";
//emit messageEvent(msg.arg(rx).arg(set->getDSPModeString(m_dspMode)));
}
void Receiver::setAGCMode(QObject *sender, int rx, AGCMode mode, bool hang) {
Q_UNUSED(sender)
Q_UNUSED(hang)
if (m_receiver != rx) return;
if (m_agcMode == mode) return;
m_agcMode = mode;
if (qtdsp) {
qtdsp->wpagc->setMode(mode);
}
}
void Receiver::setAGCGain(QObject *sender, int rx, int value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcGain == value) return;
m_agcGain = value;
if (qtdsp) {
//RECEIVER_DEBUG << "AGCThreshDB (plus offset) = " << m_agcGain - AGCOFFSET;
//qtdsp->wpagc->setAGCThreshDb(m_filterLo, m_filterHi, BUFFER_SIZE, m_agcGain - AGCOFFSET);
}
}
void Receiver::setAGCFixedGain_dB(QObject *sender, int rx, qreal value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcFixedGain_dB == value) return;
m_agcFixedGain_dB = value;
if (qtdsp) {
//RECEIVER_DEBUG << "m_agcFixedGain = " << m_agcFixedGain;
qtdsp->wpagc->setAGCFixedGainDb(m_agcFixedGain_dB);
}
}
void Receiver::setAGCMaximumGain_dB(QObject *sender, int rx, qreal value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcMaximumGain_dB == value) return;
m_agcMaximumGain_dB = value;
if (qtdsp) {
//RECEIVER_DEBUG << "setAGCMaximumGain_dB = " << m_agcMaximumGain_dB;
qtdsp->wpagc->setMaximumGainDb(m_agcMaximumGain_dB);
}
}
void Receiver::setAGCThreshold_dB(QObject *sender, int rx, qreal value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcThreshold_dBm == value) return;
m_agcThreshold_dBm = value;
if (qtdsp) {
//RECEIVER_DEBUG << "AGCThreshDB (minus offset) for Rx " << m_receiver << ": " << m_agcThreshold_dBm - AGCOFFSET;
qtdsp->wpagc->setAGCThreshDb(m_filterLo, m_filterHi, 2*BUFFER_SIZE, m_agcThreshold_dBm - AGCOFFSET);
}
}
void Receiver::setAGCHangThreshold(QObject *sender, int rx, int value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcHangThreshold == value) return;
m_agcHangThreshold = value;
if (qtdsp) {
RECEIVER_DEBUG << "m_agcHangThreshold =" << m_agcHangThreshold/100.0;
qtdsp->wpagc->setHangThresh(m_agcHangThreshold/100.0);
}
}
void Receiver::setAGCHangLevel_dB(QObject *sender, int rx, qreal value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcHangLevel == value) return;
m_agcHangLevel = value;
if (qtdsp) {
//RECEIVER_DEBUG << "m_agcHangLevel = " << m_agcHangLevel - AGCOFFSET;
qtdsp->wpagc->setHangLevelDb(m_agcHangLevel - AGCOFFSET);
}
//set->setAGCHangLeveldB(this, m_receiverID, value);
}
void Receiver::setAGCVariableGain_dB(QObject *sender, int rx, qreal value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcVariableGain == value) return;
m_agcVariableGain = value;
if (qtdsp) {
RECEIVER_DEBUG << "m_agcVariableGain = " << m_agcVariableGain;
qtdsp->wpagc->setVarGainDb(m_agcVariableGain);
}
}
void Receiver::setAGCAttackTime(QObject *sender, int rx, qreal value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcAttackTime == value) return;
m_agcAttackTime = value;
if (qtdsp) {
RECEIVER_DEBUG << "m_agcAttackTime = " << m_agcAttackTime;
qtdsp->wpagc->setTauAttack(m_agcAttackTime);
}
}
void Receiver::setAGCDecayTime(QObject *sender, int rx, qreal value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcDecayTime == value) return;
m_agcDecayTime = value;
if (qtdsp) {
RECEIVER_DEBUG << "m_agcDecayTime = " << m_agcDecayTime;
qtdsp->wpagc->setTauDecay(m_agcDecayTime);
}
}
void Receiver::setAGCHangTime(QObject *sender, int rx, qreal value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
if (m_agcHangTime == value) return;
m_agcHangTime = value;
if (qtdsp) {
RECEIVER_DEBUG << "m_agcHangTime = " << m_agcHangTime;
qtdsp->wpagc->setHangTime(m_agcHangTime);
}
}
void Receiver::setAudioVolume(QObject *sender, int rx, float value) {
Q_UNUSED(sender)
if (m_receiver != rx) return;
//if (m_audioVolume == value) return;
m_audioVolume = value;
if (qtdsp) {
//RECEIVER_DEBUG << "setAudioVolume =" << m_audioVolume;
qtdsp->setVolume(value);
}
}
void Receiver::setFilterFrequencies(QObject *sender, int rx, double low, double high) {
Q_UNUSED(sender)
if (m_receiver == rx) {
if (m_filterLo == low && m_filterHi == high) return;
m_filterLo = low;
m_filterHi = high;
if (qtdsp) {
qtdsp->filter->setFilter((float)low, (float)high);
qtdsp->wpagc->filterChanged();
}
}
}
void Receiver::setCtrFrequency(long frequency) {
if (m_ctrFrequency == frequency) return;
m_ctrFrequency = frequency;
HamBand band = getBandFromFrequency(set->getBandFrequencyList(), frequency);
m_lastCtrFrequencyList[(int) band] = m_ctrFrequency;
}
void Receiver::setVfoFrequency(long frequency) {
if (m_vfoFrequency == frequency) return;
m_vfoFrequency = frequency;
HamBand band = getBandFromFrequency(set->getBandFrequencyList(), frequency);
m_lastVfoFrequencyList[(int) band] = m_vfoFrequency;
}
void Receiver::setLastCtrFrequencyList(const QList<long> &fList) {
m_lastCtrFrequencyList = fList;
}
void Receiver::setLastVfoFrequencyList(const QList<long> &fList) {
m_lastVfoFrequencyList = fList;
}
void Receiver::setdBmPanScaleMin(qreal value) {
if (m_dBmPanScaleMin == value) return;
m_dBmPanScaleMin = value;
}
void Receiver::setdBmPanScaleMax(qreal value) {
if (m_dBmPanScaleMax == value) return;
m_dBmPanScaleMax = value;
}
void Receiver::setMercuryAttenuators(const QList<int> &attenuators) {
m_mercuryAttenuators = attenuators;
}
void Receiver::setFramesPerSecond(QObject *sender, int rx, int value) {
Q_UNUSED(sender)
if (m_receiver == rx)
m_displayTime = (int)(1000000.0/value);
}
void Receiver::setPeerAddress(QHostAddress addr) {
m_peerAddress = addr;
}
void Receiver::setSocketDescriptor(int value) {
m_socketDescriptor = value;
}
void Receiver::setClient(int value) {
m_client = value;
}
void Receiver::setIQPort(int value) {
m_iqPort = value;
}
void Receiver::setBSPort(int value) {
m_bsPort = value;
}
void Receiver::setConnectedStatus(bool value) {
m_connected = value;
}
+231
View File
@@ -0,0 +1,231 @@
/**
* @file cusdr_receiver.h
* @brief cuSDR receiver header file
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2010-11-12
*/
/* Copyright (C)
*
* 2010 - Hermann von Hasseln, DL3HVH
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef CUSDR_RECEIVER_H
#define CUSDR_RECEIVER_H
//#include <QObject>
//#include <QtNetwork>
#include "cusdr_settings.h"
#include "QtDSP/qtdsp_dspEngine.h"
#include "Util/cusdr_highResTimer.h"
#ifdef LOG_RECEIVER
# define RECEIVER_DEBUG qDebug().nospace() << "Receiver::\t"
#else
# define RECEIVER_DEBUG nullDebug()
#endif
class Receiver : public QObject {
Q_OBJECT
public:
Receiver(int rx = 0);
~Receiver();
void setupConnections();
bool initDSPInterface();
void deleteDSPInterface();
void enqueueData();
QSDR::_ServerMode getServerMode() const;
QSDR::_DSPCore getDSPCoreMode() const;
QHostAddress getPeerAddress() { return m_peerAddress; }
HamBand getHamBand() { return m_hamBand; }
AGCMode getAGCMode() { return m_agcMode; }
QList<int> getMercuryAttenuators() { return m_mercuryAttenuators; }
QList<DSPMode> getDSPModeList() { return m_dspModeList; }
int getAudioMode() { return m_audioMode; }
int getSocketDescriptor() { return m_socketDescriptor; }
int getReceiverNo() { return m_receiver; }
int getClient() { return m_client; }
int getIQPort() { return m_iqPort; }
int getBSPort() { return m_bsPort; }
//int getID() { return m_receiverID; }
int getSampleRate() { return m_sampleRate; }
int getDisplayDelay() { return m_displayTime; }
qreal getAGCGain() { return m_agcGain; }
float getAudioVolume() { return m_audioVolume; }
long getCtrFrequency() { return m_ctrFrequency; }
long getVfoFrequency() { return m_vfoFrequency; }
double getFilterLo() { return m_filterLo; }
double getFilterHi() { return m_filterHi; }
qreal getdBmPanScaleMin() { return m_dBmPanScaleMin; }
qreal getdBmPanScaleMax() { return m_dBmPanScaleMax; }
bool getConnectedStatus() { return m_connected; }
float in[BUFFER_SIZE * 2];
float out[BUFFER_SIZE * 2];
float temp[BUFFER_SIZE * 4];
float spectrum[BUFFER_SIZE * 4];
float postSpectrum[BUFFER_SIZE * 4];
QVector<float> newSpectrum;
QDSPEngine *qtdsp;
HResTimer *highResTimer;
CPX inBuf;
CPX outBuf;
QHQueue<CPX> inQueue;
public slots:
void setReceiverData(TReceiver data);
void setAudioMode(QObject* sender, int mode);
void setServerMode(QSDR::_ServerMode mode);
void setPeerAddress(QHostAddress addr);
void setSocketDescriptor(int value);
void setReceiver(int value);
void setClient(int value);
void setIQPort(int value);
void setBSPort(int value);
void setConnectedStatus(bool value);
//void setID(int value);
void setSampleRate(int value);
void setHamBand(QObject* sender, int rx, bool byBtn, HamBand band);
void setDspMode(QObject* sender, int rx, DSPMode mode);
void setAGCMode(QObject* sender, int rx, AGCMode mode, bool hang);
void setAGCGain(QObject* sender, int rx, int value);
void setAudioVolume(QObject* sender, int rx, float value);
void setCtrFrequency(long frequency);
void setVfoFrequency(long frequency);
void setFilterFrequencies(QObject* sender, int rx, qreal low, qreal high);
void setLastCtrFrequencyList(const QList<long> &frequencies);
void setLastVfoFrequencyList(const QList<long> &frequencies);
void setdBmPanScaleMin(qreal value);
void setdBmPanScaleMax(qreal value);
void setMercuryAttenuators(const QList<int> &attenuators);
void dspProcessing();
void stop();
private slots:
void setSystemState(
QObject* sender,
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state);
void setSampleRate(QObject *sender, int value);
void setFramesPerSecond(QObject *sender, int rx, int value);
bool initQtDSPInterface();
void deleteQtDSP();
//void setAGCMaximumGain_dBm(QObject* sender, int rx, int value);
void setAGCMaximumGain_dB(QObject* sender, int rx, qreal value);
void setAGCFixedGain_dB(QObject* sender, int rx, qreal value);
void setAGCThreshold_dB(QObject* sender, int rx, qreal value);
void setAGCHangLevel_dB(QObject* sender, int rx, qreal value);
void setAGCHangThreshold(QObject* sender, int rx, int value);
void setAGCVariableGain_dB(QObject* sender, int rx, qreal value);
void setAGCAttackTime(QObject* sender, int rx, qreal value);
void setAGCDecayTime(QObject* sender, int rx, qreal value);
void setAGCHangTime(QObject* sender, int rx, qreal value);
private:
Settings* set;
QSDR::_DSPCore m_dspCore;
QSDR::_ServerMode m_serverMode;
QSDR::_HWInterfaceMode m_hwInterface;
QSDR::_DataEngineState m_dataEngineState;
TReceiver m_receiverData;
QHostAddress m_peerAddress;
quint16 m_peerPort;
HamBand m_hamBand;
DSPMode m_dspMode;
AGCMode m_agcMode;
TDefaultFilterMode m_filterMode;
QList<long> m_lastCtrFrequencyList;
QList<long> m_lastVfoFrequencyList;
QList<DSPMode> m_dspModeList;
QList<int> m_mercuryAttenuators;
QTime m_smeterTime;
QMutex m_mutex;
volatile bool m_stopped;
int m_receiver;
int m_samplerate;
int m_audioMode; // 1 = audio on, 0 = audio off
int m_socketDescriptor;
int m_client;
int m_iqPort;
int m_bsPort;
int m_sampleRate;
int m_displayTime;
long m_ctrFrequency;
long m_vfoFrequency;
float m_audioVolume;
float m_sMeterValue;
qreal m_agcGain;
qreal m_agcFixedGain_dB;
qreal m_agcMaximumGain_dB;
qreal m_agcThreshold_dBm;
qreal m_agcHangThreshold;
qreal m_agcHangLevel;
qreal m_agcVariableGain;
qreal m_agcAttackTime;
qreal m_agcDecayTime;
qreal m_agcHangTime;
//qreal m_calOffset;
qreal m_filterLo;
qreal m_filterHi;
qreal m_dBmPanScaleMin;
qreal m_dBmPanScaleMax;
bool m_connected;
bool m_hangEnabled;
//void setupConnections();
signals:
void messageEvent(QString msg);
void spectrumBufferChanged(int rx, const qVectorFloat& buffer);
void sMeterValueChanged(int rx, float value);
void outputBufferSignal(int rx, const CPX &buffer);
//void audioReady(int rx);
};
#endif // CUSDR_RECEIVER_H
+51
View File
@@ -0,0 +1,51 @@
//////////////////////////////////////////////////////////////////////
// datatypes.h: Common data type declarations
//
// History:
// 2010-09-15 Initial creation MSW
// 2011-03-27 Initial release
//////////////////////////////////////////////////////////////////////
#ifndef DATATYPES_H
#define DATATYPES_H
#include <math.h>
#include <QtGlobal>
//define single or double precision reals and complex types
typedef float tSReal;
typedef double tDReal;
typedef struct _sCplx
{
tSReal re;
tSReal im;
}tSComplex;
typedef struct _dCplx
{
tDReal re;
tDReal im;
}tDComplex;
typedef struct _isCplx
{
qint16 re;
qint16 im;
}tStereo16;
#define TYPEREAL tDReal
#define TYPECPX tDComplex
#define TYPESTEREO16 tStereo16
#define TYPEMONO16 qint16
//#define K_2PI (8.0*atan(1)) //maybe some compilers are't too smart to optimize out
#define K_2PI (2.0 * 3.14159265358979323846)
#define K_PI (3.14159265358979323846)
#define K_PI4 (K_PI/4.0)
#define K_PI2 (K_PI/2.0)
#define K_3PI4 (3.0*K_PI4)
#endif // DATATYPES_H
+352
View File
@@ -0,0 +1,352 @@
//////////////////////////////////////////////////////////////////////
// FractResampler.cpp: implementation of the CFractResampler class.
//
// This class implements a fractional resampler that can be used to
//convert between different sample rates. A windowes sinc interpolator
// is used to create samples "in between" input samples.
//
// History:
// 2010-09-15 Initial creation MSW
// 2011-03-27 Initial release
/////////////////////////////////////////////////////////////////////
//==========================================================================================
// + + + This Software is released under the "Simplified BSD License" + + +
//Copyright 2010 Moe Wheatley. All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those of the
//authors and should not be interpreted as representing official policies, either expressed
//or implied, of Moe Wheatley.
//==========================================================================================
#include "fractresampler.h"
#include <QDir>
#include <QFile>
#include <QDebug>
//////////////////////////////////////////////////////////////////////
// Local defines
//////////////////////////////////////////////////////////////////////
#define SINC_PERIOD_PTS 10000 //number of points in sinc table between "zero crossings"
//smaller value increases noise floor
#define SINC_PERIODS 28 //number of input sample periods("zero crossings"-1) in
//sinc function(should be even)
//decreasing reduces alias free bandwidth
#define SINC_LENGTH ( (SINC_PERIODS)*SINC_PERIOD_PTS + 1)//number of total points in sinc table
#define MAX_SOUNDCARDVAL 32767.0
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFractResampler::CFractResampler()
{
m_pSinc = NULL;
m_pInputBuf = NULL;
}
CFractResampler::~CFractResampler()
{
if(m_pSinc)
delete m_pSinc;
if(m_pInputBuf)
delete m_pInputBuf;
}
//
//////////////////////////////////////////////////////////////////////
// Initialize resampler memory and create windowed sinc table
// MaxInputSize is the largest number of input samples expected to be processed
//////////////////////////////////////////////////////////////////////
void CFractResampler::Init(int MaxInputSize)
{
int i;
TYPEREAL fi;
TYPEREAL window;
MaxInputSize += SINC_PERIODS; //expand buffer size to include wrap around
if(NULL == m_pSinc)
m_pSinc = new TYPEREAL[SINC_LENGTH];
if(m_pInputBuf)
delete m_pInputBuf;
m_pInputBuf = new TYPECPX[MaxInputSize];
for(i=0; i<MaxInputSize; i++)
{
m_pInputBuf[i].re = 0.0;
m_pInputBuf[i].im = 0.0;
}
for(i=0; i<SINC_LENGTH; i++)
{ //calc Blackman-Harris window points
window = (0.35875
- 0.48829*cos( (K_2PI*i)/(SINC_LENGTH-1) )
+ 0.14128*cos( (2.0*K_2PI*i)/(SINC_LENGTH-1) )
- 0.01168*cos( (3.0*K_2PI*i)/(SINC_LENGTH-1) ) );
//calculate sin(x)/x sinc point * window
fi = K_PI*(double)(i - SINC_LENGTH/2)/(double)SINC_PERIOD_PTS ;
if(i != SINC_LENGTH/2)
m_pSinc[i] = window * (TYPEREAL)sin( (double)fi )/(double)fi;
else
m_pSinc[i] = 1.0;
}
m_FloatTime = 0.0; //init floating point time accumulator
#if 0 //debug hack to write m_pSinc to a file for analysis
QDir::setCurrent("d:/");
QFile File;
File.setFileName("Sinc.txt");
if(File.open(QIODevice::WriteOnly))
{
qDebug()<<"file Opened OK";
char Buf[30000];
for( i=0; i<SINC_LENGTH; i++)
{
sprintf( Buf, "%19.12g\r\n", m_pSinc[i]);
File.write(Buf);
}
}
else
qDebug()<<"file Failed to Open";
#endif
}
//////////////////////////////////////////////////////////////////////
// Resample InLength samples in pInBuf and place into pOutBuf
// using Rate = input rate / output rate
// !!!! Make sure pOutBuf from caller is large enough to hold all
// the generated samples, especially if up converting !!!!!
// COMPLEX version
//////////////////////////////////////////////////////////////////////
int CFractResampler::Resample( int InLength, TYPEREAL Rate, TYPECPX* pInBuf, TYPECPX* pOutBuf)
{
int i;
int j;
int IntegerTime = (int)m_FloatTime; //integer input time accumulator
double dt = Rate; //output delta time as function of input sample time (input rate/output rate)
int outsamples = 0;
TYPECPX acc;
//copy input samples into buffer starting at position SINC_PERIODS
j = SINC_PERIODS;
for(i=0; i<InLength; i++)
m_pInputBuf[j++] = pInBuf[i];
//now calculate output samples by looping until end of input buffer
// is reached. The output position is incremented in fractional time
// of input sample time until all the possible input samples are
//processed.
while(IntegerTime < InLength )
{ //convolve sinc function with input samples where sinc
//function is centered at the output fractional time position
acc.re = 0.0; acc.im = 0.0;
for(i=1; i<=SINC_PERIODS; i++)
{
j = IntegerTime + i; //temp integer time position for convolution loop
int sindx = (int)(( (double)j - m_FloatTime) * (double)SINC_PERIOD_PTS );
acc.re += (m_pInputBuf[j].re * m_pSinc[sindx] );
acc.im += (m_pInputBuf[j].im * m_pSinc[sindx] );
}
pOutBuf[outsamples++] = acc;
m_FloatTime += dt; //inc floating pt output time step
IntegerTime = (int)m_FloatTime; //truncate to integer
}
m_FloatTime -= (double)InLength; //move floating time position back for next call
//keeping leftover fraction
//need to copy last SINC_PERIODS input samples in buffer to beginning of buffer
// for FIR wrap around management. j points to last input sample processed
j = InLength;
for(i=0; i<SINC_PERIODS; i++)
m_pInputBuf[i] = m_pInputBuf[j++];
return outsamples; //return number of output samples processed
}
//////////////////////////////////////////////////////////////////////
// Resample InLength samples in pInBuf and place into pOutBuf
// using Rate = input rate / output rate
// !!!! Make sure pOutBuf from caller is large enough to hold all
// the generated samples, especially if up converting !!!!!
// stereo Integer version
//////////////////////////////////////////////////////////////////////
int CFractResampler::Resample( int InLength, TYPEREAL Rate, TYPECPX* pInBuf, TYPESTEREO16* pOutBuf, TYPEREAL gain)
{
int i;
int j;
int IntegerTime = (int)m_FloatTime; //integer input time accumulator
double dt = Rate; //output delta time as function of input sample time (input rate/output rate)
int outsamples = 0;
TYPECPX acc;
//copy input samples into buffer starting at position SINC_PERIODS
j = SINC_PERIODS;
for(i=0; i<InLength; i++)
{
m_pInputBuf[j++] = pInBuf[i];
}
//now calculate output samples by looping until end of input buffer
// is reached. The output position is incremented in fractional time
// of input sample time until all the possible input samples are
//processed.
while(IntegerTime < InLength )
{ //convolve sinc function with input samples where sinc
//function is centered at the output fractional time position
acc.re = 0.0; acc.im = 0.0;
for(i=1; i<=SINC_PERIODS; i++)
{
j = IntegerTime + i; //temp integer time position for convolution loop
int sindx = (int)(( (double)j - m_FloatTime) * (double)SINC_PERIOD_PTS );
acc.re += (m_pInputBuf[j].re * m_pSinc[sindx] );
acc.im += (m_pInputBuf[j].im * m_pSinc[sindx] );
}
TYPECPX tmp;
tmp.re = (acc.re * gain);;
tmp.im = (acc.im * gain);;
if(tmp.re > MAX_SOUNDCARDVAL)
tmp.re = MAX_SOUNDCARDVAL;
if(tmp.re < -MAX_SOUNDCARDVAL)
tmp.re = -MAX_SOUNDCARDVAL;
if(tmp.im>MAX_SOUNDCARDVAL)
tmp.im = MAX_SOUNDCARDVAL;
if(tmp.im < -MAX_SOUNDCARDVAL)
tmp.im = -MAX_SOUNDCARDVAL;
pOutBuf[outsamples].re = (qint16)tmp.re;
pOutBuf[outsamples++].im = (qint16)tmp.im;
m_FloatTime += dt; //inc floating pt output time step
IntegerTime = (int)m_FloatTime; //truncate to integer
}
m_FloatTime -= (double)InLength; //move floating time position back for next call
//keeping leftover fraction
//need to copy last SINC_PERIODS input samples in buffer to beginning of buffer
// for FIR wrap around management. j points to last input sample processed
j = InLength;
for(i=0; i<SINC_PERIODS; i++)
m_pInputBuf[i] = m_pInputBuf[j++];
return outsamples; //return number of output samples processed
}
//////////////////////////////////////////////////////////////////////
// Resample InLength samples in pInBuf and place into pOutBuf
// using Rate = input rate / output rate
// !!!! Make sure pOutBuf from caller is large enough to hold all
// the generated samples, especially if up converting !!!!!
// REAL version
//////////////////////////////////////////////////////////////////////
int CFractResampler::Resample( int InLength, TYPEREAL Rate, TYPEREAL* pInBuf, TYPEREAL* pOutBuf)
{
int i;
int j;
int IntegerTime = (int)m_FloatTime; //integer input time accumulator
double dt = Rate; //output delta time as function of input sample time (input rate/output rate)
int outsamples = 0;
TYPEREAL acc;
//copy input samples into buffer starting at position SINC_PERIODS
j = SINC_PERIODS;
for(i=0; i<InLength; i++)
m_pInputBuf[j++].re = pInBuf[i];
//now calculate output samples by looping until end of input buffer
// is reached. The output position is incremented in fractional time
// of input sample time until all the possible input samples are
//processed.
while(IntegerTime < InLength )
{ //convolve sinc function with input samples where sinc
//function is centered at the output fractional time position
acc = 0.0;
for(i=1; i<=SINC_PERIODS; i++)
{
j = IntegerTime + i; //temp integer time position for convolution loop
int sindx = (int)(( (double)j - m_FloatTime) * (double)SINC_PERIOD_PTS );
acc += (m_pInputBuf[j].re * m_pSinc[sindx] );
}
pOutBuf[outsamples++] = acc;
m_FloatTime += dt;
IntegerTime = (int)m_FloatTime;
}
m_FloatTime -= (double)InLength; //move floating time position back for next call
//keeping leftover fraction
//need to copy last SINC_PERIODS input samples in buffer to beginning of buffer
// for FIR wrap around management. j points to last input sample processed
j = InLength;
for(i=0; i<SINC_PERIODS; i++)
m_pInputBuf[i].re = m_pInputBuf[j++].re;
return outsamples;
}
//////////////////////////////////////////////////////////////////////
// Resample InLength samples in pInBuf and place into pOutBuf
// using Rate = input rate / output rate
// !!!! Make sure pOutBuf from caller is large enough to hold all
// the generated samples, especially if up converting !!!!!
// short Integer version
//////////////////////////////////////////////////////////////////////
int CFractResampler::Resample( int InLength, TYPEREAL Rate, TYPEREAL* pInBuf, TYPEMONO16* pOutBuf, TYPEREAL gain)
{
int i;
int j;
int IntegerTime = (int)m_FloatTime; //integer input time accumulator
double dt = Rate; //output delta time as function of input sample time (input rate/output rate)
int outsamples = 0;
TYPEREAL acc;
//copy input samples into buffer starting at position SINC_PERIODS
j = SINC_PERIODS;
for(i=0; i<InLength; i++)
m_pInputBuf[j++].re = pInBuf[i];
//now calculate output samples by looping until end of input buffer
// is reached. The output position is incremented in fractional time
// of input sample time until all the possible input samples are
//processed.
while(IntegerTime < InLength )
{ //convolve sinc function with input samples where sinc
//function is centered at the output fractional time position
acc = 0.0;
for(i=1; i<=SINC_PERIODS; i++)
{
j = IntegerTime + i; //temp integer time position for convolution loop
int sindx = (int)(( (double)j - m_FloatTime) * (double)SINC_PERIOD_PTS );
acc += (m_pInputBuf[j].re * m_pSinc[sindx] );
}
TYPEREAL tmp;
tmp = (acc * gain);;
if(tmp > MAX_SOUNDCARDVAL)
tmp = MAX_SOUNDCARDVAL;
if(tmp < -MAX_SOUNDCARDVAL)
tmp = -MAX_SOUNDCARDVAL;
pOutBuf[outsamples++] = (TYPEMONO16)tmp;
m_FloatTime += dt;
IntegerTime = (int)m_FloatTime;
}
m_FloatTime -= (double)InLength; //move floating time position back for next call
//keeping leftover fraction
//need to copy last SINC_PERIODS input samples in buffer to beginning of buffer
// for FIR wrap around management. j points to last input sample processed
j = InLength;
for(i=0; i<SINC_PERIODS; i++)
m_pInputBuf[i].re = m_pInputBuf[j++].re;
return outsamples;
}
+35
View File
@@ -0,0 +1,35 @@
//////////////////////////////////////////////////////////////////////
// fractresampler.h: interface for the CFractResampler class.
//
// This class implements a fractional resampler that can be used to
//convert between different sample rates
//
// History:
// 2010-09-15 Initial creation MSW
// 2011-03-27 Initial release
//////////////////////////////////////////////////////////////////////
#ifndef FRACTRESAMPLER_H
#define FRACTRESAMPLER_H
#include "datatypes.h"
class CFractResampler
{
public:
CFractResampler();
virtual ~CFractResampler();
void Init(int MaxInputSize);
//overloaded functions for processing different data types
int Resample( int InLength, TYPEREAL Rate, TYPEREAL* pInBuf, TYPEREAL* pOutBuf);
int Resample( int InLength, TYPEREAL Rate, TYPECPX* pInBuf, TYPECPX* pOutBuf);
int Resample( int InLength, TYPEREAL Rate, TYPEREAL* pInBuf, TYPEMONO16* pOutBuf, TYPEREAL gain);
int Resample( int InLength, TYPEREAL Rate, TYPECPX* pInBuf, TYPESTEREO16* pOutBuf, TYPEREAL gain);
private:
TYPEREAL m_FloatTime; //floating pt output time accumulator
TYPEREAL* m_pSinc; //ptr to sinc table
TYPECPX* m_pInputBuf; //internal working input sample buffer
};
#endif // FRACTRESAMPLER_H
+583
View File
@@ -0,0 +1,583 @@
/////////////////////////////////////////////////////////////////////
// soundout.cpp: implementation of the CSoundOut class.
//
// This class implements a class to output data to a soundcard.
// A fractional resampler is used to convert the users input rate to
// the sound card rate and also perform frequency lock between the
// two clock domains.
//
// History:
// 2010-09-15 Initial creation MSW
// 2011-03-27 Initial release
// 2011-08-07 Changed some debug output
// 2015-01-24 RRK, Minor mods, adding to cudaSDR
/////////////////////////////////////////////////////////////////////
//==========================================================================================
// + + + This Software is released under the "Simplified BSD License" + + +
//Copyright 2010 Moe Wheatley. All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those of the
//authors and should not be interpreted as representing official policies, either expressed
//or implied, of Moe Wheatley.
//==========================================================================================
#include "soundout.h"
#include <QDebug>
#include <math.h>
#define SOUNDCARD_RATE 48000 //output soundcard sample rate
//#define SOUNDCARD_RATE 44100
#define FILTERQLEVEL_ALPHA 0.001
#define P_GAIN 2.38e-7 //Proportional gain
#define TRUE 1
#define FALSE 0
#define TEST_ERROR 1.0
//#define TEST_ERROR 1.001 //use to force fixed sample rate error for testing
//#define TEST_ERROR 0.999
/////////////////////////////////////////////////////////////////////
// constructor/destructor
/////////////////////////////////////////////////////////////////////
CSoundOut::CSoundOut(QObject *parent) :
QThread(parent)
{
m_pParent = parent;
m_pAudioOutput = NULL;
m_pOutput = NULL;
m_ThreadQuit = true;
m_UserDataRate = SOUNDCARD_RATE;
m_OutRatio = 1.0;
//RRK m_OutAudioFormat.setFrequency(SOUNDCARD_RATE);
m_OutAudioFormat.setSampleRate(SOUNDCARD_RATE);
m_OutResampler.Init(8192);
m_RateCorrection = 0.0;
m_Gain = 1.0;
m_Startup = true;
m_BlockingMode = false;
}
CSoundOut::~CSoundOut()
{
Stop();
}
void GetAlsaMasterVolume(long *volume)
{
long min, max;
snd_mixer_t *handle;
snd_mixer_selem_id_t *sid;
const char *card = "default";
const char *selem_name = "Master";
snd_mixer_open(&handle, 0);
snd_mixer_attach(handle, card);
snd_mixer_selem_register(handle, NULL, NULL);
snd_mixer_load(handle);
snd_mixer_selem_id_alloca(&sid);
snd_mixer_selem_id_set_index(sid, 0);
snd_mixer_selem_id_set_name(sid, selem_name);
snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume);
snd_mixer_close(handle);
}
void SetAlsaMasterVolume(long volume)
{
long min, max;
snd_mixer_t *handle;
snd_mixer_selem_id_t *sid;
const char *card = "default";
const char *selem_name = "Master";
snd_mixer_open(&handle, 0);
snd_mixer_attach(handle, card);
snd_mixer_selem_register(handle, NULL, NULL);
snd_mixer_load(handle);
snd_mixer_selem_id_alloca(&sid);
snd_mixer_selem_id_set_index(sid, 0);
snd_mixer_selem_id_set_name(sid, selem_name);
snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
snd_mixer_selem_set_playback_volume_all(elem, volume * max / 100);
snd_mixer_close(handle);
}
/////////////////////////////////////////////////////////////////////
// Starts up soundcard output thread using soundcard at list OutDevIndx
/////////////////////////////////////////////////////////////////////
bool CSoundOut::Start(int OutDevIndx, bool StereoOut, double UsrDataRate, bool BlockingMode)
{
QAudioDeviceInfo DeviceInfo;
long mvolume;
m_StereoOut = StereoOut;
m_BlockingMode = BlockingMode;
//Get required soundcard from list
m_OutDevices = DeviceInfo.availableDevices(QAudio::AudioOutput);
if (-1 == OutDevIndx) GetAlsaMasterVolume(&mvolume);
qDebug()<<"Soundcard volume" << mvolume;
if (-1 == OutDevIndx) m_OutDeviceInfo = QAudioDeviceInfo::defaultOutputDevice();
else m_OutDeviceInfo = m_OutDevices.at(OutDevIndx);
#if 0 //RRK get a list of audio devices and the default
foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) {
qDebug() << "l:" << deviceInfo.deviceName();
}
QAudioDeviceInfo info = QAudioDeviceInfo::defaultOutputDevice();
qDebug() << "res:" << info.deviceName();
#endif
//Setup fixed format for sound ouput
m_OutAudioFormat.setCodec("audio/pcm");
//m_OutAudioFormat.setFrequency(SOUNDCARD_RATE);
m_OutAudioFormat.setSampleRate(SOUNDCARD_RATE);
m_OutAudioFormat.setSampleSize(16);
m_OutAudioFormat.setSampleType(QAudioFormat::SignedInt);
m_OutAudioFormat.setByteOrder(QAudioFormat::LittleEndian);
if(m_StereoOut)
//RRK m_OutAudioFormat.setChannels(2);
m_OutAudioFormat.setChannelCount(2);
else
m_OutAudioFormat.setChannelCount(1);
m_pAudioOutput = new QAudioOutput(m_OutDeviceInfo, m_OutAudioFormat, this);
if(!m_pAudioOutput)
{
qDebug()<<"Soundcard output error";
return false;
}
if(QAudio::NoError == m_pAudioOutput->error() )
{
//initialize the data queue variables
m_UserDataRate = 1; //force user data rate to be changed
ChangeUserDataRate(UsrDataRate);
m_pOutput = m_pAudioOutput->start(); //start QT AudioOutput
//RRK workaround for default, for some reason choosing default
//sets the master volume to max!
if (-1 == OutDevIndx) SetAlsaMasterVolume(50);
//determine how long to sleep between low level reads based on samplerate and period size
m_BlockTime = ( 250*m_pAudioOutput->periodSize() )/
( SOUNDCARD_RATE*m_OutAudioFormat.channelCount() );
//RRK ( SOUNDCARD_RATE*m_OutAudioFormat.channels() );
//qDebug()<<"periodSize "<<m_pAudioOutput->periodSize();
//qDebug()<<"BlockTime "<<m_BlockTime;
m_ThreadQuit = FALSE;
start(QThread::HighestPriority); //start worker thread and set its priority
// start(QThread::TimeCriticalPriority); //start worker thread and set its priority
return true;
}
else
{
qDebug()<<"Soundcard output error";
return false;
}
}
/////////////////////////////////////////////////////////////////////
// Closes down sound card output thread
/////////////////////////////////////////////////////////////////////
void CSoundOut::Stop()
{
if(!m_ThreadQuit)
{
m_ThreadQuit = TRUE;
m_pAudioOutput->stop();
wait(500);
}
if(NULL != m_pAudioOutput)
{
delete m_pAudioOutput;
m_pAudioOutput = NULL;
}
}
/////////////////////////////////////////////////////////////////////
// Sets/changes user data input rate
/////////////////////////////////////////////////////////////////////
void CSoundOut::ChangeUserDataRate(double UsrDataRate)
{
if(m_UserDataRate != UsrDataRate)
{
m_UserDataRate = UsrDataRate;
for(int i=0; i<OUTQSIZE ;i++) //zero buffer for data output
{
m_OutQueueMono[i] = 0;
m_OutQueueStereo[i].re = 0;
m_OutQueueStereo[i].im = 0;
}
m_OutRatio = m_UserDataRate/m_OutAudioFormat.sampleRate();
m_OutQHead = 0;
m_OutQTail = 0;
m_OutQLevel = 0;
m_AveOutQLevel = OUTQSIZE/2;
m_Startup = true;
}
qDebug()<<"SoundOutRatio Rate"<<(1.0/m_OutRatio) << m_UserDataRate;
}
/////////////////////////////////////////////////////////////////////
// Sets/changes volume control gain 0 <= vol <= 99
//range scales to attenuation(gain) of -50dB to 0dB
/////////////////////////////////////////////////////////////////////
void CSoundOut::SetVolume(qint32 vol)
{
m_Mutex.lock();
if(0==vol) //if zero make infinite attenuation
m_Gain = 0.0;
else if(vol<=99)
m_Gain = pow(10.0, ((double)vol-99.0)/39.2 );
m_Mutex.unlock();
//qDebug()<<"Volume "<<vol << m_Gain;
}
////////////////////////////////////////////////////////////////
//Called by application to put COMPLEX input into
// STEREO 2 channel soundcard output queue
////////////////////////////////////////////////////////////////
void CSoundOut::PutOutQueue(int numsamples, TYPECPX* pData )
{
TYPESTEREO16 RData[OUTQSIZE]; //buffer to hold resampled data
int i;
bool overflow = false;
if(( 0==numsamples) || m_ThreadQuit)
return;
//Call Resampler to match sample rates between radio and sound card
numsamples = m_OutResampler.Resample(numsamples, TEST_ERROR*m_OutRatio *(1.0+m_RateCorrection),
pData, RData, m_Gain);
if(m_BlockingMode) //if in Blocking Mode then wait for soundcard queue to be available
{
for( i=0; i<numsamples; i++)
{
while( ((m_OutQHead+1) & (OUTQSIZE-1)) == m_OutQTail)
msleep(10); //wait if Queue is full
m_OutQueueStereo[m_OutQHead++] = RData[i];
m_OutQHead &= (OUTQSIZE-1);
m_OutQLevel++;
}
}
else
{ //here if non-blocking mode so need to deal with possible over/under flow
m_Mutex.lock();
for( i=0; i<numsamples; i++)
{
m_OutQueueStereo[m_OutQHead++] = RData[i];
m_OutQHead &= (OUTQSIZE-1);
m_OutQLevel++;
if(m_OutQHead==m_OutQTail) //if full
{ //remove 1/4 a queue's worth of data
m_OutQTail += OUTQSIZE/4;
m_OutQTail &= (OUTQSIZE-1);
m_OutQLevel -= OUTQSIZE/4;
i = numsamples; //force break out of for loop
overflow = true;
}
}
if(overflow)
{
qDebug()<<"Snd Overflow";
m_AveOutQLevel = m_OutQLevel;
}
//calculate average Queue fill level
m_AveOutQLevel = (1.0-FILTERQLEVEL_ALPHA)*m_AveOutQLevel + FILTERQLEVEL_ALPHA*(double)m_OutQLevel;
m_Mutex.unlock();
}
}
////////////////////////////////////////////////////////////////
//Called by application to put REAL soundcard output samples
//into MONO soundcard queue
////////////////////////////////////////////////////////////////
void CSoundOut::PutOutQueue(int numsamples, TYPEREAL* pData )
{
TYPEMONO16 RData[OUTQSIZE]; //buffer to hold resampled data
int i;
bool overflow = false;
if(( 0==numsamples) || m_ThreadQuit)
return;
//Call Resampler to match sample rates between radio and sound card
numsamples = m_OutResampler.Resample(numsamples, TEST_ERROR*m_OutRatio *(1.0+m_RateCorrection),
pData, RData, m_Gain);
if(m_BlockingMode) //if in Blocking Mode then wait for soundcard queue to be available
{
for( i=0; i<numsamples; i++)
{
while( ((m_OutQHead+1) & (OUTQSIZE-1)) == m_OutQTail)
msleep(10); //wait if Queue is full
m_OutQueueMono[m_OutQHead++] = RData[i];
m_OutQHead &= (OUTQSIZE-1);
m_OutQLevel++;
}
}
else
{ //here if non-blocking mode so need to deal with possible over/under flow
m_Mutex.lock();
for( i=0; i<numsamples; i++)
{
m_OutQueueMono[m_OutQHead++] = RData[i];
m_OutQHead &= (OUTQSIZE-1);
m_OutQLevel++;
if(m_OutQHead==m_OutQTail) //if full
{ //remove 1/4 a queue's worth of data
m_OutQTail += OUTQSIZE/4;
m_OutQTail &= (OUTQSIZE-1);
m_OutQLevel -= OUTQSIZE/4;
i = numsamples; //force break out of for loop
overflow = true;
}
}
if(overflow)
{
qDebug()<<"Snd Overflow";
m_AveOutQLevel = m_OutQLevel;
}
//calculate average Queue fill level
m_AveOutQLevel = (1.0-FILTERQLEVEL_ALPHA)*m_AveOutQLevel + FILTERQLEVEL_ALPHA*(double)m_OutQLevel;
m_Mutex.unlock();
}
}
////////////////////////////////////////////////////////////////
//Called by CSoundOut worker thread to get new samples from queue
// This routine is called from a worker thread so must be careful.
// MONO version
////////////////////////////////////////////////////////////////
void CSoundOut::GetOutQueue(int numsamples, TYPEMONO16* pData )
{
int i;
bool underflow = false;
m_Mutex.lock();
if(m_Startup)
{ //if no data in queue yet just stuff in silence until something is put in queue
for( i=0; i<numsamples; i++)
pData[i] = 0;
if(m_OutQLevel>OUTQSIZE/2)
{
m_Startup = false;
m_RateUpdateCount = -5*SOUNDCARD_RATE; //delay first error update to let settle
m_PpmError = 0;
m_AveOutQLevel = m_OutQLevel;
m_UpdateToggle = true;
}
else
{
m_Mutex.unlock();
return;
}
}
for( i=0; i<numsamples; i++)
{
if(m_OutQHead!=m_OutQTail)
{
pData[i] = m_OutQueueMono[m_OutQTail++];
m_OutQTail &= (OUTQSIZE-1);
m_OutQLevel--;
}
else //queue went empty
{ //backup queue ptr and use previous data in queue
m_OutQTail -= (OUTQSIZE/4);
m_OutQTail &= (OUTQSIZE-1);
pData[i] = m_OutQueueMono[m_OutQTail];
m_OutQLevel += (OUTQSIZE/4);
underflow = true;
}
}
if(m_BlockingMode)
{ //if in blocking mode just return
m_Mutex.unlock();
return;
}
//calculate average Queue fill level
m_AveOutQLevel = (1.0-FILTERQLEVEL_ALPHA)*m_AveOutQLevel + FILTERQLEVEL_ALPHA*m_OutQLevel;
if(underflow)
{
qDebug()<<"Snd Underflow";
m_AveOutQLevel = m_OutQLevel;
}
// See if time to update rate error calculation routine
m_RateUpdateCount += numsamples;
if(m_RateUpdateCount >= SOUNDCARD_RATE) //every second
{
CalcError();
m_RateUpdateCount = 0;
}
m_Mutex.unlock();
}
////////////////////////////////////////////////////////////////
//Called by CSoundOut worker thread to get new samples from queue
// This routine is called from a worker thread so must be careful.
// STEREO version
////////////////////////////////////////////////////////////////
void CSoundOut::GetOutQueue(int numsamples, TYPESTEREO16* pData )
{
int i;
bool underflow = false;
m_Mutex.lock();
if(m_Startup)
{ //if no data in queue yet just stuff in silence until something is put in queue
for( i=0; i<numsamples; i++)
{
pData[i].re = 0;
pData[i].im = 0;
}
if(m_OutQLevel>OUTQSIZE/2)
{
m_Startup = false;
m_RateUpdateCount = -5*SOUNDCARD_RATE; //delay first error update to let settle
m_PpmError = 0;
m_AveOutQLevel = m_OutQLevel;
m_UpdateToggle = true;
}
else
{
m_Mutex.unlock();
return;
}
}
for( i=0; i<numsamples; i++)
{
if(m_OutQHead!=m_OutQTail)
{
pData[i] = m_OutQueueStereo[m_OutQTail++];
m_OutQTail &= (OUTQSIZE-1);
m_OutQLevel--;
}
else //queue went empty
{ //backup queue ptr and use previous data in queue
m_OutQTail -= (OUTQSIZE/4);
m_OutQTail &= (OUTQSIZE-1);
pData[i] = m_OutQueueStereo[m_OutQTail];
m_OutQLevel += (OUTQSIZE/4);
underflow = true;
}
}
if(m_BlockingMode)
{ //if in blocking mode just return
m_Mutex.unlock();
return;
}
//calculate average Queue fill level
m_AveOutQLevel = (1.0-FILTERQLEVEL_ALPHA)*m_AveOutQLevel + FILTERQLEVEL_ALPHA*m_OutQLevel;
if(underflow)
{
qDebug()<<"Snd Underflow";
m_AveOutQLevel = m_OutQLevel;
}
// See if time to update rate error calculation routine
m_RateUpdateCount += numsamples;
if(m_RateUpdateCount >= SOUNDCARD_RATE) //every second
{
CalcError();
m_RateUpdateCount = 0;
}
m_Mutex.unlock();
}
////////////////////////////////////////////////////////////////
// Called alternately from the Get routines to update the
// error correction process
////////////////////////////////////////////////////////////////
void CSoundOut::CalcError()
{
double error;
error = (double)(m_AveOutQLevel - OUTQSIZE/2 ); //neg==level is too low pos == level is to high
error = error * P_GAIN;
m_RateCorrection = error;
m_PpmError = (int)( m_RateCorrection*1e6 );
if( abs(m_PpmError) > 500)
{
// qDebug()<<"SoundOut "<<m_PpmError << m_AveOutQLevel;
}
}
//////////////////////////////////////////////////////////////////////////
// Worker thread polls QAudioOutput device to see if there is room
// to put more data into it and then calls GetOutQueue(..) to get more data.
// This thread was needed because the normal "pull" mechanism of Qt does
// not work very well since it depends on the main process signal-slot event
// queue and you get dropouts if the GUI gets busy.
//////////////////////////////////////////////////////////////////////////
void CSoundOut::run()
{
while(!m_ThreadQuit ) //execute loop until quit flag set
{
if( (QAudio::IdleState == m_pAudioOutput->state() ) ||
(QAudio::ActiveState == m_pAudioOutput->state() ) )
{ //Process sound data while soundcard is active and no errors
unsigned int len = m_pAudioOutput->bytesFree(); //in bytes
if( len>0 )
{
//limit size to SOUND_WRITEBUFSIZE
if(len > SOUND_WRITEBUFSIZE)
len = SOUND_WRITEBUFSIZE;
if(m_StereoOut)
{
len &= ~(0x03); //keep on 4 byte chunks
GetOutQueue( len/4, (TYPESTEREO16*)m_pData );
}
else
{
len &= ~(0x01); //keep on 2 byte chunks
GetOutQueue( len/2, (TYPEMONO16*)m_pData );
}
m_pOutput->write((char*)m_pData,len);
}
else //no room in sound card output buffer so wait
{ //not good but no other wait or blocking mechanism available
msleep(m_BlockTime);
}
}
else
{ //bail out if error occurs
qDebug()<<"SoundOut Error";
#if 0 //RRK
if(m_pParent)
((CSdrInterface*)m_pParent)->SendIOStatus(CSdrInterface::ERROR);
#endif
m_ThreadQuit = true;
}
}
qDebug()<<"sound thread exit";
}
+76
View File
@@ -0,0 +1,76 @@
//////////////////////////////////////////////////////////////////////
// soundout.h: interface for the CSoundOut class.
//
// History:
// 2010-09-15 Initial creation MSW
// 2011-03-27 Initial release
/////////////////////////////////////////////////////////////////////
#ifndef SOUNDOUT_H
#define SOUNDOUT_H
#include <QObject>
#include <QThread>
#include <QList>
#include <QMutex>
#include <QAudioOutput>
#include "fractresampler.h"
#include <alsa/asoundlib.h>
#include <alsa/mixer.h>
#define OUTQSIZE 16384 //max samples (keep power of 2 for ptr wrap around)
#define SOUND_WRITEBUFSIZE 8192
class CSoundOut : public QThread
{
Q_OBJECT
public:
explicit CSoundOut(QObject *parent = 0);
virtual ~CSoundOut();
//Exposed functions
bool Start(int OutDevIndx, bool StereoOut, double UsrDataRate, bool BlockingMode); //starts soundcard output
void Stop(); //stops soundcard output
void PutOutQueue(int numsamples, TYPEREAL* pData );
void PutOutQueue(int numsamples, TYPECPX* pData );
void ChangeUserDataRate(double UsrDataRate);
void SetVolume(qint32 vol);
int GetRateError(){return (int)m_PpmError;}
protected:
void run(); //implements worker thread loop
int m_BlockTime;
private:
void GetOutQueue(int numsamples, TYPEMONO16* pData );
void GetOutQueue(int numsamples, TYPESTEREO16* pData );
void CalcError();
QList<QAudioDeviceInfo> m_OutDevices;
QAudioDeviceInfo m_OutDeviceInfo;
QAudioFormat m_OutAudioFormat;
QAudioOutput* m_pAudioOutput;
QIODevice* m_pOutput; // ptr to internal soundout IODevice
QObject* m_pParent;
QMutex m_Mutex;
CFractResampler m_OutResampler;
TYPEMONO16 m_OutQueueMono[OUTQSIZE];
TYPESTEREO16 m_OutQueueStereo[OUTQSIZE];
bool m_BlockingMode;
bool m_ThreadQuit;
bool m_Startup;
bool m_StereoOut;
bool m_UpdateToggle;
quint32 m_OutQHead;
quint32 m_OutQTail;
char m_pData[SOUND_WRITEBUFSIZE];
int m_RateUpdateCount;
int m_OutQLevel;
int m_PpmError;
double m_Gain;
double m_UserDataRate;
double m_OutRatio;
double m_RateCorrection;
double m_AveOutQLevel;
};
#endif // SOUNDOUT_H
File diff suppressed because it is too large Load Diff
+345
View File
@@ -0,0 +1,345 @@
/**
* @file cusdr_oglDisplayPanel.h
* @brief display panel header file for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-02-22
*/
/*
* Copyright 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_QGL_DISPLAYPANEL_H
#define _CUSDR_QGL_DISPLAYPANEL_H
#include "cusdr_oglUtils.h"
#include "cusdr_oglInfo.h"
#include "cusdr_settings.h"
#include "cusdr_fonts.h"
#include "cusdr_oglText.h"
//#include <QPixmap>
//#include <QImage>
//#include <QFontMetrics>
#include <QWheelEvent>
//#include <QQueue>
//#include <QDebug>
//#include <QMutex>
//#include <QtOpenGL/QGLWidget>
#ifdef LOG_DISPLAYPANEL
# define DISPLAYPANEL_DEBUG qDebug().nospace() << "DisplayPanel::\t"
#else
# define DISPLAYPANEL_DEBUG nullDebug()
#endif
class OGLDisplayPanel : public QGLWidget {
Q_OBJECT
public:
OGLDisplayPanel(QWidget *parent = 0);
~OGLDisplayPanel();
public slots:
QSize minimumSizeHint() const;
QSize sizeHint() const;
void setSampleRate(QObject *sender, int value);
void setFrequency(QObject *sender, int mode, int rx, long freq);
protected:
void initializeGL();
void resizeGL(int iWidth, int iHeight);
void paintGL();
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent * event );
void keyPressEvent(QKeyEvent* event);
void closeEvent(QCloseEvent *event);
void showEvent(QShowEvent *event);
void timerEvent(QTimerEvent *);
private:
Settings* set;
QSDR::_ServerMode m_serverMode;
QSDR::_HWInterfaceMode m_hwInterface;
QSDR::_DataEngineState m_dataEngineState;
QGLFramebufferObject *m_smeterFBO;
QList<TFrequency> m_frequencyList;
TPanadapterColors m_colors;
TScale m_dBmScale;
CFonts *fonts;
TFonts m_fonts;
QMutex m_mutex;
OGLText *m_oglTextTiny;
OGLText *m_oglTextSmall;
OGLText *m_oglTextSmallItalic;
OGLText *m_oglTextNormal;
OGLText *m_oglTextBig;
OGLText *m_oglTextBigItalic;
OGLText *m_oglTextFreq1;
OGLText *m_oglTextFreq2;
OGLText *m_oglTextImpact;
QRect m_rect;
QRect m_rxRect;
QRect m_smeterRect;
QString m_src10mhz;
QString m_src122_88mhz;
QString m_mercuryVersion;
QString m_penelopeVersion;
QString m_pennylaneVersion;
QString m_hermesVersion;
QString m_excaliburVersion;
QString m_metisVersion;
QString m_alexVersion;
QString m_mercuryString;
QString m_penelopeString;
QString m_pennylaneString;
QString m_excaliburString;
QString m_metisString;
QString m_alexString;
QString m_hermesString;
QString m_hermesStepAttnString;
QString m_SYNCString;
QString m_ADCString;
QString m_PacketLossString;
QString m_sendIQString;
QString m_recvAudioString;
QString m_AttnString;
QString m_ditherString;
QString m_randomString;
QString m_sampleRateString;
QString m_modusString;
QString m_10MHzString;
QString m_12288MHzString;
QString m_sMeterNumValueString;
QString m_bandText;
QRegion m_freg1;
QRegion m_freg10;
QRegion m_freg100;
QRegion m_freg1000;
QRegion m_freg10000;
QRegion m_freg100000;
QRegion m_freg1000000;
QRegion m_freg10000000;
QColor m_digitColor;
QColor m_bkgColor1;
QColor m_bkgColor2;
QColor m_activeTextColor;
QColor m_inactiveTextColor;
QColor m_textBackgroundColor;
QTime m_sMeterTimer;
QTime m_sMeterMaxTimer;
QTime m_sMeterMinTimer;
QTime m_sMeterDisplayTime;
enum Region {
upperRegion,
lowerRegion,
rxRegion,
smeterRegion,
hpsdrRegion,
elsewhere,
out
};
enum FreqDigit {
Freq1,
Freq10,
Freq100,
Freq1000,
Freq10000,
Freq100000,
Freq1000000,
Freq10000000,
None
};
GLuint m_sMeterTex;
bool m_mercury;
bool m_penelope;
bool m_pennylane;
bool m_excalibur;
bool m_metis;
bool m_alex;
bool m_smeterUpdate;
bool m_smeterRenew;
bool m_SMeterA;
bool m_sMeterAvg;
long m_oldFreq;
int m_height;
int m_sMeterWidth;
int m_sMeterOffset;
int m_rxRectWidth;
int m_lowerRectY;
int m_upperRectY;
int m_digitPosition;
int m_syncStatus;
int m_adcStatus;
int m_packetLossStatus;
int m_sendIQStatus;
int m_recvAudioStatus;
int m_receivers;
int m_sample_rate;
int m_mercuryAttenuator;
int m_dither;
int m_random;
int m_currentReceiver;
int m_pointStringWidth;
int m_blankWidth;
int m_blankWidthf;
int m_blankWidthf1;
int m_blankWidthf2;
int m_fUnitStringWidth;
int m_blankHeight;
int m_freqStringLeftPos;
int m_versionStringWidth;
int m_syncWidth;
int m_adcWidth;
int m_packetLossWidth;
int m_sendIQWidth;
int m_recvAudioWidth;
int m_metisStringWidth;
int m_mercuryStringWidth;
int m_penelopeStringWidth;
int m_pennylaneStringWidth;
int m_hermesStringWidth;
int m_hermesStepAttnStringWidth;
int m_alexStringWidth;
int m_excaliburStringWidth;
int m_AttnWidth;
int m_ditherWidth;
int m_randomWidth;
int m_sampleRateWidth;
int m_modusWidth;
int m_10MHzWidth;
int m_sMeterDeform;
int m_12288MHzWidth;
int m_freqDigitsPosY;
int m_sMeterPosY;
int m_sMeterHoldTime;
int m_sMeterPrevHoldTimeMax;
int m_sMeterPrevHoldTimeMin;
int m_sMeterMeanValueCnt;
qreal m_mouseWheelFreqStep;
qreal m_dBmPanMin;
qreal m_dBmPanMax;
qreal m_unit;
float m_smeterVertices;
float m_sMeterValue;
float m_sMeterMeanValue;
float m_sMeterOrgValue;
float m_sMeterMaxValueA;
float m_sMeterMinValueA;
float m_sMeterMaxValueB;
float m_sMeterMinValueB;
//*************************
void setupConnections();
void setupTextstrings();
void paintUpperRegion();
void paintLowerRegion();
void paintRxRegion();
void paintSMeter();
void renderSMeterScale();
void renderSMeterA();
void renderSMeterB();
void getSelectedDigit(QPoint p);
private slots:
void systemStateChanged(
QObject *sender,
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state);
void setupDisplayRegions(QSize size);
void setSyncStatus(int value);
void setADCStatus(int value);
void setPacketLossStatus(int value);
void setSendIQStatus(int value);
void setRecvAudioStatus(int value);
void setCurrentReceiver(QObject *sender, int value);
void setMercuryAttenuator(QObject* sender, HamBand band, int value);
void setReceivers(QObject *sender, int value);
void setDither(QObject *sender, int value);
void setRandom(QObject *sender, int value);
void set10mhzSource(QObject *sender, int value);
void set122_88mhzSource(QObject *sender, int value);
void setMercuryPresence(bool value);
void setPenelopePresence(bool value);
void setPennylanePresence(bool value);
void setAlexPresence(bool value);
void setExcaliburPresence(bool value);
void setHermesVersion(int value);
void setMercuryVersion(int value);
void setPenelopeVersion(int value);
void setPennylaneVersion(int value);
void setMetisVersion(int value);
void setExcaliburVersion(QObject *sender, int value);
void setAlexVersion(QObject *sender, int value);
void setMouseWheelFreqStep(QObject *sender, int rx, qreal value);
void setSMeterValue(int rx, float value);
void setSMeterHoldTime(int value);
void updateSyncStatus();
void updateADCStatus();
void updatePacketLossStatus();
signals:
void showEvent(QObject *sender);
void closeEvent(QObject *sender);
void messageEvent(QString msg);
};
#endif // _CUSDR_QGL_DISPLAYPANEL_H
File diff suppressed because it is too large Load Diff
+318
View File
@@ -0,0 +1,318 @@
/**
* @file cusdr_oglDistancePanel.h
* @brief distance panel header file for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-02-14
*/
/*
* Copyright 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_QGL_DISTANCEPANEL_H
#define _CUSDR_QGL_DISTANCEPANEL_H
#include "cusdr_oglUtils.h"
#include "cusdr_oglInfo.h"
#include "cusdr_settings.h"
#include "cusdr_fonts.h"
#include "cusdr_oglText.h"
//#include <QtOpenGL/QGLWidget>
//#include <QImage>
//#include <QFontMetrics>
#include <QWheelEvent>
//#include <QQueue>
//#include <QDebug>
class QGLDistancePanel : public QGLWidget {
Q_OBJECT
public:
QGLDistancePanel(QWidget *parent = 0);
~QGLDistancePanel();
public slots:
//QSize minimumSizeHint() const;
QSize sizeHint() const;
void setSpectrumBuffer(const float *buffer);
void distanceSpectrumBufferChanged(int sampleRate, qint64 length, const float *buffer);
void setFrequency(QObject *sender, bool value, long freq);
protected:
void initializeGL();
void resizeGL(int iWidth, int iHeight);
void paintGL();
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent * event );
void keyPressEvent(QKeyEvent* event);
void closeEvent(QCloseEvent *event);
void showEvent(QShowEvent *event);
void timerEvent(QTimerEvent *);
private:
Settings* set;
QSDR::_ServerMode m_serverMode;
QSDR::_HWInterfaceMode m_hwInterface;
QSDR::_DataEngineState m_dataEngineState;
PanGraphicsMode m_panMode;
QTime m_displayTime;
QTime m_resizeTime;
QTime freqChangeTimer;
CFonts *fonts;
TScale m_frequencyScale;
TScale m_dBmScale;
TScale m_distanceScale;
TScale m_dBmDistScale;
TFonts m_fonts;
QList<TReceiver> m_rxDataList;
QVector<qreal> m_panadapterBins;
QQueue<QVector<float> > specAv_queue;
QGLFramebufferObject* m_frequencyScaleFBO;
QGLFramebufferObject* m_dBmScaleFBO;
QGLFramebufferObject* m_panadapterGridFBO;
QGLFramebufferObject* m_textureFBO;
QRect m_panRect;
QRect m_dBmScalePanRect;
QRect m_freqScalePanRect;
QRect m_distancePanRect;
QRect m_freqScaleDistancePanRect;
QRect m_dBmScaleDistancePanRect;
QRect m_filterRect;
QRect m_freqScaleWideBandPanRect;
QRect m_dBmScaleWideBandPanRect;
QRect m_distanceSpectrumRect;
OGLText* m_oglTextTiny;
OGLText* m_oglTextSmall;
OGLText* m_oglTextNormal;
QPoint m_mousePos;
QPoint m_oldMousePos;
QPoint m_mouseLastPos;
QPoint m_mouseDownPos;
QPoint m_rulerMouseDownPos;
enum Region {
freqScalePanadapterRegion,
freqScaleDistancePanRegion,
panadapterRegion,
dBmScalePanadapterRegion,
dBmScaleDistancePanRegion,
distancePanRegion,
filterRegion,
filterRegionLow,
filterRegionHigh,
elsewhere,
out
};
long m_frequency;
long m_oldFreq;
float m_spectrumBuffer[4*BUFFER_SIZE];
float m_distanceSpectrumBuffer[16*BUFFER_SIZE];
float m_scale;
float m_tmpBuf[SAMPLE_BUFFER_SIZE];
float m_avgBuf[SAMPLE_BUFFER_SIZE];
float m_distMax;
QMutex mutex;
QMutex spectrumBufferMutex;
QMutex distanceSpectrumBufferMutex;
int m_oldWidth;
int m_oldPanRectHeight;
int m_smallFontHeight;
int m_cnt;
int m_specAveragingCnt;
int m_freqRulerDisplayWidth;
int m_displayTop;
int m_dBmPanLogGain;
int m_panSpectrumMinimumHeight;
unsigned int timer;
GLint m_panRectWidth;
GLint m_panSpectrumBinsLength;
bool m_spectrumUpdate;
bool m_showZerodBmLine;
bool m_spectrumVertexColorUpdate;
bool m_dBmScalePanadapterRenew;
bool m_dBmScalePanadapterUpdate;
bool m_freqScalePanadapterRenew;
bool m_freqScalePanadapterUpdate;
bool m_panGridRenew;
bool m_panGridUpdate;
bool m_distRulerUpdate;
bool m_newWidebandPanFreqRuler;
bool m_spectrumColorsChanged;
bool m_showChirpFFT;
bool m_spectrumAveraging;
bool m_spectrumAveragingOld;
bool m_crossHairCursor;
bool m_panGrid;
float m_freqRulerPosition;
float m_wideBandZoomFactor;
double m_distRulerKilometerSpan;
double m_distRulerDisplayDelta;
double m_distRulerDisplayDeltaStep;
double m_distRulerMaxDist;
qreal m_panFrequencyScale;
qreal m_freqScaleZoomFactor;
qreal m_distScaleZoomFactor;
qreal m_dBmPanMin;
qreal m_dBmPanMax;
qreal m_dBmPanDelta;
qreal m_panScale;
qreal m_scaleMult;
qreal m_scaleMultOld;
qreal m_filterLowerFrequency;
qreal m_filterUpperFrequency;
qreal m_mouseDownFilterFrequencyLo;
qreal m_mouseDownFilterFrequencyHi;
qreal m_dBmDistScaleMin;
qreal m_dBmDistScaleMax;
qreal m_dBmDistMin;
qreal m_dBmDistMax;
qreal m_dBmDistDelta;
int m_mouseRegion;
int m_oldMouseRegion;
int m_snapMouse;
int m_panDisplayMode;
int m_sampleRate;
int m_downRate;
double m_kilometersPerGate;
qint64 m_chirpBufferLength;
GLfloat m_bkgRed;
GLfloat m_bkgGreen;
GLfloat m_bkgBlue;
GLfloat m_red;
GLfloat m_green;
GLfloat m_blue;
GLfloat m_redF;
GLfloat m_greenF;
GLfloat m_blueF;
GLfloat m_redST;
GLfloat m_greenST;
GLfloat m_blueST;
GLfloat m_redSB;
GLfloat m_greenSB;
GLfloat m_blueSB;
GLfloat m_redD;
GLfloat m_greenD;
GLfloat m_blueD;
//******************************************************************
//QColor getWaterfallColorAtPixel(qreal value);
void saveGLState();
void restoreGLState();
// drawing
void paintReceiverDisplay();
void paintChirpWSPRDisplay();
void drawPanadapter();
void drawPanVerticalScale();
void drawPanHorizontalScale();
void drawPanadapterGrid();
void drawPanFilter();
void drawCrossHair();
void drawDistanceSpectrum();
void drawDistHorizontalScale();
void drawDistVerticalScale();
void renderPanVerticalScale();
void renderPanHorizontalScale();
void renderPanadapterGrid();
void computeDisplayBins(const float *panBuffer);
private slots:
void systemStateChanged(
QObject* sender,
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state);
void graphicModeChanged(
QObject* sender,
int rx,
PanGraphicsMode panMode,
WaterfallColorMode waterfallColorMode);
void setupConnections();
void setFilterFrequencies(QObject *sender, int rx, qreal lo, qreal hi);
void setupDisplayRegions(QSize size);
void setDistanceSpectrumBuffer(int sampleRate, qint64 length, const float *buffer);
void setSpectrumAveraging(bool value);
void setSpectrumAveragingCnt(int value);
void setPanGridStatus(bool value);
void setPanadapterColors();
void getRegion(QPoint p);
void freqRulerPositionChanged(float pos, int rx);
void sampleRateChanged(QObject *sender, int value);
void setChirpFFTShow(bool value);
signals:
void showEvent(QObject* sender);
void closeEvent(QObject* sender);
void messageEvent(QString msg);
void coordChanged(int x,int y);
};
#endif // _CUSDR_QGL_DISTANCEPANEL_H
+180
View File
@@ -0,0 +1,180 @@
/**
* @file cusdr_oglInfo.cpp
* @brief OpenGL info class for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-11-10
*/
/*
* adapted from glInfo.h of Song Ho Ahn (song.ahn@gmail.com)
* Copyright (c) 2005 Song Ho Ahn
*
* (C) 2011 adapted for cuSDR by Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//#include <GL/gl.h>
#include "cusdr_oglUtils.h"
#include "cusdr_oglInfo.h"
QOpenGLInfo::QOpenGLInfo(QObject *parent)
: QObject(parent)
, set(Settings::instance())
{
m_glInfo.redBits = 0;
m_glInfo.greenBits = 0;
m_glInfo.blueBits = 0;
m_glInfo.alphaBits = 0;
m_glInfo.depthBits = 0;
m_glInfo.stencilBits = 0;
m_glInfo.maxTextureSize = 0;
m_glInfo.maxLights = 0;
m_glInfo.maxAttribStacks = 0;
m_glInfo.maxModelViewStacks = 0;
m_glInfo.maxClipPlanes = 0;
m_glInfo.maxTextureStacks = 0;
}
QOpenGLInfo::~QOpenGLInfo() {
}
bool QOpenGLInfo::getInfo() {
QString str;
// get vendor string
str = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
if(!str.isNull())
m_glInfo.vendor = str;
else
return false;
// get renderer string
str = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
//str = (char*)glGetString(GL_RENDERER);
if(!str.isNull())
m_glInfo.renderer = str;
else
return false;
// get version string
str = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_VERSION)));
str = (char*)glGetString(GL_VERSION);
if(!str.isNull())
m_glInfo.version = str;
else
return false;
// get all extensions as a string
str = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
//str = (char*)glGetString(GL_EXTENSIONS);
// split extensions
if(!str.isNull()) {
m_glInfo.extensions = str.split(' ');
m_glInfo.extensions.sort();
}
else
return false;
// get number of color bits
glGetIntegerv(GL_RED_BITS, &m_glInfo.redBits);
glGetIntegerv(GL_GREEN_BITS, &m_glInfo.greenBits);
glGetIntegerv(GL_BLUE_BITS, &m_glInfo.blueBits);
glGetIntegerv(GL_ALPHA_BITS, &m_glInfo.alphaBits);
// get depth bits
glGetIntegerv(GL_DEPTH_BITS, &m_glInfo.depthBits);
// get stecil bits
glGetIntegerv(GL_STENCIL_BITS, &m_glInfo.stencilBits);
// get max number of lights allowed
glGetIntegerv(GL_MAX_LIGHTS, &m_glInfo.maxLights);
// get max texture resolution
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_glInfo.maxTextureSize);
// get max number of clipping planes
glGetIntegerv(GL_MAX_CLIP_PLANES, &m_glInfo.maxClipPlanes);
// get max modelview and projection matrix stacks
glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &m_glInfo.maxModelViewStacks);
glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, &m_glInfo.maxProjectionStacks);
glGetIntegerv(GL_MAX_ATTRIB_STACK_DEPTH, &m_glInfo.maxAttribStacks);
// get max texture stacks
glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, &m_glInfo.maxTextureStacks);
return true;
}
bool QOpenGLInfo::isExtensionSupported(const QString &extension) {
for (int i = 0; i < m_glInfo.extensions.size(); ++i) {
if (extension == m_glInfo.extensions.at(i))
return true;
}
return false;
}
void QOpenGLInfo::printSelf() {
//std::stringstream ss;
qDebug() << "";
qDebug() << "OpenGL Driver Info";
qDebug() << "==================";
qDebug() << "Vendor: " << m_glInfo.vendor;
qDebug() << "Version: " << m_glInfo.version;
qDebug() << "Renderer: " << m_glInfo.renderer;
qDebug() << "";
qDebug() << "Color Bits(R,G,B,A): ("
<< m_glInfo.redBits
<< ", " << m_glInfo.greenBits
<< ", " << m_glInfo.blueBits
<< ", " << m_glInfo.alphaBits
<< ")\n";
qDebug() << "Depth Bits: " << m_glInfo.depthBits;
qDebug() << "Stencil Bits: " << m_glInfo.stencilBits;
qDebug() << "";
qDebug() << "Max Texture Size: "
<< m_glInfo.maxTextureSize
<< "x"
<< m_glInfo.maxTextureSize;
qDebug() << "Max Lights: " << m_glInfo.maxLights;
qDebug() << "Max Clip Planes: " << m_glInfo.maxClipPlanes;
qDebug() << "Max Modelview Matrix Stacks: " << m_glInfo.maxModelViewStacks;
qDebug() << "Max Projection Matrix Stacks: " << m_glInfo.maxProjectionStacks;
qDebug() << "Max Attribute Stacks: " << m_glInfo.maxAttribStacks;
qDebug() << "Max Texture Stacks: " << m_glInfo.maxTextureStacks;
qDebug() << "";
qDebug() << "Total Number of Extensions: " << m_glInfo.extensions.size();
qDebug() << "==============================";
for(int i = 0; i < m_glInfo.extensions.size(); ++i)
qDebug() << m_glInfo.extensions.at(i);
qDebug() << "======================================================================";
}
+82
View File
@@ -0,0 +1,82 @@
/**
* @file cusdr_oglInfo.h
* @brief OpenGL info header file for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-11-10
*/
/*
* adapted from glInfo.h of Song Ho Ahn (song.ahn@gmail.com)
* Copyright (c) 2005 Song Ho Ahn
*
* (C) 2011 adapted for cuSDR by Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_OGLINFO_H
#define _CUSDR_OGLINFO_H
//#include <QObject>
//#include <QString>
//#include <QStringList>
#include "cusdr_settings.h"
// struct variable to store OpenGL info
typedef struct _glinfo {
QString vendor;
QString renderer;
QString version;
QStringList extensions;
int redBits;
int greenBits;
int blueBits;
int alphaBits;
int depthBits;
int stencilBits;
int maxTextureSize;
int maxLights;
int maxAttribStacks;
int maxModelViewStacks;
int maxProjectionStacks;
int maxClipPlanes;
int maxTextureStacks;
} t_glinfo;
class QOpenGLInfo : public QObject {
Q_OBJECT
public:
QOpenGLInfo(QObject *parent = 0);
~QOpenGLInfo();
bool getInfo();
void printSelf();
bool isExtensionSupported(const QString &extension);
private:
Settings* set;
t_glinfo m_glInfo;
};
#endif // _CUSDR_OGLINFO_H
File diff suppressed because it is too large Load Diff
+432
View File
@@ -0,0 +1,432 @@
/**
* @file cusdr_oglReceiverPanel.h
* @brief receiver panel header file for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-03-14
*/
/*
* Copyright 2010, 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_QGL_RECEIVERPANEL_H
#define _CUSDR_QGL_RECEIVERPANEL_H
#include "cusdr_oglUtils.h"
#include "cusdr_oglInfo.h"
#include "cusdr_settings.h"
#include "cusdr_fonts.h"
#include "Util/cusdr_buttons.h"
#include "cusdr_oglText.h"
#include "QtDSP/qtdsp_dualModeAverager.h"
#include "cusdr_radioPopupWidget.h"
#include <QWheelEvent>
#include <QtOpenGL/QGLWidget>
#ifdef LOG_GRAPHICS
# define GRAPHICS_DEBUG qDebug().nospace() << "ReceiverPanel::\t"
#else
# define GRAPHICS_DEBUG nullDebug()
#endif
class QGLReceiverPanel : public QGLWidget {
Q_OBJECT
public:
QGLReceiverPanel(QWidget *parent = 0, int rx = 0);
~QGLReceiverPanel();
public slots:
QSize minimumSizeHint() const;
QSize sizeHint() const;
//void setSpectrumBuffer(const float* buffer, int size);
//void setSpectrumBuffer(const qVectorFloat& buffer);
void setSpectrumBuffer(int rx, const qVectorFloat& buffer);
void setCtrFrequency(QObject* sender, int mode, int rx, long freq);
void setVFOFrequency(QObject* sender, int mode, int rx, long freq);
protected:
void initializeGL();
void resizeGL(int iWidth, int iHeight);
void paintGL();
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent * event );
void keyPressEvent(QKeyEvent* event);
private:
Settings* set;
QSDR::_ServerMode m_serverMode;
QSDR::_HWInterfaceMode m_hwInterface;
QSDR::_DataEngineState m_dataEngineState;
CFonts* fonts;
TFonts m_fonts;
DualModeAverager* averager;
RadioPopupWidget* radioPopup;
AGCMode m_agcMode;
DSPMode m_dspMode;
PanGraphicsMode m_panMode;
WaterfallColorMode m_waterfallMode;
QTime m_displayTime;
QTime m_resizeTime;
QTime freqChangeTimer;
QTime peakHoldTimer;
QString m_bandText;
QString m_agcModeString;
QString m_dspModeString;
QString m_filterWidthString;
TScale m_frequencyScale;
TScale m_dBmScale;
TScale m_secScale;
QList<TReceiver> m_rxDataList;
QVector<qreal> m_panadapterBins;
QVector<qreal> m_panPeakHoldBins;
QVarLengthArray<TGL_ubyteRGBA> m_waterfallPixel;
QQueue<QVector<float> > specAv_queue;
QGLFramebufferObject* m_frequencyScaleFBO;
QGLFramebufferObject* m_dBmScaleFBO;
QGLFramebufferObject* m_panadapterGridFBO;
QGLFramebufferObject* m_textureFBO;
QGLFramebufferObject* m_waterfallLineFBO;
QGLFramebufferObject* m_waterfallFBO;
QGLFramebufferObject* m_secScaleWaterfallFBO;
QRect m_panRect;
QRect m_dBmScalePanRect;
QRect m_freqScalePanRect;
QRect m_waterfallRect;
QRect m_secScaleWaterfallRect;
QRect m_filterRect;
QRect m_agcButtonRect;
QRect m_lockedPanButtonRect;
QRect m_vfoToMidButtonRect;
QRect m_midToVfoButtonRect;
QRect m_clickVFOButtonRect;
OGLText* m_oglTextTiny;
OGLText* m_oglTextSmall;
OGLText* m_oglTextNormal;
OGLText* m_oglTextFreq1;
OGLText* m_oglTextFreq2;
OGLText* m_oglTextBig1;
OGLText* m_oglTextBig2;
OGLText* m_oglTextHuge;
QPoint m_mousePos;
QPoint m_oldMousePos;
QPoint m_mouseLastPos;
QPoint m_mouseDownPos;
QPoint m_rulerMouseDownPos;
QPoint m_cameraAngle;
QColor m_waterfallLoColor;
QColor m_waterfallHiColor;
QColor m_waterfallMidColor;
QColor m_gridColor;
QColor m_darkColor;
QMutex mutex;
QMutex spectrumBufferMutex;
enum Region {
freqScalePanadapterRegion,
panadapterRegion,
dBmScalePanadapterRegion,
waterfallRegion,
filterRegion,
filterRegionLow,
filterRegionHigh,
agcButtonRegion,
agcThresholdLine,
agcHangLine,
agcFixedGainLine,
//lockedPanButtonRegion,
//vfoToMidButtonRegion,
//midToVfoButtonRegion,
//clickVfoButtonRegion,
elsewhere,
out
};
GLint m_panRectWidth;
GLint m_panSpectrumBinsLength;
GLint m_filterLeft;
GLint m_filterRight;
GLint m_filterTop;
GLint m_filterBottom;
GLfloat m_agcThresholdPixel;
GLfloat m_agcHangLevelPixel;
GLfloat m_agcFixedGainLevelPixel;
GLfloat m_bkgRed;
GLfloat m_bkgGreen;
GLfloat m_bkgBlue;
GLfloat m_red;
GLfloat m_green;
GLfloat m_blue;
GLfloat m_redF;
GLfloat m_greenF;
GLfloat m_blueF;
GLfloat m_redST;
GLfloat m_greenST;
GLfloat m_blueST;
GLfloat m_redSB;
GLfloat m_greenSB;
GLfloat m_blueSB;
GLfloat m_redGrid;
GLfloat m_greenGrid;
GLfloat m_blueGrid;
unsigned int timer;
int m_bigHeight;
int m_bigWidth;
int m_receiver;
//int m_frequencyRxOnRx;
int m_spectrumSize;
int m_sampleSize;
int m_oldSampleSize;
int m_oldWidth;
int m_oldPanRectHeight;
int m_cnt;
int m_specAveragingCnt;
int m_currentReceiver;
int m_waterfallAlpha;
int m_waterfallOffsetLo;
int m_waterfallOffsetHi;
int m_waterfallColorRange;
int m_freqRulerDisplayWidth;
int m_oldWaterfallWidth;
int m_displayTop;
int m_dBmPanLogGain;
int m_panSpectrumMinimumHeight;
int m_mouseRegion;
int m_oldMouseRegion;
int m_oldMousePosX;
int m_snapMouse;
int m_panDisplayMode;
int m_sampleRate;
int m_downRate;
int m_mercuryAttenuator;
int m_haircrossOffsetRight;
int m_haircrossOffsetLeft;
int m_haircrossMaxRight;
int m_haircrossMinTop;
int m_displayCenterlineHeight;
int m_waterfallLineCnt;
int m_adcStatus;
int m_fps;
int m_filterWidth;
int m_fftMult;
long m_centerFrequency;
long m_vfoFrequency;
long m_deltaFrequency;
long m_otherFrequency;
//long m_oldFreq;
bool m_smallSize;
bool m_spectrumVertexColorUpdate;
bool m_dBmScalePanadapterRenew;
bool m_dBmScalePanadapterUpdate;
bool m_freqScalePanadapterRenew;
bool m_freqScalePanadapterUpdate;
bool m_secScaleWaterfallUpdate;
bool m_secScaleWaterfallRenew;
bool m_panGridRenew;
bool m_panGridUpdate;
bool m_waterfallUpdate;
bool m_waterfallDisplayUpdate;
bool m_distRulerUpdate;
bool m_newWidebandPanFreqRuler;
bool m_spectrumColorsChanged;
bool m_spectrumAveraging;
//bool m_spectrumAveragingOld;
bool m_crossHair;
bool m_crossHairCursor;
bool m_panGrid;
bool m_peakHold;
bool m_filterChanged;
bool m_showFilterLeftBoundary;
bool m_showFilterRightBoundary;
bool m_highlightFilter;
bool m_peakHoldBufferResize;
bool m_showAGCLines;
bool m_agcHangEnabled;
bool m_dragMouse;
bool m_panLocked;
bool m_clickVFO;
qreal m_yScaleFactor;
qreal m_panFrequencyScale;
qreal m_freqScaleZoomFactor;
qreal m_dBmPanMin;
qreal m_dBmPanMax;
qreal m_dBmPanDelta;
qreal m_mouseWheelFreqStep;
qreal m_secWaterfallMin;
qreal m_secWaterfallMax;
qreal m_panScale;
qreal m_scaleMult;
qreal m_scaleMultOld;
qreal m_filterLowerFrequency;
qreal m_filterUpperFrequency;
qreal m_mouseDownFilterFrequencyLo;
qreal m_mouseDownFilterFrequencyHi;
qreal m_filterLo;
qreal m_filterHi;
qreal m_deltaF;
qreal m_agcThresholdNew;
qreal m_agcThresholdOld;
qreal m_mouseDownAGCThreshold;
qreal m_agcHangLevelNew;
qreal m_agcHangLevelOld;
qreal m_mouseDownAGCHangLevel;
qreal m_agcFixedGain;
qreal m_mouseDownFixedGainLevel;
float m_scale;
float m_cameraDistance;
float m_freqRulerPosition;
QVector<float> m_tmp;
//******************************************************************
void setupConnections();
QColor getWaterfallColorAtPixel(qreal value);
void saveGLState();
void restoreGLState();
// drawing
void paintReceiverDisplay();
void paint3DPanadapterMode();
void drawPanadapter();
void drawPanVerticalScale();
void drawPanHorizontalScale();
void drawPanadapterGrid();
void drawPanFilter();
void drawCenterLine();
void drawWaterfall();
void drawWaterfallVerticalScale();
void drawCrossHair();
void drawReceiverInfo();
void drawAGCControl();
void drawVFOControl();
void renderPanVerticalScale();
void renderPanHorizontalScale();
void renderPanadapterGrid();
void renderWaterfallVerticalScale();
//void computeDisplayBins(const QVector<float>& panBuffer, const float* waterfallBuffer);
//void computeDisplayBins(QVector<float> &buffer);
void computeDisplayBins(QVector<float>& panBuffer, QVector<float>& waterfallBuffer);
void showText(float x, float y, float z, const QString &text, bool smallText);
void showRadioPopup(bool value);
private slots:
void systemStateChanged(
QObject *sender,
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state);
void graphicModeChanged(
QObject *sender,
int rx,
PanGraphicsMode panMode,
WaterfallColorMode waterfallColorMode);
void setSpectrumSize(QObject *sender, int value);
void setCurrentReceiver(QObject *sender, int value);
void setHamBand(QObject *sender, int rx, bool byButton, HamBand band);
void setFilterFrequencies(QObject *sender, int rx, qreal lo, qreal hi);
void setMercuryAttenuator(QObject* sender, HamBand band, int value);
void setupDisplayRegions(QSize size);
void setSpectrumAveraging(QObject* sender, int rx, bool value);
void setSpectrumAveragingCnt(int value);
void setVfoToMidFrequency();
void setMidToVfoFrequency();
void setPanGridStatus(bool value, int rx);
void setPeakHoldStatus(bool value, int rx);
void setPanLockedStatus(bool value, int rx);
void setClickVFOStatus(bool value, int rx);
void setHairCrossStatus(bool value, int rx);
void setPanadapterColors();
void getRegion(QPoint p);
void freqRulerPositionChanged(QObject *sender, int rx, float pos);
void sampleRateChanged(QObject *sender, int value);
void setWaterfallOffesetLo(int rx, int value);
void setWaterfallOffesetHi(int rx, int value);
void setdBmScaleMin(int rx, qreal value);
void setdBmScaleMax(int rx, qreal value);
void setMouseWheelFreqStep(QObject *, int, qreal);
void setADCStatus(int value);
void updateADCStatus();
void setFramesPerSecond(QObject* sender, int rx, int value);
void setDSPMode(QObject* sender, int rx, DSPMode mode);
void setAGCMode(QObject* sender, int rx, AGCMode mode, bool hangEnabled);
void setAGCLineLevels(QObject* sender, int rx, qreal thresh, qreal hang);
void setAGCLineFixedLevel(QObject* sender, int rx, qreal value);
void setAGCLinesStatus(QObject* sender, bool value, int rx);
//void setAGCHangEnabled(QObject *sender, int rx, bool hangEnabled);
signals:
void showEvent(QObject *sender);
void closeEvent(QObject *sender);
void messageEvent(QString msg);
void coordChanged(int x,int y);
};
#endif // _CUSDR_QGL_RECEIVERPANEL_H
+282
View File
@@ -0,0 +1,282 @@
/**
* @file cusdr_oglText.cpp
* @brief OpenGL Text generation class for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-02-18
*/
/*
* adapted from the MIFit project: http://code.google.com/p/mifit
*
* Copyright 2012 adapted for cuSDR by Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "cusdr_oglText.h"
const int TEXTURE_SIZE = 256;
struct CharData {
GLuint textureId;
uint width;
uint height;
GLfloat s[2];
GLfloat t[2];
};
struct OGLTextPrivate {
OGLTextPrivate(const QFont &f);
~OGLTextPrivate();
void allocateTexture();
CharData &createCharacter(QChar c);
QFont font;
QFontMetrics fontMetrics;
QHash<ushort, CharData> characters;
QList<GLuint> textures;
GLint xOffset;
GLint yOffset;
};
OGLTextPrivate::OGLTextPrivate(const QFont &f)
: font(f), fontMetrics(f), xOffset(0), yOffset(0) {}
OGLTextPrivate::~OGLTextPrivate() {
foreach (GLuint texture, textures)
glDeleteTextures(1, &texture);
}
void OGLTextPrivate::allocateTexture() {
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// the texture ends at the edges (clamp)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// select modulate to mix texture with color for shading
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
QImage image(TEXTURE_SIZE, TEXTURE_SIZE, QImage::Format_ARGB32);
image.fill(Qt::transparent);
image = QGLWidget::convertToGLFormat(image);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEXTURE_SIZE, TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, TEXTURE_SIZE, TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
textures += texture;
}
CharData &OGLTextPrivate::createCharacter(QChar c) {
ushort unicodeC = c.unicode();
if (characters.contains(unicodeC))
return characters[unicodeC];
if (textures.empty())
allocateTexture();
GLuint texture = textures.last();
GLsizei width = fontMetrics.width(c);
GLsizei height = fontMetrics.height();
QPixmap pixmap(width, height);
pixmap.fill(Qt::transparent);
/*QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
if (!image.isNull()) {
image.fill(Qt::transparent);
QPainter p(&image);
if (&font) p.setFont(this->font);
}*/
QPainter painter;
//const QPainter::CompositionMode comp_mode = painter.compositionMode();
//painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.begin(&pixmap);
//painter.setRenderHints(QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing);
painter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing, false);
painter.setFont(font);
painter.setPen(Qt::white);
//painter.drawText(0, fontMetrics.ascent(), c);
painter.drawText(pixmap.rect(), Qt::TextSingleLine | Qt::TextDontClip | Qt::AlignCenter, c);
painter.end();
QImage image = QGLWidget::convertToGLFormat(pixmap.toImage());
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
CharData& character = characters[unicodeC];
character.textureId = texture;
character.width = width;
character.height = height;
character.s[0] = static_cast<GLfloat>(xOffset) / TEXTURE_SIZE;
character.t[0] = static_cast<GLfloat>(yOffset) / TEXTURE_SIZE;
character.s[1] = static_cast<GLfloat>(xOffset + width) / TEXTURE_SIZE;
character.t[1] = static_cast<GLfloat>(yOffset + height) / TEXTURE_SIZE;
xOffset += width;
if (xOffset + fontMetrics.maxWidth() >= TEXTURE_SIZE) {
xOffset = 1;
yOffset += height;
}
if (yOffset + fontMetrics.height() >= TEXTURE_SIZE) {
allocateTexture();
yOffset = 1;
}
return character;
}
OGLText::OGLText(const QFont &f) : d(new OGLTextPrivate(f)) {}
OGLText::~OGLText() {
delete d;
}
QFont OGLText::font() const
{
return d->font;
}
QFontMetrics OGLText::fontMetrics() const {
return d->fontMetrics;
}
//! Renders text at given x, y.
void OGLText::renderText(float x, float y, const QString &text) {
const bool GL_TEXTURE_2D_wasEnabled = glIsEnabled(GL_TEXTURE_2D);
GLint prev_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_texture);
GLint prev_shade_model; glGetIntegerv(GL_SHADE_MODEL, &prev_shade_model);
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT);
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (prev_shade_model != GL_FLAT) glShadeModel(GL_FLAT);
if (!GL_TEXTURE_2D_wasEnabled) glEnable(GL_TEXTURE_2D);
GLuint texture = 0;
glTranslatef(x, y, 0);
for (int i = 0; i < text.length(); ++i) {
//if (text.length() > 80)
// qDebug() << "********************* OK";
CharData &c = d->createCharacter(text.at(i));
if (texture != c.textureId) {
texture = c.textureId;
glBindTexture(GL_TEXTURE_2D, texture);
}
glBegin(GL_QUADS);
glTexCoord2f(c.s[0], c.t[0]); glVertex2f(0, c.height);
glTexCoord2f(c.s[1], c.t[0]); glVertex2f(c.width, c.height);
glTexCoord2f(c.s[1], c.t[1]); glVertex2f(c.width, 0);
glTexCoord2f(c.s[0], c.t[1]); glVertex2f(0, 0);
glEnd();
glTranslatef(c.width, 0, 0);
}
glShadeModel(prev_shade_model);
glBindTexture(GL_TEXTURE_2D, prev_texture);
if (!GL_TEXTURE_2D_wasEnabled) glDisable(GL_TEXTURE_2D);
glPopMatrix();
glPopAttrib();
}
void OGLText::renderText(float x, float y, float z, const QString &text) {
const bool GL_TEXTURE_2D_wasEnabled = glIsEnabled(GL_TEXTURE_2D);
GLint prev_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_texture);
GLint prev_shade_model; glGetIntegerv(GL_SHADE_MODEL, &prev_shade_model);
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT);
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (prev_shade_model != GL_FLAT) glShadeModel(GL_FLAT);
if (!GL_TEXTURE_2D_wasEnabled) glEnable(GL_TEXTURE_2D);
GLuint texture = 0;
glTranslatef(x, y, 0);
for (int i = 0; i < text.length(); ++i) {
CharData &c = d->createCharacter(text.at(i));
if (texture != c.textureId) {
texture = c.textureId;
glBindTexture(GL_TEXTURE_2D, texture);
}
/*glBegin(GL_QUADS);
glTexCoord2f(c.s[0], c.t[0]); glVertex2f(0, c.height);
glTexCoord2f(c.s[1], c.t[0]); glVertex2f(c.width, c.height);
glTexCoord2f(c.s[1], c.t[1]); glVertex2f(c.width, 0);
glTexCoord2f(c.s[0], c.t[1]); glVertex2f(0, 0);
glEnd();*/
glBegin(GL_QUADS);
glTexCoord2f(c.s[0], c.t[0]); glVertex3f(0, c.height, z);
glTexCoord2f(c.s[1], c.t[0]); glVertex3f(c.width, c.height, z);
glTexCoord2f(c.s[1], c.t[1]); glVertex3f(c.width, 0, z);
glTexCoord2f(c.s[0], c.t[1]); glVertex3f(0, 0, z);
glEnd();
glTranslatef(c.width, 0, 0);
}
glShadeModel(prev_shade_model);
glBindTexture(GL_TEXTURE_2D, prev_texture);
if (!GL_TEXTURE_2D_wasEnabled) glDisable(GL_TEXTURE_2D);
glPopMatrix();
glPopAttrib();
}
+63
View File
@@ -0,0 +1,63 @@
/**
* @file cusdr_oglText.h
* @brief OpenGL Text generation header file for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-02-18
*/
/*
* adapted from the MIFit project: http://code.google.com/p/mifit
*
* Copyright 2012 adapted for cuSDR by Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_OGL_TEXT_H
#define _CUSDR_OGL_TEXT_H
#include "cusdr_oglUtils.h"
#include "cusdr_oglInfo.h"
#include "cusdr_settings.h"
#include <QtGlobal>
class QChar;
class QFont;
class QFontMetrics;
class QString;
class OGLTextPrivate;
class OGLText {
public:
OGLText(const QFont &f);
virtual ~OGLText();
QFont font() const;
QFontMetrics fontMetrics() const;
void renderText(float x, float y, const QString &text);
void renderText(float x, float y, float z, const QString &text);
private:
Q_DISABLE_COPY(OGLText)
OGLTextPrivate *const d;
};
#endif // _CUSDR_OGL_TEXT_H
+899
View File
@@ -0,0 +1,899 @@
/**
* @file cusdr_oglUtils.h
* @brief Utils header file for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-11-17
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_OPENGLTYPES_H
#define _CUSDR_OPENGLTYPES_H
#include <QGLWidget>
//#include <QList>
//#include <QRect>
//#include <QColor>
//#include <QVarLengthArray>
#include <QGLFramebufferObject>
#include <QtCore/qmath.h>
#define GL_CLAMP_TO_EDGE 0x812F
typedef struct _gl2i {
GLint x;
GLint y;
} TGL2int;
typedef struct _gl3i {
GLint x;
GLint y;
GLint z;
} TGL3int;
typedef struct _gl2f {
GLfloat x;
GLfloat y;
} TGL2float;
typedef struct _gl3f {
GLfloat x;
GLfloat y;
GLfloat z;
} TGL3float;
typedef struct _ucharRGBA {
uchar red;
uchar green;
uchar blue;
uchar alpha;
} ucharRGBA;
typedef struct _glubyteRGBA {
GLubyte red;
GLubyte green;
GLubyte blue;
GLubyte alpha;
} TGL_ubyteRGBA;
typedef struct _scaleSteps {
double smallStep;
double bigStep;
} TScaleSteps;
typedef struct _scale {
QList<int> mainPointPositions;
QList<int> subPointPositions;
QList<qreal> mainPoints;
QList<qreal> subPoints;
} TScale;
struct s_glRGBA_float {
GLfloat r, g, b, a;
s_glRGBA_float() : r(0), g(0), b(0), a(0) {}
s_glRGBA_float(GLfloat red, GLfloat grn, GLfloat blu, GLfloat alpha) : r(red), g(grn), b(blu), a(alpha) {}
};
struct s_glRGBA_uByte {
GLubyte r, g, b, a;
s_glRGBA_uByte() : r(0), g(0), b(0), a(0) {}
s_glRGBA_uByte(GLubyte red, GLubyte grn, GLubyte blu, GLubyte alpha) : r(red), g(grn), b(blu), a(alpha) {}
};
typedef struct _widebandDisplayData {
QSize size;
QRect widebandPanRect;
QRect freqScaleWidebandPanRect;
QRect dBmScaleWidebandPanRect;
QVector<qreal> widebandPanBins;
qreal dBmPanMin;
qreal dBmPanMax;
qreal scaleMult;
qreal freqScaleZoomFactor;
long frequency;
bool freqScaleWidebandUpdate;
bool freqScaleWidebandRenew;
bool dBmScaleWidebandUpdate;
bool dBmScaleWidebandRenew;
bool widebandPanGridUpdate;
bool widebandPanGridRenew;
} TWideBandDisplayData;
//**************************************************************
inline QString frequencyString(double frequency, bool addPlusSign = false) {
QString str("");
double f = qAbs(frequency);
if (f >= 1e9) {
str = QString::number(f / 1e9, 'f', 6);
str.insert(str.size() - 3, '.');
str += " GHz";
}
else
if (f >= 1e6) {
str = QString::number(f / 1e6, 'f', 6 + 1);
str.insert(str.size() - 4, '.');
str.insert(str.size() - 1, '.');
str += " MHz";
}
else
if (f >= 1e3) {
str = QString::number(f / 1e3, 'f', 3 + 1);
str.insert(str.size() - 1, '.');
str += " kHz";
}
else {
str = QString::number(f, 'f', 1) + "Hz";
}
if (frequency < 0) str = '-' + str;
else
if (frequency > 0 && addPlusSign) str = '+' + str;
return str;
}
inline int nextPowerOfTwo(int value) {
value--;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
++value;
return value;
}
inline TScaleSteps getXScale(double size) {
TScaleSteps s;
qint64 base = 1;
int mult = 1;
while (size > 10.0f) {
size /= 10;
base *= 10;
}
if (size < 2) mult = 2;
else if (size < 5) mult = 5;
else mult = 10;
s.bigStep = base * mult;
switch (mult) {
case 1: s.smallStep = s.bigStep / 5; break;
case 2: s.smallStep = s.bigStep / 2; break;
case 5: s.smallStep = s.bigStep / 5; break;
case 10: s.smallStep = s.bigStep / 5; break;
}
return s;
}
inline TScaleSteps getXScale(double size, float scale) {
TScaleSteps s;
qint64 base = 1;
int mult = 1;
while (size > scale) {
size /= scale;
base *= scale;
}
if (size < 2) mult = 2;
else if (size < 5) mult = 5;
else mult = 10;
s.bigStep = base * mult;
switch (mult) {
case 1: s.smallStep = s.bigStep / 5; break;
case 2: s.smallStep = s.bigStep / 2; break;
case 5: s.smallStep = s.bigStep / 5; break;
case 10: s.smallStep = s.bigStep / 5; break;
}
return s;
}
inline TScaleSteps getYScale(double size, float scale) {
TScaleSteps s;
qint64 base = 1;
int mult = 1;
while (size > scale) {
size /= scale;
base *= scale;
}
if (size < 2) mult = 2;
else if (size < 5) mult = 5;
else mult = 10;
s.bigStep = base * mult;
switch (mult) {
case 1: s.smallStep = s.bigStep / 5; break;
case 2: s.smallStep = s.bigStep / 2; break;
case 5: s.smallStep = s.bigStep / 5; break;
case 10: s.smallStep = s.bigStep / 2; break;
}
return s;
}
inline TScale getXRuler(const QRect &rect, int fontMaxWidth, qreal unit, qreal lo, qreal hi) {
TScale ruler;
TScaleSteps scale = getXScale(fontMaxWidth / unit);
//qreal value = floor(lo / scale.bigStep) * scale.bigStep;
qreal value = qFloor(lo / scale.bigStep) * scale.bigStep;
while (value < hi) {
int x = qRound(unit * (value - lo));
if (x >= rect.width()) break;
if (x > 0) {
ruler.mainPoints << value;
ruler.mainPointPositions << x;
}
if (scale.smallStep > 0) {
qreal smallValue = value + scale.smallStep;
qreal smallUpperValue = value + scale.bigStep;
while (smallValue < smallUpperValue && smallValue < hi) {
int x = qRound(unit * (smallValue - lo));
if (x >= rect.width()) break;
if (x > 0) ruler.subPointPositions << x;
smallValue += scale.smallStep;
}
}
value += scale.bigStep;
}
return ruler;
}
inline TScale getXRuler(const QRect &rect, int fontMaxWidth, qreal unit, qreal lo, qreal hi, float s) {
TScale ruler;
TScaleSteps scale = getXScale(fontMaxWidth / unit, s);
//qreal value = floor(lo / scale.bigStep) * scale.bigStep;
qreal value = qFloor(lo / scale.bigStep) * scale.bigStep;
while (value < hi) {
int x = qRound(unit * (value - lo));
if (x >= rect.width()) break;
if (x > 0) {
ruler.mainPoints << value;
ruler.mainPointPositions << x;
}
if (scale.smallStep > 0) {
qreal smallValue = value + scale.smallStep;
qreal smallUpperValue = value + scale.bigStep;
while (smallValue < smallUpperValue && smallValue < hi) {
int x = qRound(unit * (smallValue - lo));
if (x >= rect.width()) break;
if (x > 0) ruler.subPointPositions << x;
smallValue += scale.smallStep;
}
}
value += scale.bigStep;
}
return ruler;
}
inline TScale getYRuler(const QRect &rect, int fontHeight, qreal unit, qreal lo, qreal hi) {
TScale ruler;
TScaleSteps scale = getYScale(fontHeight / unit, 10.0f);
//qreal value = ceil(hi / scale.bigStep) * scale.bigStep;
qreal value = qCeil(hi / scale.bigStep) * scale.bigStep;
while (value >= lo) {
int y = qRound(unit * -(value - hi));
if (y > 0 && y < rect.height()) {
if (ruler.mainPointPositions.length() < 100) {
ruler.mainPoints << value;
ruler.mainPointPositions << rect.top() + y;
}
}
if (scale.smallStep > 0) {
qreal smallValue = value - scale.smallStep;
qreal smallEndValue = value - scale.bigStep;
while (smallValue > smallEndValue && smallValue > lo) {
int y = qRound(unit * -(smallValue - hi));
if (y > 0 && y < rect.height()) {
if (ruler.subPointPositions.length() < 200)
ruler.subPointPositions << rect.top() + y;
}
smallValue -= scale.smallStep;
}
}
value -= scale.bigStep;
}
return ruler;
}
inline TScale getYRuler2(const QRect &rect, int fontHeight, qreal unit, qreal lo, qreal hi) {
TScale ruler;
TScaleSteps scale = getYScale(fontHeight / unit, 10.0f);
qreal value = qCeil(hi / scale.bigStep) * scale.bigStep;
while (value >= lo) {
int y = qRound(unit * -(value - hi));
if (y > 0 && y < rect.height()) {
if (ruler.mainPointPositions.length() < 100) {
ruler.mainPoints << value;
//ruler.mainPointPositions << rect.top() + y;
ruler.mainPointPositions << y;
}
}
if (scale.smallStep > 0) {
qreal smallValue = value - scale.smallStep;
qreal smallEndValue = value - scale.bigStep;
while (smallValue > smallEndValue && smallValue > lo) {
int y = qRound(unit * -(smallValue - hi));
if (y > 0 && y < rect.height()) {
if (ruler.subPointPositions.length() < 200)
ruler.subPointPositions << y;
//ruler.subPointPositions << rect.top() + y;
}
smallValue -= scale.smallStep;
}
}
value -= scale.bigStep;
}
return ruler;
}
inline TScale getYRuler3(const QRect &rect, int fontHeight, qreal unit, qreal lo, qreal hi, float v) {
TScale ruler;
TScaleSteps scale = getYScale(fontHeight / unit, v);
qreal value = qCeil(hi / scale.bigStep) * scale.bigStep;
while (value >= lo) {
int y = qRound(unit * -(value - hi));
if (y > 0 && y < rect.height()) {
if (ruler.mainPointPositions.length() < 100) {
ruler.mainPoints << value;
//ruler.mainPointPositions << rect.top() + y;
ruler.mainPointPositions << y;
}
}
if (scale.smallStep > 0) {
qreal smallValue = value - scale.smallStep;
qreal smallEndValue = value - scale.bigStep;
while (smallValue > smallEndValue && smallValue > lo) {
int y = qRound(unit * -(smallValue - hi));
if (y > 0 && y < rect.height()) {
if (ruler.subPointPositions.length() < 200)
ruler.subPointPositions << y;
//ruler.subPointPositions << rect.top() + y;
}
smallValue -= scale.smallStep;
}
}
value -= scale.bigStep;
}
return ruler;
}
inline GLfloat dBmToGLPixel(const QRect &rect, qreal dBmMax, qreal dBmMin, qreal value) {
GLfloat y;
qreal yScale = rect.height() / qAbs(dBmMax - dBmMin);
y = (GLfloat)(yScale * (dBmMax - value) + (qreal)rect.top());
return y;
}
inline qreal glPixelTodBm(const QRect &rect, qreal dBmMax, qreal dBmMin, int position) {
qreal dBm;
float yScale = rect.height() / qAbs(dBmMax - dBmMin);
dBm = dBmMax - (qreal)(position - rect.top())/yScale;
//qreal dBm = m_dBmPanMax - ((m_dBmPanMax - m_dBmPanMin) * ((qreal)(position - rect.top()) / rect.height()));
return dBm;
}
//**************************************************************
inline void setProjectionOrthographic(int width, int height) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//glOrtho(-1.0, +1.0, -1.0, +1.0, -90.0, +90.0);
glOrtho(0.0, width, height, 0, -5.0, 5.0);
//glOrtho(0.0, width, height, 0, -1.0, 1.0);
//glOrtho(0.0, width, 0, height, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
inline void setProjectionPerspective(int width, int height) {
Q_UNUSED(width)
Q_UNUSED(height)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//glFrustum(-aspect, +aspect, -1.0, +1.0, 4.0, 15.0);
//gluPerspective(60.0f, (float)(width)/height, 1.0f, 10.0f);
glMatrixMode(GL_MODELVIEW);
}
inline GLuint emptyTexture1D(int width) {
GLuint txtnumber;
unsigned int* data;
data = (unsigned int*)new GLuint[(width * 4 * sizeof(unsigned int))];
#if defined(Q_OS_WIN32)
ZeroMemory(data,(width * 4 * sizeof(unsigned int)));
#elif defined(Q_OS_LINUX)
memset(data, 0, width * 4 * sizeof(unsigned int));
#endif
glGenTextures(1, &txtnumber);
glBindTexture(GL_TEXTURE_1D, txtnumber);
glTexImage1D(GL_TEXTURE_1D, 0, 4, width, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
delete[] data;
return txtnumber;
}
inline GLuint emptyTexture2D(int width, int height) {
GLuint txtnumber;
unsigned int* data;
data = (unsigned int*)new GLuint[((width * height)* 4 * sizeof(unsigned int))];
#if defined(Q_OS_WIN32)
ZeroMemory(data,((width * height)* 4 * sizeof(unsigned int)));
#elif defined(Q_OS_LINUX)
memset(data, 0, (width * height)* 4 * sizeof(unsigned int));
#endif
glGenTextures(1, &txtnumber);
glBindTexture(GL_TEXTURE_2D, txtnumber);
glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
delete [] data;
return txtnumber;
}
inline void drawQuad2Di(int x, int y, int width, int height) {
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2f(0, 1); glVertex2i(x - width/2, y - height/2);
glTexCoord2f(1, 1); glVertex2i(x + width/2, y - height/2);
glTexCoord2f(1, 0); glVertex2i(x + width/2, y + height/2);
glTexCoord2f(0, 0); glVertex2i(x - width/2, y + height/2);
glEnd();
glDisable(GL_TEXTURE_2D);
}
inline void drawQuad3Df(float x, float y, float z, float width, float height) {
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2f(0, 1); glVertex3f(x - width/2, y - height/2, -z);
glTexCoord2f(1, 1); glVertex3f(x + width/2, y - height/2, -z);
glTexCoord2f(1, 0); glVertex3f(x + width/2, y + height/2, -z);
glTexCoord2f(0, 0); glVertex3f(x - width/2, y + height/2, -z);
glEnd();
glDisable(GL_TEXTURE_2D);
}
inline void drawGLRect(const QRect &rect, const QColor &color) {
if (rect.isEmpty()) return;
// draw a rectangle using 2 triangles
GLint x1 = rect.left();
GLint y1 = rect.top();
GLint x2 = x1 + rect.width();//rect.right() + 1;
GLint y2 = y1 + rect.height();//rect.bottom() + 1;
TGL2int vertexArray[4] = {{x1, y1}, {x2, y1}, {x1, y2}, {x2, y2}};
glColor4ub(color.red(), color.green(), color.blue(), color.alpha());
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_INT, 0, vertexArray);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
}
inline void drawGLRect(const QRect &rect, const QColor &color, float z) {
if (rect.isEmpty()) return;
// draw a rectangle using 2 triangles
GLint x1 = rect.left();
GLint y1 = rect.top();
GLint x2 = x1 + rect.width();
GLint y2 = y1 + rect.height();
TGL3float vertexArray[4] =
{
{(GLfloat)x1, (GLfloat)y1, z},
{(GLfloat)x2, (GLfloat)y1, z},
{(GLfloat)x1, (GLfloat)y2, z},
{(GLfloat)x2, (GLfloat)y2, z}
};
glColor4ub(color.red(), color.green(), color.blue(), color.alpha());
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertexArray);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
}
inline void drawGLRect(const QRect &rect, const QColor &color1, const QColor &color2, bool colorLeftToRight) {
// draw a rectangle using 2 triangles
GLint x1 = rect.left();
GLint y1 = rect.top();
GLint x2 = rect.right() + 1;
GLint y2 = rect.bottom() + 1;
TGL2int vertexArray[4] = {{x1, y1}, {x2, y1}, {x1, y2}, {x2, y2}};
s_glRGBA_uByte gl_color1;
gl_color1.r = color1.red();
gl_color1.g = color1.green();
gl_color1.b = color1.blue();
gl_color1.a = color1.alpha();
s_glRGBA_uByte gl_color2;
gl_color2.r = color2.red();
gl_color2.g = color2.green();
gl_color2.b = color2.blue();
gl_color2.a = color2.alpha();
s_glRGBA_uByte vertexColors[4];
if (!colorLeftToRight) {
// top to bottom
vertexColors[0] = gl_color1; // top left
vertexColors[1] = gl_color1; // top right
vertexColors[2] = gl_color2; // bottom left
vertexColors[3] = gl_color2; // bottom right
}
else {
// left to right
vertexColors[0] = gl_color1; // top left
vertexColors[1] = gl_color2; // top right
vertexColors[2] = gl_color1; // bottom left
vertexColors[3] = gl_color2; // bottom right
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_INT, 0, vertexArray);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, vertexColors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
inline void drawGLRect(const QRect &rect, const QColor &color1, const QColor &color2, float z, bool colorLeftToRight) {
// draw a rectangle using 2 triangles
GLint x1 = rect.left();
GLint y1 = rect.top();
GLint x2 = rect.right() + 1;
GLint y2 = rect.bottom() + 1;
TGL3float vertexArray[4] =
{
{(GLfloat)x1, (GLfloat)y1, z},
{(GLfloat)x2, (GLfloat)y1, z},
{(GLfloat)x1, (GLfloat)y2, z},
{(GLfloat)x2, (GLfloat)y2, z}
};
s_glRGBA_uByte gl_color1;
gl_color1.r = color1.red();
gl_color1.g = color1.green();
gl_color1.b = color1.blue();
gl_color1.a = color1.alpha();
s_glRGBA_uByte gl_color2;
gl_color2.r = color2.red();
gl_color2.g = color2.green();
gl_color2.b = color2.blue();
gl_color2.a = color2.alpha();
s_glRGBA_uByte vertexColors[4];
if (!colorLeftToRight) {
// top to bottom
vertexColors[0] = gl_color1; // top left
vertexColors[1] = gl_color1; // top right
vertexColors[2] = gl_color2; // bottom left
vertexColors[3] = gl_color2; // bottom right
}
else {
// left to right
vertexColors[0] = gl_color1; // top left
vertexColors[1] = gl_color2; // top right
vertexColors[2] = gl_color1; // bottom left
vertexColors[3] = gl_color2; // bottom right
}
glEnableClientState(GL_VERTEX_ARRAY);
//glVertexPointer(2, GL_INT, 0, vertexArray);
glVertexPointer(3, GL_FLOAT, 0, vertexArray);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, vertexColors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
inline void drawGLTriangleLeft(const QRect &rect, const QColor &color, float z) {
if (rect.isEmpty()) return;
GLint x1 = rect.left();
GLint x2 = rect.left() + rect.width();
GLint y1 = rect.top() + rect.height()/2;
GLint y2 = rect.top();
GLint y3 = rect.top() + rect.height();
TGL3float vertexArray[3] =
{
{(GLfloat)x1, (GLfloat)y1, z},
{(GLfloat)x2, (GLfloat)y2, z},
{(GLfloat)x2, (GLfloat)y3, z}
};
glColor4ub(color.red(), color.green(), color.blue(), color.alpha());
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertexArray);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableClientState(GL_VERTEX_ARRAY);
}
inline void drawGLTriangleRight(const QRect &rect, const QColor &color, float z) {
if (rect.isEmpty()) return;
GLint x1 = rect.left();
GLint x2 = rect.left() + rect.width();
GLint y1 = rect.top();
GLint y2 = y1 + rect.height();
GLint y3 = y1 + rect.height()/2;
TGL3float vertexArray[3] =
{
{(GLfloat)x1, (GLfloat)y1, z},
{(GLfloat)x2, (GLfloat)y3, z},
{(GLfloat)x1, (GLfloat)y2, z}
};
glColor4ub(color.red(), color.green(), color.blue(), color.alpha());
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertexArray);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableClientState(GL_VERTEX_ARRAY);
}
inline void drawGLBackground(const QRect &rect) {
if (rect.isEmpty()) return;
GLint x1 = rect.left();
GLint y1 = rect.top();
GLint x2 = x1 + rect.width();
GLint y2 = y1 + rect.height();
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_TRIANGLE_STRIP);
glColor3f((GLfloat)0.13, (GLfloat)0.13, (GLfloat)0.13); glVertex3f(x1, y1, 0.0); // top left corner
glColor3f((GLfloat)0.13, (GLfloat)0.13, (GLfloat)0.13); glVertex3f(x2, y1, 0.0); // top right corner
glColor3f((GLfloat)0.18, (GLfloat)0.18, (GLfloat)0.18); glVertex3f(x1, y2, 0.0); // bottom left corner
glColor3f((GLfloat)0.31, (GLfloat)0.31, (GLfloat)0.31); glVertex3f(x2, y2, 0.0); // bottom right corner
glEnd();
//glFlush();
}
inline void drawGLScaleBackground(const QRect &rect, const QColor &color) {
if (rect.isEmpty()) return;
GLint x1 = rect.left();
GLint y1 = rect.top();
GLint x2 = x1 + rect.width();
GLint y2 = y1 + rect.height();
//const bool GL_TEXTURE_2D_wasEnabled = glIsEnabled(GL_TEXTURE_2D);
glColor4ub(color.red(), color.green(), color.blue(), color.alpha());
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_POLYGON);
glVertex3f(x1, y1, 0.0); // top left corner
glVertex3f(x2, y1, 0.0); // top middle corner
glVertex3f(x2, y2, 0.0); // bottom middle corner
glVertex3f(x1, y2, 0.0); // bottom left corner
glEnd();
glFlush();
}
inline void renderTexture(
const QRect &rect,
const GLuint texId,
float z)
{
if (rect.isEmpty()) return;
if (!texId) return;
const bool GL_TEXTURE_2D_enabled = glIsEnabled(GL_TEXTURE_2D);
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
GLint x1 = rect.left();
GLint y1 = rect.top();
GLint x2 = x1 + rect.width();
GLint y2 = y1 + rect.height();
if (!GL_TEXTURE_2D_enabled) glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texId);
glBegin(GL_QUADS);
glTexCoord2f(0, 1); glVertex3f(x1, y1, z); // top left corner
glTexCoord2f(1, 1); glVertex3f(x2, y1, z); // top right corner
glTexCoord2f(1, 0); glVertex3f(x2, y2, z); // bottom right corner
glTexCoord2f(0, 0); glVertex3f(x1, y2, z); // bottom left corner
glEnd();
glBindTexture(GL_TEXTURE_2D, oldTex);
if (!GL_TEXTURE_2D_enabled) glDisable(GL_TEXTURE_2D);
}
//inline void writeBitmapString(void *font, char *string) {
//
// char *c;
// for (c = string; *c != '\0'; c++) glutBitmapCharacter(font, *c);
//}
//
//inline void writeStrokeString(void *font, char *string) {
//
// char *c;
// for (c = string; *c != '\0'; c++) glutStrokeCharacter(font, *c);
//}
#endif // _CUSDR_OPENGLTYPES_H
File diff suppressed because it is too large Load Diff
+290
View File
@@ -0,0 +1,290 @@
/**
* @file cusdr_oglWidebandPanel.h
* @brief wide band spectrum panel header file for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-02-11
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CUSDR_OGL_WIDEBANDPANEL_H
#define _CUSDR_OGL_WIDEBANDPANEL_H
#include "cusdr_oglUtils.h"
#include "cusdr_oglInfo.h"
#include "cusdr_settings.h"
#include "cusdr_fonts.h"
#include "cusdr_oglText.h"
//#include <QPixmap>
//#include <QImage>
//#include <QFontMetrics>
#include <QWheelEvent>
//#include <QQueue>
//#include <QDebug>
//#include <QtOpenGL/QGLWidget>
//#include <QGLFramebufferObject>
#ifdef LOG_WBGRAPHICS
# define WBGRAPHICS_DEBUG qDebug().nospace() << "WB-Graphics::\t"
#else
# define WBGRAPHICS_DEBUG nullDebug()
#endif
class QGLWidebandPanel : public QGLWidget {
Q_OBJECT
public:
QGLWidebandPanel(QWidget *parent = 0);
~QGLWidebandPanel();
public slots:
QSize minimumSizeHint() const;
QSize sizeHint() const;
//void setSpectrumBuffer(const float *buffer);
//void setFrequency(QObject *sender, bool value, long freq);
protected:
void initializeGL();
void resizeGL(int iWidth, int iHeight);
void paintGL();
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent * event );
void keyPressEvent(QKeyEvent* event);
void closeEvent(QCloseEvent *event);
void showEvent(QShowEvent *event);
void timerEvent(QTimerEvent *);
private:
Settings* set;
QSDR::_ServerMode m_serverMode;
QSDR::_HWInterfaceMode m_hwInterface;
QSDR::_DataEngineState m_dataEngineState;
PanGraphicsMode m_panMode;
WaterfallColorMode m_waterfallMode;
QVector<qreal> m_widebandPanSpectrumBins;
QQueue<QVector<float> > specAv_queue;
QList<TReceiver> m_rxDataList;
TWideband m_widebandOptions;
QGLFramebufferObject* m_frequencyScaleFBO;
QGLFramebufferObject* m_dBmScaleFBO;
QGLFramebufferObject* m_gridFBO;
CFonts *fonts;
TFonts m_fonts;
QTime m_panTimer;
QTime m_displayTime;
QTime m_resizeTime;
QRect m_panRect;
QRect m_freqScaleRect;
QRect m_dBmScaleRect;
QMutex mutex;
OGLText *m_oglTextTiny;
OGLText *m_oglTextSmall;
OGLText *m_oglTextNormal;
QPoint m_mousePos;
QPoint m_oldMousePos;
QPoint m_mouseLastPos;
QPoint m_mouseDownPos;
QPoint m_yScaleMouseDownPos;
QPoint m_cameraAngle;
TScale m_frequencyScale;
TScale m_dBmScale;
QColor m_gridColor;
GLfloat m_redGrid;
GLfloat m_greenGrid;
GLfloat m_blueGrid;
GLfloat m_r;
GLfloat m_g;
GLfloat m_b;
GLfloat m_rf;
GLfloat m_gf;
GLfloat m_bf;
GLfloat m_redST;
GLfloat m_greenST;
GLfloat m_blueST;
GLfloat m_redSB;
GLfloat m_greenSB;
GLfloat m_blueSB;
GLfloat m_bkgRed;
GLfloat m_bkgGreen;
GLfloat m_bkgBlue;
enum Region {
panRegion,
freqScaleRegion,
dBmScaleRegion,
elsewhere,
out
};
long m_frequency;
qreal m_dBmPanMin;
qreal m_dBmPanMax;
qreal m_dBmPanMinOld;
qreal m_dBmPanMaxOld;
qVectorFloat m_wbSpectrumBuffer;
float m_scale;
float m_distMax;
bool m_spectrumUpdate;
bool m_freqScaleUpdate;
bool m_freqScaleRenew;
bool m_dBmScaleUpdate;
bool m_dBmScaleRenew;
bool m_panGridUpdate;
bool m_panGridRenew;
bool m_spectrumColorsChanged;
bool m_spectrumVertexColorUpdate;
bool m_crossHairCursor;
bool m_panGrid;
bool m_calibrate;
int m_receiver;
int m_oldWidth;
int m_oldHeight;
int m_oldPanRectHeight;
int m_cnt;
int m_specAveragingCnt;
int m_mercuryAttenuator;
int m_dBmScaleTextPos;
int m_wbSpectrumBufferLength;
int m_scaledBufferSize;
float m_cameraDistance;
unsigned int timer;
GLint m_panRectWidth;
GLint m_panSpectrumBinsLength;
int m_mouseRegion;
int m_oldMouseRegion;
int m_snapMouse;
int m_currentReceiver;
int m_freqScaleWidth;
int m_displayTop;
int m_dBmPanLogGain;
int m_panDisplayMode;
int m_sampleRate;
int m_downRate;
float m_freqScalePosition;
float m_freqScaleZoomFactor;
qreal m_dBmPanDelta;
qreal m_dBmScaleOffset;
qreal m_panScale;
qreal m_scaleMultOld;
qreal m_panFrequencyScale;
qreal m_frequencySpan;
qreal m_frequencyUnit;
qreal m_lowerFrequency;
qreal m_upperFrequency;
//******************************************************************
void saveGLState();
void restoreGLState();
//void computeDisplayBins(const float* panBuffer);
void drawSpectrum();
void drawVerticalScale();
void drawHorizontalScale();
void drawGrid();
void drawCrossHair();
void drawHamBand(int lo, int hi, const QString &band);
void renderVerticalScale();
void renderHorizontalScale();
void renderGrid();
private slots:
void systemStateChanged(
QObject* sender,
QSDR::_Error err,
QSDR::_HWInterfaceMode hwmode,
QSDR::_ServerMode mode,
QSDR::_DataEngineState state);
void graphicModeChanged(
QObject* sender,
int rx,
PanGraphicsMode panMode,
WaterfallColorMode waterfallColorMode);
void setupConnections();
void setCurrentReceiver(QObject *sender, int value);
void setFrequency(QObject *sender, int mode, int rx, long freq);
void setupDisplayRegions(QSize size);
void setWidebandSpectrumBuffer(const qVectorFloat &buffer);
void resetWidebandSpectrumBuffer();
//void setSpectrumAveragingCnt(int value);
void setPanadapterColors();
void setPanGridStatus(bool value, int rx);
void setMercuryAttenuator(QObject* sender, HamBand band, int value);
void getRegion(QPoint p);
void sampleRateChanged(QObject* sender, int value);
void freqScaleUpdate(bool value);
void freqScaleRenew(bool value);
void dBmScaleUpdate(bool value);
void dBmScaleRenew(bool value);
void panGridUpdate(bool value);
void panGridRenew(bool value);
signals:
void showEvent(QObject* sender);
void closeEvent(QObject* sender);
void messageEvent(QString msg);
void coordChanged(int x, int y);
};
#endif // _CUSDR_OGL_WIDEBANDPANEL_H
+412
View File
@@ -0,0 +1,412 @@
/*
* Copyright (c) 2003, 2007-11 Matteo Frigo
* Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology
*
* The following statement of license applies *only* to this header file,
* and *not* to the other files distributed with FFTW or derived therefrom:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/***************************** NOTE TO USERS *********************************
*
* THIS IS A HEADER FILE, NOT A MANUAL
*
* If you want to know how to use FFTW, please read the manual,
* online at http://www.fftw.org/doc/ and also included with FFTW.
* For a quick start, see the manual's tutorial section.
*
* (Reading header files to learn how to use a library is a habit
* stemming from code lacking a proper manual. Arguably, it's a
* *bad* habit in most cases, because header files can contain
* interfaces that are not part of the public, stable API.)
*
****************************************************************************/
#ifndef FFTW3_H
#define FFTW3_H
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
/* If <complex.h> is included, use the C99 complex type. Otherwise
define a type bit-compatible with C99 complex */
#if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I)
# define FFTW_DEFINE_COMPLEX(R, C) typedef R _Complex C
#else
# define FFTW_DEFINE_COMPLEX(R, C) typedef R C[2]
#endif
#define FFTW_CONCAT(prefix, name) prefix ## name
#define FFTW_MANGLE_DOUBLE(name) FFTW_CONCAT(fftw_, name)
#define FFTW_MANGLE_FLOAT(name) FFTW_CONCAT(fftwf_, name)
#define FFTW_MANGLE_LONG_DOUBLE(name) FFTW_CONCAT(fftwl_, name)
#define FFTW_MANGLE_QUAD(name) FFTW_CONCAT(fftwq_, name)
/* IMPORTANT: for Windows compilers, you should add a line
*/
#define FFTW_DLL
/*
here and in kernel/ifftw.h if you are compiling/using FFTW as a
DLL, in order to do the proper importing/exporting, or
alternatively compile with -DFFTW_DLL or the equivalent
command-line flag. This is not necessary under MinGW/Cygwin, where
libtool does the imports/exports automatically. */
#if defined(FFTW_DLL) && (defined(_WIN32) || defined(__WIN32__))
/* annoying Windows syntax for shared-library declarations */
# if defined(COMPILING_FFTW) /* defined in api.h when compiling FFTW */
# define FFTW_EXTERN extern __declspec(dllexport)
# else /* user is calling FFTW; import symbol */
# define FFTW_EXTERN extern __declspec(dllimport)
# endif
#else
# define FFTW_EXTERN extern
#endif
enum fftw_r2r_kind_do_not_use_me {
FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2,
FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6,
FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10
};
struct fftw_iodim_do_not_use_me {
int n; /* dimension size */
int is; /* input stride */
int os; /* output stride */
};
#include <stddef.h> /* for ptrdiff_t */
struct fftw_iodim64_do_not_use_me {
ptrdiff_t n; /* dimension size */
ptrdiff_t is; /* input stride */
ptrdiff_t os; /* output stride */
};
typedef void (*fftw_write_char_func_do_not_use_me)(char c, void *);
typedef int (*fftw_read_char_func_do_not_use_me)(void *);
/*
huge second-order macro that defines prototypes for all API
functions. We expand this macro for each supported precision
X: name-mangling macro
R: real data type
C: complex data type
*/
#define FFTW_DEFINE_API(X, R, C) \
\
FFTW_DEFINE_COMPLEX(R, C); \
\
typedef struct X(plan_s) *X(plan); \
\
typedef struct fftw_iodim_do_not_use_me X(iodim); \
typedef struct fftw_iodim64_do_not_use_me X(iodim64); \
\
typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \
\
typedef fftw_write_char_func_do_not_use_me X(write_char_func); \
typedef fftw_read_char_func_do_not_use_me X(read_char_func); \
\
FFTW_EXTERN void X(execute)(const X(plan) p); \
\
FFTW_EXTERN X(plan) X(plan_dft)(int rank, const int *n, \
C *in, C *out, int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_1d)(int n, C *in, C *out, int sign, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_2d)(int n0, int n1, \
C *in, C *out, int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_3d)(int n0, int n1, int n2, \
C *in, C *out, int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_many_dft)(int rank, const int *n, \
int howmany, \
C *in, const int *inembed, \
int istride, int idist, \
C *out, const int *onembed, \
int ostride, int odist, \
int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_dft)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
C *in, C *out, \
int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_split_dft)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *ri, R *ii, R *ro, R *io, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_dft)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
C *in, C *out, \
int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_split_dft)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *ri, R *ii, R *ro, R *io, \
unsigned flags); \
\
FFTW_EXTERN void X(execute_dft)(const X(plan) p, C *in, C *out); \
FFTW_EXTERN void X(execute_split_dft)(const X(plan) p, R *ri, R *ii, \
R *ro, R *io); \
\
FFTW_EXTERN X(plan) X(plan_many_dft_r2c)(int rank, const int *n, \
int howmany, \
R *in, const int *inembed, \
int istride, int idist, \
C *out, const int *onembed, \
int ostride, int odist, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_r2c)(int rank, const int *n, \
R *in, C *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_r2c_2d)(int n0, int n1, \
R *in, C *out, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_r2c_3d)(int n0, int n1, \
int n2, \
R *in, C *out, unsigned flags); \
\
\
FFTW_EXTERN X(plan) X(plan_many_dft_c2r)(int rank, const int *n, \
int howmany, \
C *in, const int *inembed, \
int istride, int idist, \
R *out, const int *onembed, \
int ostride, int odist, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_c2r)(int rank, const int *n, \
C *in, R *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_c2r_2d)(int n0, int n1, \
C *in, R *out, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_c2r_3d)(int n0, int n1, \
int n2, \
C *in, R *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_dft_r2c)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, C *out, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_dft_c2r)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
C *in, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_split_dft_r2c)( \
int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, R *ro, R *io, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_split_dft_c2r)( \
int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *ri, R *ii, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_dft_r2c)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, C *out, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_dft_c2r)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
C *in, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_split_dft_r2c)( \
int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, R *ro, R *io, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_split_dft_c2r)( \
int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *ri, R *ii, R *out, \
unsigned flags); \
\
FFTW_EXTERN void X(execute_dft_r2c)(const X(plan) p, R *in, C *out); \
FFTW_EXTERN void X(execute_dft_c2r)(const X(plan) p, C *in, R *out); \
\
FFTW_EXTERN void X(execute_split_dft_r2c)(const X(plan) p, \
R *in, R *ro, R *io); \
FFTW_EXTERN void X(execute_split_dft_c2r)(const X(plan) p, \
R *ri, R *ii, R *out); \
\
FFTW_EXTERN X(plan) X(plan_many_r2r)(int rank, const int *n, \
int howmany, \
R *in, const int *inembed, \
int istride, int idist, \
R *out, const int *onembed, \
int ostride, int odist, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_r2r)(int rank, const int *n, R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_r2r_1d)(int n, R *in, R *out, \
X(r2r_kind) kind, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_r2r_2d)(int n0, int n1, R *in, R *out, \
X(r2r_kind) kind0, X(r2r_kind) kind1, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_r2r_3d)(int n0, int n1, int n2, \
R *in, R *out, X(r2r_kind) kind0, \
X(r2r_kind) kind1, X(r2r_kind) kind2, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_r2r)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_r2r)(int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN void X(execute_r2r)(const X(plan) p, R *in, R *out); \
\
FFTW_EXTERN void X(destroy_plan)(X(plan) p); \
FFTW_EXTERN void X(forget_wisdom)(void); \
FFTW_EXTERN void X(cleanup)(void); \
\
FFTW_EXTERN void X(set_timelimit)(double t); \
\
FFTW_EXTERN void X(plan_with_nthreads)(int nthreads); \
FFTW_EXTERN int X(init_threads)(void); \
FFTW_EXTERN void X(cleanup_threads)(void); \
\
FFTW_EXTERN int X(export_wisdom_to_filename)(const char *filename); \
FFTW_EXTERN void X(export_wisdom_to_file)(FILE *output_file); \
FFTW_EXTERN char *X(export_wisdom_to_string)(void); \
FFTW_EXTERN void X(export_wisdom)(X(write_char_func) write_char, \
void *data); \
FFTW_EXTERN int X(import_system_wisdom)(void); \
FFTW_EXTERN int X(import_wisdom_from_filename)(const char *filename); \
FFTW_EXTERN int X(import_wisdom_from_file)(FILE *input_file); \
FFTW_EXTERN int X(import_wisdom_from_string)(const char *input_string); \
FFTW_EXTERN int X(import_wisdom)(X(read_char_func) read_char, void *data); \
\
FFTW_EXTERN void X(fprint_plan)(const X(plan) p, FILE *output_file); \
FFTW_EXTERN void X(print_plan)(const X(plan) p); \
\
FFTW_EXTERN void *X(malloc)(size_t n); \
FFTW_EXTERN R *X(alloc_real)(size_t n); \
FFTW_EXTERN C *X(alloc_complex)(size_t n); \
FFTW_EXTERN void X(free)(void *p); \
\
FFTW_EXTERN void X(flops)(const X(plan) p, \
double *add, double *mul, double *fmas); \
FFTW_EXTERN double X(estimate_cost)(const X(plan) p); \
FFTW_EXTERN double X(cost)(const X(plan) p); \
\
FFTW_EXTERN const char X(version)[]; \
FFTW_EXTERN const char X(cc)[]; \
FFTW_EXTERN const char X(codelet_optim)[];
/* end of FFTW_DEFINE_API macro */
FFTW_DEFINE_API(FFTW_MANGLE_DOUBLE, double, fftw_complex)
FFTW_DEFINE_API(FFTW_MANGLE_FLOAT, float, fftwf_complex)
FFTW_DEFINE_API(FFTW_MANGLE_LONG_DOUBLE, long double, fftwl_complex)
/* __float128 (quad precision) is a gcc extension on i386, x86_64, and ia64
for gcc >= 4.6 (compiled in FFTW with --enable-quad-precision) */
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) \
&& !(defined(__ICC) || defined(__INTEL_COMPILER)) \
&& (defined(__i386__) || defined(__x86_64__) || defined(__ia64__))
# if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I)
/* note: __float128 is a typedef, which is not supported with the _Complex
keyword in gcc, so instead we use this ugly __attribute__ version.
However, we can't simply pass the __attribute__ version to
FFTW_DEFINE_API because the __attribute__ confuses gcc in pointer
types. Hence redefining FFTW_DEFINE_COMPLEX. Ugh. */
# undef FFTW_DEFINE_COMPLEX
# define FFTW_DEFINE_COMPLEX(R, C) typedef _Complex float __attribute__((mode(TC))) C
# endif
FFTW_DEFINE_API(FFTW_MANGLE_QUAD, __float128, fftwq_complex)
#endif
#define FFTW_FORWARD (-1)
#define FFTW_BACKWARD (+1)
#define FFTW_NO_TIMELIMIT (-1.0)
/* documented flags */
#define FFTW_MEASURE (0U)
#define FFTW_DESTROY_INPUT (1U << 0)
#define FFTW_UNALIGNED (1U << 1)
#define FFTW_CONSERVE_MEMORY (1U << 2)
#define FFTW_EXHAUSTIVE (1U << 3) /* NO_EXHAUSTIVE is default */
#define FFTW_PRESERVE_INPUT (1U << 4) /* cancels FFTW_DESTROY_INPUT */
#define FFTW_PATIENT (1U << 5) /* IMPATIENT is default */
#define FFTW_ESTIMATE (1U << 6)
#define FFTW_WISDOM_ONLY (1U << 21)
/* undocumented beyond-guru flags */
#define FFTW_ESTIMATE_PATIENT (1U << 7)
#define FFTW_BELIEVE_PCOST (1U << 8)
#define FFTW_NO_DFT_R2HC (1U << 9)
#define FFTW_NO_NONTHREADED (1U << 10)
#define FFTW_NO_BUFFERING (1U << 11)
#define FFTW_NO_INDIRECT_OP (1U << 12)
#define FFTW_ALLOW_LARGE_GENERIC (1U << 13) /* NO_LARGE_GENERIC is default */
#define FFTW_NO_RANK_SPLITS (1U << 14)
#define FFTW_NO_VRANK_SPLITS (1U << 15)
#define FFTW_NO_VRECURSE (1U << 16)
#define FFTW_NO_SIMD (1U << 17)
#define FFTW_NO_SLOW (1U << 18)
#define FFTW_NO_FIXED_RADIX_LARGE_N (1U << 19)
#define FFTW_ALLOW_PRUNING (1U << 20)
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* FFTW3_H */
+303
View File
@@ -0,0 +1,303 @@
/**
* @file qtdsp_agc.cpp
* @brief AGC class for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-05-14
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for cuSDR by (C) 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qtdsp_agc.h"
#include <cmath>
QAGC::QAGC(QObject *parent, int size)
: QObject(parent)
, set(Settings::instance())
, m_size(size)
, m_mask(size * 2)
, m_index(0)
, m_sndex(0)
, m_hangIndex(0)
, m_fastIndex(FASTLEAD)
, m_fastHang(0)
, m_samplerate(set->getSampleRate())
//, m_agcMode(agcMED)
, m_gainTop(qPow(10.0f, 120.0f/20.0f))
, m_gainNow(1.0f)
, m_gainFastNow(1.0f)
, m_gainBottom(.001f)
, m_gainLimit(1.0f)
//, m_gainFix(pow(10.0, 60.0/20.0))
, m_gainFix(qPow(10.0f, 80.0f/20.0f))
, m_attack(0.0f)
, m_oneMAttack(0.0f)
, m_decay(0.0f)
, m_oneMDecay(0.0f)
, m_slope(1.0f)
, m_fastAttack(0.0f)
, m_oneMFastAttack(0.0f)
, m_fastDecay(0.0f)
, m_oneMFastDecay(0.0f)
, m_hangTime(480.0f * 0.001f)
, m_hangThresh(0.001f)
, m_fastHangTime(48.0f * 0.001f)
{
setAttack(1.0);
setDecay(1.0);
setMode(agcMED);
m_fastAttack = 1.0 - qExp(-1000.0 / (0.2f * m_samplerate));
m_oneMFastAttack = qExp(-1000.0 / (0.2 * m_samplerate));
m_fastDecay = 1.0 - qExp(-1000.0 / (3.0 * m_samplerate));
m_oneMFastDecay = qExp(-1000.0 / (3.0 * m_samplerate));
InitCPX(G, m_mask, 0.0f);
m_mask -= 1;
}
QAGC::~QAGC() {
G.clear();
}
void QAGC::ProcessAGC(const CPX &in, CPX &out, int size) {
if (m_agcMode == agcOFF) {
for (int i = 0; i < size; i++)
out[i] = ScaleCPX(in[i], m_gainFix);
//memcpy(out.data(), in.data(), size * sizeof(cpx));
return;
}
unsigned int hangTime = (unsigned int)(m_samplerate * m_hangTime);
unsigned int fastHangTime = (unsigned int)(m_samplerate * m_fastHangTime);
float hangThresh = 0.0;
if (m_hangThresh > 0.0)
hangThresh = m_gainTop * m_hangThresh + m_gainBottom * (1.0 - m_hangThresh);
for (int i = 0; i < m_size; i++) {
G[m_index] = in.at(i);
float tmp = 1.1 * SqrMagCPX(G.at(m_index));
if (tmp == 0.0)
tmp = m_gainNow;
else
tmp = m_gainLimit / tmp;
if (tmp < hangThresh)
m_hangIndex = hangTime;
if (tmp > m_gainNow) {
if (m_hangIndex++ > (qint16)hangTime)
m_gainNow = m_oneMDecay * m_gainNow + m_decay * qMin(m_gainTop, tmp);
}
else {
m_hangIndex = 0;
m_gainNow = m_oneMAttack * m_gainNow + m_attack * qMax(tmp, m_gainBottom);
}
tmp = 1.2 * SqrMagCPX(G[m_fastIndex]);
if (tmp != 0.0)
tmp = m_gainLimit / tmp;
else
tmp = m_gainFastNow;
if (tmp > m_gainFastNow) {
if (m_fastHang++ > (qint16)fastHangTime)
m_gainFastNow = qMin(m_oneMFastDecay * m_gainFastNow + m_fastDecay * qMin(m_gainTop, tmp), m_gainTop);
}
else {
m_fastHang = 0;
m_gainFastNow = qMax(m_oneMFastAttack * m_gainFastNow + m_fastAttack * qMax(tmp, m_gainBottom), m_gainBottom);
}
m_gainFastNow = qMax(qMin(m_gainFastNow, m_gainTop), m_gainBottom);
m_gainNow = qMax(qMin(m_gainNow, m_gainTop), m_gainBottom);
out[i].re = Scale(G.at(m_sndex).re, qMin(m_gainFastNow, qMin(m_slope * m_gainNow, m_gainTop)));
out[i].im = Scale(G.at(m_sndex).im, qMin(m_gainFastNow, qMin(m_slope * m_gainNow, m_gainTop)));
m_index = (m_index + m_mask) & m_mask;
m_sndex = (m_sndex + m_mask) & m_mask;
m_fastIndex = (m_fastIndex + m_mask) & m_mask;
}
}
void QAGC::setMode(AGCMode mode) {
mutex.lock();
m_agcMode = mode;
switch (mode) {
case agcOFF:
break;
case agcSLOW:
m_hangTime = 0.5;
m_fastHangTime = 0.1F;
m_decay = 1.0 - qExp(-2.0 / m_samplerate);
m_oneMDecay = 1.0 - m_decay;
break;
case agcMED:
m_hangTime = 0.25;
m_fastHangTime = 0.1f;
m_decay = 1.0 - qExp(-4.0 / m_samplerate);
m_oneMDecay = 1.0 - m_decay;
break;
case agcFAST:
m_hangTime = 0.1f;
m_fastHangTime = 0.1f;
m_decay = 1.0 - qExp(-10.0 / m_samplerate);
m_oneMDecay = 1.0 - m_decay;
break;
case agcLONG:
m_hangTime = 0.75;
m_fastHangTime = 0.1f;
m_decay = 1.0 - qExp(-0.5 / m_samplerate);
m_oneMDecay = 1.0 - m_decay;
break;
case agcUser:
break;
}
mutex.unlock();
}
float QAGC::gain() const {
return 20.0 * log10(m_gainNow);
}
void QAGC::setGain(float gain) {
mutex.lock();
m_gainNow = qPow(10.0, gain/20.0);
mutex.unlock();
}
float QAGC::fastGain() const {
return 20.0 * log10(m_gainFastNow);
}
float QAGC::hangTime() const {
return m_hangTime / 0.001;
}
void QAGC::setHangTime(float time) {
mutex.lock();
m_hangTime = time * 0.001;
mutex.unlock();
}
float QAGC::gainTop() const {
return 20.0 * log10(m_gainTop);
}
void QAGC::setGainTop(float gain) {
mutex.lock();
m_gainTop = qPow(10.0, gain/20.0);
mutex.unlock();
}
float QAGC::gainBottom() const {
return 20.0 * log10(m_gainBottom);
}
void QAGC::setGainBottom(float gain) {
mutex.lock();
m_gainBottom = qPow(10.0, gain/20.0);
mutex.unlock();
}
float QAGC::attack() const { return m_attack; }
void QAGC::setAttack(float attack) {
mutex.lock();
m_attack = 1.0 - qExp(-1000.0 / (attack * m_samplerate));
m_oneMAttack = qExp (-1000.0 / (attack * m_samplerate));
m_sndex = (m_index + (int)(0.003 * m_samplerate * attack)) & m_mask;
m_fastIndex = (m_sndex + FASTLEAD * m_mask) & m_mask;
m_fastHangTime = 0.1f;
mutex.unlock();
}
float QAGC::decay() const {
return m_decay;
}
void QAGC::setDecay(float decay) {
mutex.lock();
m_decay = 1.0 - qExp(-1000.0 / (decay * m_samplerate));
m_oneMDecay = qExp(-1000.0 / (decay * m_samplerate));
mutex.unlock();
}
float QAGC::fixedGain() const {
return 20.0 * log10(m_gainFix);
}
void QAGC::setFixedGain(float gain) {
mutex.lock();
m_gainFix = qPow(10.0, gain/20.0);
mutex.unlock();
}
inline float QAGC::Scale(float in_val, float scalevalue) {
return in_val * scalevalue;
}
+116
View File
@@ -0,0 +1,116 @@
/**
* @file qtdsp_agc.h
* @brief AGC header file for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-05-14
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_AGC_H
#define _QTDSP_AGC_H
#include "qtdsp_qComplex.h"
#include "../cusdr_settings.h"
//#include <QObject>
//#include <QMutex>
const int FASTLEAD = 72;
class QAGC : public QObject {
Q_OBJECT
public:
QAGC(QObject *parent = 0, int size = 0);
~QAGC();
//void ProcessAGC(CPX* in, CPX* out, int size);
void ProcessAGC(const CPX &in, CPX &out, int size);
//AGCMode Mode() const;
float gain() const;
float fastGain() const;
float hangTime() const;
float gainTop() const;
float gainBottom() const;
float attack() const;
float decay() const;
float fixedGain() const;
void setGain(float gain);
void setHangTime(float time);
void setGainTop(float gain);
void setGainBottom(float gain);
void setAttack(float attack);
void setDecay(float decay);
void setFixedGain(float gain);
public slots:
void setMode(AGCMode mode);
private:
Settings *set;
QMutex mutex;
//TReceiver m_rxData;
AGCMode m_agcMode;
CPX G;
int m_size;
qint16 m_mask;
qint16 m_index;
qint16 m_sndex;
qint16 m_hangIndex;
qint16 m_fastIndex;
qint16 m_fastHang;
float m_samplerate;
float m_gainTop;
float m_gainNow;
float m_gainFastNow;
float m_gainBottom;
float m_gainLimit;
float m_gainFix;
float m_attack;
float m_oneMAttack;
float m_decay;
float m_oneMDecay;
float m_slope;
float m_fastAttack;
float m_oneMFastAttack;
float m_fastDecay;
float m_oneMFastDecay;
float m_hangTime;
float m_hangThresh;
float m_fastHangTime;
float Scale(float in_val, float scalevalue);
};
#endif // _QTDSP_AGC_H
+274
View File
@@ -0,0 +1,274 @@
/**
* @file qtdsp_demodulation.cpp
* @brief Demodulation class for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-09-20
*/
/*
* Copyright (C) 2007, 2008 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qtdsp_demodulation.h"
Demodulation::Demodulation(QObject *parent, int size)
: QObject(parent)
, set(Settings::instance())
, m_mode((DSPMode) LSB)
, m_size(size)
, m_samplerate((float)set->getSampleRate())
, m_phase(0.0f)
, m_delay_real(0.0f)
, m_delay_imag(1.0f)
, m_alpha(0.3f * 500.0f * TWOPI / m_samplerate)
, m_beta(m_alpha * m_alpha * 0.25f)
, m_lockcurrent(0.5f)
, m_lockprevious(1.0f)
, m_dc(0.0f)
, m_afc(0.0f)
, m_cvt(0.45f * m_samplerate / (ONEPI * 500.0))
, m_smooth(0.0f)
, m_twopi_over_sr(TWOPI/m_samplerate)
, m_cvt_sr_mult((0.45f * m_samplerate) / ONEPI)
, m_pll_lo_limit(-1000.0f)
, m_pll_hi_limit(1000.0f)
, m_pll_bandwidth(500.0f)
, m_pll_frequency(0.0f)
{
setDemodMode((DSPMode) LSB);
delay0.re = 0.0f;
delay0.im = 0.0f;
tmp0.re = 0.0f;
tmp0.im = 0.0f;
}
Demodulation::~Demodulation() {
}
void Demodulation::ProcessBlock(CPX &in, CPX &out, int bsize) {
Q_UNUSED(bsize)
switch(m_mode) {
case (DSPMode) AM:
DoMagnitude(in, out);
break;
case (DSPMode) SAM:
DoSAM(in, out);
break;
case (DSPMode)FMN:
DoFMN(in, out);
break;
//case (DSPMode) FMW:
//DoFMN(in, out);
//break;
default:
memcpy(out.data(), in.data(), sizeof(cpx) * m_size);
break;
}
}
inline void Demodulation::DoMagnitude(CPX &in, CPX &out) {
for (int i = 0; i < m_size; i++) {
float magn = SqrMagCPX(in.at(i));
out[i].re = magn;
out[i].im = magn;
}
}
void Demodulation::DoSAM(CPX &in, CPX &out ) {
float difference;
for (int i = 0; i < m_size; i++) {
tmp0.re = qCos(m_phase);
tmp0.im = qSin(m_phase);
delay0.re = tmp0.re * in.at(i).re + tmp0.im * in.at(i).im;
delay0.im = -tmp0.im * in.at(i).re + tmp0.re * in.at(i).im;
if ((delay0.im) == 0.0 && (delay0.re == 0.0)) {
delay0.re = 0.000000000001;
}
difference = sqrt(in.at(i).re * in.at(i).re + in.at(i).im * in.at(i).im) * (qAtan2(delay0.im, delay0.re));
m_pll_frequency += m_beta * difference;
if (m_pll_frequency < m_pll_lo_limit)
m_pll_frequency = m_pll_lo_limit;
if (m_pll_frequency > m_pll_hi_limit)
m_pll_frequency = m_pll_hi_limit;
m_phase += m_pll_frequency + m_alpha * difference;
while (m_phase >= TWOPI)
m_phase -= TWOPI;
while (m_phase < 0)
m_phase += TWOPI;
m_lockcurrent = 0.999 * m_lockcurrent + 0.001 * qAbs(delay0.re);
m_lockprevious = m_lockcurrent;
m_dc = (0.999 * m_dc) + (0.001 * delay0.re);
out[i].re = delay0.re - m_dc;
out[i].im = out.at(i).re;
}
}
void Demodulation::DoFMN(CPX &in, CPX &out ) {
float difference;
for (int i = 0; i < m_size; i++) {
tmp0.re = qCos(m_phase);
tmp0.im = qSin(m_phase);
delay0.re = tmp0.re * in.at(i).re + tmp0.im * in.at(i).im;
delay0.im = -tmp0.im * in.at(i).re + tmp0.re * in.at(i).im;
if ((delay0.im) == 0.0 && (delay0.re == 0.0)) {
delay0.re = 0.000000000001;
}
difference = qAtan2(delay0.im, delay0.re);
m_pll_frequency += m_beta * difference;
if (m_pll_frequency < m_pll_lo_limit)
m_pll_frequency = m_pll_lo_limit;
if (m_pll_frequency > m_pll_hi_limit)
m_pll_frequency = m_pll_hi_limit;
m_phase += m_pll_frequency + m_alpha * difference;
while (m_phase >= TWOPI)
m_phase -= TWOPI;
while (m_phase < 0)
m_phase += TWOPI;
m_afc = 0.99 * m_afc + 0.01 * m_pll_frequency;
out[i].re = (m_pll_frequency - m_afc) * m_cvt;
out[i].im = out.at(i).re;
}
}
void Demodulation::DoFMW(CPX &in, CPX &out ) {
memcpy(out.data(), in.data(), sizeof(CPX) * m_size);
}
void Demodulation::setDemodMode(DSPMode mode) {
m_mode = mode;
switch(m_mode) {
case AM: // AM
break;
case SAM: // SAM
m_pll_bandwidth = 500.0;
m_alpha = 0.3 * m_pll_bandwidth * m_twopi_over_sr;
m_beta = m_alpha * m_alpha * 0.25;
m_cvt = m_cvt_sr_mult / m_pll_bandwidth;
break;
case FMN: // FMN
m_pll_bandwidth = 10000.0;
m_alpha = 0.3 * m_pll_bandwidth * m_twopi_over_sr;
m_beta = m_alpha * m_alpha * 0.25;
m_cvt = m_cvt_sr_mult / m_pll_bandwidth;
break;
// case dmFMW: // FMW
// m_pll_bandwidth = 90000.0;
// m_alpha = 0.3 * m_pll_bandwidth * m_twopi_over_sr;
// m_beta = m_alpha * m_alpha * 0.25;
// m_cvt = m_cvt_sr_mult / m_pll_bandwidth;
// break;
case CWL:
break;
case CWU:
break;
case DIGL:
break;
case DIGU:
break;
case DSB:
break;
case LSB:
break;
case USB:
break;
default:
//std::cout << "Unknown mode:" << m_mode << std::endl;
break;
}
}
DSPMode Demodulation::demodMode() const {
return m_mode;
}
void Demodulation::setSampleRate(QObject *sender, int value) {
Q_UNUSED(sender)
m_samplerate = value;
m_alpha = 0.3f * 500.0f * TWOPI / m_samplerate;
m_beta = m_alpha * m_alpha * 0.25f;
m_cvt = 0.45f * m_samplerate / (ONEPI * 500.0f);
m_twopi_over_sr = TWOPI / m_samplerate;
m_cvt_sr_mult = (0.45f * m_samplerate) / ONEPI;
}
+90
View File
@@ -0,0 +1,90 @@
/**
* @file qtdsp_demodulation.h
* @brief Demodulation header file for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-09-20
*/
/*
* Copyright (C) 2007, 2008 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_DEMODULATION_H
#define _QTDSP_DEMODULATION_H
#include <cmath>
#include "qtdsp_qComplex.h"
#include "../cusdr_settings.h"
class Demodulation : public QObject {
Q_OBJECT
public:
Demodulation(QObject *parent = 0, int size = 0);
~Demodulation();
void ProcessBlock(CPX &in, CPX &out, int bsize);
DSPMode demodMode() const;
public slots:
void setDemodMode(DSPMode mode);
void setSampleRate(QObject *sender, int value);
private:
Settings *set;
cpx tmp0;
cpx delay0;
DSPMode m_mode;
int m_size;
float m_samplerate;
float m_phase;
float m_delay_real;
float m_delay_imag;
float m_alpha;
float m_beta;
float m_lockcurrent;
float m_lockprevious;
float m_dc;
float m_afc;
float m_cvt;
float m_smooth;
float m_twopi_over_sr;
float m_cvt_sr_mult;
float m_pll_lo_limit;
float m_pll_hi_limit;
float m_pll_bandwidth;
float m_pll_frequency;
void DoMagnitude(CPX &in, CPX &out);
void DoSAM(CPX &in, CPX &out);
void DoFMN(CPX &in, CPX &out);
void DoFMW(CPX &in, CPX &out);
};
#endif // _QTDSP_DEMODULATION_H
+392
View File
@@ -0,0 +1,392 @@
/**
* @file qtdsp_dspEngine.cpp
* @brief QtDSP DSP engine class
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-04-07
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* The ProcessFrequencyShift method is adpated from cuteSDR by (C) Moe Wheatley, AE4JY.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define LOG_DSP_ENGINE
// use: DSP_ENGINE_DEBUG << "debug message";
#include "qtdsp_dspEngine.h"
QDSPEngine::QDSPEngine(QObject *parent, int rx, int size)
: QObject(parent)
, set(Settings::instance())
, m_qtdspOn(false)
, m_rx(rx)
, m_size(size)
, m_samplerate(set->getSampleRate())
, m_fftMultiplcator(1)
, m_volume(0.0f)
{
qRegisterMetaType<QVector<cpx> >();
qRegisterMetaType<CPX>();
fft = new QFFT(m_size);
filter = new QFilter(this, m_size, 2, 12);//8);
wpagc = new QWPAGC(this, m_size);
spectrum = new PowerSpectrum(this, m_size*2);
QString str = "Initializing DSP engine for rx %1: 8k FFT ...please wait";
set->setSystemMessage(str.arg(m_rx), 0);
if (m_rx == 0) {
spectrum2 = new PowerSpectrum(this, m_size*4);
str = "Initializing DSP engine for rx %1: 16k FFT ...please wait";
set->setSystemMessage(str.arg(m_rx), 0);
spectrum4 = new PowerSpectrum(this, m_size*8);
str = "Initializing DSP engine for rx %1: 32k FFT ...please wait";
set->setSystemMessage(str.arg(m_rx), 0);
spectrum8 = new PowerSpectrum(this, m_size*16);
}
m_spectrumSize = m_size*4;
signalmeter = new SignalMeter(this, m_size);
demod = new Demodulation(this, m_size);
m_rxData = set->getReceiverDataList().at(rx);
m_agcMode = m_rxData.agcMode;
wpagc->setReceiver(m_rx);
InitCPX(tmp1CPX, m_size, 0.0f);
InitCPX(tmp2CPX, m_size, 0.0f);
osc1cpx.re = 1.0f;
osc1cpx.im = 0.0f;
m_NcoInc = 0.0;
m_NcoTime = 0.0;
m_NcoFreq = 0.0;
m_CWoffset = 0.0;
//DSP_ENGINE_DEBUG << "set NCO to " << m_rxData.vfoFrequency - m_rxData.ctrFrequency;
setNCOFrequency(m_rx, m_rxData.vfoFrequency - m_rxData.ctrFrequency);
DSP_ENGINE_DEBUG << "init DSPEngine with size: " << m_size;
SleeperThread::msleep(100);
setupConnections();
}
QDSPEngine::~QDSPEngine() {
tmp1CPX.clear();
tmp2CPX.clear();
//if (agc)
// delete agc;
if (fft)
delete fft;
if (filter)
delete filter;
if (wpagc)
delete wpagc;
if (spectrum)
delete spectrum;
if (signalmeter)
delete signalmeter;
if (demod)
delete demod;
}
void QDSPEngine::setupConnections() {
CHECKED_CONNECT(
set,
SIGNAL(ncoFrequencyChanged(int, long)),
this,
SLOT(setNCOFrequency(int, long)));
CHECKED_CONNECT(
set,
SIGNAL(sampleSizeChanged(int, int)),
this,
SLOT(setSampleSize(int, int)));
CHECKED_CONNECT(
wpagc,
SIGNAL(agcMaximumGainChanged(qreal)),
this,
SLOT(setAGCMaximumGain(qreal)));
CHECKED_CONNECT(
wpagc,
SIGNAL(agcHangThresholdChanged(qreal)),
this,
SLOT(setAGCHangThreshold(qreal)));
// CHECKED_CONNECT(
// wpagc,
// SIGNAL(hangLeveldBLineChanged(qreal)),
// this,
// SLOT(setAGCHangLeveldBLine(qreal)));
//
// CHECKED_CONNECT(
// wpagc,
// SIGNAL(minimumVoltageChanged(QObject *, int, qreal)),
// this,
// SLOT(setAGCThresholdLine(QObject *, int, qreal)));
CHECKED_CONNECT(
wpagc,
SIGNAL(displayValues(QObject *, int, qreal, qreal)),
this,
SLOT(setAGCLineValues(QObject *, int, qreal, qreal)));
}
void QDSPEngine::processDSP(CPX &in, CPX &out, int size) {
m_mutex.lock();
switch (m_fftMultiplcator) {
case 1:
spectrum->ProcessSpectrum(in, size*2, 1);
break;
case 2:
spectrum2->ProcessSpectrum(in, size*4, 3);
break;
case 4:
spectrum4->ProcessSpectrum(in, size*8, 7);
break;
case 8:
spectrum8->ProcessSpectrum(in, size*16, 15);
break;
}
if (m_NcoFreq != 0)
ProcessFrequencyShift(in, in, size);
filter->ProcessFilter(in, tmp1CPX, size);
signalmeter->ProcessBlock(tmp1CPX, size);
wpagc->ProcessAGC(tmp1CPX, tmp2CPX, size);
demod->ProcessBlock(tmp2CPX, out, size);
//memcpy(out.data(), in.data(), size * sizeof(cpx));
//out = in;
for (int i = 0; i < size; i++) {
out[i] = ScaleCPX(out.at(i), m_volume);
}
m_mutex.unlock();
}
int QDSPEngine::getSpectrum(qVectorFloat &buffer, int mult) {
if (m_rx == 0) {
m_fftMultiplcator = mult;
switch (m_fftMultiplcator) {
case 1:
return spectrum->spectrumResult(buffer, 0);
break;
case 2:
return spectrum2->spectrumResult(buffer, 2048);
break;
case 4:
return spectrum4->spectrumResult(buffer, 6144);
break;
case 8:
return spectrum8->spectrumResult(buffer, 14336);
break;
default:
return spectrum->spectrumResult(buffer, 0);
break;
}
}
else {
return spectrum->spectrumResult(buffer, 0);
}
}
float QDSPEngine::getSMeterInstValue() {
return signalmeter->getInstFValue();
}
void QDSPEngine::setVolume(float value) {
if (m_volume == value) return;
m_volume = value;
}
void QDSPEngine::setQtDSPStatus(bool value) {
m_qtdspOn = value;
}
void QDSPEngine::setDSPMode(DSPMode mode) {
demod->setDemodMode(mode);
}
void QDSPEngine::setAGCMode(AGCMode mode) {
wpagc->setMode(mode);
}
void QDSPEngine::setAGCMaximumGain(qreal value) {
qreal maxGain = 20.0 * log10(value);
set->setAGCMaximumGain_dB(this, m_rx, maxGain);
}
void QDSPEngine::setAGCHangThreshold(qreal value) {
set->setAGCHangThresholdSlider(this, m_rx, value);
}
void QDSPEngine::setAGCLineValues(QObject *sender, int rx, qreal thresh, qreal hang) {
if (m_rx != rx) return;
qreal noiseOffset = 10.0 * log10(qAbs(filter->filterHi() - filter->filterLo()) * 2 * m_size / m_samplerate);
qreal threshold = 20.0 * log10(thresh) - noiseOffset + AGCOFFSET;
set->setAGCLineLevels(sender, m_rx, threshold, hang + AGCOFFSET);
}
void QDSPEngine::setSampleRate(QObject *sender, int value) {
Q_UNUSED(sender)
if (m_samplerate == value) return;
m_mutex.lock();
switch (value) {
case 48000:
m_samplerate = value;
break;
case 96000:
m_samplerate = value;
break;
case 192000:
m_samplerate = value;
break;
case 384000:
m_samplerate = value;
break;
default:
DSP_ENGINE_DEBUG << "invalid sample rate (possible values are: 48, 96, 192, or 384 kHz)!\n";
break;
}
//DSP_ENGINE_DEBUG << "set sample rate to " << m_samplerate;
//setNCOFrequency(m_rx, m_rxData.vfoFrequency - m_rxData.ctrFrequency);
m_NcoInc = TWOPI * m_NcoFreq/m_samplerate;
m_OscCos = qCos(m_NcoInc);
m_OscSin = qSin(m_NcoInc);
filter->setSampleRate(this, m_samplerate);
demod->setSampleRate(this, m_samplerate);
wpagc->setSampleRate(this, m_samplerate);
m_mutex.unlock();
}
void QDSPEngine::setNCOFrequency(int rx, long ncoFreq) {
if (m_rx != rx) return;
qreal tmp = ncoFreq + m_CWoffset;
m_NcoFreq = tmp;
m_NcoInc = TWOPI * m_NcoFreq/m_samplerate;
m_OscCos = qCos(m_NcoInc);
m_OscSin = qSin(m_NcoInc);
//DSP_ENGINE_DEBUG << "NCO: " << m_NcoFreq;
}
void QDSPEngine::setSampleSize(int rx, int size) {
Q_UNUSED(rx)
if (m_rx == 0) {
m_mutex.lock();
m_spectrumSize = size;
m_mutex.unlock();
}
}
void QDSPEngine::ProcessFrequencyShift(CPX &in, CPX &out, int size) {
cpx tmp;
CPX Osc;
Osc.resize(size);
for (int i = 0; i < size; i++) {
tmp = in.at(i);
qreal OscGn;
Osc[i].re = osc1cpx.re * m_OscCos - osc1cpx.im * m_OscSin;
Osc[i].im = osc1cpx.im * m_OscCos + osc1cpx.re * m_OscSin;
OscGn = 1.95 - (osc1cpx.re * osc1cpx.re + osc1cpx.im * osc1cpx.im);
osc1cpx.re = OscGn * Osc.at(i).re;
osc1cpx.im = OscGn * Osc.at(i).im;
//Cpx multiply by shift frequency
out[i].re = ((tmp.re * Osc.at(i).re) - (tmp.im * Osc.at(i).im));
out[i].im = ((tmp.re * Osc.at(i).im) + (tmp.im * Osc.at(i).re));
}
}
+133
View File
@@ -0,0 +1,133 @@
/**
* @file qtdsp_dspEngine.h
* @brief header file for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-04-07
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_DSP_ENGINE_H
#define _QTDSP_DSP_ENGINE_H
#define AGCOFFSET -18.0//-63.0
//#include <QObject>
//#include <QThread>
//#include <QMetaType>
//#include <QMutexLocker>
//#include <QMutex>
//#include <QWaitCondition>
//#include <QVariant>
//#include <QElapsedTimer>
#include "../cusdr_settings.h"
#include "qtdsp_qComplex.h"
#include "qtdsp_filter.h"
#include "qtdsp_fft.h"
#include "qtdsp_wpagc.h"
#include "qtdsp_powerSpectrum.h"
#include "qtdsp_signalMeter.h"
#include "qtdsp_demodulation.h"
#ifdef LOG_DSP_ENGINE
# define DSP_ENGINE_DEBUG qDebug().nospace() << "DSPEngine::\t"
#else
# define DSP_ENGINE_DEBUG nullDebug()
#endif
class QDSPEngine : public QObject {
Q_OBJECT
public:
QDSPEngine(QObject* parent = 0, int rx = 0, int size = 0);
~QDSPEngine();
QFFT* fft;
QFilter* filter;
QWPAGC* wpagc;
PowerSpectrum* spectrum;
PowerSpectrum* spectrum2;
PowerSpectrum* spectrum4;
PowerSpectrum* spectrum8;
SignalMeter* signalmeter;
Demodulation* demod;
void processDSP(CPX &in, CPX &out, int size);
int getSpectrum(qVectorFloat &buffer, int mult);
float getSMeterInstValue();
public slots:
bool getQtDSPStatus() { return m_qtdspOn; }
void setNCOFrequency(int rx, long value);
void setSampleRate(QObject *sender, int value);
void setSampleSize(int rx, int size);
void setQtDSPStatus(bool value);
void setVolume(float value);
void setDSPMode(DSPMode mode);
void setAGCMode(AGCMode mode);
private:
Settings* set;
TReceiver m_rxData;
AGCMode m_agcMode;
CPX tmp1CPX;
CPX tmp2CPX;
cpx osc1cpx;
QMutex m_mutex;
bool m_qtdspOn;
int m_rx;
int m_size;
int m_spectrumSize;
int m_samplerate;
int m_fftMultiplcator;
float m_volume;
qreal m_NcoFreq;
qreal m_NcoInc;
qreal m_NcoTime;
qreal m_CWoffset;
qreal m_OscCos;
qreal m_OscSin;
//qreal m_calOffset;
void ProcessFrequencyShift(CPX &in, CPX &out, int size);
void setupConnections();
private slots:
void setAGCMaximumGain(qreal);
void setAGCHangThreshold(qreal);
//void setAGCHangLeveldBLine(qreal value);
//void setAGCThresholdLine(QObject *sender, int rx, qreal value);
void setAGCLineValues(QObject *sender, int rx, qreal thresh, qreal hang);
};
#endif // _QTDSP_DSP_ENGINE_H
+116
View File
@@ -0,0 +1,116 @@
/**
* @file qtdsp_dualModeAverager.cpp
* @brief Dual mode averager class for QtDSP;
Dual-Mode Averaging implmemented following "Understanding Digital Signal Processing" by Richard G. Lyons, 3rd ed., p.791
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-07-12
*/
/*
*
* Copyright 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qtdsp_dualModeAverager.h"
DualModeAverager::DualModeAverager(int rx, int size)
: QObject()
, set(Settings::instance())
, m_receiver(rx)
, m_size(size)
, m_length(set->getSpectrumAveragingCnt(m_receiver))
{
m_tmp.resize(m_size);
m_tmp.fill(-20.0);
cnt = 0;
k = 1.0f/m_length;
CHECKED_CONNECT(
set,
SIGNAL(spectrumAveragingCntChanged(QObject*, int, int)),
this,
SLOT(setAveragingLength(QObject*, int, int)));
/*CHECKED_CONNECT(
set,
SIGNAL(widebandAveragingCntChanged(QObject*, int)),
this,
SLOT(setWidebandAveragingLength(QObject*, int)));*/
}
DualModeAverager::~DualModeAverager() {
m_tmp.clear();
}
void DualModeAverager::ProcessDBAverager(qVectorFloat &in, qVectorFloat &out) {
mutex.lock();
if (cnt < m_length) {
for (int i = 0; i < m_size; i++)
out[i] = m_tmp.at(i) + k * in.at(i);
cnt++;
}
else {
for (int i = 0; i < m_size; i++)
out[i] = m_tmp.at(i) + k * (in.at(i) - m_tmp.at(i));
}
mutex.unlock();
m_tmp = out;
}
void DualModeAverager::setAveragingLength(QObject* sender, int rx, int value) {
Q_UNUSED (sender)
if (m_receiver != rx) return;
mutex.lock();
m_length = value;
k = 1.0f/m_length;
cnt = 0;
m_tmp.fill(0.0f);
mutex.unlock();
}
//void DualModeAverager::setWidebandAveragingLength(QObject* sender, int value) {
//
// Q_UNUSED (sender)
//
// mutex.lock();
// m_length = value;
// k = 1.0f/m_length;
// cnt = 0;
//
// m_tmp.fill(0.0f);
// mutex.unlock();
//}
void DualModeAverager::clearBuffer() {
m_tmp.clear();
m_tmp.resize(m_size);
m_tmp.fill(-20.0);
}
+64
View File
@@ -0,0 +1,64 @@
/**
* @file qtdsp_dualModeAverager.h
* @brief Dual mode averager header file for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-07-12
*/
/*
*
* Copyright 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_DUAL_MODE_AVERAGER_H
#define _QTDSP_DUAL_MODE_AVERAGER_H
#include <QObject>
#include "../cusdr_settings.h"
class DualModeAverager : public QObject {
Q_OBJECT
public:
DualModeAverager(int rx = 0, int size = 0);
~DualModeAverager();
void ProcessDBAverager(qVectorFloat &in, qVectorFloat &out);
void clearBuffer();
//void setAveragingLength(int value);
private:
Settings* set;
QMutex mutex;
qVectorFloat m_tmp;
int m_receiver;
int m_size;
int m_length;
int cnt;
float k;
private slots:
void setAveragingLength(QObject* sender, int rx, int value);
//void setWidebandAveragingLength(QObject* sender, int value);
};
#endif // _QTDSP_DUAL_MODE_AVERAGER_H
+90
View File
@@ -0,0 +1,90 @@
/**
* @file qtdsp_fft.cpp
* @brief QFFT FFTW class for QtDSP
* @author by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-02-18
*/
/*
* Copyright (C) 2007, 2008 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qtdsp_fft.h"
#include <string.h>
#include <QDebug>
QFFT::QFFT(int size)
: QObject()
, m_size(size)
, half_sz(size/2)
{
cpxbuf = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * m_size);
plan_fwd = fftwf_plan_dft_1d(m_size , cpxbuf, cpxbuf, FFTW_FORWARD, FFTW_MEASURE);
plan_rev = fftwf_plan_dft_1d(m_size , cpxbuf, cpxbuf, FFTW_BACKWARD, FFTW_MEASURE);
memset(cpxbuf, 0, m_size * sizeof(cpxbuf));
InitCPX(buf, m_size, 0.0f);
}
QFFT::~QFFT() {
fftwf_destroy_plan(plan_fwd);
fftwf_destroy_plan(plan_rev);
if (cpxbuf)
fftwf_free(cpxbuf);
buf.clear();
}
void QFFT::DoFFTWForward(CPX &in, CPX &out, int size) {
memcpy(cpxbuf, in.data(), sizeof(cpx) * size);
fftwf_execute(plan_fwd);
memcpy(out.data(), cpxbuf, sizeof(cpx) * size);
}
void QFFT::DoFFTWInverse(CPX &in, CPX &out, int size) {
memcpy(cpxbuf, in.data(), sizeof(cpx) * size);
fftwf_execute(plan_rev);
memcpy(out.data(), cpxbuf, sizeof(cpx) * size);
}
void QFFT::DoFFTWMagnForward(CPX &in, int size, float baseline, float correction, float *fbr) {
memcpy(cpxbuf, in.data(), sizeof(cpx) * size);
fftwf_execute(plan_fwd);
for (int i = 0, j = size-1; i < size; i++, j--) {
*(buf.data()+j) = *(cpx *)(cpxbuf+i);
}
for (int i = 0, j = half_sz; i < half_sz; i++, j++) {
*(fbr+i) = 10.0 * log10(MagCPX(*(buf.data()+j)) + baseline) + correction;
*(fbr+j) = 10.0 * log10(MagCPX(*(buf.data()+i)) + baseline) + correction;
}
}
+91
View File
@@ -0,0 +1,91 @@
/**
* @file qtdsp_fft.cpp
* @brief QFFT FFTW class for QtDSP
* @author by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-02-18
*/
/*
* Copyright (C) 2007, 2008 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qtdsp_fft.h"
#include <string.h>
#include <QDebug>
QFFT::QFFT(int size)
: QObject()
, m_size(size)
, half_sz(size/2)
{
cpxbuf = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * m_size);
plan_fwd = fftwf_plan_dft_1d(m_size , cpxbuf, cpxbuf, FFTW_FORWARD, FFTW_MEASURE);
plan_rev = fftwf_plan_dft_1d(m_size , cpxbuf, cpxbuf, FFTW_BACKWARD, FFTW_MEASURE);
memset(cpxbuf, 0, m_size * sizeof(cpxbuf));
InitCPX(buf, m_size, 0.0f);
}
QFFT::~QFFT() {
fftwf_destroy_plan(plan_fwd);
fftwf_destroy_plan(plan_rev);
if (cpxbuf)
fftwf_free(cpxbuf);
buf.clear();
}
void QFFT::DoFFTWForward(CPX &in, CPX &out, int size) {
memcpy(cpxbuf, in.data(), sizeof(cpx) * size);
fftwf_execute(plan_fwd);
memcpy(out.data(), cpxbuf, sizeof(cpx) * size);
}
void QFFT::DoFFTWInverse(CPX &in, CPX &out, int size) {
memcpy(cpxbuf, in.data(), sizeof(cpx) * size);
fftwf_execute(plan_rev);
memcpy(out.data(), cpxbuf, sizeof(cpx) * size);
}
void QFFT::DoFFTWMagnForward(CPX &in, int size, float baseline, float correction, float *fbr) {
memcpy(cpxbuf, in.data(), sizeof(cpx) * size);
fftwf_execute(plan_fwd);
for (int i = 0, j = size-1; i < size; i++, j--) {
*(buf.data()+j) = *(cpx *)(cpxbuf+i);
}
for (int i = 0, j = half_sz; i < half_sz; i++, j++) {
*(fbr+i) = 10.0 * log10(MagCPX(*(buf.data()+j)) + baseline) + correction;
*(fbr+j) = 10.0 * log10(MagCPX(*(buf.data()+i)) + baseline) + correction;
}
}
+64
View File
@@ -0,0 +1,64 @@
/**
* @file qtdsp_fft.h
* @brief QFFT header FFTW for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-02-18
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_FFT_H
#define _QTDSP_FFT_H
#include <QObject>
#include <cmath>
#include "fftw3.h"
#include "qtdsp_qComplex.h"
class QFFT : public QObject {
Q_OBJECT
public:
QFFT(int size = 0);
~QFFT();
public slots:
void DoFFTWForward(CPX &in, CPX &out, int size);
void DoFFTWInverse(CPX &in, CPX &out, int size);
void DoFFTWMagnForward(CPX &in, int size, float baseline, float correction, float* fbr);
private:
fftwf_complex *cpxbuf;
fftwf_plan plan_fwd;
fftwf_plan plan_rev;
CPX buf;
int m_size;
int half_sz;
};
#endif // _QTDSP_FFT_H
+64
View File
@@ -0,0 +1,64 @@
/**
* @file qtdsp_fft.h
* @brief QFFT header FFTW for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-02-18
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_FFT_H
#define _QTDSP_FFT_H
#include <QObject>
#include <cmath>
#include <cufftw.h>
#include "qtdsp_qComplex.h"
class QFFT : public QObject {
Q_OBJECT
public:
QFFT(int size = 0);
~QFFT();
public slots:
void DoFFTWForward(CPX &in, CPX &out, int size);
void DoFFTWInverse(CPX &in, CPX &out, int size);
void DoFFTWMagnForward(CPX &in, int size, float baseline, float correction, float* fbr);
private:
fftwf_complex *cpxbuf;
fftwf_plan plan_fwd;
fftwf_plan plan_rev;
CPX buf;
int m_size;
int half_sz;
};
#endif // _QTDSP_FFT_H
+682
View File
@@ -0,0 +1,682 @@
/**
* @file qtdsp_filter.cpp
* @brief Filter class for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-02-18
*/
/*
* Copyright (C) 2007, 2008 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qtdsp_filter.h"
//#include <cstring>
#define LOG_QTDSP_FILTER
// use: FILTER_DEBUG
#ifndef NULL
#define NULL 0
#endif
QFilter::QFilter(QObject *parent, int size, const int ftype, const int wtype)
: QObject(parent)
, set(Settings::instance())
, m_streamMode(true)
, m_size(size)
, m_ftype(ftype)
, m_wtype(wtype)
, m_samplerate(set->getSampleRate())
, m_filter_lo(-3050.0f)
, m_filter_hi(-150.0f)
{
InitCPX(ovlp, m_size, 0.0f);
InitCPX(tmp, m_size, 0.0f);
InitCPX(res, m_size, 0.0f);
InitCPX(filter, m_size * 2, 0.0f);
InitCPX(tmp0, m_size * 2, 0.0f);
InitCPX(tmp1, m_size * 2, 0.0f);
InitCPX(tmp2, m_size * 2, 0.0f);
InitCPX(tmpfilt0, m_size * 2, 0.0f);
InitCPX(tmpfilt1, m_size * 2, 0.0f);
ovlpfft = new QFFT(m_size * 2);
filtfft = new QFFT(m_size * 2);
MakeFilter(m_filter_lo, m_filter_hi, m_ftype, m_wtype);
}
QFilter::~QFilter() {
if (ovlpfft) delete ovlpfft;
if (filtfft) delete filtfft;
ovlp.clear();
filter.clear();
tmpfilt0.clear();
tmpfilt1.clear();
tmp.clear();
tmp0.clear();
tmp1.clear();
}
void QFilter::DoConvolutionCPX() {
mutex.lock();
for (int i = 0; i < m_size * 2; i++) //convolution in frequency space here
{
tmp0[i].re = (filter.at(i).re * tmp1.at(i).re) - (filter.at(i).im * tmp1.at(i).im);
tmp0[i].im = (filter.at(i).re * tmp1.at(i).im) + (filter.at(i).im * tmp1.at(i).re);
}
mutex.unlock();
}
void QFilter::DoOverlapAddCPX() {
//SSEAddCPX(tmp0, tmp1, ovlp, m_size);
for (int i = 0; i < m_size; i++) {
//tmp0[i] = AddCPX(tmp1.at(i), ovlp.at(i));
//ovlp[i] = tmp1.at(i + m_size);
res[i] = AddCPX(tmp2.at(i), ovlp.at(i));
ovlp[i] = tmp2.at(i + m_size);
}
}
void QFilter::ProcessFilter(CPX &in, CPX &out, int bsize) {
Q_UNUSED (bsize)
memcpy(tmp0.data(), in.data(), sizeof(cpx) * m_size);
ovlpfft->DoFFTWForward(tmp0, tmp1, m_size * 2);
DoConvolutionCPX();
ovlpfft->DoFFTWInverse(tmp0, tmp1, m_size * 2);
if (m_streamMode) {
//Normalize(tmp1, tmp2, m_size * 2);
// Overlap-Add
for (int i = 0; i < m_size; i++) {
out[i] = AddCPX(tmp1.at(i), ovlp.at(i));
ovlp[i] = tmp1.at(i + m_size);
}
//DoOverlapAddCPX();
//Normalize(tmp0, out, m_size * 2);
//memcpy(out.data(), res.data(), sizeof(cpx) * m_size);
}
else {
memcpy(out.data(), tmp1.data(), sizeof(cpx) * m_size);
}
}
void QFilter::ProcessChirpFilter(CPX &in, CPX &out, int bsize) {
Q_UNUSED(in)
Q_UNUSED(out)
Q_UNUSED(bsize)
}
void QFilter::ProcessForwardFilter(CPX &in, CPX &out, int bsize) {
Q_UNUSED (bsize)
//memcpy(tmp0, in, sizeof(CPX) * m_size);
memcpy(tmp0.data(), in.data(), sizeof(cpx) * m_size);
ovlpfft->DoFFTWForward(tmp0, tmp1, m_size * 2);
DoConvolutionCPX();
//ovlpfft->DoFFTWInverse(tmp0, tmp1, m_size * 2);
if (m_streamMode) {
DoOverlapAddCPX();
//memcpy(out, tmp0, sizeof(CPX) * m_size);
memcpy(out.data(), tmp0.data(), sizeof(cpx) * m_size);
}
else {
//memcpy(out, tmp1, sizeof(CPX) * m_size);
memcpy(out.data(), tmp1.data(), sizeof(cpx) * m_size);
}
}
int QFilter::ProcessAndDecimate(CPX &in, CPX &out, int bsize) {
Q_UNUSED(in)
Q_UNUSED(bsize)
//memset(tmp0, 0, sizeof(CPX) * m_size * 2);
//memset(tmp1, 0, sizeof(CPX) * m_size * 2);
//memcpy(tmp0, in, sizeof(CPX) * m_size);
tmp0.resize(m_size * 2);
tmp1.resize(m_size * 2);
tmp0.resize(m_size);
ovlpfft->DoFFTWForward(tmp0, tmp1, m_size * 2);
DoConvolutionCPX();
ovlpfft->DoFFTWInverse(tmp0, tmp1, m_size * 2);
if (m_streamMode) {
DoOverlapAddCPX();
for (int i = 0, j = 0; i < m_size; i+=2, j++) {
*(out.data()+j) = *(tmp0.data()+i);
}
}
else {
for (int i = 0, j = 0; i < m_size; i+=2, j++) {
*(out.data()+j) = *(tmp1.data()+i);
}
}
return m_size/2;
}
void QFilter::Normalize(CPX &in, CPX &out, int size) {
float norm = 1.0f/size;
for (int i = 0; i < size; i++) {
out[i].re = in.at(i).re * norm;
out[i].im = in.at(i).im * norm;
}
}
void QFilter::Decimate(CPX &in, CPX &out, int downrate) {
int newsize = qRound((float) m_size/downrate);
//memset(out, 0, newsize * sizeof(CPX));
//memset(tmp, 0, m_size * sizeof(CPX));
out.resize(newsize);
tmp.resize(m_size);
//memcpy(tmp, in, m_size * sizeof(CPX));
memcpy(tmp.data(), in.data(), m_size * sizeof(cpx));
for (int j = 0; j < newsize; j++) {
for (int k = 0; k < downrate; k++) {
//for (int k = 0; k < downrate - 1; k++) {
if (j * downrate + k < m_size) {
out[j].re += tmp.at(j * downrate + k).re;
out[j].im += tmp.at(j * downrate + k).im;
}
}
}
}
void QFilter::setSampleRate(QObject *sender, int value) {
Q_UNUSED(sender)
m_samplerate = (float)value;
//FILTER_DEBUG << "set sample rate to " << m_samplerate;
MakeFilter(m_filter_lo, m_filter_hi, m_ftype, m_wtype);
}
void QFilter::setFilterLo(const float value) {
if (value != m_filter_lo) {
m_filter_lo = value;
MakeFilter(m_filter_lo, m_filter_hi, m_ftype, m_wtype);
}
}
void QFilter::setFilterHi(const float value) {
if (value != m_filter_hi) {
m_filter_hi = value;
MakeFilter(m_filter_lo, m_filter_hi, m_ftype, m_wtype);
}
}
void QFilter::setFilter(const float loval, const float hival) {
if (m_filter_lo != loval || m_filter_hi != hival) {
m_filter_lo = loval;
m_filter_hi = hival;
MakeFilter(m_filter_lo, m_filter_hi, m_ftype, m_wtype);
}
}
float QFilter::filterLo() const {
return m_filter_lo;
}
float QFilter::filterHi() const {
return m_filter_hi;
}
int QFilter::isStreamMode() const {
return m_streamMode;
}
void QFilter::setStreamMode(int value) {
m_streamMode = value;
}
void QFilter::MakeFilter(const float lo, const float hi, const int ftype = 2, const int wtype = 12) {
// size x 4 adjusts for no gain
//float one_over_norm = 1.0 / (m_size * 4);
float one_over_norm = 1.0 / (m_size * 2);
filter.resize(m_size * 2);
tmpfilt0.resize(m_size * 2);
tmpfilt1.resize(m_size * 2);
switch (ftype) {
case 1: // lowpass
MakeFirLowpass( hi,
m_samplerate,
wtype,
tmpfilt0,
m_size);
break;
case 2: // bandpass
MakeFirBandpass(lo,
hi,
m_samplerate,
wtype,
tmpfilt0,
m_size);
break;
case 3: // loadable coeff
LoadFilter(tmpfilt0);
break;
case 4: // bandstop
MakeFirBandstop(lo,
hi,
m_samplerate,
tmpfilt0,
m_size);
break;
default:
MakeFirBandpass(lo,
hi,
m_samplerate,
wtype,
tmpfilt0,
m_size);
break;
}
mutex.lock();
//filtfft->DoFFTWForward(tmpfilt0, tmpfilt1, m_size * 2);
filtfft->DoFFTWForward(tmpfilt0, filter, m_size * 2);
for (int i = 0; i < m_size * 2; i++) {
filter[i].re *= one_over_norm;
filter[i].im *= one_over_norm;
}
mutex.unlock();
// Do compensation here instead of in inverse FFT
//filter_mutex.lock();
//SSEScaleCPX(filter, tmpfilt1, one_over_norm, m_size * 2);
//filter_mutex.unlock();
}
//void QFilter::LoadFilter(CPX * taps) {
void QFilter::LoadFilter(CPX &taps) {
if (FILTERCOEFFSIZE > m_size) return;
for (int i = 0; i < FILTERCOEFFSIZE; i++) {
taps[i].re = FILTERCOEFF[i];
taps[i].im = FILTERCOEFF[i];
}
}
void QFilter::MakeFirLowpass(float cutoff,
float samplerate,
int wtype,
float *taps_re,
float *taps_im,
int length)
{
//float window[length];
float * window = 0;
float fc = cutoff / samplerate;
if (fc > 0.5)
return;
int midpoint = length >> 1;
window = (float *)malloc(length * sizeof(float));
if (!window) return;
MakeWindow(wtype, length, &window[0]);
for (int i = 1; i <= length; i++) {
int j = i - 1;
if (i != midpoint) {
taps_re[j] = (sin(TWOPI * (i - midpoint) * fc) / (ONEPI * (i - midpoint))) * window[j];
taps_im[j] = (cos(TWOPI * (i - midpoint) * fc) / (ONEPI * (i - midpoint))) * window[j];
}
else {
taps_re[midpoint - 1] = 2.0 * fc;
taps_im[midpoint - 1] = 2.0 * fc;
}
}
free(window);
}
void QFilter::MakeFirLowpass(float cutoff,
float samplerate,
int wtype,
CPX &taps,
int length)
{
//float window[length];
float * window = 0;
float fc = cutoff / samplerate;
if (fc > 0.5)
return;
int midpoint = length >> 1;
window = (float *)malloc(length * sizeof(float));
if (!window)
return;
MakeWindow(wtype, length, &window[0]);
for (int i = 1; i <= length; i++) {
int j = i - 1;
if (i != midpoint) {
taps[j].re = (sin(TWOPI * (i - midpoint) * fc) / (ONEPI * (i - midpoint))) * window[j];
taps[j].im = (cos(TWOPI * (i - midpoint) * fc) / (ONEPI * (i - midpoint))) * window[j];
}
else {
taps[midpoint - 1].re = 2.0 * fc;
//taps[midpoint - 1].re = 2.0 * fc;
taps[midpoint - 1].im = 2.0 * fc;
}
}
free(window);
}
void QFilter::MakeFirBandpass(float lo,
float hi,
float samplerate,
int wtype,
float * taps_re,
float * taps_im,
int length)
{
//float window[length];
float * window = 0;
float fl = lo / samplerate;
float fh = hi / samplerate;
float fc = (fh - fl) / 2.0;
float ff = (fl + fh) * ONEPI;
int midpoint = length >> 1;
window = (float *)malloc(length * sizeof(float));
if (!window) return;
MakeWindow(wtype, length, &window[0]);
for (int i = 1; i <= length; i++) {
int j = i - 1;
int k = i - midpoint;
float temp = 0.0;
float phase = k * ff * -1;
if (i != midpoint)
temp = ((sin(TWOPI * k * fc) / (ONEPI * k))) * window[j];
else
temp = 2.0 * fc;
temp *= 2.0;
taps_re[j] = temp * (cos(phase));
taps_im[j] = temp * (sin(phase));
}
free(window);
}
void QFilter::MakeFirBandpass(float lo,
float hi,
float samplerate,
int wtype,
CPX &taps,
int length)
{
//float window[length];
float *window = 0;
float fl = lo / samplerate;
float fh = hi / samplerate;
float fc = (fh - fl) / 2.0f;
float ff = (fl + fh) * ONEPI;
int midpoint = length >> 1;
window = (float *)malloc(length * sizeof(float));
if (!window) return;
MakeWindow(wtype, length, &window[0]);
for (int i = 1; i <= length; i++) {
int j = i - 1;
int k = i - midpoint;
float temp = 0.0;
float phase = k * ff * -1;
if (i != midpoint)
temp = ((qSin(TWOPI * k * fc) / (ONEPI * k))) * window[j];
else
temp = 2.0 * fc;
temp *= 2.0;
taps[j].re = temp * (qCos(phase));
taps[j].im = temp * (qSin(phase));
}
free(window);
}
void QFilter::MakeFirBandstop(float lo, float hi, float samplerate, CPX &taps, int length) {
//float window[length];
float * window = 0;
float fl = lo / samplerate;
float fh = hi / samplerate;
float fc = (fh - fl) / 2.0;
float ff = (fl + fh) * ONEPI;
int midpoint = (length >> 1) | 1;
window = (float *)malloc(length * sizeof(float));
if (!window) return;
MakeWindow(12, length, &window[0]);
for (int i = 1; i <= length; i++) {
int j = i - 1;
int k = i - midpoint;
float temp = 0.0;
float phase = k * ff * -1.0;
if (i != midpoint) {
temp = ((sin(TWOPI * k * fc) / (ONEPI * k))) * window[j];
taps[j].re = -2.0 * temp * (cos(phase));
taps[j].im = -2.0 * temp * (sin(phase));
}
else {
temp = 4.0 * fc;
taps[midpoint - 1].re = 1.0 - taps[midpoint - 1].re;
taps[midpoint - 1].im = 0.0 - taps[midpoint - 1].im;
}
}
free(window);
}
void QFilter::MakeWindow(int wtype, int size, float *window) {
int i, j, midn, midp1, midm1;
float freq, rate, sr1, angle, expn, expsum, cx, two_pi;
midn = size / 2;
midp1 = (size + 1) / 2;
midm1 = (size - 1) / 2;
two_pi = 8.0f * qAtan(1.0);
freq = two_pi / size;
rate = 1.0 / midn;
angle = 0.0;
expn = log(2.0) / midn + 1.0;
expsum = 1.0;
switch (wtype) {
case 1: // RECTANGULAR_WINDOW
for (i = 0; i < size; i++)
window[i] = 1.0;
break;
case 2: // HANNING_WINDOW
for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
window[j] = (window[i] = 0.5 - 0.5 * cos(angle));
break;
case 3: // WELCH_WINDOW
for (i = 0, j = size - 1; i <= midn; i++, j--)
window[j] = (window[i] = 1.0 - (float)sqrt((float)((i - midm1) / midp1)));
break;
case 4: // PARZEN_WINDOW
for (i = 0, j = size - 1; i <= midn; i++, j--)
window[j] = (window[i] = 1.0 - ((float)fabs((float)(i - midm1) / midp1)));
break;
case 5: // BARTLETT_WINDOW
for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += rate)
window[j] = (window[i] = angle);
break;
case 6: // HAMMING_WINDOW
for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
window[j] = (window[i] = 0.5F - 0.46 * cos(angle));
break;
case 7: // BLACKMAN2_WINDOW
for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq) {
cx = cos(angle);
window[j] = (window[i] = (.34401 + (cx * (-.49755 + (cx * .15844)))));
}
break;
case 8: // BLACKMAN3_WINDOW
for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq) {
cx = cos(angle);
window[j] = (window[i] = (.21747 + (cx * (-.45325 + (cx * (.28256 - (cx * .04672)))))));
}
break;
case 9: // BLACKMAN4_WINDOW
for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
{
cx = cos(angle);
window[j] = (window[i] =
(.084037 +
(cx *
(-.29145 +
(cx *
(.375696 + (cx * (-.20762 + (cx * .041194)))))))));
}
break;
case 10: // EXPONENTIAL_WINDOW
for (i = 0, j = size - 1; i <= midn; i++, j--) {
window[j] = (window[i] = expsum - 1.0);
expsum *= expn;
}
break;
case 11: // RIEMANN_WINDOW
sr1 = two_pi / size;
for (i = 0, j = size - 1; i <= midn; i++, j--) {
if (i == midn) window[j] = (window[i] = 1.0);
else {
cx = sr1 * (midn - i);
window[i] = sin(cx) / cx;
window[j] = window[i];
}
}
break;
case 12: // BLACKMANHARRIS_WINDOW
{
float
a0 = 0.35875f,
a1 = 0.48829f,
a2 = 0.14128f,
a3 = 0.01168f;
for (i = 0; i < size; i++)
{
window[i] = a0 - a1* qCos(TWOPI * (i+0.5)/size)
+ a2* qCos(2.0 * TWOPI * (i+0.5)/size)
- a3* qCos(3.0 * TWOPI * (i+0.5)/size);
}
}
break;
default:
return;
}
}
+153
View File
@@ -0,0 +1,153 @@
/**
* @file qtdsp_filter.h
* @brief Filter header file for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-02-18
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_FILTER_H
#define _QTDSP_FILTER_H
//#include <cstdlib>
//#include <cmath>
//#include <vector>
#include <string.h>
//#include <math.h>
#include "qtdsp_fft.h"
#include "qtdsp_qComplex.h"
#include "qtdsp_invsinc_coeff.h"
#include "../cusdr_settings.h"
//#include <QObject>
//#include <QMutex>
#ifdef LOG_QTDSP_FILTER
# define FILTER_DEBUG qDebug().nospace() << "QtDSP_Filter::\t"
#else
# define FILTER_DEBUG nullDebug()
#endif
#define BLACKMANHARRIS_WINDOW 12
class QFilter : public QObject {
Q_OBJECT
public:
QFilter(QObject *parent = 0, int size = 0, const int ftype = 2, const int wtype = 12);
~QFilter();
private:
Settings *set;
QMutex mutex;
bool m_streamMode;
int m_size;
int m_ftype;
int m_wtype;
float m_samplerate;
float m_filter_lo;
float m_filter_hi;
CPX ovlp;
CPX filter;
CPX res;
CPX tmpfilt0;
CPX tmpfilt1;
CPX tmp;
CPX tmp0;
CPX tmp1;
CPX tmp2;
QFFT *ovlpfft;
QFFT *filtfft;
private slots:
void LoadFilter(CPX &taps);
void MakeFirLowpass(float cutoff,
float samplerate,
int wtype,
float *taps_re,
float *taps_im,
int length);
void MakeFirLowpass(float cutoff,
float samplerate,
int wtype,
CPX &taps,
int length);
void MakeFirBandpass(float lo,
float hi,
float samplerate,
int wtype,
float *taps_re,
float *taps_im,
int length);
void MakeFirBandpass(float lo,
float hi,
float samplerate,
int wtype,
CPX &taps,
int length);
void MakeFirBandstop(float lo,
float hi,
float samplerate,
CPX &taps,
int length);
//void DoConvolutionCPX();
void DoOverlapAddCPX();
public slots:
void setSampleRate(QObject *sender, int value);
void MakeFilter(const float lo, const float hi, const int ftype, const int wtype);
static void MakeWindow(int wtype, int size, float * window);
void ProcessFilter(CPX &in, CPX &out, int bsize);
void ProcessForwardFilter(CPX &in, CPX &out, int bsize);
void ProcessChirpFilter(CPX &in, CPX &out, int bsize);
int ProcessAndDecimate(CPX &in, CPX &out, int bsize);
void Decimate(CPX &in, CPX &out, int downrate);
void DoConvolutionCPX();
void Normalize(CPX &in, CPX &out, int size);
float filterLo() const ;
float filterHi() const ;
int isStreamMode() const;
void setFilterLo(const float value);
void setFilterHi(const float value);
void setFilter(const float loval, const float hival);
void setStreamMode(int value);
};
#endif // _QTDSP_FILTER_H
+141
View File
@@ -0,0 +1,141 @@
/**
* @file qtdsp_invsinc_coeff.h
* @brief Filter coefficients header file for QtDSP
* @author by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-02-18
*/
/*
* Copyright (C) 2007, 2008 Philip A Covington, N8VB
*
* adapted for cuSDR by (C) 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_INVSINC_COEFF_H
#define _QTDSP_INVSINC_COEFF_H
#define FILTERCOEFFSIZE 512
const float FILTERCOEFF[512] = {
-7.298647688e-005f, -0.0006591212004f, -0.002619047416f, -0.006309854332f, -0.0100497622f,
-0.01030933112f, -0.00512559386f, 0.002354965545f, 0.005713210441f, 0.002275705803f,
-0.003084241645f, -0.003601335222f, 0.0007034620503f, 0.003363352269f, 0.0008431510651f,
-0.002575940453f, -0.001681111869f, 0.001701403758f, 0.002036997117f, -0.0009210249991f,
-0.002096840879f, 0.0002871879842f, 0.001987287775f, 0.0001987546857f, -0.001792274415f,
-0.0005589024513f, 0.001559824217f, 0.0008162951563f, -0.001320442185f, -0.000995823415f,
0.001087572658f, 0.001113920705f, -0.0008722782368f, -0.001188867842f, 0.0006758925156f,
0.001231985865f, -0.000498666428f, -0.001251817564f, 0.0003399479028f, 0.001254849718f,
-0.0001991765457f, -0.001247569569f, 7.392977568e-005f, 0.001235375414f, 4.123276085e-005f,
-0.001217678422f, -0.0001465942914f, 0.001196535421f, 0.000243384231f, -0.00117429113f,
-0.0003348062455f, 0.001149932388f, 0.0004205152218f, -0.00112563686f, -0.0005032685003f,
0.001100820256f, 0.0005843482213f, -0.001074886066f, -0.0006646135589f, 0.001047056401f,
0.0007442943752f, -0.00101693254f, -0.0008235950954f, 0.0009842554573f, 0.0009030248038f,
-0.0009477832355f, -0.0009810557822f, 0.0009091657703f, 0.001059165923f, -0.0008679664461f,
-0.001138553023f, 0.00082209229f, 0.001217685989f, -0.0007719836431f, -0.001296614995f,
0.0007174044149f, 0.001375256572f, -0.0006578231696f, -0.001452584052f, 0.000594522804f,
0.001530058333f, -0.0005264937645f, -0.001608328195f, 0.0004511743609f, 0.001684416085f,
-0.0003703148686f, -0.001758773113f, 0.0002839826047f, 0.001831884147f, -0.0001910350693f,
-0.001902386313f, 9.27066576e-005f, 0.001972250175f, 1.451703884e-005f,-0.002037639031f,
-0.0001286926563f, 0.002098251833f, 0.0002489787876f, -0.002154306741f, -0.0003754671779f,
0.002205130411f, 0.0005068014725f, -0.002253053477f, -0.0006465745391f, 0.002294297796f,
0.0007927893312f, -0.00232853787f, -0.000944050902f, 0.002357372548f, 0.001102598035f,
-0.002377682133f, -0.001264899038f, 0.002393632894f, 0.001436556573f, -0.002398973331f,
-0.001613004017f, 0.002395873656f, 0.001796123339f, -0.002380831633f, -0.001981404843f,
0.002357972786f, 0.002172444016f, -0.00232419977f, -0.002367483685f, 0.002279908862f,
0.002567417221f, -0.002222327981f, -0.002768594073f, 0.00215465948f, 0.002974577248f,
-0.002071162919f, -0.003176601371f, 0.001984296367f, 0.003392344108f, -0.001870410633f,
-0.003593309782f, 0.001762269414f, 0.003818378551f, -0.001613235101f, -0.004014817532f,
0.001478523714f, 0.004237284884f, -0.001307581435f, -0.004444869235f, 0.001126970164f,
0.004649222363f, -0.0009381354903f, -0.004864084534f, 0.0007162823458f, 0.005058682058f,
-0.0004906012327f, -0.005254743621f, 0.0002504401491f, 0.005455542356f, 2.14788397e-005f,
-0.005635460373f, -0.0003002338926f, 0.005811699666f, 0.0005916802911f, -0.005991247483f,
-0.0009132201085f, 0.006154606584f, 0.001253017108f, -0.006301850546f, -0.001601491706f,
0.006448314991f, 0.001975012943f, -0.006583563052f, -0.002374651376f, 0.00669672247f,
0.002787304111f, -0.006796817295f, -0.003215527395f, 0.006888513919f, 0.003669659607f,
-0.006961984094f, -0.004147280473f, 0.007011558395f, 0.004639521241f, -0.007045097649f,
-0.005150847603f, 0.007064725272f, 0.005690811202f, -0.007059961092f, -0.006256772671f,
0.007024813443f, 0.006840964779f, -0.00696356874f, -0.007443124428f, 0.006882129703f,
0.008074145764f, -0.00677188905f, -0.00873577781f, 0.006622628309f, 0.009418459609f,
-0.006438742857f, -0.01012247056f, 0.006224870216f, 0.01085730083f, -0.005974722095f,
-0.01162762847f, 0.005678492598f, 0.01243014261f, -0.005333583802f, -0.01326503698f,
0.004937817343f, 0.01413488016f, -0.004487683997f, -0.01504271384f, 0.003980736714f,
0.01599739864f, -0.003406297183f, -0.0170029439f, 0.002752586966f, 0.01805772632f,
-0.002016746672f, -0.01917018928f, 0.00119104574f, 0.02035386302f, -0.0002581478329f,
-0.02161752619f, -0.0007987120189f, 0.02297377214f, 0.00200156169f, -0.02443705499f,
-0.003379397793f, 0.02601802349f, 0.004954055417f, -0.02774950489f, -0.0067701675f,
0.02966706641f, 0.00888942834f, -0.03181019425f, -0.01138752978f, 0.03424045816f,
0.01438213047f, -0.03702627495f, -0.01802601293f, 0.04027441144f, 0.02255047485f,
-0.04414317012f, -0.02832753956f, 0.04885149002f, 0.03595076501f, -0.0547539629f,
-0.04649358243f, 0.06237275898f, 0.06197695807f, -0.07256446034f, -0.08679046482f,
0.0865688622f, 0.1321066916f, -0.1050333083f, -0.2351729274f, 0.1105839834f,
0.6013018489f, 0.6013018489f, 0.1105839834f, -0.2351729274f, -0.1050333083f,
0.1321066916f, 0.0865688622f, -0.08679046482f, -0.07256446034f, 0.06197695807f,
0.06237275898f, -0.04649358243f, -0.0547539629f, 0.03595076501f, 0.04885149002f,
-0.02832753956f, -0.04414317012f, 0.02255047485f, 0.04027441144f, -0.01802601293f,
-0.03702627495f, 0.01438213047f, 0.03424045816f, -0.01138752978f, -0.03181019425f,
0.00888942834f, 0.02966706641f, -0.0067701675f, -0.02774950489f, 0.004954055417f,
0.02601802349f, -0.003379397793f, -0.02443705499f, 0.00200156169f, 0.02297377214f,
-0.0007987120189f, -0.02161752619f, -0.0002581478329f, 0.02035386302f, 0.00119104574f,
-0.01917018928f, -0.002016746672f, 0.01805772632f, 0.002752586966f, -0.0170029439f,
-0.003406297183f, 0.01599739864f, 0.003980736714f, -0.01504271384f, -0.004487683997f,
0.01413488016f, 0.004937817343f, -0.01326503698f, -0.005333583802f, 0.01243014261f,
0.005678492598f, -0.01162762847f, -0.005974722095f, 0.01085730083f, 0.006224870216f,
-0.01012247056f, -0.006438742857f, 0.009418459609f, 0.006622628309f, -0.00873577781f,
-0.00677188905f, 0.008074145764f, 0.006882129703f, -0.007443124428f, -0.00696356874f,
0.006840964779f, 0.007024813443f, -0.006256772671f, -0.007059961092f, 0.005690811202f,
0.007064725272f, -0.005150847603f, -0.007045097649f, 0.004639521241f, 0.007011558395f,
-0.004147280473f, -0.006961984094f, 0.003669659607f, 0.006888513919f, -0.003215527395f,
-0.006796817295f, 0.002787304111f, 0.00669672247f, -0.002374651376f, -0.006583563052f,
0.001975012943f, 0.006448314991f, -0.001601491706f, -0.006301850546f, 0.001253017108f,
0.006154606584f, -0.0009132201085f, -0.005991247483f, 0.0005916802911f, 0.005811699666f,
-0.0003002338926f, -0.005635460373f, 2.14788397e-005f, 0.005455542356f, 0.0002504401491f,
-0.005254743621f, -0.0004906012327f, 0.005058682058f, 0.0007162823458f, -0.004864084534f,
-0.0009381354903f, 0.004649222363f, 0.001126970164f, -0.004444869235f, -0.001307581435f,
0.004237284884f, 0.001478523714f, -0.004014817532f, -0.001613235101f, 0.003818378551f,
0.001762269414f, -0.003593309782f, -0.001870410633f, 0.003392344108f, 0.001984296367f,
-0.003176601371f, -0.002071162919f, 0.002974577248f, 0.00215465948f, -0.002768594073f,
-0.002222327981f, 0.002567417221f, 0.002279908862f, -0.002367483685f, -0.00232419977f,
0.002172444016f, 0.002357972786f, -0.001981404843f, -0.002380831633f, 0.001796123339f,
0.002395873656f, -0.001613004017f, -0.002398973331f, 0.001436556573f, 0.002393632894f,
-0.001264899038f, -0.002377682133f, 0.001102598035f, 0.002357372548f, -0.000944050902f,
-0.00232853787f, 0.0007927893312f, 0.002294297796f, -0.0006465745391f, -0.002253053477f,
0.0005068014725f, 0.002205130411f, -0.0003754671779f, -0.002154306741f, 0.0002489787876f,
0.002098251833f, -0.0001286926563f, -0.002037639031f, 1.451703884e-005f, 0.001972250175f,
9.27066576e-005f, -0.001902386313f, -0.0001910350693f, 0.001831884147f, 0.0002839826047f,
-0.001758773113f, -0.0003703148686f, 0.001684416085f, 0.0004511743609f, -0.001608328195f,
-0.0005264937645f, 0.001530058333f, 0.000594522804f, -0.001452584052f, -0.0006578231696f,
0.001375256572f, 0.0007174044149f, -0.001296614995f, -0.0007719836431f, 0.001217685989f,
0.00082209229f, -0.001138553023f, -0.0008679664461f, 0.001059165923f, 0.0009091657703f,
-0.0009810557822f, -0.0009477832355f, 0.0009030248038f, 0.0009842554573f, -0.0008235950954f,
-0.00101693254f, 0.0007442943752f, 0.001047056401f, -0.0006646135589f, -0.001074886066f,
0.0005843482213f, 0.001100820256f, -0.0005032685003f, -0.00112563686f, 0.0004205152218f,
0.001149932388f, -0.0003348062455f, -0.00117429113f, 0.000243384231f, 0.001196535421f,
-0.0001465942914f, -0.001217678422f, 4.123276085e-005f, 0.001235375414f, 7.392977568e-005f,
-0.001247569569f, -0.0001991765457f, 0.001254849718f, 0.0003399479028f, -0.001251817564f,
-0.000498666428f, 0.001231985865f, 0.0006758925156f, -0.001188867842f, -0.0008722782368f,
0.001113920705f, 0.001087572658f, -0.000995823415f, -0.001320442185f, 0.0008162951563f,
0.001559824217f, -0.0005589024513f, -0.001792274415f, 0.0001987546857f, 0.001987287775f,
0.0002871879842f, -0.002096840879f, -0.0009210249991f, 0.002036997117f, 0.001701403758f,
-0.001681111869f, -0.002575940453f, 0.0008431510651f, 0.003363352269f, 0.0007034620503f,
-0.003601335222f, -0.003084241645f, 0.002275705803f, 0.005713210441f, 0.002354965545f,
-0.00512559386f, -0.01030933112f, -0.0100497622f, -0.006309854332f, -0.002619047416f,
-0.0006591212004f, -7.298647688e-005f
};
#endif // _QTDSP_INVSINC_COEFF_H
+212
View File
@@ -0,0 +1,212 @@
/**
* @file qtdsp_powerSpectrum.cpp
* @brief Power Spectrum class for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-05-14
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define LOG_POWERSPECTRUM
#include "qtdsp_powerSpectrum.h"
PowerSpectrum::PowerSpectrum(QObject *parent, int size)
: QObject(parent)
, set(Settings::instance())
, first(true)
, m_size(size)
, m_spectrumSize(size*2)
, m_psswitch(0)
, m_averages(4)
, m_samplerate(set->getSampleRate())
, m_baseline((float)1.0e-15)
, m_correction(0.0f)
{
m_window = new float[m_size];
m_fPsdBm = new float[m_size * 2];
m_fAvePsdBm = new float[m_size * 2];
windowCPX.resize(m_size);
tmpCPX.resize(m_size * 2);
dataCPX.resize(0);
zero.re = 0.0f;
zero.im = 0.0f;
m_fft = new QFFT(m_size * 2);
memset(m_fPsdBm, 0, m_size * 2 * sizeof(float));
memset(m_fAvePsdBm, 0, m_size * 2 * sizeof(float));
memset(m_window, 0, m_size * sizeof(float));
QFilter::MakeWindow(BLACKMANHARRIS_WINDOW, size, m_window);
for (int i = 0; i < m_size; i++) {
windowCPX[i].re = m_window[i];
windowCPX[i].im = m_window[i];
}
cnt = 0;
}
PowerSpectrum::~PowerSpectrum() {
if (m_fft)
delete m_fft;
windowCPX.clear();
tmpCPX.clear();
dataCPX.clear();
if (m_window)
delete m_window;
if (m_fPsdBm)
delete m_fPsdBm;
if (m_fAvePsdBm)
delete m_fAvePsdBm;
}
void PowerSpectrum::setupConnections() {
}
//void PowerSpectrum::ProcessSpectrum(CPX &in, int size) {
//
// Q_UNUSED(size)
//
// if (first && dataCPX.size() == 0) {
//
// dataCPX << in;
// first = false;
// return;
// }
// else {
//
// dataCPX << in;
// tmpCPX.fill(zero, m_size*2);
//
// if (dataCPX.size() == m_size) {
//
// for (int i = 0; i < m_size; i++)
// tmpCPX[i] = MultCPX(dataCPX.at(i), windowCPX.at(i));
//
// m_mutex.lock();
// m_fft->DoFFTWMagnForward(tmpCPX, m_size * 2, m_baseline, m_correction, m_fPsdBm);
// m_mutex.unlock();
// }
//
// first = true;
// dataCPX.resize(0);
// }
//}
void PowerSpectrum::ProcessSpectrum(CPX &in, int size, int maxCnt) {
Q_UNUSED(size)
if (cnt < maxCnt) { // maxCnt = 1: 4096, maxCnt = 3: 8192, maxCnt = 7: 16384
dataCPX << in;
//first = false;
cnt++;
return;
}
else {
dataCPX << in;
tmpCPX.fill(zero, m_size*2);
if (dataCPX.size() == m_size) {
for (int i = 0; i < m_size; i++)
tmpCPX[i] = MultCPX(dataCPX.at(i), windowCPX.at(i));
m_mutex.lock();
m_fft->DoFFTWMagnForward(tmpCPX, m_size * 2, m_baseline, m_correction, m_fPsdBm);
m_mutex.unlock();
}
//first = true;
cnt = 0;
dataCPX.resize(0);
}
}
void PowerSpectrum::setBaseLine(float value) {
m_baseline = value;
}
void PowerSpectrum::setCorrection(float value) {
m_correction = value;
}
void PowerSpectrum::setPsOn(int value) {
m_psswitch = value;
}
//int PowerSpectrum::psdBmResults(float* buffer) {
//
// if (buffer == NULL) return 0;
//
// m_mutex.lock();
// memcpy(buffer, m_fPsdBm, dBmSize() * sizeof(float));
// m_mutex.unlock();
//
// return dBmSize();
//}
int PowerSpectrum::spectrumResult(qVectorFloat &buffer, int shift) {
if (buffer.size() == 0) return 0;
m_mutex.lock();
memcpy(
(float *) buffer.data(),
(float *) &m_fPsdBm[shift],
4096 * sizeof(float));
m_mutex.unlock();
return buffer.size();
}
void PowerSpectrum::setAverages(int value) {
m_averages = value;
}
float PowerSpectrum::grabPsPoint(int index) {
return m_fPsdBm[index];
}
int PowerSpectrum::dBmSize() const {
return m_spectrumSize;
}
+108
View File
@@ -0,0 +1,108 @@
/**
* @file qtdsp_powerSpectrum.h
* @brief Power Spectrum header file for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-05-14
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2011 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_POWERSPECTRUM_H
#define _QTDSP_POWERSPECTRUM_H
#include "qtdsp_qComplex.h"
#include "qtdsp_fft.h"
#include "qtdsp_filter.h"
#include "../cusdr_settings.h"
#include <QObject>
#include <QMutex>
#ifdef LOG_POWERSPECTRUM
# define POWERSPECTRUM_DEBUG qDebug().nospace() << "PowerSpectrum::\t"
#else
# define POWERSPECTRUM_DEBUG nullDebug()
#endif
class PowerSpectrum : public QObject {
Q_OBJECT
public:
PowerSpectrum(QObject *parent = 0, int size = 0);
~PowerSpectrum();
void ProcessSpectrum(CPX &in, int size, int maxCnt);
//int psdBmResults(float *buffer);
int spectrumResult(qVectorFloat &buffer, int shift);
float grabPsPoint(int index);
void setBaseLine(float value);
void setCorrection(float value);
void setPsOn(int value);
void setAverages(int value);
int dBmSize() const;// { return m_size * 2; }
int psIsOn() const { return m_psswitch; }
int averages() const { return m_averages; }
float baseLine() const { return m_baseline; }
float correction() const { return m_correction; }
public slots:
//void setSampleSize(int rx, int size);
private:
Settings* set;
QMutex m_mutex;
cpx zero;
CPX windowCPX;
CPX tmpCPX;
CPX dataCPX;
QFFT* m_fft;
bool first;
int m_size;
int m_spectrumSize;
int m_psswitch;
int m_averages;
int cnt;
float m_samplerate;
float m_baseline;
float m_correction;
float* m_window;
float* m_fPsdBm;
float* m_fAvePsdBm;
void setupConnections();
};
#endif // _QTDSP_POWERSPECTRUM_H
+146
View File
@@ -0,0 +1,146 @@
/**
* @file qtdsp_qComplex.h
* @brief qComplex type header for QtDSP
* @author by Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2011-09-22
*/
/*
* Copyright 2011 Hermann von Hasseln, DL3HVH
*
* Based on the complex type CPX by Philip A Covington, p.covington@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_QCOMPLEX_H
#define _QTDSP_QCOMPLEX_H
#include <cmath>
#include <limits>
#include <QVector>
#include <QVector2D>
#include <QString>
using namespace std;
#undef max
typedef struct _QCOMPLEX {
float re;
float im;
} cpx;
Q_DECLARE_METATYPE (cpx)
Q_DECLARE_TYPEINFO(cpx, Q_MOVABLE_TYPE);
typedef QVector<cpx> CPX;
Q_DECLARE_METATYPE (CPX)
inline void InitCPX(CPX &vec, int size, float value) {
cpx zero;
zero.re = value; zero.im = value;
vec.resize(size);
vec.fill(zero);
}
inline cpx ToCPX(qreal x, qreal y) {
cpx z;
z.re = x;
z.im = y;
return z;
}
inline cpx ScaleCPX(const cpx &c, float a) {
cpx z;
z.re = a * c.re;
z.im = a * c.im;
return z;
}
inline cpx AddCPX(cpx x, cpx y) {
cpx z;
z.re = x.re + y.re;
z.im = x.im + y.im;
return z;
}
inline void PlusCPX(CPX &a, CPX &b, CPX &c) {
CPX z;
z.resize(0);
int sa = a.size();
int sb = b.size();
if (sa != sb) return;
z.resize(sa);
for (int i = 0; i < sa; i++) {
z[i].re = a.at(i).re + b.at(i).re;
z[i].im = a.at(i).im + b.at(i).im;
c[i].re = z.at(i).re;
c[i].im = z.at(i).im;
}
}
inline cpx MultCPX(cpx x, cpx y) {
cpx z;
z.re = x.re * y.re - x.im * y.im;
z.im = x.im * y.re + x.re * y.im;
return z;
}
inline float MagCPX(cpx z) {
return (float) (z.re * z.re + z.im * z.im);
}
inline float SqrMagCPX(cpx z) {
return (float) sqrt(z.re * z.re + z.im * z.im);
}
inline QString ValidQReal(qreal value) {
if (value != value) {
return "NaN";
}
else if (value > numeric_limits<double>::max()){
return "+Inf";
}
else if (value < -numeric_limits<double>::max()){
return "-Inf";
}
else
return "";
}
#endif // _QTDSP_QCOMPLEX_H
+74
View File
@@ -0,0 +1,74 @@
/**
* @file qtdsp_signalMeter.cpp
* @brief Signal Meter class for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-09-19
*/
/*
* Copyright (C) 2007, 2008, Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* With Algorithms borrowed from DttSP
* Copyright (C) 2004, 2005, 2006 by Frank Brickle, AB2KT and Bob McGwier, N4HY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qtdsp_signalMeter.h"
SignalMeter::SignalMeter(QObject *parent, int size)
: QObject(parent)
, set(Settings::instance())
, m_size(size)
, m_instValue(-80.0)
//, m_correction(59.0f)
, m_correction(-8.0f)
{
}
SignalMeter::~SignalMeter() {
}
void SignalMeter::ProcessBlock(CPX &in, int bsize) {
Q_UNUSED(bsize)
float tmp = 0.0f;
for (int i = 0; i < m_size; i++)
tmp += (in.at(i).re * in.at(i).re + in.at(i).im * in.at(i).im);
m_instValue = (float)(10.0f * log10(tmp + 1.5E-45));
}
float SignalMeter::getInstFValue() const {
return m_instValue + m_correction;
}
float SignalMeter::getCorrection() const {
return m_correction;
}
void SignalMeter::setCorrection(const float value) {
if (m_correction == value) return;
m_correction = value;
}
+69
View File
@@ -0,0 +1,69 @@
/**
* @file qtdsp_signalMeter.h
* @brief Signal meter header file for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-09-19
*/
/*
* Copyright (C) 2007, 2008, Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* With Algorithms borrowed from DttSP
* Copyright (C) 2004, 2005, 2006 by Frank Brickle, AB2KT and Bob McGwier, N4HY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QTDSP_SIGNALMETER_H
#define _QTDSP_SIGNALMETER_H
#define SPECDBMOFFSET 100.50
#include <cmath>
#include "qtdsp_qComplex.h"
#include "../cusdr_settings.h"
#include <QObject>
#include <QMutex>
class SignalMeter : public QObject {
Q_OBJECT
public:
SignalMeter(QObject *parent = 0, int size = 0);
~SignalMeter();
void ProcessBlock(CPX &in, int bsize);
float getInstFValue() const;
float getCorrection() const;
public slots:
void setCorrection(const float value);
private:
Settings *set;
int m_size;
float m_instValue;
float m_correction;
};
#endif // _QTDSP_SIGNALMETER_H
+630
View File
@@ -0,0 +1,630 @@
/**
* @file qtdsp_wpagc.cpp
* @brief Warren Pratt's ingenious AGC class for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-05-14
*/
/*
* Copyright (C) 2011, 2012 Warren Pratt, NR0V
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The author can be reached by email at
*
* warren@wpratt.com
*/
#define LOG_WPAGC
#include "qtdsp_wpagc.h"
QWPAGC::QWPAGC(QObject *parent, int size)
: QObject(parent)
, set(Settings::instance())
, m_size(size)
, m_samplerate(set->getSampleRate())
, m_nTau(4)
, m_outIndex(-1)
, m_inIndex(0)
, m_attackBuffersize(0)
, m_state(0)
, m_hangCounter(0)
, m_decayType(0)
, m_fixedGain(1000)
, m_tauAttack(0.001)
, m_tauDecay(0.250)
//, m_maxGain(100000.0)
, m_varGain(1.0)
, m_minVolts(0.0)
// Warren NR0V reports that this change needs to be made in order for things to be
// in the right position on the screen and other factors:
, m_maxInput(500.0)
, m_out_targ(1.0)
, m_out_target(0.0)
, m_inv_max_input(0.0)
, m_slope_constant(0.0)
, m_ring_max(0.0)
, m_attack_mult(0.0)
, m_decay_mult(0.0)
, m_volts(0.0)
, m_save_volts(0.0)
, m_abs_out_sample(0.0)
, m_tau_fast_backaverage(0.250)
, m_fast_backmult(0.0)
, m_onemfast_backmult(1.0)
, m_fast_backaverage(0.0)
, m_tau_fast_decay(0.005)
, m_fast_decay_mult(0.0)
, m_pop_ratio(5.0)
, m_hang_backaverage(0.0)
, m_tau_hang_backmult(0.500)
, m_hang_backmult(0.0)
, m_onemhang_backmult(1.0)
, m_hangtime(0.250)
, m_hangThresh(0.01)
, m_hangLevel(0.0)
, m_tau_hang_decay(0.100)
, m_hang_decay_mult(0.0)
, SinAverage(0.637)
{
InitCPX(buf, m_size, 0.0f);
InitCPX(ring, RINGBUFFERSIZE, 0.0f);
outSample.re = 0.0f;
outSample.im = 0.0f;
absRing.resize(RINGBUFFERSIZE);
absRing.fill(0.0);
initWcpAGC();
}
QWPAGC::~QWPAGC() {
buf.clear();
ring.clear();
}
//void QWPAGC::setupConnections() {
//
//}
void QWPAGC::ProcessAGC(CPX &in, CPX &out, int size) {
Q_UNUSED(size)
if (m_agcMode == agcOFF) {
for (int i = 0; i < m_size; i++)
out[i] = ScaleCPX(in.at(i), m_fixedGain);
return;
}
memcpy(buf.data(), in.data(), sizeof(cpx) * m_size);
int i, j, k;
//qreal mult;
mutex.lock();
for (i = 0; i < m_size; i++) {
if (++m_outIndex >= RINGBUFFERSIZE)
m_outIndex -= RINGBUFFERSIZE;
if (++m_inIndex >= RINGBUFFERSIZE)
m_inIndex -= RINGBUFFERSIZE;
outSample.re = ring.at(m_outIndex).re;
outSample.im = ring.at(m_outIndex).im;
//m_abs_out_sample = absRing[m_out_index];
m_abs_out_sample = absRing.at(m_outIndex);
ring[m_inIndex].re = buf.at(i).re;
ring[m_inIndex].im = buf.at(i).im;
absRing[m_inIndex] = qMax(qAbs(ring.at(m_inIndex).re), qAbs(ring.at(m_inIndex).im));
m_fast_backaverage = m_fast_backmult * m_abs_out_sample + m_onemfast_backmult * m_fast_backaverage;
m_hang_backaverage = m_hang_backmult * m_abs_out_sample + m_onemhang_backmult * m_hang_backaverage;
if ((m_abs_out_sample >= m_ring_max) && (m_abs_out_sample > 0)) {
m_ring_max = 0.0;
k = m_outIndex;
for (j = 0; j < m_attackBuffersize; j++) {
if (++k == RINGBUFFERSIZE)
k = 0;
if (absRing[k] > m_ring_max)
//m_ring_max = absRing[k];
m_ring_max = absRing.at(k);
}
}
if (absRing[m_inIndex] > m_ring_max)
//m_ring_max = absRing[m_in_index];
m_ring_max = absRing.at(m_inIndex);
if (m_hangCounter > 0)
--m_hangCounter;
switch (m_state) {
case 0:
if (m_ring_max >= m_volts) {
m_volts += (m_ring_max - m_volts) * m_attack_mult;
}
else {
if (m_volts > m_pop_ratio * m_fast_backaverage) {
m_state = 1;
m_volts += (m_ring_max - m_volts) * m_fast_decay_mult;
}
else {
if (m_hang_backaverage > m_hangLevel) {
m_state = 2;
m_hangCounter = (int)(m_hangtime * m_samplerate);
m_decayType = 1;
}
else {
m_state = 3;
m_volts += (m_ring_max - m_volts) * m_decay_mult;
m_decayType = 0;
}
}
}
break;
case 1:
if (m_ring_max >= m_volts) {
m_state = 0;
m_volts += (m_ring_max - m_volts) * m_attack_mult;
}
else {
if (m_volts > m_save_volts) {
m_volts += (m_ring_max - m_volts) * m_fast_decay_mult;
}
else {
if (m_hangCounter > 0) {
m_state = 2;
}
else {
if (m_decayType == 0) {
m_state = 3;
m_volts += (m_ring_max - m_volts) * m_decay_mult;
}
else {
m_state = 4;
m_volts += (m_ring_max - m_volts) * m_hang_decay_mult;
}
}
}
}
break;
case 2:
if (m_ring_max >= m_volts) {
m_state = 0;
m_save_volts = m_volts;
m_volts += (m_ring_max - m_volts) * m_attack_mult;
}
else {
if (m_hangCounter == 0) {
m_state = 4;
m_volts += (m_ring_max - m_volts) * m_hang_decay_mult;
}
}
break;
case 3:
if (m_ring_max >= m_volts) {
m_state = 0;
m_save_volts = m_volts;
m_volts += (m_ring_max - m_volts) * m_attack_mult;
}
else {
m_volts += (m_ring_max - m_volts) * m_decay_mult;
}
break;
case 4:
if (m_ring_max >= m_volts) {
m_state = 0;
m_save_volts = m_volts;
m_volts += (m_ring_max - m_volts) * m_attack_mult;
}
else {
m_volts += (m_ring_max - m_volts) * m_hang_decay_mult;
}
break;
} // end switch on state
if (m_volts < m_minVolts)
m_volts = m_minVolts;
mult = (m_out_target - m_slope_constant * qMin(0.0, log10 (m_inv_max_input * m_volts))) / m_volts;
out[i].re = (float)(outSample.re * mult);
out[i].im = (float)(outSample.im * mult);
}
mutex.unlock();
}
void QWPAGC::initWcpAGC() {
m_outIndex = -1;
m_ring_max = 0.0;
m_volts = 0.0;
m_save_volts = 0.0;
m_fast_backaverage = 0.0;
m_hang_backaverage = 0.0;
m_hangCounter = 0;
m_state = 0;
//memset(absRing, 0, RINGBUFFERSIZE * sizeof(qreal));
absRing.fill(0.0);
for (int i = 0; i < RINGBUFFERSIZE; i++) {
ring[i].re = 0.0f;
ring[i].im = 0.0f;
}
outSample.re = 0.0f;
outSample.im = 0.0f;
m_abs_out_sample = 0.0f;
m_decayType = 0;
}
void QWPAGC::loadWcpAGC() {
qreal tmp;
m_attackBuffersize = (int)qCeil(m_samplerate * m_nTau * m_tauAttack);
m_inIndex = m_attackBuffersize + m_outIndex;
m_attack_mult = 1.0 - qExp(-1.0 / (m_samplerate * m_tauAttack));
m_decay_mult = 1.0 - qExp(-1.0 / (m_samplerate * m_tauDecay));
m_fast_decay_mult = 1.0 - qExp(-1.0 / (m_samplerate * m_tau_fast_decay));
m_fast_backmult = 1.0 - qExp(-1.0 / (m_samplerate * m_tau_fast_backaverage));
m_onemfast_backmult = 1.0 - m_fast_backmult;
m_out_target = m_out_targ * (1.0 - qExp(-m_nTau)) * 0.99;
m_minVolts = m_out_target / (m_varGain * m_maxGain);
//WPAGC_DEBUG << "emit m_min_volts = " << m_min_volts;
//WPAGC_DEBUG << "emit m_max_gain = " << maxGain;
//emit minimumVoltageChanged(this, m_receiver, m_min_volts);
//emit agcMaximumGainChanged(m_max_gain);
tmp = log10(m_out_target / (m_maxInput * m_varGain * m_maxGain));
if (tmp == 0.0)
tmp = 1.5E-45;
m_slope_constant = (m_out_target * (1.0 - (1.0 / m_varGain))) / tmp;
//m_slope_constant = (m_out_target * (1.0 - (1.0 / m_var_gain))) / (tmp + 1.5E-45);
m_inv_max_input = 1.0 / m_maxInput;
tmp = qPow(10.0, ((m_agcHangEnable ? m_hangThresh : 1.0) - 1.0) / 0.125);
m_hangLevel = (m_maxInput * tmp + (m_out_target / (m_varGain * m_maxGain)) * (1.0 - tmp)) * SinAverage;
// send the hang level value out for display
//WPAGC_DEBUG << "hangLevel_dB = " << 20.0 * log10(m_hangLevel / SinAverage);
//emit hangLeveldBLineChanged(20.0 * log10(m_hangLevel / SinAverage));
m_hang_backmult = 1.0 - qExp(-1.0 / (m_samplerate * m_tau_hang_backmult));
m_onemhang_backmult = 1.0 - m_hang_backmult;
m_hang_decay_mult = 1.0 - qExp(-1.0 / (m_samplerate * m_tau_hang_decay));
emit displayValues(this, m_receiver, m_minVolts, 20.0 * log10(m_hangLevel / SinAverage));
}
void QWPAGC::setReceiver(int rx) {
m_receiver = rx;
}
void QWPAGC::setMode(AGCMode mode) {
//mutex.lock();
if ((m_agcMode == (AGCMode) agcOFF) && (mode != 0)) initWcpAGC();
m_agcMode = mode;
switch (mode) {
case agcOFF:
break;
case agcSLOW:
m_agcHangEnable = true;
m_hangtime = 1.0;
m_tauDecay = 0.500;
break;
case agcMED:
m_agcHangEnable = false;
m_hangtime = 0.0;
m_tauDecay = 0.250;
break;
case agcFAST:
m_agcHangEnable = false;
m_hangtime = 0.0;
m_tauDecay = 0.050;
break;
case agcLONG:
m_agcHangEnable = true;
m_hangtime = 2.0;
m_tauDecay = 2.0;
break;
case agcUser:
m_agcHangEnable = true;
m_hangtime = 2.0;
m_tauDecay = 2.0;
break;
default:
m_agcHangEnable = true;
m_hangtime = 2.0;
m_tauDecay = 2.0;
break;
}
//mutex.unlock();
}
void QWPAGC::setAGCHangEnable(bool value) {
m_agcHangEnable = value;
}
// fixed_gain when AGC is OFF (set to 'fixed'), linear
void QWPAGC::setAGCFixedGain(qreal value) {
m_fixedGain = value;
}
qreal QWPAGC::getAGCFixedGain() {
return m_fixedGain;
}
// fixed_gain when AGC is OFF (set to 'fixed'), in dB
void QWPAGC::setAGCFixedGainDb(qreal value) {
qreal tmp = value;
if (tmp > 60.0) tmp = 60.0;
m_fixedGain = qPow(10.0, tmp / 20.0);
//WPAGC_DEBUG << "m_fixedGain = " << m_fixedGain;
}
qreal QWPAGC::getAGCFixedGainDb() {
return 20.0 * log10(m_fixedGain);
}
void QWPAGC::setSampleRate(QObject *sender, int value) {
Q_UNUSED(sender)
//mutex.lock();
m_samplerate = value;
initWcpAGC();
loadWcpAGC();
//mutex.unlock();
}
// attack time constant in SECONDS
void QWPAGC::setTauAttack(qreal value) {
mutex.lock();
m_tauAttack = value;
loadWcpAGC();
mutex.unlock();
}
qreal QWPAGC::getTauAttack() {
return m_tauAttack;
}
//decay time constant in SECONDS
void QWPAGC::setTauDecay(qreal value) {
mutex.lock();
m_tauDecay = value;
loadWcpAGC();
mutex.unlock();
}
qreal QWPAGC::getTauDecay() {
return m_tauDecay;
}
// maximum AGC gain = gain below the "knee", linear
bool QWPAGC::setMaximumGain(qreal value) {
mutex.lock();
m_maxGain = value;
if (ValidQReal(m_maxGain) == "NaN" || ValidQReal(m_maxGain) == "+Inf" || (m_maxGain <= 0)) {
mutex.unlock();
return false; // illegal values!
}
else
loadWcpAGC();
mutex.unlock();
return true;
}
qreal QWPAGC::getAGCMaximumGain_dBm() {
return 20.0 * log10(m_maxGain);
}
// maximum AGC gain = gain below the "knee", in dB
bool QWPAGC::setMaximumGainDb(qreal value) {
mutex.lock();
m_maxGain = qPow(10.0, value / 20.0);
//WPAGC_DEBUG << "maxGain from Slider = " << m_maxGain << " (" << value << " dB)";
if (ValidQReal(m_maxGain) == "NaN" || ValidQReal(m_maxGain) == "+Inf" || (m_maxGain <= 0)) {
mutex.unlock();
WPAGC_DEBUG << "illegal value for maximum gain !";
return false; // illegal values!
}
else
loadWcpAGC();
mutex.unlock();
return true;
}
// variable AGC gain = "Slope", linear
void QWPAGC::setVarGain(qreal value) {
mutex.lock();
m_varGain = value;
loadWcpAGC();
mutex.unlock();
}
// variable AGC gain = "Slope", in dB
void QWPAGC::setVarGainDb(qreal value) {
mutex.lock();
m_varGain = qPow(10.0, value / 20.0);
loadWcpAGC();
mutex.unlock();
}
// for hang threshold slider, range 0.0 to 1.0
void QWPAGC::setHangThresh(qreal value) {
mutex.lock();
//WPAGC_DEBUG << "m_hang_thresh = " << value;
m_hangThresh = value;
loadWcpAGC();
mutex.unlock();
}
// hangtime in SECONDS
void QWPAGC::setHangTime(qreal value) {
mutex.lock();
m_hangtime = value;
loadWcpAGC();
mutex.unlock();
}
// for line on bandscope
void QWPAGC::setHangLevelDb(qreal value) {
mutex.lock();
if (m_maxInput > m_minVolts) {
// BUG: found by Warren, 15 Jan 2012: 'SinAverage' term NOT needed!
// double convert = SinAverage * qPow(10.0, value / 20.0);
qreal convert = qPow(10.0, value / 20.0);
qreal tmp = qMax(1.0e-8, (convert - m_minVolts) / (m_maxInput - m_minVolts));
m_hangThresh = 1.0 + 0.125 * log10(tmp);
}
else
m_hangThresh = 1.0;
loadWcpAGC();
mutex.unlock();
emit agcHangThresholdChanged(m_hangThresh * 100.0);
}
// for line on bandscope
qreal QWPAGC::getHangLevelDb() {
return 20.0 * log10(m_hangLevel / SinAverage);
}
// for line on bandscope
//qreal QWPAGC::getAGCThreshDb(qreal filt_high, qreal filt_low, int spec_size) {
//
// qreal noise_offset = 10.0 * log10(qAbs(filt_high - filt_low) * spec_size / m_samplerate);
// return 20.0 * log10(m_min_volts) - noise_offset;
//}
// for line on bandscope
void QWPAGC::setAGCThreshDb(qreal filt_high, qreal filt_low, int spec_size, qreal thresh) {
mutex.lock();
qreal noise_offset = 10.0 * log10(qAbs(filt_high - filt_low) * spec_size / m_samplerate);
m_maxGain = m_out_target / (m_varGain * qPow(10.0, (thresh + noise_offset) / 20.0));
loadWcpAGC();
mutex.unlock();
//WPAGC_DEBUG << "maxGain = " << m_maxGain;
emit agcMaximumGainChanged(m_maxGain);
}
void QWPAGC::filterChanged() {
emit displayValues(this, m_receiver, m_minVolts, 20.0 * log10(m_hangLevel / SinAverage));
}
+178
View File
@@ -0,0 +1,178 @@
/**
* @file qtdsp_wpagc.h
* @brief Warren Pratt's ingenious AGC header file for QtDSP
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-05-14
*/
/*
* Copyright (C) 2011, 2012 Warren Pratt, NR0V
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The author can be reached by email at
*
* warren@wpratt.com
*/
#ifndef _QTDSP_WPAGC_H
#define _QTDSP_WPAGC_H
#include "qtdsp_qComplex.h"
#include "../cusdr_settings.h"
#include <QObject>
#include <QMutex>
#define RINGBUFFERSIZE 19200
#define SINAVERAGE 0.637f
#ifdef LOG_WPAGC
# define WPAGC_DEBUG qDebug().nospace() << "WPAGC::\t"
#else
# define WPAGC_DEBUG nullDebug()
#endif
class QWPAGC : public QObject {
Q_OBJECT
public:
QWPAGC(QObject *parent = 0, int size = 0);
~QWPAGC();
void ProcessAGC(CPX &in, CPX &out, int size);
qreal getAGCFixedGain();
qreal getAGCFixedGainDb();
qreal getAGCMaximumGain_dBm();
qreal getTauAttack();
qreal getTauDecay();
void setReceiver(int rx);
public slots:
void setSampleRate(QObject *sender, int value);
void setMode(AGCMode mode);
void setAGCHangEnable(bool value);
void setAGCFixedGain(qreal value);
void setAGCFixedGainDb(qreal value);
void setTauAttack(qreal value);
void setTauDecay(qreal value);
bool setMaximumGain(qreal value);
bool setMaximumGainDb(qreal value);
void setVarGain(qreal value);
void setVarGainDb(qreal value);
void setHangThresh(qreal value);
void setHangTime(qreal value);
void setHangLevelDb(qreal value);
void setAGCThreshDb(qreal filt_high, qreal filt_low, int spec_size, qreal thresh);
void filterChanged();
//qreal getAGCThreshDb(qreal filt_high, qreal filt_low, int spec_size);
qreal getHangLevelDb();
private:
Settings *set;
QMutex mutex;
//QVector<qreal> m_abs_ring;
AGCMode m_agcMode;
CPX ring;
CPX buf;
cpx outSample;
bool m_agcHangEnable;
int m_size;
int m_receiver;
int m_samplerate;
int m_nTau;
int m_outIndex;
int m_inIndex;
int m_attackBuffersize;
int m_state;
int m_hangCounter;
int m_decayType;
qreal m_fixedGain;
qreal m_tauAttack;
qreal m_tauDecay;
qreal m_maxGain;
qreal m_varGain;
qreal m_minVolts;
qreal m_maxInput;
qreal m_out_targ;
qreal m_out_target;
qreal m_inv_max_input;
qreal m_slope_constant;
qreal m_ring_max;
//qreal absRing[RINGBUFFERSIZE];
QVector<qreal> absRing;
qreal m_attack_mult;
qreal m_decay_mult;
qreal m_volts;
qreal m_save_volts;
qreal m_abs_out_sample;
qreal m_tau_fast_backaverage;
qreal m_fast_backmult;
qreal m_onemfast_backmult;
qreal m_fast_backaverage;
qreal m_tau_fast_decay;
qreal m_fast_decay_mult;
qreal m_pop_ratio;
qreal m_hang_backaverage;
qreal m_tau_hang_backmult;
qreal m_hang_backmult;
qreal m_onemhang_backmult;
qreal mult;
qreal m_hangtime;
qreal m_hangThresh;
qreal m_hangLevel;
qreal m_tau_hang_decay;
qreal m_hang_decay_mult;
// average of the absolute value of a sin wave of magnitude 1.0
qreal SinAverage;// = 0.637;
void initWcpAGC();
void loadWcpAGC();
bool getAGCHangEnable() { return m_agcHangEnable; }
private slots:
signals:
void agcMaximumGainChanged(qreal value);
void agcHangThresholdChanged(qreal value);
void hangLeveldBLineChanged(qreal value);
void minimumVoltageChanged(QObject* sender, int rx, qreal value);
void displayValues(QObject* sender, int rx, qreal minVoltage, qreal hangLevel);
};
#endif // _QTDSP_WPAGC_H
+223
View File
@@ -0,0 +1,223 @@
/**
* @file cusdr_buttons.cpp
* @brief Button implementation class for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2010-11-28
*/
/*
* adapted from: http://www.qtcentre.org/wiki/index.php?title=AeroButton
* Copyright (C) 2008 Jim Daniel
*
* (C) 2010, 2011 adapted for cuSDR by Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "cusdr_buttons.h"
AeroButton::AeroButton(QWidget *parent)
: QPushButton(parent)
,m_state(OFF)
,m_hovered(false)
,m_pressed(false)
,m_color(QColor(150, 150, 150))
,m_color_on(QColor(85, 210, 250))
//,m_color_on(QColor(105, 105, 250))
,m_highlight(QColor(0x91, 0xeb, 0xff))
,m_shadow(Qt::black)
,m_textcolor(QColor(255, 255, 255))
,m_opacity(1.0)
,m_glass(true)
,m_roundness(0){}
AeroButton::AeroButton(const QString &text, QWidget *parent)
: QPushButton(text, parent)
,m_state(OFF)
,m_hovered(false)
,m_pressed(false)
,m_color(QColor(90, 90, 90))
,m_color_on(QColor(85, 210, 250))
//,m_color_on(QColor(105, 105, 250))
,m_highlight(QColor(0x91, 0xeb, 0xff))
,m_shadow(Qt::black)
,m_textcolor(QColor(255, 255, 255))
,m_opacity(1.0)
,m_glass(true)
,m_roundness(0){}
AeroButton::AeroButton(const QIcon &icon, const QString &text, QWidget *parent)
: QPushButton(icon, text, parent)
,m_state(OFF)
,m_hovered(false)
,m_pressed(false)
,m_color(QColor(150, 150, 150))
,m_color_on(QColor(85, 210, 250))
//,m_color_on(QColor(105, 105, 250))
,m_highlight(QColor(0x91, 0xeb, 0xff))
,m_shadow(Qt::black)
,m_textcolor(QColor(255, 255, 255))
,m_icon(icon)
,m_opacity(1.0)
,m_glass(true)
,m_roundness(0){}
AeroButton::~AeroButton(){}
void AeroButton::paintEvent(QPaintEvent * pe)
{
Q_UNUSED(pe);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
//test for state changes
QColor button_color;
if(this->isEnabled())
{
if (m_state == ON) {
m_hovered ? button_color = m_highlight : button_color = m_color_on;
}
else if (m_state == OFF) {
m_hovered ? button_color = m_highlight : button_color = m_color;
}
if(m_pressed)
{
button_color = m_highlight.darker(250);
}
}
else
{
button_color = QColor(50, 50, 50);
}
QRect button_rect = this->geometry();
//outline
painter.setPen(QPen(QBrush(Qt::black), 2.0));
QPainterPath outline;
outline.addRoundRect(0, 0, button_rect.width(), button_rect.height(), m_roundness, m_roundness);
painter.setOpacity(m_opacity);
painter.drawPath(outline);
//gradient
QLinearGradient gradient(0, 0, 0, button_rect.height());
gradient.setSpread(QGradient::ReflectSpread);
gradient.setColorAt(0.0, button_color);
gradient.setColorAt(0.4, m_shadow);
gradient.setColorAt(0.6, m_shadow);
gradient.setColorAt(1.0, button_color);
QBrush brush(gradient);
painter.setBrush(brush);
painter.setPen(QPen(QBrush(button_color), 2.0));
//main button
QPainterPath painter_path;
painter_path.addRoundRect(1, 1, button_rect.width() - 2, button_rect.height() - 2, m_roundness, m_roundness);
painter.setClipPath(painter_path);
painter.setOpacity(m_opacity);
painter.drawRoundRect(1, 1, button_rect.width() - 2, button_rect.height() - 2, m_roundness, m_roundness);
//glass highlight
painter.setBrush(QBrush(Qt::white));
painter.setPen(QPen(QBrush(Qt::white), 0.01));
painter.setOpacity(0.30);
if (m_glass)
painter.drawRect(1, 1, button_rect.width() - 2, (button_rect.height() / 2) - 2);
//text
QString text = this->text();
if(!text.isNull())
{
QFont font = this->font();
painter.setFont(font);
//painter.setPen(Qt::white);
painter.setPen(m_textcolor);
painter.setOpacity(1.0);
painter.drawText(0, 0, button_rect.width(), button_rect.height(), Qt::AlignCenter, text);
}
//icon
//QIcon icon = this->icon();
QIcon icon = m_icon;
if(!icon.isNull())
{
QSize icon_size = this->iconSize();
QRect icon_position = this->calculateIconPosition(button_rect, icon_size);
//painter.setOpacity(1.0);
m_hovered ? painter.setOpacity(1.0) : painter.setOpacity(0.7);
painter.drawPixmap(icon_position, QPixmap(icon.pixmap(icon_size)));
//painter.drawPixmap(QRect(0, 0, icon_size.width(), icon_size.height()), QPixmap(icon.pixmap(icon_size)));
}
}
//void AeroButton::setBtnState( BtnState state ) { m_btnState = state; }
AeroButton::BtnState AeroButton::btnState() const { return m_state; }
void AeroButton::enterEvent(QEvent * e)
{
m_hovered = true;
this->repaint();
QPushButton::enterEvent(e);
}
void AeroButton::leaveEvent(QEvent * e)
{
m_hovered = false;
this->repaint();
QPushButton::leaveEvent(e);
}
void AeroButton::mousePressEvent(QMouseEvent * e)
{
m_pressed = true;
this->repaint();
QPushButton::mousePressEvent(e);
}
void AeroButton::mouseReleaseEvent(QMouseEvent * e)
{
m_pressed = false;
this->repaint();
QPushButton::mouseReleaseEvent(e);
}
QRect AeroButton::calculateIconPosition(QRect button_rect, QSize icon_size)
{
int x = (button_rect.width() / 2) - (icon_size.width() / 2);
int y = (button_rect.height() / 2) - (icon_size.height() / 2);
int width = icon_size.width();
int height = icon_size.height();
QRect icon_position;
icon_position.setX(x);
icon_position.setY(y);
icon_position.setWidth(width);
icon_position.setHeight(height);
return icon_position;
}
+100
View File
@@ -0,0 +1,100 @@
/**
* @file cusdr_buttons.h
* @brief Button implementation header file for cuSDR
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2010-11-28
*/
/*
* adapted from: http://www.qtcentre.org/wiki/index.php?title=AeroButton
* Copyright (C) 2008 Jim Daniel
*
* (C) 2010, 2011 adapted for cuSDR by Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef CUSDR_BUTTON
#define CUSDR_BUTTON
//#include <QtCore>
#include <QtGui>
#include <QPushButton>
class AeroButton : public QPushButton
{
Q_OBJECT
public:
AeroButton(QWidget* parent = 0);
AeroButton(const QString &text, QWidget* parent = 0);
AeroButton(const QIcon &icon, const QString &text, QWidget* parent = 0);
~AeroButton();
enum BtnState { OFF, ON };
void setBtnState(BtnState state) { m_state = state; }
BtnState btnState() const;
void setColor(QColor &color) { m_color = color; }
void setColorOn(QColor &color) { m_color_on = color; }
void setTextColor(QColor &color) { m_textcolor = color; }
void setHighlight(QColor &highlight) { m_highlight = highlight; }
void setShadow(QColor &shadow) { m_shadow = shadow; }
void setGlass(bool glass) { m_glass = glass; }
//Range: 0.0 [invisible] - 1.0 [opaque]
void setOpacity(qreal opacity) { m_opacity = opacity; }
//Range: 0 [rectangle] - 99 [oval]
void setRoundness(int roundness) { m_roundness = roundness; }
void setIcon(QIcon icon) { m_icon = icon; }
protected:
void paintEvent(QPaintEvent *pe);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
private:
QRect calculateIconPosition(QRect button_rect, QSize icon_size);
private:
BtnState m_state;
bool m_hovered;
bool m_pressed;
QColor m_color;
QColor m_color_on;
QColor m_highlight;
QColor m_shadow;
QColor m_textcolor;
QIcon m_icon;
qreal m_opacity;
bool m_glass;
int m_roundness;
};
#endif // CUSDR_BUTTON
File diff suppressed because it is too large Load Diff
+140
View File
@@ -0,0 +1,140 @@
/**
* @file cusdr_colorTriangle.h
* @brief Color triangle header file for cuSDR
*/
/****************************************************************************
**
** This file is part of a Qt Solutions component.
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Solutions Commercial License Agreement provided
** with the Software or, alternatively, in accordance with the terms
** contained in a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** Please note Third Party Software included with Qt Solutions may impose
** additional restrictions and it is the user's responsibility to ensure
** that they have met the licensing requirements of the GPL, LGPL, or Qt
** Solutions Commercial license and the relevant license of the Third
** Party Software they are using.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
****************************************************************************/
#ifndef _CUSDR_COLORTRIANGLE_H
#define _CUSDR_COLORTRIANGLE_H
#include <QImage>
#include <QWidget>
class QPointF;
struct Vertex;
#if defined(Q_WS_WIN)
# if !defined(QT_QTCOLORTRIANGLE_EXPORT) && !defined(QT_QTCOLORTRIANGLE_IMPORT)
# define QT_QTCOLORTRIANGLE_EXPORT
# elif defined(QT_QTCOLORTRIANGLE_IMPORT)
# if defined(QT_QTCOLORTRIANGLE_EXPORT)
# undef QT_QTCOLORTRIANGLE_EXPORT
# endif
# define QT_QTCOLORTRIANGLE_EXPORT __declspec(dllimport)
# elif defined(QT_QTCOLORTRIANGLE_EXPORT)
# undef QT_QTCOLORTRIANGLE_EXPORT
# define QT_QTCOLORTRIANGLE_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTCOLORTRIANGLE_EXPORT
#endif
class QT_QTCOLORTRIANGLE_EXPORT QtColorTriangle : public QWidget
{
Q_OBJECT
public:
QtColorTriangle(QWidget *parent = 0);
~QtColorTriangle();
QSize sizeHint() const;
int heightForWidth(int w) const;
void polish();
QColor color() const;
Q_SIGNALS:
void colorChanged(const QColor &col);
public Q_SLOTS:
void setColor(const QColor &col);
QColor getColor() { return curColor; }
protected:
void paintEvent(QPaintEvent *);
void mouseMoveEvent(QMouseEvent *);
void mousePressEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
void keyPressEvent(QKeyEvent *e);
void resizeEvent(QResizeEvent *);
void drawTrigon(QImage *p, const QPointF &a, const QPointF &b,
const QPointF &c, const QColor &color);
private:
double radiusAt(const QPointF &pos, const QRect &rect) const;
double angleAt(const QPointF &pos, const QRect &rect) const;
QPointF movePointToTriangle(double x, double y, const Vertex &a,
const Vertex &b, const Vertex &c) const;
QPointF pointFromColor(const QColor &col) const;
QColor colorFromPoint(const QPointF &p) const;
void genBackground();
QImage bg;
double a, b, c;
QPointF pa, pb, pc, pd;
QColor curColor;
int curHue;
bool mustGenerateBackground;
int penWidth;
int ellipseSize;
int outerRadius;
QPointF selectorPos;
enum SelectionMode {
Idle,
SelectingHue,
SelectingSatValue
} selMode;
};
#endif // _CUSDR_COLORTRIANGLE_H
+316
View File
@@ -0,0 +1,316 @@
/*
* Windows part for CPU usage by (c) 2009 Ben Watson
*
* taken from http://www.philosophicalgeek.com/2009/01/03/determine-cpu-usage-of-current-process-c-and-c/
*
* adapted for cuSDR by (c) 2012 Hermann von Hasseln, DL3HVH
*
*
* Linux part for CPU usage by (c) by Fabian Holler
*
* taken from https://github.com/fho/code_snippets/blob/master/c/getusage.c
*
* adapted for cuSDR by (c) 2012 Andrea Montefusco, IW0HDV
*
*/
#include "cusdr_cpuUsage.h"
#if defined(Q_OS_LINUX)
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <strings.h> // bzero
#include <unistd.h> // getpagesize
#include <string.h> // strncat, strlen
/*
* read /proc data into the passed struct pstat
* returns 0 on success, -1 on error
*/
static int get_usage(const pid_t pid, struct pstat* result) {
//convert pid to string
char pid_s[20];
snprintf(pid_s, sizeof(pid_s), "%d", pid);
char stat_filepath[30] = "/proc/"; strncat(stat_filepath, pid_s,
sizeof(stat_filepath) - strlen(stat_filepath) -1);
strncat(stat_filepath, "/stat", sizeof(stat_filepath) -
strlen(stat_filepath) -1);
//Open /proc/stat and /proc/$pid/stat fds successive(dont want that cpu
//ticks increases too much during measurements)
//TODO: open /proc dir, to lock all files and read the results from the
//same timefragem
FILE *fpstat = fopen(stat_filepath, "r");
if (fpstat == NULL) {
perror("FOPEN ERROR ");
return -1;
}
FILE *fstat = fopen("/proc/stat", "r");
if (fstat == NULL) {
perror("FOPEN ERROR ");
fclose(fstat);
return -1;
}
//read values from /proc/pid/stat
bzero(result, sizeof(struct pstat));
long int rss;
if (fscanf(fpstat, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu"
"%lu %ld %ld %*d %*d %*d %*d %*u %lu %ld",
&result->utime_ticks, &result->stime_ticks,
&result->cutime_ticks, &result->cstime_ticks, &result->vsize,
&rss) == EOF) {
fclose(fpstat);
return -1;
}
fclose(fpstat);
result->rss = rss * getpagesize();
//read+calc cpu total time from /proc/stat
long unsigned int cpu_time[10];
bzero(cpu_time, sizeof(cpu_time));
if (fscanf(fstat, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&cpu_time[0], &cpu_time[1], &cpu_time[2], &cpu_time[3],
&cpu_time[4], &cpu_time[5], &cpu_time[6], &cpu_time[7],
&cpu_time[8], &cpu_time[9]) == EOF) {
fclose(fstat);
return -1;
}
fclose(fstat);
for (int i = 0; i < 10; i++) {
result->cpu_total_time += cpu_time[i];
}
return 0;
}
/*
* calculates the actual CPU usage(cur_usage - last_usage) in percent
* cur_usage, last_usage: both last measured get_usage() results
* ucpu_usage, scpu_usage: result parameters: user and sys cpu usage in %
*/
static void calc_cpu_usage(const struct pstat* cur_usage, const struct pstat*
last_usage, double* ucpu_usage, double* scpu_usage) {
const long unsigned int total_time_diff = cur_usage->cpu_total_time - last_usage->cpu_total_time;
*ucpu_usage = 100 * (((cur_usage->utime_ticks + cur_usage->cutime_ticks)
- (last_usage->utime_ticks + last_usage->cutime_ticks))
/ (double) total_time_diff);
*scpu_usage = 100 * ((((cur_usage->stime_ticks + cur_usage->cstime_ticks)
- (last_usage->stime_ticks + last_usage->cstime_ticks))) /
(double) total_time_diff);
}
CpuUsage :: CpuUsage (void) {
pid = getpid();
int rc = get_usage(pid, &cpst);
if (rc < 0) {
printf ("Error, check PID\n");
}
else {
lpst = cpst;
}
}
short CpuUsage :: GetUsage (void) {
int rc = get_usage(pid, &cpst);
if (rc < 0) {
printf ("Error, check PID\n");
}
double ucpu_usage;
double scpu_usage;
calc_cpu_usage (&cpst, &lpst, &ucpu_usage, &scpu_usage);
//printf ("usr: %7.2g sys: %7.2g", ucpu_usage, scpu_usage);
//printf (" T: %7.0f\n", (float)(ucpu_usage+scpu_usage)/2.0*10.0);
lpst = cpst;
return (short) ((ucpu_usage+scpu_usage)/2.0*10.0);
}
#endif
#ifdef TEST_MODULE
int main (int argc, char **argv) {
int pid;
struct pstat cpst;
struct pstat lpst;
if (argc > 1 && sscanf (argv[1], "%d", &pid) == 1) {
int rc = get_usage(pid, &cpst);
if (rc < 0) {
printf ("Error, check PID\n");
return 254;
}
else {
lpst = cpst;
}
}
else {
return 255;
}
for (;;) {
sleep (1);
int rc = get_usage(pid, &cpst);
if (rc < 0) {
printf ("Error, check PID\n");
return 254;
}
double ucpu_usage;
double scpu_usage;
calc_cpu_usage (&cpst, &lpst, &ucpu_usage, &scpu_usage);
printf ("usr: %7.2g sys: %7.2g", ucpu_usage, scpu_usage);
printf (" T: %7.0f\n", (float)(ucpu_usage+scpu_usage)/2.0*10.0);
lpst = cpst;
}
}
#endif
#if defined(Q_OS_WIN32)
//#error WWWWWWWW
CpuUsage::CpuUsage(void)
:m_nCpuUsage(-1)
,m_dwLastRun(0)
,m_lRunCount(0)
{
ZeroMemory(&m_ftPrevSysKernel, sizeof(FILETIME));
ZeroMemory(&m_ftPrevSysUser, sizeof(FILETIME));
ZeroMemory(&m_ftPrevProcKernel, sizeof(FILETIME));
ZeroMemory(&m_ftPrevProcUser, sizeof(FILETIME));
}
/**********************************************
* CpuUsage::GetUsage
* returns the percent of the CPU that this process
* has used since the last time the method was called.
* If there is not enough information, -1 is returned.
* If the method is recalled to quickly, the previous value
* is returned.
***********************************************/
short CpuUsage::GetUsage() {
//create a local copy to protect against race conditions in setting the
//member variable
short nCpuCopy = m_nCpuUsage;
if (::InterlockedIncrement(&m_lRunCount) == 1) {
/*
If this is called too often, the measurement itself will greatly affect the
results.
*/
if (!EnoughTimePassed()) {
::InterlockedDecrement(&m_lRunCount);
return nCpuCopy;
}
FILETIME ftSysIdle, ftSysKernel, ftSysUser;
FILETIME ftProcCreation, ftProcExit, ftProcKernel, ftProcUser;
if (!GetSystemTimes(&ftSysIdle, &ftSysKernel, &ftSysUser) ||
!GetProcessTimes(GetCurrentProcess(), &ftProcCreation, &ftProcExit, &ftProcKernel, &ftProcUser))
{
::InterlockedDecrement(&m_lRunCount);
return nCpuCopy;
}
if (!IsFirstRun()) {
/*
CPU usage is calculated by getting the total amount of time the system has operated
since the last measurement (made up of kernel + user) and the total
amount of time the process has run (kernel + user).
*/
ULONGLONG ftSysKernelDiff = SubtractTimes(ftSysKernel, m_ftPrevSysKernel);
ULONGLONG ftSysUserDiff = SubtractTimes(ftSysUser, m_ftPrevSysUser);
ULONGLONG ftProcKernelDiff = SubtractTimes(ftProcKernel, m_ftPrevProcKernel);
ULONGLONG ftProcUserDiff = SubtractTimes(ftProcUser, m_ftPrevProcUser);
ULONGLONG nTotalSys = ftSysKernelDiff + ftSysUserDiff;
ULONGLONG nTotalProc = ftProcKernelDiff + ftProcUserDiff;
if (nTotalSys > 0) {
m_nCpuUsage = (short)((100.0 * nTotalProc) / nTotalSys);
}
}
m_ftPrevSysKernel = ftSysKernel;
m_ftPrevSysUser = ftSysUser;
m_ftPrevProcKernel = ftProcKernel;
m_ftPrevProcUser = ftProcUser;
m_dwLastRun = GetTickCount();
nCpuCopy = m_nCpuUsage;
}
::InterlockedDecrement(&m_lRunCount);
return nCpuCopy;
}
ULONGLONG CpuUsage::SubtractTimes(const FILETIME& ftA, const FILETIME& ftB) {
LARGE_INTEGER a, b;
a.LowPart = ftA.dwLowDateTime;
a.HighPart = ftA.dwHighDateTime;
b.LowPart = ftB.dwLowDateTime;
b.HighPart = ftB.dwHighDateTime;
return a.QuadPart - b.QuadPart;
}
bool CpuUsage::EnoughTimePassed() {
const int minElapsedMS = 250;//milliseconds
ULONGLONG dwCurrentTickCount = GetTickCount();
return ((int)(dwCurrentTickCount - m_dwLastRun)) > minElapsedMS;
}
#endif
+87
View File
@@ -0,0 +1,87 @@
/*
* Windows part for CPU usage by (c) 2009 Ben Watson
*
* taken from http://www.philosophicalgeek.com/2009/01/03/determine-cpu-usage-of-current-process-c-and-c/
*
* adapted for cuSDR by (c) 2012 Hermann von Hasseln, DL3HVH
*
*
* Linux part for CPU usage by (c) by Fabian Holler
*
* taken from https://github.com/fho/code_snippets/blob/master/c/getusage.c
*
* adapted for cuSDR by (c) 2012 Andrea Montefusco, IW0HDV
*
*/
#include <QtGlobal> // needed in order to get Q_OS_LINUX macro defined
#if defined(Q_OS_WIN32)
#pragma once
//#define _WIN32_WINNT 0×0501
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <windows.h>
class CpuUsage {
public:
CpuUsage(void);
short GetUsage();
private:
ULONGLONG SubtractTimes(const FILETIME& ftA, const FILETIME& ftB);
bool EnoughTimePassed();
inline bool IsFirstRun() const { return (m_dwLastRun == 0); }
//system total times
FILETIME m_ftPrevSysKernel;
FILETIME m_ftPrevSysUser;
//process times
FILETIME m_ftPrevProcKernel;
FILETIME m_ftPrevProcUser;
short m_nCpuUsage;
ULONGLONG m_dwLastRun;
volatile LONG m_lRunCount;
};
#elif defined(Q_OS_LINUX)
#include <sys/types.h>
#include <unistd.h>
struct pstat {
long unsigned int utime_ticks;
long int cutime_ticks;
long unsigned int stime_ticks;
long int cstime_ticks;
long unsigned int vsize; // virtual memory size in bytes
long unsigned int rss; //Resident Set Size in bytes
long unsigned int cpu_total_time;
};
class CpuUsage {
public:
CpuUsage(void);
short GetUsage(void);
private:
pid_t pid;
struct pstat cpst;
struct pstat lpst;
};
#endif
+42
View File
@@ -0,0 +1,42 @@
#include <unistd.h>
#include <sys/resource.h>
#include <sys/times.h>
#include "cusdr_cpuUsage_unix.h"
#include "cusdr_settings.h"
cusdr_cpuUsage::cusdr_cpuUsage()
{
ptick=0;
ptime=0.0;
CLOCK_TICK = sysconf(_SC_CLK_TCK);
QTimer *timer = new QTimer();
cusdr_cpuUsage::connect(timer, SIGNAL(timeout()), this, SLOT(getCPUUsage()));
timer->start(1000);
}
void cusdr_cpuUsage::getCPUUsage()
{
clock_t tick;
double time;
double load;
struct rusage usage;
struct tms systime;
tick = times(&systime);
getrusage(RUSAGE_SELF, &usage);
time = usage.ru_utime.tv_sec + usage.ru_utime.tv_usec * 1e-6 +
usage.ru_stime.tv_sec + usage.ru_stime.tv_usec * 1e-6;
load = ((time-ptime)/(tick-ptick)) * CLOCK_TICK * 100;
if(ptick && ptime)
Settings::instance()->setCPULoad((int) load);
ptick=tick;
ptime=time;
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef CUSDR_CPULOAD_H
#define CUSDR_CPULOAD_H
#include <QThread>
#include <QTimer>
class cusdr_cpuUsage : public QThread
{
Q_OBJECT
public:
clock_t ptick;
double ptime;
QTimer *timer;
cusdr_cpuUsage();
private:
int CLOCK_TICK;
private slots:
void getCPUUsage();
};
#endif // CUSDR_CPULOAD_H
+109
View File
@@ -0,0 +1,109 @@
/**
* @file cusdr_highResTimer.h
* @brief HPSDR high resolution timer header file
* @author Song Ho Ahn (song.ahn@gmail.com)
* @version
* @date 2006-01-13
*/
/*
* High Resolution Timer.
* This timer is able to measure the elapsed time with 1 micro-second accuracy
* in both Windows, Linux and Unix system
*
* Copyright 2006 Song Ho Ahn (song.ahn@gmail.com)
* Copyright 2012 adapted for cuSDR by Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "cusdr_highResTimer.h"
#include <stdlib.h>
HResTimer::HResTimer() {
#ifdef WIN32
QueryPerformanceFrequency(&frequency);
startCount.QuadPart = 0;
endCount.QuadPart = 0;
#else
startCount.tv_sec = startCount.tv_usec = 0;
endCount.tv_sec = endCount.tv_usec = 0;
#endif
stopped = 0;
startTimeInMicroSec = 0;
endTimeInMicroSec = 0;
}
HResTimer::~HResTimer() {
}
void HResTimer::start() {
stopped = 0; // reset stop flag
#ifdef WIN32
QueryPerformanceCounter(&startCount);
#else
gettimeofday(&startCount, NULL);
#endif
}
void HResTimer::stop() {
stopped = 1; // set timer stopped flag
#ifdef WIN32
QueryPerformanceCounter(&endCount);
#else
gettimeofday(&endCount, NULL);
#endif
}
double HResTimer::getElapsedTimeInMicroSec() {
#ifdef WIN32
if(!stopped)
QueryPerformanceCounter(&endCount);
startTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart);
endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);
#else
if(!stopped)
gettimeofday(&endCount, NULL);
startTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec;
endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;
#endif
return endTimeInMicroSec - startTimeInMicroSec;
}
double HResTimer::getElapsedTimeInMilliSec() {
return this->getElapsedTimeInMicroSec() * 0.001;
}
double HResTimer::getElapsedTimeInSec() {
return this->getElapsedTimeInMicroSec() * 0.000001;
}
double HResTimer::getElapsedTime() {
return this->getElapsedTimeInSec();
}
+72
View File
@@ -0,0 +1,72 @@
/**
* @file cusdr_highResTimer.h
* @brief HPSDR high resolution timer header file
* @author Song Ho Ahn (song.ahn@gmail.com)
* @version
* @date 2006-01-13
*/
/*
* High Resolution Timer.
* This timer is able to measure the elapsed time with 1 micro-second accuracy
* in both Windows, Linux and Unix system
*
* Copyright 2006 Song Ho Ahn (song.ahn@gmail.com)
* Copyright 2012 adapted for cuSDR by Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef CUSDR_HRES_TIMER_H
#define CUSDR_HRES_TIMER_H
#ifdef WIN32 // Windows system specific
#include <windows.h>
#else // Unix based system specific
#include <sys/time.h>
#endif
class HResTimer {
public:
HResTimer(); // default constructor
~HResTimer(); // default destructor
void start(); // start timer
void stop(); // stop the timer
double getElapsedTime(); // get elapsed time in second
double getElapsedTimeInSec(); // get elapsed time in second (same as getElapsedTime)
double getElapsedTimeInMilliSec(); // get elapsed time in milli-second
double getElapsedTimeInMicroSec(); // get elapsed time in micro-second
protected:
private:
double startTimeInMicroSec; // starting time in micro-second
double endTimeInMicroSec; // ending time in micro-second
int stopped; // stop flag
#ifdef WIN32
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER startCount; //
LARGE_INTEGER endCount; //
#else
timeval startCount; //
timeval endCount; //
#endif
};
#endif // CUSDR_HRES_TIMER_H
+96
View File
@@ -0,0 +1,96 @@
/**
* @file cusdr_image.cpp
* @brief image definitions class for cuSDR
*/
/*
* This is an adaptation of Matteo Bertozzi's "Black Bar and Buttons" code.
*
* see: http://qt-apps.org/content/show.php/Black+Bar+and+Buttons?content=100399
*
* Copyright 2009 Matteo Bertozzi
* Copyright 2010 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "cusdr_imageblur.h"
#include "cusdr_painter.h"
#include "cusdr_image.h"
QHImage::QHImage (const QSize& size, Format format)
: QImage(size, format)
{
}
QHImage::QHImage (int width, int height, Format format)
: QImage(width, height, format)
{
}
QHImage::QHImage (uchar *data, int width, int height, Format format)
: QImage(data, width, height, format)
{
}
QHImage::QHImage (const uchar *data, int width, int height, Format format)
: QImage(data, width, height, format)
{
}
QHImage::QHImage (uchar *data, int width, int height, int bytesPerLine, Format format)
: QImage(data, width, height, bytesPerLine, format)
{
}
QHImage::QHImage (const uchar *data, int width, int height, int bytesPerLine, Format format)
: QImage(data, width, height, bytesPerLine, format)
{
}
QHImage::QHImage (const QString& fileName, const char *format)
: QImage(fileName, format)
{
}
QHImage::QHImage (const char *fileName, const char *format)
: QImage(fileName, format)
{
}
QHImage::QHImage (const QImage& image)
: QImage(image)
{
}
QHImage::~QHImage() {
}
void QHImage::expblur(int aprec, int zprec, int radius) {
ImageBlur::expblur(this, aprec, zprec, radius);
}
#include <QCoreApplication>
void QHImage::shadowBlur (int radius, const QColor& color) {
ImageBlur::expblur(this, 16, 7, radius);
QHPainter p(this);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(rect(), color);
p.end();
}
+52
View File
@@ -0,0 +1,52 @@
/**
* @file cusdr_image.h
* @brief image definitions header file for cuSDR
*/
/*
* This is an adaptation of Matteo Bertozzi's "Black Bar and Buttons" code.
*
* see: http://qt-apps.org/content/show.php/Black+Bar+and+Buttons?content=100399
*
* Copyright 2009 Matteo Bertozzi
* Copyright 2010 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef CUSDR_IMAGE_H
#define CUSDR_IMAGE_H
#include <QImage>
class QHImage : public QImage {
public:
QHImage (const QSize& size, Format format);
QHImage (int width, int height, Format format);
QHImage (uchar *data, int width, int height, Format format);
QHImage (const uchar *data, int width, int height, Format format);
QHImage (uchar *data, int width, int height, int bytesPerLine, Format format);
QHImage (const uchar *data, int width, int height, int bytesPerLine, Format format);
QHImage (const QString& fileName, const char *format = 0);
QHImage (const char *fileName, const char *format = 0);
QHImage (const QImage& image);
~QHImage();
public:
void expblur(int aprec, int zprec, int radius);
void shadowBlur (int radius, const QColor& color);
};
#endif // CUSDR_IMAGE_H
+139
View File
@@ -0,0 +1,139 @@
/**
* @file cusdr_imageblur.cpp
* @brief image blur class for cuSDR
*/
/*
* This is an adaptation of Jani Huhtanen Exponential blur code.
*
* Copyright 2007 Jani Huhtanen <jani.huhtanen@tut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <QImage>
#include <cmath>
#include "cusdr_imageblur.h"
/* ============================================================================
* PUBLIC Constructor/Destructors
*/
ImageBlur::ImageBlur (QImage *image, int aprec, int zprec) {
m_image = image;
m_aprec = aprec;
m_zprec = zprec;
}
ImageBlur::~ImageBlur() {
m_image = NULL;
}
/* ============================================================================
* PUBLIC STATIC Methods
*/
void ImageBlur::expblur (QImage *image, int aprec, int zprec, int radius) {
ImageBlur imageBlur(image, aprec, zprec);
imageBlur.expblur(radius);
}
/* ============================================================================
* PUBLIC Methods
*/
void ImageBlur::expblur (int radius) {
if (radius < 1)
return;
/* Calculate the alpha such that 90% of
* the kernel is within the radius.
* (Kernel extends to infinity)
*/
//int alpha = (int)((1 << m_aprec) * (1.0f - std::exp(-2.3f / (radius + 1.f))));
int alpha = (unsigned int)((1 << m_aprec) * (1.0f - std::exp(-2.3f / (radius + 1.f))));
for (int row = 0; row < m_image->height(); ++row)
blurrow(row, alpha);
for (int col = 0; col < m_image->width(); ++col)
blurcol(col, alpha);
}
/* ============================================================================
* PRIVATE Methods
*/
void ImageBlur::blurcol (int col, int alpha) {
int zR, zG, zB, zA;
QRgb *ptr = (QRgb *)m_image->bits();
ptr += col;
zR = *((unsigned char *)ptr ) << m_zprec;
zG = *((unsigned char *)ptr + 1) << m_zprec;
zB = *((unsigned char *)ptr + 2) << m_zprec;
zA = *((unsigned char *)ptr + 3) << m_zprec;
for (int index = m_image->width();
index < (m_image->height() - 1) * m_image->width();
index += m_image->width())
{
blurinner((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
}
for (int index = (m_image->height() - 2) * m_image->width();
index >= 0;
index -= m_image->width())
{
blurinner((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
}
}
void ImageBlur::blurrow (int line, int alpha) {
int zR, zG, zB, zA;
QRgb *ptr = (QRgb *)m_image->scanLine(line);
zR = *((unsigned char *)ptr ) << m_zprec;
zG = *((unsigned char *)ptr + 1) << m_zprec;
zB = *((unsigned char *)ptr + 2) << m_zprec;
zA = *((unsigned char *)ptr + 3) << m_zprec;
for (int index = 1; index < m_image->width(); ++index)
blurinner((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
for (int index = m_image->width() - 2; index >= 0; --index)
blurinner((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
}
void ImageBlur::blurinner ( unsigned char *bptr,
int &zR, int &zG, int &zB, int &zA,
int alpha)
{
int R, G, B, A;
R = *bptr;
G = *(bptr + 1);
B = *(bptr + 2);
A = *(bptr + 3);
zR += (alpha * ((R << m_zprec) - zR)) >> m_aprec;
zG += (alpha * ((G << m_zprec) - zG)) >> m_aprec;
zB += (alpha * ((B << m_zprec) - zB)) >> m_aprec;
zA += (alpha * ((A << m_zprec) - zA)) >> m_aprec;
*bptr = zR >> m_zprec;
*(bptr+1) = zG >> m_zprec;
*(bptr+2) = zB >> m_zprec;
*(bptr+3) = zA >> m_zprec;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file cusdr_imageblur.h
* @brief image blur header file for cuSDR
*/
/*
* This is an adaptation of Jani Huhtanen Exponential blur code.
*
* Copyright 2007 Jani Huhtanen <jani.huhtanen@tut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _KDE_PLASMA_BLUR_H_
#define _KDE_PLASMA_BLUR_H_
class QImage;
class ImageBlur {
public:
ImageBlur (QImage *image, int aprec, int zprec);
~ImageBlur();
public:
void expblur (int radius);
public:
static void expblur (QImage *image, int aprec, int zprec, int radius);
private:
void blurcol (int col, int alpha);
void blurrow (int line, int alpha);
void blurinner (unsigned char *bptr,
int &zR, int &zG, int &zB, int &zA,
int alpha);
private:
QImage *m_image;
int m_aprec;
int m_zprec;
};
#endif /* !_KDE_PLASMA_BLUR_H_ */
+91
View File
@@ -0,0 +1,91 @@
/**
* @file cusdr_led.cpp
* @brief LED objects
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2010-09-21
*/
/*
*
* Copyright 2010 Hermann von Hasseln, DL3HVH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//#include <QtGui>
#include <QDebug>
#include <QPaintEvent>
#include "cusdr_led.h"
//#include "cusdr_settings.h"
QHLed::QHLed(const QString& text, QWidget *parent) : QAbstractButton (parent) {
setText(text);
this->setEnabled(false);
}
QHLed::~QHLed() {
}
void QHLed::setColors(const QColor bgr, const QColor pen) {
penColor = pen;
linearGrad = QLinearGradient(QPointF(0, 0), QPointF(0, 1));
linearGrad.setCoordinateMode(QGradient::ObjectBoundingMode);
linearGrad.setSpread(QGradient::PadSpread);
linearGrad.setColorAt(0, bgr);
//linearGrad.setColorAt(0.8, QColor(0x31, 0x8b, 0xda));
linearGrad.setColorAt(1, bgr);
update();
}
//void QHLed::changeColor (QColor color) {
//}
void QHLed::setLEDText(const QString& text) {
QHLed::setText(text);
}
QSize QHLed::minimumSizeHint(void) const {
QFontMetrics fontMetrics(QFont("Arial", 8, QFont::Bold));
int width = fontMetrics.width(text()) + 12;
return(QSize(width, 13));
}
void QHLed::paintEvent(QPaintEvent *event) {
int height = event->rect().height();
int width = event->rect().width();
p = new QHPainter(this);
p->setPen (QPen(penColor, 1));
p->fillRoundRect(QRect(0, 0, width, height), 1, 1, 1, 1, QBrush(linearGrad));
p->setFont (QFont("Arial", 8, -1, true));
//p->setPen(QPen(m_btnPenColor, 1));
//p->drawText(event->rect(), Qt::AlignCenter, text());
p->drawText(event->rect(), Qt::AlignLeft, text());
p->end();
}

Some files were not shown because too many files have changed in this diff Show More