first commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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() << "======================================================================";
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user