diff options
62 files changed, 823 insertions, 375 deletions
diff --git a/bundles/ingen.lv2/ingen.ttl b/bundles/ingen.lv2/ingen.ttl index 71124bb8..dd8a37e7 100644 --- a/bundles/ingen.lv2/ingen.ttl +++ b/bundles/ingen.lv2/ingen.ttl @@ -141,3 +141,10 @@ ingen:head rdfs:range ingen:Port ; rdfs:label "head" ; rdfs:comment "The destination/receiving/sink port of this edge" . + +ingen:incidentTo + a owl:ObjectProperty , + owl:FunctionalProperty ; + rdfs:domain ingen:Edge ; + rdfs:label "incident to" ; + rdfs:comment "A special property used to describe any edge incident to a port or node. This is never saved in patch files, but is used in the control protocol to completely disconnect a Node or Port." . diff --git a/ingen/EngineBase.hpp b/ingen/EngineBase.hpp index 5288eafa..caa1cf00 100644 --- a/ingen/EngineBase.hpp +++ b/ingen/EngineBase.hpp @@ -54,6 +54,11 @@ public: virtual void deactivate() = 0; /** + Return true iff events are waiting to be processed. + */ + virtual bool pending_events() = 0; + + /** Process audio for @p sample_count frames. If the return value is non-zero, events have been processed and are diff --git a/ingen/Status.hpp b/ingen/Status.hpp index 79655e3d..c14bfc06 100644 --- a/ingen/Status.hpp +++ b/ingen/Status.hpp @@ -25,6 +25,7 @@ enum Status { BAD_INDEX, BAD_OBJECT_TYPE, + BAD_REQUEST, BAD_VALUE_TYPE, CLIENT_NOT_FOUND, CREATION_FAILED, @@ -33,8 +34,10 @@ enum Status { INTERNAL_ERROR, INVALID_PARENT_PATH, INVALID_POLY, + NOT_DELETABLE, NOT_FOUND, NOT_MOVABLE, + NOT_PREPARED, NO_SPACE, PARENT_DIFFERS, PARENT_NOT_FOUND, @@ -53,6 +56,7 @@ ingen_status_string(Status st) case BAD_INDEX: return "Invalid index"; case BAD_OBJECT_TYPE: return "Invalid object type"; + case BAD_REQUEST: return "Bad request"; case BAD_VALUE_TYPE: return "Invalid value type"; case CLIENT_NOT_FOUND: return "Client not found"; case CREATION_FAILED: return "Creation failed"; @@ -61,13 +65,15 @@ ingen_status_string(Status st) case INTERNAL_ERROR: return "Internal error"; case INVALID_PARENT_PATH: return "Invalid parent path"; case INVALID_POLY: return "Invalid polyphony"; + case NOT_DELETABLE: return "Object not deletable"; case NOT_FOUND: return "Object not found"; case NOT_MOVABLE: return "Object not movable"; + case NOT_PREPARED: return "Not prepared"; case NO_SPACE: return "Insufficient space"; case PARENT_DIFFERS: return "Parent differs"; case PARENT_NOT_FOUND: return "Parent not found"; - case PORT_NOT_FOUND: return "Port not found"; case PLUGIN_NOT_FOUND: return "Plugin not found"; + case PORT_NOT_FOUND: return "Port not found"; case TYPE_MISMATCH: return "Type mismatch"; case UNKNOWN_TYPE: return "Unknown type"; } diff --git a/ingen/shared/AtomReader.hpp b/ingen/shared/AtomReader.hpp index 2887aad1..1386d3ba 100644 --- a/ingen/shared/AtomReader.hpp +++ b/ingen/shared/AtomReader.hpp @@ -38,10 +38,11 @@ public: AtomReader(URIMap& map, URIs& uris, Forge& forge, Interface& iface); ~AtomReader() {} - void write(const LV2_Atom* msg); + bool write(const LV2_Atom* msg); private: void get_atom(const LV2_Atom* in, Raul::Atom& out); + const char* atom_to_uri(const LV2_Atom* atom); void get_props(const LV2_Atom_Object* obj, Ingen::Resource::Properties& props); diff --git a/ingen/shared/AtomSink.hpp b/ingen/shared/AtomSink.hpp index b4694926..f25e6548 100644 --- a/ingen/shared/AtomSink.hpp +++ b/ingen/shared/AtomSink.hpp @@ -28,7 +28,11 @@ namespace Shared { class AtomSink { public: virtual ~AtomSink() {} - virtual void write(const LV2_Atom* msg) = 0; + + /** Write an Atom to the sink. + * @return True on success. + */ + virtual bool write(const LV2_Atom* msg) = 0; }; } // namespace Shared diff --git a/ingen/shared/URIs.hpp b/ingen/shared/URIs.hpp index 7b89c2ba..c1eec103 100644 --- a/ingen/shared/URIs.hpp +++ b/ingen/shared/URIs.hpp @@ -59,6 +59,7 @@ public: const Quark atom_Bool; const Quark atom_Float; const Quark atom_Int; + const Quark atom_Resource; const Quark atom_Sequence; const Quark atom_Sound; const Quark atom_String; @@ -82,6 +83,7 @@ public: const Quark ingen_enabled; const Quark ingen_engine; const Quark ingen_head; + const Quark ingen_incidentTo; const Quark ingen_nil; const Quark ingen_node; const Quark ingen_polyphonic; diff --git a/scripts/ingenish b/scripts/ingenish index 6e73915a..41b26850 100755 --- a/scripts/ingenish +++ b/scripts/ingenish @@ -28,6 +28,7 @@ except: class Client: def __init__(self, uri='unix:///tmp/ingen.sock'): print 'Connecting to server %s' % uri + self.msg_id = 1 if uri.startswith('unix://'): self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.sock.connect(uri[len('unix://'):]) @@ -46,8 +47,14 @@ class Client: else: return msg + def msg_subject(self): + #self.msg_id += 1 + #return '_:msg%d' % self.msg_id + return '[]' + def send(self, msg): self.sock.send(self.msgencode(msg)) + return True #response = self.sock.recv(1024) # if response != self.msgencode('OK'): # print('Error: %s' % response) @@ -57,27 +64,27 @@ class Client: def put(self, path, body): return self.send(''' -[] +%s a patch:Put ; patch:subject <%s> ; patch:body [ %s ] . -''' % (path, body)) +''' % (self.msg_subject(), path, body)) def set(self, path, body): return self.send(''' -[] +%s a patch:Set ; patch:subject <%s> ; patch:body [ %s ] . -''' % (path, body)) +''' % (self.msg_subject(), path, body)) def connect(self, tail, head): return self.send(''' -[] +%s a patch:Put ; patch:subject <%s> ; patch:body [ @@ -85,25 +92,25 @@ class Client: ingen:tail <%s> ; ingen:head <%s> ; ] . -''' % (os.path.commonprefix([tail, head]), tail, head)) +''' % (self.msg_subject(), os.path.commonprefix([tail, head]), tail, head)) def disconnect(self, tail, head): return self.send(''' -[] +%s a patch:Delete ; patch:body [ a ingen:Edge ; ingen:tail <%s> ; ingen:head <%s> ; ] . -''' % (tail, head)) +''' % (self.msg_subject(), tail, head)) def delete(self, path): return self.send(''' -[] +%s a patch:Delete ; patch:subject <%s> . -''' % (path)) +''' % (self.msg_subject(), path)) def print_usage(): print('''Usage: ingenish [OPTION]... [COMMAND [ARGUMENT]...] diff --git a/src/gui/ingen_gui_lv2.cpp b/src/gui/ingen_gui_lv2.cpp index 18f1c970..f7510f62 100644 --- a/src/gui/ingen_gui_lv2.cpp +++ b/src/gui/ingen_gui_lv2.cpp @@ -40,12 +40,13 @@ struct IngenLV2AtomSink : public Ingen::Shared::AtomSink { , _ui_controller(ui_controller) {} - void write(const LV2_Atom* atom) { + bool write(const LV2_Atom* atom) { _ui_write(_ui_controller, 0, lv2_atom_total_size(atom), _uris.atom_eventTransfer, atom); + return true; } Ingen::Shared::URIs& _uris; diff --git a/src/server/Engine.cpp b/src/server/Engine.cpp index 9359bacf..ead11895 100644 --- a/src/server/Engine.cpp +++ b/src/server/Engine.cpp @@ -66,6 +66,7 @@ Engine::Engine(Ingen::Shared::World* a_world) , _message_context(*this) , _process_context(*this) , _quit_flag(false) + , _direct_driver(true) { if (a_world->store()) { SharedPtr<EngineStore> estore = PtrCast<EngineStore>(a_world->store()); @@ -133,10 +134,27 @@ Engine::set_driver(SharedPtr<Driver> driver) _driver = driver; } +SampleCount +Engine::event_time() +{ + const SampleCount start = _direct_driver + ? _process_context.start() + : _driver->frame_time(); + + /* Exactly one cycle latency (some could run ASAP if we get lucky, but not + always, and a slight constant latency is far better than jittery lower + (average) latency */ + return start + _driver->block_length(); +} + static void execute_and_delete_event(ProcessContext& context, Event* ev) { ev->pre_process(); + if (ev->time() < context.start()) { + // Didn't get around to executing in time, oh well... + ev->set_time(context.start()); + } ev->execute(context); ev->post_process(); delete ev; @@ -146,6 +164,7 @@ void Engine::init(double sample_rate, uint32_t block_length) { set_driver(SharedPtr<Driver>(new DirectDriver(sample_rate, block_length))); + _direct_driver = true; } bool @@ -252,6 +271,8 @@ Engine::deactivate() unsigned Engine::run(uint32_t sample_count) { + _process_context.locate(_process_context.end(), sample_count, 0); + // Apply control bindings to input control_bindings()->pre_process( _process_context, _root_patch->port_impl(0)->buffer(0).get()); diff --git a/src/server/Engine.hpp b/src/server/Engine.hpp index edbe33ae..11b7b35b 100644 --- a/src/server/Engine.hpp +++ b/src/server/Engine.hpp @@ -68,6 +68,7 @@ public: virtual void init(double sample_rate, uint32_t block_length); virtual bool activate(); virtual void deactivate(); + virtual bool pending_events(); virtual unsigned run(uint32_t sample_count); virtual void quit(); virtual bool main_iteration(); @@ -77,8 +78,7 @@ public: void set_driver(SharedPtr<Driver> driver); - /** Return true iff any events are pending. */ - bool pending_events(); + SampleCount event_time(); /** Enqueue an event to be processed (non-realtime threads only). */ void enqueue_event(Event* ev); @@ -128,6 +128,7 @@ private: ProcessContext _process_context; bool _quit_flag; + bool _direct_driver; }; } // namespace Server diff --git a/src/server/Event.cpp b/src/server/Event.cpp deleted file mode 100644 index 7063acdb..00000000 --- a/src/server/Event.cpp +++ /dev/null @@ -1,72 +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 "ingen/Interface.hpp" - -#include "Driver.hpp" -#include "Engine.hpp" -#include "Event.hpp" -#include "ProcessContext.hpp" -#include "ThreadManager.hpp" - -/*! \page methods Method Documentation - * - * <p>All changes in Ingen (both engine and client) occur as a result of - * a small set of methods defined in terms of RDF and matching the - * HTTP and WebDAV standards as closely as possible.</p> - */ - -namespace Ingen { -namespace Server { - -void -Event::pre_process() -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - assert(_pre_processed == false); - _pre_processed = true; -} - -void -Event::execute(ProcessContext& context) -{ - assert(_pre_processed); - assert(!_executed); - assert(_time <= context.end()); - - // Didn't get around to executing in time, jitter, oh well... - if (_time < context.start()) - _time = context.start(); - - _executed = true; -} - -void -Event::post_process() -{ - ThreadManager::assert_not_thread(THREAD_PROCESS); -} - -void -Event::respond(Status status) -{ - if (_request_client) { - _request_client->response(_request_id, status); - } -} - -} // namespace Server -} // namespace Ingen diff --git a/src/server/Event.hpp b/src/server/Event.hpp index d47a8e94..6820e8e2 100644 --- a/src/server/Event.hpp +++ b/src/server/Event.hpp @@ -52,20 +52,23 @@ public: virtual ~Event() {} /** Pre-process event before execution (non-realtime). */ - virtual void pre_process(); + virtual bool pre_process() = 0; /** Execute this event in the audio thread (realtime). */ - virtual void execute(ProcessContext& context); + virtual void execute(ProcessContext& context) = 0; /** Post-process event after execution (non-realtime). */ - virtual void post_process(); + virtual void post_process() = 0; /** Return true iff this event has been pre-processed. */ - inline bool is_prepared() const { return _pre_processed; } + inline bool is_prepared() const { return _status != NOT_PREPARED; } /** Return the time stamp of this event. */ inline SampleCount time() const { return _time; } + /** Set the time stamp of this event. */ + inline void set_time(SampleCount time) { _time = time; } + /** Get the next event to be processed after this one. */ Event* next() const { return _next.get(); } @@ -76,7 +79,11 @@ public: Status status() const { return _status; } /** Respond to the originating client. */ - void respond(Status status); + void respond(Status status) { + if (_request_client) { + _request_client->response(_request_id, status); + } + } protected: Event(Engine& engine, Interface* client, int32_t id, FrameTime time) @@ -84,9 +91,7 @@ protected: , _request_client(client) , _request_id(id) , _time(time) - , _status(SUCCESS) - , _pre_processed(false) - , _executed(false) + , _status(NOT_PREPARED) {} /** Constructor for internal events only */ @@ -95,19 +100,20 @@ protected: , _request_client(NULL) , _request_id(-1) , _time(0) - , _status(SUCCESS) - , _pre_processed(false) - , _executed(false) + , _status(NOT_PREPARED) {} + inline bool pre_process_done(Status st) { + _status = st; + return !st; + } + Engine& _engine; Raul::AtomicPtr<Event> _next; Interface* _request_client; int32_t _request_id; FrameTime _time; Status _status; - bool _pre_processed; - bool _executed; }; } // namespace Server diff --git a/src/server/EventWriter.cpp b/src/server/EventWriter.cpp index 6fb682c2..33462c1c 100644 --- a/src/server/EventWriter.cpp +++ b/src/server/EventWriter.cpp @@ -46,12 +46,7 @@ EventWriter::~EventWriter() SampleCount EventWriter::now() const { - /* Exactly one cycle latency (some could run ASAP if we get lucky, but not - always, and a slight constant latency is far better than jittery lower - (average) latency */ - return (_engine.driver()) - ? _engine.driver()->frame_time() + _engine.driver()->block_length() - : 0; + return _engine.event_time(); } void diff --git a/src/server/PreProcessor.cpp b/src/server/PreProcessor.cpp index 013a43dd..9db13fd1 100644 --- a/src/server/PreProcessor.cpp +++ b/src/server/PreProcessor.cpp @@ -83,6 +83,10 @@ PreProcessor::process(ProcessContext& context, PostProcessor& dest, bool limit) Event* last = ev; while (ev && ev->is_prepared() && ev->time() < context.end()) { + if (ev->time() < context.start()) { + // Didn't get around to executing in time, oh well... + ev->set_time(context.start()); + } ev->execute(context); last = ev; ev = (Event*)ev->next(); diff --git a/src/server/events/Connect.cpp b/src/server/events/Connect.cpp index 8fec67f6..64f81e78 100644 --- a/src/server/events/Connect.cpp +++ b/src/server/events/Connect.cpp @@ -55,7 +55,7 @@ Connect::Connect(Engine& engine, , _buffers(NULL) {} -void +bool Connect::pre_process() { Glib::RWLock::ReaderLock rlock(_engine.engine_store()->lock()); @@ -63,39 +63,29 @@ Connect::pre_process() PortImpl* tail = _engine.engine_store()->find_port(_tail_path); PortImpl* head = _engine.engine_store()->find_port(_head_path); if (!tail || !head) { - _status = PORT_NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(PORT_NOT_FOUND); } _dst_input_port = dynamic_cast<InputPort*>(head); _src_output_port = dynamic_cast<OutputPort*>(tail); if (!_dst_input_port || !_src_output_port) { - _status = DIRECTION_MISMATCH; - Event::pre_process(); - return; + return Event::pre_process_done(DIRECTION_MISMATCH); } NodeImpl* const src_node = tail->parent_node(); NodeImpl* const dst_node = head->parent_node(); if (!src_node || !dst_node) { - _status = PARENT_NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(PARENT_NOT_FOUND); } if (src_node->parent() != dst_node->parent() && src_node != dst_node->parent() && src_node->parent() != dst_node) { - _status = PARENT_DIFFERS; - Event::pre_process(); - return; + return Event::pre_process_done(PARENT_DIFFERS); } if (!EdgeImpl::can_connect(_src_output_port, _dst_input_port)) { - _status = TYPE_MISMATCH; - Event::pre_process(); - return; + return Event::pre_process_done(TYPE_MISMATCH); } if (src_node->parent_patch() != dst_node->parent_patch()) { @@ -115,9 +105,7 @@ Connect::pre_process() } if (_patch->has_edge(_src_output_port, _dst_input_port)) { - _status = EXISTS; - Event::pre_process(); - return; + return Event::pre_process_done(EXISTS); } _edge = SharedPtr<EdgeImpl>( @@ -149,14 +137,12 @@ Connect::pre_process() if (_patch->enabled()) _compiled_patch = _patch->compile(); - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } void Connect::execute(ProcessContext& context) { - Event::execute(context); - if (_status == SUCCESS) { // This must be inserted here, since they're actually used by the audio thread _dst_input_port->add_edge(context, _edge.get()); diff --git a/src/server/events/Connect.hpp b/src/server/events/Connect.hpp index f5939386..8a93200f 100644 --- a/src/server/events/Connect.hpp +++ b/src/server/events/Connect.hpp @@ -55,7 +55,7 @@ public: const Raul::Path& tail, const Raul::Path& head); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/events/CreateNode.cpp b/src/server/events/CreateNode.cpp index 4c2d1382..756f937d 100644 --- a/src/server/events/CreateNode.cpp +++ b/src/server/events/CreateNode.cpp @@ -39,43 +39,43 @@ CreateNode::CreateNode(Engine& engine, int32_t id, SampleCount timestamp, const Raul::Path& path, - const Raul::URI& plugin_uri, const Resource::Properties& properties) : Event(engine, client, id, timestamp) , _path(path) - , _plugin_uri(plugin_uri) , _properties(properties) , _patch(NULL) , _node(NULL) , _compiled_patch(NULL) {} -void +bool CreateNode::pre_process() { Ingen::Shared::URIs& uris = _engine.world()->uris(); + typedef Resource::Properties::const_iterator iterator; + + const iterator t = _properties.find(uris.ingen_prototype); + if (t != _properties.end() && t->second.type() == uris.forge.URI) { + _plugin_uri = t->second.get_uri(); + } else { + return Event::pre_process_done(BAD_REQUEST); + } + if (_engine.engine_store()->find_object(_path)) { - _status = EXISTS; - Event::pre_process(); - return; + return Event::pre_process_done(EXISTS); } if (!(_patch = _engine.engine_store()->find_patch(_path.parent()))) { - _status = PARENT_NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(PARENT_NOT_FOUND); } - PluginImpl* plugin = _engine.node_factory()->plugin(_plugin_uri.str()); + PluginImpl* plugin = _engine.node_factory()->plugin(_plugin_uri); if (!plugin) { - _status = PLUGIN_NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(PLUGIN_NOT_FOUND); } - const Resource::Properties::const_iterator p = _properties.find( - _engine.world()->uris().ingen_polyphonic); + const iterator p = _properties.find(uris.ingen_polyphonic); const bool polyphonic = ( p != _properties.end() && p->second.type() == _engine.world()->forge().Bool && @@ -86,9 +86,7 @@ CreateNode::pre_process() polyphonic, _patch, _engine))) { - _status = CREATION_FAILED; - Event::pre_process(); - return; + return Event::pre_process_done(CREATION_FAILED); } _node->properties().insert(_properties.begin(), _properties.end()); @@ -115,14 +113,12 @@ CreateNode::pre_process() _update.push_back(std::make_pair(port->path(), pprops)); } - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } void CreateNode::execute(ProcessContext& context) { - Event::execute(context); - if (_node) { _engine.maid()->push(_patch->compiled_patch()); _patch->compiled_patch(_compiled_patch); @@ -132,10 +128,8 @@ CreateNode::execute(ProcessContext& context) void CreateNode::post_process() { - if (_status) { - respond(_status); - } else { - respond(SUCCESS); + respond(_status); + if (!_status) { for (Update::const_iterator i = _update.begin(); i != _update.end(); ++i) { _engine.broadcaster()->put(i->first, i->second); } diff --git a/src/server/events/CreateNode.hpp b/src/server/events/CreateNode.hpp index 95d504de..90b2b2b6 100644 --- a/src/server/events/CreateNode.hpp +++ b/src/server/events/CreateNode.hpp @@ -45,10 +45,9 @@ public: int32_t id, SampleCount timestamp, const Raul::Path& node_path, - const Raul::URI& plugin_uri, const Resource::Properties& properties); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); @@ -57,7 +56,7 @@ private: typedef std::list< std::pair<Raul::URI, Resource::Properties> > Update; Raul::Path _path; - Raul::URI _plugin_uri; + std::string _plugin_uri; Resource::Properties _properties; Update _update; PatchImpl* _patch; diff --git a/src/server/events/CreatePatch.cpp b/src/server/events/CreatePatch.cpp index 92d7a5e3..575cf11e 100644 --- a/src/server/events/CreatePatch.cpp +++ b/src/server/events/CreatePatch.cpp @@ -36,7 +36,6 @@ CreatePatch::CreatePatch(Engine& engine, int32_t id, SampleCount timestamp, const Raul::Path& path, - int poly, const Resource::Properties& properties) : Event(engine, client, id, timestamp) , _path(path) @@ -44,37 +43,38 @@ CreatePatch::CreatePatch(Engine& engine, , _patch(NULL) , _parent(NULL) , _compiled_patch(NULL) - , _poly(poly) + , _poly(1) { + Ingen::Shared::URIs& uris = _engine.world()->uris(); + typedef Resource::Properties::const_iterator iterator; + iterator p = _properties.find(uris.ingen_polyphony); + if (p != _properties.end() && p->second.type() == uris.forge.Int) { + _poly = p->second.get_int32(); + } } -void +bool CreatePatch::pre_process() { if (_path.is_root() || _engine.engine_store()->find_object(_path) != NULL) { - _status = EXISTS; - Event::pre_process(); - return; + return Event::pre_process_done(EXISTS); } if (_poly < 1) { - _status = INVALID_POLY; - Event::pre_process(); - return; + return Event::pre_process_done(INVALID_POLY); } const Raul::Path& path = (const Raul::Path&)_path; _parent = _engine.engine_store()->find_patch(path.parent()); - if (_parent == NULL) { - _status = PARENT_NOT_FOUND; - Event::pre_process(); - return; + if (!_parent) { + return Event::pre_process_done(PARENT_NOT_FOUND); } uint32_t poly = 1; - if (_parent != NULL && _poly > 1 && _poly == static_cast<int>(_parent->internal_poly())) + if (_poly > 1 && _poly == static_cast<int>(_parent->internal_poly())) { poly = _poly; + } const Ingen::Shared::URIs& uris = _engine.world()->uris(); @@ -85,12 +85,10 @@ CreatePatch::pre_process() _patch->add_property(uris.rdf_type, Resource::Property(uris.ingen_Node, Resource::EXTERNAL)); - if (_parent) { - _parent->add_node(new PatchImpl::Nodes::Node(_patch)); - if (_parent->enabled()) { - _patch->enable(); - _compiled_patch = _parent->compile(); - } + _parent->add_node(new PatchImpl::Nodes::Node(_patch)); + if (_parent->enabled()) { + _patch->enable(); + _compiled_patch = _parent->compile(); } _patch->activate(*_engine.buffer_factory()); @@ -100,14 +98,12 @@ CreatePatch::pre_process() _update = _patch->properties(); - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } void CreatePatch::execute(ProcessContext& context) { - Event::execute(context); - if (_patch) { assert(_parent); assert(!_path.is_root()); diff --git a/src/server/events/CreatePatch.hpp b/src/server/events/CreatePatch.hpp index 0747ec06..95f24641 100644 --- a/src/server/events/CreatePatch.hpp +++ b/src/server/events/CreatePatch.hpp @@ -40,10 +40,9 @@ public: int32_t id, SampleCount timestamp, const Raul::Path& path, - int poly, const Resource::Properties& properties); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp index a783512f..9f061238 100644 --- a/src/server/events/CreatePort.cpp +++ b/src/server/events/CreatePort.cpp @@ -81,30 +81,21 @@ CreatePort::CreatePort(Engine& engine, _buffer_type = _engine.world()->uri_map().map_uri(i->second.get_uri()); } } - - if (_port_type == PortType::UNKNOWN) { - _status = UNKNOWN_TYPE; - } } -void +bool CreatePort::pre_process() { - if (_status) { - Event::pre_process(); - return; + if (_port_type == PortType::UNKNOWN) { + return Event::pre_process_done(UNKNOWN_TYPE); } if (_engine.engine_store()->find_object(_path)) { - _status = EXISTS; - Event::pre_process(); - return; + return Event::pre_process_done(_status); } if (!(_patch = _engine.engine_store()->find_patch(_path.parent()))) { - _status = PARENT_NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(PARENT_NOT_FOUND); } const Ingen::Shared::URIs& uris = _engine.world()->uris(); @@ -124,9 +115,7 @@ CreatePort::pre_process() _engine.world()->forge().make(int32_t(old_num_ports)))); } else if (index_i->second.type() != uris.forge.Int || index_i->second.get_int32() != static_cast<int32_t>(old_num_ports)) { - _status = BAD_INDEX; - Event::pre_process(); - return; + return Event::pre_process_done(BAD_INDEX); } Resource::Properties::const_iterator poly_i = _properties.find(uris.ingen_polyphonic); @@ -137,9 +126,7 @@ CreatePort::pre_process() if (!(_patch_port = _patch->create_port( *_engine.buffer_factory(), _path.symbol(), _port_type, _buffer_type, buffer_size, _is_output, polyphonic))) { - _status = CREATION_FAILED; - Event::pre_process(); - return; + return Event::pre_process_done(CREATION_FAILED); } _patch_port->properties().insert(_properties.begin(), _properties.end()); @@ -168,19 +155,17 @@ CreatePort::pre_process() assert(_ports_array->size() == _patch->num_ports_non_rt()); } else { - _status = CREATION_FAILED; + return Event::pre_process_done(CREATION_FAILED); } _update = _patch_port->properties(); - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } void CreatePort::execute(ProcessContext& context) { - Event::execute(context); - if (_patch_port) { _engine.maid()->push(_patch->external_ports()); _patch->external_ports(_ports_array); diff --git a/src/server/events/CreatePort.hpp b/src/server/events/CreatePort.hpp index 3b40136e..3952b1b7 100644 --- a/src/server/events/CreatePort.hpp +++ b/src/server/events/CreatePort.hpp @@ -49,7 +49,7 @@ public: bool is_output, const Resource::Properties& properties); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/events/Delete.cpp b/src/server/events/Delete.cpp index d54bcab4..5e7dd20e 100644 --- a/src/server/events/Delete.cpp +++ b/src/server/events/Delete.cpp @@ -60,12 +60,11 @@ Delete::~Delete() delete _disconnect_event; } -void +bool Delete::pre_process() { if (_path.is_root() || _path == "path:/control_in" || _path == "path:/control_out") { - Event::pre_process(); - return; + return Event::pre_process_done(NOT_DELETABLE); } _lock.acquire(); @@ -125,14 +124,12 @@ Delete::pre_process() } - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } void Delete::execute(ProcessContext& context) { - Event::execute(context); - PatchImpl* parent_patch = NULL; if (_patch_node_listnode) { diff --git a/src/server/events/Delete.hpp b/src/server/events/Delete.hpp index 2ca24469..4316763f 100644 --- a/src/server/events/Delete.hpp +++ b/src/server/events/Delete.hpp @@ -65,7 +65,7 @@ public: ~Delete(); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/events/Disconnect.cpp b/src/server/events/Disconnect.cpp index e1a86b13..fc6813ea 100644 --- a/src/server/events/Disconnect.cpp +++ b/src/server/events/Disconnect.cpp @@ -111,7 +111,7 @@ Disconnect::Impl::Impl(Engine& e, } } -void +bool Disconnect::pre_process() { Glib::RWLock::WriterLock lock(_engine.engine_store()->lock()); @@ -119,18 +119,14 @@ Disconnect::pre_process() if (_tail_path.parent().parent() != _head_path.parent().parent() && _tail_path.parent() != _head_path.parent().parent() && _tail_path.parent().parent() != _head_path.parent()) { - _status = PARENT_DIFFERS; - Event::pre_process(); - return; + return Event::pre_process_done(PARENT_DIFFERS); } _tail = _engine.engine_store()->find_port(_tail_path); _head = _engine.engine_store()->find_port(_head_path); if (_tail == NULL || _head == NULL) { - _status = PORT_NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(PORT_NOT_FOUND); } NodeImpl* const src_node = _tail->parent_node(); @@ -155,15 +151,11 @@ Disconnect::pre_process() assert(_patch); if (!_patch->has_edge(_tail, _head)) { - _status = NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(NOT_FOUND); } if (src_node == NULL || dst_node == NULL) { - _status = PARENT_NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(PARENT_NOT_FOUND); } _impl = new Impl(_engine, @@ -174,7 +166,7 @@ Disconnect::pre_process() if (_patch->enabled()) _compiled_patch = _patch->compile(); - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } bool @@ -208,8 +200,6 @@ Disconnect::Impl::execute(ProcessContext& context, bool set_dst_buffers) void Disconnect::execute(ProcessContext& context) { - Event::execute(context); - if (_status == SUCCESS) { if (!_impl->execute(context, true)) { _status = NOT_FOUND; diff --git a/src/server/events/Disconnect.hpp b/src/server/events/Disconnect.hpp index fa17e9f4..68356e84 100644 --- a/src/server/events/Disconnect.hpp +++ b/src/server/events/Disconnect.hpp @@ -52,7 +52,7 @@ public: const Raul::Path& tail_path, const Raul::Path& head_path); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/events/DisconnectAll.cpp b/src/server/events/DisconnectAll.cpp index 0a4c2ef1..d9f8b8c1 100644 --- a/src/server/events/DisconnectAll.cpp +++ b/src/server/events/DisconnectAll.cpp @@ -79,7 +79,7 @@ DisconnectAll::~DisconnectAll() delete (*i); } -void +bool DisconnectAll::pre_process() { Glib::RWLock::WriterLock lock(_engine.engine_store()->lock(), Glib::NOT_LOCK); @@ -88,25 +88,18 @@ DisconnectAll::pre_process() lock.acquire(); _parent = _engine.engine_store()->find_patch(_parent_path); - - if (_parent == NULL) { - _status = PARENT_NOT_FOUND; - Event::pre_process(); - return; + if (!_parent) { + return Event::pre_process_done(PARENT_NOT_FOUND); } GraphObjectImpl* object = _engine.engine_store()->find_object(_path); if (!object) { - _status = NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(NOT_FOUND); } if (object->parent_patch() != _parent && object->parent()->parent_patch() != _parent) { - _status = INVALID_PARENT_PATH; - Event::pre_process(); - return; + return Event::pre_process_done(INVALID_PARENT_PATH); } // Only one of these will succeed @@ -146,14 +139,12 @@ DisconnectAll::pre_process() if (!_deleting && _parent->enabled()) _compiled_patch = _parent->compile(); - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } void DisconnectAll::execute(ProcessContext& context) { - Event::execute(context); - if (_status == SUCCESS) { for (Impls::iterator i = _impls.begin(); i != _impls.end(); ++i) { (*i)->execute(context, diff --git a/src/server/events/DisconnectAll.hpp b/src/server/events/DisconnectAll.hpp index 9006fd9d..1446d962 100644 --- a/src/server/events/DisconnectAll.hpp +++ b/src/server/events/DisconnectAll.hpp @@ -56,7 +56,7 @@ public: ~DisconnectAll(); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/events/Get.cpp b/src/server/events/Get.cpp index 80fc34e8..6e0aafda 100644 --- a/src/server/events/Get.cpp +++ b/src/server/events/Get.cpp @@ -48,20 +48,21 @@ Get::Get(Engine& engine, { } -void +bool Get::pre_process() { _lock.acquire(); if (_uri == "ingen:plugins") { _plugins = _engine.node_factory()->plugins(); + return Event::pre_process_done(SUCCESS); } else if (Raul::Path::is_valid(_uri.str())) { _object = _engine.engine_store()->find_object(Raul::Path(_uri.str())); + return Event::pre_process_done(_object ? SUCCESS : NOT_FOUND); } else { _plugin = _engine.node_factory()->plugin(_uri); + return Event::pre_process_done(_plugin ? SUCCESS : NOT_FOUND); } - - Event::pre_process(); } static void @@ -84,12 +85,9 @@ send_node(Interface* client, const NodeImpl* node) PluginImpl* const plugin = node->plugin_impl(); if (plugin->type() == Plugin::Patch) { send_patch(client, (PatchImpl*)node); - } else if (plugin->uri().length() == 0) { - Raul::error((Raul::fmt("Node %1%'s plugin has no URI\n") - % node->path())); } else { client->put(node->path(), node->properties()); - for (size_t j=0; j < node->num_ports(); ++j) { + for (size_t j = 0; j < node->num_ports(); ++j) { send_port(client, node->port_impl(j)); } } diff --git a/src/server/events/Get.hpp b/src/server/events/Get.hpp index 146c2b39..f1b5003d 100644 --- a/src/server/events/Get.hpp +++ b/src/server/events/Get.hpp @@ -44,7 +44,8 @@ public: SampleCount timestamp, const Raul::URI& uri); - void pre_process(); + bool pre_process(); + void execute(ProcessContext& context) {} void post_process(); private: diff --git a/src/server/events/Move.cpp b/src/server/events/Move.cpp index 3874fcf1..84deba05 100644 --- a/src/server/events/Move.cpp +++ b/src/server/events/Move.cpp @@ -49,27 +49,22 @@ Move::~Move() { } -void +bool Move::pre_process() { Glib::RWLock::WriterLock lock(_engine.engine_store()->lock()); if (!_old_path.parent().is_parent_of(_new_path)) { - _status = PARENT_DIFFERS; - Event::pre_process(); - return; + return Event::pre_process_done(PARENT_DIFFERS); } + _store_iterator = _engine.engine_store()->find(_old_path); - if (_store_iterator == _engine.engine_store()->end()) { - _status = NOT_FOUND; - Event::pre_process(); - return; + if (_store_iterator == _engine.engine_store()->end()) { + return Event::pre_process_done(NOT_FOUND); } - if (_engine.engine_store()->find_object(_new_path)) { - _status = EXISTS; - Event::pre_process(); - return; + if (_engine.engine_store()->find_object(_new_path)) { + return Event::pre_process_done(EXISTS); } SharedPtr< Raul::Table< Raul::Path, SharedPtr<GraphObject> > > removed @@ -93,14 +88,12 @@ Move::pre_process() _engine.engine_store()->add(*removed.get()); - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } void Move::execute(ProcessContext& context) { - Event::execute(context); - SharedPtr<PortImpl> port = PtrCast<PortImpl>(_store_iterator->second); if (port && port->parent()->parent() == NULL) { EnginePort* eport = _engine.driver()->engine_port(context, _new_path); diff --git a/src/server/events/Move.hpp b/src/server/events/Move.hpp index 1b35e9bd..2e21b190 100644 --- a/src/server/events/Move.hpp +++ b/src/server/events/Move.hpp @@ -53,7 +53,7 @@ public: ~Move(); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/events/SetMetadata.cpp b/src/server/events/SetMetadata.cpp index 26757426..7bd3e7a5 100644 --- a/src/server/events/SetMetadata.cpp +++ b/src/server/events/SetMetadata.cpp @@ -101,7 +101,7 @@ SetMetadata::~SetMetadata() delete _create_event; } -void +bool SetMetadata::pre_process() { typedef Properties::const_iterator iterator; @@ -116,9 +116,7 @@ SetMetadata::pre_process() : static_cast<Shared::ResourceImpl*>(_engine.node_factory()->plugin(_subject)); if (!_object && (!is_graph_object || !_create)) { - _status = NOT_FOUND; - Event::pre_process(); - return; + return Event::pre_process_done(NOT_FOUND); } const Ingen::Shared::URIs& uris = _engine.world()->uris(); @@ -129,19 +127,15 @@ SetMetadata::pre_process() Shared::ResourceImpl::type(uris, _properties, is_patch, is_node, is_port, is_output); if (is_patch) { - uint32_t poly = 1; - iterator p = _properties.find(uris.ingen_polyphony); - if (p != _properties.end() && p->second.is_valid() && p->second.type() == uris.forge.Int) - poly = p->second.get_int32(); - _create_event = new CreatePatch(_engine, _request_client, _request_id, _time, - path, poly, _properties); + _create_event = new CreatePatch( + _engine, _request_client, _request_id, _time, path, _properties); } else if (is_node) { - const iterator p = _properties.find(uris.ingen_prototype); - _create_event = new CreateNode(_engine, _request_client, _request_id, _time, - path, p->second.get_uri(), _properties); + _create_event = new CreateNode( + _engine, _request_client, _request_id, _time, path, _properties); } else if (is_port) { - _create_event = new CreatePort(_engine, _request_client, _request_id, _time, - path, is_output, _properties); + _create_event = new CreatePort( + _engine, _request_client, _request_id, _time, + path, is_output, _properties); } if (_create_event) { _create_event->pre_process(); @@ -177,7 +171,7 @@ SetMetadata::pre_process() _object->remove_property(key, value); } - for (Properties::iterator p = _properties.begin(); p != _properties.end(); ++p) { + for (Properties::const_iterator p = _properties.begin(); p != _properties.end(); ++p) { const Raul::URI& key = p->first; const Resource::Property& value = p->second; SpecialType op = NONE; @@ -252,32 +246,34 @@ SetMetadata::pre_process() } } - if (_status != SUCCESS) { + if (_status != NOT_PREPARED) { break; } _types.push_back(op); } - Event::pre_process(); + return Event::pre_process_done(_status == NOT_PREPARED ? SUCCESS : _status); } void SetMetadata::execute(ProcessContext& context) { - if (_status != SUCCESS) { - Event::execute(context); + if (_status) { return; } const Ingen::Shared::URIs& uris = _engine.world()->uris(); if (_create_event) { + _create_event->set_time(_time); _create_event->execute(context); } - for (SetEvents::iterator i = _set_events.begin(); i != _set_events.end(); ++i) + for (SetEvents::iterator i = _set_events.begin(); i != _set_events.end(); ++i) { + (*i)->set_time(_time); (*i)->execute(context); + } GraphObjectImpl* const object = dynamic_cast<GraphObjectImpl*>(_object); NodeImpl* const node = dynamic_cast<NodeImpl*>(_object); @@ -289,8 +285,9 @@ SetMetadata::execute(ProcessContext& context) const Raul::Atom& value = p->second; switch (*t) { case ENABLE_BROADCAST: - if (port) + if (port) { port->broadcast(value.get_bool()); + } break; case ENABLE: if (value.get_bool()) { @@ -303,15 +300,14 @@ SetMetadata::execute(ProcessContext& context) _patch->disable(context); } break; - case POLYPHONIC: - { - PatchImpl* parent = reinterpret_cast<PatchImpl*>(object->parent()); - if (value.get_bool()) - object->apply_poly(context, *_engine.maid(), parent->internal_poly()); - else - object->apply_poly(context, *_engine.maid(), 1); + case POLYPHONIC: { + PatchImpl* parent = reinterpret_cast<PatchImpl*>(object->parent()); + if (value.get_bool()) { + object->apply_poly(context, *_engine.maid(), parent->internal_poly()); + } else { + object->apply_poly(context, *_engine.maid(), 1); } - break; + } break; case POLYPHONY: if (_patch->internal_poly() != static_cast<uint32_t>(value.get_int32()) && !_patch->apply_internal_poly(context, @@ -340,8 +336,6 @@ SetMetadata::execute(ProcessContext& context) break; } } - - Event::execute(context); } void diff --git a/src/server/events/SetMetadata.hpp b/src/server/events/SetMetadata.hpp index 84957e02..223339da 100644 --- a/src/server/events/SetMetadata.hpp +++ b/src/server/events/SetMetadata.hpp @@ -78,7 +78,7 @@ public: ~SetMetadata(); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/events/SetPortValue.cpp b/src/server/events/SetPortValue.cpp index b4b26ccf..9eb57d55 100644 --- a/src/server/events/SetPortValue.cpp +++ b/src/server/events/SetPortValue.cpp @@ -69,19 +69,20 @@ SetPortValue::~SetPortValue() { } -void +bool SetPortValue::pre_process() { - if (_queued) { - if (_port == NULL) - _port = _engine.engine_store()->find_port(_port_path); - if (_port == NULL) - _status = PORT_NOT_FOUND; + if (_queued && !_port) { + _port = _engine.engine_store()->find_port(_port_path); + } + + if (!_port) { + return Event::pre_process_done(PORT_NOT_FOUND); } // Port is a message context port, set its value and // call the plugin's message run function once - if (_port && _port->parent_node()->context() == Context::MESSAGE) { + if (_port->parent_node()->context() == Context::MESSAGE) { apply(_engine.message_context()); _engine.message_context().run( _engine.message_context(), @@ -89,20 +90,18 @@ SetPortValue::pre_process() _engine.driver()->frame_time() + _engine.driver()->block_length()); } - if (_port) { - _port->set_value(_value); - _port->set_property(_engine.world()->uris().ingen_value, _value); - } + // Set value metadata (does not affect buffers) + _port->set_value(_value); + _port->set_property(_engine.world()->uris().ingen_value, _value); _binding = _engine.control_bindings()->port_binding(_port); - Event::pre_process(); + return Event::pre_process_done(SUCCESS); } void SetPortValue::execute(ProcessContext& context) { - Event::execute(context); assert(_time >= context.start() && _time <= context.end()); if (_port && _port->parent_node()->context() == Context::MESSAGE) diff --git a/src/server/events/SetPortValue.hpp b/src/server/events/SetPortValue.hpp index a6166060..4d97ee99 100644 --- a/src/server/events/SetPortValue.hpp +++ b/src/server/events/SetPortValue.hpp @@ -59,7 +59,7 @@ public: ~SetPortValue(); - void pre_process(); + bool pre_process(); void execute(ProcessContext& context); void post_process(); diff --git a/src/server/ingen_lv2.cpp b/src/server/ingen_lv2.cpp index 2cc12846..c9c6907e 100644 --- a/src/server/ingen_lv2.cpp +++ b/src/server/ingen_lv2.cpp @@ -232,7 +232,7 @@ public: /** AtomSink::write implementation called by the PostProcessor in the main * thread to write responses to the UI. */ - void write(const LV2_Atom* atom) { + bool write(const LV2_Atom* atom) { // Called from post-processor in main thread while (_to_ui.write(lv2_atom_total_size(atom), atom) == 0) { // Overflow, wait until ring is drained next cycle @@ -240,6 +240,7 @@ public: _to_ui_overflow_sem.wait(); _to_ui_overflow = false; } + return true; } void consume_from_ui() { diff --git a/src/server/wscript b/src/server/wscript index 8f505983..c1ea75e9 100644 --- a/src/server/wscript +++ b/src/server/wscript @@ -12,7 +12,6 @@ def build(bld): EdgeImpl.cpp Engine.cpp EngineStore.cpp - Event.cpp EventWriter.cpp GraphObjectImpl.cpp InputPort.cpp diff --git a/src/shared/AtomReader.cpp b/src/shared/AtomReader.cpp index dc2aa15c..c6ff7e18 100644 --- a/src/shared/AtomReader.cpp +++ b/src/shared/AtomReader.cpp @@ -62,53 +62,68 @@ AtomReader::get_props(const LV2_Atom_Object* obj, } } -void +const char* +AtomReader::atom_to_uri(const LV2_Atom* atom) +{ + if (atom && atom->type == _uris.atom_URI) { + return (const char*)LV2_ATOM_BODY(atom); + } else if (atom && atom->type == _uris.atom_URID) { + return _map.unmap_uri(((LV2_Atom_URID*)atom)->body); + } else { + return NULL; + } +} + +bool AtomReader::write(const LV2_Atom* msg) { - if (msg->type != _uris.atom_Blank) { - Raul::warn << "Unknown message type " << msg->type << std::endl; - return; + if (msg->type != _uris.atom_Blank && msg->type != _uris.atom_Resource) { + Raul::warn << (Raul::fmt("Unknown message type <%1%>\n") + % _map.unmap_uri(msg->type)).str(); + return false; } const LV2_Atom_Object* obj = (const LV2_Atom_Object*)msg; const LV2_Atom* subject = NULL; lv2_atom_object_get(obj, (LV2_URID)_uris.patch_subject, &subject, NULL); - const char* subject_uri = NULL; - if (subject && subject->type == _uris.atom_URI) { - subject_uri = (const char*)LV2_ATOM_BODY(subject); - } else if (subject && subject->type == _uris.atom_URID) { - subject_uri = _map.unmap_uri(((LV2_Atom_URID*)subject)->body); - } + const char* subject_uri = atom_to_uri(subject); if (obj->body.otype == _uris.patch_Get) { _iface.set_response_id(obj->body.id); _iface.get(subject_uri); } else if (obj->body.otype == _uris.patch_Delete) { - if (subject_uri) { - _iface.del(subject_uri); - return; - } - const LV2_Atom_Object* body = NULL; lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0); - if (body && body->body.otype == _uris.ingen_Edge) { - const LV2_Atom* tail = NULL; - const LV2_Atom* head = NULL; + + if (subject_uri && !body) { + _iface.del(subject_uri); + return true; + } else if (body && body->body.otype == _uris.ingen_Edge) { + const LV2_Atom* tail = NULL; + const LV2_Atom* head = NULL; + const LV2_Atom* incidentTo = NULL; lv2_atom_object_get(body, (LV2_URID)_uris.ingen_tail, &tail, (LV2_URID)_uris.ingen_head, &head, + (LV2_URID)_uris.ingen_incidentTo, &incidentTo, NULL); Raul::Atom tail_atom; Raul::Atom head_atom; + Raul::Atom incidentTo_atom; get_atom(tail, tail_atom); get_atom(head, head_atom); + get_atom(incidentTo, incidentTo_atom); if (tail_atom.is_valid() && head_atom.is_valid()) { _iface.disconnect(Raul::Path(tail_atom.get_uri()), Raul::Path(head_atom.get_uri())); + } else if (incidentTo_atom.is_valid()) { + _iface.disconnect_all(subject_uri, + Raul::Path(incidentTo_atom.get_uri())); } else { Raul::warn << "Delete of unknown object." << std::endl; + return false; } } } else if (obj->body.otype == _uris.patch_Put) { @@ -116,10 +131,10 @@ AtomReader::write(const LV2_Atom* msg) lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0); if (!body) { Raul::warn << "Put message has no body" << std::endl; - return; + return false; } else if (!subject_uri) { Raul::warn << "Put message has no subject" << std::endl; - return; + return false; } if (body->body.otype == _uris.ingen_Edge) { @@ -131,7 +146,7 @@ AtomReader::write(const LV2_Atom* msg) NULL); if (!tail || !head) { Raul::warn << "Edge has no tail or head" << std::endl; - return; + return false; } Raul::Atom tail_atom; @@ -151,10 +166,10 @@ AtomReader::write(const LV2_Atom* msg) lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0); if (!body) { Raul::warn << "Set message has no body" << std::endl; - return; + return false; } else if (!subject_uri) { Raul::warn << "Set message has no subject" << std::endl; - return; + return false; } LV2_ATOM_OBJECT_FOREACH(body, p) { @@ -165,21 +180,21 @@ AtomReader::write(const LV2_Atom* msg) } else if (obj->body.otype == _uris.patch_Patch) { if (!subject_uri) { Raul::warn << "Put message has no subject" << std::endl; - return; + return false; } const LV2_Atom_Object* remove = NULL; lv2_atom_object_get(obj, (LV2_URID)_uris.patch_remove, &remove, 0); if (!remove) { Raul::warn << "Patch message has no remove" << std::endl; - return; + return false; } const LV2_Atom_Object* add = NULL; lv2_atom_object_get(obj, (LV2_URID)_uris.patch_add, &add, 0); if (!add) { Raul::warn << "Patch message has no add" << std::endl; - return; + return false; } Ingen::Resource::Properties add_props; @@ -189,6 +204,26 @@ AtomReader::write(const LV2_Atom* msg) get_props(remove, remove_props); _iface.delta(subject_uri, remove_props, add_props); + } else if (obj->body.otype == _uris.patch_Move) { + if (!subject_uri) { + Raul::warn << "Move message has no subject" << std::endl; + return false; + } + + const LV2_Atom* dest = NULL; + lv2_atom_object_get(obj, (LV2_URID)_uris.patch_destination, &dest, 0); + if (!dest) { + Raul::warn << "Move message has no destination" << std::endl; + return false; + } + + const char* dest_uri = atom_to_uri(dest); + if (!dest_uri) { + Raul::warn << "Move message destination is not a URI" << std::endl; + return false; + } + + _iface.move(subject_uri, dest_uri); } else if (obj->body.otype == _uris.patch_Response) { const LV2_Atom* request = NULL; const LV2_Atom* body = NULL; @@ -198,10 +233,10 @@ AtomReader::write(const LV2_Atom* msg) 0); if (!request || request->type != _uris.atom_Int) { Raul::warn << "Response message has no request" << std::endl; - return; + return false; } else if (!body || body->type != _uris.atom_Int) { Raul::warn << "Response message body is not integer" << std::endl; - return; + return false; } _iface.response(((LV2_Atom_Int*)request)->body, (Ingen::Status)((LV2_Atom_Int*)body)->body); @@ -210,6 +245,8 @@ AtomReader::write(const LV2_Atom* msg) << _map.unmap_uri(obj->body.otype) << ">" << std::endl; } + + return true; } } // namespace Shared diff --git a/src/shared/AtomWriter.cpp b/src/shared/AtomWriter.cpp index a1ce8fb1..7d600466 100644 --- a/src/shared/AtomWriter.cpp +++ b/src/shared/AtomWriter.cpp @@ -216,6 +216,21 @@ void AtomWriter::disconnect_all(const Raul::Path& parent_patch_path, const Raul::Path& path) { + LV2_Atom_Forge_Frame msg; + lv2_atom_forge_blank(&_forge, &msg, next_id(), _uris.patch_Delete); + + lv2_atom_forge_property_head(&_forge, _uris.patch_subject, 0); + forge_uri(parent_patch_path); + + lv2_atom_forge_property_head(&_forge, _uris.patch_body, 0); + LV2_Atom_Forge_Frame edge; + lv2_atom_forge_blank(&_forge, &edge, 0, _uris.ingen_Edge); + lv2_atom_forge_property_head(&_forge, _uris.ingen_incidentTo, 0); + forge_uri(path); + lv2_atom_forge_pop(&_forge, &edge); + + lv2_atom_forge_pop(&_forge, &msg); + finish_msg(); } void diff --git a/src/shared/ResourceImpl.cpp b/src/shared/ResourceImpl.cpp index bb60da5c..13284cf4 100644 --- a/src/shared/ResourceImpl.cpp +++ b/src/shared/ResourceImpl.cpp @@ -122,7 +122,7 @@ ResourceImpl::type(const URIs& uris, patch = node = port = is_output = false; for (iterator i = types_range.first; i != types_range.second; ++i) { const Raul::Atom& atom = i->second; - if (atom.type() != uris.forge.URI) { + if (atom.type() != uris.forge.URI && atom.type() != uris.forge.URID) { Raul::warn << "[ResourceImpl] Non-URI type " << uris.forge.str(atom) << endl; continue; } diff --git a/src/shared/URIs.cpp b/src/shared/URIs.cpp index 1bc64c27..2c44c826 100644 --- a/src/shared/URIs.cpp +++ b/src/shared/URIs.cpp @@ -54,6 +54,7 @@ URIs::URIs(Shared::Forge& f, URIMap* map) , atom_Bool (forge, map, LV2_ATOM__Bool) , atom_Float (forge, map, LV2_ATOM__Float) , atom_Int (forge, map, LV2_ATOM__Int) + , atom_Resource (forge, map, LV2_ATOM__Resource) , atom_Sequence (forge, map, LV2_ATOM__Sequence) , atom_Sound (forge, map, LV2_ATOM__Sound) , atom_String (forge, map, LV2_ATOM__String) @@ -77,6 +78,7 @@ URIs::URIs(Shared::Forge& f, URIMap* map) , ingen_enabled (forge, map, NS_INGEN "enabled") , ingen_engine (forge, map, NS_INGEN "engine") , ingen_head (forge, map, NS_INGEN "head") + , ingen_incidentTo (forge, map, NS_INGEN "incidentTo") , ingen_nil (forge, map, NS_INGEN "nil") , ingen_node (forge, map, NS_INGEN "node") , ingen_polyphonic (forge, map, NS_INGEN "polyphonic") diff --git a/src/socket/SocketWriter.cpp b/src/socket/SocketWriter.cpp index 9a9decd7..c375ae16 100644 --- a/src/socket/SocketWriter.cpp +++ b/src/socket/SocketWriter.cpp @@ -76,12 +76,13 @@ SocketWriter::~SocketWriter() sratom_free(_sratom); } -void +bool SocketWriter::write(const LV2_Atom* msg) { sratom_write(_sratom, &_map.urid_unmap_feature()->urid_unmap, 0, NULL, NULL, msg->type, msg->size, LV2_ATOM_BODY(msg)); serd_writer_finish(_writer); + return true; } } // namespace Socket diff --git a/src/socket/SocketWriter.hpp b/src/socket/SocketWriter.hpp index 2e27ea98..2a17d843 100644 --- a/src/socket/SocketWriter.hpp +++ b/src/socket/SocketWriter.hpp @@ -43,7 +43,7 @@ public: ~SocketWriter(); - void write(const LV2_Atom* msg); + bool write(const LV2_Atom* msg); int fd() { return _socket->fd(); } Raul::URI uri() const { return _uri; } diff --git a/tests/connect_disconnect_node_node.ttl b/tests/connect_disconnect_node_node.ttl new file mode 100644 index 00000000..0f84dcaa --- /dev/null +++ b/tests/connect_disconnect_node_node.ttl @@ -0,0 +1,36 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/node1> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg1> + a patch:Put ; + patch:subject <path:/node2> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg2> + a patch:Put ; + patch:subject <path:/> ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/node1/left_out> ; + ingen:head <path:/node2/left_in> + ] . + +<msg3> + a patch:Delete ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/node1/left_out> ; + ingen:head <path:/node2/left_in> + ] . diff --git a/tests/connect_disconnect_node_patch.ttl b/tests/connect_disconnect_node_patch.ttl new file mode 100644 index 00000000..2f7fd0df --- /dev/null +++ b/tests/connect_disconnect_node_patch.ttl @@ -0,0 +1,36 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/node> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg1> + a patch:Put ; + patch:subject <path:/out> ; + patch:body [ + a lv2:OutputPort , + lv2:AudioPort + ] . + +<msg2> + a patch:Put ; + patch:subject <path:/> ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/node/left_out> ; + ingen:head <path:/out> + ] . + +<msg3> + a patch:Delete ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/node/left_out> ; + ingen:head <path:/out> + ] . diff --git a/tests/connect_disconnect_patch_patch.ttl b/tests/connect_disconnect_patch_patch.ttl new file mode 100644 index 00000000..ba31a8ec --- /dev/null +++ b/tests/connect_disconnect_patch_patch.ttl @@ -0,0 +1,36 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/in> ; + patch:body [ + a lv2:InputPort , + lv2:AudioPort + ] . + +<msg1> + a patch:Put ; + patch:subject <path:/out> ; + patch:body [ + a lv2:InputPort , + lv2:AudioPort + ] . + +<msg2> + a patch:Put ; + patch:subject <path:/> ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/in> ; + ingen:head <path:/out> + ] . + +<msg3> + a patch:Delete ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/in> ; + ingen:head <path:/out> + ] . diff --git a/tests/create_delete_node.ttl b/tests/create_delete_node.ttl new file mode 100644 index 00000000..3494abe1 --- /dev/null +++ b/tests/create_delete_node.ttl @@ -0,0 +1,15 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/node> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg1> + a patch:Delete ; + patch:subject <path:/node> . diff --git a/tests/create_delete_patch.ttl b/tests/create_delete_patch.ttl new file mode 100644 index 00000000..8dc5e09a --- /dev/null +++ b/tests/create_delete_patch.ttl @@ -0,0 +1,14 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/sub> ; + patch:body [ + a ingen:Patch ; + ] . + +<msg1> + a patch:Delete ; + patch:subject <path:/sub> . diff --git a/tests/create_delete_port.ttl b/tests/create_delete_port.ttl new file mode 100644 index 00000000..6a92f0cc --- /dev/null +++ b/tests/create_delete_port.ttl @@ -0,0 +1,15 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/in> ; + patch:body [ + a lv2:InputPort , + lv2:AudioPort + ] . + +<msg1> + a patch:Delete ; + patch:subject <path:/in> . diff --git a/tests/disconnect_all_node.ttl b/tests/disconnect_all_node.ttl new file mode 100644 index 00000000..b4fc2747 --- /dev/null +++ b/tests/disconnect_all_node.ttl @@ -0,0 +1,45 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/node1> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg1> + a patch:Put ; + patch:subject <path:/node2> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg2> + a patch:Put ; + patch:subject <path:/> ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/node1/left_out> ; + ingen:head <path:/node2/left_in> + ] . + +<msg3> + a patch:Put ; + patch:subject <path:/> ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/node1/right_out> ; + ingen:head <path:/node2/right_in> + ] . + +<msg4> + a patch:Delete ; + patch:subject <path:/> ; + patch:body [ + a ingen:Edge ; + ingen:incidentTo <path:/node1> + ] . diff --git a/tests/get_engine.ttl b/tests/get_engine.ttl new file mode 100644 index 00000000..f1be242c --- /dev/null +++ b/tests/get_engine.ttl @@ -0,0 +1,7 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Get ; + patch:subject <ingen:engine> . diff --git a/tests/get_node.ttl b/tests/get_node.ttl new file mode 100644 index 00000000..10ac10fb --- /dev/null +++ b/tests/get_node.ttl @@ -0,0 +1,15 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/node> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg1> + a patch:Get ; + patch:subject <path:/node> . diff --git a/tests/get_patch.ttl b/tests/get_patch.ttl new file mode 100644 index 00000000..843316dc --- /dev/null +++ b/tests/get_patch.ttl @@ -0,0 +1,39 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/sub> ; + patch:body [ + a ingen:Patch + ] . + +<msg1> + a patch:Put ; + patch:subject <path:/sub/node1> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg2> + a patch:Put ; + patch:subject <path:/sub/node2> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Combo> + ] . + +<msg3> + a patch:Put ; + patch:subject <path:/> ; + patch:body [ + a ingen:Edge ; + ingen:tail <path:/sub/node1/left_out> ; + ingen:head <path:/sub/node2/left_in> + ] . + +<msg4> + a patch:Get ; + patch:subject <path:/> . diff --git a/tests/get_plugins.ttl b/tests/get_plugins.ttl new file mode 100644 index 00000000..37b65127 --- /dev/null +++ b/tests/get_plugins.ttl @@ -0,0 +1,7 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Get ; + patch:subject <ingen:plugins> . diff --git a/tests/get_port.ttl b/tests/get_port.ttl new file mode 100644 index 00000000..3e522af8 --- /dev/null +++ b/tests/get_port.ttl @@ -0,0 +1,15 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/in> ; + patch:body [ + a lv2:InputPort , + lv2:AudioPort + ] . + +<msg1> + a patch:Get ; + patch:subject <path:/in> . diff --git a/tests/ingen_test.cpp b/tests/ingen_test.cpp index 0a882023..ec41cb2c 100644 --- a/tests/ingen_test.cpp +++ b/tests/ingen_test.cpp @@ -35,13 +35,17 @@ #include "serd/serd.h" #include "sord/sordmm.hpp" +#include "sratom/sratom.h" #include "ingen_config.h" #include "ingen/EngineBase.hpp" #include "ingen/Interface.hpp" #include "ingen/serialisation/Parser.hpp" +#include "ingen/shared/AtomReader.hpp" +#include "ingen/shared/AtomWriter.hpp" #include "ingen/shared/Configuration.hpp" +#include "ingen/shared/URIMap.hpp" #include "ingen/shared/World.hpp" #include "ingen/shared/runtime_paths.hpp" #include "ingen/client/ThreadedSigClientInterface.hpp" @@ -52,7 +56,70 @@ using namespace std; using namespace Ingen; -Ingen::Shared::World* world = NULL; +Shared::World* world = NULL; + +/* +class TestClient : public Shared::AtomSink { + void write(const LV2_Atom* msg) { + } +}; +*/ +class TestClient : public Interface +{ +public: + TestClient() {} + ~TestClient() {} + + Raul::URI uri() const { return "http://drobilla.net/ns/ingen#AtomWriter"; } + + void bundle_begin() {} + + void bundle_end() {} + + void put(const Raul::URI& uri, + const Resource::Properties& properties, + Resource::Graph ctx = Resource::DEFAULT) {} + + void delta(const Raul::URI& uri, + const Resource::Properties& remove, + const Resource::Properties& add) {} + + void move(const Raul::Path& old_path, + const Raul::Path& new_path) {} + + void del(const Raul::URI& uri) {} + + void connect(const Raul::Path& tail, + const Raul::Path& head) {} + + void disconnect(const Raul::Path& tail, + const Raul::Path& head) {} + + void disconnect_all(const Raul::Path& parent_patch_path, + const Raul::Path& path) {} + + void set_property(const Raul::URI& subject, + const Raul::URI& predicate, + const Raul::Atom& value) {} + + void set_response_id(int32_t id) {} + + void get(const Raul::URI& uri) {} + + void response(int32_t id, Status status) { + if (status) { + Raul::error(Raul::fmt("error on message %1%: %2%\n") + % id % ingen_status_string(status)); + exit(EXIT_FAILURE); + } + } + + void error(const std::string& msg) { + Raul::error(Raul::fmt("error: %1%\n") % msg); + exit(EXIT_FAILURE); + } +}; + void ingen_try(bool cond, const char* msg) @@ -70,46 +137,118 @@ main(int argc, char** argv) Glib::thread_init(); Shared::set_bundle_path_from_code((void*)&main); + if (argc != 3) { + cerr << "Usage: ingen_test START_PATCH COMMANDS_FILE" << endl; + return EXIT_FAILURE; + } + // Create world try { - world = new Ingen::Shared::World(argc, argv, NULL, NULL); - if (argc <= 1) { - world->conf().print_usage("ingen", cout); - return EXIT_FAILURE; - } else if (world->conf().option("help").get_bool()) { - world->conf().print_usage("ingen", cout); - return EXIT_SUCCESS; - } + world = new Shared::World(argc, argv, NULL, NULL); } catch (std::exception& e) { cout << "ingen: " << e.what() << endl; return EXIT_FAILURE; } - // Run engine - //SharedPtr<Interface> engine_interface; + // Load modules ingen_try(world->load_module("server_profiled"), "Unable to load server module"); - //ingen_try(world->load_module("client"), - // "Unable to load client module"); - - ingen_try(world->engine(), - "Unable to create engine"); - ingen_try(world->load_module("serialisation_profiled"), "Unable to load serialisation module"); + // Initialise engine + ingen_try(world->engine(), + "Unable to create engine"); world->engine()->init(48000.0, 4096); world->engine()->activate(); + // Load patch world->parser()->parse_file(world, world->interface().get(), argv[1]); - while (world->engine()->run(4096)) { + while (world->engine()->pending_events()) { + world->engine()->run(4096); world->engine()->main_iteration(); + g_usleep(1000); + } + + // Read commands + + SerdChunk out = { NULL, 0 }; + LV2_URID_Map* map = &world->uri_map().urid_map_feature()->urid_map; + Sratom* sratom = sratom_new(map); + + sratom_set_object_mode(sratom, SRATOM_OBJECT_MODE_BLANK_SUBJECT); + + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, map); + lv2_atom_forge_set_sink(&forge, sratom_forge_sink, sratom_forge_deref, &out); + + const std::string cmds_file_path = argv[2]; + + // AtomReader to read commands from a file and send them to engine + Shared::AtomReader atom_reader( + world->uri_map(), world->uris(), world->forge(), *world->interface().get()); + + // AtomWriter to serialise responses from the engine + /* + TestClient client; + SharedPtr<Shared::AtomWriter> atom_writer( + new Shared::AtomWriter(world->uri_map(), world->uris(), client)); + */ + SharedPtr<Interface> client(new TestClient()); + + world->interface()->set_respondee(client); + world->engine()->register_client( + "http://drobilla.net/ns/ingen#AtomWriter", + client); + + SerdURI cmds_base; + const SerdNode cmds_file_uri = serd_node_new_file_uri( + (const uint8_t*)cmds_file_path.c_str(), + NULL, &cmds_base, false); + Sord::Model* cmds = new Sord::Model(*world->rdf_world(), + (const char*)cmds_file_uri.buf); + SerdEnv* env = serd_env_new(&cmds_file_uri); + cmds->load_file(env, SERD_TURTLE, cmds_file_path); + Sord::Node nil; + for (int i = 0; ; ++i) { + std::string subject_str = (Raul::fmt("msg%1%") % i).str(); + Sord::URI subject(*world->rdf_world(), subject_str, + (const char*)cmds_file_uri.buf); + Sord::Iter iter = cmds->find(subject, nil, nil); + if (iter.end()) { + break; + } + + out.len = 0; + sratom_read(sratom, &forge, world->rdf_world()->c_obj(), + cmds->c_obj(), subject.c_obj()); + + /* + cerr << "READ " << out.len << " BYTES" << endl; + LV2_Atom* atom = (LV2_Atom*)out.buf; + cerr << sratom_to_turtle( + sratom, + &world->uri_map().urid_unmap_feature()->urid_unmap, + (const char*)cmds_file_uri.buf, + NULL, NULL, atom->type, atom->size, LV2_ATOM_BODY(atom)) << endl; + */ + + if (!atom_reader.write((LV2_Atom*)out.buf)) { + return EXIT_FAILURE; + } + + while (world->engine()->pending_events()) { + world->engine()->run(4096); + world->engine()->main_iteration(); + g_usleep(1000); + } } + serd_env_free(env); + delete cmds; // Shut down - if (world->engine()) - world->engine()->deactivate(); + world->engine()->deactivate(); delete world; return 0; diff --git a/tests/move_node.ttl b/tests/move_node.ttl new file mode 100644 index 00000000..f24c14c2 --- /dev/null +++ b/tests/move_node.ttl @@ -0,0 +1,16 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/node> ; + patch:body [ + a ingen:Node ; + ingen:prototype <http://drobilla.net/plugins/mda/Shepard> + ] . + +<msg1> + a patch:Move ; + patch:subject <path:/node> ; + patch:destination <path:/tone> . diff --git a/tests/move_port.ttl b/tests/move_port.ttl new file mode 100644 index 00000000..b6c9ab83 --- /dev/null +++ b/tests/move_port.ttl @@ -0,0 +1,16 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix ingen: <http://drobilla.net/ns/ingen#> . + +<msg0> + a patch:Put ; + patch:subject <path:/in> ; + patch:body [ + a lv2:InputPort , + lv2:AudioPort + ] . + +<msg1> + a patch:Move ; + patch:subject <path:/in> ; + patch:destination <path:/input> . diff --git a/tests/put_audio_in.ttl b/tests/put_audio_in.ttl new file mode 100644 index 00000000..2f724ab9 --- /dev/null +++ b/tests/put_audio_in.ttl @@ -0,0 +1,10 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . + +<msg0> + a patch:Put ; + patch:subject <path:/in> ; + patch:body [ + a lv2:InputPort , + lv2:AudioPort + ] . diff --git a/tests/set_patch_port_value.ttl b/tests/set_patch_port_value.ttl new file mode 100644 index 00000000..226d4811 --- /dev/null +++ b/tests/set_patch_port_value.ttl @@ -0,0 +1,18 @@ +@prefix ingen: <http://drobilla.net/ns/ingen#> . +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . + +<msg0> + a patch:Put ; + patch:subject <path:/in> ; + patch:body [ + a lv2:InputPort , + lv2:ControlPort + ] . + +<msg1> + a patch:Set ; + patch:subject <path:/in> ; + patch:body [ + ingen:value 0.5 + ] . @@ -172,7 +172,7 @@ def build(bld): install_path = '', lib = bld.env['INGEN_TEST_LIBS'], cxxflags = bld.env['INGEN_TEST_CXXFLAGS']) - autowaf.use_lib(bld, obj, 'GTHREAD GLIBMM SORD RAUL LILV INGEN LV2') + autowaf.use_lib(bld, obj, 'GTHREAD GLIBMM SORD RAUL LILV INGEN LV2 SRATOM') bld.install_files('${DATADIR}/applications', 'src/ingen/ingen.desktop') bld.install_files('${BINDIR}', 'scripts/ingenish', chmod=Utils.O755) @@ -209,5 +209,9 @@ def test(ctx): os.path.join('src', 'serialisation')]) autowaf.pre_test(ctx, APPNAME, dirs=['.', 'src', 'tests']) - autowaf.run_tests(ctx, APPNAME, ['ingen_test ../tests/empty.ingen'], dirs=['.', 'src', 'tests']) - autowaf.post_test(ctx, APPNAME, dirs=['.', 'src', 'tests']) + for i in ctx.path.ant_glob('tests/*.ttl'): + autowaf.run_tests(ctx, APPNAME, + ['ingen_test ../tests/empty.ingen %s' % i.abspath()], + dirs=['.', 'src', 'tests']) + autowaf.post_test(ctx, APPNAME, dirs=['.', 'src', 'tests'], + remove=['/usr*']) |