From cbc7847a12e57176c5bafa9baa007de6865745c7 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 18 Sep 2007 15:13:05 +0000 Subject: Work on dynamic polyphony. git-svn-id: http://svn.drobilla.net/lad/ingen@720 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/engine/InputPort.cpp | 44 +++++++++++++++++++++--------------------- src/libs/engine/LV2Node.cpp | 14 ++++++++++++++ src/libs/engine/LV2Node.hpp | 4 ++++ src/libs/engine/Node.hpp | 17 +++++++++++++++- src/libs/engine/NodeBase.cpp | 18 +++++++++++++++++ src/libs/engine/NodeBase.hpp | 3 +++ src/libs/engine/OutputPort.cpp | 4 ++-- src/libs/engine/Port.cpp | 44 +++++++++++++++++++++++++++++++++++------- src/libs/engine/Port.hpp | 24 +++++++++++++++++++++-- 9 files changed, 138 insertions(+), 34 deletions(-) diff --git a/src/libs/engine/InputPort.cpp b/src/libs/engine/InputPort.cpp index 5025f6e3..edc89225 100644 --- a/src/libs/engine/InputPort.cpp +++ b/src/libs/engine/InputPort.cpp @@ -55,25 +55,25 @@ InputPort::add_connection(Raul::ListNode* const c) if (_connections.size() == 1) { // Use buffer directly to avoid copying for (uint32_t i=0; i < _poly; ++i) { - _buffers.at(i)->join(c->elem()->buffer(i)); + _buffers->at(i)->join(c->elem()->buffer(i)); //if (_is_tied) - // _tied_port->buffer(i)->join(_buffers.at(i)); - //assert(_buffers.at(i)->data() == c->elem()->buffer(i)->data()); + // _tied_port->buffer(i)->join(_buffers->at(i)); + //assert(_buffers->at(i)->data() == c->elem()->buffer(i)->data()); } } else if (_connections.size() == 2) { // Used to directly use single connection buffer, now there's two // so have to use local ones again and mix down for (uint32_t i=0; i < _poly; ++i) { - _buffers.at(i)->unjoin(); + _buffers->at(i)->unjoin(); //if (_is_tied) - // _tied_port->buffer(i)->join(_buffers.at(i)); + // _tied_port->buffer(i)->join(_buffers->at(i)); } } Port::connect_buffers(); } //assert( ! _is_tied || _tied_port != NULL); - //assert( ! _is_tied || _buffers.at(0)->data() == _tied_port->buffer(0)->data()); + //assert( ! _is_tied || _buffers->at(0)->data() == _tied_port->buffer(0)->data()); } @@ -103,17 +103,17 @@ InputPort::remove_connection(const OutputPort* src_port) for (uint32_t i=0; i < _poly; ++i) { // Use a local buffer if (modify_buffers) - _buffers.at(i)->unjoin(); - _buffers.at(i)->clear(); // Write silence + _buffers->at(i)->unjoin(); + _buffers->at(i)->clear(); // Write silence //if (_is_tied) - //m_tied_port->buffer(i)->join(_buffers.at(i)); + //m_tied_port->buffer(i)->join(_buffers->at(i)); } } else if (modify_buffers && _connections.size() == 1) { // Share a buffer for (uint32_t i=0; i < _poly; ++i) { - _buffers.at(i)->join((*_connections.begin())->buffer(i)); + _buffers->at(i)->join((*_connections.begin())->buffer(i)); //if (_is_tied) - // _tied_port->buffer(i)->join(_buffers.at(i)); + // _tied_port->buffer(i)->join(_buffers->at(i)); } } } @@ -122,7 +122,7 @@ InputPort::remove_connection(const OutputPort* src_port) Port::connect_buffers(); //assert( ! _is_tied || _tied_port != NULL); - //assert( ! _is_tied || _buffers.at(0)->data() == _tied_port->buffer(0)->data()); + //assert( ! _is_tied || _buffers->at(0)->data() == _tied_port->buffer(0)->data()); return connection; } @@ -153,7 +153,7 @@ InputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end) if (_connections.size() == 0) { for (uint32_t i=0; i < _poly; ++i) - _buffers.at(i)->prepare_read(nframes); + _buffers->at(i)->prepare_read(nframes); return; } @@ -163,13 +163,13 @@ InputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end) // If only one connection, buffer is (maybe) used directly (no copying) if (_connections.size() == 1) { // Buffer changed since connection - if (!_buffers.at(0)->is_joined_to((*_connections.begin())->buffer(0))) { + if (!_buffers->at(0)->is_joined_to((*_connections.begin())->buffer(0))) { if (_fixed_buffers) { // || (_is_tied && _tied_port->fixed_buffers())) { // can't change buffer, must copy do_mixdown = true; } else { // zero-copy - _buffers.at(0)->join((*_connections.begin())->buffer(0)); + _buffers->at(0)->join((*_connections.begin())->buffer(0)); do_mixdown = false; } connect_buffers(); @@ -181,20 +181,20 @@ InputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end) //cerr << path() << " mixing: " << do_mixdown << endl; for (uint32_t i=0; i < _poly; ++i) - _buffers.at(i)->prepare_read(nframes); + _buffers->at(i)->prepare_read(nframes); if (!do_mixdown) { - assert(_buffers.at(0)->is_joined_to((*_connections.begin())->buffer(0))); + assert(_buffers->at(0)->is_joined_to((*_connections.begin())->buffer(0))); return; } /*assert(!_is_tied || _tied_port != NULL); - assert(!_is_tied || _buffers.at(0)->data() == _tied_port->buffer(0)->data());*/ + assert(!_is_tied || _buffers->at(0)->data() == _tied_port->buffer(0)->data());*/ if (_type == DataType::FLOAT) { for (uint32_t voice=0; voice < _poly; ++voice) { // Copy first connection - _buffers.at(voice)->copy( + _buffers->at(voice)->copy( (*_connections.begin())->buffer(voice), 0, _buffer_size-1); // Accumulate the rest @@ -203,7 +203,7 @@ InputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end) Connections::iterator c = _connections.begin(); for (++c; c != _connections.end(); ++c) - ((AudioBuffer*)_buffers.at(voice))->accumulate( + ((AudioBuffer*)_buffers->at(voice))->accumulate( ((AudioBuffer*)(*c)->buffer(voice)), 0, _buffer_size-1); } } @@ -215,7 +215,7 @@ InputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end) // cerr << "WARNING: MIDI mixing not implemented, only first connection used." << endl; // Copy first connection - _buffers.at(0)->copy( + _buffers->at(0)->copy( (*_connections.begin())->buffer(0), 0, _buffer_size-1); } } @@ -237,7 +237,7 @@ InputPort::post_process(SampleCount nframes, FrameTime start, FrameTime end) { // Prepare for next cycle for (uint32_t i=0; i < _poly; ++i) - _buffers.at(i)->prepare_write(nframes); + _buffers->at(i)->prepare_write(nframes); } diff --git a/src/libs/engine/LV2Node.cpp b/src/libs/engine/LV2Node.cpp index ccad761f..36bfd319 100644 --- a/src/libs/engine/LV2Node.cpp +++ b/src/libs/engine/LV2Node.cpp @@ -50,6 +50,20 @@ LV2Node::LV2Node(const Plugin* plugin, } +void +LV2Node::prepare_poly(uint32_t poly) +{ + NodeBase::prepare_poly(poly); +} + + +void +LV2Node::apply_poly(Raul::Maid& maid, uint32_t poly) +{ + NodeBase::apply_poly(maid, poly); +} + + /** Instantiate self from LV2 plugin descriptor. * * Implemented as a seperate function (rather than in the constructor) to diff --git a/src/libs/engine/LV2Node.hpp b/src/libs/engine/LV2Node.hpp index 8a6847f1..88ae5ffc 100644 --- a/src/libs/engine/LV2Node.hpp +++ b/src/libs/engine/LV2Node.hpp @@ -44,6 +44,9 @@ public: virtual ~LV2Node(); virtual bool instantiate(); + + void prepare_poly(uint32_t poly); + void apply_poly(Raul::Maid& maid, uint32_t poly); void activate(); void deactivate(); @@ -57,6 +60,7 @@ protected: SLV2Plugin _lv2_plugin; SLV2Instance* _instances; + SLV2Instance* _prepared_instances; }; diff --git a/src/libs/engine/Node.hpp b/src/libs/engine/Node.hpp index feb9e9ef..ca495904 100644 --- a/src/libs/engine/Node.hpp +++ b/src/libs/engine/Node.hpp @@ -23,7 +23,7 @@ #include "types.hpp" #include "GraphObject.hpp" -namespace Raul { template class List; } +namespace Raul { template class List; class Maid; } namespace Ingen { @@ -61,7 +61,22 @@ public: virtual void activate() = 0; virtual void deactivate() = 0; virtual bool activated() = 0; + + /** Prepare for a new (external) polyphony value. + * + * Preprocessor thread, poly is actually applied by apply_poly. + */ + virtual void prepare_poly(uint32_t poly) = 0; + /** Apply a new polyphony value. + * + * Audio thread. + * + * \param poly Must be < the most recent value passed to prepare_poly. + * \param maid Any objects no longer needed will be pushed to this + */ + virtual void apply_poly(Raul::Maid& maid, uint32_t poly) = 0; + /** Parallelism: Reset flags for start of a new cycle. */ virtual void reset_input_ready() = 0; diff --git a/src/libs/engine/NodeBase.cpp b/src/libs/engine/NodeBase.cpp index b61783b3..32b641e0 100644 --- a/src/libs/engine/NodeBase.cpp +++ b/src/libs/engine/NodeBase.cpp @@ -82,6 +82,24 @@ NodeBase::deactivate() } +void +NodeBase::prepare_poly(uint32_t poly) +{ + if (_ports) + for (size_t i=0; i < _ports->size(); ++i) + _ports->at(i)->prepare_poly(poly); +} + + +void +NodeBase::apply_poly(Raul::Maid& maid, uint32_t poly) +{ + if (_ports) + for (size_t i=0; i < _ports->size(); ++i) + _ports->at(i)->apply_poly(maid, poly); +} + + void NodeBase::set_buffer_size(size_t size) { diff --git a/src/libs/engine/NodeBase.hpp b/src/libs/engine/NodeBase.hpp index 668f615c..ed3cd80d 100644 --- a/src/libs/engine/NodeBase.hpp +++ b/src/libs/engine/NodeBase.hpp @@ -55,6 +55,9 @@ public: virtual void deactivate(); bool activated() { return _activated; } + virtual void prepare_poly(uint32_t poly); + virtual void apply_poly(Raul::Maid& maid, uint32_t poly); + virtual void reset_input_ready(); virtual bool process_lock(); virtual void process_unlock(); diff --git a/src/libs/engine/OutputPort.cpp b/src/libs/engine/OutputPort.cpp index ce945f09..9724c4c7 100644 --- a/src/libs/engine/OutputPort.cpp +++ b/src/libs/engine/OutputPort.cpp @@ -25,7 +25,7 @@ void OutputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end) { for (uint32_t i=0; i < _poly; ++i) - _buffers.at(i)->prepare_write(nframes); + _buffers->at(i)->prepare_write(nframes); } @@ -33,7 +33,7 @@ void OutputPort::post_process(SampleCount nframes, FrameTime start, FrameTime end) { for (uint32_t i=0; i < _poly; ++i) - _buffers.at(i)->prepare_read(nframes); + _buffers->at(i)->prepare_read(nframes); } diff --git a/src/libs/engine/Port.cpp b/src/libs/engine/Port.cpp index c104c32a..8f9e9ce7 100644 --- a/src/libs/engine/Port.cpp +++ b/src/libs/engine/Port.cpp @@ -15,6 +15,8 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include +#include #include "Port.hpp" #include "Node.hpp" #include "DataType.hpp" @@ -42,24 +44,52 @@ Port::Port(Node* const node, const string& name, uint32_t index, uint32_t poly, allocate_buffers(); clear_buffers(); - assert(_buffers.size() > 0); + assert(_buffers->size() > 0); } Port::~Port() { for (uint32_t i=0; i < _poly; ++i) - delete _buffers.at(i); + delete _buffers->at(i); +} + + +void +Port::prepare_poly(uint32_t poly) +{ + /* FIXME: poly never goes down, harsh on memory.. */ + if (poly > _poly) { + _prepared_buffers = new Raul::Array(poly, *_buffers); + _prepared_poly = poly; + for (uint32_t i = _poly; i < _prepared_poly; ++i) + _buffers->at(i) = BufferFactory::create(_type, _buffer_size); + } +} + + +void +Port::apply_poly(Raul::Maid& maid, uint32_t poly) +{ + assert(poly <= _prepared_poly); + + // Apply a new set of buffers from a preceding call to prepare_poly + if (_prepared_buffers && _buffers != _prepared_buffers) { + maid.push(_buffers); + _buffers = _prepared_buffers; + } + + _poly = poly; } void Port::allocate_buffers() { - _buffers.alloc(_poly); + _buffers->alloc(_poly); for (uint32_t i=0; i < _poly; ++i) - _buffers.at(i) = BufferFactory::create(_type, _buffer_size); + _buffers->at(i) = BufferFactory::create(_type, _buffer_size); } @@ -69,7 +99,7 @@ Port::set_buffer_size(size_t size) _buffer_size = size; for (uint32_t i=0; i < _poly; ++i) - _buffers.at(i)->resize(size); + _buffers->at(i)->resize(size); connect_buffers(); } @@ -79,7 +109,7 @@ void Port::connect_buffers() { for (uint32_t i=0; i < _poly; ++i) - Port::parent_node()->set_port_buffer(i, _index, _buffers.at(i)); + Port::parent_node()->set_port_buffer(i, _index, _buffers->at(i)); } @@ -87,7 +117,7 @@ void Port::clear_buffers() { for (uint32_t i=0; i < _poly; ++i) - _buffers.at(i)->clear(); + _buffers->at(i)->clear(); } diff --git a/src/libs/engine/Port.hpp b/src/libs/engine/Port.hpp index 2899915f..5b1c86b2 100644 --- a/src/libs/engine/Port.hpp +++ b/src/libs/engine/Port.hpp @@ -25,6 +25,8 @@ #include "GraphObject.hpp" #include "DataType.hpp" +namespace Raul { class Maid; } + namespace Ingen { class Node; @@ -46,8 +48,22 @@ public: /** A port's parent is always a node, so static cast should be safe */ Node* parent_node() const { return (Node*)_parent; } + + /** Prepare for a new (external) polyphony value. + * + * Preprocessor thread, poly is actually applied by apply_poly. + */ + virtual void prepare_poly(uint32_t poly); + + /** Apply a new polyphony value. + * + * Audio thread. + * + * \param poly Must be < the most recent value passed to prepare_poly. + */ + virtual void apply_poly(Raul::Maid& maid, uint32_t poly); - Buffer* buffer(uint32_t voice) const { return _buffers.at(voice); } + Buffer* buffer(uint32_t voice) const { return _buffers->at(voice); } /** Called once per process cycle */ virtual void pre_process(SampleCount nframes, FrameTime start, FrameTime end) = 0; @@ -82,7 +98,11 @@ protected: size_t _buffer_size; bool _fixed_buffers; - Raul::Array _buffers; + Raul::Array* _buffers; + + // Dynamic polyphony + uint32_t _prepared_poly; + Raul::Array* _prepared_buffers; }; -- cgit v1.2.1