summaryrefslogtreecommitdiffstats
path: root/src/engine/ControlBindings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/ControlBindings.cpp')
-rw-r--r--src/engine/ControlBindings.cpp384
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