diff options
Diffstat (limited to 'src/libs/engine/Patch.cpp')
-rw-r--r-- | src/libs/engine/Patch.cpp | 445 |
1 files changed, 0 insertions, 445 deletions
diff --git a/src/libs/engine/Patch.cpp b/src/libs/engine/Patch.cpp deleted file mode 100644 index 8256f0c5..00000000 --- a/src/libs/engine/Patch.cpp +++ /dev/null @@ -1,445 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 Dave Robillard <http://drobilla.net> - * - * Ingen 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; either version 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 for details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <cassert> -#include <cmath> -#include <iostream> -#include "ThreadManager.hpp" -#include "NodeImpl.hpp" -#include "Patch.hpp" -#include "PluginImpl.hpp" -#include "PortImpl.hpp" -#include "ConnectionImpl.hpp" -#include "DuplexPort.hpp" -#include "Engine.hpp" -#include "ProcessSlave.hpp" - -using namespace std; - -namespace Ingen { - - -Patch::Patch(Engine& engine, const string& path, uint32_t poly, Patch* parent, SampleRate srate, size_t buffer_size, uint32_t internal_poly) -: NodeBase(new PluginImpl(Plugin::Patch, "ingen:patch"), path, poly, parent, srate, buffer_size), - _engine(engine), - _internal_poly(internal_poly), - _compiled_patch(NULL), - _process(false) -{ - assert(internal_poly >= 1); - - //_plugin->plug_label("om_patch"); - //_plugin->name("Ingen Patch"); - - //std::cerr << "Creating patch " << _name << ", poly = " << poly - // << ", internal poly = " << internal_poly << std::endl; -} - - -Patch::~Patch() -{ - assert(!_activated); - - for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) { - (*i).reset(); - delete _connections.erase(i); - } - - for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) { - assert(!(*i)->activated()); - delete (*i); - delete _nodes.erase(i); - } - - delete _compiled_patch; -} - - -void -Patch::activate() -{ - NodeBase::activate(); - - for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) - (*i)->activate(); - - assert(_activated); -} - - -void -Patch::deactivate() -{ - if (_activated) { - - NodeBase::deactivate(); - - for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) { - if ((*i)->activated()) - (*i)->deactivate(); - assert(!(*i)->activated()); - } - } - assert(!_activated); -} - - -void -Patch::disable() -{ - _process = false; - - for (List<PortImpl*>::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i) - (*i)->clear_buffers(); -} - - -bool -Patch::prepare_internal_poly(uint32_t poly) -{ - /* TODO: ports? internal/external poly? */ - - for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) - (*i)->prepare_poly(poly); - - for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) - ((ConnectionImpl*)i->get())->prepare_poly(poly); - - /* FIXME: Deal with failure */ - - return true; -} - - -bool -Patch::apply_internal_poly(Raul::Maid& maid, uint32_t poly) -{ - /* TODO: ports? internal/external poly? */ - - 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) - PtrCast<ConnectionImpl>(*i)->apply_poly(maid, poly); - - _internal_poly = poly; - - return true; -} - - -/** Run the patch for the specified number of frames. - * - * Calls all Nodes in (roughly, if parallel) the order _compiled_patch specifies. - */ -void -Patch::process(ProcessContext& context) -{ - if (_compiled_patch == NULL || _compiled_patch->size() == 0 || !_process) - return; - - NodeBase::pre_process(context); - - /* Run */ - if (_engine.process_slaves().size() > 0) - process_parallel(context); - else - process_single(context); - - NodeBase::post_process(context); -} - - -void -Patch::process_parallel(ProcessContext& context) -{ - size_t n_slaves = _engine.process_slaves().size(); - - CompiledPatch* const cp = _compiled_patch; - - /* Start p-1 slaves */ - - if (n_slaves >= cp->size()) - n_slaves = cp->size()-1; - - if (n_slaves > 0) { - for (size_t i=0; i < cp->size(); ++i) - (*cp)[i].node()->reset_input_ready(); - - for (size_t i=0; i < n_slaves; ++i) - _engine.process_slaves()[i]->whip(cp, i+1, context); - } - - - /* Process ourself until everything is done - * This is analogous to ProcessSlave::_whipped(), but this is the master - * (i.e. what the main Jack process thread calls). Where ProcessSlave - * waits on input, this just skips the node and tries the next, to avoid - * waiting in the Jack thread which pisses Jack off. - */ - - size_t index = 0; - size_t num_finished = 0; // Number of consecutive finished nodes hit - - while (num_finished < cp->size()) { - - CompiledNode& n = (*cp)[index]; - - if (n.node()->process_lock()) { - if (n.node()->n_inputs_ready() == n.n_providers()) { - n.node()->process(context); - - /* Signal dependants their input is ready */ - for (size_t i=0; i < n.dependants().size(); ++i) - n.dependants()[i]->signal_input_ready(); - - ++num_finished; - } else { - n.node()->process_unlock(); - num_finished = 0; - } - } else { - if (n.node()->n_inputs_ready() == n.n_providers()) - ++num_finished; - else - num_finished = 0; - } - - index = (index + 1) % cp->size(); - } - - /* Tell slaves we're done in case we beat them, and pray they're - * really done by the start of next cycle. - * FIXME: This probably breaks (race) at extremely small nframes where - * ingen is the majority of the DSP load. - */ - for (size_t i=0; i < n_slaves; ++i) - _engine.process_slaves()[i]->finish(); -} - - -void -Patch::process_single(ProcessContext& context) -{ - CompiledPatch* const cp = _compiled_patch; - - for (size_t i=0; i < cp->size(); ++i) - (*cp)[i].node()->process(context); -} - - -void -Patch::set_buffer_size(size_t size) -{ - NodeBase::set_buffer_size(size); - assert(_buffer_size == size); - - for (List<NodeImpl*>::iterator j = _nodes.begin(); j != _nodes.end(); ++j) - (*j)->set_buffer_size(size); -} - - -// Patch specific stuff - - -void -Patch::add_node(List<NodeImpl*>::Node* ln) -{ - assert(ln != NULL); - assert(ln->elem() != NULL); - assert(ln->elem()->parent_patch() == this); - //assert(ln->elem()->polyphony() == _internal_poly); - - _nodes.push_back(ln); -} - - -/** Remove a node. - * Realtime Safe. Preprocessing thread. - */ -Patch::Nodes::Node* -Patch::remove_node(const string& name) -{ - for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) - if ((*i)->name() == name) - return _nodes.erase(i); - - return NULL; -} - - -/** Remove a connection. Realtime safe. - */ -Patch::Connections::Node* -Patch::remove_connection(const PortImpl* src_port, const PortImpl* dst_port) -{ - bool found = false; - Connections::Node* connection = NULL; - for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) { - ConnectionImpl* const c = (ConnectionImpl*)i->get(); - if (c->src_port() == src_port && c->dst_port() == dst_port) { - connection = _connections.erase(i); - found = true; - break; - } - } - - if ( ! found) - cerr << "WARNING: [Patch::remove_connection] Connection not found !" << endl; - - return connection; -} - - -uint32_t -Patch::num_ports() const -{ - ThreadID context = ThreadManager::current_thread_id(); - - if (context == THREAD_PROCESS) - return NodeBase::num_ports(); - else - return _input_ports.size() + _output_ports.size(); -} - - -/** Create a port. Not realtime safe. - */ -PortImpl* -Patch::create_port(const string& name, DataType type, size_t buffer_size, bool is_output) -{ - if (type == DataType::UNKNOWN) { - cerr << "[Patch::create_port] Unknown port type " << type.uri() << endl; - return NULL; - } - - assert( !(type == DataType::UNKNOWN) ); - - return new DuplexPort(this, name, 0, _polyphony, type, buffer_size, is_output); -} - - -/** Remove port from ports list used in pre-processing thread. - * - * Port is not removed from ports array for process thread (which could be - * simultaneously running). - * - * Realtime safe. Preprocessing thread only. - */ -List<PortImpl*>::Node* -Patch::remove_port(const string& name) -{ - assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS); - - bool found = false; - List<PortImpl*>::Node* ret = NULL; - for (List<PortImpl*>::iterator i = _input_ports.begin(); i != _input_ports.end(); ++i) { - if ((*i)->name() == name) { - ret = _input_ports.erase(i); - found = true; - } - } - - if (!found) - for (List<PortImpl*>::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i) { - if ((*i)->name() == name) { - ret = _output_ports.erase(i); - found = true; - } - } - - if ( ! found) - cerr << "WARNING: [Patch::remove_port] Port not found !" << endl; - - return ret; -} - - -Raul::Array<PortImpl*>* -Patch::build_ports_array() const -{ - assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS); - - Raul::Array<PortImpl*>* const result = new Raul::Array<PortImpl*>(_input_ports.size() + _output_ports.size()); - - size_t i = 0; - - for (List<PortImpl*>::const_iterator p = _input_ports.begin(); p != _input_ports.end(); ++p,++i) - result->at(i) = *p; - - for (List<PortImpl*>::const_iterator p = _output_ports.begin(); p != _output_ports.end(); ++p,++i) - result->at(i) = *p; - - return result; -} - - -/** Find the process order for this Patch. - * - * The process order is a flat list that the patch will execute in order - * when it's run() method is called. Return value is a newly allocated list - * which the caller is reponsible to delete. Note that this function does - * NOT actually set the process order, it is returned so it can be inserted - * at the beginning of an audio cycle (by various Events). - * - * Not realtime safe. - */ -CompiledPatch* -Patch::compile() const -{ - assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS); - - //cerr << "*********** Building process order for " << path() << endl; - - CompiledPatch* const compiled_patch = new CompiledPatch();//_nodes.size()); - - for (Nodes::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i) - (*i)->traversed(false); - - for (Nodes::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i) { - NodeImpl* const node = (*i); - // Either a sink or connected to our output ports: - if ( ( ! node->traversed()) && node->dependants()->size() == 0) - compile_recursive(node, compiled_patch); - } - - // Traverse any nodes we didn't hit yet - for (Nodes::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i) { - NodeImpl* const node = (*i); - if ( ! node->traversed()) - compile_recursive(node, compiled_patch); - } - - /*cerr << "----------------------------------------\n"; - for (size_t i=0; i < process_order->size(); ++i) { - assert(process_order->at(i)); - cerr << process_order->at(i)->path() << endl; - } - cerr << "----------------------------------------\n";*/ - - assert(compiled_patch->size() == _nodes.size()); - -#ifndef NDEBUG - for (size_t i=0; i < compiled_patch->size(); ++i) - assert(compiled_patch->at(i).node()); -#endif - - return compiled_patch; -} - - -} // namespace Ingen |