diff options
author | David Robillard <d@drobilla.net> | 2012-08-18 23:05:06 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2012-08-18 23:05:06 +0000 |
commit | 317627ef40f7654c298aa1ac707851c852259e3a (patch) | |
tree | 38f7ed57aafb7b3b8e21e6caa3429a39207e4a9a /src/server/LV2Node.cpp | |
parent | 160b2baf7df8b960f22619c013b3197c0dc51c2b (diff) | |
download | ingen-317627ef40f7654c298aa1ac707851c852259e3a.tar.gz ingen-317627ef40f7654c298aa1ac707851c852259e3a.tar.bz2 ingen-317627ef40f7654c298aa1ac707851c852259e3a.zip |
Node => Block
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4720 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/server/LV2Node.cpp')
-rw-r--r-- | src/server/LV2Node.cpp | 469 |
1 files changed, 0 insertions, 469 deletions
diff --git a/src/server/LV2Node.cpp b/src/server/LV2Node.cpp deleted file mode 100644 index 654aeab0..00000000 --- a/src/server/LV2Node.cpp +++ /dev/null @@ -1,469 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard <http://drobilla.net/> - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or 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 Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <stdint.h> - -#include <cassert> -#include <cmath> - -#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h" -#include "lv2/lv2plug.in/ns/ext/morph/morph.h" - -#include "raul/Maid.hpp" -#include "raul/Array.hpp" - -#include "ingen/Log.hpp" -#include "ingen/URIMap.hpp" -#include "ingen/URIs.hpp" - -#include "Buffer.hpp" -#include "Driver.hpp" -#include "Engine.hpp" -#include "InputPort.hpp" -#include "LV2Node.hpp" -#include "LV2Plugin.hpp" -#include "OutputPort.hpp" -#include "PatchImpl.hpp" -#include "ProcessContext.hpp" - -using namespace std; - -namespace Ingen { -namespace Server { - -/** Partially construct a LV2Node. - * - * Object is not usable until instantiate() is called with success. - * (It _will_ crash!) - */ -LV2Node::LV2Node(LV2Plugin* plugin, - const Raul::Symbol& symbol, - bool polyphonic, - PatchImpl* parent, - SampleRate srate) - : NodeImpl(plugin, symbol, polyphonic, parent, srate) - , _lv2_plugin(plugin) - , _instances(NULL) - , _prepared_instances(NULL) - , _worker_iface(NULL) -{ - assert(_lv2_plugin); -} - -LV2Node::~LV2Node() -{ - delete _instances; -} - -SharedPtr<LilvInstance> -LV2Node::make_instance(URIs& uris, - SampleRate rate, - uint32_t voice, - bool preparing) -{ - LilvInstance* inst = lilv_plugin_instantiate( - _lv2_plugin->lilv_plugin(), rate, _features->array()); - - if (!inst) { - parent_patch()->engine().log().error( - Raul::fmt("Failed to instantiate <%1%>\n") - % _lv2_plugin->uri().c_str()); - return SharedPtr<LilvInstance>(); - } - - const LV2_Morph_Interface* morph_iface = (const LV2_Morph_Interface*) - lilv_instance_get_extension_data(inst, LV2_MORPH__interface); - - for (uint32_t p = 0; p < num_ports(); ++p) { - PortImpl* const port = _ports->at(p); - Buffer* const buffer = (preparing) - ? port->prepared_buffer(voice).get() - : port->buffer(voice).get(); - if (port->is_morph() && port->is_a(PortType::CV)) { - if (morph_iface) { - morph_iface->morph_port( - inst->lv2_handle, p, uris.lv2_CVPort, NULL); - } - } - - if (buffer) { - if (port->is_a(PortType::CV) || port->is_a(PortType::CONTROL)) { - buffer->set_block(port->value().get_float(), 0, buffer->nframes()); - } else { - buffer->clear(); - } - } - } - - if (morph_iface) { - for (uint32_t p = 0; p < num_ports(); ++p) { - PortImpl* const port = _ports->at(p); - if (port->is_auto_morph()) { - LV2_URID type = morph_iface->port_type( - inst->lv2_handle, p, NULL); - if (type == _uris.lv2_ControlPort) { - port->set_type(PortType::CONTROL, 0); - } else if (type == _uris.lv2_CVPort) { - port->set_type(PortType::CV, 0); - } else { - parent_patch()->engine().log().error( - Raul::fmt("%1% auto-morphed to unknown type %2%\n") - % port->path().c_str() % type); - return SharedPtr<LilvInstance>(); - } - } - } - } - - return SharedPtr<LilvInstance>(inst, lilv_instance_free); -} - -bool -LV2Node::prepare_poly(BufferFactory& bufs, uint32_t poly) -{ - if (!_polyphonic) - poly = 1; - - NodeImpl::prepare_poly(bufs, poly); - - if (_polyphony == poly) - return true; - - const SampleRate rate = bufs.engine().driver()->sample_rate(); - assert(!_prepared_instances); - _prepared_instances = new Instances(poly, *_instances, SharedPtr<void>()); - for (uint32_t i = _polyphony; i < _prepared_instances->size(); ++i) { - SharedPtr<LilvInstance> inst = make_instance(bufs.uris(), rate, i, true); - if (!inst) { - return false; - } - - _prepared_instances->at(i) = inst; - - if (_activated) { - lilv_instance_activate(inst.get()); - } - } - - return true; -} - -bool -LV2Node::apply_poly(ProcessContext& context, Raul::Maid& maid, uint32_t poly) -{ - if (!_polyphonic) - poly = 1; - - if (_prepared_instances) { - maid.dispose(_instances); - _instances = _prepared_instances; - _prepared_instances = NULL; - } - assert(poly <= _instances->size()); - - return NodeImpl::apply_poly(context, maid, poly); -} - -/** Instantiate self from LV2 plugin descriptor. - * - * Implemented as a seperate function (rather than in the constructor) to - * allow graceful error-catching of broken plugins. - * - * Returns whether or not plugin was successfully instantiated. If return - * value is false, this object may not be used. - */ -bool -LV2Node::instantiate(BufferFactory& bufs) -{ - const Ingen::URIs& uris = bufs.uris(); - SharedPtr<LV2Info> info = _lv2_plugin->lv2_info(); - const LilvPlugin* plug = _lv2_plugin->lilv_plugin(); - Ingen::Forge& forge = bufs.forge(); - const uint32_t num_ports = lilv_plugin_get_num_ports(plug); - - _ports = new Raul::Array<PortImpl*>(num_ports, NULL); - - bool ret = true; - - float* min_values = new float[num_ports]; - float* max_values = new float[num_ports]; - float* def_values = new float[num_ports]; - lilv_plugin_get_port_ranges_float(plug, min_values, max_values, def_values); - - // Get all the necessary information about ports - for (uint32_t j = 0; j < num_ports; ++j) { - const LilvPort* id = lilv_plugin_get_port_by_index(plug, j); - - /* LV2 port symbols are guaranteed to be unique, valid C identifiers, - and Lilv guarantees that lilv_port_get_symbol() is valid. */ - const Raul::Symbol port_sym( - lilv_node_as_string(lilv_port_get_symbol(plug, id))); - - // Get port type - Raul::Atom val; - PortType port_type = PortType::UNKNOWN; - LV2_URID buffer_type = 0; - bool is_morph = false; - bool is_auto_morph = false; - if (lilv_port_is_a(plug, id, info->lv2_ControlPort)) { - if (lilv_port_is_a(plug, id, info->morph_MorphPort)) { - is_morph = true; - LilvNodes* types = lilv_port_get_value( - plug, id, info->morph_supportsType); - LILV_FOREACH(nodes, i, types) { - const LilvNode* type = lilv_nodes_get(types, i); - if (lilv_node_equals(type, info->lv2_CVPort)) { - port_type = PortType::CV; - buffer_type = uris.atom_Sound; - } - } - lilv_nodes_free(types); - } - if (port_type == PortType::UNKNOWN) { - port_type = PortType::CONTROL; - buffer_type = uris.atom_Float; - } - } else if (lilv_port_is_a(plug, id, info->lv2_CVPort)) { - port_type = PortType::CV; - buffer_type = uris.atom_Sound; - } else if (lilv_port_is_a(plug, id, info->lv2_AudioPort)) { - port_type = PortType::AUDIO; - buffer_type = uris.atom_Sound; - } else if (lilv_port_is_a(plug, id, info->atom_AtomPort)) { - port_type = PortType::ATOM; - } - - if (lilv_port_is_a(plug, id, info->morph_AutoMorphPort)) { - is_auto_morph = true; - } - - // Get buffer type if necessary (atom ports) - if (!buffer_type) { - LilvNodes* types = lilv_port_get_value( - plug, id, info->atom_bufferType); - LILV_FOREACH(nodes, i, types) { - const LilvNode* type = lilv_nodes_get(types, i); - if (lilv_node_is_uri(type)) { - buffer_type = bufs.engine().world()->uri_map().map_uri( - lilv_node_as_uri(type)); - } - } - lilv_nodes_free(types); - } - - uint32_t port_buffer_size = bufs.default_size(buffer_type); - - if (port_type == PortType::ATOM) { - // Get default value, and its length - LilvNodes* defaults = lilv_port_get_value(plug, id, info->lv2_default); - LILV_FOREACH(nodes, i, defaults) { - const LilvNode* d = lilv_nodes_get(defaults, i); - if (lilv_node_is_string(d)) { - const char* str_val = lilv_node_as_string(d); - const uint32_t str_val_len = strlen(str_val); - val = forge.alloc(str_val); - port_buffer_size = std::max(port_buffer_size, str_val_len); - } - } - lilv_nodes_free(defaults); - - // Get minimum size, if set in data - LilvNodes* sizes = lilv_port_get_value(plug, id, info->rsz_minimumSize); - LILV_FOREACH(nodes, i, sizes) { - const LilvNode* d = lilv_nodes_get(sizes, i); - if (lilv_node_is_int(d)) { - uint32_t size_val = lilv_node_as_int(d); - port_buffer_size = std::max(port_buffer_size, size_val); - } - } - lilv_nodes_free(sizes); - - bufs.engine().log().info( - Raul::fmt("Atom port %1% buffer size %2%\n") - % path().c_str() % port_buffer_size); - } - - enum { UNKNOWN, INPUT, OUTPUT } direction = UNKNOWN; - if (lilv_port_is_a(plug, id, info->lv2_InputPort)) { - direction = INPUT; - } else if (lilv_port_is_a(plug, id, info->lv2_OutputPort)) { - direction = OUTPUT; - } - - if (port_type == PortType::UNKNOWN || direction == UNKNOWN) { - parent_patch()->engine().log().error( - Raul::fmt("<%1%> port %2% has unknown type or direction\n") - % _lv2_plugin->uri().c_str() % port_sym.c_str()); - ret = false; - break; - } - - if (!val.type()) - val = forge.make(isnan(def_values[j]) ? 0.0f : def_values[j]); - - PortImpl* port = (direction == INPUT) - ? static_cast<PortImpl*>( - new InputPort(bufs, this, port_sym, j, _polyphony, - port_type, buffer_type, val)) - : static_cast<PortImpl*>( - new OutputPort(bufs, this, port_sym, j, _polyphony, - port_type, buffer_type, val)); - - port->set_morphable(is_morph, is_auto_morph); - if (direction == INPUT && (port_type == PortType::CONTROL - || port_type == PortType::CV)) { - port->set_value(val); - if (!isnan(min_values[j])) { - port->set_property(uris.lv2_minimum, forge.make(min_values[j])); - port->set_minimum(forge.make(min_values[j])); - } - if (!isnan(max_values[j])) { - port->set_property(uris.lv2_maximum, forge.make(max_values[j])); - port->set_maximum(forge.make(max_values[j])); - } - } - - // Inherit certain properties from plugin port - LilvNode* preds[] = { info->lv2_portProperty, info->atom_supports, 0 }; - for (int p = 0; preds[p]; ++p) { - LilvNodes* values = lilv_port_get_value(plug, id, preds[p]); - LILV_FOREACH(nodes, v, values) { - const LilvNode* val = lilv_nodes_get(values, v); - if (lilv_node_is_uri(val)) { - port->add_property(Raul::URI(lilv_node_as_uri(preds[p])), - forge.alloc_uri(lilv_node_as_uri(val))); - } - } - lilv_nodes_free(values); - } - - port->cache_properties(); - - _ports->at(j) = port; - } - - delete[] min_values; - delete[] max_values; - delete[] def_values; - - if (!ret) { - delete _ports; - _ports = NULL; - return ret; - } - - _features = info->world().lv2_features().lv2_features(&info->world(), this); - - // Actually create plugin instances and port buffers. - const SampleRate rate = bufs.engine().driver()->sample_rate(); - _instances = new Instances(_polyphony, SharedPtr<void>()); - for (uint32_t i = 0; i < _polyphony; ++i) { - _instances->at(i) = make_instance(bufs.uris(), rate, i, false); - if (!_instances->at(i)) { - return false; - } - } - - // FIXME: Polyphony + worker? - if (lilv_plugin_has_feature(plug, info->work_schedule)) { - _worker_iface = (const LV2_Worker_Interface*) - lilv_instance_get_extension_data(instance(0), - LV2_WORKER__interface); - } - - return ret; -} - -void -LV2Node::activate(BufferFactory& bufs) -{ - NodeImpl::activate(bufs); - - for (uint32_t i = 0; i < _polyphony; ++i) - lilv_instance_activate(instance(i)); -} - -void -LV2Node::deactivate() -{ - NodeImpl::deactivate(); - - for (uint32_t i = 0; i < _polyphony; ++i) - lilv_instance_deactivate(instance(i)); -} - -LV2_Worker_Status -LV2Node::work_respond(LV2_Worker_Respond_Handle handle, - uint32_t size, - const void* data) -{ - LV2Node* node = (LV2Node*)handle; - LV2Node::Response* r = new LV2Node::Response(size, data); - node->_responses.push_back(*r); - return LV2_WORKER_SUCCESS; -} - -void -LV2Node::work(uint32_t size, const void* data) -{ - if (_worker_iface) { - LV2_Handle inst = lilv_instance_get_handle(instance(0)); - if (_worker_iface->work(inst, work_respond, this, size, data)) { - parent_patch()->engine().log().error( - Raul::fmt("Error calling %1% work method\n") % _path); - } - } -} - -void -LV2Node::process(ProcessContext& context) -{ - NodeImpl::pre_process(context); - - for (uint32_t i = 0; i < _polyphony; ++i) - lilv_instance_run(instance(i), context.nframes()); - - if (_worker_iface) { - LV2_Handle inst = lilv_instance_get_handle(instance(0)); - while (!_responses.empty()) { - Response& r = _responses.front(); - _worker_iface->work_response(inst, r.size, r.data); - _responses.pop_front(); - context.engine().maid()->dispose(&r); - } - - if (_worker_iface->end_run) { - _worker_iface->end_run(inst); - } - } - - NodeImpl::post_process(context); -} - -void -LV2Node::set_port_buffer(uint32_t voice, - uint32_t port_num, - BufferRef buf) -{ - NodeImpl::set_port_buffer(voice, port_num, buf); - lilv_instance_connect_port( - instance(voice), port_num, - buf ? buf->port_data(_ports->at(port_num)->type()) : NULL); -} - -} // namespace Server -} // namespace Ingen - |