From 46e5de590817756b21a7a5d99bd4963df343f455 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 20 Feb 2010 21:52:36 +0000 Subject: Heavy overhaul of buffer management and polyphony. * Working polyphony when nodes are instantiated at desired polyphony level (dynamic still doesn't work) * Use shared silent buffer for disconnected audio inputs (save memory) * Eliminate redundant patch compiling on delete and disconnect-all events that have child events * Fix a ton of crash bugs and other issues I've since forgotten git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2468 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/InputPort.cpp | 126 +++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 69 deletions(-) (limited to 'src/engine/InputPort.cpp') diff --git a/src/engine/InputPort.cpp b/src/engine/InputPort.cpp index 75f0234e..04573a1a 100644 --- a/src/engine/InputPort.cpp +++ b/src/engine/InputPort.cpp @@ -47,6 +47,7 @@ InputPort::InputPort(BufferFactory& bufs, const Raul::Atom& value, size_t buffer_size) : PortImpl(bufs, parent, symbol, index, poly, type, value, buffer_size) + , _num_connections(0) { const LV2URIMap& uris = Shared::LV2URIMap::instance(); @@ -62,81 +63,60 @@ InputPort::InputPort(BufferFactory& bufs, bool -InputPort::can_direct() const +InputPort::apply_poly(Maid& maid, uint32_t poly) { - return _connections.size() == 1 - && _connections.front()->src_port()->poly() == poly() - && (_connections.front()->src_port()->type() == type() - || (_connections.front()->src_port()->type() == PortType::AUDIO - && type() == PortType::CONTROL)); -} - - -void -InputPort::set_buffer_size(BufferFactory& bufs, size_t size) -{ - PortImpl::set_buffer_size(bufs, size); - assert(_buffer_size = size); + bool ret = PortImpl::apply_poly(maid, poly); + if (!ret) + poly = 1; - for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) - ((ConnectionImpl*)c->get())->set_buffer_size(bufs, size); -} - - -bool -InputPort::prepare_poly(BufferFactory& bufs, uint32_t poly) -{ - PortImpl::prepare_poly(bufs, poly); - - for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) - ((ConnectionImpl*)c->get())->prepare_poly(bufs, poly); + assert(_buffers->size() >= poly); return true; } -bool -InputPort::apply_poly(Raul::Maid& maid, uint32_t poly) +void +InputPort::set_buffer_size(Context& context, BufferFactory& bufs, size_t size) { - if (!_polyphonic || !_parent->polyphonic()) - return true; + PortImpl::set_buffer_size(context, bufs, size); for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) - ((ConnectionImpl*)c->get())->apply_poly(maid, poly); - - PortImpl::apply_poly(maid, poly); - assert(this->poly() == poly); - - if (_connections.size() == 1) { - ConnectionImpl* c = _connections.begin()->get(); - for (uint32_t v = _poly; v < poly; ++v) - _buffers->at(v) = c->buffer(v); - } - - for (uint32_t i = 0; i < _poly; ++i) - PortImpl::parent_node()->set_port_buffer(i, _index, buffer(i)); - - return true; + ((ConnectionImpl*)c->get())->update_buffer_size(context, bufs); } -/** Connect buffers to the appropriate locations based on the current connections */ +/** Set \a buffers appropriately if this port has \a num_connections connections. + */ void -InputPort::connect_buffers() +InputPort::get_buffers(BufferFactory& bufs, Raul::Array* buffers, uint32_t poly) { - // Single connection now, use it directly - if (_connections.size() == 1) { - for (uint32_t v = 0; v < _poly; ++v) - _buffers->at(v) = _connections.front()->buffer(v); + size_t num_connections = (ThreadManager::current_thread_id() == THREAD_PROCESS) + ? _connections.size() : _num_connections; + + if (_type == PortType::AUDIO && num_connections == 0) { + // Audio input with no connections, use shared zero buffer + for (uint32_t v = 0; v < poly; ++v) + buffers->at(v) = bufs.silent_buffer(); + + } 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; + } - // Use local buffers } else { - for (uint32_t v = 0; v < _poly; ++v) - _buffers->at(v) = _bufs.get(_type, _buffer_size); // Use local buffer + // 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(_type, _buffer_size); + buffers->at(v)->clear(); + } } - - // Connect node to buffers - PortImpl::connect_buffers(); } @@ -144,6 +124,9 @@ InputPort::connect_buffers() * * The buffer of this port will be set directly to the connection's buffer * if there is only one connection, since no copying/mixing needs to take place. + * + * Note that setup_buffers must be called after this before the change + * will audibly take effect. */ void InputPort::add_connection(Connections::Node* const c) @@ -151,7 +134,6 @@ InputPort::add_connection(Connections::Node* const c) ThreadManager::assert_thread(THREAD_PROCESS); _connections.push_back(c); - connect_buffers(); // Automatically broadcast connected control inputs if (_type == PortType::CONTROL) @@ -159,9 +141,13 @@ InputPort::add_connection(Connections::Node* const c) } -/** Remove a connection. Realtime safe. */ +/** Remove a connection. Realtime safe. + * + * Note that setup_buffers must be called after this before the change + * will audibly take effect. + */ InputPort::Connections::Node* -InputPort::remove_connection(const OutputPort* src_port) +InputPort::remove_connection(ProcessContext& context, const OutputPort* src_port) { ThreadManager::assert_thread(THREAD_PROCESS); @@ -181,12 +167,6 @@ InputPort::remove_connection(const OutputPort* src_port) return NULL; } - connect_buffers(); - - if (_connections.size() == 0) - for (uint32_t v = 0; v < _poly; ++v) - buffer(v)->clear(); - // Turn off broadcasting if we're no longer connected if (_type == PortType::CONTROL && _connections.size() == 0) _broadcast = false; @@ -204,14 +184,15 @@ InputPort::pre_process(Context& context) if (_set_by_user) return; - //connect_buffers(); - // Process connections (mix down polyphony, if necessary) for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) (*c)->process(context); // 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); + for (uint32_t v = 0; v < _poly; ++v) { const uint32_t num_srcs = _connections.size(); Connections::iterator c = _connections.begin(); @@ -237,7 +218,7 @@ void InputPort::post_process(Context& context) { // Prepare buffers for next cycle - if (!can_direct()) + if (type() != PortType::CONTROL && num_connections() > 1) for (uint32_t v = 0; v < _poly; ++v) buffer(v)->prepare_write(context); @@ -245,5 +226,12 @@ InputPort::post_process(Context& context) } +bool +InputPort::is_silent() const +{ + return (_connections.size() == 0 && _type == PortType::AUDIO); +} + + } // namespace Ingen -- cgit v1.2.1