summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-09-15 07:17:10 +0000
committerDavid Robillard <d@drobilla.net>2011-09-15 07:17:10 +0000
commitc7f671ff5bf9cf2559697bbc90cf3cee97cc7975 (patch)
treec9448a87cce9bfc957d32bc3b1b404cb7f0c6984 /src
parentba99f4ca92ea2e6cf8de51341489b0689223e1fc (diff)
downloadingen-c7f671ff5bf9cf2559697bbc90cf3cee97cc7975.tar.gz
ingen-c7f671ff5bf9cf2559697bbc90cf3cee97cc7975.tar.bz2
ingen-c7f671ff5bf9cf2559697bbc90cf3cee97cc7975.zip
Fix control bindings (MIDI learn).
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@3464 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/server/ControlBindings.cpp85
-rw-r--r--src/server/ControlBindings.hpp27
-rw-r--r--src/server/GraphObjectImpl.cpp2
-rw-r--r--src/server/LV2Node.cpp2
-rw-r--r--src/server/Notification.cpp33
-rw-r--r--src/server/Notification.hpp20
-rw-r--r--src/server/PortImpl.cpp10
-rw-r--r--src/server/PortImpl.hpp12
-rw-r--r--src/server/PostProcessor.cpp19
-rw-r--r--src/server/events/CreatePort.cpp1
-rw-r--r--src/server/events/SetMetadata.cpp12
-rw-r--r--src/server/events/SetMetadata.hpp7
-rw-r--r--src/server/events/SetPortValue.cpp4
-rw-r--r--src/server/events/SetPortValue.hpp11
-rw-r--r--src/shared/Configuration.cpp2
15 files changed, 154 insertions, 93 deletions
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<AudioBuffer*>(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), &note);
}
@@ -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), &note);
_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<Bindings> 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<BufferFactory::Ref>(static_cast<size_t>(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), &note);
}
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), &note);
}
}
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<PortType> _types;
Raul::Atom _value;
+ Raul::Atom _min;
+ Raul::Atom _max;
Raul::Atom _last_broadcasted_value;
Context::ID _context;
Raul::Array<BufferFactory::Ref>* _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), &note)) {
- 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), &note);
+ 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<SpecialType>::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 <vector>
+
#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<ControlBindings::Bindings> _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
diff --git a/src/shared/Configuration.cpp b/src/shared/Configuration.cpp
index 14ebbb04..fca13b05 100644
--- a/src/shared/Configuration.cpp
+++ b/src/shared/Configuration.cpp
@@ -51,7 +51,7 @@ Configuration::Configuration()
.add("packet-size", 'k', "Maximum UDP packet size", Atom::INT, 4096)
.add("parallelism", 'p', "Number of concurrent process threads", Atom::INT, 1)
.add("path", 'L', "Target path for loaded patch", Atom::STRING, Atom())
- .add("queue-size", 'q', "Event queue size", Atom::INT, 1024)
+ .add("queue-size", 'q', "Event queue size", Atom::INT, 4096)
.add("run", 'r', "Run script", Atom::STRING, Atom());
}