From 0f9c8151d5b42b243a499bb31a1e1f0b2e8c5f6f Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 8 Feb 2015 07:02:59 +0000 Subject: Server-side copy paste with LV2 state support. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5541 a436a847-0d15-0410-975c-d299462d15a1 --- src/server/events/CreateBlock.cpp | 93 +++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 42 deletions(-) (limited to 'src/server/events/CreateBlock.cpp') diff --git a/src/server/events/CreateBlock.cpp b/src/server/events/CreateBlock.cpp index 1e1e2228..e14a3356 100644 --- a/src/server/events/CreateBlock.cpp +++ b/src/server/events/CreateBlock.cpp @@ -23,6 +23,7 @@ #include "BlockImpl.hpp" #include "Broadcaster.hpp" #include "CreateBlock.hpp" +#include "Driver.hpp" #include "Engine.hpp" #include "GraphImpl.hpp" #include "PluginImpl.hpp" @@ -54,58 +55,72 @@ CreateBlock::~CreateBlock() bool CreateBlock::pre_process() { - Ingen::URIs& uris = _engine.world()->uris(); - typedef Resource::Properties::const_iterator iterator; + const Ingen::URIs& uris = _engine.world()->uris(); + const SPtr store = _engine.store(); + + // Check sanity of target path if (_path.is_root()) { return Event::pre_process_done(Status::BAD_URI, _path); + } else if (store->get(_path)) { + return Event::pre_process_done(Status::EXISTS, _path); + } else if (!(_graph = dynamic_cast(store->get(_path.parent())))) { + return Event::pre_process_done(Status::PARENT_NOT_FOUND, _path.parent()); } - std::string plugin_uri_str; + // Get prototype URI const iterator t = _properties.find(uris.ingen_prototype); - if (t != _properties.end() && t->second.type() == uris.forge.URI) { - plugin_uri_str = t->second.ptr(); - } else { + if (t == _properties.end() || t->second.type() != uris.forge.URI) { return Event::pre_process_done(Status::BAD_REQUEST); } - if (_engine.store()->get(_path)) { - return Event::pre_process_done(Status::EXISTS, _path); - } - - _graph = dynamic_cast(_engine.store()->get(_path.parent())); - if (!_graph) { - return Event::pre_process_done(Status::PARENT_NOT_FOUND, _path.parent()); - } - - const Raul::URI plugin_uri(plugin_uri_str); - PluginImpl* plugin = _engine.block_factory()->plugin(plugin_uri); - if (!plugin) { - return Event::pre_process_done(Status::PLUGIN_NOT_FOUND, - Raul::URI(plugin_uri)); - } + const Raul::URI prototype(t->second.ptr()); + + // Find polyphony + const iterator p = _properties.find(uris.ingen_polyphonic); + const bool polyphonic = (p != _properties.end() && + p->second.type() == uris.forge.Bool && + p->second.get()); + + // Find and instantiate/duplicate prototype (plugin/existing node) + if (Node::uri_is_path(prototype)) { + // Prototype is an existing block + BlockImpl* const ancestor = dynamic_cast( + store->get(Node::uri_to_path(prototype))); + if (!ancestor) { + return Event::pre_process_done(Status::PROTOTYPE_NOT_FOUND, prototype); + } else if (!(_block = ancestor->duplicate( + _engine, Raul::Symbol(_path.symbol()), _graph))) { + return Event::pre_process_done(Status::CREATION_FAILED, _path); + } - const iterator p = _properties.find(uris.ingen_polyphonic); - const bool polyphonic = ( - p != _properties.end() && - p->second.type() == _engine.world()->forge().Bool && - p->second.get()); - - if (!(_block = plugin->instantiate(*_engine.buffer_factory(), - Raul::Symbol(_path.symbol()), - polyphonic, - _graph, - _engine))) { - return Event::pre_process_done(Status::CREATION_FAILED, _path); + /* Replace prototype with the ancestor's. This is less informative, + but the client expects an actual LV2 plugin as prototype. */ + _properties.erase(uris.ingen_prototype); + _properties.insert(std::make_pair(uris.ingen_prototype, + uris.forge.alloc_uri(ancestor->plugin()->uri()))); + } else { + // Prototype is a plugin + PluginImpl* const plugin = _engine.block_factory()->plugin(prototype); + if (!plugin) { + return Event::pre_process_done(Status::PROTOTYPE_NOT_FOUND, prototype); + } else if (!(_block = plugin->instantiate(*_engine.buffer_factory(), + Raul::Symbol(_path.symbol()), + polyphonic, + _graph, + _engine))) { + return Event::pre_process_done(Status::CREATION_FAILED, _path); + } } + // Activate block _block->properties().insert(_properties.begin(), _properties.end()); _block->activate(*_engine.buffer_factory()); // Add block to the store and the graph's pre-processor only block list _graph->add_block(*_block); - _engine.store()->add(_block); + store->add(_block); /* Compile graph with new block added for insertion in audio thread TODO: Since the block is not connected at this point, a full compilation @@ -114,11 +129,7 @@ CreateBlock::pre_process() _compiled_graph = _graph->compile(); } - _update.push_back(make_pair(_block->uri(), _block->properties())); - for (uint32_t i = 0; i < _block->num_ports(); ++i) { - const PortImpl* port = _block->port_impl(i); - _update.push_back(std::make_pair(port->uri(), port->properties())); - } + _update.put_block(_block); return Event::pre_process_done(Status::SUCCESS); } @@ -137,9 +148,7 @@ CreateBlock::post_process() { Broadcaster::Transfer t(*_engine.broadcaster()); if (respond() == Status::SUCCESS) { - for (const auto& u : _update) { - _engine.broadcaster()->put(u.first, u.second); - } + _update.send(_engine.broadcaster()); } } -- cgit v1.2.1