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 PluginAPI;
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
class BasebandSampleSource;
|
class BasebandSampleSource;
|
||||||
class ThreadedBasebandSampleSource;
|
|
||||||
class UpChannelizer;
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class WFMModGUI;
|
class WFMModGUI;
|
||||||
@ -66,8 +64,6 @@ private:
|
|||||||
WFMModSettings m_settings;
|
WFMModSettings m_settings;
|
||||||
bool m_doApplySettings;
|
bool m_doApplySettings;
|
||||||
|
|
||||||
// ThreadedBasebandSampleSource* m_threadedChannelizer;
|
|
||||||
// UpChannelizer* m_channelizer;
|
|
||||||
WFMMod* m_wfmMod;
|
WFMMod* m_wfmMod;
|
||||||
MovingAverageUtil<double, double, 20> m_channelPowerDbAvg;
|
MovingAverageUtil<double, double, 20> m_channelPowerDbAvg;
|
||||||
|
|
||||||
|
@ -63,7 +63,6 @@ set(sdrbase_SOURCES
|
|||||||
dsp/afsquelch.cpp
|
dsp/afsquelch.cpp
|
||||||
dsp/agc.cpp
|
dsp/agc.cpp
|
||||||
dsp/downchannelizer.cpp
|
dsp/downchannelizer.cpp
|
||||||
#dsp/upchannelizer.cpp
|
|
||||||
dsp/upsamplechannelizer.cpp
|
dsp/upsamplechannelizer.cpp
|
||||||
dsp/channelmarker.cpp
|
dsp/channelmarker.cpp
|
||||||
dsp/ctcssdetector.cpp
|
dsp/ctcssdetector.cpp
|
||||||
@ -108,7 +107,6 @@ set(sdrbase_SOURCES
|
|||||||
dsp/nullsink.cpp
|
dsp/nullsink.cpp
|
||||||
dsp/recursivefilters.cpp
|
dsp/recursivefilters.cpp
|
||||||
dsp/threadedbasebandsamplesink.cpp
|
dsp/threadedbasebandsamplesink.cpp
|
||||||
#dsp/threadedbasebandsamplesource.cpp
|
|
||||||
dsp/wfir.cpp
|
dsp/wfir.cpp
|
||||||
dsp/devicesamplesource.cpp
|
dsp/devicesamplesource.cpp
|
||||||
dsp/devicesamplesink.cpp
|
dsp/devicesamplesink.cpp
|
||||||
@ -180,7 +178,6 @@ set(sdrbase_HEADERS
|
|||||||
dsp/afsquelch.h
|
dsp/afsquelch.h
|
||||||
dsp/autocorrector.h
|
dsp/autocorrector.h
|
||||||
dsp/downchannelizer.h
|
dsp/downchannelizer.h
|
||||||
#dsp/upchannelizer.h
|
|
||||||
dsp/upsamplechannelizer.h
|
dsp/upsamplechannelizer.h
|
||||||
dsp/channelmarker.h
|
dsp/channelmarker.h
|
||||||
dsp/channelsamplesource.h
|
dsp/channelsamplesource.h
|
||||||
@ -248,7 +245,6 @@ set(sdrbase_HEADERS
|
|||||||
dsp/basebandsamplesource.h
|
dsp/basebandsamplesource.h
|
||||||
dsp/nullsink.h
|
dsp/nullsink.h
|
||||||
dsp/threadedbasebandsamplesink.h
|
dsp/threadedbasebandsamplesink.h
|
||||||
#dsp/threadedbasebandsamplesource.h
|
|
||||||
dsp/wfir.h
|
dsp/wfir.h
|
||||||
dsp/devicesamplesource.h
|
dsp/devicesamplesource.h
|
||||||
dsp/devicesamplesink.h
|
dsp/devicesamplesink.h
|
||||||
|
@ -29,7 +29,6 @@ class BasebandSampleSink;
|
|||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DeviceSampleSink;
|
class DeviceSampleSink;
|
||||||
class BasebandSampleSource;
|
class BasebandSampleSource;
|
||||||
class ThreadedBasebandSampleSource;
|
|
||||||
class AudioFifo;
|
class AudioFifo;
|
||||||
|
|
||||||
class SDRBASE_API DSPAcquisitionInit : public Message {
|
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)
|
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();
|
(*it)->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include "export.h"
|
#include "export.h"
|
||||||
|
|
||||||
class DeviceSampleMIMO;
|
class DeviceSampleMIMO;
|
||||||
class ThreadedBasebandSampleSource;
|
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class BasebandSampleSink;
|
class BasebandSampleSink;
|
||||||
class MIMOChannel;
|
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