combine.hh
#ifndef __SDR_COMBINE_HH__
#define __SDR_COMBINE_HH__
#include "config.hh"
#include "traits.hh"
#include "node.hh"
#include "buffer.hh"
#include "logger.hh"
#include <limits>
namespace sdr {
template <class Scalar> class Combine;
template <class Scalar>
class CombineSink: public Sink<Scalar>
{
public:
CombineSink(Combine<Scalar> *combine, size_t index, RingBuffer<Scalar> &buffer)
: Sink<Scalar>(), _index(index), _parent(combine), _buffer(buffer)
{
// Pass...
}
virtual ~CombineSink() {
// pass...
}
virtual void config(const Config &src_cfg) {
// Requires sample rate and type
if (!src_cfg.hasType() || !src_cfg.hasSampleRate()) { return; }
// Check type
if (Config::typeId<Scalar>() != src_cfg.type()) {
ConfigError err;
err << "Can not configure CombinSink: Invalid source type " << src_cfg.type()
<< ", expected " << Config::typeId<Scalar>();
throw err;
}
// Notify parent
_parent->notifyConfig(_index, src_cfg);
}
virtual void process(const Buffer<Scalar> &buffer, bool allow_overwrite) {
// Copy data into ring buffer and notify parent
_buffer.put(buffer);
_parent->notifyData(_index);
}
protected:
size_t _index;
Combine<Scalar> *_parent;
RingBuffer<Scalar> &_buffer;
};
template <class Scalar>
class Combine
{
public:
Combine(size_t N) {
_buffers.reserve(N); _sinks.reserve(N);
for (size_t i=0; i<N; i++) {
_buffers.push_back(RingBuffer<Scalar>());
_sinks.push_back(new CombineSink<Scalar>(this, i, _buffers.back()));
}
}
virtual ~Combine() {
// Unref all buffers and free sinks
for (size_t i=0; i<_sinks.size(); i++) {
delete _sinks[i];
_buffers[i].unref();
}
_buffers.clear();
_sinks.clear();
}
virtual void config(const Config &cfg) = 0;
virtual void process(std::vector< RingBuffer<Scalar> > &buffers, size_t N) = 0;
protected:
void notifyConfig(size_t idx, const Config &cfg)
{
// Requires type, sampleRate and buffer size
if (!cfg.hasType() || !cfg.hasSampleRate() || !cfg.hasBufferSize()) { return; }
// check or unify type
if (!_config.hasType()) { _config.setType(cfg.type()); }
else if (_config.type() != cfg.type()) {
ConfigError err;
err << "Can not configure Combine node: Invalid type of sink #" << idx
<< " " << cfg.type() << ", expected " << _config.type();
throw err;
}
// Check sample rate
if (!_config.hasSampleRate()) { _config.setSampleRate(cfg.sampleRate()); }
else if (_config.sampleRate() != cfg.sampleRate()) {
ConfigError err;
err << "Can ont configure Combine node: Invalid sample rate of sink #" << idx
<< " " << cfg.sampleRate() << ", expected " << _config.sampleRate();
throw err;
}
// Determine max buffer size
if (!_config.hasBufferSize()) { _config.setBufferSize(cfg.bufferSize()); }
else {
// Take maximum:
_config.setBufferSize(std::max(_config.bufferSize(), cfg.bufferSize()));
}
// Reallocate buffers
for (size_t i=0; i<_sinks.size(); i++) {
_buffers[i] = RingBuffer<Scalar>(_config.bufferSize());
}
// Propergate config
this->config(_config);
}
void notifyData(size_t idx) {
// Determine minimum size of available data
size_t N = std::numeric_limits<size_t>::max();
for (size_t i=0; i<_sinks.size(); i++) {
N = std::min(N, _buffers[i].stored());
}
if (N > 0) { this->process(_buffers, N); }
}
protected:
std::vector< RingBuffer<Scalar> > _buffers;
std::vector< CombineSink<Scalar> *> _sinks;
Config _config;
friend class CombineSink<Scalar>;
};
template <class Scalar>
class Interleave : public Combine<Scalar>, public Source
{
public:
Interleave(size_t N)
: Combine<Scalar>(N), Source(), _N(N), _buffer()
{
// pass...
}
Sink<Scalar> *sink(size_t i) {
if (i >= _N) {
RuntimeError err;
err << "Interleave: Sink index " << i << " out of range [0," << _N << ")";
throw err;
}
return Combine<Scalar>::_sinks[i];
}
virtual void config(const Config &cfg) {
//Requres type & buffer size
if (!cfg.hasType() || !cfg.hasBufferSize()) { return; }
// Check type
if (Config::typeId<Scalar>() != cfg.type()) {
ConfigError err;
err << "Can not configure Interleave node: Invalid source type " << cfg.type()
<< ", expected " << Config::typeId<Scalar>();
throw err;
}
// Allocate buffer:
_buffer = Buffer<Scalar>(_N*cfg.bufferSize());
// Propergate config
this->setConfig(Config(Config::typeId<Scalar>(), cfg.sampleRate(), _buffer.size(), 1));
}
virtual void process(std::vector<RingBuffer<Scalar> > &buffers, size_t N) {
if (0 == N) { return; }
if (! _buffer.isUnused()) {
#ifdef SDR_DEBUG
LogMessage msg(LOG_WARNING);
msg << "Interleave: Output buffer in use: Drop " << _N << "x" << N
<< " input values";
Logger::get().log(msg);
#endif
for (size_t i=0; i<buffers.size(); i++) { buffers[i].drop(N); }
return;
}
size_t num = std::min(_buffer.size()/_N,N);
// Interleave data
size_t idx = 0;
for (size_t i=0; i<num; i++) {
for (size_t j=0; j<_N; j++, idx++) {
_buffer[idx] = buffers[j][i];
}
}
// Drop num elements from all ring buffers
for (size_t i=0; i<_N; i++) {
buffers[i].drop(num);
}
// Send buffer
this->send(_buffer.head(num*_N));
}
protected:
size_t _N;
Buffer<Scalar> _buffer;
};
}
#endif // __SDR_COMBINE_HH__
sdr::Config
A collection of configuration information that is send by a source to all connected sinks to properga...
Definition: node.hh:35
sdr::Interleave::config
virtual void config(const Config &cfg)
Configures the interleave node.
Definition: combine.hh:177
sdr::Interleave
Interleaves several input streams.
Definition: combine.hh:156
sdr::CombineSink::_index
size_t _index
The index of the sink within the combine node.
Definition: combine.hh:55
sdr::Combine::notifyData
void notifyData(size_t idx)
Determines the minimum amount of data that is available on all ring buffers.
Definition: combine.hh:132
sdr::RingBuffer
A simple typed ring-buffer.
Definition: buffer.hh:473
sdr::Source::send
virtual void send(const RawBuffer &buffer, bool allow_overwrite=false)
Sends the given buffer to all connected sinks.
Definition: node.cc:67
sdr::Interleave::_buffer
Buffer< Scalar > _buffer
The putput buffer.
Definition: combine.hh:226
sdr::Sink
Typed sink.
Definition: node.hh:192
sdr::CombineSink::process
virtual void process(const Buffer< Scalar > &buffer, bool allow_overwrite)
Handles the given buffer.
Definition: combine.hh:47
sdr
Definition: autocast.hh:8
sdr::Combine::config
virtual void config(const Config &cfg)=0
Needs to be overridden.
sdr::Config::hasSampleRate
bool hasSampleRate() const
If true, the configuration has a sample rate.
Definition: node.hh:75
sdr::Source
Generic source class.
Definition: node.hh:213
sdr::CombineSink::_buffer
RingBuffer< Scalar > & _buffer
The input ring-buffer.
Definition: combine.hh:59
sdr::RuntimeError
The runtime error class.
Definition: exception.hh:36
sdr::Interleave::_N
size_t _N
The number of sinks.
Definition: combine.hh:224
sdr::Buffer::size
size_t size() const
Returns the number of elements of type T in this buffer.
Definition: buffer.hh:166
sdr::Config::hasType
bool hasType() const
If true, the configuration has a type.
Definition: node.hh:69
sdr::Combine::process
virtual void process(std::vector< RingBuffer< Scalar > > &buffers, size_t N)=0
Needs to be overridden.
sdr::Combine
A combine node.
Definition: combine.hh:13
sdr::Source::setConfig
virtual void setConfig(const Config &config)
Stores the configuration and propergates it if the configuration has been changed.
Definition: node.cc:98
sdr::Buffer::head
Buffer< T > head(size_t n) const
Returns a new view on this buffer.
Definition: buffer.hh:237
sdr::Logger::log
void log(const LogMessage &message)
Logs a message.
Definition: logger.cc:100
sdr::Combine::_buffers
std::vector< RingBuffer< Scalar > > _buffers
The ring buffers of all combine sinks.
Definition: combine.hh:143
sdr::Config::type
Type type() const
Returns the type.
Definition: node.hh:71
sdr::Config::setType
void setType(Type type)
Sets the type.
Definition: node.hh:73
sdr::Combine::_sinks
std::vector< CombineSink< Scalar > * > _sinks
The combine sinks.
Definition: combine.hh:145
sdr::CombineSink::config
virtual void config(const Config &src_cfg)
Configures the sink.
Definition: combine.hh:32
sdr::Logger::get
static Logger & get()
Returns the singleton instance of the logger.
Definition: logger.cc:89
sdr::CombineSink::_parent
Combine< Scalar > * _parent
A reference to the combine node.
Definition: combine.hh:57
sdr::ConfigError
The configuration error class.
Definition: exception.hh:24
sdr::Interleave::process
virtual void process(std::vector< RingBuffer< Scalar > > &buffers, size_t N)
Processes the data from all sinks.
Definition: combine.hh:194
sdr::LogMessage
A log message.
Definition: logger.hh:22
sdr::Config::bufferSize
size_t bufferSize() const
Returns the max.
Definition: node.hh:83
sdr::Combine::Combine
Combine(size_t N)
Constructor, N specifies the number of sinks.
Definition: combine.hh:70
sdr::Interleave::Interleave
Interleave(size_t N)
Constructor.
Definition: combine.hh:160
sdr::CombineSink::~CombineSink
virtual ~CombineSink()
Destructor.
Definition: combine.hh:27
sdr::Config::setSampleRate
void setSampleRate(double rate)
Sets the sample rate.
Definition: node.hh:79
sdr::Interleave::sink
Sink< Scalar > * sink(size_t i)
Retunrs the i-th sink.
Definition: combine.hh:167
sdr::Combine::_config
Config _config
The output configuration.
Definition: combine.hh:147
sdr::RawBuffer::isUnused
bool isUnused() const
We assume here that buffers are owned by one object: A buffer is therefore "unused" if the owner hold...
Definition: buffer.hh:87
sdr::Combine::notifyConfig
void notifyConfig(size_t idx, const Config &cfg)
Unifies the configuration of all sinks.
Definition: combine.hh:97
sdr::CombineSink::CombineSink
CombineSink(Combine< Scalar > *combine, size_t index, RingBuffer< Scalar > &buffer)
Constructor.
Definition: combine.hh:21
sdr::CombineSink
A single sink of a Combine node.
Definition: combine.hh:17
sdr::Combine::~Combine
virtual ~Combine()
Destructor.
Definition: combine.hh:79
sdr::Buffer< Scalar >
sdr::Config::setBufferSize
void setBufferSize(size_t size)
Sets the max.
Definition: node.hh:85
sdr::Config::hasBufferSize
bool hasBufferSize() const
If true, the configuration has a buffer size.
Definition: node.hh:81
sdr::Config::sampleRate
double sampleRate() const
Returns the sample rate.
Definition: node.hh:77