summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2010-01-29 01:43:54 +0000
committerDavid Robillard <d@drobilla.net>2010-01-29 01:43:54 +0000
commitd5a514148bec58cd7e97d032259362b2e19c0e95 (patch)
tree64ea4dd182a8918b47a6d5f391e2cd097aebb526 /src
parent36039b294ee823ceb2c239129defc5eafa110247 (diff)
downloadingen-d5a514148bec58cd7e97d032259362b2e19c0e95.tar.gz
ingen-d5a514148bec58cd7e97d032259362b2e19c0e95.tar.bz2
ingen-d5a514148bec58cd7e97d032259362b2e19c0e95.zip
Magic MIDI binding via special ingen_control port.
Always set lv2:minimum and lv2:maximum properties for control ports so they show up in properties dialog (and can be used for MIDI binding). git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2391 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/client/HTTPEngineSender.cpp2
-rw-r--r--src/client/HTTPEngineSender.hpp2
-rw-r--r--src/client/OSCEngineSender.cpp6
-rw-r--r--src/client/OSCEngineSender.hpp2
-rw-r--r--src/client/PortModel.hpp3
-rw-r--r--src/common/interface/EngineInterface.hpp2
-rw-r--r--src/common/interface/PortType.hpp1
-rw-r--r--src/engine/AudioBuffer.cpp1
-rw-r--r--src/engine/BufferFactory.cpp2
-rw-r--r--src/engine/ClientBroadcaster.hpp3
-rw-r--r--src/engine/ControlBindings.cpp96
-rw-r--r--src/engine/ControlBindings.hpp57
-rw-r--r--src/engine/Engine.cpp24
-rw-r--r--src/engine/Engine.hpp37
-rw-r--r--src/engine/EngineStore.cpp6
-rw-r--r--src/engine/Event.cpp8
-rw-r--r--src/engine/EventSource.cpp2
-rw-r--r--src/engine/InputPort.cpp4
-rw-r--r--src/engine/JackDriver.cpp13
-rw-r--r--src/engine/LV2Node.cpp11
-rw-r--r--src/engine/MessageContext.hpp2
-rw-r--r--src/engine/NodeBase.cpp18
-rw-r--r--src/engine/NodeFactory.cpp2
-rw-r--r--src/engine/OSCEngineReceiver.cpp10
-rw-r--r--src/engine/OSCEngineReceiver.hpp2
-rw-r--r--src/engine/PatchImpl.cpp20
-rw-r--r--src/engine/QueuedEngineInterface.cpp4
-rw-r--r--src/engine/QueuedEngineInterface.hpp2
-rw-r--r--src/engine/QueuedEvent.cpp2
-rw-r--r--src/engine/QueuedEvent.hpp9
-rw-r--r--src/engine/ThreadManager.hpp14
-rw-r--r--src/engine/events.hpp2
-rw-r--r--src/engine/events/CreatePort.cpp3
-rw-r--r--src/engine/events/CreatePort.hpp1
-rw-r--r--src/engine/events/Learn.cpp (renamed from src/engine/events/MidiLearn.cpp)54
-rw-r--r--src/engine/events/Learn.hpp (renamed from src/engine/events/MidiLearn.hpp)9
-rw-r--r--src/engine/events/SendPortValue.cpp4
-rw-r--r--src/engine/events/SetMetadata.cpp2
-rw-r--r--src/engine/internals/Controller.cpp10
-rw-r--r--src/engine/wscript3
-rw-r--r--src/gui/NodeMenu.cpp10
-rw-r--r--src/gui/NodeMenu.hpp3
-rw-r--r--src/gui/ObjectMenu.cpp13
-rw-r--r--src/gui/ObjectMenu.hpp2
-rw-r--r--src/gui/Port.cpp6
-rw-r--r--src/gui/PortMenu.cpp3
-rw-r--r--src/gui/ingen_gui.glade18
47 files changed, 365 insertions, 145 deletions
diff --git a/src/client/HTTPEngineSender.cpp b/src/client/HTTPEngineSender.cpp
index abf5180e..ece89ca0 100644
--- a/src/client/HTTPEngineSender.cpp
+++ b/src/client/HTTPEngineSender.cpp
@@ -193,7 +193,7 @@ HTTPEngineSender::set_voice_value(const Path& port_path,
void
-HTTPEngineSender::midi_learn(const Path& node_path)
+HTTPEngineSender::learn(const Path& path)
{
}
diff --git a/src/client/HTTPEngineSender.hpp b/src/client/HTTPEngineSender.hpp
index b2df7821..971793d5 100644
--- a/src/client/HTTPEngineSender.hpp
+++ b/src/client/HTTPEngineSender.hpp
@@ -108,7 +108,7 @@ public:
uint32_t voice,
const Raul::Atom& value);
- virtual void midi_learn(const Raul::Path& node_path);
+ virtual void learn(const Raul::Path& path);
// Requests //
diff --git a/src/client/OSCEngineSender.cpp b/src/client/OSCEngineSender.cpp
index 0e2b11ab..e7fc4078 100644
--- a/src/client/OSCEngineSender.cpp
+++ b/src/client/OSCEngineSender.cpp
@@ -238,11 +238,11 @@ OSCEngineSender::set_voice_value(const Path& port_path,
void
-OSCEngineSender::midi_learn(const Path& node_path)
+OSCEngineSender::learn(const Path& path)
{
- send("/ingen/midi_learn", "is",
+ send("/ingen/learn", "is",
next_id(),
- node_path.c_str(),
+ path.c_str(),
LO_ARGS_END);
}
diff --git a/src/client/OSCEngineSender.hpp b/src/client/OSCEngineSender.hpp
index f43c3b18..8311cbb1 100644
--- a/src/client/OSCEngineSender.hpp
+++ b/src/client/OSCEngineSender.hpp
@@ -105,7 +105,7 @@ public:
uint32_t voice,
const Raul::Atom& value);
- virtual void midi_learn(const Raul::Path& node_path);
+ virtual void learn(const Raul::Path& path);
// Requests //
diff --git a/src/client/PortModel.hpp b/src/client/PortModel.hpp
index dbf82f1a..74b15283 100644
--- a/src/client/PortModel.hpp
+++ b/src/client/PortModel.hpp
@@ -26,6 +26,9 @@
#include "interface/Port.hpp"
#include "ObjectModel.hpp"
+#include <stdio.h>
+
+
namespace Raul { class Path; }
namespace Ingen {
diff --git a/src/common/interface/EngineInterface.hpp b/src/common/interface/EngineInterface.hpp
index 742e0ed5..6d99a14d 100644
--- a/src/common/interface/EngineInterface.hpp
+++ b/src/common/interface/EngineInterface.hpp
@@ -58,7 +58,7 @@ public:
virtual void disconnect_all(const Raul::Path& parent_patch_path,
const Raul::Path& path) = 0;
- virtual void midi_learn(const Raul::Path& node_path) = 0;
+ virtual void learn(const Raul::Path& path) = 0;
// Requests
diff --git a/src/common/interface/PortType.hpp b/src/common/interface/PortType.hpp
index f659cc81..557d7e75 100644
--- a/src/common/interface/PortType.hpp
+++ b/src/common/interface/PortType.hpp
@@ -32,7 +32,6 @@ namespace Shared {
*/
class PortType {
public:
-
enum Symbol {
UNKNOWN = 0,
AUDIO = 1,
diff --git a/src/engine/AudioBuffer.cpp b/src/engine/AudioBuffer.cpp
index a1e10b63..90534f90 100644
--- a/src/engine/AudioBuffer.cpp
+++ b/src/engine/AudioBuffer.cpp
@@ -24,7 +24,6 @@
#include "AudioBuffer.hpp"
#include "ProcessContext.hpp"
#include "LV2Features.hpp"
-#include "LV2URIMap.hpp"
using namespace std;
using namespace Raul;
diff --git a/src/engine/BufferFactory.cpp b/src/engine/BufferFactory.cpp
index 86862ef8..87caa2af 100644
--- a/src/engine/BufferFactory.cpp
+++ b/src/engine/BufferFactory.cpp
@@ -80,7 +80,7 @@ BufferFactory::get(Shared::PortType type, size_t size, bool force_create)
BufferFactory::Ref
BufferFactory::create(Shared::PortType type, size_t size)
{
- assert(ThreadManager::current_thread_id() != THREAD_PROCESS);
+ ThreadManager::assert_not_thread(THREAD_PROCESS);
Buffer* buffer = NULL;
diff --git a/src/engine/ClientBroadcaster.hpp b/src/engine/ClientBroadcaster.hpp
index cfe0a14f..9de7aeff 100644
--- a/src/engine/ClientBroadcaster.hpp
+++ b/src/engine/ClientBroadcaster.hpp
@@ -26,6 +26,9 @@
#include "interface/ClientInterface.hpp"
#include "NodeFactory.hpp"
+#include <iostream>
+using namespace std;
+
namespace Ingen {
class GraphObjectImpl;
diff --git a/src/engine/ControlBindings.cpp b/src/engine/ControlBindings.cpp
new file mode 100644
index 00000000..00241b54
--- /dev/null
+++ b/src/engine/ControlBindings.cpp
@@ -0,0 +1,96 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2009 Dave 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 "raul/log.hpp"
+#include "raul/midi_events.h"
+#include "events/SendPortValue.hpp"
+#include "ControlBindings.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 {
+
+
+void
+ControlBindings::learn(PortImpl* port)
+{
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
+ _learn_port = port;
+}
+
+
+void
+ControlBindings::set_port_value(ProcessContext& context, PortImpl* port, int8_t value)
+{
+ float min = port->get_property("lv2:minimum").get_float();
+ float max = port->get_property("lv2:maximum").get_float();
+
+ Raul::Atom scaled_value(static_cast<float>(((float)value / 127.0) * (max - min) + min));
+ port->set_value(scaled_value);
+
+ const Events::SendPortValue ev(context.engine(), context.start(), port, true, 0,
+ scaled_value.get_float());
+ context.event_sink().write(sizeof(ev), &ev);
+}
+
+
+void
+ControlBindings::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;
+
+ if (_learn_port) {
+ buffer->rewind();
+ while (buffer->get_event(&frames, &subframes, &type, &size, &buf)) {
+ if (type == _map->midi_event && (buf[0] & 0xF0) == MIDI_CMD_CONTROL) {
+ const int8_t controller = static_cast<const int8_t>(buf[1]);
+ _bindings.insert(make_pair(controller, _learn_port));
+ _learn_port = NULL;
+ break;
+ }
+ buffer->increment();
+ }
+ }
+
+ if (!_bindings.empty()) {
+ buffer->rewind();
+ while (buffer->get_event(&frames, &subframes, &type, &size, &buf)) {
+ if (type == _map->midi_event && (buf[0] & 0xF0) == MIDI_CMD_CONTROL) {
+ const int8_t controller = static_cast<const int8_t>(buf[1]);
+ const int8_t value = static_cast<const int8_t>(buf[2]);
+ Bindings::const_iterator i = _bindings.find(controller);
+ if (i != _bindings.end()) {
+ set_port_value(context, i->second, value);
+ }
+ }
+ buffer->increment();
+ }
+ }
+}
+
+}
diff --git a/src/engine/ControlBindings.hpp b/src/engine/ControlBindings.hpp
new file mode 100644
index 00000000..5e1e123d
--- /dev/null
+++ b/src/engine/ControlBindings.hpp
@@ -0,0 +1,57 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2009 Dave 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
+ */
+
+#ifndef CONTROL_BINDIGNS_HPP
+#define CONTROL_BINDINGS_HPP
+
+#include <stdint.h>
+#include <map>
+#include "raul/SharedPtr.hpp"
+#include "shared/LV2URIMap.hpp"
+
+namespace Ingen {
+
+class Engine;
+class ProcessContext;
+class EventBuffer;
+class PortImpl;
+
+class ControlBindings {
+public:
+ ControlBindings(Engine& engine, SharedPtr<Shared::LV2URIMap> map)
+ : _engine(engine)
+ , _map(map)
+ , _learn_port(NULL)
+ {}
+
+ void learn(PortImpl* port);
+ void process(ProcessContext& context, EventBuffer* buffer);
+
+private:
+ Engine& _engine;
+ SharedPtr<Shared::LV2URIMap> _map;
+ PortImpl* _learn_port;
+
+ void set_port_value(ProcessContext& context, PortImpl* port, int8_t value);
+
+ typedef std::map<int8_t, PortImpl*> Bindings;
+ Bindings _bindings;
+};
+
+} // namespace Ingen
+
+#endif // CONTROL_BINDINGS_HPP
diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp
index 2ca2b03d..437389d3 100644
--- a/src/engine/Engine.cpp
+++ b/src/engine/Engine.cpp
@@ -25,16 +25,19 @@
#include "uri-map.lv2/uri-map.h"
#include "common/interface/EventType.hpp"
#include "events/CreatePatch.hpp"
+#include "events/CreatePort.hpp"
#include "module/World.hpp"
#include "shared/LV2Features.hpp"
#include "shared/LV2URIMap.hpp"
#include "shared/Store.hpp"
-#include "Driver.hpp"
#include "BufferFactory.hpp"
#include "ClientBroadcaster.hpp"
+#include "ControlBindings.hpp"
+#include "Driver.hpp"
#include "Engine.hpp"
#include "EngineStore.hpp"
#include "Event.hpp"
+#include "EventSource.hpp"
#include "MessageContext.hpp"
#include "NodeFactory.hpp"
#include "PatchImpl.hpp"
@@ -43,7 +46,6 @@
#include "ProcessContext.hpp"
#include "ProcessSlave.hpp"
#include "QueuedEngineInterface.hpp"
-#include "EventSource.hpp"
#include "ThreadManager.hpp"
#include "tuning.hpp"
@@ -54,6 +56,7 @@ namespace Ingen {
using namespace Shared;
+bool ThreadManager::single_threaded = true;
Engine::Engine(Ingen::Shared::World* world)
: _world(world)
@@ -64,6 +67,8 @@ Engine::Engine(Ingen::Shared::World* world)
, _message_context(new MessageContext(*this))
, _buffer_factory(new BufferFactory(*this, PtrCast<LV2URIMap>(
world->lv2_features->feature(LV2_URI_MAP_URI))))
+ , _control_bindings(new ControlBindings(*this, PtrCast<LV2URIMap>(
+ world->lv2_features->feature(LV2_URI_MAP_URI))))
, _quit_flag(false)
, _activated(false)
{
@@ -172,6 +177,17 @@ Engine::activate()
_world->store->add(root_patch);
root_patch->compiled_patch(root_patch->compile());
_driver->set_root_patch(root_patch);
+
+ // Add control port
+ Shared::Resource::Properties properties;
+ properties.insert(make_pair("lv2:name", "Control"));
+ Events::CreatePort* ev = new Events::CreatePort(*this, SharedPtr<Responder>(), 0,
+ "/ingen_control", "lv2ev:EventPort", false, NULL, properties);
+ ev->pre_process();
+ ProcessContext context(*this);
+ ev->execute(context);
+ ev->post_process();
+ delete ev;
}
_driver->activate();
@@ -183,9 +199,8 @@ Engine::activate()
root_patch->enable();
- //_post_processor->start();
-
_activated = true;
+ ThreadManager::single_threaded = false;
return true;
}
@@ -204,6 +219,7 @@ Engine::deactivate()
_driver->root_patch()->deactivate();
_activated = false;
+ ThreadManager::single_threaded = true;
}
diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp
index 1b2a1276..9a665077 100644
--- a/src/engine/Engine.hpp
+++ b/src/engine/Engine.hpp
@@ -33,9 +33,10 @@ namespace Raul { class Maid; }
namespace Ingen {
-class Driver;
class BufferFactory;
class ClientBroadcaster;
+class ControlBindings;
+class Driver;
class Driver;
class EngineStore;
class Event;
@@ -80,13 +81,14 @@ public:
virtual bool activated() { return _activated; }
- Raul::Maid* maid() const { return _maid; }
- Driver* driver() const { return _driver.get(); }
- PostProcessor* post_processor() const { return _post_processor; }
- ClientBroadcaster* broadcaster() const { return _broadcaster; }
- NodeFactory* node_factory() const { return _node_factory; }
- MessageContext* message_context() const { return _message_context; }
- BufferFactory* buffer_factory() const { return _buffer_factory; }
+ BufferFactory* buffer_factory() const { return _buffer_factory; }
+ ClientBroadcaster* broadcaster() const { return _broadcaster; }
+ ControlBindings* control_bindings() const { return _control_bindings; }
+ Driver* driver() const { return _driver.get(); }
+ MessageContext* message_context() const { return _message_context; }
+ NodeFactory* node_factory() const { return _node_factory; }
+ PostProcessor* post_processor() const { return _post_processor; }
+ Raul::Maid* maid() const { return _maid; }
SharedPtr<EngineStore> engine_store() const;
@@ -106,15 +108,16 @@ private:
typedef std::set< SharedPtr<EventSource> > EventSources;
EventSources _event_sources;
- ProcessSlaves _process_slaves;
- Ingen::Shared::World* _world;
- SharedPtr<Driver> _driver;
- Raul::Maid* _maid;
- PostProcessor* _post_processor;
- ClientBroadcaster* _broadcaster;
- NodeFactory* _node_factory;
- MessageContext* _message_context;
- BufferFactory* _buffer_factory;
+ ProcessSlaves _process_slaves;
+ Ingen::Shared::World* _world;
+ SharedPtr<Driver> _driver;
+ Raul::Maid* _maid;
+ PostProcessor* _post_processor;
+ ClientBroadcaster* _broadcaster;
+ NodeFactory* _node_factory;
+ MessageContext* _message_context;
+ BufferFactory* _buffer_factory;
+ ControlBindings* _control_bindings;
bool _quit_flag;
bool _activated;
diff --git a/src/engine/EngineStore.cpp b/src/engine/EngineStore.cpp
index 1d17bb48..4ac40ec0 100644
--- a/src/engine/EngineStore.cpp
+++ b/src/engine/EngineStore.cpp
@@ -80,7 +80,7 @@ EngineStore::find_object(const Path& path)
void
EngineStore::add(Shared::GraphObject* obj)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
Store::add(obj);
}
@@ -90,7 +90,7 @@ EngineStore::add(Shared::GraphObject* obj)
void
EngineStore::add(const Objects& table)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
cram(table);
}
@@ -115,7 +115,7 @@ EngineStore::remove(const Path& path)
SharedPtr<EngineStore::Objects>
EngineStore::remove(iterator object)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
if (object != end()) {
iterator descendants_end = find_descendants_end(object);
diff --git a/src/engine/Event.cpp b/src/engine/Event.cpp
index e48d32a2..889dd74e 100644
--- a/src/engine/Event.cpp
+++ b/src/engine/Event.cpp
@@ -15,9 +15,11 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "Driver.hpp"
+#include "Engine.hpp"
#include "Event.hpp"
-#include "ThreadManager.hpp"
#include "ProcessContext.hpp"
+#include "ThreadManager.hpp"
/*! \page methods Method Documentation
*
@@ -32,7 +34,7 @@ namespace Ingen {
void
Event::execute(ProcessContext& context)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
assert(!_executed);
assert(_time <= context.end());
@@ -47,7 +49,7 @@ Event::execute(ProcessContext& context)
void
Event::post_process()
{
- assert(ThreadManager::current_thread_id() != THREAD_PROCESS);
+ ThreadManager::assert_not_thread(THREAD_PROCESS);
}
diff --git a/src/engine/EventSource.cpp b/src/engine/EventSource.cpp
index 0b8cb9dd..c51b580a 100644
--- a/src/engine/EventSource.cpp
+++ b/src/engine/EventSource.cpp
@@ -64,7 +64,7 @@ EventSource::push_queued(QueuedEvent* const ev)
void
EventSource::process(PostProcessor& dest, ProcessContext& context)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
if (_events.empty())
return;
diff --git a/src/engine/InputPort.cpp b/src/engine/InputPort.cpp
index 6566ab2f..010fdd93 100644
--- a/src/engine/InputPort.cpp
+++ b/src/engine/InputPort.cpp
@@ -139,7 +139,7 @@ InputPort::connect_buffers()
void
InputPort::add_connection(Connections::Node* const c)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
_connections.push_back(c);
connect_buffers();
@@ -154,7 +154,7 @@ InputPort::add_connection(Connections::Node* const c)
InputPort::Connections::Node*
InputPort::remove_connection(const OutputPort* src_port)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
Connections::Node* connection = NULL;
for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i)
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp
index 0a747397..1cd7d3ee 100644
--- a/src/engine/JackDriver.cpp
+++ b/src/engine/JackDriver.cpp
@@ -22,6 +22,7 @@
#include "shared/LV2Features.hpp"
#include "shared/LV2URIMap.hpp"
#include "AudioBuffer.hpp"
+#include "ControlBindings.hpp"
#include "DuplexPort.hpp"
#include "Engine.hpp"
#include "Event.hpp"
@@ -326,7 +327,7 @@ JackDriver::deactivate()
void
JackDriver::add_port(DriverPort* port)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
assert(dynamic_cast<JackPort*>(port));
_ports.push_back((JackPort*)port);
}
@@ -343,7 +344,7 @@ JackDriver::add_port(DriverPort* port)
Raul::List<DriverPort*>::Node*
JackDriver::remove_port(const Path& path)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
for (Raul::List<JackPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i)
if ((*i)->patch_port()->path() == path)
@@ -382,7 +383,7 @@ JackDriver::create_port(DuplexPort* patch_port)
DriverPort*
JackDriver::driver_port(const Path& path)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
for (Raul::List<JackPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i)
if ((*i)->patch_port()->path() == path)
@@ -434,6 +435,10 @@ JackDriver::_process_cb(jack_nframes_t nframes)
for (Raul::List<JackPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i)
(*i)->pre_process(_process_context);
+ // Process control bindings
+ _engine.control_bindings()->process(_process_context,
+ PtrCast<EventBuffer>(_root_patch->port_impl(0)->buffer(0)).get());
+
// Run root patch
if (_root_patch)
_root_patch->process(_process_context);
@@ -459,7 +464,7 @@ JackDriver::_thread_init_cb()
_jack_thread = Thread::create_for_this_thread("Jack");
assert(&Thread::get() == _jack_thread);
_jack_thread->set_context(THREAD_PROCESS);
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
}
diff --git a/src/engine/LV2Node.cpp b/src/engine/LV2Node.cpp
index 3356b4aa..003a6284 100644
--- a/src/engine/LV2Node.cpp
+++ b/src/engine/LV2Node.cpp
@@ -183,8 +183,10 @@ LV2Node::instantiate(BufferFactory& bufs)
PortImpl* port = NULL;
+ float* min_values = new float[num_ports];
+ float* max_values = new float[num_ports];
float* def_values = new float[num_ports];
- slv2_plugin_get_port_ranges_float(plug, 0, 0, def_values);
+ slv2_plugin_get_port_ranges_float(plug, min_values, max_values, def_values);
SLV2Value context_pred = slv2_value_new_uri(info->lv2_world(),
"http://lv2plug.in/ns/dev/contexts#context");
@@ -198,7 +200,7 @@ LV2Node::instantiate(BufferFactory& bufs)
//SLV2Value as_large_as_pred = slv2_value_new_uri(info->lv2_world(),
// "http://lv2plug.in/ns/dev/resize-port#asLargeAs");
- for (uint32_t j=0; j < num_ports; ++j) {
+ for (uint32_t j = 0; j < num_ports; ++j) {
SLV2Port id = slv2_plugin_get_port_by_index(plug, j);
// LV2 port symbols are guaranteed to be unique, valid C identifiers
@@ -276,8 +278,11 @@ LV2Node::instantiate(BufferFactory& bufs)
else
port = new OutputPort(bufs, this, port_name, j, _polyphony, data_type, val, port_buffer_size);
- if (direction == INPUT && data_type == PortType::CONTROL)
+ if (direction == INPUT && data_type == PortType::CONTROL) {
((AudioBuffer*)port->buffer(0).get())->set_value(val.get_float(), 0, 0);
+ port->set_property("lv2:minimum", min_values[j]);
+ port->set_property("lv2:maximum", max_values[j]);
+ }
SLV2Values contexts = slv2_port_get_value(plug, id, context_pred);
for (uint32_t i = 0; i < slv2_values_size(contexts); ++i) {
diff --git a/src/engine/MessageContext.hpp b/src/engine/MessageContext.hpp
index c0813e69..a68d9927 100644
--- a/src/engine/MessageContext.hpp
+++ b/src/engine/MessageContext.hpp
@@ -72,7 +72,7 @@ public:
* AUDIO THREAD ONLY.
*/
inline void signal(ProcessContext& context) {
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
const Request cycle_end_request(context.end(), NULL);
_requests.write(sizeof(Request), &cycle_end_request);
_sem.post();
diff --git a/src/engine/NodeBase.cpp b/src/engine/NodeBase.cpp
index 8fe266e6..0a30b33a 100644
--- a/src/engine/NodeBase.cpp
+++ b/src/engine/NodeBase.cpp
@@ -84,7 +84,7 @@ NodeBase::plugin() const
void
NodeBase::activate()
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
assert(!_activated);
_activated = true;
}
@@ -94,7 +94,7 @@ void
NodeBase::deactivate()
{
// FIXME: Not true witn monolithic GUI/engine
- //assert(ThreadManager::current_thread_id() == THREAD_POST_PROCESS);
+ //ThreadManager::assert_thread(THREAD_POST_PROCESS);
assert(_activated);
_activated = false;
}
@@ -103,7 +103,7 @@ NodeBase::deactivate()
bool
NodeBase::prepare_poly(BufferFactory& bufs, uint32_t poly)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
if (!_polyphonic)
return true;
@@ -119,7 +119,7 @@ NodeBase::prepare_poly(BufferFactory& bufs, uint32_t poly)
bool
NodeBase::apply_poly(Raul::Maid& maid, uint32_t poly)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
if (!_polyphonic)
return true;
@@ -140,7 +140,7 @@ NodeBase::apply_poly(Raul::Maid& maid, uint32_t poly)
void
NodeBase::set_buffer_size(BufferFactory& bufs, size_t size)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
_buffer_size = size;
@@ -176,7 +176,7 @@ NodeBase::process_unlock()
void
NodeBase::wait_for_input(size_t num_providers)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
assert(_process_lock.get() == 1);
while ((unsigned)_n_inputs_ready.get() < num_providers)
@@ -187,7 +187,7 @@ NodeBase::wait_for_input(size_t num_providers)
void
NodeBase::signal_input_ready()
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
++_n_inputs_ready;
_input_ready.post();
}
@@ -198,7 +198,7 @@ NodeBase::signal_input_ready()
void
NodeBase::pre_process(Context& context)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
// Mix down input ports
for (uint32_t i = 0; i < num_ports(); ++i) {
@@ -214,7 +214,7 @@ NodeBase::pre_process(Context& context)
void
NodeBase::post_process(Context& context)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
// Write output ports
for (size_t i = 0; _ports && i < _ports->size(); ++i) {
diff --git a/src/engine/NodeFactory.cpp b/src/engine/NodeFactory.cpp
index 224c2b68..de321077 100644
--- a/src/engine/NodeFactory.cpp
+++ b/src/engine/NodeFactory.cpp
@@ -107,7 +107,7 @@ NodeFactory::plugin(const string& type, const string& lib, const string& label)
void
NodeFactory::load_plugins()
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
_world->rdf_world->mutex().lock();
diff --git a/src/engine/OSCEngineReceiver.cpp b/src/engine/OSCEngineReceiver.cpp
index 8d1a49dc..ee202c95 100644
--- a/src/engine/OSCEngineReceiver.cpp
+++ b/src/engine/OSCEngineReceiver.cpp
@@ -104,7 +104,7 @@ OSCEngineReceiver::OSCEngineReceiver(Engine& engine, size_t queue_size, uint16_t
lo_server_add_method(_server, "/ingen/note_on", "isii", note_on_cb, this);
lo_server_add_method(_server, "/ingen/note_off", "isi", note_off_cb, this);
lo_server_add_method(_server, "/ingen/all_notes_off", "isi", all_notes_off_cb, this);
- lo_server_add_method(_server, "/ingen/midi_learn", "is", midi_learn_cb, this);
+ lo_server_add_method(_server, "/ingen/learn", "is", learn_cb, this);
lo_server_add_method(_server, "/ingen/set_property", NULL, set_property_cb, this);
// Queries
@@ -615,7 +615,7 @@ OSCEngineReceiver::_all_notes_off_cb(const char* path, const char* types, lo_arg
/** \page engine_osc_namespace
- * <h2>/ingen/midi_learn</h2>
+ * <h2>/ingen/learn</h2>
* \arg \b response-id (integer)
* \arg \b node-path (string) - Path of control node.
*
@@ -625,11 +625,11 @@ OSCEngineReceiver::_all_notes_off_cb(const char* path, const char* types, lo_arg
* This command does nothing for objects that are not a control internal.
*/
int
-OSCEngineReceiver::_midi_learn_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+OSCEngineReceiver::_learn_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
{
- const char* patch_path = &argv[1]->s;
+ const char* object_path = &argv[1]->s;
- midi_learn(patch_path);
+ learn(object_path);
return 0;
}
diff --git a/src/engine/OSCEngineReceiver.hpp b/src/engine/OSCEngineReceiver.hpp
index 23764c64..42ef1f5a 100644
--- a/src/engine/OSCEngineReceiver.hpp
+++ b/src/engine/OSCEngineReceiver.hpp
@@ -100,7 +100,7 @@ private:
LO_HANDLER(note_on);
LO_HANDLER(note_off);
LO_HANDLER(all_notes_off);
- LO_HANDLER(midi_learn);
+ LO_HANDLER(learn);
LO_HANDLER(set_property);
LO_HANDLER(property_set);
LO_HANDLER(request_property);
diff --git a/src/engine/PatchImpl.cpp b/src/engine/PatchImpl.cpp
index fb1db54e..96841b33 100644
--- a/src/engine/PatchImpl.cpp
+++ b/src/engine/PatchImpl.cpp
@@ -89,7 +89,7 @@ PatchImpl::deactivate()
void
PatchImpl::disable()
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
_process = false;
@@ -101,7 +101,7 @@ PatchImpl::disable()
bool
PatchImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
/* TODO: ports? internal/external poly? */
@@ -120,7 +120,7 @@ PatchImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly)
bool
PatchImpl::apply_internal_poly(Raul::Maid& maid, uint32_t poly)
{
- assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
+ ThreadManager::assert_thread(THREAD_PROCESS);
/* TODO: ports? internal/external poly? */
@@ -267,7 +267,7 @@ PatchImpl::set_buffer_size(BufferFactory& bufs, size_t size)
void
PatchImpl::add_node(List<NodeImpl*>::Node* ln)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
assert(ln != NULL);
assert(ln->elem() != NULL);
assert(ln->elem()->parent_patch() == this);
@@ -283,7 +283,7 @@ PatchImpl::add_node(List<NodeImpl*>::Node* ln)
PatchImpl::Nodes::Node*
PatchImpl::remove_node(const string& symbol)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i)
if ((*i)->symbol() == symbol)
return _nodes.erase(i);
@@ -298,7 +298,7 @@ PatchImpl::remove_node(const string& symbol)
PatchImpl::Connections::Node*
PatchImpl::remove_connection(const PortImpl* src_port, const PortImpl* dst_port)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
bool found = false;
Connections::Node* connection = NULL;
for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) {
@@ -369,7 +369,7 @@ PatchImpl::create_port(BufferFactory& bufs, const string& name, PortType type, s
List<PortImpl*>::Node*
PatchImpl::remove_port(const string& symbol)
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
bool found = false;
List<PortImpl*>::Node* ret = NULL;
@@ -405,7 +405,7 @@ PatchImpl::remove_port(const string& symbol)
void
PatchImpl::clear_ports()
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
_input_ports.clear();
_output_ports.clear();
@@ -415,7 +415,7 @@ PatchImpl::clear_ports()
Raul::Array<PortImpl*>*
PatchImpl::build_ports_array() const
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
Raul::Array<PortImpl*>* const result = new Raul::Array<PortImpl*>(_input_ports.size() + _output_ports.size());
@@ -444,7 +444,7 @@ PatchImpl::build_ports_array() const
CompiledPatch*
PatchImpl::compile() const
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
CompiledPatch* const compiled_patch = new CompiledPatch();//_nodes.size());
diff --git a/src/engine/QueuedEngineInterface.cpp b/src/engine/QueuedEngineInterface.cpp
index 8f5fdade..575fa5d6 100644
--- a/src/engine/QueuedEngineInterface.cpp
+++ b/src/engine/QueuedEngineInterface.cpp
@@ -228,9 +228,9 @@ QueuedEngineInterface::set_voice_value(const Path& port_path,
void
-QueuedEngineInterface::midi_learn(const Path& node_path)
+QueuedEngineInterface::learn(const Path& path)
{
- push_queued(new Events::MidiLearn(_engine, _responder, now(), node_path));
+ push_queued(new Events::Learn(_engine, _responder, now(), path));
}
diff --git a/src/engine/QueuedEngineInterface.hpp b/src/engine/QueuedEngineInterface.hpp
index 04314c35..6c22a379 100644
--- a/src/engine/QueuedEngineInterface.hpp
+++ b/src/engine/QueuedEngineInterface.hpp
@@ -101,7 +101,7 @@ public:
virtual void disconnect_all(const Raul::Path& parent_patch_path,
const Raul::Path& path);
- virtual void midi_learn(const Raul::Path& node_path);
+ virtual void learn(const Raul::Path& path);
// Requests
virtual void ping();
diff --git a/src/engine/QueuedEvent.cpp b/src/engine/QueuedEvent.cpp
index 23e7ac55..6e9cdeaa 100644
--- a/src/engine/QueuedEvent.cpp
+++ b/src/engine/QueuedEvent.cpp
@@ -25,7 +25,7 @@ namespace Ingen {
void
QueuedEvent::pre_process()
{
- assert(ThreadManager::current_thread_id() == THREAD_PRE_PROCESS);
+ ThreadManager::assert_thread(THREAD_PRE_PROCESS);
assert(_pre_processed == false);
_pre_processed = true;
}
diff --git a/src/engine/QueuedEvent.hpp b/src/engine/QueuedEvent.hpp
index f19c7b95..eca7da03 100644
--- a/src/engine/QueuedEvent.hpp
+++ b/src/engine/QueuedEvent.hpp
@@ -62,10 +62,7 @@ protected:
, _source(source)
, _pre_processed(false)
, _blocking(blocking)
- {
- if (blocking)
- assert(_source);
- }
+ {}
// NULL event base (for internal events only!)
QueuedEvent(Engine& engine)
@@ -76,8 +73,8 @@ protected:
{}
EventSource* _source;
- bool _pre_processed;
- bool _blocking;
+ bool _pre_processed;
+ bool _blocking;
};
diff --git a/src/engine/ThreadManager.hpp b/src/engine/ThreadManager.hpp
index 6821949c..26368deb 100644
--- a/src/engine/ThreadManager.hpp
+++ b/src/engine/ThreadManager.hpp
@@ -18,6 +18,7 @@
#ifndef THREADMANAGER_H
#define THREADMANAGER_H
+#include <cassert>
#include "raul/Thread.hpp"
namespace Ingen {
@@ -36,6 +37,19 @@ public:
inline static ThreadID current_thread_id() {
return (ThreadID)Raul::Thread::get().context();
}
+
+ inline static void assert_thread(ThreadID id) {
+ assert(single_threaded || current_thread_id() == id);
+ }
+
+ inline static void assert_not_thread(ThreadID id) {
+ assert(single_threaded || current_thread_id() != id);
+ }
+
+ /** Set to true during initialisation so ensure_thread doesn't fail.
+ * Defined in Engine.cpp
+ */
+ static bool single_threaded;
};
diff --git a/src/engine/events.hpp b/src/engine/events.hpp
index 62a37aba..501e7941 100644
--- a/src/engine/events.hpp
+++ b/src/engine/events.hpp
@@ -30,8 +30,8 @@
#include "events/Disconnect.hpp"
#include "events/DisconnectAll.hpp"
#include "events/Get.hpp"
+#include "events/Learn.hpp"
#include "events/LoadPlugins.hpp"
-#include "events/MidiLearn.hpp"
#include "events/Move.hpp"
#include "events/Note.hpp"
#include "events/Ping.hpp"
diff --git a/src/engine/events/CreatePort.cpp b/src/engine/events/CreatePort.cpp
index 7845994a..73ba4b83 100644
--- a/src/engine/events/CreatePort.cpp
+++ b/src/engine/events/CreatePort.cpp
@@ -143,6 +143,9 @@ CreatePort::execute(ProcessContext& context)
if (_driver_port) {
_engine.driver()->add_port(_driver_port);
}
+
+ if (_source)
+ _source->unblock();
}
diff --git a/src/engine/events/CreatePort.hpp b/src/engine/events/CreatePort.hpp
index c7ddb56a..adda30bb 100644
--- a/src/engine/events/CreatePort.hpp
+++ b/src/engine/events/CreatePort.hpp
@@ -55,7 +55,6 @@ public:
void post_process();
private:
-
enum ErrorType {
NO_ERROR,
UNKNOWN_TYPE,
diff --git a/src/engine/events/MidiLearn.cpp b/src/engine/events/Learn.cpp
index b5c25102..e700ab79 100644
--- a/src/engine/events/MidiLearn.cpp
+++ b/src/engine/events/Learn.cpp
@@ -15,14 +15,16 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "events/MidiLearn.hpp"
-#include "Responder.hpp"
+#include "events/Learn.hpp"
+#include "ClientBroadcaster.hpp"
+#include "ControlBindings.hpp"
#include "Engine.hpp"
#include "EngineStore.hpp"
#include "NodeImpl.hpp"
-#include "internals/Controller.hpp"
-#include "ClientBroadcaster.hpp"
#include "PluginImpl.hpp"
+#include "PortImpl.hpp"
+#include "Responder.hpp"
+#include "internals/Controller.hpp"
using namespace std;
@@ -30,50 +32,62 @@ namespace Ingen {
namespace Events {
-MidiLearn::MidiLearn(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const Raul::Path& node_path)
+Learn::Learn(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const Raul::Path& path)
: QueuedEvent(engine, responder, timestamp)
, _error(NO_ERROR)
- , _node_path(node_path)
- , _node(NULL)
+ , _path(path)
+ , _object(NULL)
+ , _done(false)
{
}
void
-MidiLearn::pre_process()
+Learn::pre_process()
{
- _node = _engine.engine_store()->find_node(_node_path);
+ _object = _engine.engine_store()->find_object(_path);
+
+ PortImpl* port = dynamic_cast<PortImpl*>(_object);
+ if (port) {
+ _done = true;
+ if (port->type() == Shared::PortType::CONTROL)
+ _engine.control_bindings()->learn(port);
+ }
QueuedEvent::pre_process();
}
void
-MidiLearn::execute(ProcessContext& context)
+Learn::execute(ProcessContext& context)
{
QueuedEvent::execute(context);
- if (_node != NULL) {
- if (_node->plugin_impl()->type() == Shared::Plugin::Internal) {
- ((NodeBase*)_node)->learn();
- } else {
- _error = INVALID_NODE_TYPE;
- }
+ if (_done || !_object)
+ return;
+
+ NodeImpl* node = dynamic_cast<NodeImpl*>(_object);
+ if (node) {
+ if (node->plugin_impl()->type() == Shared::Plugin::Internal) {
+ ((NodeBase*)_object)->learn();
+ } else {
+ _error = INVALID_NODE_TYPE;
+ }
}
}
void
-MidiLearn::post_process()
+Learn::post_process()
{
if (_error == NO_ERROR) {
_responder->respond_ok();
- } else if (_node == NULL) {
+ } else if (_object == NULL) {
string msg = "Did not find node '";
- msg.append(_node_path.str()).append("' for MIDI learn.");
+ msg.append(_path.str()).append("' for learn.");
_responder->respond_error(msg);
} else {
- const string msg = string("Node '") + _node_path.str() + "' is not capable of MIDI learn.";
+ const string msg = string("Object '") + _path.str() + "' is not capable of learning.";
_responder->respond_error(msg);
}
}
diff --git a/src/engine/events/MidiLearn.hpp b/src/engine/events/Learn.hpp
index 5835cf6a..8eb61c5f 100644
--- a/src/engine/events/MidiLearn.hpp
+++ b/src/engine/events/Learn.hpp
@@ -33,10 +33,10 @@ namespace Events {
*
* \ingroup engine
*/
-class MidiLearn : public QueuedEvent
+class Learn : public QueuedEvent
{
public:
- MidiLearn(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const Raul::Path& node_path);
+ Learn(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const Raul::Path& path);
void pre_process();
void execute(ProcessContext& context);
@@ -49,8 +49,9 @@ private:
};
ErrorType _error;
- const Raul::Path _node_path;
- NodeImpl* _node;
+ const Raul::Path _path;
+ GraphObjectImpl* _object;
+ bool _done;
};
diff --git a/src/engine/events/SendPortValue.cpp b/src/engine/events/SendPortValue.cpp
index 4088568f..1052033b 100644
--- a/src/engine/events/SendPortValue.cpp
+++ b/src/engine/events/SendPortValue.cpp
@@ -30,12 +30,10 @@ namespace Events {
void
SendPortValue::post_process()
{
- // FIXME...
-
if (_omni) {
_engine.broadcaster()->set_port_value(_port->path(), _value);
} else {
- _engine.broadcaster()->set_port_value(_port->path(), _value);
+ _engine.broadcaster()->set_voice_value(_port->path(), _voice_num, _value);
}
}
diff --git a/src/engine/events/SetMetadata.cpp b/src/engine/events/SetMetadata.cpp
index 5669b63d..ae69aecf 100644
--- a/src/engine/events/SetMetadata.cpp
+++ b/src/engine/events/SetMetadata.cpp
@@ -203,7 +203,7 @@ SetMetadata::execute(ProcessContext& context)
if (_create_event) {
QueuedEvent::execute(context);
_create_event->execute(context);
- if (_blocking)
+ if (_blocking && _source)
_source->unblock();
return;
}
diff --git a/src/engine/internals/Controller.cpp b/src/engine/internals/Controller.cpp
index 9ad940d2..44b6a184 100644
--- a/src/engine/internals/Controller.cpp
+++ b/src/engine/internals/Controller.cpp
@@ -19,7 +19,7 @@
#include "raul/midi_events.h"
#include "internals/Controller.hpp"
#include "PostProcessor.hpp"
-#include "events/MidiLearn.hpp"
+#include "events/Learn.hpp"
#include "events/SendPortValue.hpp"
#include "InputPort.hpp"
#include "OutputPort.hpp"
@@ -78,11 +78,11 @@ ControllerNode::process(ProcessContext& context)
{
NodeBase::pre_process(context);
- uint32_t frames = 0;
+ uint32_t frames = 0;
uint32_t subframes = 0;
- uint16_t type = 0;
- uint16_t size = 0;
- uint8_t* buf = NULL;
+ uint16_t type = 0;
+ uint16_t size = 0;
+ uint8_t* buf = NULL;
EventBuffer* const midi_in = (EventBuffer*)_midi_in_port->buffer(0).get();
diff --git a/src/engine/wscript b/src/engine/wscript
index 2b98df26..e0ac6d69 100644
--- a/src/engine/wscript
+++ b/src/engine/wscript
@@ -10,6 +10,7 @@ def build(bld):
BufferFactory.cpp
ClientBroadcaster.cpp
ConnectionImpl.cpp
+ ControlBindings.cpp
DuplexPort.cpp
Engine.cpp
EngineStore.cpp
@@ -42,8 +43,8 @@ def build(bld):
events/Disconnect.cpp
events/DisconnectAll.cpp
events/Get.cpp
+ events/Learn.cpp
events/LoadPlugins.cpp
- events/MidiLearn.cpp
events/Move.cpp
events/Note.cpp
events/RegisterClient.cpp
diff --git a/src/gui/NodeMenu.cpp b/src/gui/NodeMenu.cpp
index d667181a..f676ed79 100644
--- a/src/gui/NodeMenu.cpp
+++ b/src/gui/NodeMenu.cpp
@@ -37,13 +37,11 @@ NodeMenu::NodeMenu(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml
{
Gtk::Menu* node_menu = NULL;
xml->get_widget("node_menu", node_menu);
- xml->get_widget("node_learn_menuitem", _learn_menuitem);
xml->get_widget("node_controls_menuitem", _controls_menuitem);
xml->get_widget("node_popup_gui_menuitem", _popup_gui_menuitem);
xml->get_widget("node_embed_gui_menuitem", _embed_gui_menuitem);
xml->get_widget("node_randomize_menuitem", _randomize_menuitem);
- node_menu->remove(*_learn_menuitem);
node_menu->remove(*_controls_menuitem);
node_menu->remove(*_popup_gui_menuitem);
node_menu->remove(*_embed_gui_menuitem);
@@ -54,7 +52,6 @@ NodeMenu::NodeMenu(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml
insert(*_controls_menuitem, 0);
insert(*_popup_gui_menuitem, 0);
insert(*_embed_gui_menuitem, 0);
- insert(*_learn_menuitem, 0);
}
@@ -154,13 +151,6 @@ NodeMenu::on_menu_randomize()
void
-NodeMenu::on_menu_learn()
-{
- App::instance().engine()->midi_learn(_object->path());
-}
-
-
-void
NodeMenu::on_menu_disconnect()
{
App::instance().engine()->disconnect_all(_object->parent()->path(), _object->path());
diff --git a/src/gui/NodeMenu.hpp b/src/gui/NodeMenu.hpp
index 29abc603..dc9c2cfe 100644
--- a/src/gui/NodeMenu.hpp
+++ b/src/gui/NodeMenu.hpp
@@ -47,17 +47,14 @@ public:
sigc::signal<void, bool> signal_embed_gui;
protected:
-
virtual void enable_controls_menuitem();
virtual void disable_controls_menuitem();
void on_menu_disconnect();
- void on_menu_learn();
void on_menu_embed_gui();
void on_menu_randomize();
void on_preset_activated(const std::string uri);
- Gtk::MenuItem* _learn_menuitem;
Gtk::MenuItem* _controls_menuitem;
Gtk::MenuItem* _popup_gui_menuitem;
Gtk::CheckMenuItem* _embed_gui_menuitem;
diff --git a/src/gui/ObjectMenu.cpp b/src/gui/ObjectMenu.cpp
index 261cbd44..781c4359 100644
--- a/src/gui/ObjectMenu.cpp
+++ b/src/gui/ObjectMenu.cpp
@@ -37,6 +37,7 @@ ObjectMenu::ObjectMenu(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade:
, _destroy_menuitem(NULL)
, _properties_menuitem(NULL)
{
+ xml->get_widget("object_learn_menuitem", _learn_menuitem);
xml->get_widget("object_polyphonic_menuitem", _polyphonic_menuitem);
xml->get_widget("object_disconnect_menuitem", _disconnect_menuitem);
xml->get_widget("object_rename_menuitem", _rename_menuitem);
@@ -57,6 +58,9 @@ ObjectMenu::init(SharedPtr<ObjectModel> object)
_polyphonic_menuitem->set_active(object->polyphonic());
+ _learn_menuitem->signal_activate().connect(
+ sigc::mem_fun(this, &ObjectMenu::on_menu_learn));
+
_disconnect_menuitem->signal_activate().connect(
sigc::mem_fun(this, &ObjectMenu::on_menu_disconnect));
@@ -72,11 +76,20 @@ ObjectMenu::init(SharedPtr<ObjectModel> object)
object->signal_property.connect(sigc::mem_fun(this, &ObjectMenu::property_changed));
+ _learn_menuitem->hide();
+
_enable_signal = true;
}
void
+ObjectMenu::on_menu_learn()
+{
+ App::instance().engine()->learn(_object->path());
+}
+
+
+void
ObjectMenu::on_menu_polyphonic()
{
if (_enable_signal)
diff --git a/src/gui/ObjectMenu.hpp b/src/gui/ObjectMenu.hpp
index 1a722581..a619c5e4 100644
--- a/src/gui/ObjectMenu.hpp
+++ b/src/gui/ObjectMenu.hpp
@@ -44,6 +44,7 @@ public:
void init(SharedPtr<ObjectModel> object);
protected:
+ void on_menu_learn();
virtual void on_menu_disconnect() = 0;
void on_menu_polyphonic();
void on_menu_destroy();
@@ -53,6 +54,7 @@ protected:
bool _enable_signal;
SharedPtr<ObjectModel> _object;
+ Gtk::MenuItem* _learn_menuitem;
Gtk::CheckMenuItem* _polyphonic_menuitem;
Gtk::MenuItem* _disconnect_menuitem;
Gtk::MenuItem* _rename_menuitem;
diff --git a/src/gui/Port.cpp b/src/gui/Port.cpp
index bbde8100..fafac68d 100644
--- a/src/gui/Port.cpp
+++ b/src/gui/Port.cpp
@@ -139,10 +139,12 @@ Port::on_event(GdkEvent* ev)
{
switch (ev->type) {
case GDK_BUTTON_PRESS:
- _pressed = true;
+ if (ev->button.button == 1)
+ _pressed = true;
break;
case GDK_BUTTON_RELEASE:
- _pressed = false;
+ if (ev->button.button == 1)
+ _pressed = false;
default:
break;
}
diff --git a/src/gui/PortMenu.cpp b/src/gui/PortMenu.cpp
index a32eb662..3cb8c071 100644
--- a/src/gui/PortMenu.cpp
+++ b/src/gui/PortMenu.cpp
@@ -50,6 +50,9 @@ PortMenu::init(SharedPtr<PortModel> port, bool patch_port)
if (port->type() == PortType::EVENTS)
_polyphonic_menuitem->hide();
+ if (port->type() == PortType::CONTROL)
+ _learn_menuitem->show();
+
_enable_signal = true;
}
diff --git a/src/gui/ingen_gui.glade b/src/gui/ingen_gui.glade
index f294678b..ad84483f 100644
--- a/src/gui/ingen_gui.glade
+++ b/src/gui/ingen_gui.glade
@@ -2924,6 +2924,7 @@ Thank you for contributing.</property>
<widget class="GtkImageMenuItem" id="port_control_menu_properties">
<property name="label">gtk-properties</property>
<property name="visible">True</property>
+ <property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_port_control_menu_properties_activate"/>
</widget>
@@ -3064,6 +3065,13 @@ Thank you for contributing.</property>
</widget>
</child>
<child>
+ <widget class="GtkMenuItem" id="object_learn_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Learn</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
<widget class="GtkImageMenuItem" id="object_disconnect_menuitem">
<property name="label">Dis_connect</property>
<property name="visible">True</property>
@@ -3113,16 +3121,6 @@ Thank you for contributing.</property>
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
- <widget class="GtkImageMenuItem" id="node_learn_menuitem">
- <property name="label">_Learn</property>
- <property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="tooltip" translatable="yes">Learn from the next received event</property>
- <property name="use_underline">True</property>
- <property name="use_stock">False</property>
- </widget>
- </child>
- <child>
<widget class="GtkImageMenuItem" id="node_controls_menuitem">
<property name="label">Con_trols...</property>
<property name="visible">True</property>