diff options
author | David Robillard <d@drobilla.net> | 2010-02-26 01:39:16 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2010-02-26 01:39:16 +0000 |
commit | 52e49500bb78974d43bdfd30b2ec9b2a4522dd25 (patch) | |
tree | 44a5a46e946c6b43b657ca5733a165943dd947ae | |
parent | 3d6b047cd19baf9bf5a81b4fe16e1e9e53ed8fef (diff) | |
download | ingen-52e49500bb78974d43bdfd30b2ec9b2a4522dd25.tar.gz ingen-52e49500bb78974d43bdfd30b2ec9b2a4522dd25.tar.bz2 ingen-52e49500bb78974d43bdfd30b2ec9b2a4522dd25.zip |
Perform all mixing for an audio input in a single mix operation (instead of a two step polyphony mixdown (by connections) and connections mixdown (by ports)).
Speed up and inline AudioBuffer::accumulate, to speed up mix().
Remove local buffer from Connection (always mix into destination InputPort's buffers).
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2494 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r-- | src/engine/AudioBuffer.cpp | 26 | ||||
-rw-r--r-- | src/engine/AudioBuffer.hpp | 32 | ||||
-rw-r--r-- | src/engine/ConnectionImpl.cpp | 95 | ||||
-rw-r--r-- | src/engine/ConnectionImpl.hpp | 18 | ||||
-rw-r--r-- | src/engine/DuplexPort.cpp | 2 | ||||
-rw-r--r-- | src/engine/DuplexPort.hpp | 2 | ||||
-rw-r--r-- | src/engine/InputPort.cpp | 81 | ||||
-rw-r--r-- | src/engine/InputPort.hpp | 5 | ||||
-rw-r--r-- | src/engine/OutputPort.cpp | 4 | ||||
-rw-r--r-- | src/engine/OutputPort.hpp | 2 | ||||
-rw-r--r-- | src/engine/PatchImpl.cpp | 10 | ||||
-rw-r--r-- | src/engine/PortImpl.cpp | 11 | ||||
-rw-r--r-- | src/engine/PortImpl.hpp | 4 | ||||
-rw-r--r-- | src/engine/events/Connect.cpp | 12 | ||||
-rw-r--r-- | src/engine/events/Disconnect.cpp | 4 |
15 files changed, 123 insertions, 185 deletions
diff --git a/src/engine/AudioBuffer.cpp b/src/engine/AudioBuffer.cpp index 145df559..e29fa5c4 100644 --- a/src/engine/AudioBuffer.cpp +++ b/src/engine/AudioBuffer.cpp @@ -194,32 +194,6 @@ AudioBuffer::copy(Context& context, const Buffer* src) } -/** Accumulate a block of @a src into buffer. - * - * @a start_sample and @a end_sample define the inclusive range to be accumulated. - * This function only adds the same range in one buffer to another. - */ -void -AudioBuffer::accumulate(Context& context, const AudioBuffer* const src) -{ - Sample* const buf = data(); - const Sample* const src_buf = src->data(); - - const size_t frames = std::min(nframes(), src->nframes()); - assert(frames != 0); - - // Mix initial portions - SampleCount i = 0; - for (; i < frames; ++i) - buf[i] += src_buf[i]; - - // Extend/Mix the final sample of src if it is shorter - const Sample last = src_buf[i - 1]; - while (i < nframes()) - buf[i++] += last; -} - - void AudioBuffer::prepare_read(Context& context) { diff --git a/src/engine/AudioBuffer.hpp b/src/engine/AudioBuffer.hpp index cfac3d59..7edfdef3 100644 --- a/src/engine/AudioBuffer.hpp +++ b/src/engine/AudioBuffer.hpp @@ -23,6 +23,7 @@ #include <boost/utility.hpp> #include "types.hpp" #include "ObjectBuffer.hpp" +#include "Context.hpp" using namespace std; @@ -42,7 +43,7 @@ public: void copy(Context& context, const Buffer* src); void accumulate(Context& context, const AudioBuffer* src); - bool is_control() const { return _type.symbol() == Shared::PortType::CONTROL; } + inline bool is_control() const { return _type.symbol() == Shared::PortType::CONTROL; } inline Sample* data() const { return (is_control()) @@ -75,6 +76,35 @@ private: }; +/** Accumulate a block of @a src into buffer. + */ +inline void +AudioBuffer::accumulate(Context& context, const AudioBuffer* const src) +{ + Sample* const buf = data(); + const Sample* const src_buf = src->data(); + + if (is_control()) { + if (src->is_control()) { // control => control + buf[0] += src_buf[0]; + } else { // audio => control + buf[0] += src_buf[context.offset()]; + } + } else { + const SampleCount end = context.offset() + context.nframes(); + if (src->is_control()) { // control => audio + for (SampleCount i = context.offset(); i < end; ++i) { + buf[i] += src_buf[0]; + } + } else { // audio => audio + for (SampleCount i = context.offset(); i < end; ++i) { + buf[i] += src_buf[i]; + } + } + } +} + + } // namespace Ingen #endif // INGEN_ENGINE_AUDIOBUFFER_HPP diff --git a/src/engine/ConnectionImpl.cpp b/src/engine/ConnectionImpl.cpp index d3ec6cc7..c6ccf3ba 100644 --- a/src/engine/ConnectionImpl.cpp +++ b/src/engine/ConnectionImpl.cpp @@ -55,9 +55,6 @@ ConnectionImpl::ConnectionImpl(BufferFactory& bufs, PortImpl* src_port, PortImpl assert(src_port != dst_port); assert(src_port->path() != dst_port->path()); - if (must_mix() || must_queue()) - _local_buffer = bufs.get(dst_port->buffer_type(), dst_port->buffer_size(), true); - if (must_queue()) _queue = new Raul::RingBuffer<LV2_Object>(src_port->buffer_size() * 2); } @@ -74,82 +71,23 @@ ConnectionImpl::dump() const void -ConnectionImpl::update_buffer_size(Context& context, BufferFactory& bufs) -{ - if (must_mix() || must_queue()) - allocate_buffer(bufs); -} - - -void -ConnectionImpl::allocate_buffer(BufferFactory& bufs) -{ - if (!_local_buffer) - _local_buffer = bufs.get(_dst_port->buffer_type(), _dst_port->buffer_size()); -} - - -void -ConnectionImpl::prepare_poly(BufferFactory& bufs, uint32_t poly) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - assert(_src_port->prepared_poly() == _dst_port->prepared_poly() - || _src_port->prepared_poly() == 1 - || _dst_port->prepared_poly() == 1); - - const bool mix = _src_port->prepared_poly() > _dst_port->prepared_poly(); - if ((mix || must_queue()) && !_local_buffer) - _local_buffer = bufs.get(_dst_port->buffer_type(), _dst_port->buffer(0)->size()); -} - - -void -ConnectionImpl::apply_poly(Raul::Maid& maid, uint32_t poly) +ConnectionImpl::get_sources(Context& context, uint32_t voice, + Buffer** srcs, uint32_t max_num_srcs, uint32_t& num_srcs) { - ThreadManager::assert_thread(THREAD_PROCESS); - - assert(_src_port->poly() == _dst_port->poly() - || _src_port->poly() == 1 - || _dst_port->poly() == 1); - - // Recycle buffer if it's no longer needed - if (!(must_mix() || must_queue())) - _local_buffer = NULL; -} - - -void -ConnectionImpl::process(Context& context) -{ - if (must_queue()) { - IntrusivePtr<EventBuffer> src_buf = PtrCast<EventBuffer>(_src_port->buffer(0)); - if (!src_buf) { - error << "Queued connection but source is not an EventBuffer" << endl; - return; - } - - IntrusivePtr<ObjectBuffer> local_buf = PtrCast<ObjectBuffer>(_local_buffer); - if (!local_buf) { - error << "Queued connection but local buffer is not an ObjectBuffer" << endl; - return; - } - - local_buf->clear(); + if (must_queue()) + return; - if (_queue->read_space()) { - LV2_Object obj; - _queue->full_peek(sizeof(LV2_Object), &obj); - _queue->full_read(sizeof(LV2_Object) + obj.size, local_buf->object()); + if (must_mix()) { + // Mixing down voices: every src voice mixed into every dst voice + for (uint32_t v = 0; v < _src_port->poly(); ++v) { + assert(num_srcs < max_num_srcs); + srcs[num_srcs++] = _src_port->buffer(v).get(); } - - } else if (must_mix()) { - const uint32_t num_srcs = src_port()->poly(); - Buffer* srcs[num_srcs]; - for (uint32_t v = 0; v < num_srcs; ++v) - srcs[v] = src_port()->buffer(v).get(); - - mix(context, _local_buffer.get(), srcs, num_srcs); + } else { + // Matching polyphony: each src voice mixed into corresponding dst voice + assert(_src_port->poly() == _dst_port->poly()); + assert(num_srcs < max_num_srcs); + srcs[num_srcs++] = _src_port->buffer(voice).get(); } } @@ -166,8 +104,7 @@ ConnectionImpl::queue(Context& context) return; } - src_buf->rewind(); - while (src_buf->is_valid()) { + for (src_buf->rewind(); src_buf->is_valid(); src_buf->increment()) { LV2_Event* ev = src_buf->get_event(); LV2_Object* obj = LV2_OBJECT_FROM_EVENT(ev); /*debug << _src_port->path() << " -> " << _dst_port->path() @@ -177,8 +114,6 @@ ConnectionImpl::queue(Context& context) debug << endl;*/ _queue->write(sizeof(LV2_Object) + obj->size, obj); - src_buf->increment(); - context.engine().message_context()->run(_dst_port, context.start() + ev->frames); } } diff --git a/src/engine/ConnectionImpl.hpp b/src/engine/ConnectionImpl.hpp index 232d8033..2725dd83 100644 --- a/src/engine/ConnectionImpl.hpp +++ b/src/engine/ConnectionImpl.hpp @@ -20,6 +20,7 @@ #include <cstdlib> #include <boost/utility.hpp> +#include "raul/log.hpp" #include "raul/Deletable.hpp" #include "interface/PortType.hpp" #include "interface/Connection.hpp" @@ -63,11 +64,10 @@ public: bool pending_disconnection() { return _pending_disconnection; } void pending_disconnection(bool b) { _pending_disconnection = b; } - void process(Context& context); void queue(Context& context); - void allocate_buffer(BufferFactory& bufs); - void recycle_buffer() { _local_buffer = NULL; } + void get_sources(Context& context, uint32_t voice, + Buffer** srcs, uint32_t max_num_srcs, uint32_t& num_srcs); /** Get the buffer for a particular voice. * A Connection is smart - it knows the destination port requesting the @@ -75,19 +75,16 @@ public: * voice in a mono->poly connection). */ inline BufferFactory::Ref buffer(uint32_t voice) const { - if (must_mix() || must_queue()) { - return _local_buffer; - } else if (_src_port->poly() == 1) { + assert(!must_mix()); + assert(!must_queue()); + assert(_src_port->poly() == 1 || _src_port->poly() > voice); + if (_src_port->poly() == 1) { return _src_port->buffer(0); } else { return _src_port->buffer(voice); } } - void update_buffer_size(Context& context, BufferFactory& bufs); - void prepare_poly(BufferFactory& bufs, uint32_t poly); - void apply_poly(Raul::Maid& maid, uint32_t poly); - /** Returns true if this connection must mix down voices into a local buffer */ inline bool must_mix() const { return _src_port->poly() > _dst_port->poly(); } @@ -104,7 +101,6 @@ protected: BufferFactory& _bufs; PortImpl* const _src_port; PortImpl* const _dst_port; - BufferFactory::Ref _local_buffer; bool _pending_disconnection; }; diff --git a/src/engine/DuplexPort.cpp b/src/engine/DuplexPort.cpp index 1e23b5b5..a78da58a 100644 --- a/src/engine/DuplexPort.cpp +++ b/src/engine/DuplexPort.cpp @@ -54,7 +54,7 @@ DuplexPort::DuplexPort( } -void +bool DuplexPort::get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) { if (_is_output) diff --git a/src/engine/DuplexPort.hpp b/src/engine/DuplexPort.hpp index aab33c33..ff375edd 100644 --- a/src/engine/DuplexPort.hpp +++ b/src/engine/DuplexPort.hpp @@ -52,7 +52,7 @@ public: virtual ~DuplexPort() {} - void get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); + bool get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); void pre_process(Context& context); void post_process(Context& context); diff --git a/src/engine/InputPort.cpp b/src/engine/InputPort.cpp index d5051865..4c5b56e2 100644 --- a/src/engine/InputPort.cpp +++ b/src/engine/InputPort.cpp @@ -75,19 +75,10 @@ InputPort::apply_poly(Maid& maid, uint32_t poly) } -void -InputPort::set_buffer_size(Context& context, BufferFactory& bufs, size_t size) -{ - PortImpl::set_buffer_size(context, bufs, size); - - for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) - (*c)->update_buffer_size(context, bufs); -} - - /** Set \a buffers appropriately if this port has \a num_connections connections. + * \return true iff buffers are locally owned by the port */ -void +bool InputPort::get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) { size_t num_connections = (ThreadManager::current_thread_id() == THREAD_PROCESS) @@ -97,26 +88,25 @@ InputPort::get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buf // Audio input with no connections, use shared zero buffer for (uint32_t v = 0; v < poly; ++v) buffers->at(v) = bufs.silent_buffer(); + return false; } else if (num_connections == 1) { if (ThreadManager::current_thread_id() == THREAD_PROCESS) { - // Single connection, use it directly - for (uint32_t v = 0; v < poly; ++v) - buffers->at(v) = _connections.front()->buffer(v); - } else { - // Not in the process thread, will be set later - for (uint32_t v = 0; v < poly; ++v) - buffers->at(v) = NULL; + if (!_connections.front()->must_mix()) { + // Single non-mixing conneciton, use buffers directly + for (uint32_t v = 0; v < poly; ++v) + buffers->at(v) = _connections.front()->buffer(v); + return false; + } } + } - } else { - // Use local buffers - for (uint32_t v = 0; v < poly; ++v) { - buffers->at(v) = NULL; // Release first (potential immediate recycling) - buffers->at(v) = _bufs.get(buffer_type(), _buffer_size); - buffers->at(v)->clear(); - } + // Otherwise, allocate local buffers + for (uint32_t v = 0; v < poly; ++v) { + buffers->at(v) = _bufs.get(buffer_type(), _buffer_size); + buffers->at(v)->clear(); } + return true; } @@ -186,31 +176,32 @@ InputPort::pre_process(Context& context) if (_set_by_user) return; - // Process connections (mix down polyphony, if necessary) + uint32_t max_num_srcs = 0; for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) - (*c)->process(context); + max_num_srcs += (*c)->src_port()->poly(); - // Multiple connections, mix them all into our local buffers - if (_connections.size() > 1) { - for (uint32_t v = 0; v < _poly; ++v) - buffer(v)->prepare_write(context); + Buffer* srcs[max_num_srcs]; + if (_connections.empty()) { for (uint32_t v = 0; v < _poly; ++v) { - const uint32_t num_srcs = _connections.size(); - Connections::iterator c = _connections.begin(); - Buffer* srcs[num_srcs]; - for (uint32_t i = 0; c != _connections.end(); ++c) { - assert(i < num_srcs); - srcs[i++] = (*c)->buffer(v).get(); - } + buffer(v)->prepare_read(context); + } + } else if (direct_connect()) { + for (uint32_t v = 0; v < _poly; ++v) { + _buffers->at(v) = _connections.front()->buffer(v); + _buffers->at(v)->prepare_read(context); + } + } else { + for (uint32_t v = 0; v < _poly; ++v) { + uint32_t num_srcs = 0; + for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) + (*c)->get_sources(context, v, srcs, max_num_srcs, num_srcs); mix(context, buffer(v).get(), srcs, num_srcs); + buffer(v)->prepare_read(context); } } - for (uint32_t v = 0; v < _poly; ++v) - buffer(v)->prepare_read(context); - if (_broadcast) broadcast_value(context, false); } @@ -223,5 +214,13 @@ InputPort::post_process(Context& context) } +bool +InputPort::direct_connect() const +{ + ThreadManager::assert_thread(THREAD_PROCESS); + return _connections.size() == 1 && !_connections.front()->must_mix(); +} + + } // namespace Ingen diff --git a/src/engine/InputPort.hpp b/src/engine/InputPort.hpp index 44f82370..40282dee 100644 --- a/src/engine/InputPort.hpp +++ b/src/engine/InputPort.hpp @@ -65,9 +65,8 @@ public: Connections::Node* remove_connection(ProcessContext& context, const OutputPort* src_port); bool apply_poly(Raul::Maid& maid, uint32_t poly); - void set_buffer_size(Context& context, BufferFactory& bufs, size_t size); - void get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); + bool get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); void pre_process(Context& context); void post_process(Context& context); @@ -79,6 +78,8 @@ public: bool is_input() const { return true; } bool is_output() const { return false; } + bool direct_connect() const; + protected: size_t _num_connections; ///< Pre-process thread Connections _connections; diff --git a/src/engine/OutputPort.cpp b/src/engine/OutputPort.cpp index c2381cff..5509b655 100644 --- a/src/engine/OutputPort.cpp +++ b/src/engine/OutputPort.cpp @@ -51,11 +51,13 @@ OutputPort::OutputPort(BufferFactory& bufs, } -void +bool OutputPort::get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) { for (uint32_t v = 0; v < poly; ++v) buffers->at(v) = bufs.get(buffer_type(), _buffer_size); + + return true; } diff --git a/src/engine/OutputPort.hpp b/src/engine/OutputPort.hpp index b143ae32..fde0f861 100644 --- a/src/engine/OutputPort.hpp +++ b/src/engine/OutputPort.hpp @@ -48,7 +48,7 @@ public: const Raul::Atom& value, size_t buffer_size=0); - void get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); + bool get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); void pre_process(Context& context); void post_process(Context& context); diff --git a/src/engine/PatchImpl.cpp b/src/engine/PatchImpl.cpp index 309ac3f8..c5327e44 100644 --- a/src/engine/PatchImpl.cpp +++ b/src/engine/PatchImpl.cpp @@ -111,8 +111,9 @@ PatchImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly) for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) (*i)->prepare_poly(bufs, poly); - for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) - ((ConnectionImpl*)i->second.get())->prepare_poly(bufs, poly); + for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) + for (uint32_t j = 0; j < (*i)->num_ports(); ++j) + (*i)->port_impl(j)->prepare_poly_buffers(bufs); return true; } @@ -128,13 +129,10 @@ PatchImpl::apply_internal_poly(ProcessContext& context, BufferFactory& bufs, Rau for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) (*i)->apply_poly(maid, poly); - for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) - ((ConnectionImpl*)i->second.get())->apply_poly(maid, poly); - for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) { for (uint32_t j = 0; j < (*i)->num_ports(); ++j) { PortImpl* const port = (*i)->port_impl(j); - if (port->is_input() && dynamic_cast<InputPort*>(port)->num_connections() == 1) + if (port->is_input() && dynamic_cast<InputPort*>(port)->direct_connect()) port->setup_buffers(bufs, port->poly()); port->connect_buffers(context.offset()); } diff --git a/src/engine/PortImpl.cpp b/src/engine/PortImpl.cpp index a1a20ba8..7abfb90d 100644 --- a/src/engine/PortImpl.cpp +++ b/src/engine/PortImpl.cpp @@ -127,13 +127,18 @@ PortImpl::prepare_poly(BufferFactory& bufs, uint32_t poly) if (!_prepared_buffers) _prepared_buffers = new Array<BufferFactory::Ref>(poly, *_buffers, NULL); - get_buffers(bufs, _prepared_buffers, poly); - assert(prepared_poly() == poly); - return true; } +void +PortImpl::prepare_poly_buffers(BufferFactory& bufs) +{ + if (_prepared_buffers) + get_buffers(bufs, _prepared_buffers, _prepared_buffers->size()); +} + + bool PortImpl::apply_poly(Maid& maid, uint32_t poly) { diff --git a/src/engine/PortImpl.hpp b/src/engine/PortImpl.hpp index 637336af..cb458d01 100644 --- a/src/engine/PortImpl.hpp +++ b/src/engine/PortImpl.hpp @@ -68,6 +68,8 @@ public: */ virtual bool prepare_poly(BufferFactory& bufs, uint32_t poly); + virtual void prepare_poly_buffers(BufferFactory& bufs); + /** Apply a new polyphony value. * * Audio thread. @@ -92,7 +94,7 @@ public: /** Empty buffer contents completely (ie silence) */ virtual void clear_buffers(); - virtual void get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) = 0; + virtual bool get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) = 0; void setup_buffers(BufferFactory& bufs, uint32_t poly) { get_buffers(bufs, _buffers, poly); diff --git a/src/engine/events/Connect.cpp b/src/engine/events/Connect.cpp index 5b7726d9..5eefb181 100644 --- a/src/engine/events/Connect.cpp +++ b/src/engine/events/Connect.cpp @@ -135,15 +135,11 @@ Connect::pre_process() _patch->add_connection(_connection); _dst_input_port->increment_num_connections(); - switch (_dst_input_port->num_connections()) { - case 1: - _connection->allocate_buffer(*_engine.buffer_factory()); - break; - case 2: + if ((_dst_input_port->num_connections() == 1 && _connection->must_mix()) + || _dst_input_port->num_connections() == 2) { _buffers = new Raul::Array<BufferFactory::Ref>(_dst_input_port->poly()); - _dst_input_port->get_buffers(*_engine.buffer_factory(), _buffers, _dst_input_port->poly()); - default: - break; + _dst_input_port->get_buffers(*_engine.buffer_factory(), + _buffers, _dst_input_port->poly()); } if (_patch->enabled()) diff --git a/src/engine/events/Disconnect.cpp b/src/engine/events/Disconnect.cpp index f25c0f4a..443cc512 100644 --- a/src/engine/events/Disconnect.cpp +++ b/src/engine/events/Disconnect.cpp @@ -161,7 +161,8 @@ Disconnect::pre_process() if (_dst_input_port->num_connections() == 0) { _buffers = new Raul::Array<BufferFactory::Ref>(_dst_input_port->poly()); - _dst_input_port->get_buffers(*_engine.buffer_factory(), _buffers, _dst_input_port->poly()); + _dst_input_port->get_buffers(*_engine.buffer_factory(), + _buffers, _dst_input_port->poly()); _clear_dst_port = true; } @@ -181,7 +182,6 @@ Disconnect::execute(ProcessContext& context) if (_error == NO_ERROR) { InputPort::Connections::Node* const port_connections_node = _dst_input_port->remove_connection(context, _src_output_port); - port_connections_node->elem()->recycle_buffer(); if (_reconnect_dst_port) { if (_buffers) _engine.maid()->push(_dst_input_port->set_buffers(_buffers)); |