diff options
author | David Robillard <d@drobilla.net> | 2010-01-29 01:43:54 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2010-01-29 01:43:54 +0000 |
commit | d5a514148bec58cd7e97d032259362b2e19c0e95 (patch) | |
tree | 64ea4dd182a8918b47a6d5f391e2cd097aebb526 /src | |
parent | 36039b294ee823ceb2c239129defc5eafa110247 (diff) | |
download | ingen-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')
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> |