From 6bd13dfa606f758212a20634f0f073596f42101f Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 18 Jul 2012 02:45:35 +0000 Subject: Working bi-directional UI <=> plugin messaging. Rewrite notification system to support variably sized notifications. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4548 a436a847-0d15-0410-975c-d299462d15a1 --- ingen/shared/URIMap.hpp | 2 +- src/gui/NodeModule.cpp | 24 ++++++++++ src/gui/NodeModule.hpp | 1 + src/server/Context.cpp | 52 ++++++++++++++++++--- src/server/Context.hpp | 14 +++--- src/server/ControlBindings.cpp | 48 ++++++++++++++++--- src/server/ControlBindings.hpp | 7 +-- src/server/InputPort.cpp | 6 +-- src/server/LV2Node.hpp | 2 +- src/server/Notification.cpp | 91 ------------------------------------- src/server/Notification.hpp | 61 ------------------------- src/server/PortImpl.cpp | 28 +++++++----- src/server/PostProcessor.cpp | 1 - src/server/Worker.cpp | 2 +- src/server/internals/Controller.cpp | 1 - src/server/wscript | 1 - src/shared/URIMap.cpp | 2 +- 17 files changed, 147 insertions(+), 196 deletions(-) delete mode 100644 src/server/Notification.cpp delete mode 100644 src/server/Notification.hpp diff --git a/ingen/shared/URIMap.hpp b/ingen/shared/URIMap.hpp index 952d67ce..bb3e55be 100644 --- a/ingen/shared/URIMap.hpp +++ b/ingen/shared/URIMap.hpp @@ -37,7 +37,7 @@ public: virtual ~URIMap() {} uint32_t map_uri(const char* uri); - const char* unmap_uri(uint32_t urid); + const char* unmap_uri(uint32_t urid) const; class Feature : public LV2Features::Feature { public: diff --git a/src/gui/NodeModule.cpp b/src/gui/NodeModule.cpp index 5ee75584..1d3f6801 100644 --- a/src/gui/NodeModule.cpp +++ b/src/gui/NodeModule.cpp @@ -19,6 +19,8 @@ #include +#include "lv2/lv2plug.in/ns/ext/atom/util.h" + #include "ingen/Interface.hpp" #include "ingen/client/NodeModel.hpp" #include "ingen/client/PatchModel.hpp" @@ -181,6 +183,24 @@ NodeModule::value_changed(uint32_t index, const Atom& value) } } +void +NodeModule::port_activity(uint32_t index, const Atom& value) +{ + if (!_plugin_ui) + return; + + const URIs& uris = app().uris(); + + // FIXME: Well, this sucks... + LV2_Atom* atom = (LV2_Atom*)malloc(sizeof(LV2_Atom) + value.size()); + atom->type = value.type(); + atom->size = value.type(); + memcpy(LV2_ATOM_BODY(atom), value.get_body(), value.size()); + _plugin_ui->port_event( + index, lv2_atom_total_size(atom), uris.atom_eventTransfer, atom); + free(atom); +} + void NodeModule::plugin_changed() { @@ -252,6 +272,10 @@ NodeModule::new_port_view(SharedPtr port) port->signal_value_changed().connect( sigc::bind<0>(sigc::mem_fun(this, &NodeModule::value_changed), port->index())); + + port->signal_activity().connect( + sigc::bind<0>(sigc::mem_fun(this, &NodeModule::port_activity), + port->index())); } Port* diff --git a/src/gui/NodeModule.hpp b/src/gui/NodeModule.hpp index 0cfa4ec8..3ec72f6d 100644 --- a/src/gui/NodeModule.hpp +++ b/src/gui/NodeModule.hpp @@ -83,6 +83,7 @@ protected: void new_port_view(SharedPtr port); void value_changed(uint32_t index, const Raul::Atom& value); + void port_activity(uint32_t index, const Raul::Atom& value); void plugin_changed(); void set_control_values(); diff --git a/src/server/Context.cpp b/src/server/Context.cpp index 9979415b..0736b451 100644 --- a/src/server/Context.cpp +++ b/src/server/Context.cpp @@ -14,20 +14,45 @@ along with Ingen. If not, see . */ +#include "ingen/shared/Forge.hpp" +#include "ingen/shared/URIMap.hpp" +#include "raul/log.hpp" + #include "Context.hpp" +#include "Engine.hpp" +#include "Broadcaster.hpp" +#include "PortImpl.hpp" namespace Ingen { namespace Server { +struct Notification +{ + inline Notification(PortImpl* p = 0, + FrameTime f = 0, + LV2_URID k = 0, + uint32_t s = 0, + Raul::Atom::TypeID t = 0) + : port(p), key(k), size(s), type(t) + {} + + PortImpl* port; + LV2_URID key; + uint32_t size; + Raul::Atom::TypeID type; +}; + void -Context::notify(Notification::Type type, - FrameTime time, - PortImpl* port, - const Raul::Atom& value, - const ControlBindings::Type btype) +Context::notify(LV2_URID key, + FrameTime time, + PortImpl* port, + uint32_t size, + Raul::Atom::TypeID type, + const void* body) { - const Notification n = Notification::make(type, time, port, value, btype); + const Notification n(port, time, key, size, type); _event_sink.write(sizeof(n), &n); + _event_sink.write(size, body); } void @@ -37,7 +62,20 @@ Context::emit_notifications() Notification note; for (uint32_t i = 0; i < read_space; i += sizeof(note)) { if (_event_sink.read(sizeof(note), ¬e) == sizeof(note)) { - Notification::post_process(note, _engine); + Raul::Atom value = _engine.world()->forge().alloc( + note.size, note.type, NULL); + if (_event_sink.read(note.size, value.get_body()) == note.size) { + i += note.size; + const char* key = _engine.world()->uri_map().unmap_uri(note.key); + if (key) { + _engine.broadcaster()->set_property( + note.port->path(), key, value); + } else { + Raul::error("Error unmapping notification key URI\n"); + } + } else { + Raul::error("Error reading from notification ring\n"); + } } } } diff --git a/src/server/Context.hpp b/src/server/Context.hpp index 8afe1caa..7bcfb136 100644 --- a/src/server/Context.hpp +++ b/src/server/Context.hpp @@ -22,12 +22,12 @@ #include "ingen/shared/World.hpp" #include "types.hpp" -#include "Notification.hpp" namespace Ingen { namespace Server { class Engine; +class PortImpl; /** Graph execution context. * @@ -63,12 +63,12 @@ public: virtual ~Context() {} /** Send a notification from this run context. */ - void notify( - Notification::Type type = Notification::NIL, - FrameTime time = 0, - PortImpl* port = 0, - const Raul::Atom& value = Raul::Atom(), - const ControlBindings::Type btype = ControlBindings::NULL_CONTROL); + void notify(LV2_URID key = 0, + FrameTime time = 0, + PortImpl* port = 0, + uint32_t size = 0, + Raul::Atom::TypeID type = 0, + const void* body = NULL); /** Emit pending notifications in some other non-realtime thread. */ void emit_notifications(); diff --git a/src/server/ControlBindings.cpp b/src/server/ControlBindings.cpp index 844568d8..32d99c52 100644 --- a/src/server/ControlBindings.cpp +++ b/src/server/ControlBindings.cpp @@ -17,7 +17,6 @@ #include #include "ingen/shared/URIMap.hpp" - #include "ingen/shared/URIs.hpp" #include "ingen/shared/World.hpp" #include "lv2/lv2plug.in/ns/ext/atom/util.h" @@ -27,7 +26,6 @@ #include "AudioBuffer.hpp" #include "ControlBindings.hpp" #include "Engine.hpp" -#include "Notification.hpp" #include "PortImpl.hpp" #include "ProcessContext.hpp" #include "ThreadManager.hpp" @@ -47,6 +45,8 @@ ControlBindings::ControlBindings(Engine& engine) engine.world()->uris().atom_Sequence, 4096)) // FIXME: capacity? { + lv2_atom_forge_init( + &_forge, &engine.world()->uri_map().urid_map_feature()->urid_map); } ControlBindings::~ControlBindings() @@ -263,6 +263,37 @@ ControlBindings::port_value_to_control(PortImpl* port, } } +static void +forge_binding(const Shared::URIs& uris, + LV2_Atom_Forge* forge, + ControlBindings::Type binding_type, + int32_t value) +{ + LV2_Atom_Forge_Frame frame; + switch (binding_type) { + case ControlBindings::MIDI_CC: + lv2_atom_forge_blank(forge, &frame, 0, uris.midi_Controller); + lv2_atom_forge_property_head(forge, uris.midi_controllerNumber, 0); + lv2_atom_forge_int(forge, value); + break; + case ControlBindings::MIDI_BENDER: + lv2_atom_forge_blank(forge, &frame, 0, uris.midi_Bender); + break; + case ControlBindings::MIDI_CHANNEL_PRESSURE: + lv2_atom_forge_blank(forge, &frame, 0, uris.midi_ChannelPressure); + break; + case ControlBindings::MIDI_NOTE: + lv2_atom_forge_blank(forge, &frame, 0, uris.midi_NoteOn); + lv2_atom_forge_property_head(forge, uris.midi_noteNumber, 0); + lv2_atom_forge_int(forge, value); + break; + case ControlBindings::MIDI_RPN: // TODO + case ControlBindings::MIDI_NRPN: // TODO + case ControlBindings::NULL_CONTROL: + break; + } +} + void ControlBindings::set_port_value(ProcessContext& context, PortImpl* port, @@ -281,7 +312,9 @@ ControlBindings::set_port_value(ProcessContext& context, reinterpret_cast(port->buffer(v).get())->set_value( port_value.get_float(), context.start(), context.start()); - context.notify(Notification::PORT_VALUE, context.start(), port, port_value); + Shared::URIs& uris = context.engine().world()->uris(); + context.notify(uris.ingen_value, context.start(), port, + port_value.size(), port_value.type(), port_value.get_body()); } bool @@ -297,11 +330,14 @@ ControlBindings::bind(ProcessContext& context, Key key) _bindings->insert(make_pair(key, _learn_port)); - context.notify(Notification::PORT_BINDING, + uint8_t buf[128]; + lv2_atom_forge_set_buffer(&_forge, buf, sizeof(buf)); + forge_binding(uris, &_forge, key.type, key.num); + const LV2_Atom* atom = (const LV2_Atom*)buf; + context.notify(uris.ingen_controlBinding, context.start(), _learn_port, - context.engine().world()->forge().make(key.num), - key.type); + atom->size, atom->type, LV2_ATOM_BODY(atom)); _learn_port = NULL; return true; diff --git a/src/server/ControlBindings.hpp b/src/server/ControlBindings.hpp index 2a107dfc..c98175ab 100644 --- a/src/server/ControlBindings.hpp +++ b/src/server/ControlBindings.hpp @@ -20,6 +20,7 @@ #include #include +#include "lv2/lv2plug.in/ns/ext/atom/forge.h" #include "raul/Atom.hpp" #include "raul/Path.hpp" #include "raul/SharedPtr.hpp" @@ -106,11 +107,11 @@ private: const Raul::Atom& min, const Raul::Atom& max) const; - Engine& _engine; - PortImpl* _learn_port; - + Engine& _engine; + PortImpl* _learn_port; SharedPtr _bindings; BufferRef _feedback; + LV2_Atom_Forge _forge; }; } // namespace Server diff --git a/src/server/InputPort.cpp b/src/server/InputPort.cpp index d94a971b..70d3662c 100644 --- a/src/server/InputPort.cpp +++ b/src/server/InputPort.cpp @@ -24,7 +24,6 @@ #include "Engine.hpp" #include "InputPort.hpp" #include "NodeImpl.hpp" -#include "Notification.hpp" #include "OutputPort.hpp" #include "ProcessContext.hpp" #include "ingen/shared/URIs.hpp" @@ -154,10 +153,11 @@ InputPort::remove_edge(ProcessContext& context, const OutputPort* tail) if (_edges.empty()) { if (is_a(PortType::AUDIO)) { // Send an update peak of 0.0 to reset to silence - context.notify(Notification::PORT_ACTIVITY, + const Raul::Atom z = context.engine().world()->forge().make(0.0f); + context.notify(context.engine().world()->uris().ingen_activity, context.start(), this, - context.engine().world()->forge().make(0.0f)); + z.size(), z.type(), z.get_body()); } _broadcast = false; } diff --git a/src/server/LV2Node.hpp b/src/server/LV2Node.hpp index 18d96dc8..b588de78 100644 --- a/src/server/LV2Node.hpp +++ b/src/server/LV2Node.hpp @@ -88,7 +88,7 @@ protected: ~Response() { free(data); } - + const uint32_t size; void* const data; }; diff --git a/src/server/Notification.cpp b/src/server/Notification.cpp deleted file mode 100644 index d3298f8e..00000000 --- a/src/server/Notification.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include "lv2/lv2plug.in/ns/ext/atom/forge.h" - -#include "ingen/shared/URIMap.hpp" -#include "ingen/shared/URIs.hpp" - -#include "Broadcaster.hpp" -#include "Engine.hpp" -#include "Notification.hpp" -#include "PortImpl.hpp" - -namespace Ingen { -namespace Server { - -void -Notification::post_process(Notification& note, - Engine& engine) -{ - const Ingen::Shared::URIs& uris = engine.world()->uris(); - LV2_Atom_Forge forge; - uint8_t buf[128]; - switch (note.type) { - case PORT_VALUE: - engine.broadcaster()->set_property(note.port->path(), - uris.ingen_value, - note.value); - break; - case PORT_ACTIVITY: - engine.broadcaster()->set_property(note.port->path(), - uris.ingen_activity, - note.value); - break; - case PORT_BINDING: { - lv2_atom_forge_init( - &forge, &engine.world()->uri_map().urid_map_feature()->urid_map); - lv2_atom_forge_set_buffer(&forge, buf, sizeof(buf)); - LV2_Atom_Forge_Frame frame; - switch (note.binding_type) { - case ControlBindings::MIDI_CC: - lv2_atom_forge_blank(&forge, &frame, 0, uris.midi_Controller); - lv2_atom_forge_property_head(&forge, uris.midi_controllerNumber, 0); - lv2_atom_forge_int(&forge, note.value.get_int32()); - break; - case ControlBindings::MIDI_BENDER: - lv2_atom_forge_blank(&forge, &frame, 0, uris.midi_Bender); - break; - case ControlBindings::MIDI_CHANNEL_PRESSURE: - lv2_atom_forge_blank(&forge, &frame, 0, uris.midi_ChannelPressure); - break; - case ControlBindings::MIDI_NOTE: - lv2_atom_forge_blank(&forge, &frame, 0, uris.midi_NoteOn); - lv2_atom_forge_property_head(&forge, uris.midi_noteNumber, 0); - lv2_atom_forge_int(&forge, note.value.get_int32()); - break; - case ControlBindings::MIDI_RPN: // TODO - case ControlBindings::MIDI_NRPN: // TODO - case ControlBindings::NULL_CONTROL: - break; - } - LV2_Atom* atom = (LV2_Atom*)buf; - // FIXME: not thread-safe - const Raul::Atom dict_atom = engine.world()->forge().alloc( - atom->size, atom->type, LV2_ATOM_BODY(atom)); - note.port->set_property(uris.ingen_controlBinding, dict_atom); - engine.broadcaster()->set_property(note.port->path(), - uris.ingen_controlBinding, - dict_atom); - break; - } - case NIL: - break; - } -} - -} // namespace Server -} // namespace Ingen diff --git a/src/server/Notification.hpp b/src/server/Notification.hpp deleted file mode 100644 index d24a523d..00000000 --- a/src/server/Notification.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_ENGINE_NOTIFICATION_HPP -#define INGEN_ENGINE_NOTIFICATION_HPP - -#include "ControlBindings.hpp" -#include "types.hpp" - -namespace Ingen { -namespace Server { - -class Engine; -class PortImpl; - -struct Notification -{ - enum Type { - NIL, - PORT_VALUE, - PORT_ACTIVITY, - PORT_BINDING - }; - - static inline Notification make( - Type type = NIL, - FrameTime time = 0, - PortImpl* port = 0, - const Raul::Atom& value = Raul::Atom(), - const ControlBindings::Type btype = ControlBindings::NULL_CONTROL) - { - const Notification note = { port, type, btype, value }; - return note; - } - - static void post_process(Notification& note, - Engine& engine); - - PortImpl* port; - Type type; - ControlBindings::Type binding_type; - Raul::Atom value; -}; - -} // namespace Server -} // namespace Ingen - -#endif // INGEN_ENGINE_NOTIFICATION_HPP diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp index d4fcb6c8..6920198c 100644 --- a/src/server/PortImpl.cpp +++ b/src/server/PortImpl.cpp @@ -15,6 +15,7 @@ */ #include "ingen/shared/URIs.hpp" +#include "lv2/lv2plug.in/ns/ext/atom/util.h" #include "raul/Array.hpp" #include "raul/Maid.hpp" @@ -22,7 +23,6 @@ #include "BufferFactory.hpp" #include "Engine.hpp" #include "NodeImpl.hpp" -#include "Notification.hpp" #include "PortImpl.hpp" #include "PortType.hpp" #include "ThreadManager.hpp" @@ -218,28 +218,33 @@ PortImpl::clear_buffers() void PortImpl::broadcast_value(Context& context, bool force) { - Shared::Forge& forge = context.engine().world()->forge(); - Notification::Type ntype = Notification::PORT_VALUE; - Raul::Atom val; + Shared::Forge& forge = context.engine().world()->forge(); + Shared::URIs& uris = context.engine().world()->uris(); + LV2_URID key = 0; + Raul::Atom val; switch (_type.symbol()) { case PortType::UNKNOWN: break; case PortType::AUDIO: - val = forge.make(((AudioBuffer*)buffer(0).get())->peak(context)); - ntype = Notification::PORT_ACTIVITY; + key = uris.ingen_activity; + val = forge.make(((AudioBuffer*)buffer(0).get())->peak(context)); break; case PortType::CONTROL: case PortType::CV: + key = uris.ingen_value; val = forge.make(((AudioBuffer*)buffer(0).get())->value_at(0)); break; case PortType::ATOM: if (_buffer_type == _bufs.uris().atom_Sequence) { LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)buffer(0)->atom(); - if (seq->atom.size > sizeof(LV2_Atom_Sequence_Body)) { - context.notify(Notification::PORT_ACTIVITY, - context.start(), + // TODO: Filter events, or only send one activity for blinkenlights + LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { + context.notify(uris.ingen_activity, + context.start() + ev->time.frames, this, - forge.make(true)); + ev->body.size, + ev->body.type, + LV2_ATOM_BODY(&ev->body)); } } break; @@ -247,7 +252,8 @@ PortImpl::broadcast_value(Context& context, bool force) if (val.is_valid() && (force || val != _last_broadcasted_value)) { _last_broadcasted_value = val; - context.notify(ntype, context.start(), this, val); + context.notify(key, context.start(), this, + val.size(), val.type(), val.get_body()); } } diff --git a/src/server/PostProcessor.cpp b/src/server/PostProcessor.cpp index df83cc7b..16b0317d 100644 --- a/src/server/PostProcessor.cpp +++ b/src/server/PostProcessor.cpp @@ -18,7 +18,6 @@ #include "Engine.hpp" #include "Event.hpp" -#include "Notification.hpp" #include "PostProcessor.hpp" #include "ProcessContext.hpp" diff --git a/src/server/Worker.cpp b/src/server/Worker.cpp index c3cebffd..006b45d4 100644 --- a/src/server/Worker.cpp +++ b/src/server/Worker.cpp @@ -66,7 +66,7 @@ Worker::request(LV2Node* node, Raul::error("Error writing body to work request ring\n"); return LV2_WORKER_ERR_UNKNOWN; } - + _sem.post(); return LV2_WORKER_SUCCESS; diff --git a/src/server/internals/Controller.cpp b/src/server/internals/Controller.cpp index 41b56a77..76183e85 100644 --- a/src/server/internals/Controller.cpp +++ b/src/server/internals/Controller.cpp @@ -27,7 +27,6 @@ #include "Engine.hpp" #include "InputPort.hpp" #include "InternalPlugin.hpp" -#include "Notification.hpp" #include "OutputPort.hpp" #include "PostProcessor.hpp" #include "ProcessContext.hpp" diff --git a/src/server/wscript b/src/server/wscript index 1c5e57bd..fbdf78fa 100644 --- a/src/server/wscript +++ b/src/server/wscript @@ -23,7 +23,6 @@ def build(bld): MessageContext.cpp NodeFactory.cpp NodeImpl.cpp - Notification.cpp OutputPort.cpp PatchImpl.cpp PortImpl.cpp diff --git a/src/shared/URIMap.cpp b/src/shared/URIMap.cpp index f9bf7072..b8981fd3 100644 --- a/src/shared/URIMap.cpp +++ b/src/shared/URIMap.cpp @@ -88,7 +88,7 @@ URIMap::map_uri(const char* uri) } const char* -URIMap::unmap_uri(uint32_t urid) +URIMap::unmap_uri(uint32_t urid) const { return _urid_unmap_feature->unmap(urid); } -- cgit v1.2.1