From c7f671ff5bf9cf2559697bbc90cf3cee97cc7975 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 15 Sep 2011 07:17:10 +0000 Subject: Fix control bindings (MIDI learn). git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@3464 a436a847-0d15-0410-975c-d299462d15a1 --- src/server/ControlBindings.cpp | 85 +++++++++++++++++++++++--------------- src/server/ControlBindings.hpp | 27 +++++++++--- src/server/GraphObjectImpl.cpp | 2 + src/server/LV2Node.cpp | 2 + src/server/Notification.cpp | 33 +++++---------- src/server/Notification.hpp | 20 +++++---- src/server/PortImpl.cpp | 10 +++-- src/server/PortImpl.hpp | 12 ++++++ src/server/PostProcessor.cpp | 19 ++++----- src/server/events/CreatePort.cpp | 1 - src/server/events/SetMetadata.cpp | 12 +++++- src/server/events/SetMetadata.hpp | 7 +++- src/server/events/SetPortValue.cpp | 4 +- src/server/events/SetPortValue.hpp | 11 +++-- 14 files changed, 153 insertions(+), 92 deletions(-) (limited to 'src/server') diff --git a/src/server/ControlBindings.cpp b/src/server/ControlBindings.cpp index 44a22f98..39db7de1 100644 --- a/src/server/ControlBindings.cpp +++ b/src/server/ControlBindings.cpp @@ -52,10 +52,18 @@ ControlBindings::~ControlBindings() } ControlBindings::Key -ControlBindings::port_binding(PortImpl* port) +ControlBindings::port_binding(PortImpl* port) const { + ThreadManager::assert_thread(THREAD_PRE_PROCESS); const Ingen::Shared::LV2URIMap& uris = *_engine.world()->uris().get(); const Raul::Atom& binding = port->get_property(uris.ingen_controlBinding); + return binding_key(binding); +} + +ControlBindings::Key +ControlBindings::binding_key(const Raul::Atom& binding) const +{ + const Ingen::Shared::LV2URIMap& uris = *_engine.world()->uris().get(); Key key; if (binding.type() == Atom::DICT) { const Atom::DictValue& dict = binding.get_dict(); @@ -100,20 +108,26 @@ ControlBindings::midi_event_key(uint16_t size, uint8_t* buf, uint16_t& value) } void -ControlBindings::port_binding_changed(ProcessContext& context, PortImpl* port) +ControlBindings::port_binding_changed(ProcessContext& context, + PortImpl* port, + const Raul::Atom& binding) { - Key key = port_binding(port); - if (key) + const Key key = binding_key(binding); + if (key) { _bindings->insert(make_pair(key, port)); + } } void -ControlBindings::port_value_changed(ProcessContext& context, PortImpl* port) +ControlBindings::port_value_changed(ProcessContext& context, + PortImpl* port, + Key key, + const Raul::Atom& value_atom) { const Ingen::Shared::LV2URIMap& uris = *_engine.world()->uris().get(); - Key key = port_binding(port); if (key) { - int16_t value = port_value_to_control(port, key.type); + int16_t value = port_value_to_control( + port, key.type, value_atom, port->minimum(), port->maximum()); uint16_t size = 0; uint8_t buf[4]; switch (key.type) { @@ -162,14 +176,14 @@ ControlBindings::learn(PortImpl* port) } Raul::Atom -ControlBindings::control_to_port_value(PortImpl* port, Type type, int16_t value) +ControlBindings::control_to_port_value(Type type, + int16_t value, + const Raul::Atom& min_atom, + const Raul::Atom& max_atom) const { - const Ingen::Shared::LV2URIMap& uris = *_engine.world()->uris().get(); - - // TODO: cache these to avoid the lookup - float min = port->get_property(uris.lv2_minimum).get_float(); - float max = port->get_property(uris.lv2_maximum).get_float(); - bool toggled = port->has_property(uris.lv2_portProperty, uris.lv2_toggled); + float min = min_atom.get_float(); + float max = max_atom.get_float(); + //bool toggled = port->has_property(uris.lv2_portProperty, uris.lv2_toggled); float normal = 0.0f; switch (type) { @@ -188,26 +202,26 @@ ControlBindings::control_to_port_value(PortImpl* port, Type type, int16_t value) } float scaled_value = normal * (max - min) + min; - if (toggled) - scaled_value = (scaled_value < 0.5) ? 0.0 : 1.0; + //if (toggled) + // scaled_value = (scaled_value < 0.5) ? 0.0 : 1.0; return Raul::Atom(scaled_value); } int16_t -ControlBindings::port_value_to_control(PortImpl* port, Type type) +ControlBindings::port_value_to_control(PortImpl* port, + Type type, + const Raul::Atom& value_atom, + const Raul::Atom& min_atom, + const Raul::Atom& max_atom) const { - if (port->value().type() != Atom::FLOAT) + if (value_atom.type() != Atom::FLOAT) return 0; - const Ingen::Shared::LV2URIMap& uris = *_engine.world()->uris().get(); - - // TODO: cache these to avoid the lookup - float min = port->get_property(uris.lv2_minimum).get_float(); - float max = port->get_property(uris.lv2_maximum).get_float(); - //bool toggled = port->has_property(uris.lv2_portProperty, uris.lv2_toggled); - float value = port->value().get_float(); - float normal = (value - min) / (max - min); + const float min = min_atom.get_float(); + const float max = max_atom.get_float(); + const float value = value_atom.get_float(); + float normal = (value - min) / (max - min); if (normal < 0.0f) { warn << "Value " << value << " (normal " << normal << ") for " @@ -235,9 +249,14 @@ ControlBindings::port_value_to_control(PortImpl* port, Type type) } void -ControlBindings::set_port_value(ProcessContext& context, PortImpl* port, Type type, int16_t value) +ControlBindings::set_port_value(ProcessContext& context, + PortImpl* port, + Type type, + int16_t value) { - const Raul::Atom port_value(control_to_port_value(port, type, value)); + const Raul::Atom port_value( + control_to_port_value(type, value, port->minimum(), port->maximum())); + port->set_value(port_value); assert(port_value.type() == Atom::FLOAT); @@ -247,8 +266,8 @@ ControlBindings::set_port_value(ProcessContext& context, PortImpl* port, Type ty reinterpret_cast(port->buffer(v).get())->set_value( port_value.get_float(), context.start(), context.start()); - const Notification note(Notification::PORT_VALUE, - context.start(), port, port_value); + const Notification note = Notification::make( + Notification::PORT_VALUE, context.start(), port, port_value); context.event_sink().write(sizeof(note), ¬e); } @@ -265,9 +284,9 @@ ControlBindings::bind(ProcessContext& context, Key key) _bindings->insert(make_pair(key, _learn_port)); - // FIXME - //const Events::SendBinding ev(context.engine(), context.start(), _learn_port, key.type, key.num); - //context.event_sink().write(sizeof(ev), &ev); + const Notification note = Notification::make( + Notification::PORT_BINDING, context.start(), _learn_port, key.num, key.type); + context.event_sink().write(sizeof(note), ¬e); _learn_port = NULL; return true; diff --git a/src/server/ControlBindings.hpp b/src/server/ControlBindings.hpp index 92eee7c7..b1e69498 100644 --- a/src/server/ControlBindings.hpp +++ b/src/server/ControlBindings.hpp @@ -60,10 +60,20 @@ public: explicit ControlBindings(Engine& engine); ~ControlBindings(); + Key port_binding(PortImpl* port) const; + Key binding_key(const Raul::Atom& binding) const; + void learn(PortImpl* port); - void port_binding_changed(ProcessContext& context, PortImpl* port); - void port_value_changed(ProcessContext& context, PortImpl* port); + void port_binding_changed(ProcessContext& context, + PortImpl* port, + const Raul::Atom& binding); + + void port_value_changed(ProcessContext& context, + PortImpl* port, + Key key, + const Raul::Atom& value); + void pre_process(ProcessContext& context, EventBuffer* control_in); void post_process(ProcessContext& context, EventBuffer* control_out); @@ -80,14 +90,21 @@ public: SharedPtr remove(PortImpl* port); private: - Key port_binding(PortImpl* port); Key midi_event_key(uint16_t size, uint8_t* buf, uint16_t& value); void set_port_value(ProcessContext& context, PortImpl* port, Type type, int16_t value); bool bind(ProcessContext& context, Key key); - Raul::Atom control_to_port_value(PortImpl* port, Type type, int16_t value); - int16_t port_value_to_control(PortImpl* port, Type type); + Raul::Atom control_to_port_value(Type type, + int16_t value, + const Raul::Atom& min, + const Raul::Atom& max) const; + + int16_t port_value_to_control(PortImpl* port, + Type type, + const Raul::Atom& value, + const Raul::Atom& min, + const Raul::Atom& max) const; Engine& _engine; PortImpl* _learn_port; diff --git a/src/server/GraphObjectImpl.cpp b/src/server/GraphObjectImpl.cpp index f4677e4f..88edfb0e 100644 --- a/src/server/GraphObjectImpl.cpp +++ b/src/server/GraphObjectImpl.cpp @@ -20,6 +20,7 @@ #include "GraphObjectImpl.hpp" #include "PatchImpl.hpp" #include "EngineStore.hpp" +#include "ThreadManager.hpp" using namespace std; using namespace Raul; @@ -40,6 +41,7 @@ GraphObjectImpl::GraphObjectImpl(Ingen::Shared::LV2URIMap& uris, const Atom& GraphObjectImpl::get_property(const Raul::URI& key) const { + ThreadManager::assert_not_thread(THREAD_PROCESS); static const Atom null_atom; Resource::Properties::const_iterator i = properties().find(key); return (i != properties().end()) ? i->second : null_atom; diff --git a/src/server/LV2Node.cpp b/src/server/LV2Node.cpp index f6a80cb8..8b8b1b29 100644 --- a/src/server/LV2Node.cpp +++ b/src/server/LV2Node.cpp @@ -290,9 +290,11 @@ LV2Node::instantiate(BufferFactory& bufs) port->set_value(val); if (!isnan(min_values[j])) { port->set_property(uris.lv2_minimum, min_values[j]); + port->set_minimum(min_values[j]); } if (!isnan(max_values[j])) { port->set_property(uris.lv2_maximum, max_values[j]); + port->set_maximum(max_values[j]); } } diff --git a/src/server/Notification.cpp b/src/server/Notification.cpp index 652662f2..9181147f 100644 --- a/src/server/Notification.cpp +++ b/src/server/Notification.cpp @@ -24,37 +24,26 @@ namespace Ingen { namespace Server { -Notification::Notification(Type y, - FrameTime t, - PortImpl* p, - const Raul::Atom& v, - const ControlBindings::Type bt) - : type(y) - , binding_type(bt) - , time(t) - , port(p) - , value(v) -{} - void -Notification::post_process(Engine& engine) +Notification::post_process(Notification& note, + Engine& engine) { - switch (type) { + switch (note.type) { case PORT_VALUE: engine.broadcaster()->set_property( - port->path(), - engine.world()->uris()->ingen_value, value); + note.port->path(), + engine.world()->uris()->ingen_value, note.value); break; case PORT_ACTIVITY: - engine.broadcaster()->activity(port->path()); + engine.broadcaster()->activity(note.port->path()); break; case PORT_BINDING: { const Ingen::Shared::LV2URIMap& uris = *engine.world()->uris().get(); Raul::Atom::DictValue dict; - switch (binding_type) { + switch (note.binding_type) { case ControlBindings::MIDI_CC: dict[uris.rdf_type] = uris.midi_Controller; - dict[uris.midi_controllerNumber] = value.get_int32(); + dict[uris.midi_controllerNumber] = note.value.get_int32(); break; case ControlBindings::MIDI_BENDER: dict[uris.rdf_type] = uris.midi_Bender; @@ -64,15 +53,15 @@ Notification::post_process(Engine& engine) break; case ControlBindings::MIDI_NOTE: dict[uris.rdf_type] = uris.midi_Note; - dict[uris.midi_noteNumber] = value.get_int32(); + dict[uris.midi_noteNumber] = note.value.get_int32(); break; case ControlBindings::MIDI_RPN: // TODO case ControlBindings::MIDI_NRPN: // TODO case ControlBindings::NULL_CONTROL: break; } - port->set_property(uris.ingen_controlBinding, dict); // FIXME: thread unsafe - engine.broadcaster()->set_property(port->path(), + note.port->set_property(uris.ingen_controlBinding, dict); // FIXME: thread unsafe + engine.broadcaster()->set_property(note.port->path(), uris.ingen_controlBinding, dict); break; diff --git a/src/server/Notification.hpp b/src/server/Notification.hpp index f6824318..8fea775e 100644 --- a/src/server/Notification.hpp +++ b/src/server/Notification.hpp @@ -38,20 +38,24 @@ struct Notification PORT_BINDING }; - Notification( + 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 ControlBindings::Type btype = ControlBindings::NULL_CONTROL) + { + const Notification note = { port, type, btype, value }; + return note; + } - void post_process(Engine& engine); + static void post_process(Notification& note, + Engine& engine); - Type type; - const ControlBindings::Type binding_type; - FrameTime time; - PortImpl* port; - const Raul::Atom value; + PortImpl* port; + Type type; + ControlBindings::Type binding_type; + Raul::Atom value; }; } // namespace Server diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp index 7d309bc3..2e1ad61e 100644 --- a/src/server/PortImpl.cpp +++ b/src/server/PortImpl.cpp @@ -56,6 +56,8 @@ PortImpl::PortImpl(BufferFactory& bufs, , _buffer_size(buffer_size) , _buffer_type(type) , _value(value) + , _min(0.0f) + , _max(1.0f) , _last_broadcasted_value(value) , _context(Context::AUDIO) , _buffers(new Array(static_cast(poly))) @@ -211,8 +213,8 @@ PortImpl::broadcast_value(Context& context, bool force) break; case PortType::EVENTS: if (((EventBuffer*)buffer(0).get())->event_count() > 0) { - const Notification note(Notification::PORT_ACTIVITY, - context.start(), this, Atom(true)); + const Notification note = Notification::make( + Notification::PORT_ACTIVITY, context.start(), this, Atom(true)); context.event_sink().write(sizeof(note), ¬e); } break; @@ -226,8 +228,8 @@ PortImpl::broadcast_value(Context& context, bool force) if (val.is_valid() && (force || val != _last_broadcasted_value)) { _last_broadcasted_value = val; - const Notification note(Notification::PORT_VALUE, - context.start(), this, val); + const Notification note = Notification::make( + Notification::PORT_VALUE, context.start(), this, val); context.event_sink().write(sizeof(note), ¬e); } } diff --git a/src/server/PortImpl.hpp b/src/server/PortImpl.hpp index d9540bb2..b00504f8 100644 --- a/src/server/PortImpl.hpp +++ b/src/server/PortImpl.hpp @@ -83,6 +83,16 @@ public: const Raul::Atom& value() const { return _value; } void set_value(const Raul::Atom& v) { _value = v; } + const Raul::Atom& minimum() const { return _min; } + const Raul::Atom& maximum() const { return _max; } + + /* The following two methods store the range in variables so it can be + accessed in the process thread, which is required for applying control + bindings from incoming MIDI data. + */ + void set_minimum(const Raul::Atom& min) { _min = min; } + void set_maximum(const Raul::Atom& max) { _max = max; } + inline BufferFactory::Ref buffer(uint32_t voice) const { return _buffers->at((_poly == 1) ? 0 : voice); } @@ -160,6 +170,8 @@ protected: PortType _buffer_type; std::set _types; Raul::Atom _value; + Raul::Atom _min; + Raul::Atom _max; Raul::Atom _last_broadcasted_value; Context::ID _context; Raul::Array* _buffers; diff --git a/src/server/PostProcessor.cpp b/src/server/PostProcessor.cpp index 2dd9666b..5a54d728 100644 --- a/src/server/PostProcessor.cpp +++ b/src/server/PostProcessor.cpp @@ -71,18 +71,13 @@ PostProcessor::process() /* FIXME: process events from all threads if parallel */ /* Process audio thread generated events */ - while (true) { - Driver* driver = _engine.driver(); - Notification note; - if (driver && driver->context().event_sink().peek(sizeof(note), ¬e)) { - if (note.time > end_time) { - break; - } - - note.post_process(_engine); - driver->context().event_sink().skip(sizeof(note)); - } else { - break; + Driver* driver = _engine.driver(); + if (driver) { + Notification note; + const uint32_t read_space = driver->context().event_sink().read_space(); + for (uint32_t i = 0; i <= read_space; i += sizeof(note)) { + driver->context().event_sink().read(sizeof(note), ¬e); + Notification::post_process(note, _engine); } } diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp index ba46a35d..4541892b 100644 --- a/src/server/events/CreatePort.cpp +++ b/src/server/events/CreatePort.cpp @@ -148,7 +148,6 @@ CreatePort::execute(ProcessContext& context) if (_patch_port) { _engine.maid()->push(_patch->external_ports()); _patch->external_ports(_ports_array); - _engine.control_bindings()->port_binding_changed(context, _patch_port); } if (_driver_port) { diff --git a/src/server/events/SetMetadata.cpp b/src/server/events/SetMetadata.cpp index 23109a2f..b01e17cb 100644 --- a/src/server/events/SetMetadata.cpp +++ b/src/server/events/SetMetadata.cpp @@ -268,6 +268,8 @@ SetMetadata::execute(ProcessContext& context) return; } + const Ingen::Shared::LV2URIMap& uris = *_engine.world()->uris().get(); + if (_create_event) { _create_event->execute(context); } @@ -281,6 +283,7 @@ SetMetadata::execute(ProcessContext& context) std::vector::const_iterator t = _types.begin(); for (Properties::const_iterator p = _properties.begin(); p != _properties.end(); ++p, ++t) { + const Raul::Atom& key = p->first; const Raul::Atom& value = p->second; switch (*t) { case ENABLE_BROADCAST: @@ -317,7 +320,7 @@ SetMetadata::execute(ProcessContext& context) break; case CONTROL_BINDING: if (port) { - _engine.control_bindings()->port_binding_changed(context, port); + _engine.control_bindings()->port_binding_changed(context, port, value); } else if (node) { if (node->plugin_impl()->type() == Plugin::Internal) { node->learn(); @@ -325,6 +328,13 @@ SetMetadata::execute(ProcessContext& context) } break; case NONE: + if (port) { + if (key == uris.lv2_minimum) { + port->set_minimum(value); + } else if (key == uris.lv2_maximum) { + port->set_maximum(value); + } + } break; } } diff --git a/src/server/events/SetMetadata.hpp b/src/server/events/SetMetadata.hpp index 59856730..6e2a93a2 100644 --- a/src/server/events/SetMetadata.hpp +++ b/src/server/events/SetMetadata.hpp @@ -18,10 +18,14 @@ #ifndef INGEN_EVENTS_SETMETADATA_HPP #define INGEN_EVENTS_SETMETADATA_HPP + #include + #include "raul/URI.hpp" -#include "shared/ResourceImpl.hpp" + +#include "ControlBindings.hpp" #include "QueuedEvent.hpp" +#include "shared/ResourceImpl.hpp" namespace Ingen { namespace Server { @@ -113,6 +117,7 @@ private: std::string _error_predicate; bool _create; Resource::Graph _context; + ControlBindings::Key _binding; SharedPtr _old_bindings; }; diff --git a/src/server/events/SetPortValue.cpp b/src/server/events/SetPortValue.cpp index 4af14d44..e5877d47 100644 --- a/src/server/events/SetPortValue.cpp +++ b/src/server/events/SetPortValue.cpp @@ -101,6 +101,8 @@ SetPortValue::pre_process() _port->set_property(_engine.world()->uris()->ingen_value, _value); } + _binding = _engine.control_bindings()->port_binding(_port); + QueuedEvent::pre_process(); } @@ -114,7 +116,7 @@ SetPortValue::execute(ProcessContext& context) return; apply(context); - _engine.control_bindings()->port_value_changed(context, _port); + _engine.control_bindings()->port_value_changed(context, _port, _binding, _value); } void diff --git a/src/server/events/SetPortValue.hpp b/src/server/events/SetPortValue.hpp index 6f3cde87..13d77225 100644 --- a/src/server/events/SetPortValue.hpp +++ b/src/server/events/SetPortValue.hpp @@ -19,6 +19,8 @@ #define INGEN_EVENTS_SETPORTVALUE_HPP #include "raul/Atom.hpp" + +#include "ControlBindings.hpp" #include "QueuedEvent.hpp" #include "types.hpp" @@ -70,10 +72,11 @@ private: void apply(Context& context); - bool _queued; - const Raul::Path _port_path; - const Raul::Atom _value; - PortImpl* _port; + bool _queued; + const Raul::Path _port_path; + const Raul::Atom _value; + PortImpl* _port; + ControlBindings::Key _binding; }; } // namespace Server -- cgit v1.2.1