diff options
author | David Robillard <d@drobilla.net> | 2012-05-31 02:09:54 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2012-05-31 02:09:54 +0000 |
commit | a62965fa2e16f283680de5580e5bb6307fdf2a01 (patch) | |
tree | 4b5a0ee96e98bcd3abc849db166485d5a54714de /src | |
parent | 227df4d7e475de8ca69c498984ae12e61c3324ec (diff) | |
download | ingen-a62965fa2e16f283680de5580e5bb6307fdf2a01.tar.gz ingen-a62965fa2e16f283680de5580e5bb6307fdf2a01.tar.bz2 ingen-a62965fa2e16f283680de5580e5bb6307fdf2a01.zip |
Implement Control/CV morph ports.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4475 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r-- | src/server/LV2Info.cpp | 4 | ||||
-rw-r--r-- | src/server/LV2Info.hpp | 3 | ||||
-rw-r--r-- | src/server/LV2Node.cpp | 244 | ||||
-rw-r--r-- | src/server/LV2Node.hpp | 3 | ||||
-rw-r--r-- | src/server/PortImpl.cpp | 26 | ||||
-rw-r--r-- | src/server/PortImpl.hpp | 12 |
6 files changed, 195 insertions, 97 deletions
diff --git a/src/server/LV2Info.cpp b/src/server/LV2Info.cpp index 5a9ac556..7f985492 100644 --- a/src/server/LV2Info.cpp +++ b/src/server/LV2Info.cpp @@ -19,6 +19,7 @@ #include <assert.h> #include "lv2/lv2plug.in/ns/ext/atom/atom.h" +#include "lv2/lv2plug.in/ns/ext/morph/morph.h" #include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h" #include "lv2/lv2plug.in/ns/ext/worker/worker.h" @@ -43,6 +44,9 @@ LV2Info::LV2Info(Ingen::Shared::World* world) , lv2_OutputPort(lilv_new_uri(world->lilv_world(), LV2_CORE__OutputPort)) , lv2_default(lilv_new_uri(world->lilv_world(), LV2_CORE__default)) , lv2_portProperty(lilv_new_uri(world->lilv_world(), LV2_CORE__portProperty)) + , morph_AutoMorphPort(lilv_new_uri(world->lilv_world(), LV2_MORPH__AutoMorphPort)) + , morph_MorphPort(lilv_new_uri(world->lilv_world(), LV2_MORPH__MorphPort)) + , morph_supportsType(lilv_new_uri(world->lilv_world(), LV2_MORPH__supportsType)) , rsz_minimumSize(lilv_new_uri(world->lilv_world(), LV2_RESIZE_PORT__minimumSize)) , work_schedule(lilv_new_uri(world->lilv_world(), LV2_WORKER__schedule)) , _world(world) diff --git a/src/server/LV2Info.hpp b/src/server/LV2Info.hpp index 30b43191..f9bc80e3 100644 --- a/src/server/LV2Info.hpp +++ b/src/server/LV2Info.hpp @@ -43,6 +43,9 @@ public: LilvNode* lv2_OutputPort; LilvNode* lv2_default; LilvNode* lv2_portProperty; + LilvNode* morph_AutoMorphPort; + LilvNode* morph_MorphPort; + LilvNode* morph_supportsType; LilvNode* rsz_minimumSize; LilvNode* work_schedule; diff --git a/src/server/LV2Node.cpp b/src/server/LV2Node.cpp index 4a7800f3..fa2f23e0 100644 --- a/src/server/LV2Node.cpp +++ b/src/server/LV2Node.cpp @@ -21,6 +21,7 @@ #include <string> #include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h" +#include "lv2/lv2plug.in/ns/ext/morph/morph.h" #include "raul/log.hpp" #include "raul/Maid.hpp" @@ -66,6 +67,70 @@ LV2Node::~LV2Node() delete _instances; } +SharedPtr<LilvInstance> +LV2Node::make_instance(Shared::URIs& uris, uint32_t voice, bool preparing) +{ + LilvInstance* inst = lilv_plugin_instantiate( + _lv2_plugin->lilv_plugin(), _srate, _features->array()); + + if (!inst) { + Raul::error(Raul::fmt("Failed to instantiate <%1%>\n") + % _lv2_plugin->uri()); + return SharedPtr<LilvInstance>(); + } + + LV2_Morph_Interface* morph_iface = (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)) { + Raul::info(Raul::fmt("Morphing %1% to CV\n") % port->path()); + 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)) { + ((AudioBuffer*)buffer)->set_value( + port->value().get_float(), 0, 0); + } 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); + Raul::info(Raul::fmt("Auto-morphed %1% to control\n") + % port->path()); + } else if (type == _uris.lv2_CVPort) { + port->set_type(PortType::CV, 0); + Raul::info(Raul::fmt("Auto-morphed %1% to CV\n") + % port->path()); + } else { + Raul::error(Raul::fmt("%1% auto-morphed to unknown type %2%\n") + % port->path() % type); + return SharedPtr<LilvInstance>(); + } + } + } + } + + return SharedPtr<LilvInstance>(inst, lilv_instance_free); +} + bool LV2Node::prepare_poly(BufferFactory& bufs, uint32_t poly) { @@ -77,33 +142,19 @@ LV2Node::prepare_poly(BufferFactory& bufs, uint32_t poly) if (_polyphony == poly) return true; + assert(!_prepared_instances); _prepared_instances = new Instances(poly, *_instances, SharedPtr<void>()); for (uint32_t i = _polyphony; i < _prepared_instances->size(); ++i) { - _prepared_instances->at(i) = SharedPtr<void>( - lilv_plugin_instantiate( - _lv2_plugin->lilv_plugin(), _srate, _features->array()), - lilv_instance_free); - - if (!_prepared_instances->at(i)) { - Raul::error << "Failed to instantiate plugin" << endl; + SharedPtr<LilvInstance> inst = make_instance(bufs.uris(), i, true); + if (!inst) { return false; } - // Initialize the values of new ports - for (uint32_t j = 0; j < num_ports(); ++j) { - PortImpl* const port = _ports->at(j); - Buffer* const buffer = port->prepared_buffer(i).get(); - if (buffer) { - if (port->is_a(PortType::CV) || port->is_a(PortType::CONTROL)) { - ((AudioBuffer*)buffer)->set_value(port->value().get_float(), 0, 0); - } else { - buffer->clear(); - } - } - } + _prepared_instances->at(i) = inst; - if (_activated) - lilv_instance_activate((LilvInstance*)(*_prepared_instances)[i].get()); + if (_activated) { + lilv_instance_activate(inst.get()); + } } return true; @@ -136,97 +187,89 @@ LV2Node::apply_poly(ProcessContext& context, Raul::Maid& maid, uint32_t poly) bool LV2Node::instantiate(BufferFactory& bufs) { - const Ingen::Shared::URIs& uris = bufs.uris(); - SharedPtr<LV2Info> info = _lv2_plugin->lv2_info(); - const LilvPlugin* plug = _lv2_plugin->lilv_plugin(); - Ingen::Shared::Forge& forge = bufs.forge(); - - uint32_t num_ports = lilv_plugin_get_num_ports(plug); - assert(num_ports > 0); + const Ingen::Shared::URIs& uris = bufs.uris(); + SharedPtr<LV2Info> info = _lv2_plugin->lv2_info(); + const LilvPlugin* plug = _lv2_plugin->lilv_plugin(); + Ingen::Shared::Forge& forge = bufs.forge(); + const uint32_t num_ports = lilv_plugin_get_num_ports(plug); - _ports = new Raul::Array<PortImpl*>(num_ports, NULL); - _instances = new Instances(_polyphony, SharedPtr<void>()); + _ports = new Raul::Array<PortImpl*>(num_ports, NULL); - _features = info->world().lv2_features().lv2_features(&info->world(), this); - - uint32_t port_buffer_size = 0; - for (uint32_t i = 0; i < _polyphony; ++i) { - (*_instances)[i] = SharedPtr<void>( - lilv_plugin_instantiate(plug, _srate, _features->array()), - lilv_instance_free); - - if (!instance(i)) { - Raul::error << "Failed to instantiate plugin " << _lv2_plugin->uri() - << " voice " << i << endl; - return false; - } - - if (i == 0 && lilv_plugin_has_feature(plug, info->work_schedule)) { - _worker_iface = (LV2_Worker_Interface*) - lilv_instance_get_extension_data(instance(i), - LV2_WORKER__interface); - } - } - - string port_name; - Raul::Path port_path; - - PortImpl* port = NULL; - bool ret = true; + 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 - port_name = lilv_node_as_string(lilv_port_get_symbol(plug, id)); + const std::string port_sym = lilv_node_as_string( + lilv_port_get_symbol(plug, id)); - if (!Raul::Symbol::is_valid(port_name)) { - Raul::error << "Plugin " << _lv2_plugin->uri() << " port " << j - << " has illegal symbol `" << port_name << "'" << endl; + if (!Raul::Symbol::is_valid(port_sym)) { + Raul::error(Raul::fmt("<%1%> port %2% has invalid symbol `%3'\n") + % _lv2_plugin->uri() % j % port_sym); ret = false; break; } - assert(port_name.find('/') == string::npos); - - port_path = path().child(port_name); - + // Get port type Raul::Atom val; - PortType port_type = PortType::UNKNOWN; - LV2_URID buffer_type = 0; + 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)) { - port_type = PortType::CONTROL; - buffer_type = uris.atom_Float; + 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; + port_type = PortType::CV; buffer_type = uris.atom_Sound; } else if (lilv_port_is_a(plug, id, info->lv2_AudioPort)) { - port_type = PortType::AUDIO; + port_type = PortType::AUDIO; buffer_type = uris.atom_Sound; } else if (lilv_port_is_a(plug, id, info->atom_AtomPort)) { port_type = PortType::ATOM; } - // Get buffer type if necessary (value and message ports) + 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); + 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)) { - port->add_property(uris.atom_bufferType, - forge.alloc_uri(lilv_node_as_uri(type))); buffer_type = bufs.engine().world()->uri_map().map_uri( lilv_node_as_uri(type)); } } + lilv_nodes_free(types); } - port_buffer_size = bufs.default_size(buffer_type); + uint32_t port_buffer_size = bufs.default_size(buffer_type); if (port_type == PortType::ATOM) { // Get default value, and its length @@ -240,6 +283,7 @@ LV2Node::instantiate(BufferFactory& bufs) 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); @@ -250,9 +294,10 @@ LV2Node::instantiate(BufferFactory& bufs) port_buffer_size = std::max(port_buffer_size, size_val); } } + lilv_nodes_free(sizes); - Raul::info << "Atom port " << path() << " buffer size " - << port_buffer_size << std::endl; + Raul::info(Raul::fmt("Atom port %1% buffer size %2%\n") + % path() % port_buffer_size); } enum { UNKNOWN, INPUT, OUTPUT } direction = UNKNOWN; @@ -263,7 +308,7 @@ LV2Node::instantiate(BufferFactory& bufs) } if (port_type == PortType::UNKNOWN || direction == UNKNOWN) { - Raul::warn << "Unknown type or direction for port `" << port_name << "'" << endl; + Raul::warn << "Unknown type or direction for port `" << port_sym << "'" << endl; ret = false; break; } @@ -271,12 +316,15 @@ LV2Node::instantiate(BufferFactory& bufs) if (!val.type()) val = forge.make(isnan(def_values[j]) ? 0.0f : def_values[j]); - // TODO: set buffer size when necessary - if (direction == INPUT) - port = new InputPort(bufs, this, port_name, j, _polyphony, port_type, buffer_type, val); - else - port = new OutputPort(bufs, this, port_name, j, _polyphony, port_type, buffer_type, val); + 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); @@ -299,6 +347,7 @@ LV2Node::instantiate(BufferFactory& bufs) forge.alloc_uri(lilv_node_as_uri(p))); } } + lilv_nodes_free(properties); // Set atom:supports properties LilvNodes* types = lilv_port_get_value(plug, id, info->atom_supports); @@ -309,20 +358,39 @@ LV2Node::instantiate(BufferFactory& bufs) forge.alloc_uri(lilv_node_as_uri(type))); } } + lilv_nodes_free(types); _ports->at(j) = port; } + delete[] min_values; + delete[] max_values; + delete[] def_values; + if (!ret) { delete _ports; _ports = NULL; - delete _instances; - _instances = NULL; + return ret; } - delete[] min_values; - delete[] max_values; - delete[] def_values; + _features = info->world().lv2_features().lv2_features(&info->world(), this); + + // Actually create plugin instances and port buffers. + _instances = new Instances(_polyphony, SharedPtr<void>()); + for (uint32_t i = 0; i < _polyphony; ++i) { + _instances->at(i) = make_instance(bufs.uris(), i, false); + if (!_instances->at(i)) { + return false; + } + } + + // FIXME: Polyphony + worker? + if (lilv_plugin_has_feature(plug, info->work_schedule)) { + _worker_iface = (LV2_Worker_Interface*) + lilv_instance_get_extension_data( + (LilvInstance*)(*_prepared_instances)[0].get(), + LV2_WORKER__interface); + } return ret; } diff --git a/src/server/LV2Node.hpp b/src/server/LV2Node.hpp index b0102772..03f8bf43 100644 --- a/src/server/LV2Node.hpp +++ b/src/server/LV2Node.hpp @@ -65,6 +65,9 @@ public: SampleCount offset); protected: + SharedPtr<LilvInstance> make_instance( + Shared::URIs& uris, uint32_t voice, bool preparing); + inline LilvInstance* instance(uint32_t voice) { return (LilvInstance*)(*_instances)[voice].get(); } diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp index ce4a0b5a..2fdca1ed 100644 --- a/src/server/PortImpl.cpp +++ b/src/server/PortImpl.cpp @@ -56,32 +56,40 @@ PortImpl::PortImpl(BufferFactory& bufs, , _prepared_buffers(NULL) , _broadcast(false) , _set_by_user(false) + , _is_morph(false) + , _is_auto_morph(false) { assert(node != NULL); assert(_poly > 0); const Ingen::Shared::URIs& uris = bufs.uris(); - if (_buffer_size == 0) { - _buffer_size = bufs.default_size(buffer_type); - } + set_type(type, buffer_type); + + add_property(uris.atom_bufferType, bufs.forge().make_urid(buffer_type)); + add_property(uris.rdf_type, bufs.forge().alloc_uri(type.uri().str())); + set_property(uris.lv2_index, bufs.forge().make((int32_t)index)); +} - if (_buffer_type == 0) { +void +PortImpl::set_type(PortType port_type, LV2_URID buffer_type) +{ + _type = port_type; + _buffer_type = buffer_type; + if (!_buffer_type) { switch (_type.symbol()) { case PortType::CONTROL: - _buffer_type = uris.atom_Float; + _buffer_type = _bufs.uris().atom_Float; break; case PortType::AUDIO: case PortType::CV: - _buffer_type = uris.atom_Sound; + _buffer_type = _bufs.uris().atom_Sound; break; default: break; } } - - add_property(uris.rdf_type, bufs.forge().alloc_uri(type.uri().str())); - set_property(uris.lv2_index, bufs.forge().make((int32_t)index)); + _buffer_size = _bufs.default_size(_buffer_type); } PortImpl::~PortImpl() diff --git a/src/server/PortImpl.hpp b/src/server/PortImpl.hpp index 0dbb271c..69cd1a96 100644 --- a/src/server/PortImpl.hpp +++ b/src/server/PortImpl.hpp @@ -149,6 +149,16 @@ public: BufferFactory& bufs() const { return _bufs; } + void set_morphable(bool is_morph, bool is_auto_morph) { + _is_morph = is_morph; + _is_auto_morph = is_auto_morph; + } + + void set_type(PortType port_type, LV2_URID buffer_type); + + bool is_morph() const { return _is_morph; } + bool is_auto_morph() const { return _is_auto_morph; } + protected: PortImpl(BufferFactory& bufs, NodeImpl* node, @@ -174,6 +184,8 @@ protected: Raul::Array<BufferRef>* _prepared_buffers; bool _broadcast; bool _set_by_user; + bool _is_morph; + bool _is_auto_morph; }; } // namespace Server |