diff options
author | David Robillard <d@drobilla.net> | 2008-09-30 16:50:21 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2008-09-30 16:50:21 +0000 |
commit | 93850c202de8b073a1ce1dd8bd246d407bce4e2f (patch) | |
tree | 6910b135bf4eff12de1af116cef73f6e9c107cd0 /src/engine/events | |
parent | a8bf5272d096de73507d2eab47f282c345f4ca8a (diff) | |
download | ingen-93850c202de8b073a1ce1dd8bd246d407bce4e2f.tar.gz ingen-93850c202de8b073a1ce1dd8bd246d407bce4e2f.tar.bz2 ingen-93850c202de8b073a1ce1dd8bd246d407bce4e2f.zip |
Flatten ingen source directory heirarchy a bit.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@1551 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/engine/events')
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 |