Removal of UpChannelizer and ThreadedBasebandSampleSource

This commit is contained in:
f4exb 2019-11-15 01:26:38 +01:00
parent 3b74153ec6
commit 5a843a573c
9 changed files with 1 additions and 722 deletions

View File

@ -30,8 +30,6 @@
class PluginAPI;
class DeviceUISet;
class BasebandSampleSource;
class ThreadedBasebandSampleSource;
class UpChannelizer;
namespace Ui {
class WFMModGUI;
@ -66,8 +64,6 @@ private:
WFMModSettings m_settings;
bool m_doApplySettings;
// ThreadedBasebandSampleSource* m_threadedChannelizer;
// UpChannelizer* m_channelizer;
WFMMod* m_wfmMod;
MovingAverageUtil<double, double, 20> m_channelPowerDbAvg;

View File

@ -63,7 +63,6 @@ set(sdrbase_SOURCES
dsp/afsquelch.cpp
dsp/agc.cpp
dsp/downchannelizer.cpp
#dsp/upchannelizer.cpp
dsp/upsamplechannelizer.cpp
dsp/channelmarker.cpp
dsp/ctcssdetector.cpp
@ -108,7 +107,6 @@ set(sdrbase_SOURCES
dsp/nullsink.cpp
dsp/recursivefilters.cpp
dsp/threadedbasebandsamplesink.cpp
#dsp/threadedbasebandsamplesource.cpp
dsp/wfir.cpp
dsp/devicesamplesource.cpp
dsp/devicesamplesink.cpp
@ -180,7 +178,6 @@ set(sdrbase_HEADERS
dsp/afsquelch.h
dsp/autocorrector.h
dsp/downchannelizer.h
#dsp/upchannelizer.h
dsp/upsamplechannelizer.h
dsp/channelmarker.h
dsp/channelsamplesource.h
@ -248,7 +245,6 @@ set(sdrbase_HEADERS
dsp/basebandsamplesource.h
dsp/nullsink.h
dsp/threadedbasebandsamplesink.h
#dsp/threadedbasebandsamplesource.h
dsp/wfir.h
dsp/devicesamplesource.h
dsp/devicesamplesink.h

View File

@ -29,7 +29,6 @@ class BasebandSampleSink;
class ThreadedBasebandSampleSink;
class DeviceSampleSink;
class BasebandSampleSource;
class ThreadedBasebandSampleSource;
class AudioFifo;
class SDRBASE_API DSPAcquisitionInit : public Message {

View File

@ -551,7 +551,7 @@ DSPDeviceMIMOEngine::State DSPDeviceMIMOEngine::gotoIdle(int subsystemIndex)
{
for (ThreadedBasebandSampleSinks::const_iterator it = vtSinkIt->begin(); it != vtSinkIt->end(); ++it)
{
qDebug() << "DSPDeviceMIMOEngine::gotoIdle: stopping ThreadedBasebandSampleSource(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")";
qDebug() << "DSPDeviceMIMOEngine::gotoIdle: stopping ThreadedBasebandSampleSink(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")";
(*it)->stop();
}
}

View File

@ -30,7 +30,6 @@
#include "export.h"
class DeviceSampleMIMO;
class ThreadedBasebandSampleSource;
class ThreadedBasebandSampleSink;
class BasebandSampleSink;
class MIMOChannel;

View File

@ -1,81 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// 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 //
// (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 V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QThread>
#include "dsp/threadedbasebandsamplesource.h"
ThreadedBasebandSampleSource::ThreadedBasebandSampleSource(BasebandSampleSource* sampleSource, QObject *parent) :
m_basebandSampleSource(sampleSource)
{
QString name = "ThreadedBasebandSampleSource(" + m_basebandSampleSource->objectName() + ")";
setObjectName(name);
qDebug() << "ThreadedBasebandSampleSource::ThreadedBasebandSampleSource: " << name;
m_thread = new QThread(parent);
m_basebandSampleSource->moveToThread(m_thread);
qDebug() << "ThreadedBasebandSampleSource::ThreadedBasebandSampleSource: thread: " << thread() << " m_thread: " << m_thread;
}
ThreadedBasebandSampleSource::~ThreadedBasebandSampleSource()
{
if (m_thread->isRunning()) {
stop();
}
delete m_thread;
}
void ThreadedBasebandSampleSource::start()
{
qDebug() << "ThreadedBasebandSampleSource::start";
m_thread->start();
m_basebandSampleSource->start();
}
void ThreadedBasebandSampleSource::stop()
{
qDebug() << "ThreadedBasebandSampleSource::stop";
m_basebandSampleSource->stop();
m_thread->exit();
m_thread->wait();
}
void ThreadedBasebandSampleSource::pull(Sample& sample)
{
m_basebandSampleSource->pull(sample);
}
void ThreadedBasebandSampleSource::feed(SampleSourceFifoDB* sampleFifo,
int nbSamples)
{
m_basebandSampleSource->feed(sampleFifo, nbSamples);
}
bool ThreadedBasebandSampleSource::handleSourceMessage(const Message& cmd)
{
return m_basebandSampleSource->handleMessage(cmd);
}
QString ThreadedBasebandSampleSource::getSampleSourceObjectName() const
{
return m_basebandSampleSource->objectName();
}

View File

@ -1,64 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// 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 //
// (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 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 SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_
#define SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_
#include <QMutex>
#include "dsp/basebandsamplesource.h"
#include "util/messagequeue.h"
#include "export.h"
class BasebandSampleSource;
class QThread;
/**
* This class is a wrapper for BasebandSampleSource that runs the BasebandSampleSource object in its own thread
*/
class SDRBASE_API ThreadedBasebandSampleSource : public QObject {
Q_OBJECT
public:
ThreadedBasebandSampleSource(BasebandSampleSource* sampleSource, QObject *parent = 0);
~ThreadedBasebandSampleSource();
const BasebandSampleSource *getSource() const { return m_basebandSampleSource; }
void start(); //!< this thread start()
void stop(); //!< this thread exit() and wait()
bool handleSourceMessage(const Message& cmd); //!< Send message to source synchronously
void pull(Sample& sample); //!< Pull one sample from source
void pullAudio(int nbSamples) { if (m_basebandSampleSource) m_basebandSampleSource->pullAudio(nbSamples); }
/** direct feeding of sample source FIFO */
void feed(SampleSourceFifoDB* sampleFifo,
int nbSamples);
SampleSourceFifoDB& getSampleSourceFifo() { return m_basebandSampleSource->getSampleSourceFifo(); }
void setDeviceSampleSourceFifo(SampleSourceFifoDB *deviceSampleFifo) { m_basebandSampleSource->setDeviceSampleSourceFifo(deviceSampleFifo); }
QString getSampleSourceObjectName() const;
protected:
QThread *m_thread; //!< The thead object
BasebandSampleSource* m_basebandSampleSource;
};
#endif /* SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_ */

View File

@ -1,418 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// 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 //
// (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 V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsp/upchannelizer.h"
#include "dsp/inthalfbandfilter.h"
#include "dsp/dspcommands.h"
#include "dsp/hbfilterchainconverter.h"
#include <QString>
#include <QDebug>
MESSAGE_CLASS_DEFINITION(UpChannelizer::MsgChannelizerNotification, Message)
MESSAGE_CLASS_DEFINITION(UpChannelizer::MsgSetChannelizer, Message)
UpChannelizer::UpChannelizer(BasebandSampleSource* sampleSource) :
m_filterChainSetMode(false),
m_sampleSource(sampleSource),
m_outputSampleRate(0),
m_requestedInputSampleRate(0),
m_requestedCenterFrequency(0),
m_currentInputSampleRate(0),
m_currentCenterFrequency(0)
{
QString name = "UpChannelizer(" + m_sampleSource->objectName() + ")";
setObjectName(name);
}
UpChannelizer::~UpChannelizer()
{
freeFilterChain();
}
void UpChannelizer::configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency)
{
Message* cmd = new DSPConfigureChannelizer(sampleRate, centerFrequency);
messageQueue->push(cmd);
}
void UpChannelizer::set(MessageQueue* messageQueue, unsigned int log2Interp, unsigned int filterChainHash)
{
Message* cmd = new MsgSetChannelizer(log2Interp, filterChainHash);
messageQueue->push(cmd);
}
void UpChannelizer::pull(Sample& sample)
{
if(m_sampleSource == 0) {
m_sampleBuffer.clear();
return;
}
if (m_filterStages.size() == 0) // optimization when no downsampling is done anyway
{
m_sampleSource->pull(sample);
}
else
{
m_mutex.lock();
FilterStages::iterator stage = m_filterStages.begin();
std::vector<Sample>::iterator stageSample = m_stageSamples.begin();
for (; stage != m_filterStages.end(); ++stage, ++stageSample)
{
if(stage == m_filterStages.end() - 1)
{
if ((*stage)->work(&m_sampleIn, &(*stageSample)))
{
m_sampleSource->pull(m_sampleIn); // get new input sample
}
}
else
{
if (!(*stage)->work(&(*(stageSample+1)), &(*stageSample)))
{
break;
}
}
}
sample = *m_stageSamples.begin();
// for (; stage != m_filterStages.end(); ++stage)
// {
// // let's make it work for one stage only (96 kS/s < SR < 192 kS/s)
// if(stage == m_filterStages.end() - 1)
// {
// if ((*stage)->work(&m_sampleIn, &sample))
// {
// m_sampleSource->pull(m_sampleIn); // get new input sample
// }
// }
// }
m_mutex.unlock();
}
}
void UpChannelizer::start()
{
if (m_sampleSource != 0)
{
qDebug() << "UpChannelizer::start: thread: " << thread()
<< " m_outputSampleRate: " << m_outputSampleRate
<< " m_requestedInputSampleRate: " << m_requestedInputSampleRate
<< " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
m_sampleSource->start();
}
}
void UpChannelizer::stop()
{
if(m_sampleSource != 0)
m_sampleSource->stop();
}
bool UpChannelizer::handleMessage(const Message& cmd)
{
qDebug() << "UpChannelizer::handleMessage: " << cmd.getIdentifier();
// TODO: apply changes only if input sample rate or requested output sample rate change. Change of center frequency has no impact.
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_outputSampleRate = notif.getSampleRate();
qDebug() << "UpChannelizer::handleMessage: DSPSignalNotification: m_outputSampleRate: " << m_outputSampleRate;
if (!m_filterChainSetMode) {
applyConfiguration();
}
if (m_sampleSource != 0)
{
DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy
m_sampleSource->getInputMessageQueue()->push(rep);
}
emit outputSampleRateChanged();
return true;
}
else if (DSPConfigureChannelizer::match(cmd))
{
DSPConfigureChannelizer& chan = (DSPConfigureChannelizer&) cmd;
m_requestedInputSampleRate = chan.getSampleRate();
m_requestedCenterFrequency = chan.getCenterFrequency();
qDebug() << "UpChannelizer::handleMessage: DSPConfigureChannelizer:"
<< " m_requestedInputSampleRate: " << m_requestedInputSampleRate
<< " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
applyConfiguration();
return true;
}
else if (MsgSetChannelizer::match(cmd))
{
MsgSetChannelizer& chan = (MsgSetChannelizer&) cmd;
qDebug() << "UpChannelizer::handleMessage: MsgSetChannelizer";
applySetting(chan.getLog2Interp(), chan.getFilterChainHash());
return true;
}
else
{
return false;
// if (m_sampleSource != 0)
// {
// return m_sampleSource->handleMessage(cmd);
// }
// else
// {
// return false;
// }
}
}
void UpChannelizer::applyConfiguration()
{
m_filterChainSetMode = false;
if (m_outputSampleRate == 0)
{
qDebug() << "UpChannelizer::applyConfiguration: aborting (out=0):"
<< " out =" << m_outputSampleRate
<< ", req =" << m_requestedInputSampleRate
<< ", in =" << m_currentInputSampleRate
<< ", fc =" << m_currentCenterFrequency;
return;
}
m_mutex.lock();
freeFilterChain();
m_currentCenterFrequency = createFilterChain(
m_outputSampleRate / -2, m_outputSampleRate / 2,
m_requestedCenterFrequency - m_requestedInputSampleRate / 2, m_requestedCenterFrequency + m_requestedInputSampleRate / 2);
m_mutex.unlock();
m_currentInputSampleRate = m_outputSampleRate / (1 << m_filterStages.size());
qDebug() << "UpChannelizer::applyConfiguration:"
<< " out=" << m_outputSampleRate
<< ", req=" << m_requestedInputSampleRate
<< ", in=" << m_currentInputSampleRate
<< ", fc=" << m_currentCenterFrequency;
if (m_sampleSource != 0)
{
MsgChannelizerNotification *notif = MsgChannelizerNotification::create(m_outputSampleRate, m_currentInputSampleRate, m_currentCenterFrequency);
m_sampleSource->getInputMessageQueue()->push(notif);
}
}
void UpChannelizer::applySetting(unsigned int log2Interp, unsigned int filterChainHash)
{
m_filterChainSetMode = true;
std::vector<unsigned int> stageIndexes;
m_currentCenterFrequency = m_outputSampleRate * HBFilterChainConverter::convertToIndexes(log2Interp, filterChainHash, stageIndexes);
m_requestedCenterFrequency = m_currentCenterFrequency;
m_mutex.lock();
freeFilterChain();
m_currentCenterFrequency = m_outputSampleRate * setFilterChain(stageIndexes);
m_mutex.unlock();
m_currentInputSampleRate = m_outputSampleRate / (1 << m_filterStages.size());
m_requestedInputSampleRate = m_currentInputSampleRate;
qDebug() << "UpChannelizer::applySetting in=" << m_outputSampleRate
<< ", out=" << m_currentInputSampleRate
<< ", fc=" << m_currentCenterFrequency;
if (m_sampleSource != 0)
{
MsgChannelizerNotification *notif = MsgChannelizerNotification::create(m_outputSampleRate, m_currentInputSampleRate, m_currentCenterFrequency);
m_sampleSource->getInputMessageQueue()->push(notif);
}
}
#ifdef USE_SSE4_1
UpChannelizer::FilterStage::FilterStage(Mode mode) :
m_filter(new IntHalfbandFilterEO1<UPCHANNELIZER_HB_FILTER_ORDER>),
m_workFunction(0)
{
switch(mode) {
case ModeCenter:
m_workFunction = &IntHalfbandFilterEO1<UPCHANNELIZER_HB_FILTER_ORDER>::workInterpolateCenter;
break;
case ModeLowerHalf:
m_workFunction = &IntHalfbandFilterEO1<UPCHANNELIZER_HB_FILTER_ORDER>::workInterpolateLowerHalf;
break;
case ModeUpperHalf:
m_workFunction = &IntHalfbandFilterEO1<UPCHANNELIZER_HB_FILTER_ORDER>::workInterpolateUpperHalf;
break;
}
}
#else
UpChannelizer::FilterStage::FilterStage(Mode mode) :
m_filter(new IntHalfbandFilterDB<qint32, UPCHANNELIZER_HB_FILTER_ORDER>),
m_workFunction(0)
{
switch(mode) {
case ModeCenter:
m_workFunction = &IntHalfbandFilterDB<qint32, UPCHANNELIZER_HB_FILTER_ORDER>::workInterpolateCenter;
break;
case ModeLowerHalf:
m_workFunction = &IntHalfbandFilterDB<qint32, UPCHANNELIZER_HB_FILTER_ORDER>::workInterpolateLowerHalf;
break;
case ModeUpperHalf:
m_workFunction = &IntHalfbandFilterDB<qint32, UPCHANNELIZER_HB_FILTER_ORDER>::workInterpolateUpperHalf;
break;
}
}
#endif
UpChannelizer::FilterStage::~FilterStage()
{
delete m_filter;
}
bool UpChannelizer::signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const
{
//qDebug(" testing signal [%f, %f], channel [%f, %f]", sigStart, sigEnd, chanStart, chanEnd);
if(sigEnd <= sigStart)
return false;
if(chanEnd <= chanStart)
return false;
return (sigStart <= chanStart) && (sigEnd >= chanEnd);
}
Real UpChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd)
{
Real sigBw = sigEnd - sigStart;
Real rot = sigBw / 4;
Sample s;
qDebug() << "UpChannelizer::createFilterChain: start:"
<< " sig: [" << sigStart << ":" << sigEnd << "]"
<< " BW: " << sigBw
<< " chan: [" << chanStart << ":" << chanEnd << "]"
<< " rot: " << rot;
// check if it fits into the left half
if(signalContainsChannel(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd))
{
qDebug() << "UpChannelizer::createFilterChain: take left half (rotate by +1/4 and decimate by 2):"
<< " [" << m_filterStages.size() << "]"
<< " sig: [" << sigStart << ":" << sigStart + sigBw / 2.0 << "]";
m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf));
m_stageSamples.push_back(s);
return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd);
}
// check if it fits into the right half
if(signalContainsChannel(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd))
{
qDebug() << "UpChannelizer::createFilterChain: take right half (rotate by -1/4 and decimate by 2):"
<< " [" << m_filterStages.size() << "]"
<< " sig: [" << sigEnd - sigBw / 2.0f << ":" << sigEnd << "]";
m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf));
m_stageSamples.push_back(s);
return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd);
}
// check if it fits into the center
// Was: if(signalContainsChannel(sigStart + rot + safetyMargin, sigStart + rot + sigBw / 2.0f - safetyMargin, chanStart, chanEnd)) {
if(signalContainsChannel(sigStart + rot, sigEnd - rot, chanStart, chanEnd))
{
qDebug() << "UpChannelizer::createFilterChain: take center half (decimate by 2):"
<< " [" << m_filterStages.size() << "]"
<< " sig: [" << sigStart + rot << ":" << sigEnd - rot << "]";
m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter));
m_stageSamples.push_back(s);
// Was: return createFilterChain(sigStart + rot, sigStart + sigBw / 2.0f + rot, chanStart, chanEnd);
return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd);
}
Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart);
qDebug() << "UpChannelizer::createFilterChain: complete:"
<< " #stages: " << m_filterStages.size()
<< " BW: " << sigBw
<< " ofs: " << ofs;
return ofs;
}
double UpChannelizer::setFilterChain(const std::vector<unsigned int>& stageIndexes)
{
// filters are described from lower to upper level but the chain is constructed the other way round
std::vector<unsigned int>::const_reverse_iterator rit = stageIndexes.rbegin();
double ofs = 0.0, ofs_stage = 0.25;
Sample s;
// Each index is a base 3 number with 0 = low, 1 = center, 2 = high
// Functions at upper level will convert a number to base 3 to describe the filter chain. Common converting
// algorithms will go from LSD to MSD. This explains the reverse order.
for (; rit != stageIndexes.rend(); ++rit)
{
if (*rit == 0)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf));
m_stageSamples.push_back(s);
ofs -= ofs_stage;
}
else if (*rit == 1)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter));
m_stageSamples.push_back(s);
}
else if (*rit == 2)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf));
m_stageSamples.push_back(s);
ofs += ofs_stage;
}
ofs_stage /= 2;
}
return ofs;
}
void UpChannelizer::freeFilterChain()
{
for(FilterStages::iterator it = m_filterStages.begin(); it != m_filterStages.end(); ++it)
delete *it;
m_filterStages.clear();
m_stageSamples.clear();
}

View File

@ -1,148 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// 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 //
// (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 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 SDRBASE_DSP_UPCHANNELIZER_H_
#define SDRBASE_DSP_UPCHANNELIZER_H_
#include <dsp/basebandsamplesource.h>
#include <vector>
#include <QMutex>
#include "export.h"
#include "util/message.h"
#ifdef USE_SSE4_1
#include "dsp/inthalfbandfiltereo1.h"
#else
#include "dsp/inthalfbandfilterdb.h"
#endif
#define UPCHANNELIZER_HB_FILTER_ORDER 96
class MessageQueue;
class SDRBASE_API UpChannelizer : public BasebandSampleSource {
Q_OBJECT
public:
class SDRBASE_API MsgChannelizerNotification : public Message {
MESSAGE_CLASS_DECLARATION
public:
MsgChannelizerNotification(int basebandSampleRate, int samplerate, qint64 frequencyOffset) :
Message(),
m_basebandSampleRate(basebandSampleRate),
m_sampleRate(samplerate),
m_frequencyOffset(frequencyOffset)
{ }
int getBasebandSampleRate() const { return m_basebandSampleRate; }
int getSampleRate() const { return m_sampleRate; }
qint64 getFrequencyOffset() const { return m_frequencyOffset; }
static MsgChannelizerNotification* create(int basebandSampleRate, int samplerate, qint64 frequencyOffset)
{
return new MsgChannelizerNotification(basebandSampleRate, samplerate, frequencyOffset);
}
private:
int m_basebandSampleRate;
int m_sampleRate;
qint64 m_frequencyOffset;
};
class SDRBASE_API MsgSetChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
MsgSetChannelizer(unsigned int log2Interp, unsigned int filterChainHash) :
Message(),
m_log2interp(log2Interp),
m_filterChainHash(filterChainHash)
{ }
unsigned int getLog2Interp() const { return m_log2interp; }
unsigned int getFilterChainHash() const { return m_filterChainHash; }
private:
unsigned int m_log2interp;
unsigned int m_filterChainHash;
};
UpChannelizer(BasebandSampleSource* sampleSink);
virtual ~UpChannelizer();
void configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency);
void set(MessageQueue* messageQueue, unsigned int log2Interp, unsigned int filterChainHash);
int getOutputSampleRate() const { return m_outputSampleRate; }
virtual void start();
virtual void stop();
virtual void pull(Sample& sample);
virtual void pullAudio(int nbSamples) { if (m_sampleSource) m_sampleSource->pullAudio(nbSamples); }
virtual bool handleMessage(const Message& cmd);
protected:
struct FilterStage {
enum Mode {
ModeCenter,
ModeLowerHalf,
ModeUpperHalf
};
#ifdef USE_SSE4_1
typedef bool (IntHalfbandFilterEO1<UPCHANNELIZER_HB_FILTER_ORDER>::*WorkFunction)(Sample* sIn, Sample *sOut);
IntHalfbandFilterEO1<UPCHANNELIZER_HB_FILTER_ORDER>* m_filter;
#else
typedef bool (IntHalfbandFilterDB<qint32, UPCHANNELIZER_HB_FILTER_ORDER>::*WorkFunction)(Sample* sIn, Sample *sOut);
IntHalfbandFilterDB<qint32, UPCHANNELIZER_HB_FILTER_ORDER>* m_filter;
#endif
WorkFunction m_workFunction;
FilterStage(Mode mode);
~FilterStage();
bool work(Sample* sampleIn, Sample *sampleOut)
{
return (m_filter->*m_workFunction)(sampleIn, sampleOut);
}
};
typedef std::vector<FilterStage*> FilterStages;
FilterStages m_filterStages;
bool m_filterChainSetMode;
std::vector<Sample> m_stageSamples;
BasebandSampleSource* m_sampleSource; //!< Modulator
int m_outputSampleRate;
int m_requestedInputSampleRate;
int m_requestedCenterFrequency;
int m_currentInputSampleRate;
int m_currentCenterFrequency;
SampleVector m_sampleBuffer;
Sample m_sampleIn;
QMutex m_mutex;
void applyConfiguration();
void applySetting(unsigned int log2Decim, unsigned int filterChainHash);
bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const;
Real createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd);
double setFilterChain(const std::vector<unsigned int>& stageIndexes); //!< returns offset in ratio of sample rate
void freeFilterChain();
signals:
void outputSampleRateChanged();
};
#endif /* SDRBASE_DSP_UPCHANNELIZER_H_ */