diff options
Diffstat (limited to 'src/server/ControlBindings.cpp')
-rw-r--r-- | src/server/ControlBindings.cpp | 425 |
1 files changed, 0 insertions, 425 deletions
diff --git a/src/server/ControlBindings.cpp b/src/server/ControlBindings.cpp deleted file mode 100644 index 3901d1c2..00000000 --- a/src/server/ControlBindings.cpp +++ /dev/null @@ -1,425 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2017 David Robillard <http://drobilla.net/> - - 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 <http://www.gnu.org/licenses/>. -*/ - -#include <cmath> - -#include "ingen/Log.hpp" -#include "ingen/URIMap.hpp" -#include "ingen/URIs.hpp" -#include "ingen/World.hpp" -#include "lv2/lv2plug.in/ns/ext/atom/util.h" -#include "lv2/lv2plug.in/ns/ext/midi/midi.h" - -#include "Buffer.hpp" -#include "ControlBindings.hpp" -#include "Engine.hpp" -#include "PortImpl.hpp" -#include "RunContext.hpp" -#include "ThreadManager.hpp" - -namespace Ingen { -namespace Server { - -ControlBindings::ControlBindings(Engine& engine) - : _engine(engine) - , _learn_binding(nullptr) - , _bindings(new Bindings()) - , _feedback(new Buffer(*_engine.buffer_factory(), - engine.world()->uris().atom_Sequence, - 0, - 4096)) // FIXME: capacity? -{ - lv2_atom_forge_init( - &_forge, &engine.world()->uri_map().urid_map_feature()->urid_map); -} - -ControlBindings::~ControlBindings() -{ - _feedback.reset(); - delete _learn_binding.load(); -} - -ControlBindings::Key -ControlBindings::port_binding(PortImpl* port) const -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - const Ingen::URIs& uris = _engine.world()->uris(); - const Atom& binding = port->get_property(uris.midi_binding); - return binding_key(binding); -} - -ControlBindings::Key -ControlBindings::binding_key(const Atom& binding) const -{ - const Ingen::URIs& uris = _engine.world()->uris(); - Key key; - LV2_Atom* num = nullptr; - if (binding.type() == uris.atom_Object) { - const LV2_Atom_Object_Body* obj = (const LV2_Atom_Object_Body*) - binding.get_body(); - if (obj->otype == uris.midi_Bender) { - key = Key(Type::MIDI_BENDER); - } else if (obj->otype == uris.midi_ChannelPressure) { - key = Key(Type::MIDI_CHANNEL_PRESSURE); - } else if (obj->otype == uris.midi_Controller) { - lv2_atom_object_body_get( - binding.size(), obj, (LV2_URID)uris.midi_controllerNumber, &num, NULL); - if (!num) { - _engine.log().rt_error("Controller binding missing number\n"); - } else if (num->type != uris.atom_Int) { - _engine.log().rt_error("Controller number not an integer\n"); - } else { - key = Key(Type::MIDI_CC, ((LV2_Atom_Int*)num)->body); - } - } else if (obj->otype == uris.midi_NoteOn) { - lv2_atom_object_body_get( - binding.size(), obj, (LV2_URID)uris.midi_noteNumber, &num, NULL); - if (!num) { - _engine.log().rt_error("Note binding missing number\n"); - } else if (num->type != uris.atom_Int) { - _engine.log().rt_error("Note number not an integer\n"); - } else { - key = Key(Type::MIDI_NOTE, ((LV2_Atom_Int*)num)->body); - } - } - } else if (binding.type()) { - _engine.log().rt_error("Unknown binding type\n"); - } - return key; -} - -ControlBindings::Key -ControlBindings::midi_event_key(uint16_t size, 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 Key(Type::MIDI_CC, static_cast<int8_t>(buf[1])); - case LV2_MIDI_MSG_BENDER: - value = (static_cast<int8_t>(buf[2]) << 7) + static_cast<int8_t>(buf[1]); - return Key(Type::MIDI_BENDER); - case LV2_MIDI_MSG_CHANNEL_PRESSURE: - value = static_cast<int8_t>(buf[1]); - return Key(Type::MIDI_CHANNEL_PRESSURE); - case LV2_MIDI_MSG_NOTE_ON: - value = 1.0f; - return Key(Type::MIDI_NOTE, static_cast<int8_t>(buf[1])); - default: - return Key(); - } -} - -bool -ControlBindings::set_port_binding(RunContext& context, - PortImpl* port, - Binding* binding, - const Atom& value) -{ - const Key key = binding_key(value); - if (!!key) { - binding->key = key; - binding->port = port; - _bindings->insert(*binding); - return true; - } else { - return false; - } -} - -void -ControlBindings::port_value_changed(RunContext& ctx, - PortImpl* port, - Key key, - const Atom& value_atom) -{ - Ingen::World* world = ctx.engine().world(); - const Ingen::URIs& uris = world->uris(); - if (!!key) { - 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[2] = static_cast<int8_t>(value); - break; - case Type::MIDI_CHANNEL_PRESSURE: - size = 2; - buf[0] = LV2_MIDI_MSG_CHANNEL_PRESSURE; - buf[1] = static_cast<int8_t>(value); - break; - case Type::MIDI_BENDER: - size = 3; - buf[0] = LV2_MIDI_MSG_BENDER; - buf[1] = (value & 0x007F); - buf[2] = (value & 0x7F00) >> 7; - break; - case Type::MIDI_NOTE: - size = 3; - if (value == 1) { - buf[0] = LV2_MIDI_MSG_NOTE_ON; - } else if (value == 0) { - buf[0] = LV2_MIDI_MSG_NOTE_OFF; - } - buf[1] = key.num; - buf[2] = 0x64; // MIDI spec default - break; - default: - break; - } - if (size > 0) { - _feedback->append_event(ctx.nframes() - 1, size, (LV2_URID)uris.midi_MidiEvent, buf); - } - } -} - -void -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); - } else { - b->port = port; - } -} - -static void -get_range(RunContext& context, const PortImpl* port, float* min, float* max) -{ - *min = port->minimum().get<float>(); - *max = port->maximum().get<float>(); - if (port->is_sample_rate()) { - *min *= context.engine().sample_rate(); - *max *= context.engine().sample_rate(); - } -} - -float -ControlBindings::control_to_port_value(RunContext& context, - const PortImpl* port, - Type type, - int16_t value) const -{ - float normal = 0.0f; - switch (type) { - case Type::MIDI_CC: - case Type::MIDI_CHANNEL_PRESSURE: - normal = (float)value / 127.0f; - break; - case Type::MIDI_BENDER: - normal = (float)value / 16383.0f; - break; - case Type::MIDI_NOTE: - normal = (value == 0.0f) ? 0.0f : 1.0f; - break; - default: - break; - } - - if (port->is_logarithmic()) { - normal = (expf(normal) - 1.0f) / ((float)M_E - 1.0f); - } - - float min, max; - get_range(context, port, &min, &max); - - return normal * (max - min) + min; -} - -int16_t -ControlBindings::port_value_to_control(RunContext& context, - PortImpl* port, - Type type, - const Atom& value_atom) const -{ - if (value_atom.type() != port->bufs().forge().Float) { - return 0; - } - - float min, max; - get_range(context, port, &min, &max); - - 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; - } - - if (port->is_logarithmic()) { - normal = logf(normal * ((float)M_E - 1.0f) + 1.0); - } - - switch (type) { - case Type::MIDI_CC: - case Type::MIDI_CHANNEL_PRESSURE: - return lrintf(normal * 127.0f); - case Type::MIDI_BENDER: - return lrintf(normal * 16383.0f); - case Type::MIDI_NOTE: - return (value > 0.0f) ? 1 : 0; - default: - return 0; - } -} - -static void -forge_binding(const URIs& uris, - LV2_Atom_Forge* forge, - ControlBindings::Type binding_type, - int32_t value) -{ - LV2_Atom_Forge_Frame frame; - switch (binding_type) { - case ControlBindings::Type::MIDI_CC: - lv2_atom_forge_object(forge, &frame, 0, uris.midi_Controller); - lv2_atom_forge_key(forge, uris.midi_controllerNumber); - lv2_atom_forge_int(forge, value); - break; - case ControlBindings::Type::MIDI_BENDER: - lv2_atom_forge_object(forge, &frame, 0, uris.midi_Bender); - break; - case ControlBindings::Type::MIDI_CHANNEL_PRESSURE: - lv2_atom_forge_object(forge, &frame, 0, uris.midi_ChannelPressure); - break; - case ControlBindings::Type::MIDI_NOTE: - lv2_atom_forge_object(forge, &frame, 0, uris.midi_NoteOn); - lv2_atom_forge_key(forge, uris.midi_noteNumber); - lv2_atom_forge_int(forge, value); - break; - case ControlBindings::Type::MIDI_RPN: // TODO - case ControlBindings::Type::MIDI_NRPN: // TODO - case ControlBindings::Type::NULL_CONTROL: - break; - } -} - -void -ControlBindings::set_port_value(RunContext& context, - PortImpl* port, - Type type, - int16_t value) -{ - float min, max; - get_range(context, port, &min, &max); - - const float val = control_to_port_value(context, port, type, value); - - // TODO: Set port value property so it is saved - port->set_control_value(context, context.start(), val); - - URIs& uris = context.engine().world()->uris(); - context.notify(uris.ingen_value, context.start(), port, - sizeof(float), _forge.Float, &val); -} - -bool -ControlBindings::finish_learn(RunContext& context, Key key) -{ - const Ingen::URIs& uris = context.engine().world()->uris(); - Binding* binding = _learn_binding.exchange(nullptr); - if (!binding || (key.type == Type::MIDI_NOTE && !binding->port->is_toggled())) { - return false; - } - - binding->key = key; - _bindings->insert(*binding); - - LV2_Atom buf[16]; - memset(buf, 0, sizeof(buf)); - lv2_atom_forge_set_buffer(&_forge, (uint8_t*)buf, sizeof(buf)); - forge_binding(uris, &_forge, key.type, key.num); - const LV2_Atom* atom = buf; - context.notify(uris.midi_binding, - context.start(), - binding->port, - atom->size, atom->type, LV2_ATOM_BODY_CONST(atom)); - - return true; -} - -void -ControlBindings::get_all(const Raul::Path& path, std::vector<Binding*>& bindings) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - for (Binding& b : *_bindings) { - if (b.port->path() == path || b.port->path().is_child_of(path)) { - bindings.push_back(&b); - } - } -} - -void -ControlBindings::remove(RunContext& ctx, const std::vector<Binding*>& bindings) -{ - for (Binding* b : bindings) { - _bindings->erase(*b); - } -} - -void -ControlBindings::pre_process(RunContext& ctx, Buffer* buffer) -{ - uint16_t value = 0; - Ingen::World* world = ctx.engine().world(); - const Ingen::URIs& uris = world->uris(); - - _feedback->clear(); - if ((!_learn_binding && _bindings->empty()) || !buffer->get<LV2_Atom>()) { - return; // Don't bother reading input - } - - LV2_Atom_Sequence* seq = buffer->get<LV2_Atom_Sequence>(); - LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { - if (ev->body.type == uris.midi_MidiEvent) { - const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body); - const Key key = midi_event_key(ev->body.size, buf, value); - - if (_learn_binding && !!key) { - 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); - i != _bindings->end() && i->key == key; - ++i) { - set_port_value(ctx, i->port, key.type, value); - } - } - } -} - -void -ControlBindings::post_process(RunContext& context, Buffer* buffer) -{ - if (buffer->get<LV2_Atom>()) { - buffer->append_event_buffer(_feedback.get()); - } -} - -} // namespace Server -} // namespace Ingen |