diff options
-rw-r--r-- | src/engine/NodeImpl.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/engine/NodeImpl.cpp b/src/engine/NodeImpl.cpp new file mode 100644 index 00000000..332b69b2 --- /dev/null +++ b/src/engine/NodeImpl.cpp @@ -0,0 +1,281 @@ +/* This file is part of Ingen. + * Copyright (C) 2007-2009 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 <stdint.h> +#include "contexts.lv2/contexts.h" +#include "raul/List.hpp" +#include "raul/Array.hpp" +#include "util.hpp" +#include "AudioBuffer.hpp" +#include "ClientBroadcaster.hpp" +#include "EngineStore.hpp" +#include "NodeImpl.hpp" +#include "PatchImpl.hpp" +#include "PluginImpl.hpp" +#include "PortImpl.hpp" +#include "ThreadManager.hpp" + +using namespace std; + +namespace Ingen { + + +NodeImpl::NodeImpl(PluginImpl* plugin, const Raul::Symbol& symbol, bool polyphonic, PatchImpl* parent, SampleRate srate) + : GraphObjectImpl(parent, symbol) + , _plugin(plugin) + , _polyphonic(polyphonic) + , _polyphony((polyphonic && parent) ? parent->internal_poly() : 1) + , _srate(srate) + , _valid_ports(NULL) + , _input_ready(1) + , _process_lock(0) + , _n_inputs_ready(0) + , _ports(NULL) + , _providers(new Raul::List<NodeImpl*>()) + , _dependants(new Raul::List<NodeImpl*>()) + , _activated(false) + , _traversed(false) +{ + assert(_plugin); + assert(_polyphony > 0); + assert(_parent == NULL || (_polyphony == parent->internal_poly() || _polyphony == 1)); +} + + +NodeImpl::~NodeImpl() +{ + if (_activated) + deactivate(); + + delete _providers; + delete _dependants; + delete _ports; + + free(_valid_ports); +} + + +Shared::Port* +NodeImpl::port(uint32_t index) const +{ + return (*_ports)[index]; +} + + +const Shared::Plugin* +NodeImpl::plugin() const +{ + return _plugin; +} + + +void +NodeImpl::activate(BufferFactory& bufs) +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + assert(!_activated); + _activated = true; + + for (unsigned long p = 0; p < num_ports(); ++p) { + PortImpl* const port = _ports->at(p); + port->setup_buffers(bufs, port->poly()); + port->connect_buffers(); + for (uint32_t v = 0; v < _polyphony; ++v) { + if (!port->buffer(v)) + continue; + if (port->is_a(PortType::CONTROL)) + ((AudioBuffer*)port->buffer(v).get())->set_value(port->value().get_float(), 0, 0); + else + port->buffer(v)->clear(); + } + } +} + + +void +NodeImpl::deactivate() +{ + assert(_activated); + _activated = false; + for (uint32_t i = 0; i < _polyphony; ++i) { + for (unsigned long j = 0; j < num_ports(); ++j) { + PortImpl* const port = _ports->at(j); + if (port->is_output() && port->buffer(i)) + port->buffer(i)->clear(); + } + } +} + + +bool +NodeImpl::prepare_poly(BufferFactory& bufs, uint32_t poly) +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + + if (!_polyphonic) + poly = 1; + + for (size_t i = 0; i < _ports->size(); ++i) + _ports->at(i)->prepare_poly(bufs, poly); + + return true; +} + + +bool +NodeImpl::apply_poly(Raul::Maid& maid, uint32_t poly) +{ + ThreadManager::assert_thread(THREAD_PROCESS); + + if (!_polyphonic) + poly = 1; + + _polyphony = poly; + + for (size_t i = 0; i < num_ports(); ++i) + _ports->at(i)->apply_poly(maid, poly); + + return true; +} + + +void +NodeImpl::set_buffer_size(Context& context, BufferFactory& bufs, PortType type, size_t size) +{ + if (_ports) + for (size_t i = 0; i < _ports->size(); ++i) + if (_ports->at(i)->buffer_type() == type && _ports->at(i)->context() == context.id()) + _ports->at(i)->set_buffer_size(context, bufs, size); +} + + +void +NodeImpl::reset_input_ready() +{ + _n_inputs_ready = 0; + _process_lock = 0; + _input_ready.reset(0); +} + + +bool +NodeImpl::process_lock() +{ + return _process_lock.compare_and_exchange(0, 1); +} + + +void +NodeImpl::process_unlock() +{ + _process_lock = 0; +} + + +void +NodeImpl::wait_for_input(size_t num_providers) +{ + ThreadManager::assert_thread(THREAD_PROCESS); + assert(_process_lock.get() == 1); + + while ((unsigned)_n_inputs_ready.get() < num_providers) + _input_ready.wait(); +} + + +void +NodeImpl::signal_input_ready() +{ + ThreadManager::assert_thread(THREAD_PROCESS); + ++_n_inputs_ready; + _input_ready.post(); +} + + +/** Prepare to run a cycle (in the audio thread) + */ +void +NodeImpl::pre_process(Context& context) +{ + ThreadManager::assert_thread(THREAD_PROCESS); + + // Mix down input ports + for (uint32_t i = 0; i < num_ports(); ++i) { + PortImpl* const port = _ports->at(i); + if (port->context() == Context::AUDIO) { + port->pre_process(context); + port->connect_buffers(context.offset()); + } + } +} + + +/** Prepare to run a cycle (in the audio thread) + */ +void +NodeImpl::post_process(Context& context) +{ + ThreadManager::assert_thread(THREAD_PROCESS); + + // Write output ports + for (size_t i = 0; _ports && i < _ports->size(); ++i) { + PortImpl* const port = _ports->at(i); + if (port->context() == Context::AUDIO) + _ports->at(i)->post_process(context); + } +} + + +/** Flag a port as set (for message context) + */ +void +NodeImpl::set_port_valid(uint32_t port_index) +{ + // Allocate enough space for one bit per port + if (!_valid_ports) + _valid_ports = calloc(num_ports() / 8, 1); + lv2_contexts_set_port_valid(_valid_ports, port_index); +} + + +void* +NodeImpl::valid_ports() +{ + return _valid_ports; +} + + +void +NodeImpl::reset_valid_ports() +{ + if (_valid_ports) + memset(_valid_ports, '\0', num_ports() / 8); +} + + +void +NodeImpl::set_port_buffer(uint32_t voice, uint32_t port_num, + BufferFactory::Ref buf, SampleCount offset) +{ + /*std::cout << path() << " set port " << port_num << " voice " << voice + << " buffer " << buf << " offset " << offset << std::endl;*/ +} + + +} // namespace Ingen + |