diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2009-12-28 16:49:44 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2009-12-28 16:49:44 +0000 |
commit | 109acd156861b7a792f5c4c8b3a9cc96b6ba3eaf (patch) | |
tree | 6a9c67ba9dd64802e2b5d94748bd9a8dcce18586 | |
parent | cba3ca64b359b32909bc29f5fe75e8e2fd9c83d8 (diff) |
MIDI binding maps make their debut
git-svn-id: svn://localhost/ardour2/branches/3.0@6408 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | libs/ardour/ardour/session.h | 1 | ||||
-rw-r--r-- | libs/ardour/midi_ui.cc | 12 | ||||
-rw-r--r-- | libs/ardour/session_state.cc | 35 | ||||
-rw-r--r-- | libs/pbd/base_ui.cc | 1 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/generic_midi_control_protocol.cc | 193 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/generic_midi_control_protocol.h | 30 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/midicontrollable.cc | 8 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/midicontrollable.h | 7 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/wscript | 1 |
9 files changed, 279 insertions, 9 deletions
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index b72822bd1c..a21bc04690 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -769,6 +769,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi /* Controllables */ boost::shared_ptr<PBD::Controllable> controllable_by_id (const PBD::ID&); + boost::shared_ptr<PBD::Controllable> controllable_by_uri (const std::string&); void add_controllable (boost::shared_ptr<PBD::Controllable>); void remove_controllable (PBD::Controllable*); diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc index aa81ff2068..fb85309ee1 100644 --- a/libs/ardour/midi_ui.cc +++ b/libs/ardour/midi_ui.cc @@ -68,6 +68,12 @@ MidiControlUI::do_request (MidiUIRequest* req) } else if (req->type == CallSlot) { +#ifndef NDEBUG + if (getenv ("DEBUG_THREADED_SIGNALS")) { + cerr << "MIDI UI calls a slot\n"; + } +#endif + req->the_slot (); } else if (req->type == Quit) { @@ -149,6 +155,12 @@ MidiControlUI::thread_init () { struct sched_param rtparam; + char* c = new char[7]; + strcpy (c, X_("midiUI")); + pthread_set_name (c); + + cerr << "MIDI UI running\n"; + PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self(), X_("MIDI"), 2048); SessionEvent::create_per_thread_pool (X_("MIDI I/O"), 128); diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 9394cd7bec..8ff076f759 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -2678,6 +2678,41 @@ Session::controllable_by_id (const PBD::ID& id) return boost::shared_ptr<Controllable>(); } +boost::shared_ptr<Controllable> +Session::controllable_by_uri (const std::string& uri) +{ + boost::shared_ptr<Controllable> c; + string::size_type last_slash; + string useful_part; + + if ((last_slash = uri.find_last_of ('/')) == string::npos) { + return c; + } + + useful_part = uri.substr (last_slash+1); + + uint32_t rid; + char what[64]; + + if (sscanf (useful_part.c_str(), "rid=%" PRIu32 "?%63s", &rid, what) != 2) { + return c; + } + + boost::shared_ptr<Route> r = route_by_remote_id (rid); + + if (!r) { + return c; + } + + if (strncmp (what, "gain", 4) == 0) { + c = r->gain_control (); + } else if (strncmp (what, "pan", 3) == 0) { + } else if (strncmp (what, "plugin", 6) == 0) { + } + + return c; +} + void Session::add_instant_xml (XMLNode& node, bool write_to_config) { diff --git a/libs/pbd/base_ui.cc b/libs/pbd/base_ui.cc index 5e856d1ca0..ce7018a005 100644 --- a/libs/pbd/base_ui.cc +++ b/libs/pbd/base_ui.cc @@ -25,6 +25,7 @@ #include <cstring> #include "pbd/base_ui.h" +#include "pbd/pthread_utils.h" #include "pbd/error.h" #include "pbd/compose.h" #include "pbd/failed_constructor.h" diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index c3d7aabfaf..67e940d905 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -34,9 +34,11 @@ #include "generic_midi_control_protocol.h" #include "midicontrollable.h" +#include "midifunction.h" using namespace ARDOUR; using namespace PBD; +using namespace std; #include "i18n.h" @@ -44,7 +46,7 @@ using namespace PBD; #define ui_bind(x) boost::protect (boost::bind ((x))) GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) - : ControlProtocol (s, _("Generic MIDI"), MidiControlUI::instance()) + : ControlProtocol (s, _("Generic MIDI"), midi_ui_context()) { MIDI::Manager* mm = MIDI::Manager::instance(); @@ -71,10 +73,32 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1)); Session::SendFeedback.connect (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());; + + std::string xmlpath = "/tmp/midi.map"; + + load_bindings (xmlpath); + reset_controllables (); } GenericMidiControlProtocol::~GenericMidiControlProtocol () { + Glib::Mutex::Lock lm (pending_lock); + Glib::Mutex::Lock lm2 (controllables_lock); + + for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) { + delete *i; + } + controllables.clear (); + + for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) { + delete *i; + } + pending_controllables.clear (); + + for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) { + delete *i; + } + functions.clear (); } int @@ -136,6 +160,9 @@ GenericMidiControlProtocol::start_learning (Controllable* c) return false; } + Glib::Mutex::Lock lm (pending_lock); + Glib::Mutex::Lock lm2 (controllables_lock); + MIDIControllables::iterator tmp; for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) { tmp = i; @@ -392,3 +419,167 @@ GenericMidiControlProtocol::get_feedback () const return do_feedback; } +int +GenericMidiControlProtocol::load_bindings (const string& xmlpath) +{ + XMLTree state_tree; + + if (!state_tree.read (xmlpath.c_str())) { + error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg; + return -1; + } + + XMLNode* root = state_tree.root(); + + if (root->name() != X_("ArdourMIDIBindings")) { + error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg; + return -1; + } + + const XMLProperty* prop; + + if ((prop = root->property ("version")) == 0) { + return -1; + } else { + int major; + int minor; + int micro; + + sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ); + Stateful::loading_state_version = (major * 1000) + minor; + } + + const XMLNodeList& children (root->children()); + XMLNodeConstIterator citer; + XMLNodeConstIterator gciter; + + MIDIControllable* mc; + + for (citer = children.begin(); citer != children.end(); ++citer) { + if ((*citer)->name() == "Binding") { + const XMLNode* child = *citer; + + if (child->property ("uri")) { + /* controllable */ + + if ((mc = create_binding (*child)) != 0) { + Glib::Mutex::Lock lm2 (controllables_lock); + controllables.insert (mc); + } + + } else if (child->property ("function")) { + + /* function */ + MIDIFunction* mf; + + if ((mf = create_function (*child)) != 0) { + functions.push_back (mf); + } + } + } + } + + return 0; +} + +MIDIControllable* +GenericMidiControlProtocol::create_binding (const XMLNode& node) +{ + const XMLProperty* prop; + int detail; + int channel; + string uri; + MIDI::eventType ev; + + if ((prop = node.property (X_("channel"))) == 0) { + return 0; + } + + if (sscanf (prop->value().c_str(), "%d", &channel) != 1) { + return 0; + } + + if ((prop = node.property (X_("ctl"))) != 0) { + ev = MIDI::controller; + } else if ((prop = node.property (X_("note"))) != 0) { + ev = MIDI::on; + } else if ((prop = node.property (X_("pgm"))) != 0) { + ev = MIDI::program; + } else { + return 0; + } + + if (sscanf (prop->value().c_str(), "%d", &detail) != 1) { + return 0; + } + + prop = node.property (X_("uri")); + uri = prop->value(); + + MIDIControllable* mc = new MIDIControllable (*_port, uri, false); + mc->bind_midi (channel, ev, detail); + + cerr << "New MC with URI = " << uri << endl; + + return mc; +} + +void +GenericMidiControlProtocol::reset_controllables () +{ + Glib::Mutex::Lock lm2 (controllables_lock); + + for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) { + MIDIControllable* existingBinding = (*iter); + + boost::shared_ptr<Controllable> c = session->controllable_by_uri (existingBinding->current_uri()); + existingBinding->set_controllable (c.get()); + } +} + +MIDIFunction* +GenericMidiControlProtocol::create_function (const XMLNode& node) +{ + const XMLProperty* prop; + int detail; + int channel; + string uri; + MIDI::eventType ev; + + if ((prop = node.property (X_("channel"))) == 0) { + return 0; + } + + if (sscanf (prop->value().c_str(), "%d", &channel) != 1) { + return 0; + } + + if ((prop = node.property (X_("ctl"))) != 0) { + ev = MIDI::controller; + } else if ((prop = node.property (X_("note"))) != 0) { + ev = MIDI::on; + } else if ((prop = node.property (X_("pgm"))) != 0) { + ev = MIDI::program; + } else { + return 0; + } + + if (sscanf (prop->value().c_str(), "%d", &detail) != 1) { + return 0; + } + + prop = node.property (X_("function")); + + MIDIFunction* mf = new MIDIFunction (*_port); + + if (mf->init (*this, prop->value())) { + delete mf; + return 0; + } + + mf->bind_midi (channel, ev, detail); + + cerr << "New MF with function = " << prop->value() << endl; + + return mf; +} diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h index 39958bcf26..0c476f2418 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h @@ -1,7 +1,27 @@ +/* + Copyright (C) 2006 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + #ifndef ardour_generic_midi_control_protocol_h #define ardour_generic_midi_control_protocol_h #include <set> +#include <list> #include <glibmm/thread.h> #include "ardour/types.h" @@ -20,6 +40,7 @@ namespace ARDOUR { } class MIDIControllable; +class MIDIFunction; class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { public: @@ -50,6 +71,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { typedef std::set<MIDIControllable*> MIDIControllables; MIDIControllables controllables; + typedef std::list<MIDIFunction*> MIDIFunctions; + MIDIFunctions functions; + typedef std::pair<MIDIControllable*,PBD::Connection> MIDIPendingControllable; typedef std::list<MIDIPendingControllable* > MIDIPendingControllables; MIDIPendingControllables pending_controllables; @@ -63,6 +87,12 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { void create_binding (PBD::Controllable*, int, int); void delete_binding (PBD::Controllable*); + + int load_bindings (const std::string&); + MIDIControllable* create_binding (const XMLNode&); + MIDIFunction* create_function (const XMLNode&); + + void reset_controllables (); }; #endif /* ardour_generic_midi_control_protocol_h */ diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index d6b4007194..9c808af005 100644 --- a/libs/surfaces/generic_midi/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -91,13 +91,9 @@ MIDIControllable::drop_external_control () } void -MIDIControllable::reacquire_controllable () +MIDIControllable::set_controllable (Controllable* c) { - if (!_current_uri.empty()) { - controllable = Controllable::by_uri (_current_uri); - } else { - controllable = 0; - } + controllable = c; } void diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h index 4661b2f4c6..b6f7da5639 100644 --- a/libs/surfaces/generic_midi/midicontrollable.h +++ b/libs/surfaces/generic_midi/midicontrollable.h @@ -45,8 +45,10 @@ class MIDIControllable : public PBD::Stateful MIDIControllable (MIDI::Port&, const std::string& uri, bool bistate = false); virtual ~MIDIControllable (); - bool ok() const { return !_current_uri.empty(); } + void rediscover_controllable (); + bool ok() const { return !_current_uri.empty(); } + void send_feedback (); MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, bool force = false); @@ -64,6 +66,8 @@ class MIDIControllable : public PBD::Stateful MIDI::Port& get_port() const { return _port; } PBD::Controllable* get_controllable() const { return controllable; } + void set_controllable (PBD::Controllable*); + const std::string& current_uri() const { return _current_uri; } std::string control_description() const { return _control_description; } @@ -92,7 +96,6 @@ class MIDIControllable : public PBD::Stateful bool feedback; void init (); - void reacquire_controllable (); void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t); void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on); diff --git a/libs/surfaces/generic_midi/wscript b/libs/surfaces/generic_midi/wscript index 37975fb434..89e427323f 100644 --- a/libs/surfaces/generic_midi/wscript +++ b/libs/surfaces/generic_midi/wscript @@ -24,6 +24,7 @@ def build(bld): generic_midi_control_protocol.cc interface.cc midicontrollable.cc + midifunction.cc ''' obj.export_incdirs = ['.'] obj.cxxflags = '-DPACKAGE="ardour_genericmidi"' |