diff options
author | Christian Daniel <cd@maintech.de> | 2013-03-22 11:18:30 +0100 |
---|---|---|
committer | Christian Daniel <cd@maintech.de> | 2013-03-22 11:18:30 +0100 |
commit | eca56e35be841396f6c57bab540a3e1503253d56 (patch) | |
tree | 4a0a29cd53a84339e56754c32bf67391c83494fe /include | |
parent | 2c8c930b39fe069b36d81caa00401d9ac182a9d8 (diff) |
monster rework
- pluginify whole project
- reorganize directory structure
- fix PortAudio detection script
- implement generic channelizer
- fix several OpenGL problems
- rework presets
- add audio mixing
- too many more
Diffstat (limited to 'include')
-rw-r--r-- | include/dsp/channelmarker.h | 39 | ||||
-rw-r--r-- | include/dsp/dsptypes.h | 54 | ||||
-rw-r--r-- | include/dsp/kissfft.h | 391 | ||||
-rw-r--r-- | include/dsp/samplefifo.h | 68 | ||||
-rw-r--r-- | include/dsp/samplesink.h | 42 | ||||
-rw-r--r-- | include/dsp/samplesource/samplesource.h | 60 | ||||
-rw-r--r-- | include/dsp/threadedsamplesink.h | 40 | ||||
-rw-r--r-- | include/plugin/pluginapi.h | 56 | ||||
-rw-r--r-- | include/plugin/plugingui.h | 29 | ||||
-rw-r--r-- | include/plugin/plugininterface.h | 48 | ||||
-rw-r--r-- | include/util/message.h | 50 | ||||
-rw-r--r-- | include/util/messagequeue.h | 30 | ||||
-rw-r--r-- | include/util/miniz.h | 7 | ||||
-rw-r--r-- | include/util/simpleserializer.h | 111 | ||||
-rw-r--r-- | include/util/spinlock.h | 39 |
15 files changed, 1064 insertions, 0 deletions
diff --git a/include/dsp/channelmarker.h b/include/dsp/channelmarker.h new file mode 100644 index 0000000..229e7f1 --- /dev/null +++ b/include/dsp/channelmarker.h @@ -0,0 +1,39 @@ +#ifndef INCLUDE_CHANNELMARKER_H +#define INCLUDE_CHANNELMARKER_H + +#include <QObject> +#include <QColor> + +class ChannelMarker : public QObject { + Q_OBJECT + +public: + ChannelMarker(QObject* parent = NULL); + + void setTitle(const QString& title); + const QString& getTitle() const { return m_title; } + + void setCenterFrequency(int centerFrequency); + int getCenterFrequency() const { return m_centerFrequency; } + + void setBandwidth(int bandwidth); + int getBandwidth() const { return m_bandwidth; } + + void setVisible(bool visible); + bool getVisible() const { return m_visible; } + + void setColor(const QColor& color); + const QColor& getColor() const { return m_color; } + +protected: + QString m_title; + int m_centerFrequency; + int m_bandwidth; + bool m_visible; + QColor m_color; + +signals: + void changed(); +}; + +#endif // INCLUDE_CHANNELMARKER_H diff --git a/include/dsp/dsptypes.h b/include/dsp/dsptypes.h new file mode 100644 index 0000000..b6bbf67 --- /dev/null +++ b/include/dsp/dsptypes.h @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_DSPTYPES_H +#define INCLUDE_DSPTYPES_H + +#include <complex> +#include <vector> +#include <QtGlobal> + +typedef float Real; +typedef std::complex<Real> Complex; + +typedef qint16 FixReal; + +#pragma pack(push, 1) +struct Sample { + Sample() {} + Sample(FixReal real) : m_real(real), m_imag(0) {} + Sample(FixReal real, FixReal imag) : m_real(real), m_imag(imag) {} + Sample(const Sample& other) : m_real(other.m_real), m_imag(other.m_imag) {} + Sample& operator=(const Sample& other) { m_real = other.m_real; m_imag = other.m_imag; return *this; } + + Sample& operator+=(const Sample& other) { m_real += other.m_real; m_imag += other.m_imag; return *this; } + Sample& operator-=(const Sample& other) { m_real -= other.m_real; m_imag -= other.m_imag; return *this; } + + void setReal(FixReal v) { m_real = v; } + void setImag(FixReal v) { m_imag = v; } + + FixReal real() const { return m_real; } + FixReal imag() const { return m_imag; } + + FixReal m_real; + FixReal m_imag; +}; +#pragma pack(pop) + +typedef std::vector<Sample> SampleVector; + +#endif // INCLUDE_DSPTYPES_H diff --git a/include/dsp/kissfft.h b/include/dsp/kissfft.h new file mode 100644 index 0000000..ba1256c --- /dev/null +++ b/include/dsp/kissfft.h @@ -0,0 +1,391 @@ +#ifndef INCLUDE_KISSFFT_H +#define INCLUDE_KISSFFT_H + +#include <complex> +#include <vector> + +/* +Copyright (c) 2003-2010 Mark Borgerding + +All rights reserved. + +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 author nor the names of any 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. +*/ + +namespace kissfft_utils { + + template<typename T_scalar, typename T_complex> + struct traits { + typedef T_scalar scalar_type; + typedef T_complex cpx_type; + void fill_twiddles(std::complex<T_scalar>* dst, int nfft, bool inverse) + { + T_scalar phinc = (inverse ? 2 : -2) * acos((T_scalar)-1) / nfft; + for(int i = 0; i < nfft; ++i) + dst[i] = exp(std::complex<T_scalar>(0, i * phinc)); + } + + void prepare(std::vector<std::complex<T_scalar> >& dst, int nfft, bool inverse, std::vector<int>& stageRadix, std::vector<int>& stageRemainder) + { + _twiddles.resize(nfft); + fill_twiddles(&_twiddles[0], nfft, inverse); + dst = _twiddles; + + //factorize + //start factoring out 4's, then 2's, then 3,5,7,9,... + int n = nfft; + int p = 4; + do { + while(n % p) { + switch(p) { + case 4: + p = 2; + break; + case 2: + p = 3; + break; + default: + p += 2; + break; + } + if(p * p > n) + p = n;// no more factors + } + n /= p; + stageRadix.push_back(p); + stageRemainder.push_back(n); + } while(n > 1); + } + std::vector<cpx_type> _twiddles; + + const cpx_type twiddle(int i) + { + return _twiddles[i]; + } + }; + +} // namespace + +template<typename T_Scalar, typename T_Complex, typename T_traits = kissfft_utils::traits<T_Scalar, T_Complex> > +class kissfft { +public: + typedef T_traits traits_type; + typedef typename traits_type::scalar_type scalar_type; + typedef typename traits_type::cpx_type cpx_type; + + kissfft() + { + } + + kissfft(int nfft, bool inverse, const traits_type & traits = traits_type()) : + _nfft(nfft), _inverse(inverse), _traits(traits) + { + _traits.prepare(_twiddles, _nfft, _inverse, _stageRadix, _stageRemainder); + } + + void configure(int nfft, bool inverse, const traits_type & traits = traits_type()) + { + _twiddles.clear(); + _stageRadix.clear(); + _stageRemainder.clear(); + + _nfft = nfft; + _inverse = inverse; + _traits = traits; + _traits.prepare(_twiddles, _nfft, _inverse, _stageRadix, _stageRemainder); + } + + void transform(const cpx_type* src, cpx_type* dst) + { + kf_work(0, dst, src, 1, 1); + } + +private: + void kf_work(int stage, cpx_type* Fout, const cpx_type* f, size_t fstride, size_t in_stride) + { + int p = _stageRadix[stage]; + int m = _stageRemainder[stage]; + cpx_type * Fout_beg = Fout; + cpx_type * Fout_end = Fout + p * m; + + if(m == 1) { + do { + *Fout = *f; + f += fstride * in_stride; + } while(++Fout != Fout_end); + } else { + do { + // recursive call: + // DFT of size m*p performed by doing + // p instances of smaller DFTs of size m, + // each one takes a decimated version of the input + kf_work(stage + 1, Fout, f, fstride * p, in_stride); + f += fstride * in_stride; + } while((Fout += m) != Fout_end); + } + + Fout = Fout_beg; + + // recombine the p smaller DFTs + switch(p) { + case 2: + kf_bfly2(Fout, fstride, m); + break; + case 3: + kf_bfly3(Fout, fstride, m); + break; + case 4: + kf_bfly4(Fout, fstride, m); + break; + case 5: + kf_bfly5(Fout, fstride, m); + break; + default: + kf_bfly_generic(Fout, fstride, m, p); + break; + } + } + + // these were #define macros in the original kiss_fft + void C_ADD(cpx_type& c, const cpx_type& a, const cpx_type& b) + { + c = a + b; + } + void C_MUL(cpx_type& c, const cpx_type& a, const cpx_type& b) + { + //c = a * b; + c = cpx_type(a.real() * b.real() - a.imag() * b.imag(), a.real() * b.imag() + a.imag() * b.real()); + } + void C_SUB(cpx_type& c, const cpx_type& a, const cpx_type& b) + { + c = a - b; + } + void C_ADDTO(cpx_type& c, const cpx_type& a) + { + c += a; + } + void C_FIXDIV(cpx_type&, int) + { + } // NO-OP for float types + scalar_type S_MUL(const scalar_type& a, const scalar_type& b) + { + return a * b; + } + scalar_type HALF_OF(const scalar_type& a) + { + return a * .5; + } + void C_MULBYSCALAR(cpx_type& c, const scalar_type& a) + { + c *= a; + } + + void kf_bfly2(cpx_type* Fout, const size_t fstride, int m) + { + for(int k = 0; k < m; ++k) { + //cpx_type t = Fout[m + k] * _traits.twiddle(k * fstride); + cpx_type t; + C_MUL(t, Fout[m + k], _traits.twiddle(k * fstride)); + Fout[m + k] = Fout[k] - t; + Fout[k] += t; + } + } + + void kf_bfly4(cpx_type* Fout, const size_t fstride, const size_t m) + { + cpx_type scratch[7]; + int negative_if_inverse = _inverse * -2 + 1; + for(size_t k = 0; k < m; ++k) { + //scratch[0] = Fout[k + m] * _traits.twiddle(k * fstride); + C_MUL(scratch[0], Fout[k + m], _traits.twiddle(k * fstride)); + C_MUL(scratch[1], Fout[k + 2 * m], _traits.twiddle(k * fstride * 2)); + C_MUL(scratch[2], Fout[k + 3 * m], _traits.twiddle(k * fstride * 3)); + scratch[5] = Fout[k] - scratch[1]; + + Fout[k] += scratch[1]; + scratch[3] = scratch[0] + scratch[2]; + scratch[4] = scratch[0] - scratch[2]; + scratch[4] = cpx_type(scratch[4].imag() * negative_if_inverse, -scratch[4].real() * negative_if_inverse); + + Fout[k + 2 * m] = Fout[k] - scratch[3]; + Fout[k] += scratch[3]; + Fout[k + m] = scratch[5] + scratch[4]; + Fout[k + 3 * m] = scratch[5] - scratch[4]; + } + } + + void kf_bfly3(cpx_type* Fout, const size_t fstride, const size_t m) + { + size_t k = m; + const size_t m2 = 2 * m; + cpx_type* tw1; + cpx_type* tw2; + cpx_type scratch[5]; + cpx_type epi3; + epi3 = _twiddles[fstride * m]; + tw1 = tw2 = &_twiddles[0]; + + do { + C_FIXDIV(*Fout, 3); + C_FIXDIV(Fout[m], 3); + C_FIXDIV(Fout[m2], 3); + + C_MUL(scratch[1], Fout[m], *tw1); + C_MUL(scratch[2], Fout[m2], *tw2); + + C_ADD(scratch[3], scratch[1], scratch[2]); + C_SUB(scratch[0], scratch[1], scratch[2]); + tw1 += fstride; + tw2 += fstride * 2; + + Fout[m] = cpx_type(Fout->real() - HALF_OF(scratch[3].real()), Fout->imag() - HALF_OF(scratch[3].imag())); + + C_MULBYSCALAR(scratch[0], epi3.imag()); + + C_ADDTO(*Fout, scratch[3]); + + Fout[m2] = cpx_type(Fout[m].real() + scratch[0].imag(), Fout[m].imag() - scratch[0].real()); + + C_ADDTO(Fout[m], cpx_type(-scratch[0].imag(), scratch[0].real())); + ++Fout; + } while(--k); + } + + void kf_bfly5(cpx_type* Fout, const size_t fstride, const size_t m) + { + cpx_type* Fout0; + cpx_type* Fout1; + cpx_type* Fout2; + cpx_type* Fout3; + cpx_type* Fout4; + size_t u; + cpx_type scratch[13]; + cpx_type* twiddles = &_twiddles[0]; + cpx_type* tw; + cpx_type ya, yb; + ya = twiddles[fstride * m]; + yb = twiddles[fstride * 2 * m]; + + Fout0 = Fout; + Fout1 = Fout0 + m; + Fout2 = Fout0 + 2 * m; + Fout3 = Fout0 + 3 * m; + Fout4 = Fout0 + 4 * m; + + tw = twiddles; + for(u = 0; u < m; ++u) { + C_FIXDIV(*Fout0, 5); + C_FIXDIV(*Fout1, 5); + C_FIXDIV(*Fout2, 5); + C_FIXDIV(*Fout3, 5); + C_FIXDIV(*Fout4, 5); + scratch[0] = *Fout0; + + C_MUL(scratch[1], *Fout1, tw[u * fstride]); + C_MUL(scratch[2], *Fout2, tw[2 * u * fstride]); + C_MUL(scratch[3], *Fout3, tw[3 * u * fstride]); + C_MUL(scratch[4], *Fout4, tw[4 * u * fstride]); + + C_ADD(scratch[7], scratch[1], scratch[4]); + C_SUB(scratch[10], scratch[1], scratch[4]); + C_ADD(scratch[8], scratch[2], scratch[3]); + C_SUB(scratch[9], scratch[2], scratch[3]); + + C_ADDTO(*Fout0, scratch[7]); + C_ADDTO(*Fout0, scratch[8]); + + scratch[5] = scratch[0] + cpx_type(S_MUL(scratch[7].real(), ya.real()) + S_MUL(scratch[8].real(), yb.real()), S_MUL(scratch[7].imag(), ya.real()) + + S_MUL(scratch[8].imag(), yb.real())); + + scratch[6] = cpx_type(S_MUL(scratch[10].imag(), ya.imag()) + S_MUL(scratch[9].imag(), yb.imag()), -S_MUL(scratch[10].real(), ya.imag()) - S_MUL( + scratch[9].real(), yb.imag())); + + C_SUB(*Fout1, scratch[5], scratch[6]); + C_ADD(*Fout4, scratch[5], scratch[6]); + + scratch[11] = scratch[0] + cpx_type(S_MUL(scratch[7].real(), yb.real()) + S_MUL(scratch[8].real(), ya.real()), S_MUL(scratch[7].imag(), yb.real()) + + S_MUL(scratch[8].imag(), ya.real())); + + scratch[12] = cpx_type(-S_MUL(scratch[10].imag(), yb.imag()) + S_MUL(scratch[9].imag(), ya.imag()), S_MUL(scratch[10].real(), yb.imag()) - S_MUL( + scratch[9].real(), ya.imag())); + + C_ADD(*Fout2, scratch[11], scratch[12]); + C_SUB(*Fout3, scratch[11], scratch[12]); + + ++Fout0; + ++Fout1; + ++Fout2; + ++Fout3; + ++Fout4; + } + } + + /* perform the butterfly for one stage of a mixed radix FFT */ + void kf_bfly_generic(cpx_type* Fout, const size_t fstride, int m, int p) + { + int u; + int k; + int q1; + int q; + cpx_type* twiddles = &_twiddles[0]; + cpx_type t; + int Norig = _nfft; + cpx_type* scratchbuf = new cpx_type[p]; + + for(u = 0; u < m; ++u) { + k = u; + for(q1 = 0; q1 < p; ++q1) { + scratchbuf[q1] = Fout[k]; + C_FIXDIV(scratchbuf[q1], p); + k += m; + } + + k = u; + for(q1 = 0; q1 < p; ++q1) { + int twidx = 0; + Fout[k] = scratchbuf[0]; + for(q = 1; q < p; ++q) { + twidx += fstride * k; + if(twidx >= Norig) + twidx -= Norig; + C_MUL(t, scratchbuf[q], twiddles[twidx]); + C_ADDTO(Fout[k], t); + } + k += m; + } + } + + delete[] scratchbuf; + } + + int _nfft; + bool _inverse; + std::vector<cpx_type> _twiddles; + std::vector<int> _stageRadix; + std::vector<int> _stageRemainder; + traits_type _traits; +}; +#endif diff --git a/include/dsp/samplefifo.h b/include/dsp/samplefifo.h new file mode 100644 index 0000000..2ab3110 --- /dev/null +++ b/include/dsp/samplefifo.h @@ -0,0 +1,68 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_SAMPLEFIFO_H +#define INCLUDE_SAMPLEFIFO_H + +#include <QObject> +#include <QMutex> +#include <QTime> +#include "dsp/dsptypes.h" + +class SampleFifo : public QObject { + Q_OBJECT + +private: + QMutex m_mutex; + QTime m_msgRateTimer; + int m_suppressed; + + SampleVector m_data; + + uint m_size; + uint m_fill; + uint m_head; + uint m_tail; + + void create(uint s); + +public: + SampleFifo(QObject* parent = NULL); + SampleFifo(int size, QObject* parent = NULL); + ~SampleFifo(); + + SampleFifo(const SampleFifo&); + SampleFifo& operator=(const SampleFifo&); + + bool setSize(int size); + inline uint fill() const { return m_fill; } + + uint write(const quint8* data, uint count); + uint write(SampleVector::const_iterator begin, SampleVector::const_iterator end); + + uint read(SampleVector::iterator begin, SampleVector::iterator end); + + uint readBegin(uint count, + SampleVector::iterator* part1Begin, SampleVector::iterator* part1End, + SampleVector::iterator* part2Begin, SampleVector::iterator* part2End); + uint readCommit(uint count); + +signals: + void dataReady(); +}; + +#endif // INCLUDE_SAMPLEFIFO_H diff --git a/include/dsp/samplesink.h b/include/dsp/samplesink.h new file mode 100644 index 0000000..8a02bc8 --- /dev/null +++ b/include/dsp/samplesink.h @@ -0,0 +1,42 @@ +#ifndef INCLUDE_SAMPLESINK_H +#define INCLUDE_SAMPLESINK_H + +#include "dsptypes.h" + +class Message; + +class SampleSink { +public: + SampleSink(); + virtual ~SampleSink(); + + virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst) = 0; + virtual void start() = 0; + virtual void stop() = 0; + virtual bool handleMessage(Message* cmd) = 0; +}; + +#endif // INCLUDE_SAMPLESINK_H + +#if 0 +#ifndef INCLUDE_SAMPLESINK_H +#define INCLUDE_SAMPLESINK_H + +#include "dsptypes.h" + +class SampleSink { +public: + SampleSink(); + + virtual size_t workUnitSize() = 0; + + void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end); + virtual size_t work(SampleVector::const_iterator begin, SampleVector::const_iterator end) = 0; + +private: + SampleVector m_sinkBuffer; + size_t m_sinkBufferFill; +}; + +#endif // INCLUDE_SAMPLESINK_H +#endif diff --git a/include/dsp/samplesource/samplesource.h b/include/dsp/samplesource/samplesource.h new file mode 100644 index 0000000..0328a90 --- /dev/null +++ b/include/dsp/samplesource/samplesource.h @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_SAMPLESOURCE_H +#define INCLUDE_SAMPLESOURCE_H + +#include <QtGlobal> +#include "dsp/samplefifo.h" +#include "util/message.h" + +class PluginGUI; +class MessageQueue; + +class SampleSource { +public: + struct GeneralSettings { + quint64 m_centerFrequency; + + GeneralSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + }; + + SampleSource(MessageQueue* guiMessageQueue); + virtual ~SampleSource(); + + virtual bool startInput(int device) = 0; + virtual void stopInput() = 0; + + virtual const QString& getDeviceDescription() const = 0; + virtual int getSampleRate() const = 0; + virtual quint64 getCenterFrequency() const = 0; + + virtual bool handleMessage(Message* message) = 0; + + SampleFifo* getSampleFifo() { return &m_sampleFifo; } + +protected: + SampleFifo m_sampleFifo; + MessageQueue* m_guiMessageQueue; + + GeneralSettings m_generalSettings; +}; + +#endif // INCLUDE_SAMPLESOURCE_H diff --git a/include/dsp/threadedsamplesink.h b/include/dsp/threadedsamplesink.h new file mode 100644 index 0000000..f7e704e --- /dev/null +++ b/include/dsp/threadedsamplesink.h @@ -0,0 +1,40 @@ +#ifndef INCLUDE_THREADEDSAMPLESINK_H +#define INCLUDE_THREADEDSAMPLESINK_H + +#include <QMutex> +#include "samplesink.h" +#include "dsp/samplefifo.h" +#include "util/messagequeue.h" + +class QThread; +class SampleSink; + +class ThreadedSampleSink : public QObject, public SampleSink { + Q_OBJECT + +public: + ThreadedSampleSink(SampleSink* sampleSink); + virtual ~ThreadedSampleSink(); + + MessageQueue* getMessageQueue() { return &m_messageQueue; } + + void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst); + void start(); + void stop(); + bool handleMessage(Message* cmd); + +protected: + QMutex m_mutex; + QThread* m_thread; + MessageQueue m_messageQueue; + SampleFifo m_sampleFifo; + SampleSink* m_sampleSink; + +protected slots: + void handleData(); + void handleMessages(); + void threadStarted(); + void threadFinished(); +}; + +#endif // INCLUDE_THREADEDSAMPLESINK_H diff --git a/include/plugin/pluginapi.h b/include/plugin/pluginapi.h new file mode 100644 index 0000000..515eb0d --- /dev/null +++ b/include/plugin/pluginapi.h @@ -0,0 +1,56 @@ +#ifndef INCLUDE_PLUGINAPI_H +#define INCLUDE_PLUGINAPI_H + +#include <QObject> + +class QDockWidget; +class QAction; + +class PluginManager; +class PluginInterface; +class SampleSource; +class SampleSink; +class DSPEngine; +class AudioFifo; +class MessageQueue; +class MainWindow; +class ChannelMarker; +class PluginGUI; + +class PluginAPI : public QObject { + Q_OBJECT + +public: + // MainWindow access + QDockWidget* createMainWindowDock(Qt::DockWidgetArea dockWidgetArea, const QString& title); + MessageQueue* getMainWindowMessageQueue(); + + // Demodulator stuff + void registerDemodulator(const QString& demodName, PluginInterface* plugin, QAction* action); + void registerDemodulatorInstance(const QString& demodName, PluginGUI* pluginGUI); + + void addChannelMarker(ChannelMarker* channelMarker); + void removeChannelMarker(ChannelMarker* channelMarker); + + // DSPEngine access + void setSampleSource(SampleSource* sampleSource); + void addSampleSink(SampleSink* sampleSink); + void removeSampleSink(SampleSink* sampleSink); + MessageQueue* getDSPEngineMessageQueue(); + void addAudioSource(AudioFifo* audioFifo); + void removeAudioSource(AudioFifo* audioFifo); + + // Sample Source stuff + void registerSampleSource(const QString& sourceName, PluginInterface* plugin); + +protected: + PluginManager* m_pluginManager; + MainWindow* m_mainWindow; + DSPEngine* m_dspEngine; + + PluginAPI(PluginManager* pluginManager, MainWindow* mainWindow, DSPEngine* dspEngine); + + friend class PluginManager; +}; + +#endif // INCLUDE_PLUGINAPI_H diff --git a/include/plugin/plugingui.h b/include/plugin/plugingui.h new file mode 100644 index 0000000..2e48079 --- /dev/null +++ b/include/plugin/plugingui.h @@ -0,0 +1,29 @@ +#ifndef INCLUDE_PLUGINGUI_H +#define INCLUDE_PLUGINGUI_H + +#include <QWidget> + +class Message; + +class PluginGUI : public QWidget { + Q_OBJECT + +public: + PluginGUI(QWidget* parent = NULL); + virtual void destroy() = 0; + + virtual void setWidgetName(const QString& name); + + virtual void resetToDefaults() = 0; + + virtual QByteArray serializeGeneral() const; + virtual bool deserializeGeneral(const QByteArray& data); + virtual quint64 getCenterFrequency() const; + + virtual QByteArray serialize() const = 0; + virtual bool deserialize(const QByteArray& data) = 0; + + virtual bool handleMessage(Message* message) = 0; +}; + +#endif // INCLUDE_PLUGINGUI_H diff --git a/include/plugin/plugininterface.h b/include/plugin/plugininterface.h new file mode 100644 index 0000000..15e3c5d --- /dev/null +++ b/include/plugin/plugininterface.h @@ -0,0 +1,48 @@ +#ifndef INCLUDE_PLUGININTERFACE_H +#define INCLUDE_PLUGININTERFACE_H + +#include <QtPlugin> +#include <QString> + +struct PluginDescriptor { + // general plugin description + const QString& displayedName; + const QString& version; + const QString& copyright; + const QString& website; + bool licenseIsGPL; + const QString& sourceCodeURL; +}; + +class PluginAPI; +class PluginGUI; + +class PluginInterface { +public: + struct SampleSourceDevice { + QString displayedName; + QString name; + QByteArray address; + + SampleSourceDevice(const QString& _displayedName, const QString& _name, const QByteArray& _address) : + displayedName(_displayedName), + name(_name), + address(_address) + { } + }; + typedef QList<SampleSourceDevice> SampleSourceDevices; + + virtual ~PluginInterface() { }; + + virtual const PluginDescriptor& getPluginDescriptor() const = 0; + virtual void initPlugin(PluginAPI* pluginAPI) = 0; + + virtual PluginGUI* createDemod(const QString& demodName) { return NULL; } + + virtual SampleSourceDevices enumSampleSources() { return SampleSourceDevices(); } + virtual PluginGUI* createSampleSource(const QString& sourceName, const QByteArray& address) { return NULL; } +}; + +Q_DECLARE_INTERFACE(PluginInterface, "de.maintech.SDRangelove.PluginInterface/0.1"); + +#endif // INCLUDE_PLUGININTERFACE_H diff --git a/include/util/message.h b/include/util/message.h new file mode 100644 index 0000000..8718496 --- /dev/null +++ b/include/util/message.h @@ -0,0 +1,50 @@ +#ifndef INCLUDE_MESSAGE_H +#define INCLUDE_MESSAGE_H + +#include <QAtomicInt> +#include <QStringList> + +class MessageQueue; +class QWaitCondition; +class QMutex; + +class MessageRegistrator { +public: + MessageRegistrator(const char* name); + int operator()() const { return m_registeredID; } + + const char* name() const; + +private: + int m_registeredID; +}; + +class Message { +public: + virtual ~Message(); + + void submit(MessageQueue* queue, void* destination = NULL); + int execute(MessageQueue* queue, void* destination = NULL); + + void completed(int result = 0); + + int id() const { return m_id; } + const char* name() const; + void* destination() const { return m_destination; } + +protected: + Message(int id); + + // adressing + int m_id; + void* m_destination; + + // stuff for synchronous messages + bool m_synchronous; + QWaitCondition* m_waitCondition; + QMutex* m_mutex; + QAtomicInt m_complete; + int m_result; +}; + +#endif // INCLUDE_MESSAGE_H diff --git a/include/util/messagequeue.h b/include/util/messagequeue.h new file mode 100644 index 0000000..bf99ea2 --- /dev/null +++ b/include/util/messagequeue.h @@ -0,0 +1,30 @@ +#ifndef INCLUDE_MESSAGEQUEUE_H +#define INCLUDE_MESSAGEQUEUE_H + +#include <QObject> +#include <QQueue> +#include "spinlock.h" + +class Message; + +class MessageQueue : public QObject { + Q_OBJECT + +public: + MessageQueue(QObject* parent = NULL); + ~MessageQueue(); + + void submit(Message* message); + Message* accept(); + + int countPending(); + +signals: + void messageEnqueued(); + +private: + Spinlock m_lock; + QQueue<Message*> m_queue; +}; + +#endif // INCLUDE_MESSAGEQUEUE_H diff --git a/include/util/miniz.h b/include/util/miniz.h new file mode 100644 index 0000000..0882c06 --- /dev/null +++ b/include/util/miniz.h @@ -0,0 +1,7 @@ +#ifndef INCLUDE_MINIZ_H +#define INCLUDE_MINIZ_H + +#define MINIZ_HEADER_FILE_ONLY +#include "../../sdrapp/util/miniz.cpp" + +#endif // INCLUDE_MINIZ_H diff --git a/include/util/simpleserializer.h b/include/util/simpleserializer.h new file mode 100644 index 0000000..3893c32 --- /dev/null +++ b/include/util/simpleserializer.h @@ -0,0 +1,111 @@ +#ifndef INCLUDE_SIMPLESERIALIZER_H +#define INCLUDE_SIMPLESERIALIZER_H + +#include <QString> +#include <QMap> +#include "dsp/dsptypes.h" + +class SimpleSerializer { +public: + SimpleSerializer(quint32 version); + + void writeS32(quint32 id, qint32 value); + void writeU32(quint32 id, quint32 value); + void writeS64(quint32 id, qint64 value); + void writeU64(quint32 id, quint64 value); + void writeFloat(quint32 id, float value); + void writeDouble(quint32 id, double value); + void writeReal(quint32 id, Real value) + { + if(sizeof(Real) == 4) + writeFloat(id, value); + else writeDouble(id, value); + } + void writeBool(quint32 id, bool value); + void writeString(quint32 id, const QString& value); + void writeBlob(quint32 id, const QByteArray& value); + + const QByteArray& final(); + +protected: + enum Type { + TSigned32 = 0, + TUnsigned32 = 1, + TSigned64 = 2, + TUnsigned64 = 3, + TFloat = 4, + TDouble = 5, + TBool = 6, + TString = 7, + TBlob = 8, + TVersion = 9 + }; + + QByteArray m_data; + bool m_finalized; + + bool writeTag(Type type, quint32 id, quint32 length); +}; + +class SimpleDeserializer { +public: + SimpleDeserializer(const QByteArray& data); + + bool readS32(quint32 id, qint32* result, qint32 def = 0) const; + bool readU32(quint32 id, quint32* result, quint32 def = 0) const; + bool readS64(quint32 id, qint64* result, qint64 def = 0) const; + bool readU64(quint32 id, quint64* result, quint64 def = 0) const; + bool readFloat(quint32 id, float* result, float def = 0) const; + bool readDouble(quint32 id, double* result, double def = 0) const; + bool readReal(quint32 id, Real* result, Real def = 0) const; + bool readBool(quint32 id, bool* result, bool def = false) const; + bool readString(quint32 id, QString* result, const QString& def = QString::null) const; + bool readBlob(quint32 id, QByteArray* result, const QByteArray& def = QByteArray()) const; + + bool isValid() const { return m_valid; } + quint32 getVersion() const { return m_version; } + void dump() const; + +private: + enum Type { + TSigned32 = 0, + TUnsigned32 = 1, + TSigned64 = 2, + TUnsigned64 = 3, + TFloat = 4, + TDouble = 5, + TBool = 6, + TString = 7, + TBlob = 8, + TVersion = 9 + }; + + struct Element { + Type type; + quint32 ofs; + quint32 length; + + Element(Type _type, quint32 _ofs, quint32 _length) : + type(_type), + ofs(_ofs), + length(_length) + { } + }; + typedef QMap<quint32, Element> Elements; + + QByteArray m_data; + bool m_valid; + Elements m_elements; + quint32 m_version; + + bool parseAll(); + bool readTag(uint* readOfs, uint readEnd, Type* type, quint32* id, quint32* length) const; + quint8 readByte(uint* readOfs) const + { + quint8 res = m_data[*readOfs]; + (*readOfs)++; + return res; + } +}; + +#endif // INCLUDE_SIMPLESERIALIZER_H diff --git a/include/util/spinlock.h b/include/util/spinlock.h new file mode 100644 index 0000000..78af0b6 --- /dev/null +++ b/include/util/spinlock.h @@ -0,0 +1,39 @@ +#ifndef INCLUDE_SPINLOCK_H +#define INCLUDE_SPINLOCK_H + +#include <QAtomicInt> + +class Spinlock { +public: + void lock() + { + while(!m_atomic.testAndSetAcquire(0, 1)) ; + } + + void unlock() + { + while(!m_atomic.testAndSetRelease(1, 0)) ; + } + +protected: + QAtomicInt m_atomic; +}; + +class SpinlockHolder { +public: + SpinlockHolder(Spinlock* spinlock) : + m_spinlock(spinlock) + { + m_spinlock->lock(); + } + + ~SpinlockHolder() + { + m_spinlock->unlock(); + } + +protected: + Spinlock* m_spinlock; +}; + +#endif // INCLUDE_SPINLOCK_H |