summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bundles/ingen.lv2/ingen.ttl7
-rw-r--r--ingen/EngineBase.hpp5
-rw-r--r--ingen/Status.hpp8
-rw-r--r--ingen/shared/AtomReader.hpp3
-rw-r--r--ingen/shared/AtomSink.hpp6
-rw-r--r--ingen/shared/URIs.hpp2
-rwxr-xr-xscripts/ingenish27
-rw-r--r--src/gui/ingen_gui_lv2.cpp3
-rw-r--r--src/server/Engine.cpp21
-rw-r--r--src/server/Engine.hpp5
-rw-r--r--src/server/Event.cpp72
-rw-r--r--src/server/Event.hpp32
-rw-r--r--src/server/EventWriter.cpp7
-rw-r--r--src/server/PreProcessor.cpp4
-rw-r--r--src/server/events/Connect.cpp30
-rw-r--r--src/server/events/Connect.hpp2
-rw-r--r--src/server/events/CreateNode.cpp44
-rw-r--r--src/server/events/CreateNode.hpp5
-rw-r--r--src/server/events/CreatePatch.cpp42
-rw-r--r--src/server/events/CreatePatch.hpp3
-rw-r--r--src/server/events/CreatePort.cpp33
-rw-r--r--src/server/events/CreatePort.hpp2
-rw-r--r--src/server/events/Delete.cpp9
-rw-r--r--src/server/events/Delete.hpp2
-rw-r--r--src/server/events/Disconnect.cpp22
-rw-r--r--src/server/events/Disconnect.hpp2
-rw-r--r--src/server/events/DisconnectAll.cpp21
-rw-r--r--src/server/events/DisconnectAll.hpp2
-rw-r--r--src/server/events/Get.cpp12
-rw-r--r--src/server/events/Get.hpp3
-rw-r--r--src/server/events/Move.cpp23
-rw-r--r--src/server/events/Move.hpp2
-rw-r--r--src/server/events/SetMetadata.cpp58
-rw-r--r--src/server/events/SetMetadata.hpp2
-rw-r--r--src/server/events/SetPortValue.cpp25
-rw-r--r--src/server/events/SetPortValue.hpp2
-rw-r--r--src/server/ingen_lv2.cpp3
-rw-r--r--src/server/wscript1
-rw-r--r--src/shared/AtomReader.cpp93
-rw-r--r--src/shared/AtomWriter.cpp15
-rw-r--r--src/shared/ResourceImpl.cpp2
-rw-r--r--src/shared/URIs.cpp2
-rw-r--r--src/socket/SocketWriter.cpp3
-rw-r--r--src/socket/SocketWriter.hpp2
-rw-r--r--tests/connect_disconnect_node_node.ttl36
-rw-r--r--tests/connect_disconnect_node_patch.ttl36
-rw-r--r--tests/connect_disconnect_patch_patch.ttl36
-rw-r--r--tests/create_delete_node.ttl15
-rw-r--r--tests/create_delete_patch.ttl14
-rw-r--r--tests/create_delete_port.ttl15
-rw-r--r--tests/disconnect_all_node.ttl45
-rw-r--r--tests/get_engine.ttl7
-rw-r--r--tests/get_node.ttl15
-rw-r--r--tests/get_patch.ttl39
-rw-r--r--tests/get_plugins.ttl7
-rw-r--r--tests/get_port.ttl15
-rw-r--r--tests/ingen_test.cpp179
-rw-r--r--tests/move_node.ttl16
-rw-r--r--tests/move_port.ttl16
-rw-r--r--tests/put_audio_in.ttl10
-rw-r--r--tests/set_patch_port_value.ttl18
-rw-r--r--wscript10
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
+ ] .
diff --git a/wscript b/wscript
index 0229608c..3e13bb5e 100644
--- a/wscript
+++ b/wscript
@@ -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*'])