summaryrefslogtreecommitdiffstats
path: root/src/engine/events
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/events')
-rw-r--r--src/engine/events/AllNotesOffEvent.cpp71
-rw-r--r--src/engine/events/AllNotesOffEvent.hpp51
-rw-r--r--src/engine/events/ClearPatchEvent.cpp133
-rw-r--r--src/engine/events/ClearPatchEvent.hpp65
-rw-r--r--src/engine/events/ConnectionEvent.cpp202
-rw-r--r--src/engine/events/ConnectionEvent.hpp92
-rw-r--r--src/engine/events/CreateNodeEvent.cpp151
-rw-r--r--src/engine/events/CreateNodeEvent.hpp81
-rw-r--r--src/engine/events/CreatePatchEvent.cpp157
-rw-r--r--src/engine/events/CreatePatchEvent.hpp64
-rw-r--r--src/engine/events/CreatePortEvent.cpp173
-rw-r--r--src/engine/events/CreatePortEvent.hpp72
-rw-r--r--src/engine/events/DeactivateEvent.cpp54
-rw-r--r--src/engine/events/DeactivateEvent.hpp43
-rw-r--r--src/engine/events/DestroyEvent.cpp201
-rw-r--r--src/engine/events/DestroyEvent.hpp77
-rw-r--r--src/engine/events/DisablePortMonitoringEvent.cpp87
-rw-r--r--src/engine/events/DisablePortMonitoringEvent.hpp58
-rw-r--r--src/engine/events/DisconnectAllEvent.cpp183
-rw-r--r--src/engine/events/DisconnectAllEvent.hpp79
-rw-r--r--src/engine/events/DisconnectionEvent.cpp213
-rw-r--r--src/engine/events/DisconnectionEvent.hpp90
-rw-r--r--src/engine/events/EnablePatchEvent.cpp86
-rw-r--r--src/engine/events/EnablePatchEvent.hpp63
-rw-r--r--src/engine/events/LoadPluginsEvent.cpp56
-rw-r--r--src/engine/events/LoadPluginsEvent.hpp46
-rw-r--r--src/engine/events/Makefile.am63
-rw-r--r--src/engine/events/MidiLearnEvent.cpp89
-rw-r--r--src/engine/events/MidiLearnEvent.hpp85
-rw-r--r--src/engine/events/NoteEvent.cpp102
-rw-r--r--src/engine/events/NoteEvent.hpp68
-rw-r--r--src/engine/events/PingQueuedEvent.hpp48
-rw-r--r--src/engine/events/RegisterClientEvent.cpp55
-rw-r--r--src/engine/events/RegisterClientEvent.hpp55
-rw-r--r--src/engine/events/RenameEvent.cpp152
-rw-r--r--src/engine/events/RenameEvent.hpp64
-rw-r--r--src/engine/events/RequestAllObjectsEvent.cpp59
-rw-r--r--src/engine/events/RequestAllObjectsEvent.hpp48
-rw-r--r--src/engine/events/RequestMetadataEvent.cpp85
-rw-r--r--src/engine/events/RequestMetadataEvent.hpp62
-rw-r--r--src/engine/events/RequestObjectEvent.cpp98
-rw-r--r--src/engine/events/RequestObjectEvent.hpp55
-rw-r--r--src/engine/events/RequestPluginEvent.cpp79
-rw-r--r--src/engine/events/RequestPluginEvent.hpp53
-rw-r--r--src/engine/events/RequestPluginsEvent.cpp57
-rw-r--r--src/engine/events/RequestPluginsEvent.hpp47
-rw-r--r--src/engine/events/RequestPortValueEvent.cpp81
-rw-r--r--src/engine/events/RequestPortValueEvent.hpp56
-rw-r--r--src/engine/events/SendPortActivityEvent.cpp34
-rw-r--r--src/engine/events/SendPortActivityEvent.hpp67
-rw-r--r--src/engine/events/SendPortValueEvent.cpp43
-rw-r--r--src/engine/events/SendPortValueEvent.hpp78
-rw-r--r--src/engine/events/SetMetadataEvent.cpp114
-rw-r--r--src/engine/events/SetMetadataEvent.hpp65
-rw-r--r--src/engine/events/SetPolyphonicEvent.cpp82
-rw-r--r--src/engine/events/SetPolyphonicEvent.hpp56
-rw-r--r--src/engine/events/SetPolyphonyEvent.cpp79
-rw-r--r--src/engine/events/SetPolyphonyEvent.hpp56
-rw-r--r--src/engine/events/SetPortValueEvent.cpp224
-rw-r--r--src/engine/events/SetPortValueEvent.hpp80
-rw-r--r--src/engine/events/UnregisterClientEvent.cpp45
-rw-r--r--src/engine/events/UnregisterClientEvent.hpp54
62 files changed, 5286 insertions, 0 deletions
diff --git a/src/engine/events/AllNotesOffEvent.cpp b/src/engine/events/AllNotesOffEvent.cpp
new file mode 100644
index 00000000..fcb68b31
--- /dev/null
+++ b/src/engine/events/AllNotesOffEvent.cpp
@@ -0,0 +1,71 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "AllNotesOffEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "EngineStore.hpp"
+#include "module/World.hpp"
+#include "shared/Store.hpp"
+
+namespace Ingen {
+
+
+/** Note off with patch explicitly passed - triggered by MIDI.
+ */
+AllNotesOffEvent::AllNotesOffEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, PatchImpl* patch)
+: Event(engine, responder, timestamp),
+ _patch(patch)
+{
+}
+
+
+/** Note off event with lookup - triggered by OSC.
+ */
+AllNotesOffEvent::AllNotesOffEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& patch_path)
+: Event(engine, responder, timestamp),
+ _patch_path(patch_path),
+ _patch(NULL)
+{
+}
+
+
+void
+AllNotesOffEvent::execute(ProcessContext& context)
+{
+ Event::execute(context);
+
+ if (_patch == NULL && _patch_path != "")
+ _patch = _engine.engine_store()->find_patch(_patch_path);
+
+ //if (_patch != NULL)
+ // for (Raul::List<MidiInNode*>::iterator j = _patch->midi_in_nodes().begin(); j != _patch->midi_in_nodes().end(); ++j)
+ // (*j)->all_notes_off(offset);
+}
+
+
+void
+AllNotesOffEvent::post_process()
+{
+ if (_patch != NULL)
+ _responder->respond_ok();
+}
+
+
+} // namespace Ingen
+
+
diff --git a/src/engine/events/AllNotesOffEvent.hpp b/src/engine/events/AllNotesOffEvent.hpp
new file mode 100644
index 00000000..3e4d56b3
--- /dev/null
+++ b/src/engine/events/AllNotesOffEvent.hpp
@@ -0,0 +1,51 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ALLNOTESOFFEVENT_H
+#define ALLNOTESOFFEVENT_H
+
+#include "Event.hpp"
+#include <string>
+using std::string;
+
+namespace Ingen {
+
+class PatchImpl;
+
+
+/** A note off event for all active voices.
+ *
+ * \ingroup engine
+ */
+class AllNotesOffEvent : public Event
+{
+public:
+ AllNotesOffEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, PatchImpl* patch);
+ AllNotesOffEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& patch_path);
+
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const string _patch_path;
+ PatchImpl* _patch;
+};
+
+
+} // namespace Ingen
+
+#endif // ALLNOTESOFFEVENT_H
diff --git a/src/engine/events/ClearPatchEvent.cpp b/src/engine/events/ClearPatchEvent.cpp
new file mode 100644
index 00000000..c1fb0749
--- /dev/null
+++ b/src/engine/events/ClearPatchEvent.cpp
@@ -0,0 +1,133 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <raul/Maid.hpp>
+#include "ClearPatchEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PatchImpl.hpp"
+#include "ClientBroadcaster.hpp"
+#include "util.hpp"
+#include "EngineStore.hpp"
+#include "PortImpl.hpp"
+#include "NodeImpl.hpp"
+#include "ConnectionImpl.hpp"
+#include "QueuedEventSource.hpp"
+#include "AudioDriver.hpp"
+#include "MidiDriver.hpp"
+
+namespace Ingen {
+
+
+ClearPatchEvent::ClearPatchEvent(Engine& engine, SharedPtr<Responder> responder, FrameTime time, QueuedEventSource* source, const string& patch_path)
+ : QueuedEvent(engine, responder, time, true, source)
+ , _patch_path(patch_path)
+ , _driver_port(NULL)
+ , _process(false)
+ , _ports_array(NULL)
+ , _compiled_patch(NULL)
+{
+}
+
+
+void
+ClearPatchEvent::pre_process()
+{
+ EngineStore::Objects::iterator patch_iterator = _engine.engine_store()->find(_patch_path);
+
+ if (patch_iterator != _engine.engine_store()->end()) {
+ _patch = PtrCast<PatchImpl>(patch_iterator->second);
+ if (_patch) {
+ _process = _patch->enabled();
+ _removed_table = _engine.engine_store()->remove_children(patch_iterator);
+ _patch->nodes().clear();
+ _patch->connections().clear();
+ _ports_array = _patch->build_ports_array();
+ if (_patch->enabled())
+ _compiled_patch = _patch->compile();
+ }
+ }
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+ClearPatchEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_patch && _removed_table) {
+ _patch->disable();
+
+ if (_patch->compiled_patch() != NULL) {
+ _engine.maid()->push(_patch->compiled_patch());
+ _patch->compiled_patch(NULL);
+ }
+
+ _patch->clear_ports();
+ _patch->connections().clear();
+ _patch->compiled_patch(_compiled_patch);
+ Raul::Array<PortImpl*>* old_ports = _patch->external_ports();
+ _patch->external_ports(_ports_array);
+ _ports_array = old_ports;
+
+ // Remove driver ports, if necessary
+ if (_patch->parent() == NULL) {
+ for (EngineStore::Objects::iterator i = _removed_table->begin(); i != _removed_table->end(); ++i) {
+ SharedPtr<PortImpl> port = PtrCast<PortImpl>(i->second);
+ if (port && port->type() == DataType::AUDIO)
+ _driver_port = _engine.audio_driver()->remove_port(port->path());
+ else if (port && port->type() == DataType::EVENT)
+ _driver_port = _engine.midi_driver()->remove_port(port->path());
+ }
+ }
+ }
+}
+
+
+void
+ClearPatchEvent::post_process()
+{
+ if (_patch != NULL) {
+ delete _ports_array;
+ delete _driver_port;
+
+ // Restore patch's run state
+ if (_process)
+ _patch->enable();
+ else
+ _patch->disable();
+
+ // Make sure everything's sane
+ assert(_patch->nodes().size() == 0);
+ assert(_patch->num_ports() == 0);
+ assert(_patch->connections().size() == 0);
+
+ // Reply
+ _responder->respond_ok();
+ _engine.broadcaster()->send_patch_cleared(_patch_path);
+ } else {
+ _responder->respond_error(string("Patch ") + _patch_path + " not found");
+ }
+
+ _source->unblock(); // FIXME: can be done earlier in execute?
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/ClearPatchEvent.hpp b/src/engine/events/ClearPatchEvent.hpp
new file mode 100644
index 00000000..803721fb
--- /dev/null
+++ b/src/engine/events/ClearPatchEvent.hpp
@@ -0,0 +1,65 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CLEARPATCHEVENT_H
+#define CLEARPATCHEVENT_H
+
+#include <string>
+#include <raul/Array.hpp>
+#include <raul/Table.hpp>
+#include <raul/Path.hpp>
+#include "QueuedEvent.hpp"
+#include "EngineStore.hpp"
+#include "PatchImpl.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+class PatchImpl;
+class DriverPort;
+
+
+/** Delete all nodes from a patch.
+ *
+ * \ingroup engine
+ */
+class ClearPatchEvent : public QueuedEvent
+{
+public:
+ ClearPatchEvent(Engine& engine, SharedPtr<Responder> responder, FrameTime time, QueuedEventSource* source, const string& patch_path);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const string _patch_path;
+ SharedPtr<PatchImpl> _patch;
+ DriverPort* _driver_port;
+ bool _process;
+ Raul::Array<PortImpl*>* _ports_array; ///< New (external) ports for Patch
+ CompiledPatch* _compiled_patch; ///< Patch's new process order
+
+ SharedPtr< Table<Path, SharedPtr<Shared::GraphObject> > > _removed_table;
+};
+
+
+} // namespace Ingen
+
+
+#endif // CLEARPATCHEVENT_H
diff --git a/src/engine/events/ConnectionEvent.cpp b/src/engine/events/ConnectionEvent.cpp
new file mode 100644
index 00000000..24b80dee
--- /dev/null
+++ b/src/engine/events/ConnectionEvent.cpp
@@ -0,0 +1,202 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include <string>
+#include <boost/format.hpp>
+#include <raul/Maid.hpp>
+#include <raul/Path.hpp>
+#include "ClientBroadcaster.hpp"
+#include "ConnectionEvent.hpp"
+#include "ConnectionImpl.hpp"
+#include "Engine.hpp"
+#include "InputPort.hpp"
+#include "EngineStore.hpp"
+#include "OutputPort.hpp"
+#include "PatchImpl.hpp"
+#include "PortImpl.hpp"
+#include "Responder.hpp"
+#include "types.hpp"
+
+using std::string;
+namespace Ingen {
+
+
+ConnectionEvent::ConnectionEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path)
+: QueuedEvent(engine, responder, timestamp),
+ _src_port_path(src_port_path),
+ _dst_port_path(dst_port_path),
+ _patch(NULL),
+ _src_port(NULL),
+ _dst_port(NULL),
+ _compiled_patch(NULL),
+ _patch_listnode(NULL),
+ _port_listnode(NULL),
+ _error(NO_ERROR)
+{
+}
+
+
+void
+ConnectionEvent::pre_process()
+{
+ if (_src_port_path.parent().parent() != _dst_port_path.parent().parent()
+ && _src_port_path.parent() != _dst_port_path.parent().parent()
+ && _src_port_path.parent().parent() != _dst_port_path.parent()) {
+ _error = PARENT_PATCH_DIFFERENT;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ _src_port = _engine.engine_store()->find_port(_src_port_path);
+ _dst_port = _engine.engine_store()->find_port(_dst_port_path);
+
+ if (_src_port == NULL || _dst_port == NULL) {
+ _error = PORT_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if ( ! (_src_port->type() == _dst_port->type()
+ || ( (_src_port->type() == DataType::CONTROL || _src_port->type() == DataType::AUDIO)
+ && (_dst_port->type() == DataType::CONTROL || _dst_port->type() == DataType::AUDIO) ))) {
+ _error = TYPE_MISMATCH;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ _dst_input_port = dynamic_cast<InputPort*>(_dst_port);
+ _src_output_port = dynamic_cast<OutputPort*>(_src_port);
+
+ if (!_dst_input_port || !_src_output_port) {
+ _error = DIRECTION_MISMATCH;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ NodeImpl* const src_node = _src_port->parent_node();
+ NodeImpl* const dst_node = _dst_port->parent_node();
+
+ // Connection to a patch port from inside the patch
+ if (src_node->parent_patch() != dst_node->parent_patch()) {
+
+ assert(src_node->parent() == dst_node || dst_node->parent() == src_node);
+ if (src_node->parent() == dst_node)
+ _patch = dynamic_cast<PatchImpl*>(dst_node);
+ else
+ _patch = dynamic_cast<PatchImpl*>(src_node);
+
+ // Connection from a patch input to a patch output (pass through)
+ } else if (src_node == dst_node && dynamic_cast<PatchImpl*>(src_node)) {
+ _patch = dynamic_cast<PatchImpl*>(src_node);
+
+ // Normal connection between nodes with the same parent
+ } else {
+ _patch = src_node->parent_patch();
+ }
+
+ assert(_patch);
+
+ //if (_dst_input_port->is_connected_to(_src_output_port)) {
+ if (_patch->has_connection(_src_output_port, _dst_input_port)) {
+ _error = ALREADY_CONNECTED;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if (src_node == NULL || dst_node == NULL) {
+ _error = PARENTS_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if (_patch != src_node && src_node->parent() != _patch && dst_node->parent() != _patch) {
+ _error = PARENTS_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ _connection = SharedPtr<ConnectionImpl>(new ConnectionImpl(_src_port, _dst_port));
+ _patch_listnode = new PatchImpl::Connections::Node(_connection);
+ _port_listnode = new InputPort::Connections::Node(_connection);
+
+ // Need to be careful about patch port connections here and adding a node's
+ // parent as a dependant/provider, or adding a patch as it's own provider...
+ if (src_node != dst_node && src_node->parent() == dst_node->parent()) {
+ dst_node->providers()->push_back(new Raul::List<NodeImpl*>::Node(src_node));
+ src_node->dependants()->push_back(new Raul::List<NodeImpl*>::Node(dst_node));
+ }
+
+ _patch->add_connection(_patch_listnode);
+
+ if (_patch->enabled())
+ _compiled_patch = _patch->compile();
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+ConnectionEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_error == NO_ERROR) {
+ // This must be inserted here, since they're actually used by the audio thread
+ _dst_input_port->add_connection(_port_listnode);
+ if (_patch->compiled_patch() != NULL)
+ _engine.maid()->push(_patch->compiled_patch());
+ _patch->compiled_patch(_compiled_patch);
+ }
+}
+
+
+void
+ConnectionEvent::post_process()
+{
+ std::ostringstream ss;
+ if (_error == NO_ERROR) {
+ _responder->respond_ok();
+ _engine.broadcaster()->send_connection(_connection);
+ return;
+ }
+
+ ss << boost::format("Unable to make connection %1% -> %2% (") % _src_port_path % _dst_port_path;
+
+ switch (_error) {
+ case PARENT_PATCH_DIFFERENT:
+ ss << "Ports have mismatched parents"; break;
+ case PORT_NOT_FOUND:
+ ss << "Port not found"; break;
+ case TYPE_MISMATCH:
+ ss << "Type mismatch"; break;
+ case DIRECTION_MISMATCH:
+ ss << "Direction mismatch"; break;
+ case ALREADY_CONNECTED:
+ ss << "Already connected"; break;
+ case PARENTS_NOT_FOUND:
+ ss << "Parents not found"; break;
+ default:
+ ss << "Unknown error";
+ }
+ ss << ")";
+ _responder->respond_error(ss.str());
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/ConnectionEvent.hpp b/src/engine/events/ConnectionEvent.hpp
new file mode 100644
index 00000000..89407957
--- /dev/null
+++ b/src/engine/events/ConnectionEvent.hpp
@@ -0,0 +1,92 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CONNECTIONEVENT_H
+#define CONNECTIONEVENT_H
+
+#include <string>
+#include <raul/Path.hpp>
+#include "QueuedEvent.hpp"
+#include "PatchImpl.hpp"
+#include "InputPort.hpp"
+#include "types.hpp"
+using std::string;
+
+namespace Raul {
+ template <typename T> class ListNode;
+ template <typename T> class Array;
+}
+
+namespace Ingen {
+
+class PatchImpl;
+class NodeImpl;
+class ConnectionImpl;
+class MidiMessage;
+class PortImpl;
+class InputPort;
+class OutputPort;
+class CompiledPatch;
+
+
+/** Make a Connection between two Ports.
+ *
+ * \ingroup engine
+ */
+class ConnectionEvent : public QueuedEvent
+{
+public:
+ ConnectionEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+
+ enum ErrorType {
+ NO_ERROR,
+ PARENT_PATCH_DIFFERENT,
+ PORT_NOT_FOUND,
+ TYPE_MISMATCH,
+ DIRECTION_MISMATCH,
+ ALREADY_CONNECTED,
+ PARENTS_NOT_FOUND
+ };
+
+ Raul::Path _src_port_path;
+ Raul::Path _dst_port_path;
+
+ PatchImpl* _patch;
+ PortImpl* _src_port;
+ PortImpl* _dst_port;
+ OutputPort* _src_output_port;
+ InputPort* _dst_input_port;
+
+ CompiledPatch* _compiled_patch; ///< New process order for Patch
+
+ SharedPtr<ConnectionImpl> _connection;
+ PatchImpl::Connections::Node* _patch_listnode;
+ InputPort::Connections::Node* _port_listnode;
+
+ ErrorType _error;
+};
+
+
+} // namespace Ingen
+
+#endif // CONNECTIONEVENT_H
diff --git a/src/engine/events/CreateNodeEvent.cpp b/src/engine/events/CreateNodeEvent.cpp
new file mode 100644
index 00000000..b58bc2c3
--- /dev/null
+++ b/src/engine/events/CreateNodeEvent.cpp
@@ -0,0 +1,151 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <raul/Maid.hpp>
+#include <raul/Path.hpp>
+#include <raul/Path.hpp>
+#include <redlandmm/World.hpp>
+#include "module/World.hpp"
+#include "CreateNodeEvent.hpp"
+#include "Responder.hpp"
+#include "PatchImpl.hpp"
+#include "NodeImpl.hpp"
+#include "PluginImpl.hpp"
+#include "Engine.hpp"
+#include "PatchImpl.hpp"
+#include "NodeFactory.hpp"
+#include "ClientBroadcaster.hpp"
+#include "EngineStore.hpp"
+#include "PortImpl.hpp"
+#include "AudioDriver.hpp"
+
+namespace Ingen {
+
+
+CreateNodeEvent::CreateNodeEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& path,
+ const string& plugin_uri, bool polyphonic)
+: QueuedEvent(engine, responder, timestamp),
+ _path(path),
+ _plugin_uri(plugin_uri),
+ _polyphonic(polyphonic),
+ _patch(NULL),
+ _node(NULL),
+ _compiled_patch(NULL),
+ _node_already_exists(false)
+{
+}
+
+
+/** DEPRECATED: Construct from type, library name, and plugin label.
+ *
+ * Do not use.
+ */
+CreateNodeEvent::CreateNodeEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& path,
+ const string& plugin_type, const string& plugin_lib, const string& plugin_label, bool polyphonic)
+: QueuedEvent(engine, responder, timestamp),
+ _path(path),
+ _plugin_type(plugin_type),
+ _plugin_lib(plugin_lib),
+ _plugin_label(plugin_label),
+ _polyphonic(polyphonic),
+ _patch(NULL),
+ _node(NULL),
+ _compiled_patch(NULL),
+ _node_already_exists(false)
+{
+}
+
+
+void
+CreateNodeEvent::pre_process()
+{
+ if (_engine.engine_store()->find_object(_path) != NULL) {
+ _node_already_exists = true;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ _patch = _engine.engine_store()->find_patch(_path.parent());
+
+ PluginImpl* const plugin = (_plugin_uri != "")
+ ? _engine.node_factory()->plugin(_plugin_uri)
+ : _engine.node_factory()->plugin(_plugin_type, _plugin_lib, _plugin_label);
+
+ if (_patch && plugin) {
+
+ _node = plugin->instantiate(_path.name(), _polyphonic, _patch, _engine);
+
+ if (_node != NULL) {
+ _node->activate();
+
+ // This can be done here because the audio thread doesn't touch the
+ // node tree - just the process order array
+ _patch->add_node(new PatchImpl::Nodes::Node(_node));
+ //_node->add_to_store(_engine.engine_store());
+ _engine.engine_store()->add(_node);
+
+ // FIXME: not really necessary to build process order since it's not connected,
+ // just append to the list
+ if (_patch->enabled())
+ _compiled_patch = _patch->compile();
+ }
+ }
+ QueuedEvent::pre_process();
+}
+
+
+void
+CreateNodeEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_node != NULL) {
+ if (_patch->compiled_patch() != NULL)
+ _engine.maid()->push(_patch->compiled_patch());
+ _patch->compiled_patch(_compiled_patch);
+ }
+}
+
+
+void
+CreateNodeEvent::post_process()
+{
+ string msg;
+ if (_node_already_exists) {
+ msg = string("Could not create node - ").append(_path);// + " already exists.";
+ _responder->respond_error(msg);
+ } else if (_patch == NULL) {
+ msg = "Could not find patch '" + _path.parent() +"' for add_node.";
+ _responder->respond_error(msg);
+ } else if (_node == NULL) {
+ msg = "Unable to load node ";
+ msg += _path + " (you're missing the plugin ";
+ if (_plugin_uri != "")
+ msg += _plugin_uri;
+ else
+ msg += _plugin_lib + ":" + _plugin_label + " (" + _plugin_type + ")";
+ msg += ")";
+ _responder->respond_error(msg);
+ } else {
+ _responder->respond_ok();
+ _engine.broadcaster()->send_node(_node, true); // yes, send ports
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/CreateNodeEvent.hpp b/src/engine/events/CreateNodeEvent.hpp
new file mode 100644
index 00000000..c3ef6313
--- /dev/null
+++ b/src/engine/events/CreateNodeEvent.hpp
@@ -0,0 +1,81 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CREATENODEEVENT_H
+#define CREATENODEEVENT_H
+
+#include "QueuedEvent.hpp"
+#include <raul/Path.hpp>
+#include <string>
+using std::string;
+
+namespace Raul { template <typename T> class Array; }
+template<typename T> class TreeNode;
+
+namespace Ingen {
+
+class PatchImpl;
+class NodeImpl;
+class CompiledPatch;
+
+
+/** An event to load a Node and insert it into a Patch.
+ *
+ * \ingroup engine
+ */
+class CreateNodeEvent : public QueuedEvent
+{
+public:
+ CreateNodeEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& node_path,
+ const string& plugin_uri,
+ bool poly);
+
+ // DEPRECATED
+ CreateNodeEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& node_path,
+ const string& plugin_type,
+ const string& lib_name,
+ const string& plugin_label,
+ bool poly);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ string _patch_name;
+ Raul::Path _path;
+ string _plugin_uri; ///< If nonempty then type, library, label, are ignored
+ string _plugin_type;
+ string _plugin_lib;
+ string _plugin_label;
+ bool _polyphonic;
+ PatchImpl* _patch;
+ NodeImpl* _node;
+ CompiledPatch* _compiled_patch; ///< Patch's new process order
+ bool _node_already_exists;
+};
+
+
+} // namespace Ingen
+
+#endif // CREATENODEEVENT_H
diff --git a/src/engine/events/CreatePatchEvent.cpp b/src/engine/events/CreatePatchEvent.cpp
new file mode 100644
index 00000000..64fe5c63
--- /dev/null
+++ b/src/engine/events/CreatePatchEvent.cpp
@@ -0,0 +1,157 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <raul/Maid.hpp>
+#include <raul/Path.hpp>
+#include "CreatePatchEvent.hpp"
+#include "Responder.hpp"
+#include "PatchImpl.hpp"
+#include "NodeImpl.hpp"
+#include "PluginImpl.hpp"
+#include "Engine.hpp"
+#include "ClientBroadcaster.hpp"
+#include "AudioDriver.hpp"
+#include "EngineStore.hpp"
+
+namespace Ingen {
+
+
+CreatePatchEvent::CreatePatchEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& path, int poly)
+: QueuedEvent(engine, responder, timestamp),
+ _path(path),
+ _patch(NULL),
+ _parent(NULL),
+ _compiled_patch(NULL),
+ _poly(poly),
+ _error(NO_ERROR)
+{
+}
+
+
+void
+CreatePatchEvent::pre_process()
+{
+ if (!Path::is_valid(_path)) {
+ _error = INVALID_PATH;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if (_path == "/" || _engine.engine_store()->find_object(_path) != NULL) {
+ _error = OBJECT_EXISTS;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if (_poly < 1) {
+ _error = INVALID_POLY;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ const Path& path = (const Path&)_path;
+
+ _parent = _engine.engine_store()->find_patch(path.parent());
+ if (_parent == NULL) {
+ _error = PARENT_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ uint32_t poly = 1;
+ if (_parent != NULL && _poly > 1 && _poly == static_cast<int>(_parent->internal_polyphony()))
+ poly = _poly;
+
+ _patch = new PatchImpl(_engine, path.name(), poly, _parent, _engine.audio_driver()->sample_rate(), _engine.audio_driver()->buffer_size(), _poly);
+
+ if (_parent != NULL) {
+ _parent->add_node(new PatchImpl::Nodes::Node(_patch));
+
+ if (_parent->enabled())
+ _compiled_patch = _parent->compile();
+ }
+
+ _patch->activate();
+
+ // Insert into EngineStore
+ //_patch->add_to_store(_engine.engine_store());
+ _engine.engine_store()->add(_patch);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+CreatePatchEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_patch != NULL) {
+ if (_parent == NULL) {
+ assert(_path == "/");
+ assert(_patch->parent_patch() == NULL);
+ _engine.audio_driver()->set_root_patch(_patch);
+ } else {
+ assert(_parent != NULL);
+ assert(_path != "/");
+
+ if (_parent->compiled_patch() != NULL)
+ _engine.maid()->push(_parent->compiled_patch());
+ _parent->compiled_patch(_compiled_patch);
+ }
+ }
+}
+
+
+void
+CreatePatchEvent::post_process()
+{
+ if (_responder.get()) {
+ if (_error == NO_ERROR) {
+
+ _responder->respond_ok();
+
+ // Don't send ports/nodes that have been added since prepare()
+ // (otherwise they would be sent twice)
+ _engine.broadcaster()->send_patch(_patch, false);
+
+ } else if (_error == INVALID_PATH) {
+ string msg = "Attempt to create patch with illegal path ";
+ msg.append(_path);
+ _responder->respond_error(msg);
+ } else if (_error == OBJECT_EXISTS) {
+ _responder->respond_ok();
+ /*string msg = "Unable to create patch: ";
+ msg.append(_path).append(" already exists.");
+ _responder->respond_error(msg);*/
+ } else if (_error == PARENT_NOT_FOUND) {
+ string msg = "Unable to create patch: Parent ";
+ msg.append(Path(_path).parent()).append(" not found.");
+ _responder->respond_error(msg);
+ } else if (_error == INVALID_POLY) {
+ string msg = "Unable to create patch ";
+ msg.append(_path).append(": ").append("Invalid polyphony respondered.");
+ _responder->respond_error(msg);
+ } else {
+ _responder->respond_error("Unable to load patch.");
+ }
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/CreatePatchEvent.hpp b/src/engine/events/CreatePatchEvent.hpp
new file mode 100644
index 00000000..733aba17
--- /dev/null
+++ b/src/engine/events/CreatePatchEvent.hpp
@@ -0,0 +1,64 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CREATEPATCHEVENT_H
+#define CREATEPATCHEVENT_H
+
+#include <string>
+#include <raul/Path.hpp>
+#include "QueuedEvent.hpp"
+
+using std::string;
+
+namespace Raul { template<typename T> class Array; }
+template<typename T> class TreeNode;
+
+namespace Ingen {
+
+class PatchImpl;
+class CompiledPatch;
+
+
+/** Creates a new Patch.
+ *
+ * \ingroup engine
+ */
+class CreatePatchEvent : public QueuedEvent
+{
+public:
+ CreatePatchEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& path, int poly);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ enum ErrorType { NO_ERROR, OBJECT_EXISTS, PARENT_NOT_FOUND, INVALID_POLY, INVALID_PATH };
+
+ const std::string _path;
+ PatchImpl* _patch;
+ PatchImpl* _parent;
+ CompiledPatch* _compiled_patch;
+ int _poly;
+ ErrorType _error;
+};
+
+
+} // namespace Ingen
+
+
+#endif // CREATEPATCHEVENT_H
diff --git a/src/engine/events/CreatePortEvent.cpp b/src/engine/events/CreatePortEvent.cpp
new file mode 100644
index 00000000..e767f522
--- /dev/null
+++ b/src/engine/events/CreatePortEvent.cpp
@@ -0,0 +1,173 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <raul/Path.hpp>
+#include <raul/Array.hpp>
+#include <raul/List.hpp>
+#include <raul/Maid.hpp>
+#include "Responder.hpp"
+#include "CreatePortEvent.hpp"
+#include "PatchImpl.hpp"
+#include "PluginImpl.hpp"
+#include "Engine.hpp"
+#include "PatchImpl.hpp"
+#include "QueuedEventSource.hpp"
+#include "EngineStore.hpp"
+#include "ClientBroadcaster.hpp"
+#include "PortImpl.hpp"
+#include "AudioDriver.hpp"
+#include "MidiDriver.hpp"
+#include "OSCDriver.hpp"
+#include "DuplexPort.hpp"
+
+namespace Ingen {
+
+
+CreatePortEvent::CreatePortEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& path,
+ const string& type,
+ bool is_output,
+ QueuedEventSource* source)
+: QueuedEvent(engine, responder, timestamp, true, source),
+ _error(NO_ERROR),
+ _path(path),
+ _type(type),
+ _is_output(is_output),
+ _data_type(type),
+ _patch(NULL),
+ _patch_port(NULL),
+ _driver_port(NULL)
+{
+ /* This is blocking because of the two different sets of Patch ports, the array used in the
+ * audio thread (inherited from NodeBase), and the arrays used in the pre processor thread.
+ * If two add port events arrive in the same cycle and the second pre processes before the
+ * first executes, bad things happen (ports are lost).
+ *
+ * FIXME: fix this using RCU
+ */
+
+ if (_data_type == DataType::UNKNOWN) {
+ cerr << "[CreatePortEvent] Unknown port type " << type << endl;
+ _error = UNKNOWN_TYPE;
+ }
+}
+
+
+void
+CreatePortEvent::pre_process()
+{
+ if (_error == UNKNOWN_TYPE || _engine.engine_store()->find_object(_path)) {
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ // FIXME: this is just a mess :/
+
+ _patch = _engine.engine_store()->find_patch(_path.parent());
+
+ if (_patch != NULL) {
+ assert(_patch->path() == _path.parent());
+
+ size_t buffer_size = 1;
+ if (_type != "ingen:Float")
+ buffer_size = _engine.audio_driver()->buffer_size();
+
+ const uint32_t old_num_ports = _patch->num_ports();
+
+ _patch_port = _patch->create_port(_path.name(), _data_type, buffer_size, _is_output);
+
+ if (_patch_port) {
+
+ if (_is_output)
+ _patch->add_output(new Raul::List<PortImpl*>::Node(_patch_port));
+ else
+ _patch->add_input(new Raul::List<PortImpl*>::Node(_patch_port));
+
+ if (_patch->external_ports())
+ _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, *_patch->external_ports());
+ else
+ _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, NULL);
+
+
+ _ports_array->at(_patch->num_ports()-1) = _patch_port;
+ //_patch_port->add_to_store(_engine.engine_store());
+ _engine.engine_store()->add(_patch_port);
+
+ if (!_patch->parent()) {
+ if (_type == "ingen:AudioPort")
+ _driver_port = _engine.audio_driver()->create_port(
+ dynamic_cast<DuplexPort*>(_patch_port));
+ else if (_type == "ingen:MIDIPort" || _type == "ingen:EventPort")
+ _driver_port = _engine.midi_driver()->create_port(
+ dynamic_cast<DuplexPort*>(_patch_port));
+ else if (_type == "ingen:OSCPort" && _engine.osc_driver())
+ _driver_port = _engine.osc_driver()->create_port(
+ dynamic_cast<DuplexPort*>(_patch_port));
+ }
+
+ assert(_ports_array->size() == _patch->num_ports());
+
+ }
+ }
+ QueuedEvent::pre_process();
+}
+
+
+void
+CreatePortEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_patch_port) {
+
+ _engine.maid()->push(_patch->external_ports());
+ //_patch->add_port(_port);
+
+ _patch->external_ports(_ports_array);
+ }
+
+ if (_driver_port) {
+ if (_type == "ingen:AudioPort")
+ _engine.audio_driver()->add_port(_driver_port);
+ else if (_type == "ingen:MIDIPort" || _type == "ingen:EventPort")
+ _engine.midi_driver()->add_port(_driver_port);
+ else if (_type == "ingen:OSCPort")
+ cerr << "OSC DRIVER PORT" << endl;
+ }
+
+ if (_source)
+ _source->unblock();
+}
+
+
+void
+CreatePortEvent::post_process()
+{
+ if (_error != NO_ERROR || !_patch_port) {
+ const string msg = string("Could not create port - ").append(_path);
+ _responder->respond_error(msg);
+ } else {
+ _responder->respond_ok();
+ _engine.broadcaster()->send_port(_patch_port);
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/CreatePortEvent.hpp b/src/engine/events/CreatePortEvent.hpp
new file mode 100644
index 00000000..5ddd8aa3
--- /dev/null
+++ b/src/engine/events/CreatePortEvent.hpp
@@ -0,0 +1,72 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CREATEPORTEVENT_H
+#define CREATEPORTEVENT_H
+
+#include "QueuedEvent.hpp"
+#include <raul/Path.hpp>
+#include <raul/Array.hpp>
+#include "interface/DataType.hpp"
+#include <string>
+using std::string;
+
+template <typename T> class Array;
+
+namespace Ingen {
+
+class PatchImpl;
+class PortImpl;
+class DriverPort;
+
+
+/** An event to add a Port to a Patch.
+ *
+ * \ingroup engine
+ */
+class CreatePortEvent : public QueuedEvent
+{
+public:
+ CreatePortEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output, QueuedEventSource* source);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+
+ enum ErrorType {
+ NO_ERROR,
+ UNKNOWN_TYPE
+ };
+
+ ErrorType _error;
+ Raul::Path _path;
+ string _type;
+ bool _is_output;
+ DataType _data_type;
+ PatchImpl* _patch;
+ PortImpl* _patch_port;
+ Raul::Array<PortImpl*>* _ports_array; ///< New (external) ports array for Patch
+ DriverPort* _driver_port; ///< Driver (eg Jack) port if this is a toplevel port
+ bool _succeeded;
+};
+
+
+} // namespace Ingen
+
+#endif // CREATEPORTEVENT_H
diff --git a/src/engine/events/DeactivateEvent.cpp b/src/engine/events/DeactivateEvent.cpp
new file mode 100644
index 00000000..a68419f0
--- /dev/null
+++ b/src/engine/events/DeactivateEvent.cpp
@@ -0,0 +1,54 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "DeactivateEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+
+namespace Ingen {
+
+
+DeactivateEvent::DeactivateEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp)
+: QueuedEvent(engine, responder, timestamp)
+{
+}
+
+
+void
+DeactivateEvent::pre_process()
+{
+ QueuedEvent::pre_process();
+}
+
+
+void
+DeactivateEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+}
+
+
+void
+DeactivateEvent::post_process()
+{
+ _responder->respond_ok();
+ _engine.deactivate();
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/DeactivateEvent.hpp b/src/engine/events/DeactivateEvent.hpp
new file mode 100644
index 00000000..5a6750ba
--- /dev/null
+++ b/src/engine/events/DeactivateEvent.hpp
@@ -0,0 +1,43 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DEACTIVATEEVENT_H
+#define DEACTIVATEEVENT_H
+
+#include "QueuedEvent.hpp"
+
+namespace Ingen {
+
+
+/** Deactivates the engine.
+ *
+ * \ingroup engine
+ */
+class DeactivateEvent : public QueuedEvent
+{
+public:
+ DeactivateEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+};
+
+
+} // namespace Ingen
+
+#endif // DEACTIVATEEVENT_H
diff --git a/src/engine/events/DestroyEvent.cpp b/src/engine/events/DestroyEvent.cpp
new file mode 100644
index 00000000..07770c0a
--- /dev/null
+++ b/src/engine/events/DestroyEvent.cpp
@@ -0,0 +1,201 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <raul/Maid.hpp>
+#include <raul/Path.hpp>
+#include "DestroyEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PatchImpl.hpp"
+#include "NodeBase.hpp"
+#include "PluginImpl.hpp"
+#include "AudioDriver.hpp"
+#include "MidiDriver.hpp"
+#include "DisconnectAllEvent.hpp"
+#include "ClientBroadcaster.hpp"
+#include "EngineStore.hpp"
+#include "QueuedEventSource.hpp"
+#include "PortImpl.hpp"
+
+namespace Ingen {
+
+
+DestroyEvent::DestroyEvent(Engine& engine, SharedPtr<Responder> responder, FrameTime time, QueuedEventSource* source, const string& path, bool block)
+ : QueuedEvent(engine, responder, time, source, source)
+ , _path(path)
+ , _store_iterator(engine.engine_store()->end())
+ , _driver_port(NULL)
+ , _patch_node_listnode(NULL)
+ , _patch_port_listnode(NULL)
+ , _ports_array(NULL)
+ , _compiled_patch(NULL)
+ , _disconnect_event(NULL)
+{
+ assert(_source);
+}
+
+
+DestroyEvent::~DestroyEvent()
+{
+ delete _disconnect_event;
+}
+
+
+void
+DestroyEvent::pre_process()
+{
+ _store_iterator = _engine.engine_store()->find(_path);
+
+ if (_store_iterator != _engine.engine_store()->end()) {
+ _node = PtrCast<NodeImpl>(_store_iterator->second);
+
+ if (!_node)
+ _port = PtrCast<PortImpl>(_store_iterator->second);
+ }
+
+ if (_store_iterator != _engine.engine_store()->end()) {
+ _removed_table = _engine.engine_store()->remove(_store_iterator);
+ }
+
+ if (_node != NULL && _path != "/") {
+ assert(_node->parent_patch());
+ _patch_node_listnode = _node->parent_patch()->remove_node(_path.name());
+ if (_patch_node_listnode) {
+ assert(_patch_node_listnode->elem() == _node.get());
+
+ _disconnect_event = new DisconnectAllEvent(_engine, _node->parent_patch(), _node.get());
+ _disconnect_event->pre_process();
+
+ if (_node->parent_patch()->enabled()) {
+ // FIXME: is this called multiple times?
+ _compiled_patch = _node->parent_patch()->compile();
+#ifndef NDEBUG
+ // Be sure node is removed from process order, so it can be destroyed
+ for (size_t i=0; i < _compiled_patch->size(); ++i) {
+ assert(_compiled_patch->at(i).node() != _node.get());
+ // FIXME: check providers/dependants too
+ }
+#endif
+ }
+ }
+ } else if (_port) {
+ assert(_port->parent_patch());
+ _patch_port_listnode = _port->parent_patch()->remove_port(_path.name());
+ if (_patch_port_listnode) {
+ assert(_patch_port_listnode->elem() == _port.get());
+
+ _disconnect_event = new DisconnectAllEvent(_engine, _port->parent_patch(), _port.get());
+ _disconnect_event->pre_process();
+
+ if (_port->parent_patch()->enabled()) {
+ // FIXME: is this called multiple times?
+ _compiled_patch = _port->parent_patch()->compile();
+ _ports_array = _port->parent_patch()->build_ports_array();
+ assert(_ports_array->size() == _port->parent_patch()->num_ports());
+ }
+ }
+
+ }
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+DestroyEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_patch_node_listnode) {
+ assert(_node);
+
+ if (_disconnect_event)
+ _disconnect_event->execute(context);
+
+ if (_node->parent_patch()->compiled_patch())
+ _engine.maid()->push(_node->parent_patch()->compiled_patch());
+ _node->parent_patch()->compiled_patch(_compiled_patch);
+
+ } else if (_patch_port_listnode) {
+ assert(_port);
+
+ if (_disconnect_event)
+ _disconnect_event->execute(context);
+
+ if (_port->parent_patch()->compiled_patch())
+ _engine.maid()->push(_port->parent_patch()->compiled_patch());
+
+ _port->parent_patch()->compiled_patch(_compiled_patch);
+
+ if (_port->parent_patch()->external_ports())
+ _engine.maid()->push(_port->parent_patch()->external_ports());
+
+ _port->parent_patch()->external_ports(_ports_array);
+
+ if ( ! _port->parent_patch()->parent()) {
+ if (_port->type() == DataType::AUDIO)
+ _driver_port = _engine.audio_driver()->remove_port(_port->path());
+ else if (_port->type() == DataType::EVENT)
+ _driver_port = _engine.midi_driver()->remove_port(_port->path());
+ }
+ }
+
+ if (_source)
+ _source->unblock();
+}
+
+
+void
+DestroyEvent::post_process()
+{
+ if (!_node && !_port) {
+ if (_path == "/") {
+ _responder->respond_error("You can not destroy the root patch (/)");
+ } else {
+ string msg = string("Could not find object ") + _path + " to destroy";
+ _responder->respond_error(msg);
+ }
+ }
+
+ if (_patch_node_listnode) {
+ assert(_node);
+ _node->deactivate();
+ _responder->respond_ok();
+ _engine.broadcaster()->bundle_begin();
+ if (_disconnect_event)
+ _disconnect_event->post_process();
+ _engine.broadcaster()->send_destroyed(_path);
+ _engine.broadcaster()->bundle_end();
+ _engine.maid()->push(_patch_node_listnode);
+ } else if (_patch_port_listnode) {
+ assert(_port);
+ _responder->respond_ok();
+ _engine.broadcaster()->bundle_begin();
+ if (_disconnect_event)
+ _disconnect_event->post_process();
+ _engine.broadcaster()->send_destroyed(_path);
+ _engine.broadcaster()->bundle_end();
+ _engine.maid()->push(_patch_port_listnode);
+ } else {
+ _responder->respond_error("Unable to destroy object");
+ }
+
+ delete _driver_port;
+}
+
+
+} // namespace Ingen
diff --git a/src/engine/events/DestroyEvent.hpp b/src/engine/events/DestroyEvent.hpp
new file mode 100644
index 00000000..b24934f8
--- /dev/null
+++ b/src/engine/events/DestroyEvent.hpp
@@ -0,0 +1,77 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DESTROYEVENT_H
+#define DESTROYEVENT_H
+
+#include <string>
+#include <raul/Path.hpp>
+#include "QueuedEvent.hpp"
+#include "EngineStore.hpp"
+#include "PatchImpl.hpp"
+
+using std::string;
+
+namespace Raul {
+ template<typename T> class Array;
+ template<typename T> class ListNode;
+}
+template<typename T> class TreeNode;
+
+namespace Ingen {
+
+class GraphObjectImpl;
+class NodeImpl;
+class PortImpl;
+class DriverPort;
+class DisconnectAllEvent;
+class CompiledPatch;
+
+
+/** An event to remove and delete a Node.
+ *
+ * \ingroup engine
+ */
+class DestroyEvent : public QueuedEvent
+{
+public:
+ DestroyEvent(Engine& engine, SharedPtr<Responder> responder, FrameTime timestamp, QueuedEventSource* source, const string& path, bool block = true);
+ ~DestroyEvent();
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ Path _path;
+ EngineStore::iterator _store_iterator;
+ SharedPtr<NodeImpl> _node; ///< Non-NULL iff a node
+ SharedPtr<PortImpl> _port; ///< Non-NULL iff a port
+ DriverPort* _driver_port;
+ PatchImpl::Nodes::Node* _patch_node_listnode;
+ Raul::List<PortImpl*>::Node* _patch_port_listnode;
+ Raul::Array<PortImpl*>* _ports_array; ///< New (external) ports for Patch
+ CompiledPatch* _compiled_patch; ///< Patch's new process order
+ DisconnectAllEvent* _disconnect_event;
+
+ SharedPtr< Table<Path, SharedPtr<Shared::GraphObject> > > _removed_table;
+};
+
+
+} // namespace Ingen
+
+#endif // DESTROYEVENT_H
diff --git a/src/engine/events/DisablePortMonitoringEvent.cpp b/src/engine/events/DisablePortMonitoringEvent.cpp
new file mode 100644
index 00000000..cecc8dfd
--- /dev/null
+++ b/src/engine/events/DisablePortMonitoringEvent.cpp
@@ -0,0 +1,87 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string>
+#include "interface/ClientInterface.hpp"
+#include "events/DisablePortMonitoringEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PortImpl.hpp"
+#include "EngineStore.hpp"
+#include "ClientBroadcaster.hpp"
+#include "AudioBuffer.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+
+DisablePortMonitoringEvent::DisablePortMonitoringEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const std::string& port_path)
+: QueuedEvent(engine, responder, timestamp),
+ _port_path(port_path),
+ _port(NULL)
+{
+}
+
+
+void
+DisablePortMonitoringEvent::pre_process()
+{
+ _port = _engine.engine_store()->find_port(_port_path);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+DisablePortMonitoringEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+#if 0
+ assert(_time >= start && _time <= end);
+
+ if (_port != NULL && _port->type() == DataType::FLOAT)
+ _value = ((AudioBuffer*)_port->buffer(0))->value_at(0/*_time - start*/);
+ else
+ _port = NULL; // triggers error response
+#endif
+}
+
+
+void
+DisablePortMonitoringEvent::post_process()
+{
+#if 0
+ string msg;
+ if (!_port) {
+ _responder->respond_error("Unable to find port for get_value responder.");
+ } else if (_responder->client()) {
+ _responder->respond_ok();
+ _responder->client()->control_change(_port_path, _value);
+ } else {
+ _responder->respond_error("Unable to find client to send port value");
+ }
+#endif
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/DisablePortMonitoringEvent.hpp b/src/engine/events/DisablePortMonitoringEvent.hpp
new file mode 100644
index 00000000..7a8e23f7
--- /dev/null
+++ b/src/engine/events/DisablePortMonitoringEvent.hpp
@@ -0,0 +1,58 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DISABLEPORTNOTIFICATIONEVENT_H
+#define DISABLEPORTNOTIFICATIONEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+#include "types.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+class PortImpl;
+namespace Shared { class ClientInterface; }
+using Shared::ClientInterface;
+
+
+/** Disable sending of dynamic value change notifications for a port.
+ *
+ * \ingroup engine
+ */
+class DisablePortMonitoringEvent : public QueuedEvent
+{
+public:
+ DisablePortMonitoringEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const std::string& port_path);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const std::string _port_path;
+ Port* _port;
+};
+
+
+} // namespace Ingen
+
+#endif // DISABLEPORTNOTIFICATIONEVENT_H
diff --git a/src/engine/events/DisconnectAllEvent.cpp b/src/engine/events/DisconnectAllEvent.cpp
new file mode 100644
index 00000000..77b1b1b3
--- /dev/null
+++ b/src/engine/events/DisconnectAllEvent.cpp
@@ -0,0 +1,183 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <boost/format.hpp>
+#include <raul/Array.hpp>
+#include <raul/List.hpp>
+#include <raul/Maid.hpp>
+#include <raul/Path.hpp>
+#include "ClientBroadcaster.hpp"
+#include "ConnectionImpl.hpp"
+#include "DisconnectAllEvent.hpp"
+#include "DisconnectionEvent.hpp"
+#include "Engine.hpp"
+#include "InputPort.hpp"
+#include "NodeImpl.hpp"
+#include "EngineStore.hpp"
+#include "OutputPort.hpp"
+#include "PatchImpl.hpp"
+#include "PortImpl.hpp"
+#include "Responder.hpp"
+#include "util.hpp"
+
+namespace Ingen {
+
+
+DisconnectAllEvent::DisconnectAllEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& parent_path, const string& node_path)
+ : QueuedEvent(engine, responder, timestamp)
+ , _parent_path(parent_path)
+ , _path(node_path)
+ , _parent(NULL)
+ , _node(NULL)
+ , _port(NULL)
+ , _lookup(true)
+ , _error(NO_ERROR)
+{
+}
+
+
+/** Internal version for use by other events.
+ */
+DisconnectAllEvent::DisconnectAllEvent(Engine& engine, PatchImpl* parent, GraphObjectImpl* object)
+ : QueuedEvent(engine)
+ , _parent_path(parent->path())
+ , _path(object->path())
+ , _parent(parent)
+ , _node(dynamic_cast<NodeImpl*>(object))
+ , _port(dynamic_cast<PortImpl*>(object))
+ , _lookup(false)
+ , _error(NO_ERROR)
+{
+}
+
+
+DisconnectAllEvent::~DisconnectAllEvent()
+{
+ for (Raul::List<DisconnectionEvent*>::iterator i = _disconnection_events.begin(); i != _disconnection_events.end(); ++i)
+ delete (*i);
+}
+
+
+void
+DisconnectAllEvent::pre_process()
+{
+ if (_lookup) {
+ _parent = _engine.engine_store()->find_patch(_parent_path);
+
+ if (_parent == NULL) {
+ _error = PARENT_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ GraphObjectImpl* object = _engine.engine_store()->find_object(_path);
+
+ if (object == NULL) {
+ _error = OBJECT_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if (object->parent_patch() != _parent && object->parent()->parent_patch() != _parent) {
+ _error = INVALID_PARENT_PATH;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ // Only one of these will succeed
+ _node = dynamic_cast<NodeImpl*>(object);
+ _port = dynamic_cast<PortImpl*>(object);
+
+ assert((_node || _port) && !(_node && _port));
+ }
+
+ if (_node) {
+ for (PatchImpl::Connections::const_iterator i = _parent->connections().begin();
+ i != _parent->connections().end(); ++i) {
+ ConnectionImpl* c = (ConnectionImpl*)i->get();
+ if ((c->src_port()->parent_node() == _node || c->dst_port()->parent_node() == _node)
+ && !c->pending_disconnection()) {
+ DisconnectionEvent* ev = new DisconnectionEvent(_engine,
+ SharedPtr<Responder>(new Responder()), _time, c->src_port(), c->dst_port());
+ ev->pre_process();
+ _disconnection_events.push_back(new Raul::List<DisconnectionEvent*>::Node(ev));
+ c->pending_disconnection(true);
+ }
+ }
+ } else { // _port
+ for (PatchImpl::Connections::const_iterator i = _parent->connections().begin();
+ i != _parent->connections().end(); ++i) {
+ ConnectionImpl* c = (ConnectionImpl*)i->get();
+ if ((c->src_port() == _port || c->dst_port() == _port) && !c->pending_disconnection()) {
+ DisconnectionEvent* ev = new DisconnectionEvent(_engine,
+ SharedPtr<Responder>(new Responder()), _time, c->src_port(), c->dst_port());
+ ev->pre_process();
+ _disconnection_events.push_back(new Raul::List<DisconnectionEvent*>::Node(ev));
+ c->pending_disconnection(true);
+ }
+ }
+ }
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+DisconnectAllEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_error == NO_ERROR) {
+ for (Raul::List<DisconnectionEvent*>::iterator i = _disconnection_events.begin(); i != _disconnection_events.end(); ++i)
+ (*i)->execute(context);
+ }
+}
+
+
+void
+DisconnectAllEvent::post_process()
+{
+ if (_error == NO_ERROR) {
+ if (_responder)
+ _responder->respond_ok();
+ for (Raul::List<DisconnectionEvent*>::iterator i = _disconnection_events.begin();
+ i != _disconnection_events.end(); ++i)
+ (*i)->post_process();
+ } else {
+ if (_responder) {
+ boost::format fmt("Unable to disconnect %1% (%2%)");
+ fmt % _path;
+ switch (_error) {
+ case INVALID_PARENT_PATH:
+ fmt % string("Invalid parent path: ").append(_parent_path);
+ break;
+ case PARENT_NOT_FOUND:
+ fmt % string("Unable to find parent: ").append(_parent_path);
+ break;
+ case OBJECT_NOT_FOUND:
+ fmt % string("Unable to find object");
+ default:
+ break;
+ }
+ _responder->respond_error(fmt.str());
+ }
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/DisconnectAllEvent.hpp b/src/engine/events/DisconnectAllEvent.hpp
new file mode 100644
index 00000000..6b75e6df
--- /dev/null
+++ b/src/engine/events/DisconnectAllEvent.hpp
@@ -0,0 +1,79 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DISCONNECTNODEEVENT_H
+#define DISCONNECTNODEEVENT_H
+
+#include <string>
+#include <raul/List.hpp>
+#include <raul/Path.hpp>
+#include "QueuedEvent.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+class DisconnectionEvent;
+class PatchImpl;
+class NodeImpl;
+class Connection;
+class PortImpl;
+class InputPort;
+class OutputPort;
+
+
+/** An event to disconnect all connections to a Node.
+ *
+ * \ingroup engine
+ */
+class DisconnectAllEvent : public QueuedEvent
+{
+public:
+ DisconnectAllEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& parent_path, const string& node_path);
+ DisconnectAllEvent(Engine& engine, PatchImpl* parent, GraphObjectImpl* object);
+ ~DisconnectAllEvent();
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ enum ErrorType {
+ NO_ERROR,
+ INVALID_PARENT_PATH,
+ PARENT_NOT_FOUND,
+ OBJECT_NOT_FOUND,
+ };
+
+ Raul::Path _parent_path;
+ Raul::Path _path;
+ PatchImpl* _parent;
+ NodeImpl* _node;
+ PortImpl* _port;
+ Raul::List<DisconnectionEvent*> _disconnection_events;
+
+ bool _lookup;
+ bool _disconnect_parent;
+
+ ErrorType _error;
+};
+
+
+} // namespace Ingen
+
+
+#endif // DISCONNECTNODEEVENT_H
diff --git a/src/engine/events/DisconnectionEvent.cpp b/src/engine/events/DisconnectionEvent.cpp
new file mode 100644
index 00000000..86ad8b4e
--- /dev/null
+++ b/src/engine/events/DisconnectionEvent.cpp
@@ -0,0 +1,213 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "DisconnectionEvent.hpp"
+#include <string>
+#include <raul/Maid.hpp>
+#include <raul/Path.hpp>
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "ConnectionImpl.hpp"
+#include "InputPort.hpp"
+#include "OutputPort.hpp"
+#include "PatchImpl.hpp"
+#include "ClientBroadcaster.hpp"
+#include "PortImpl.hpp"
+#include "EngineStore.hpp"
+
+using std::string;
+namespace Ingen {
+
+
+//// DisconnectionEvent ////
+
+
+DisconnectionEvent::DisconnectionEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path)
+: QueuedEvent(engine, responder, timestamp),
+ _src_port_path(src_port_path),
+ _dst_port_path(dst_port_path),
+ _patch(NULL),
+ _src_port(NULL),
+ _dst_port(NULL),
+ _lookup(true),
+ _patch_connection(NULL),
+ _compiled_patch(NULL),
+ _error(NO_ERROR)
+{
+}
+
+
+DisconnectionEvent::DisconnectionEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, PortImpl* const src_port, PortImpl* const dst_port)
+: QueuedEvent(engine, responder, timestamp),
+ _src_port_path(src_port->path()),
+ _dst_port_path(dst_port->path()),
+ _patch(src_port->parent_node()->parent_patch()),
+ _src_port(src_port),
+ _dst_port(dst_port),
+ _lookup(false),
+ _compiled_patch(NULL),
+ _error(NO_ERROR)
+{
+ // FIXME: These break for patch ports.. is that ok?
+ /*assert(src_port->is_output());
+ assert(dst_port->is_input());
+ assert(src_port->type() == dst_port->type());
+ assert(src_port->parent_node()->parent_patch()
+ == dst_port->parent_node()->parent_patch()); */
+}
+
+
+void
+DisconnectionEvent::pre_process()
+{
+ if (_lookup) {
+ if (_src_port_path.parent().parent() != _dst_port_path.parent().parent()
+ && _src_port_path.parent() != _dst_port_path.parent().parent()
+ && _src_port_path.parent().parent() != _dst_port_path.parent()) {
+ _error = PARENT_PATCH_DIFFERENT;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ _src_port = _engine.engine_store()->find_port(_src_port_path);
+ _dst_port = _engine.engine_store()->find_port(_dst_port_path);
+ }
+
+ if (_src_port == NULL || _dst_port == NULL) {
+ _error = PORT_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ _dst_input_port = dynamic_cast<InputPort*>(_dst_port);
+ _src_output_port = dynamic_cast<OutputPort*>(_src_port);
+ assert(_src_output_port);
+ assert(_dst_input_port);
+
+ NodeImpl* const src_node = _src_port->parent_node();
+ NodeImpl* const dst_node = _dst_port->parent_node();
+
+ // Connection to a patch port from inside the patch
+ if (src_node->parent_patch() != dst_node->parent_patch()) {
+
+ assert(src_node->parent() == dst_node || dst_node->parent() == src_node);
+ if (src_node->parent() == dst_node)
+ _patch = dynamic_cast<PatchImpl*>(dst_node);
+ else
+ _patch = dynamic_cast<PatchImpl*>(src_node);
+
+ // Connection from a patch input to a patch output (pass through)
+ } else if (src_node == dst_node && dynamic_cast<PatchImpl*>(src_node)) {
+ _patch = dynamic_cast<PatchImpl*>(src_node);
+
+ // Normal connection between nodes with the same parent
+ } else {
+ _patch = src_node->parent_patch();
+ }
+
+ assert(_patch);
+
+ //if (_dst_input_port->is_connected_to(_src_output_port)) {
+ if (!_patch->has_connection(_src_output_port, _dst_input_port)) {
+ _error = NOT_CONNECTED;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if (src_node == NULL || dst_node == NULL) {
+ _error = PARENTS_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ for (Raul::List<NodeImpl*>::iterator i = dst_node->providers()->begin(); i != dst_node->providers()->end(); ++i)
+ if ((*i) == src_node) {
+ delete dst_node->providers()->erase(i);
+ break;
+ }
+
+ for (Raul::List<NodeImpl*>::iterator i = src_node->dependants()->begin(); i != src_node->dependants()->end(); ++i)
+ if ((*i) == dst_node) {
+ delete src_node->dependants()->erase(i);
+ break;
+ }
+
+ _patch_connection = _patch->remove_connection(_src_port, _dst_port);
+
+ if (_patch->enabled())
+ _compiled_patch = _patch->compile();
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+DisconnectionEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_error == NO_ERROR) {
+ InputPort::Connections::Node* const port_connection
+ = _dst_input_port->remove_connection(_src_output_port);
+
+ if (port_connection != NULL) {
+ assert(_patch_connection);
+
+ if (port_connection->elem() != _patch_connection->elem()) {
+ cerr << "ERROR: Corrupt connections:" << endl;
+ cerr << "\t" << port_connection->elem() << ": "
+ << port_connection->elem()->src_port_path()
+ << " -> " << port_connection->elem()->dst_port_path() << endl
+ << "!=" << endl
+ << "\t" << _patch_connection->elem() << ": "
+ << _patch_connection->elem()->src_port_path()
+ << " -> " << _patch_connection->elem()->dst_port_path() << endl;
+ }
+ assert(port_connection->elem() == _patch_connection->elem());
+
+ // Destroy list node, which will drop reference to connection itself
+ _engine.maid()->push(port_connection);
+ _engine.maid()->push(_patch_connection);
+
+ if (_patch->compiled_patch() != NULL)
+ _engine.maid()->push(_patch->compiled_patch());
+ _patch->compiled_patch(_compiled_patch);
+ } else {
+ _error = CONNECTION_NOT_FOUND;
+ }
+ }
+}
+
+
+void
+DisconnectionEvent::post_process()
+{
+ if (_error == NO_ERROR) {
+ _responder->respond_ok();
+ _engine.broadcaster()->send_disconnection(_src_port->path(), _dst_port->path());
+ } else {
+ // FIXME: better error messages
+ string msg = "Unable to disconnect ";
+ msg.append(_src_port_path + " -> " + _dst_port_path);
+ cerr << "DISCONNECTION ERROR " << (unsigned)_error << endl;
+ _responder->respond_error(msg);
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/DisconnectionEvent.hpp b/src/engine/events/DisconnectionEvent.hpp
new file mode 100644
index 00000000..700febeb
--- /dev/null
+++ b/src/engine/events/DisconnectionEvent.hpp
@@ -0,0 +1,90 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DISCONNECTIONEVENT_H
+#define DISCONNECTIONEVENT_H
+
+#include <string>
+#include <raul/Path.hpp>
+#include "QueuedEvent.hpp"
+#include "types.hpp"
+#include "PatchImpl.hpp"
+using std::string;
+
+namespace Raul {
+ template <typename T> class ListNode;
+ template <typename T> class Array;
+}
+
+namespace Ingen {
+
+class NodeImpl;
+class ConnectionImpl;
+class MidiMessage;
+class PortImpl;
+class InputPort;
+class OutputPort;
+class CompiledPatch;
+
+
+/** Make a Connection between two Ports.
+ *
+ * \ingroup engine
+ */
+class DisconnectionEvent : public QueuedEvent
+{
+public:
+ DisconnectionEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path);
+ DisconnectionEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, PortImpl* const src_port, PortImpl* const dst_port);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+
+ enum ErrorType {
+ NO_ERROR,
+ PARENT_PATCH_DIFFERENT,
+ PORT_NOT_FOUND,
+ TYPE_MISMATCH,
+ NOT_CONNECTED,
+ PARENTS_NOT_FOUND,
+ CONNECTION_NOT_FOUND
+ };
+
+ Raul::Path _src_port_path;
+ Raul::Path _dst_port_path;
+
+ PatchImpl* _patch;
+ PortImpl* _src_port;
+ PortImpl* _dst_port;
+ OutputPort* _src_output_port;
+ InputPort* _dst_input_port;
+
+ bool _lookup;
+
+ PatchImpl::Connections::Node* _patch_connection;
+ CompiledPatch* _compiled_patch; ///< New process order for Patch
+
+ ErrorType _error;
+};
+
+
+} // namespace Ingen
+
+#endif // DISCONNECTIONEVENT_H
diff --git a/src/engine/events/EnablePatchEvent.cpp b/src/engine/events/EnablePatchEvent.cpp
new file mode 100644
index 00000000..04759cea
--- /dev/null
+++ b/src/engine/events/EnablePatchEvent.cpp
@@ -0,0 +1,86 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "EnablePatchEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PatchImpl.hpp"
+#include "util.hpp"
+#include "ClientBroadcaster.hpp"
+#include "EngineStore.hpp"
+
+namespace Ingen {
+
+
+EnablePatchEvent::EnablePatchEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& patch_path, bool enable)
+: QueuedEvent(engine, responder, timestamp),
+ _patch_path(patch_path),
+ _patch(NULL),
+ _compiled_patch(NULL),
+ _enable(enable)
+{
+}
+
+
+void
+EnablePatchEvent::pre_process()
+{
+ _patch = _engine.engine_store()->find_patch(_patch_path);
+
+ if (_enable && _patch) {
+ /* Any event that requires a new process order will set the patch's
+ * compiled_patch to NULL if it is executed when the patch is not
+ * active. So, if the CP is NULL, calculate it here */
+ if (_patch->compiled_patch() == NULL)
+ _compiled_patch = _patch->compile();
+ }
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+EnablePatchEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_patch != NULL) {
+ if (_enable)
+ _patch->enable();
+ else
+ _patch->disable();
+
+ if (_enable && _patch->compiled_patch() == NULL)
+ _patch->compiled_patch(_compiled_patch);
+ }
+}
+
+
+void
+EnablePatchEvent::post_process()
+{
+ if (_patch != NULL) {
+ _responder->respond_ok();
+ _engine.broadcaster()->send_property_change(_patch_path, "ingen:enabled", (bool)_enable);
+ } else {
+ _responder->respond_error(string("Patch ") + _patch_path + " not found");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/EnablePatchEvent.hpp b/src/engine/events/EnablePatchEvent.hpp
new file mode 100644
index 00000000..dad1803a
--- /dev/null
+++ b/src/engine/events/EnablePatchEvent.hpp
@@ -0,0 +1,63 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ENABLEPATCHEVENT_H
+#define ENABLEPATCHEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+
+using std::string;
+
+namespace Raul { template <typename T> class Array; }
+
+namespace Ingen {
+
+class PatchImpl;
+class NodeImpl;
+class CompiledPatch;
+
+
+/** Enables a patch's DSP processing.
+ *
+ * \ingroup engine
+ */
+class EnablePatchEvent : public QueuedEvent
+{
+public:
+ EnablePatchEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& patch_path,
+ bool enable);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ string _patch_path;
+ PatchImpl* _patch;
+ CompiledPatch* _compiled_patch; // Patch's new process order
+ bool _enable;
+};
+
+
+} // namespace Ingen
+
+
+#endif // ENABLEPATCHEVENT_H
diff --git a/src/engine/events/LoadPluginsEvent.cpp b/src/engine/events/LoadPluginsEvent.cpp
new file mode 100644
index 00000000..df5ff5d9
--- /dev/null
+++ b/src/engine/events/LoadPluginsEvent.cpp
@@ -0,0 +1,56 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "LoadPluginsEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "NodeFactory.hpp"
+#include "ClientBroadcaster.hpp"
+#include "QueuedEventSource.hpp"
+
+#include <iostream>
+using std::cerr;
+
+namespace Ingen {
+
+
+LoadPluginsEvent::LoadPluginsEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, QueuedEventSource* source)
+: QueuedEvent(engine, responder, timestamp, true, source)
+{
+ /* FIXME: Not sure why this has to be blocking, but it fixes some nasty bugs.. */
+}
+
+void
+LoadPluginsEvent::pre_process()
+{
+ _engine.node_factory()->load_plugins();
+
+ QueuedEvent::pre_process();
+}
+
+void
+LoadPluginsEvent::post_process()
+{
+ if (_source)
+ _source->unblock();
+
+ _responder->respond_ok();
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/LoadPluginsEvent.hpp b/src/engine/events/LoadPluginsEvent.hpp
new file mode 100644
index 00000000..cd9a2884
--- /dev/null
+++ b/src/engine/events/LoadPluginsEvent.hpp
@@ -0,0 +1,46 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LOADPLUGINSEVENT_H
+#define LOADPLUGINSEVENT_H
+
+#include <list>
+#include "QueuedEvent.hpp"
+
+namespace Ingen {
+
+
+/** Loads all plugins into the internal plugin database (in NodeFactory).
+ *
+ * \ingroup engine
+ */
+class LoadPluginsEvent : public QueuedEvent
+{
+public:
+ LoadPluginsEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ QueuedEventSource* source);
+
+ void pre_process();
+ void post_process();
+};
+
+
+} // namespace Ingen
+
+#endif // LOADPLUGINSEVENT_H
diff --git a/src/engine/events/Makefile.am b/src/engine/events/Makefile.am
new file mode 100644
index 00000000..9a8cfbd5
--- /dev/null
+++ b/src/engine/events/Makefile.am
@@ -0,0 +1,63 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+EXTRA_DIST = \
+ AllNotesOffEvent.cpp \
+ AllNotesOffEvent.hpp \
+ ClearPatchEvent.cpp \
+ ClearPatchEvent.hpp \
+ ConnectionEvent.cpp \
+ ConnectionEvent.hpp \
+ CreateNodeEvent.cpp \
+ CreateNodeEvent.hpp \
+ CreatePatchEvent.cpp \
+ CreatePatchEvent.hpp \
+ CreatePortEvent.cpp \
+ CreatePortEvent.hpp \
+ DeactivateEvent.cpp \
+ DeactivateEvent.hpp \
+ DestroyEvent.cpp \
+ DestroyEvent.hpp \
+ DisconnectAllEvent.cpp \
+ DisconnectAllEvent.hpp \
+ DisconnectionEvent.cpp \
+ DisconnectionEvent.hpp \
+ EnablePatchEvent.cpp \
+ EnablePatchEvent.hpp \
+ LoadPluginsEvent.cpp \
+ LoadPluginsEvent.hpp \
+ MidiLearnEvent.cpp \
+ MidiLearnEvent.hpp \
+ NoteEvent.cpp \
+ NoteEvent.hpp \
+ PingQueuedEvent.hpp \
+ RegisterClientEvent.cpp \
+ RegisterClientEvent.hpp \
+ RenameEvent.cpp \
+ RenameEvent.hpp \
+ RequestAllObjectsEvent.cpp \
+ RequestAllObjectsEvent.hpp \
+ RequestMetadataEvent.cpp \
+ RequestMetadataEvent.hpp \
+ RequestObjectEvent.cpp \
+ RequestObjectEvent.hpp \
+ RequestPluginEvent.cpp \
+ RequestPluginEvent.hpp \
+ RequestPluginsEvent.cpp \
+ RequestPluginsEvent.hpp \
+ RequestPortValueEvent.cpp \
+ RequestPortValueEvent.hpp \
+ SendPortActivityEvent.cpp \
+ SendPortActivityEvent.hpp \
+ SendPortValueEvent.cpp \
+ SendPortValueEvent.hpp \
+ SetMetadataEvent.cpp \
+ SetMetadataEvent.hpp \
+ SetPolyphonicEvent.cpp \
+ SetPolyphonicEvent.hpp \
+ SetPolyphonyEvent.cpp \
+ SetPolyphonyEvent.hpp \
+ SetPortValueEvent.cpp \
+ SetPortValueEvent.hpp \
+ UnregisterClientEvent.cpp \
+ UnregisterClientEvent.hpp
+
diff --git a/src/engine/events/MidiLearnEvent.cpp b/src/engine/events/MidiLearnEvent.cpp
new file mode 100644
index 00000000..2f37f30d
--- /dev/null
+++ b/src/engine/events/MidiLearnEvent.cpp
@@ -0,0 +1,89 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "MidiLearnEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "EngineStore.hpp"
+#include "NodeImpl.hpp"
+#include "MidiControlNode.hpp"
+#include "ClientBroadcaster.hpp"
+#include "PluginImpl.hpp"
+
+namespace Ingen {
+
+
+// MidiLearnResponseEvent
+
+void
+MidiLearnResponseEvent::post_process()
+{
+ _engine.broadcaster()->send_port_value(_port_path, _value);
+}
+
+
+
+// MidiLearnEvent
+
+MidiLearnEvent::MidiLearnEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& node_path)
+: QueuedEvent(engine, responder, timestamp),
+ _node_path(node_path),
+ _node(NULL),
+ _response_event(NULL)
+{
+}
+
+
+void
+MidiLearnEvent::pre_process()
+{
+ _node = _engine.engine_store()->find_node(_node_path);
+ _response_event = new MidiLearnResponseEvent(_engine, _node_path + "/Controller_Number", _time);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+MidiLearnEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ // FIXME: this isn't very good at all.
+ if (_node != NULL && _node->plugin_impl()->type() == Plugin::Internal
+ && _node->plugin_impl()->uri() == "ingen:control_node") {
+ ((MidiControlNode*)_node)->learn(_response_event);
+ }
+}
+
+
+void
+MidiLearnEvent::post_process()
+{
+ if (_node != NULL) {
+ _responder->respond_ok();
+ } else {
+ string msg = "Did not find node '";
+ msg.append(_node_path).append("' for MIDI learn.");
+ _responder->respond_error(msg);
+ }
+}
+
+
+} // namespace Ingen
+
+
diff --git a/src/engine/events/MidiLearnEvent.hpp b/src/engine/events/MidiLearnEvent.hpp
new file mode 100644
index 00000000..c0fc4a17
--- /dev/null
+++ b/src/engine/events/MidiLearnEvent.hpp
@@ -0,0 +1,85 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MIDILEARNEVENT_H
+#define MIDILEARNEVENT_H
+
+#include "QueuedEvent.hpp"
+#include "MidiControlNode.hpp"
+#include "types.hpp"
+#include <string>
+using std::string;
+
+namespace Ingen {
+
+class NodeImpl;
+class ControlChangeEvent;
+
+
+/** Response event for a MIDI learn.
+ *
+ * This is a trivial event that sends a control change in it's post_process
+ * method (used by MidiLearnEvent to notify clients when the learn happens)
+ */
+class MidiLearnResponseEvent : public Event
+{
+public:
+ MidiLearnResponseEvent(Engine& engine, const string& port_path, SampleCount timestamp)
+ : Event(engine, SharedPtr<Responder>(), timestamp),
+ _port_path(port_path),
+ _value(0.0f)
+ {}
+
+ void set_value(Sample val) { _value = val; }
+ void post_process();
+
+private:
+ string _port_path;
+ Sample _value;
+};
+
+
+
+/** A MIDI learn event.
+ *
+ * This creates a MidiLearnResponseEvent and passes it to the learning node, which
+ * will push it to the post-processor once the learn happens in order to reply
+ * to the client with the new port (learned controller) value.
+ *
+ * \ingroup engine
+ */
+class MidiLearnEvent : public QueuedEvent
+{
+public:
+ MidiLearnEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& node_path);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const string _node_path;
+ NodeImpl* _node;
+
+ /// Event to respond with when learned
+ MidiLearnResponseEvent* _response_event;
+};
+
+
+} // namespace Ingen
+
+#endif // MIDILEARNEVENT_H
diff --git a/src/engine/events/NoteEvent.cpp b/src/engine/events/NoteEvent.cpp
new file mode 100644
index 00000000..58842ae6
--- /dev/null
+++ b/src/engine/events/NoteEvent.cpp
@@ -0,0 +1,102 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "NoteEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "EngineStore.hpp"
+#include "NodeImpl.hpp"
+#include "MidiNoteNode.hpp"
+#include "MidiTriggerNode.hpp"
+#include "PluginImpl.hpp"
+#include "InternalPlugin.hpp"
+#include "ProcessContext.hpp"
+
+namespace Ingen {
+
+
+/** Note on with Patch explicitly passed.
+ *
+ * Used to be triggered by MIDI. Not used anymore.
+ */
+NoteEvent::NoteEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, NodeImpl* node, bool on, uchar note_num, uchar velocity)
+: Event(engine, responder, timestamp),
+ _node(node),
+ _on(on),
+ _note_num(note_num),
+ _velocity(velocity)
+{
+}
+
+
+/** Note on with Node lookup.
+ *
+ * Triggered by OSC.
+ */
+NoteEvent::NoteEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& node_path, bool on, uchar note_num, uchar velocity)
+: Event(engine, responder, timestamp),
+ _node(NULL),
+ _node_path(node_path),
+ _on(on),
+ _note_num(note_num),
+ _velocity(velocity)
+{
+}
+
+
+void
+NoteEvent::execute(ProcessContext& context)
+{
+ Event::execute(context);
+ assert(_time >= context.start() && _time <= context.end());
+
+ // Lookup if neccessary
+ if (!_node)
+ _node = _engine.engine_store()->find_node(_node_path);
+
+ // FIXME: barf
+
+ if (_node != NULL && _node->plugin()->type() == Plugin::Internal) {
+ if (_on) {
+ if (_node->plugin_impl()->uri() == NS_INGEN "note_node")
+ ((MidiNoteNode*)_node)->note_on(context, _note_num, _velocity, _time);
+ else if (_node->plugin_impl()->uri() == NS_INGEN "trigger_node")
+ ((MidiTriggerNode*)_node)->note_on(context, _note_num, _velocity, _time);
+ } else {
+ if (_node->plugin_impl()->uri() == NS_INGEN "note_node")
+ ((MidiNoteNode*)_node)->note_off(context, _note_num, _time);
+ else if (_node->plugin_impl()->uri() == NS_INGEN "trigger_node")
+ ((MidiTriggerNode*)_node)->note_off(context, _note_num, _time);
+ }
+ }
+}
+
+
+void
+NoteEvent::post_process()
+{
+ if (_responder) {
+ if (_node)
+ _responder->respond_ok();
+ else
+ _responder->respond_error("Did not find node for note_on");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/NoteEvent.hpp b/src/engine/events/NoteEvent.hpp
new file mode 100644
index 00000000..31ae9d27
--- /dev/null
+++ b/src/engine/events/NoteEvent.hpp
@@ -0,0 +1,68 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef NOTEEVENT_H
+#define NOTEEVENT_H
+
+#include "Event.hpp"
+#include "types.hpp"
+#include <string>
+using std::string;
+
+namespace Ingen {
+
+class NodeImpl;
+
+
+/** A note on event.
+ *
+ * \ingroup engine
+ */
+class NoteEvent : public Event
+{
+public:
+ NoteEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ NodeImpl* node,
+ bool on,
+ uchar note_num,
+ uchar velocity);
+
+ NoteEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& node_path,
+ bool on,
+ uchar note_num,
+ uchar velocity);
+
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ NodeImpl* _node;
+ const string _node_path;
+ bool _on;
+ uchar _note_num;
+ uchar _velocity;
+};
+
+
+} // namespace Ingen
+
+#endif // NOTEEVENT_H
diff --git a/src/engine/events/PingQueuedEvent.hpp b/src/engine/events/PingQueuedEvent.hpp
new file mode 100644
index 00000000..08897bfe
--- /dev/null
+++ b/src/engine/events/PingQueuedEvent.hpp
@@ -0,0 +1,48 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PINGQUEUEDEVENT_H
+#define PINGQUEUEDEVENT_H
+
+#include "QueuedEvent.hpp"
+#include "types.hpp"
+#include "Responder.hpp"
+
+namespace Ingen {
+
+class PortImpl;
+
+
+/** A ping that travels through the pre-processed event queue before responding
+ * (useful for the order guarantee).
+ *
+ * \ingroup engine
+ */
+class PingQueuedEvent : public QueuedEvent
+{
+public:
+ PingQueuedEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp)
+ : QueuedEvent(engine, responder, timestamp)
+ {}
+
+ void post_process() { _responder->respond_ok(); }
+};
+
+
+} // namespace Ingen
+
+#endif // PINGQUEUEDEVENT_H
diff --git a/src/engine/events/RegisterClientEvent.cpp b/src/engine/events/RegisterClientEvent.cpp
new file mode 100644
index 00000000..a8f68e21
--- /dev/null
+++ b/src/engine/events/RegisterClientEvent.cpp
@@ -0,0 +1,55 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Responder.hpp"
+#include "RegisterClientEvent.hpp"
+#include "Engine.hpp"
+#include "ClientBroadcaster.hpp"
+
+namespace Ingen {
+
+
+RegisterClientEvent::RegisterClientEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& uri,
+ ClientInterface* client)
+ : QueuedEvent(engine, responder, timestamp)
+ , _uri(uri)
+ , _client(client)
+{
+}
+
+
+void
+RegisterClientEvent::pre_process()
+{
+ _engine.broadcaster()->register_client(_uri, _client);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RegisterClientEvent::post_process()
+{
+ _responder->respond_ok();
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/RegisterClientEvent.hpp b/src/engine/events/RegisterClientEvent.hpp
new file mode 100644
index 00000000..9e12b5ba
--- /dev/null
+++ b/src/engine/events/RegisterClientEvent.hpp
@@ -0,0 +1,55 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REGISTERCLIENTEVENT_H
+#define REGISTERCLIENTEVENT_H
+
+#include "QueuedEvent.hpp"
+#include "interface/ClientInterface.hpp"
+#include <string>
+using std::string;
+using Ingen::Shared::ClientInterface;
+using Ingen::Responder;
+
+namespace Ingen {
+
+
+/** Registers a new client with the OSC system, so it can receive updates.
+ *
+ * \ingroup engine
+ */
+class RegisterClientEvent : public QueuedEvent
+{
+public:
+ RegisterClientEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& uri,
+ ClientInterface* client);
+
+ void pre_process();
+ void post_process();
+
+private:
+ string _uri;
+ ClientInterface* _client;
+};
+
+
+} // namespace Ingen
+
+#endif // REGISTERCLIENTEVENT_H
diff --git a/src/engine/events/RenameEvent.cpp b/src/engine/events/RenameEvent.cpp
new file mode 100644
index 00000000..164676aa
--- /dev/null
+++ b/src/engine/events/RenameEvent.cpp
@@ -0,0 +1,152 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <raul/Path.hpp>
+#include "ClientBroadcaster.hpp"
+#include "Engine.hpp"
+#include "NodeImpl.hpp"
+#include "EngineStore.hpp"
+#include "PatchImpl.hpp"
+#include "RenameEvent.hpp"
+#include "Responder.hpp"
+#include "AudioDriver.hpp"
+#include "MidiDriver.hpp"
+
+using namespace std;
+
+namespace Ingen {
+
+
+RenameEvent::RenameEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& name)
+: QueuedEvent(engine, responder, timestamp),
+ _old_path(path),
+ _name(name),
+ _new_path("/"),
+ _parent_patch(NULL),
+ _store_iterator(engine.engine_store()->end()),
+ _error(NO_ERROR)
+{
+ /*
+ if (_old_path.parent() == "/")
+ _new_path = string("/") + _name;
+ else
+ _new_path = _old_path.parent() +"/"+ _name;*/
+}
+
+
+RenameEvent::~RenameEvent()
+{
+}
+
+
+void
+RenameEvent::pre_process()
+{
+ if ((!Raul::Path::is_valid_name(_name)) || _name.find("/") != string::npos) {
+ _error = INVALID_NAME;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ _new_path = _old_path.parent().base() + _name;
+
+ _store_iterator = _engine.engine_store()->find(_old_path);
+ if (_store_iterator == _engine.engine_store()->end()) {
+ _error = OBJECT_NOT_FOUND;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if (_engine.engine_store()->find_object(_new_path)) {
+ _error = OBJECT_EXISTS;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ SharedPtr< Table<Path, SharedPtr<Shared::GraphObject> > > removed
+ = _engine.engine_store()->remove(_store_iterator);
+
+ assert(removed->size() > 0);
+
+ for (Table<Path, SharedPtr<Shared::GraphObject> >::iterator i = removed->begin(); i != removed->end(); ++i) {
+ const Path& child_old_path = i->first;
+ assert(Path::descendant_comparator(_old_path, child_old_path));
+
+ Path child_new_path;
+ if (child_old_path == _old_path)
+ child_new_path = _new_path;
+ else
+ child_new_path = _new_path.base() + child_old_path.substr(_old_path.length()+1);
+
+ PtrCast<GraphObjectImpl>(i->second)->set_path(child_new_path);
+ i->first = child_new_path;
+ }
+
+ _engine.engine_store()->add(*removed.get());
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RenameEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ SharedPtr<PortImpl> port = PtrCast<PortImpl>(_store_iterator->second);
+ if (port && port->parent()->parent() == NULL) {
+ DriverPort* driver_port = NULL;
+
+ if (port->type() == DataType::AUDIO)
+ driver_port = _engine.audio_driver()->driver_port(_new_path);
+ else if (port->type() == DataType::EVENT)
+ driver_port = _engine.midi_driver()->driver_port(_new_path);
+
+ if (driver_port) {
+ cerr << "DRIVER PORT :)!" << endl;
+ driver_port->set_name(_new_path);
+ } else {
+ cerr << "NO DRIVER PORT :(" << endl;
+ }
+ }
+}
+
+
+void
+RenameEvent::post_process()
+{
+ string msg = "Unable to rename object - ";
+
+ if (_error == NO_ERROR) {
+ _responder->respond_ok();
+ _engine.broadcaster()->send_rename(_old_path, _new_path);
+ } else {
+ if (_error == OBJECT_EXISTS)
+ msg.append("Object already exists at ").append(_new_path);
+ else if (_error == OBJECT_NOT_FOUND)
+ msg.append("Could not find object ").append(_old_path);
+ else if (_error == OBJECT_NOT_RENAMABLE)
+ msg.append(_old_path).append(" is not renamable");
+ else if (_error == INVALID_NAME)
+ msg.append(_name).append(" is not a valid name");
+
+ _responder->respond_error(msg);
+ }
+}
+
+
+} // namespace Ingen
diff --git a/src/engine/events/RenameEvent.hpp b/src/engine/events/RenameEvent.hpp
new file mode 100644
index 00000000..e230c589
--- /dev/null
+++ b/src/engine/events/RenameEvent.hpp
@@ -0,0 +1,64 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef RENAMEEVENT_H
+#define RENAMEEVENT_H
+
+#include <string>
+#include <raul/Path.hpp>
+#include "QueuedEvent.hpp"
+#include "EngineStore.hpp"
+
+using std::string;
+
+template<typename T> class TreeNode;
+template<typename T> class ListNode;
+
+namespace Ingen {
+
+class PatchImpl;
+
+
+/** An event to change the name of an GraphObjectImpl.
+ *
+ * \ingroup engine
+ */
+class RenameEvent : public QueuedEvent
+{
+public:
+ RenameEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& name);
+ ~RenameEvent();
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ enum ErrorType { NO_ERROR, OBJECT_NOT_FOUND, OBJECT_EXISTS, OBJECT_NOT_RENAMABLE, INVALID_NAME };
+
+ Path _old_path;
+ string _name;
+ Path _new_path;
+ PatchImpl* _parent_patch;
+ EngineStore::iterator _store_iterator;
+ ErrorType _error;
+};
+
+
+} // namespace Ingen
+
+#endif // RENAMEEVENT_H
diff --git a/src/engine/events/RequestAllObjectsEvent.cpp b/src/engine/events/RequestAllObjectsEvent.cpp
new file mode 100644
index 00000000..d57080aa
--- /dev/null
+++ b/src/engine/events/RequestAllObjectsEvent.cpp
@@ -0,0 +1,59 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "RequestAllObjectsEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "ObjectSender.hpp"
+#include "ClientBroadcaster.hpp"
+#include "EngineStore.hpp"
+
+namespace Ingen {
+
+
+RequestAllObjectsEvent::RequestAllObjectsEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp)
+: QueuedEvent(engine, responder, timestamp)
+{
+}
+
+
+void
+RequestAllObjectsEvent::pre_process()
+{
+ QueuedEvent::pre_process();
+}
+
+
+void
+RequestAllObjectsEvent::post_process()
+{
+ if (_responder->client()) {
+ _responder->respond_ok();
+
+ // Everything is a child of the root patch, so this sends it all
+ PatchImpl* root = _engine.engine_store()->find_patch("/");
+ if (root && _responder->client())
+ ObjectSender::send_patch(_responder->client(), root, true);
+
+ } else {
+ _responder->respond_error("Unable to find client to send all objects");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/RequestAllObjectsEvent.hpp b/src/engine/events/RequestAllObjectsEvent.hpp
new file mode 100644
index 00000000..0537575a
--- /dev/null
+++ b/src/engine/events/RequestAllObjectsEvent.hpp
@@ -0,0 +1,48 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REQUESTALLOBJECTSEVENT_H
+#define REQUESTALLOBJECTSEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+using std::string;
+
+namespace Ingen {
+
+namespace Shared {
+ class ClientInterface;
+} using Shared::ClientInterface;
+
+
+/** A request from a client to send notification of all objects (ie refresh).
+ *
+ * \ingroup engine
+ */
+class RequestAllObjectsEvent : public QueuedEvent
+{
+public:
+ RequestAllObjectsEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp);
+
+ void pre_process();
+ void post_process();
+};
+
+
+} // namespace Ingen
+
+#endif // REQUESTALLOBJECTSEVENT_H
diff --git a/src/engine/events/RequestMetadataEvent.cpp b/src/engine/events/RequestMetadataEvent.cpp
new file mode 100644
index 00000000..733a6a82
--- /dev/null
+++ b/src/engine/events/RequestMetadataEvent.cpp
@@ -0,0 +1,85 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "RequestMetadataEvent.hpp"
+#include <string>
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "GraphObjectImpl.hpp"
+#include "EngineStore.hpp"
+#include "interface/ClientInterface.hpp"
+#include "ClientBroadcaster.hpp"
+using std::string;
+
+namespace Ingen {
+
+
+RequestMetadataEvent::RequestMetadataEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ bool property,
+ const string& node_path,
+ const string& key)
+ : QueuedEvent(engine, responder, timestamp)
+ , _path(node_path)
+ , _property(property)
+ , _key(key)
+ , _object(NULL)
+{
+}
+
+
+void
+RequestMetadataEvent::pre_process()
+{
+ if (_responder->client()) {
+ _object = _engine.engine_store()->find_object(_path);
+ if (_object == NULL) {
+ QueuedEvent::pre_process();
+ return;
+ }
+ }
+
+ if (_property)
+ _value = _object->get_property(_key);
+ else
+ _value = _object->get_variable(_key);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RequestMetadataEvent::post_process()
+{
+ if (_responder->client()) {
+ if (!_object) {
+ string msg = "Unable to find variable subject ";
+ msg += _path;
+ _responder->respond_error(msg);
+ } else {
+ _responder->respond_ok();
+ _responder->client()->set_variable(_path, _key, _value);
+ }
+ } else {
+ _responder->respond_error("Unknown client");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/RequestMetadataEvent.hpp b/src/engine/events/RequestMetadataEvent.hpp
new file mode 100644
index 00000000..f6a18dfc
--- /dev/null
+++ b/src/engine/events/RequestMetadataEvent.hpp
@@ -0,0 +1,62 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REQUESTMETADATAEVENT_H
+#define REQUESTMETADATAEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+#include <raul/Atom.hpp>
+using std::string;
+
+namespace Ingen {
+
+class GraphObjectImpl;
+namespace Shared {
+ class ClientInterface;
+} using Shared::ClientInterface;
+
+
+/** A request from a client for a piece of variable.
+ *
+ * \ingroup engine
+ */
+class RequestMetadataEvent : public QueuedEvent
+{
+public:
+ RequestMetadataEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ bool property,
+ const string& path,
+ const string& key);
+
+ void pre_process();
+ void post_process();
+
+private:
+ string _path;
+ bool _property;
+ string _key;
+ Raul::Atom _value;
+ GraphObjectImpl* _object;
+};
+
+
+} // namespace Ingen
+
+#endif // REQUESTMETADATAEVENT_H
diff --git a/src/engine/events/RequestObjectEvent.cpp b/src/engine/events/RequestObjectEvent.cpp
new file mode 100644
index 00000000..88479482
--- /dev/null
+++ b/src/engine/events/RequestObjectEvent.cpp
@@ -0,0 +1,98 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "RequestObjectEvent.hpp"
+#include <string>
+#include "interface/ClientInterface.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "EngineStore.hpp"
+#include "ClientBroadcaster.hpp"
+#include "PatchImpl.hpp"
+#include "NodeImpl.hpp"
+#include "PortImpl.hpp"
+#include "ObjectSender.hpp"
+#include "ProcessContext.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+
+RequestObjectEvent::RequestObjectEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& path)
+: QueuedEvent(engine, responder, timestamp),
+ _path(path),
+ _object(NULL)
+{
+}
+
+
+void
+RequestObjectEvent::pre_process()
+{
+ _object = _engine.engine_store()->find_object(_path);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RequestObjectEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+ assert(_time >= context.start() && _time <= context.end());
+}
+
+
+void
+RequestObjectEvent::post_process()
+{
+ if (!_object) {
+ _responder->respond_error("Unable to find object requested.");
+
+ } else if (_responder->client()) {
+ PatchImpl* const patch = dynamic_cast<PatchImpl*>(_object);
+ if (patch) {
+ _responder->respond_ok();
+ ObjectSender::send_patch(_responder->client(), patch, true);
+ return;
+ }
+
+ NodeImpl* const node = dynamic_cast<NodeImpl*>(_object);
+ if (node) {
+ _responder->respond_ok();
+ ObjectSender::send_node(_responder->client(), node, true);
+ return;
+ }
+
+ PortImpl* const port = dynamic_cast<PortImpl*>(_object);
+ if (port) {
+ _responder->respond_ok();
+ ObjectSender::send_port(_responder->client(), port);
+ return;
+ }
+
+ _responder->respond_error("Object of unknown type requested.");
+
+ } else {
+ _responder->respond_error("Unable to find client to send object.");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/RequestObjectEvent.hpp b/src/engine/events/RequestObjectEvent.hpp
new file mode 100644
index 00000000..52459ada
--- /dev/null
+++ b/src/engine/events/RequestObjectEvent.hpp
@@ -0,0 +1,55 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REQUESTOBJECTEVENT_H
+#define REQUESTOBJECTEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+#include "types.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+class GraphObjectImpl;
+namespace Shared { class ClientInterface; }
+using Shared::ClientInterface;
+
+
+/** A request from a client to send the value of a port.
+ *
+ * \ingroup engine
+ */
+class RequestObjectEvent : public QueuedEvent
+{
+public:
+ RequestObjectEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& port_path);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const string _path;
+ GraphObjectImpl* _object;
+};
+
+
+} // namespace Ingen
+
+#endif // REQUESTOBJECTEVENT_H
diff --git a/src/engine/events/RequestPluginEvent.cpp b/src/engine/events/RequestPluginEvent.cpp
new file mode 100644
index 00000000..36358df7
--- /dev/null
+++ b/src/engine/events/RequestPluginEvent.cpp
@@ -0,0 +1,79 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string>
+#include "interface/ClientInterface.hpp"
+#include "RequestPluginEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PortImpl.hpp"
+#include "EngineStore.hpp"
+#include "ClientBroadcaster.hpp"
+#include "NodeFactory.hpp"
+#include "PluginImpl.hpp"
+#include "ProcessContext.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+
+RequestPluginEvent::RequestPluginEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& uri)
+: QueuedEvent(engine, responder, timestamp),
+ _uri(uri),
+ _plugin(NULL)
+{
+}
+
+
+void
+RequestPluginEvent::pre_process()
+{
+ _plugin = _engine.node_factory()->plugin(_uri);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RequestPluginEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+ assert(_time >= context.start() && _time <= context.end());
+}
+
+
+void
+RequestPluginEvent::post_process()
+{
+ if (!_plugin) {
+ _responder->respond_error("Unable to find plugin requested.");
+
+ } else if (_responder->client()) {
+
+ _responder->respond_ok();
+ assert(_plugin->uri() == _uri);
+ _responder->client()->new_plugin(_uri, _plugin->type_uri(), _plugin->symbol(), _plugin->name());
+
+ } else {
+ _responder->respond_error("Unable to find client to send plugin.");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/RequestPluginEvent.hpp b/src/engine/events/RequestPluginEvent.hpp
new file mode 100644
index 00000000..8f936098
--- /dev/null
+++ b/src/engine/events/RequestPluginEvent.hpp
@@ -0,0 +1,53 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REQUESTPLUGINEVENT_H
+#define REQUESTPLUGINEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+#include "types.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+class PluginImpl;
+
+
+/** A request from a client to send information about a plugin.
+ *
+ * \ingroup engine
+ */
+class RequestPluginEvent : public QueuedEvent
+{
+public:
+ RequestPluginEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& uri);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const string _uri;
+ const PluginImpl* _plugin;
+};
+
+
+} // namespace Ingen
+
+#endif // REQUESTPLUGINEVENT_H
diff --git a/src/engine/events/RequestPluginsEvent.cpp b/src/engine/events/RequestPluginsEvent.cpp
new file mode 100644
index 00000000..8d7fc1ba
--- /dev/null
+++ b/src/engine/events/RequestPluginsEvent.cpp
@@ -0,0 +1,57 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "RequestPluginsEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "ClientBroadcaster.hpp"
+#include "NodeFactory.hpp"
+
+namespace Ingen {
+
+
+RequestPluginsEvent::RequestPluginsEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp)
+: QueuedEvent(engine, responder, timestamp)
+{
+}
+
+
+void
+RequestPluginsEvent::pre_process()
+{
+ // Take a copy to send in the post processing thread (to avoid problems
+ // because std::map isn't thread safe)
+ _plugins = _engine.node_factory()->plugins();
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RequestPluginsEvent::post_process()
+{
+ if (_responder->client()) {
+ _engine.broadcaster()->send_plugins_to(_responder->client(), _plugins);
+ _responder->respond_ok();
+ } else {
+ _responder->respond_error("Unable to find client to send plugins");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/RequestPluginsEvent.hpp b/src/engine/events/RequestPluginsEvent.hpp
new file mode 100644
index 00000000..f6b41d7a
--- /dev/null
+++ b/src/engine/events/RequestPluginsEvent.hpp
@@ -0,0 +1,47 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REQUESTPLUGINSEVENT_H
+#define REQUESTPLUGINSEVENT_H
+
+#include "QueuedEvent.hpp"
+#include "NodeFactory.hpp"
+
+namespace Ingen {
+
+class Responder;
+
+/** A request from a client to send notification of all objects (ie refresh).
+ *
+ * \ingroup engine
+ */
+class RequestPluginsEvent : public QueuedEvent
+{
+public:
+ RequestPluginsEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp);
+
+ void pre_process();
+ void post_process();
+
+private:
+ NodeFactory::Plugins _plugins;
+};
+
+
+} // namespace Ingen
+
+#endif // REQUESTPLUGINSEVENT_H
diff --git a/src/engine/events/RequestPortValueEvent.cpp b/src/engine/events/RequestPortValueEvent.cpp
new file mode 100644
index 00000000..025d3700
--- /dev/null
+++ b/src/engine/events/RequestPortValueEvent.cpp
@@ -0,0 +1,81 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "RequestPortValueEvent.hpp"
+#include <string>
+#include "interface/ClientInterface.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PortImpl.hpp"
+#include "EngineStore.hpp"
+#include "ClientBroadcaster.hpp"
+#include "AudioBuffer.hpp"
+#include "ProcessContext.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+
+RequestPortValueEvent::RequestPortValueEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& port_path)
+: QueuedEvent(engine, responder, timestamp),
+ _port_path(port_path),
+ _port(NULL),
+ _value(0.0)
+{
+}
+
+
+void
+RequestPortValueEvent::pre_process()
+{
+ _port = _engine.engine_store()->find_port(_port_path);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RequestPortValueEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+ assert(_time >= context.start() && _time <= context.end());
+
+ if (_port != NULL && (_port->type() == DataType::CONTROL || _port->type() == DataType::AUDIO))
+ _value = ((AudioBuffer*)_port->buffer(0))->value_at(0/*_time - start*/);
+ else
+ _port = NULL; // triggers error response
+}
+
+
+void
+RequestPortValueEvent::post_process()
+{
+ string msg;
+ if (!_port) {
+ _responder->respond_error("Unable to find port for get_value responder.");
+ } else if (_responder->client()) {
+ _responder->respond_ok();
+ _responder->client()->set_port_value(_port_path, _value);
+ } else {
+ _responder->respond_error("Unable to find client to send port value");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/RequestPortValueEvent.hpp b/src/engine/events/RequestPortValueEvent.hpp
new file mode 100644
index 00000000..dd52c535
--- /dev/null
+++ b/src/engine/events/RequestPortValueEvent.hpp
@@ -0,0 +1,56 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REQUESTPORTVALUEEVENT_H
+#define REQUESTPORTVALUEEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+#include "types.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+class PortImpl;
+namespace Shared { class ClientInterface; }
+using Shared::ClientInterface;
+
+
+/** A request from a client to send the value of a port.
+ *
+ * \ingroup engine
+ */
+class RequestPortValueEvent : public QueuedEvent
+{
+public:
+ RequestPortValueEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& port_path);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const string _port_path;
+ PortImpl* _port;
+ Sample _value;
+};
+
+
+} // namespace Ingen
+
+#endif // REQUESTPORTVALUEEVENT_H
diff --git a/src/engine/events/SendPortActivityEvent.cpp b/src/engine/events/SendPortActivityEvent.cpp
new file mode 100644
index 00000000..0ab3abdd
--- /dev/null
+++ b/src/engine/events/SendPortActivityEvent.cpp
@@ -0,0 +1,34 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "SendPortActivityEvent.hpp"
+#include "Engine.hpp"
+#include "PortImpl.hpp"
+#include "ClientBroadcaster.hpp"
+
+namespace Ingen {
+
+
+void
+SendPortActivityEvent::post_process()
+{
+ _engine.broadcaster()->send_port_activity(_port->path());
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/SendPortActivityEvent.hpp b/src/engine/events/SendPortActivityEvent.hpp
new file mode 100644
index 00000000..dfbb8a10
--- /dev/null
+++ b/src/engine/events/SendPortActivityEvent.hpp
@@ -0,0 +1,67 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SENDPORTACTIVITYEVENT_H
+#define SENDPORTACTIVITYEVENT_H
+
+#include <string>
+#include "Event.hpp"
+#include "types.hpp"
+using std::string;
+
+namespace Ingen {
+
+class PortImpl;
+
+
+/** A special event used internally to send port activity notification (e.g.
+ * MIDI event activity) from the audio thread.
+ *
+ * This is created in the audio thread (directly in a ringbuffer, not new'd)
+ * for processing in the post processing thread (unlike normal events which
+ * are created in the pre-processor thread then run through the audio
+ * thread). This event's job is done entirely in post_process.
+ *
+ * This only really makes sense for message ports.
+ *
+ * \ingroup engine
+ */
+class SendPortActivityEvent : public Event
+{
+public:
+ inline SendPortActivityEvent(Engine& engine,
+ SampleCount timestamp,
+ PortImpl* port)
+ : Event(engine, SharedPtr<Responder>(), timestamp)
+ , _port(port)
+ {
+ }
+
+ inline void operator=(const SendPortActivityEvent& ev) {
+ _port = ev._port;
+ }
+
+ void post_process();
+
+private:
+ PortImpl* _port;
+};
+
+
+} // namespace Ingen
+
+#endif // SENDPORTACTIVITYEVENT_H
diff --git a/src/engine/events/SendPortValueEvent.cpp b/src/engine/events/SendPortValueEvent.cpp
new file mode 100644
index 00000000..d3fb0d36
--- /dev/null
+++ b/src/engine/events/SendPortValueEvent.cpp
@@ -0,0 +1,43 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sstream>
+#include "SendPortValueEvent.hpp"
+#include "Engine.hpp"
+#include "PortImpl.hpp"
+#include "ClientBroadcaster.hpp"
+
+using namespace std;
+
+namespace Ingen {
+
+
+void
+SendPortValueEvent::post_process()
+{
+ // FIXME...
+
+ if (_omni) {
+ _engine.broadcaster()->send_port_value(_port->path(), _value);
+ } else {
+ _engine.broadcaster()->send_port_value(_port->path(), _value);
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/SendPortValueEvent.hpp b/src/engine/events/SendPortValueEvent.hpp
new file mode 100644
index 00000000..e8505914
--- /dev/null
+++ b/src/engine/events/SendPortValueEvent.hpp
@@ -0,0 +1,78 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SENDPORTVALUEEVENT_H
+#define SENDPORTVALUEEVENT_H
+
+#include <string>
+#include "Event.hpp"
+#include "types.hpp"
+using std::string;
+
+namespace Ingen {
+
+class PortImpl;
+
+
+/** A special event used internally to send port values from the audio thread.
+ *
+ * This is created in the audio thread (using in-place new on a preallocated
+ * buffer) for processing in the post processing thread (unlike normal events
+ * which are created in the pre-processor thread then run through the audio
+ * thread). This event's job is done entirely in post_process.
+ *
+ * This only works for control ports right now.
+ *
+ * \ingroup engine
+ */
+class SendPortValueEvent : public Event
+{
+public:
+ inline SendPortValueEvent(Engine& engine,
+ SampleCount timestamp,
+ PortImpl* port,
+ bool omni,
+ uint32_t voice_num,
+ Sample value)
+ : Event(engine, SharedPtr<Responder>(), timestamp)
+ , _port(port)
+ , _omni(omni)
+ , _voice_num(voice_num)
+ , _value(value)
+ {
+ }
+
+ inline void operator=(const SendPortValueEvent& ev) {
+ _port = ev._port;
+ _omni = ev._omni;
+ _voice_num = ev._voice_num;
+ _value = ev._value;
+ }
+
+ void post_process();
+
+private:
+ PortImpl* _port;
+ bool _omni;
+ uint32_t _voice_num;
+ Sample _value;
+};
+
+
+} // namespace Ingen
+
+#endif // SENDPORTVALUEEVENT_H
diff --git a/src/engine/events/SetMetadataEvent.cpp b/src/engine/events/SetMetadataEvent.cpp
new file mode 100644
index 00000000..db4bbc30
--- /dev/null
+++ b/src/engine/events/SetMetadataEvent.cpp
@@ -0,0 +1,114 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "SetMetadataEvent.hpp"
+#include <string>
+#include <boost/format.hpp>
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PortImpl.hpp"
+#include "ClientBroadcaster.hpp"
+#include "GraphObjectImpl.hpp"
+#include "EngineStore.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+
+SetMetadataEvent::SetMetadataEvent(
+ Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ bool property,
+ const string& path,
+ const string& key,
+ const Atom& value)
+ : QueuedEvent(engine, responder, timestamp)
+ , _error(NO_ERROR)
+ , _special_type(NONE)
+ , _property(property)
+ , _path(path)
+ , _key(key)
+ , _value(value)
+ , _object(NULL)
+{
+}
+
+
+void
+SetMetadataEvent::pre_process()
+{
+ if (!Path::is_valid(_path)) {
+ _error = INVALID_PATH;
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ _object = _engine.engine_store()->find_object(_path);
+ if (_object == NULL) {
+ QueuedEvent::pre_process();
+ return;
+ }
+
+ if (_property)
+ _object->set_property(_key, _value);
+ else
+ _object->set_variable(_key, _value);
+
+ if (_key == "ingen:broadcast") {
+ std::cout << "BROADCAST" << std::endl;
+ _special_type = ENABLE_BROADCAST;
+ }
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+SetMetadataEvent::execute(ProcessContext& context)
+{
+ if (_special_type == ENABLE_BROADCAST) {
+ PortImpl* port = dynamic_cast<PortImpl*>(_object);
+ if (port)
+ port->broadcast(_value.get_bool());
+ }
+
+ QueuedEvent::execute(context);
+ // Do nothing
+}
+
+
+void
+SetMetadataEvent::post_process()
+{
+ if (_error == INVALID_PATH) {
+ _responder->respond_error((boost::format("Invalid path %1% setting %2%") % _path % _key).str());
+ } else if (_object == NULL) {
+ string msg = (boost::format("Unable to find object %1% to set %2%") % _path % _key).str();
+ _responder->respond_error(msg);
+ } else {
+ _responder->respond_ok();
+ if (_property)
+ _engine.broadcaster()->send_property_change(_path, _key, _value);
+ else
+ _engine.broadcaster()->send_variable_change(_path, _key, _value);
+ }
+}
+
+
+} // namespace Ingen
diff --git a/src/engine/events/SetMetadataEvent.hpp b/src/engine/events/SetMetadataEvent.hpp
new file mode 100644
index 00000000..6b9be81c
--- /dev/null
+++ b/src/engine/events/SetMetadataEvent.hpp
@@ -0,0 +1,65 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SETMETADATAEVENT_H
+#define SETMETADATAEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+#include <raul/Atom.hpp>
+
+using std::string;
+
+namespace Ingen {
+
+class GraphObjectImpl;
+
+
+/** An event to set a piece of variable for an GraphObjectImpl.
+ *
+ * \ingroup engine
+ */
+class SetMetadataEvent : public QueuedEvent
+{
+public:
+ SetMetadataEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ bool property,
+ const string& path,
+ const string& key,
+ const Raul::Atom& value);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ enum { NO_ERROR, INVALID_PATH } _error;
+ enum { NONE, ENABLE_BROADCAST } _special_type;
+
+ bool _property;
+ string _path;
+ string _key;
+ Raul::Atom _value;
+ GraphObjectImpl* _object;
+};
+
+
+} // namespace Ingen
+
+#endif // SETMETADATAEVENT_H
diff --git a/src/engine/events/SetPolyphonicEvent.cpp b/src/engine/events/SetPolyphonicEvent.cpp
new file mode 100644
index 00000000..d1fc6a7c
--- /dev/null
+++ b/src/engine/events/SetPolyphonicEvent.cpp
@@ -0,0 +1,82 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <raul/Maid.hpp>
+#include "SetPolyphonicEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PatchImpl.hpp"
+#include "ClientBroadcaster.hpp"
+#include "util.hpp"
+#include "EngineStore.hpp"
+#include "PortImpl.hpp"
+#include "NodeImpl.hpp"
+#include "ConnectionImpl.hpp"
+#include "QueuedEventSource.hpp"
+
+namespace Ingen {
+
+
+SetPolyphonicEvent::SetPolyphonicEvent(Engine& engine, SharedPtr<Responder> responder, FrameTime time, QueuedEventSource* source, const string& path, bool poly)
+: QueuedEvent(engine, responder, time, true, source),
+ _path(path),
+ _object(NULL),
+ _poly(poly),
+ _success(false)
+{
+}
+
+
+void
+SetPolyphonicEvent::pre_process()
+{
+ _object = _engine.engine_store()->find_object(_path);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+SetPolyphonicEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_object)
+ _success = _object->set_polyphonic(*_engine.maid(), _poly);
+
+ _source->unblock();
+}
+
+
+void
+SetPolyphonicEvent::post_process()
+{
+ if (_object) {
+ if (_success) {
+ _responder->respond_ok();
+ _engine.broadcaster()->send_property_change(_path, "ingen:polyphonic", _poly);
+ } else {
+ _responder->respond_error("Unable to set object as polyphonic");
+ }
+ } else {
+ _responder->respond_error("Unable to find object to set polyphonic");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/SetPolyphonicEvent.hpp b/src/engine/events/SetPolyphonicEvent.hpp
new file mode 100644
index 00000000..9079d49f
--- /dev/null
+++ b/src/engine/events/SetPolyphonicEvent.hpp
@@ -0,0 +1,56 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SETPOLYPHONICEVENT_H
+#define SETPOLYPHONICEVENT_H
+
+#include <string>
+#include <raul/Array.hpp>
+#include "QueuedEvent.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+class GraphObjectImpl;
+
+
+/** Delete all nodes from a patch.
+ *
+ * \ingroup engine
+ */
+class SetPolyphonicEvent : public QueuedEvent
+{
+public:
+ SetPolyphonicEvent(Engine& engine, SharedPtr<Responder> responder, FrameTime time, QueuedEventSource* source, const string& path, bool poly);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const string _path;
+ GraphObjectImpl* _object;
+ bool _poly;
+ bool _success;
+};
+
+
+} // namespace Ingen
+
+
+#endif // SETPOLYPHONICEVENT_H
diff --git a/src/engine/events/SetPolyphonyEvent.cpp b/src/engine/events/SetPolyphonyEvent.cpp
new file mode 100644
index 00000000..eb6550cb
--- /dev/null
+++ b/src/engine/events/SetPolyphonyEvent.cpp
@@ -0,0 +1,79 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <raul/Maid.hpp>
+#include "SetPolyphonyEvent.hpp"
+#include "Responder.hpp"
+#include "Engine.hpp"
+#include "PatchImpl.hpp"
+#include "ClientBroadcaster.hpp"
+#include "util.hpp"
+#include "EngineStore.hpp"
+#include "PortImpl.hpp"
+#include "NodeImpl.hpp"
+#include "ConnectionImpl.hpp"
+#include "QueuedEventSource.hpp"
+
+namespace Ingen {
+
+
+SetPolyphonyEvent::SetPolyphonyEvent(Engine& engine, SharedPtr<Responder> responder, FrameTime time, QueuedEventSource* source, const string& patch_path, uint32_t poly)
+: QueuedEvent(engine, responder, time, true, source),
+ _patch_path(patch_path),
+ _patch(NULL),
+ _poly(poly)
+{
+}
+
+
+void
+SetPolyphonyEvent::pre_process()
+{
+ _patch = _engine.engine_store()->find_patch(_patch_path);
+ if (_patch && _poly > _patch->internal_polyphony())
+ _patch->prepare_internal_poly(_poly);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+SetPolyphonyEvent::execute(ProcessContext& context)
+{
+ QueuedEvent::execute(context);
+
+ if (_patch)
+ _patch->apply_internal_poly(*_engine.maid(), _poly);
+
+ _source->unblock();
+}
+
+
+void
+SetPolyphonyEvent::post_process()
+{
+ if (_patch) {
+ _responder->respond_ok();
+ _engine.broadcaster()->send_property_change(_patch_path, "ingen:polyphony", (int32_t)_poly);
+ } else {
+ _responder->respond_error("Unable to find patch");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/SetPolyphonyEvent.hpp b/src/engine/events/SetPolyphonyEvent.hpp
new file mode 100644
index 00000000..8aba997a
--- /dev/null
+++ b/src/engine/events/SetPolyphonyEvent.hpp
@@ -0,0 +1,56 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SETPOLYPHONYEVENT_H
+#define SETPOLYPHONYEVENT_H
+
+#include <string>
+#include <raul/Array.hpp>
+#include "QueuedEvent.hpp"
+
+using std::string;
+
+namespace Ingen {
+
+class PatchImpl;
+
+
+/** Delete all nodes from a patch.
+ *
+ * \ingroup engine
+ */
+class SetPolyphonyEvent : public QueuedEvent
+{
+public:
+ SetPolyphonyEvent(Engine& engine, SharedPtr<Responder> responder, FrameTime time, QueuedEventSource* source, const string& patch_path, uint32_t poly);
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ const string _patch_path;
+ PatchImpl* _patch;
+ const uint32_t _poly;
+
+};
+
+
+} // namespace Ingen
+
+
+#endif // SETPOLYPHONYEVENT_H
diff --git a/src/engine/events/SetPortValueEvent.cpp b/src/engine/events/SetPortValueEvent.cpp
new file mode 100644
index 00000000..a99b9f9a
--- /dev/null
+++ b/src/engine/events/SetPortValueEvent.cpp
@@ -0,0 +1,224 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sstream>
+#include <lv2ext/lv2_event.h>
+#include "Responder.hpp"
+#include "SetPortValueEvent.hpp"
+#include "Engine.hpp"
+#include "PortImpl.hpp"
+#include "ClientBroadcaster.hpp"
+#include "NodeImpl.hpp"
+#include "EngineStore.hpp"
+#include "AudioBuffer.hpp"
+#include "EventBuffer.hpp"
+#include "ProcessContext.hpp"
+#include "MessageContext.hpp"
+
+using namespace std;
+
+namespace Ingen {
+
+
+/** Omni (all voices) control setting */
+SetPortValueEvent::SetPortValueEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ bool queued,
+ SampleCount timestamp,
+ const string& port_path,
+ const Raul::Atom& value)
+ : QueuedEvent(engine, responder, timestamp)
+ , _queued(queued)
+ , _omni(true)
+ , _voice_num(0)
+ , _port_path(port_path)
+ , _value(value)
+ , _port(NULL)
+ , _error(NO_ERROR)
+{
+}
+
+
+/** Voice-specific control setting */
+SetPortValueEvent::SetPortValueEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ bool queued,
+ SampleCount timestamp,
+ uint32_t voice_num,
+ const string& port_path,
+ const Raul::Atom& value)
+ : QueuedEvent(engine, responder, timestamp)
+ , _queued(queued)
+ , _omni(false)
+ , _voice_num(voice_num)
+ , _port_path(port_path)
+ , _value(value)
+ , _port(NULL)
+ , _error(NO_ERROR)
+{
+}
+
+
+SetPortValueEvent::~SetPortValueEvent()
+{
+}
+
+
+void
+SetPortValueEvent::pre_process()
+{
+ if (_queued) {
+ if (_port == NULL) {
+ if (Path::is_valid(_port_path))
+ _port = _engine.engine_store()->find_port(_port_path);
+ else
+ _error = ILLEGAL_PATH;
+ }
+
+ if (_port == NULL && _error == NO_ERROR)
+ _error = PORT_NOT_FOUND;
+ }
+
+ // Port is a message context port, set its value and
+ // call the plugin's message run function once
+ if (_port && _port->context() == Context::MESSAGE) {
+ _engine.message_context()->run(_port->parent_node());
+ }
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+SetPortValueEvent::execute(ProcessContext& context)
+{
+ Event::execute(context);
+ assert(_time >= context.start() && _time <= context.end());
+
+ if (_port && _port->context() == Context::MESSAGE)
+ return;
+
+ if (_error == NO_ERROR && _port == NULL) {
+ if (Path::is_valid(_port_path))
+ _port = _engine.engine_store()->find_port(_port_path);
+ else
+ _error = ILLEGAL_PATH;
+ }
+
+ if (_port == NULL) {
+ if (_error == NO_ERROR)
+ _error = PORT_NOT_FOUND;
+ /*} else if (_port->buffer(0)->capacity() < _data_size) {
+ _error = NO_SPACE;*/
+ } else {
+ Buffer* const buf = _port->buffer(0);
+ AudioBuffer* const abuf = dynamic_cast<AudioBuffer*>(buf);
+ if (abuf) {
+ if (_value.type() != Atom::FLOAT) {
+ _error = TYPE_MISMATCH;
+ return;
+ }
+
+ if (_omni) {
+ for (uint32_t i=0; i < _port->poly(); ++i)
+ ((AudioBuffer*)_port->buffer(i))->set_value(
+ _value.get_float(), context.start(), _time);
+ } else {
+ if (_voice_num < _port->poly())
+ ((AudioBuffer*)_port->buffer(_voice_num))->set_value(
+ _value.get_float(), context.start(), _time);
+ else
+ _error = ILLEGAL_VOICE;
+ }
+ return;
+ }
+
+ EventBuffer* const ebuf = dynamic_cast<EventBuffer*>(buf);
+
+ const LV2Features::Feature* f = _engine.world()->lv2_features->feature(LV2_URI_MAP_URI);
+ LV2URIMap* map = (LV2URIMap*)f->controller;
+
+ // FIXME: eliminate lookups
+ // FIXME: need a proper prefix system
+ if (ebuf && _value.type() == Atom::BLOB) {
+ const uint32_t frames = std::max(
+ (uint32_t)(_time - context.start()),
+ ebuf->latest_frames());
+
+ // Size 0 event, pass it along to the plugin as a typed but empty event
+ if (_value.data_size() == 0) {
+ cout << "BANG!" << endl;
+ const uint32_t type_id = map->uri_to_id(NULL, _value.get_blob_type());
+ ebuf->append(frames, 0, type_id, 0, NULL);
+ _port->raise_set_by_user_flag();
+ return;
+
+ } else if (!strcmp(_value.get_blob_type(), "lv2_midi:MidiEvent")) {
+ const uint32_t type_id = map->uri_to_id(NULL,
+ "http://lv2plug.in/ns/ext/midi#MidiEvent");
+
+ ebuf->prepare_write(context.start(), context.nframes());
+ // FIXME: use OSC midi type? avoid MIDI over OSC entirely?
+ ebuf->append(frames, 0, type_id, _value.data_size(),
+ (const uint8_t*)_value.get_blob());
+ _port->raise_set_by_user_flag();
+ return;
+ }
+ }
+
+ if (_value.type() == Atom::BLOB)
+ cerr << "WARNING: Unknown value blob type " << _value.get_blob_type() << endl;
+ else
+ cerr << "WARNING: Unknown value type " << (int)_value.type() << endl;
+ }
+}
+
+
+void
+SetPortValueEvent::post_process()
+{
+ if (_error == NO_ERROR) {
+ assert(_port != NULL);
+ _responder->respond_ok();
+ _engine.broadcaster()->send_port_value(_port_path, _value);
+
+ } else if (_error == ILLEGAL_PATH) {
+ string msg = "Illegal port path \"";
+ msg.append(_port_path).append("\"");
+ _responder->respond_error(msg);
+
+ } else if (_error == ILLEGAL_VOICE) {
+ std::ostringstream ss;
+ ss << "Illegal voice number " << _voice_num;
+ _responder->respond_error(ss.str());
+
+ } else if (_error == PORT_NOT_FOUND) {
+ string msg = "Unable to find port ";
+ msg.append(_port_path).append(" for set_port_value");
+ _responder->respond_error(msg);
+
+ } else if (_error == NO_SPACE) {
+ std::ostringstream msg("Attempt to write ");
+ msg << _value.data_size() << " bytes to " << _port_path << ", with capacity "
+ << _port->buffer_size() << endl;
+ _responder->respond_error(msg.str());
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/SetPortValueEvent.hpp b/src/engine/events/SetPortValueEvent.hpp
new file mode 100644
index 00000000..2fc68d9b
--- /dev/null
+++ b/src/engine/events/SetPortValueEvent.hpp
@@ -0,0 +1,80 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SETPORTVALUEEVENT_H
+#define SETPORTVALUEEVENT_H
+
+#include <string>
+#include "QueuedEvent.hpp"
+#include "types.hpp"
+using std::string;
+
+namespace Ingen {
+
+class PortImpl;
+
+
+/** An event to change the value of a port.
+ *
+ * This event can either be queued or immediate, depending on the queued
+ * parameter passed to the constructor. It must be passed to the appropriate
+ * place (ie queued event passed to the event queue and non-queued event
+ * processed in the audio thread) or nasty things will happen.
+ *
+ * \ingroup engine
+ */
+class SetPortValueEvent : public QueuedEvent
+{
+public:
+ SetPortValueEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ bool queued,
+ SampleCount timestamp,
+ const string& port_path,
+ const Raul::Atom& value);
+
+ SetPortValueEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ bool queued,
+ SampleCount timestamp,
+ uint32_t voice_num,
+ const string& port_path,
+ const Raul::Atom& value);
+
+ ~SetPortValueEvent();
+
+ void pre_process();
+ void execute(ProcessContext& context);
+ void post_process();
+
+private:
+ enum ErrorType { NO_ERROR, PORT_NOT_FOUND, NO_SPACE,
+ ILLEGAL_PATH, ILLEGAL_VOICE, TYPE_MISMATCH };
+
+ bool _queued;
+ bool _omni;
+ uint32_t _voice_num;
+ const string _port_path;
+ const Raul::Atom _value;
+ PortImpl* _port;
+ ErrorType _error;
+};
+
+
+} // namespace Ingen
+
+#endif // SETPORTVALUEEVENT_H
diff --git a/src/engine/events/UnregisterClientEvent.cpp b/src/engine/events/UnregisterClientEvent.cpp
new file mode 100644
index 00000000..72ab8048
--- /dev/null
+++ b/src/engine/events/UnregisterClientEvent.cpp
@@ -0,0 +1,45 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "interface/ClientInterface.hpp"
+#include "Responder.hpp"
+#include "UnregisterClientEvent.hpp"
+#include "Engine.hpp"
+#include "ClientBroadcaster.hpp"
+
+namespace Ingen {
+
+
+UnregisterClientEvent::UnregisterClientEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& uri)
+: QueuedEvent(engine, responder, timestamp)
+, _uri(uri)
+{
+}
+
+
+void
+UnregisterClientEvent::post_process()
+{
+ if (_engine.broadcaster()->unregister_client(_uri))
+ _responder->respond_ok();
+ else
+ _responder->respond_error("Unable to unregister client");
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/events/UnregisterClientEvent.hpp b/src/engine/events/UnregisterClientEvent.hpp
new file mode 100644
index 00000000..c21bc5da
--- /dev/null
+++ b/src/engine/events/UnregisterClientEvent.hpp
@@ -0,0 +1,54 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef UNREGISTERCLIENTEVENT_H
+#define UNREGISTERCLIENTEVENT_H
+
+#include "QueuedEvent.hpp"
+#include <string>
+using std::string;
+
+namespace Ingen {
+
+namespace Shared {
+ class ClientInterface;
+}
+using Shared::ClientInterface;
+
+
+/** Unregisters an OSC client so it no longer receives notifications.
+ *
+ * \ingroup engine
+ */
+class UnregisterClientEvent : public QueuedEvent
+{
+public:
+ UnregisterClientEvent(Engine& engine,
+ SharedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& uri);
+
+ void post_process();
+
+private:
+ string _uri;
+};
+
+
+} // namespace Ingen
+
+#endif // UNREGISTERCLIENTEVENT_H