diff options
Diffstat (limited to 'src/engine/ControlBindings.cpp')
-rw-r--r-- | src/engine/ControlBindings.cpp | 384 |
1 files changed, 0 insertions, 384 deletions
diff --git a/src/engine/ControlBindings.cpp b/src/engine/ControlBindings.cpp deleted file mode 100644 index 6c5b2f95..00000000 --- a/src/engine/ControlBindings.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2009-2011 David 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 <math.h> -#include "raul/log.hpp" -#include "raul/midi_events.h" -#include "shared/LV2URIMap.hpp" -#include "shared/World.hpp" -#include "events/SendPortValue.hpp" -#include "events/SendBinding.hpp" -#include "AudioBuffer.hpp" -#include "ControlBindings.hpp" -#include "Engine.hpp" -#include "EventBuffer.hpp" -#include "PortImpl.hpp" -#include "ProcessContext.hpp" -#include "ThreadManager.hpp" - -#define LOG(s) s << "[ControlBindings] " - -using namespace std; -using namespace Raul; - -namespace Ingen { -namespace Engine { - -ControlBindings::ControlBindings(Engine& engine) - : _engine(engine) - , _learn_port(NULL) - , _bindings(new Bindings()) - , _feedback(new EventBuffer(*_engine.buffer_factory(), 1024)) // FIXME: size -{ -} - -ControlBindings::~ControlBindings() -{ - delete _feedback; -} - -ControlBindings::Key -ControlBindings::port_binding(PortImpl* port) -{ - const Ingen::Shared::LV2URIMap& uris = *_engine.world()->uris().get(); - const Raul::Atom& binding = port->get_property(uris.ingen_controlBinding); - Key key; - if (binding.type() == Atom::DICT) { - const Atom::DictValue& dict = binding.get_dict(); - Atom::DictValue::const_iterator t = dict.find(uris.rdf_type); - Atom::DictValue::const_iterator n; - if (t == dict.end()) { - return key; - } else if (t->second == uris.midi_Bender) { - key = Key(MIDI_BENDER); - } else if (t->second == uris.midi_ChannelPressure) { - key = Key(MIDI_CHANNEL_PRESSURE); - } else if (t->second == uris.midi_Controller) { - if ((n = dict.find(uris.midi_controllerNumber)) != dict.end()) - key = Key(MIDI_CC, n->second.get_int32()); - } else if (t->second == uris.midi_Note) { - if ((n = dict.find(uris.midi_noteNumber)) != dict.end()) - key = Key(MIDI_NOTE, n->second.get_int32()); - } - } - return key; -} - -ControlBindings::Key -ControlBindings::midi_event_key(uint16_t size, uint8_t* buf, uint16_t& value) -{ - switch (buf[0] & 0xF0) { - case MIDI_CMD_CONTROL: - value = static_cast<const int8_t>(buf[2]); - return Key(MIDI_CC, static_cast<const int8_t>(buf[1])); - case MIDI_CMD_BENDER: - value = (static_cast<int8_t>(buf[2]) << 7) + static_cast<int8_t>(buf[1]); - return Key(MIDI_BENDER); - case MIDI_CMD_CHANNEL_PRESSURE: - value = static_cast<const int8_t>(buf[1]); - return Key(MIDI_CHANNEL_PRESSURE); - case MIDI_CMD_NOTE_ON: - value = 1.0f; - return Key(MIDI_NOTE, static_cast<const int8_t>(buf[1])); - default: - return Key(); - } -} - -void -ControlBindings::port_binding_changed(ProcessContext& context, PortImpl* port) -{ - Key key = port_binding(port); - if (key) - _bindings->insert(make_pair(key, port)); -} - -void -ControlBindings::port_value_changed(ProcessContext& context, PortImpl* port) -{ - 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); - uint16_t size = 0; - uint8_t buf[4]; - switch (key.type) { - case MIDI_CC: - size = 3; - buf[0] = MIDI_CMD_CONTROL; - buf[1] = key.num; - buf[2] = static_cast<int8_t>(value); - break; - case MIDI_CHANNEL_PRESSURE: - size = 2; - buf[0] = MIDI_CMD_CHANNEL_PRESSURE; - buf[1] = static_cast<int8_t>(value); - break; - case MIDI_BENDER: - size = 3; - buf[0] = MIDI_CMD_BENDER; - buf[1] = (value & 0x007F); - buf[2] = (value & 0x7F00) >> 7; - break; - case MIDI_NOTE: - size = 3; - if (value == 1) - buf[0] = MIDI_CMD_NOTE_ON; - else if (value == 0) - buf[0] = MIDI_CMD_NOTE_OFF; - buf[1] = key.num; - buf[2] = 0x64; // MIDI spec default - break; - default: - break; - } - if (size > 0) { - _feedback->append(0, 0, - uris.global_to_event(uris.midi_MidiEvent.id).second, - size, buf); - } - } -} - -void -ControlBindings::learn(PortImpl* port) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - _learn_port = port; -} - -Raul::Atom -ControlBindings::control_to_port_value(PortImpl* port, Type type, int16_t value) -{ - 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 normal = 0.0f; - switch (type) { - case MIDI_CC: - case MIDI_CHANNEL_PRESSURE: - normal = (float)value / 127.0f; - break; - case MIDI_BENDER: - normal = (float)value / 16383.0f; - break; - case MIDI_NOTE: - normal = (value == 0.0f) ? 0.0f : 1.0f; - break; - default: - break; - } - - float scaled_value = normal * (max - min) + min; - 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) -{ - if (port->value().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); - - if (normal < 0.0f) { - warn << "Value " << value << " (normal " << normal << ") for " - << port->path() << " out of range" << endl; - normal = 0.0f; - } - - if (normal > 1.0f) { - warn << "Value " << value << " (normal " << normal << ") for " - << port->path() << " out of range" << endl; - normal = 1.0f; - } - - switch (type) { - case MIDI_CC: - case MIDI_CHANNEL_PRESSURE: - return lrintf(normal * 127.0f); - case MIDI_BENDER: - return lrintf(normal * 16383.0f); - case MIDI_NOTE: - return (value > 0.0f) ? 1 : 0; - default: - return 0; - } -} - -void -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)); - port->set_value(port_value); - - assert(port_value.type() == Atom::FLOAT); - assert(dynamic_cast<AudioBuffer*>(port->buffer(0).get())); - - for (uint32_t v = 0; v < port->poly(); ++v) - reinterpret_cast<AudioBuffer*>(port->buffer(v).get())->set_value( - port_value.get_float(), context.start(), context.start()); - - const Events::SendPortValue ev(context.engine(), context.start(), port, true, 0, port_value); - context.event_sink().write(sizeof(ev), &ev); -} - -bool -ControlBindings::bind(ProcessContext& context, Key key) -{ - const Ingen::Shared::LV2URIMap& uris = *context.engine().world()->uris().get(); - assert(_learn_port); - if (key.type == MIDI_NOTE) { - bool toggled = _learn_port->has_property(uris.lv2_portProperty, uris.lv2_toggled); - if (!toggled) - return false; - } - - _bindings->insert(make_pair(key, _learn_port)); - - const Events::SendBinding ev(context.engine(), context.start(), _learn_port, key.type, key.num); - context.event_sink().write(sizeof(ev), &ev); - - _learn_port = NULL; - return true; -} - -SharedPtr<ControlBindings::Bindings> -ControlBindings::remove(const Raul::Path& path) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - SharedPtr<Bindings> old_bindings(_bindings); - SharedPtr<Bindings> copy(new Bindings(*_bindings.get())); - - for (Bindings::iterator i = copy->begin(); i != copy->end();) { - Bindings::iterator next = i; - ++next; - - if (i->second->path() == path || i->second->path().is_child_of(path)) - copy->erase(i); - - i = next; - } - - _bindings = copy; - return old_bindings; -} - -SharedPtr<ControlBindings::Bindings> -ControlBindings::remove(PortImpl* port) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - SharedPtr<Bindings> old_bindings(_bindings); - SharedPtr<Bindings> copy(new Bindings(*_bindings.get())); - - for (Bindings::iterator i = copy->begin(); i != copy->end();) { - Bindings::iterator next = i; - ++next; - - if (i->second == port) - copy->erase(i); - - i = next; - } - - _bindings = copy; - return old_bindings; -} - -void -ControlBindings::pre_process(ProcessContext& context, EventBuffer* buffer) -{ - uint32_t frames = 0; - uint32_t subframes = 0; - uint16_t type = 0; - uint16_t size = 0; - uint8_t* buf = NULL; - uint16_t value = 0; - - SharedPtr<Bindings> bindings = _bindings; - _feedback->clear(); - - const Ingen::Shared::LV2URIMap& uris = *context.engine().world()->uris().get(); - - // TODO: cache - const uint32_t midi_event_type = uris.global_to_event(uris.midi_MidiEvent.id).second; - - // Learn from input if necessary - if (_learn_port) { - for (buffer->rewind(); - buffer->get_event(&frames, &subframes, &type, &size, &buf); - buffer->increment()) { - if (type != midi_event_type) - continue; - - const Key key = midi_event_key(size, buf, value); - if (key && bind(context, key)) - break; - } - } - - // If bindings are empty, no sense reading input - if (bindings->empty()) - return; - - // Read input and apply control values - for (buffer->rewind(); - buffer->get_event(&frames, &subframes, &type, &size, &buf); - buffer->increment()) { - if (type != midi_event_type) - continue; - - const Key key = midi_event_key(size, buf, value); - if (!key) - continue; - - Bindings::const_iterator i = bindings->find(key); - if (i == bindings->end()) - continue; - - set_port_value(context, i->second, key.type, value); - } -} - -void -ControlBindings::post_process(ProcessContext& context, EventBuffer* buffer) -{ - if (_feedback->event_count() > 0) { - // TODO: merge buffer's existing contents (anything send to it in the patch) - _feedback->rewind(); - buffer->copy(context, _feedback); - } -} - -} // namespace Engine -} // namespace Ingen |