diff options
Diffstat (limited to 'src/server/ControlBindings.cpp')
-rw-r--r-- | src/server/ControlBindings.cpp | 138 |
1 files changed, 85 insertions, 53 deletions
diff --git a/src/server/ControlBindings.cpp b/src/server/ControlBindings.cpp index 8bf52dfd..489d5384 100644 --- a/src/server/ControlBindings.cpp +++ b/src/server/ControlBindings.cpp @@ -23,18 +23,18 @@ #include "RunContext.hpp" #include "ThreadManager.hpp" -#include "ingen/Atom.hpp" -#include "ingen/Forge.hpp" -#include "ingen/Log.hpp" -#include "ingen/URIMap.hpp" -#include "ingen/URIs.hpp" -#include "ingen/World.hpp" -#include "lv2/atom/atom.h" -#include "lv2/atom/forge.h" -#include "lv2/atom/util.h" -#include "lv2/midi/midi.h" -#include "lv2/urid/urid.h" -#include "raul/Path.hpp" +#include <ingen/Atom.hpp> +#include <ingen/Forge.hpp> +#include <ingen/Log.hpp> +#include <ingen/URIMap.hpp> +#include <ingen/URIs.hpp> +#include <ingen/World.hpp> +#include <lv2/atom/atom.h> +#include <lv2/atom/forge.h> +#include <lv2/atom/util.h> +#include <lv2/midi/midi.h> +#include <lv2/urid/urid.h> +#include <raul/Path.hpp> #include <boost/intrusive/bstree.hpp> @@ -43,8 +43,7 @@ #include <cstring> #include <string> -namespace ingen { -namespace server { +namespace ingen::server { ControlBindings::ControlBindings(Engine& engine) : _engine(engine) @@ -74,6 +73,12 @@ ControlBindings::port_binding(PortImpl* port) const return binding_key(binding); } +static int16_t +get_atom_num(const LV2_Atom* const atom) +{ + return static_cast<int16_t>(reinterpret_cast<const LV2_Atom_Int*>(atom)->body); +} + ControlBindings::Key ControlBindings::binding_key(const Atom& binding) const { @@ -83,9 +88,31 @@ ControlBindings::binding_key(const Atom& binding) const if (binding.type() == uris.atom_Object) { const auto* obj = static_cast<const LV2_Atom_Object_Body*>(binding.get_body()); if (obj->otype == uris.midi_Bender) { - key = Key(Type::MIDI_BENDER); + lv2_atom_object_body_get(binding.size(), + obj, + uris.midi_channel.urid(), + &num, + nullptr); + if (!num) { + _engine.log().rt_error("Bender binding missing channel\n"); + } else if (num->type != uris.atom_Int) { + _engine.log().rt_error("Bender channel not an integer\n"); + } else { + key = Key(Type::MIDI_BENDER, get_atom_num(num)); + } } else if (obj->otype == uris.midi_ChannelPressure) { - key = Key(Type::MIDI_CHANNEL_PRESSURE); + lv2_atom_object_body_get(binding.size(), + obj, + uris.midi_channel.urid(), + &num, + nullptr); + if (!num) { + _engine.log().rt_error("Pressure binding missing channel\n"); + } else if (num->type != uris.atom_Int) { + _engine.log().rt_error("Pressure channel not an integer\n"); + } else { + key = Key(Type::MIDI_CHANNEL_PRESSURE, get_atom_num(num)); + } } else if (obj->otype == uris.midi_Controller) { lv2_atom_object_body_get(binding.size(), obj, @@ -97,7 +124,7 @@ ControlBindings::binding_key(const Atom& binding) const } else if (num->type != uris.atom_Int) { _engine.log().rt_error("Controller number not an integer\n"); } else { - key = Key(Type::MIDI_CC, reinterpret_cast<LV2_Atom_Int*>(num)->body); + key = Key(Type::MIDI_CC, get_atom_num(num)); } } else if (obj->otype == uris.midi_NoteOn) { lv2_atom_object_body_get(binding.size(), @@ -110,7 +137,7 @@ ControlBindings::binding_key(const Atom& binding) const } else if (num->type != uris.atom_Int) { _engine.log().rt_error("Note number not an integer\n"); } else { - key = Key(Type::MIDI_NOTE, reinterpret_cast<LV2_Atom_Int*>(num)->body); + key = Key(Type::MIDI_NOTE, get_atom_num(num)); } } } else if (binding.type()) { @@ -120,21 +147,28 @@ ControlBindings::binding_key(const Atom& binding) const } ControlBindings::Key -ControlBindings::midi_event_key(uint16_t, const uint8_t* buf, uint16_t& value) +ControlBindings::midi_event_key(const uint8_t* buf, uint16_t& value) { switch (lv2_midi_message_type(buf)) { case LV2_MIDI_MSG_CONTROLLER: - value = static_cast<int8_t>(buf[2]); - return {Type::MIDI_CC, static_cast<int8_t>(buf[1])}; + value = buf[2]; + return {Type::MIDI_CC, + static_cast<int16_t>(((buf[0] & 0x0FU) << 8U) | buf[1])}; case LV2_MIDI_MSG_BENDER: - value = (static_cast<int8_t>(buf[2]) << 7) + static_cast<int8_t>(buf[1]); - return {Type::MIDI_BENDER}; + value = static_cast<uint16_t>((buf[2] << 7U) + buf[1]); + return {Type::MIDI_BENDER, static_cast<int16_t>((buf[0] & 0x0FU))}; case LV2_MIDI_MSG_CHANNEL_PRESSURE: - value = static_cast<int8_t>(buf[1]); - return {Type::MIDI_CHANNEL_PRESSURE}; + value = buf[1]; + return {Type::MIDI_CHANNEL_PRESSURE, + static_cast<int16_t>((buf[0] & 0x0FU))}; case LV2_MIDI_MSG_NOTE_ON: - value = 1.0f; - return {Type::MIDI_NOTE, static_cast<int8_t>(buf[1])}; + value = 1; + return {Type::MIDI_NOTE, + static_cast<int16_t>(((buf[0] & 0x0FU) << 8U) | buf[1])}; + case LV2_MIDI_MSG_NOTE_OFF: + value = 0; + return {Type::MIDI_NOTE, + static_cast<int16_t>(((buf[0] & 0x0FU) << 8U) | buf[1])}; default: return {}; } @@ -152,9 +186,9 @@ ControlBindings::set_port_binding(RunContext&, binding->port = port; _bindings->insert(*binding); return true; - } else { - return false; } + + return false; } void @@ -165,15 +199,16 @@ ControlBindings::port_value_changed(RunContext& ctx, { const ingen::URIs& uris = ctx.engine().world().uris(); if (!!key) { - int16_t value = port_value_to_control( - ctx, port, key.type, value_atom); + const int16_t value = + port_value_to_control(ctx, port, key.type, value_atom); + uint16_t size = 0; uint8_t buf[4]; switch (key.type) { case Type::MIDI_CC: size = 3; buf[0] = LV2_MIDI_MSG_CONTROLLER; - buf[1] = key.num; + buf[1] = static_cast<uint8_t>(key.num); buf[2] = static_cast<int8_t>(value); break; case Type::MIDI_CHANNEL_PRESSURE: @@ -194,7 +229,7 @@ ControlBindings::port_value_changed(RunContext& ctx, } else if (value == 0) { buf[0] = LV2_MIDI_MSG_NOTE_OFF; } - buf[1] = key.num; + buf[1] = static_cast<uint8_t>(key.num); buf[2] = 0x64; // MIDI spec default break; default: @@ -215,7 +250,7 @@ ControlBindings::start_learn(PortImpl* port) ThreadManager::assert_thread(THREAD_PRE_PROCESS); Binding* b = _learn_binding.load(); if (!b) { - _learn_binding = new Binding(Type::NULL_CONTROL, port); + _learn_binding = new Binding(); } else { b->port = port; } @@ -262,7 +297,7 @@ ControlBindings::control_to_port_value(RunContext& ctx, float max = 1.0f; get_range(ctx, port, &min, &max); - return normal * (max - min) + min; + return (normal * (max - min)) + min; } int16_t @@ -282,24 +317,18 @@ ControlBindings::port_value_to_control(RunContext& ctx, const float value = value_atom.get<float>(); float normal = (value - min) / (max - min); - if (normal < 0.0f) { - normal = 0.0f; - } - - if (normal > 1.0f) { - normal = 1.0f; - } + normal = std::max(0.0f, std::min(1.0f, normal)); if (port->is_logarithmic()) { - normal = logf(normal * (static_cast<float>(M_E) - 1.0f) + 1.0f); + normal = logf((normal * (static_cast<float>(M_E) - 1.0f)) + 1.0f); } switch (type) { case Type::MIDI_CC: case Type::MIDI_CHANNEL_PRESSURE: - return lrintf(normal * 127.0f); + return static_cast<int16_t>(lrintf(normal * 127.0f)); case Type::MIDI_BENDER: - return lrintf(normal * 16383.0f); + return static_cast<int16_t>(lrintf(normal * 16383.0f)); case Type::MIDI_NOTE: return (value > 0.0f) ? 1 : 0; default: @@ -322,9 +351,13 @@ forge_binding(const URIs& uris, break; case ControlBindings::Type::MIDI_BENDER: lv2_atom_forge_object(forge, &frame, 0, uris.midi_Bender); + lv2_atom_forge_key(forge, uris.midi_channel); + lv2_atom_forge_int(forge, value); break; case ControlBindings::Type::MIDI_CHANNEL_PRESSURE: lv2_atom_forge_object(forge, &frame, 0, uris.midi_ChannelPressure); + lv2_atom_forge_key(forge, uris.midi_channel); + lv2_atom_forge_int(forge, value); break; case ControlBindings::Type::MIDI_NOTE: lv2_atom_forge_object(forge, &frame, 0, uris.midi_NoteOn); @@ -353,7 +386,7 @@ ControlBindings::set_port_value(RunContext& ctx, // TODO: Set port value property so it is saved port->set_control_value(ctx, ctx.start(), val); - URIs& uris = ctx.engine().world().uris(); + const URIs& uris = ctx.engine().world().uris(); ctx.notify(uris.ingen_value, ctx.start(), port, sizeof(float), _forge.Float, &val); } @@ -411,22 +444,22 @@ ControlBindings::pre_process(RunContext& ctx, Buffer* buffer) _feedback->clear(); if ((!_learn_binding && _bindings->empty()) || !buffer->get<LV2_Atom>()) { - return; // Don't bother reading input + return; // Don't bother reading input } auto* seq = buffer->get<LV2_Atom_Sequence>(); - LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { + LV2_ATOM_SEQUENCE_FOREACH (seq, ev) { if (ev->body.type == uris.midi_MidiEvent) { const auto* buf = static_cast<const uint8_t*>(LV2_ATOM_BODY(&ev->body)); - const Key key = midi_event_key(ev->body.size, buf, value); + const Key key = midi_event_key(buf, value); if (_learn_binding && !!key) { - finish_learn(ctx, key); // Learn new binding + finish_learn(ctx, key); // Learn new binding } // Set all controls bound to this key const Binding k = {key, nullptr}; - for (Bindings::const_iterator i = _bindings->lower_bound(k); + for (auto i = _bindings->lower_bound(k); i != _bindings->end() && i->key == key; ++i) { set_port_value(ctx, i->port, key.type, value); @@ -443,5 +476,4 @@ ControlBindings::post_process(RunContext&, Buffer* buffer) } } -} // namespace server -} // namespace ingen +} // namespace ingen::server |