mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-17 13:51:47 -05:00
Removal of UpChannelizer and ThreadedBasebandSampleSource
This commit is contained in:
parent
3b74153ec6
commit
5a843a573c
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -29,7 +29,6 @@ class BasebandSampleSink;
|
||||
class ThreadedBasebandSampleSink;
|
||||
class DeviceSampleSink;
|
||||
class BasebandSampleSource;
|
||||
class ThreadedBasebandSampleSource;
|
||||
class AudioFifo;
|
||||
|
||||
class SDRBASE_API DSPAcquisitionInit : public Message {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "export.h"
|
||||
|
||||
class DeviceSampleMIMO;
|
||||
class ThreadedBasebandSampleSource;
|
||||
class ThreadedBasebandSampleSink;
|
||||
class BasebandSampleSink;
|
||||
class MIMOChannel;
|
||||
|
@ -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();
|
||||
}
|
@ -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_ */
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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_ */
|
Loading…
Reference in New Issue
Block a user