2 Copyright (C) 2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <io.h> // Microsoft's nearest equivalent to <unistd.h>
27 #include <ardourext/misc.h>
32 #include <glibmm/fileutils.h>
33 #include <glibmm/miscutils.h>
35 #include "pbd/compose.h"
36 #include "pbd/convert.h"
37 #include "pbd/error.h"
38 #include "pbd/failed_constructor.h"
39 #include "pbd/file_utils.h"
40 #include "pbd/strsplit.h"
41 #include "pbd/types_convert.h"
42 #include "pbd/xml++.h"
44 #include "midi++/port.h"
46 #include "ardour/async_midi_port.h"
47 #include "ardour/audioengine.h"
48 #include "ardour/auditioner.h"
49 #include "ardour/filesystem_paths.h"
50 #include "ardour/session.h"
51 #include "ardour/midi_ui.h"
52 #include "ardour/plugin_insert.h"
53 #include "ardour/rc_configuration.h"
54 #include "ardour/midiport_manager.h"
55 #include "ardour/debug.h"
57 #include "generic_midi_control_protocol.h"
58 #include "midicontrollable.h"
59 #include "midifunction.h"
60 #include "midiaction.h"
62 using namespace ARDOUR;
68 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
70 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
71 : ControlProtocol (s, _("Generic MIDI"))
72 , connection_state (ConnectionState (0))
77 _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort> (s.midi_input_port ());
78 _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort> (s.midi_output_port ());
80 _input_bundle.reset (new ARDOUR::Bundle (_("Generic MIDI Control In"), true));
81 _output_bundle.reset (new ARDOUR::Bundle (_("Generic MIDI Control Out"), false));
83 _input_bundle->add_channel (
84 boost::static_pointer_cast<MidiPort>(_input_port)->name(),
85 ARDOUR::DataType::MIDI,
86 session->engine().make_port_name_non_relative (boost::static_pointer_cast<MidiPort>(_input_port)->name())
89 _output_bundle->add_channel (
90 boost::static_pointer_cast<MidiPort>(_output_port)->name(),
91 ARDOUR::DataType::MIDI,
92 session->engine().make_port_name_non_relative (boost::static_pointer_cast<MidiPort>(_output_port)->name())
95 session->BundleAddedOrRemoved ();
98 _feedback_interval = 10000; // microseconds
99 last_feedback_time = 0;
104 /* these signals are emitted by the MidiControlUI's event loop thread
105 * and we may as well handle them right there in the same the same
109 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
110 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
111 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
112 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
114 /* this signal is emitted by the process() callback, and if
115 * send_feedback() is going to do anything, it should do it in the
116 * context of the process() callback itself.
119 Session::SendFeedback.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this));
120 //Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
122 /* this one is cross-thread */
124 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
126 /* Catch port connections and disconnections (cross-thread) */
127 ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR,
128 boost::bind (&GenericMidiControlProtocol::connection_handler, this, _1, _2, _3, _4, _5),
134 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
140 list<boost::shared_ptr<ARDOUR::Bundle> >
141 GenericMidiControlProtocol::bundles ()
143 list<boost::shared_ptr<ARDOUR::Bundle> > b;
146 b.push_back (_input_bundle);
147 b.push_back (_output_bundle);
154 static const char * const midimap_env_variable_name = "ARDOUR_MIDIMAPS_PATH";
155 static const char* const midi_map_dir_name = "midi_maps";
156 static const char* const midi_map_suffix = ".map";
159 system_midi_map_search_path ()
161 bool midimap_path_defined = false;
162 std::string spath_env (Glib::getenv (midimap_env_variable_name, midimap_path_defined));
164 if (midimap_path_defined) {
168 Searchpath spath (ardour_data_search_path());
169 spath.add_subdirectory_to_paths(midi_map_dir_name);
174 user_midi_map_directory ()
176 return Glib::build_filename (user_config_directory(), midi_map_dir_name);
180 midi_map_filter (const string &str, void* /*arg*/)
182 return (str.length() > strlen(midi_map_suffix) &&
183 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
187 GenericMidiControlProtocol::reload_maps ()
189 vector<string> midi_maps;
190 Searchpath spath (system_midi_map_search_path());
191 spath += user_midi_map_directory ();
193 find_files_matching_filter (midi_maps, spath, midi_map_filter, 0, false, true);
195 if (midi_maps.empty()) {
196 cerr << "No MIDI maps found using " << spath.to_string() << endl;
200 for (vector<string>::iterator i = midi_maps.begin(); i != midi_maps.end(); ++i) {
201 string fullpath = *i;
205 if (!tree.read (fullpath.c_str())) {
212 if (!tree.root()->get_property ("name", str)) {
219 map_info.push_back (mi);
224 GenericMidiControlProtocol::drop_all ()
226 DEBUG_TRACE (DEBUG::GenericMidi, "Drop all bindings\n");
227 Glib::Threads::Mutex::Lock lm (pending_lock);
228 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
230 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
233 controllables.clear ();
235 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
236 (*i)->connection.disconnect();
242 pending_controllables.clear ();
244 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
249 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
256 GenericMidiControlProtocol::drop_bindings ()
258 DEBUG_TRACE (DEBUG::GenericMidi, "Drop bindings, leave learned\n");
259 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
261 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
262 if (!(*i)->learned()) {
264 i = controllables.erase (i);
270 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
275 _current_binding = "";
281 GenericMidiControlProtocol::set_active (bool /*yn*/)
283 /* nothing to do here: the MIDI UI thread in libardour handles all our
290 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
292 _feedback_interval = ms;
296 GenericMidiControlProtocol::send_feedback ()
298 /* This is executed in RT "process" context", so no blocking calls
305 microseconds_t now = get_microseconds ();
307 if (last_feedback_time != 0) {
308 if ((now - last_feedback_time) < _feedback_interval) {
315 last_feedback_time = now;
319 GenericMidiControlProtocol::_send_feedback ()
321 /* This is executed in RT "process" context", so no blocking calls
324 const int32_t bufsize = 16 * 1024; /* XXX too big */
325 MIDI::byte buf[bufsize];
326 int32_t bsize = bufsize;
328 /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
329 writes for each controllable here; if we send more than one MIDI message
330 in a single jack_midi_event_write then some bridges will only pass the
334 Glib::Threads::Mutex::Lock lm (controllables_lock, Glib::Threads::TRY_LOCK);
339 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
340 MIDI::byte* end = (*r)->write_feedback (buf, bsize);
342 _output_port->write (buf, (int32_t) (end - buf), 0);
348 GenericMidiControlProtocol::start_learning (Controllable* c)
354 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
355 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Learn binding: Controlable number: %1\n", c));
357 /* drop any existing mappings for the same controllable for which
358 * learning has just started.
361 MIDIControllables::iterator tmp;
362 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
365 if ((*i)->get_controllable() == c) {
367 controllables.erase (i);
372 /* check pending controllables (those for which a learn is underway) to
373 * see if it is for the same one for which learning has just started.
377 Glib::Threads::Mutex::Lock lm (pending_lock);
379 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
380 if (((*i)->mc)->get_controllable() == c) {
381 (*i)->connection.disconnect();
386 i = pending_controllables.erase (i);
393 MIDIControllable* mc = 0;
396 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
397 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
404 mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
408 /* stuff the new controllable into pending */
411 Glib::Threads::Mutex::Lock lm (pending_lock);
413 MIDIPendingControllable* element = new MIDIPendingControllable (mc, own_mc);
414 c->LearningFinished.connect_same_thread (element->connection, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
416 pending_controllables.push_back (element);
418 mc->learn_about_external_control ();
423 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
425 Glib::Threads::Mutex::Lock lm (pending_lock);
426 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
428 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
429 if ( (*i)->mc == mc) {
430 (*i)->connection.disconnect();
432 i = pending_controllables.erase(i);
438 /* add the controllable for which learning stopped to our list of
442 controllables.push_back (mc);
446 GenericMidiControlProtocol::stop_learning (Controllable* c)
448 Glib::Threads::Mutex::Lock lm (pending_lock);
449 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
450 MIDIControllable* dptr = 0;
452 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
453 relevant MIDIControllable and remove it from the pending list.
456 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
457 if (((*i)->mc)->get_controllable() == c) {
458 (*i)->mc->stop_learning ();
460 (*i)->connection.disconnect();
463 pending_controllables.erase (i);
472 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
475 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
477 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
478 MIDIControllable* existingBinding = (*iter);
480 if (control == (existingBinding->get_controllable())) {
481 delete existingBinding;
482 iter = controllables.erase (iter);
491 // This next function seems unused
493 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
495 if (control != NULL) {
496 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
498 MIDI::channel_t channel = (pos & 0xf);
499 MIDI::byte value = control_number;
501 // Create a MIDIControllable
502 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *control, false);
504 // Remove any old binding for this midi channel/type/value pair
505 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
506 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
507 MIDIControllable* existingBinding = (*iter);
509 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
510 existingBinding->get_control_additional() == value &&
511 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
513 delete existingBinding;
514 iter = controllables.erase (iter);
521 // Update the MIDI Controllable based on the the pos param
522 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
523 mc->bind_midi(channel, MIDI::controller, value);
524 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Create binding: Channel: %1 Controller: %2 Value: %3 \n", channel, MIDI::controller, value));
525 controllables.push_back (mc);
530 GenericMidiControlProtocol::check_used_event (int pos, int control_number)
532 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
534 MIDI::channel_t channel = (pos & 0xf);
535 MIDI::byte value = control_number;
537 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("checking for used event: Channel: %1 Controller: %2 value: %3\n", (int) channel, (pos & 0xf0), (int) value));
539 // Remove any old binding for this midi channel/type/value pair
540 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
541 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
542 MIDIControllable* existingBinding = (*iter);
543 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
544 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
545 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
546 delete existingBinding;
547 iter = controllables.erase (iter);
556 for (MIDIFunctions::iterator iter = functions.begin(); iter != functions.end();) {
557 MIDIFunction* existingBinding = (*iter);
558 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
559 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
560 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
561 delete existingBinding;
562 iter = functions.erase (iter);
571 for (MIDIActions::iterator iter = actions.begin(); iter != actions.end();) {
572 MIDIAction* existingBinding = (*iter);
573 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
574 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
575 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
576 delete existingBinding;
577 iter = actions.erase (iter);
589 GenericMidiControlProtocol::get_state ()
591 XMLNode& node (ControlProtocol::get_state());
593 node.set_property (X_("feedback-interval"), _feedback_interval);
594 node.set_property (X_("threshold"), _threshold);
595 node.set_property (X_("motorized"), _motorised);
597 if (!_current_binding.empty()) {
598 node.set_property ("binding", _current_binding);
601 XMLNode* children = new XMLNode (X_("Controls"));
603 node.add_child_nocopy (*children);
605 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
606 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
608 /* we don't care about bindings that come from a bindings map, because
609 they will all be reset/recreated when we load the relevant bindings
613 if ((*i)->get_controllable() && (*i)->learned()) {
614 children->add_child_nocopy ((*i)->get_state());
622 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
625 XMLNodeConstIterator niter;
627 if (ControlProtocol::set_state (node, version)) {
631 if (!node.get_property ("feedback-interval", _feedback_interval)) {
632 _feedback_interval = 10000;
635 if (!node.get_property ("threshold", _threshold)) {
639 if (!node.get_property ("motorized", _motorised)) {
643 boost::shared_ptr<Controllable> c;
646 Glib::Threads::Mutex::Lock lm (pending_lock);
647 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
648 (*i)->connection.disconnect();
654 pending_controllables.clear ();
658 // midi map has to be loaded first so learned binding can go on top
659 if (node.get_property ("binding", str)) {
660 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
661 if (str == (*x).name) {
662 load_bindings ((*x).path);
668 /* Load up specific bindings from the
669 * <Controls><MidiControllable>...</MidiControllable><Controls> section
672 bool load_dynamic_bindings = false;
673 node.get_property ("session-state", load_dynamic_bindings);
675 if (load_dynamic_bindings) {
676 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
677 nlist = node.children(); // "Controls"
679 if (!nlist.empty()) {
680 nlist = nlist.front()->children(); // "MIDIControllable" ...
682 if (!nlist.empty()) {
683 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
686 if ((*niter)->get_property ("id", id)) {
688 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Relearned binding for session: Control ID: %1\n", id.to_s()));
689 Controllable* c = Controllable::by_id (id);
692 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
694 if (mc->set_state (**niter, version) == 0) {
695 controllables.push_back (mc);
697 warning << string_compose ("Generic MIDI control: Failed to set state for Control ID: %1\n", id.to_s());
702 warning << string_compose (
703 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
704 id.to_s()) << endmsg;
716 GenericMidiControlProtocol::set_feedback (bool yn)
719 last_feedback_time = 0;
724 GenericMidiControlProtocol::get_feedback () const
730 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
732 DEBUG_TRACE (DEBUG::GenericMidi, "Load bindings: Reading midi map\n");
735 if (!state_tree.read (xmlpath.c_str())) {
736 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
740 XMLNode* root = state_tree.root();
742 if (root->name() != X_("ArdourMIDIBindings")) {
743 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
747 const XMLProperty* prop;
749 if ((prop = root->property ("version")) == 0) {
753 const XMLNodeList& children (root->children());
754 XMLNodeConstIterator citer;
755 XMLNodeConstIterator gciter;
757 MIDIControllable* mc;
761 DEBUG_TRACE (DEBUG::GenericMidi, "Loading bindings\n");
762 for (citer = children.begin(); citer != children.end(); ++citer) {
764 if ((*citer)->name() == "DeviceInfo") {
766 if ((*citer)->get_property ("bank-size", _bank_size)) {
770 if (!(*citer)->get_property ("motorized", _motorised)) {
774 if (!(*citer)->get_property ("threshold", _threshold)) {
779 if ((*citer)->name() == "Binding") {
780 const XMLNode* child = *citer;
782 if (child->property ("uri")) {
785 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
786 if ((mc = create_binding (*child)) != 0) {
787 controllables.push_back (mc);
790 } else if (child->property ("function")) {
795 if ((mf = create_function (*child)) != 0) {
796 functions.push_back (mf);
799 } else if (child->property ("action")) {
802 if ((ma = create_action (*child)) != 0) {
803 actions.push_back (ma);
809 if ((prop = root->property ("name")) != 0) {
810 _current_binding = prop->value ();
813 reset_controllables ();
819 GenericMidiControlProtocol::create_binding (const XMLNode& node)
821 const XMLProperty* prop;
823 MIDI::channel_t channel;
828 MIDIControllable::CtlType ctltype;
829 MIDIControllable::Encoder encoder = MIDIControllable::No_enc;
830 bool rpn_value = false;
831 bool nrpn_value = false;
832 bool rpn_change = false;
833 bool nrpn_change = false;
835 if ((prop = node.property (X_("ctl"))) != 0) {
836 ctltype = MIDIControllable::Ctl_Momentary;
837 ev = MIDI::controller;
838 } else if ((prop = node.property (X_("ctl-toggle"))) !=0) {
839 ctltype = MIDIControllable::Ctl_Toggle;
840 ev = MIDI::controller;
841 } else if ((prop = node.property (X_("ctl-dial"))) !=0) {
842 ctltype = MIDIControllable::Ctl_Dial;
843 ev = MIDI::controller;
844 } else if ((prop = node.property (X_("note"))) != 0) {
846 } else if ((prop = node.property (X_("pgm"))) != 0) {
848 } else if ((prop = node.property (X_("pb"))) != 0) {
849 ev = MIDI::pitchbend;
850 } else if ((prop = node.property (X_("enc-l"))) != 0) {
851 encoder = MIDIControllable::Enc_L;
852 ev = MIDI::controller;
853 } else if ((prop = node.property (X_("enc-r"))) != 0) {
854 encoder = MIDIControllable::Enc_R;
855 ev = MIDI::controller;
856 } else if ((prop = node.property (X_("enc-2"))) != 0) {
857 encoder = MIDIControllable::Enc_2;
858 ev = MIDI::controller;
859 } else if ((prop = node.property (X_("enc-b"))) != 0) {
860 encoder = MIDIControllable::Enc_B;
861 ev = MIDI::controller;
862 } else if ((prop = node.property (X_("rpn"))) != 0) {
864 } else if ((prop = node.property (X_("nrpn"))) != 0) {
866 } else if ((prop = node.property (X_("rpn-delta"))) != 0) {
868 } else if ((prop = node.property (X_("nrpn-delta"))) != 0) {
874 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
878 detail = (MIDI::byte) intval;
880 if ((prop = node.property (X_("channel"))) == 0) {
884 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
887 channel = (MIDI::channel_t) intval;
888 /* adjust channel to zero-based counting */
893 if ((prop = node.property (X_("momentary"))) != 0) {
894 momentary = string_to<bool> (prop->value());
899 prop = node.property (X_("uri"));
902 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary);
904 if (mc->init (uri)) {
910 mc->bind_rpn_value (channel, detail);
911 } else if (nrpn_value) {
912 mc->bind_nrpn_value (channel, detail);
913 } else if (rpn_change) {
914 mc->bind_rpn_change (channel, detail);
915 } else if (nrpn_change) {
916 mc->bind_nrpn_change (channel, detail);
918 mc->set_ctltype (ctltype);
919 mc->set_encoder (encoder);
920 mc->bind_midi (channel, ev, detail);
927 GenericMidiControlProtocol::reset_controllables ()
929 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
931 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
932 MIDIControllable* existingBinding = (*iter);
933 MIDIControllables::iterator next = iter;
936 if (!existingBinding->learned()) {
938 /* its entirely possible that the session doesn't have
939 * the specified controllable (e.g. it has too few
940 * tracks). if we find this to be the case, we just leave
941 * the binding around, unbound, and it will do "late
942 * binding" (or "lazy binding") if/when any data arrives.
945 existingBinding->lookup_controllable ();
952 boost::shared_ptr<Controllable>
953 GenericMidiControlProtocol::lookup_controllable (const string & str) const
955 boost::shared_ptr<Controllable> c;
957 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("lookup controllable from \"%1\"\n", str));
960 DEBUG_TRACE (DEBUG::GenericMidi, "no session\n");
964 /* step 1: split string apart */
966 string::size_type first_space = str.find_first_of (" ");
968 if (first_space == string::npos) {
972 string front = str.substr (0, first_space);
974 split (front, path, '/');
976 if (path.size() < 2) {
980 string back = str.substr (first_space);
982 split (back, rest, ' ');
988 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("parsed into path of %1, rest of %1\n", path.size(), rest.size()));
990 /* Step 2: analyse parts of the string to figure out what type of
991 * Stripable we're looking for
1003 static regex_t compiled_pattern;
1004 static bool compiled = false;
1007 const char * const pattern = "^[BS]?[0-9]+";
1008 /* this pattern compilation is not going to fail */
1009 regcomp (&compiled_pattern, pattern, REG_EXTENDED|REG_NOSUB);
1010 /* leak compiled pattern */
1014 /* Step 3: identify what "rest" looks like - name, or simple nueric, or
1015 * banked/selection specifier
1018 bool matched = (regexec (&compiled_pattern, rest[0].c_str(), 0, 0, 0) == 0);
1021 bool banked = false;
1023 if (rest[0][0] == 'B') {
1025 /* already matched digits, so we know atoi() will succeed */
1026 id = atoi (rest[0].substr (1));
1027 type = PresentationOrder;
1028 } else if (rest[0][0] == 'S') {
1029 /* already matched digits, so we know atoi() will succeed */
1030 id = atoi (rest[0].substr (1));
1032 } else if (isdigit (rest[0][0])) {
1033 /* already matched digits, so we know atoi() will succeed */
1034 id = atoi (rest[0]);
1035 type = PresentationOrder;
1040 id -= 1; /* order is zero-based, but maps use 1-based */
1043 id += _current_bank * _bank_size;
1052 /* step 4: find the reference Stripable */
1054 boost::shared_ptr<Stripable> s;
1056 if (path[0] == X_("route") || path[0] == X_("rid")) {
1061 case PresentationOrder:
1062 s = session->get_remote_nth_stripable (id, PresentationInfo::Route);
1068 if (name == "Master" || name == X_("master")) {
1069 s = session->master_out();
1070 } else if (name == X_("control") || name == X_("listen") || name == X_("monitor") || name == "Monitor") {
1071 s = session->monitor_out();
1072 } else if (name == X_("auditioner")) {
1073 s = session->the_auditioner();
1075 s = session->route_by_name (name);
1080 s = session->route_by_selected_count (id);
1084 } else if (path[0] == X_("vca")) {
1086 s = session->get_remote_nth_stripable (id, PresentationInfo::VCA);
1088 } else if (path[0] == X_("bus")) {
1092 s = session->route_by_name (name);
1095 s = session->get_remote_nth_stripable (id, PresentationInfo::Bus);
1098 } else if (path[0] == X_("track")) {
1102 s = session->route_by_name (name);
1105 s = session->get_remote_nth_stripable (id, PresentationInfo::Track);
1110 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("no stripable found for \"%1\"\n", str));
1114 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("found stripable %1\n", s->name()));
1116 /* step 5: find the referenced controllable for that stripable.
1118 * Some controls exist only for Route, so we need that too
1121 boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1123 if (path[1] == X_("gain")) {
1124 c = s->gain_control();
1125 } else if (path[1] == X_("trim")) {
1126 c = s->trim_control ();
1127 } else if (path[1] == X_("solo")) {
1128 c = s->solo_control();
1129 } else if (path[1] == X_("mute")) {
1130 c = s->mute_control();
1131 } else if (path[1] == X_("recenable")) {
1132 c = s->rec_enable_control ();
1133 } else if (path[1] == X_("panwidth")) {
1134 c = s->pan_width_control ();
1135 } else if (path[1] == X_("pandirection") || path[1] == X_("balance")) {
1136 c = s->pan_azimuth_control ();
1137 } else if (path[1] == X_("plugin")) {
1139 /* /route/plugin/parameter */
1141 if (path.size() == 3 && rest.size() == 3) {
1142 if (path[2] == X_("parameter")) {
1144 int plugin = atoi (rest[1]);
1145 int parameter_index = atoi (rest[2]);
1147 /* revert to zero based counting */
1151 if (parameter_index > 0) {
1156 boost::shared_ptr<Processor> proc = r->nth_plugin (plugin);
1159 boost::shared_ptr<PluginInsert> p = boost::dynamic_pointer_cast<PluginInsert> (proc);
1163 param = p->plugin()->nth_parameter (parameter_index, ok);
1165 c = boost::dynamic_pointer_cast<Controllable> (proc->control (Evoral::Parameter (PluginAutomation, 0, param)));
1173 } else if (path[1] == X_("send")) {
1175 if (path.size() == 3 && rest.size() == 2) {
1176 if (path[2] == X_("gain")) {
1177 uint32_t send = atoi (rest[1]);
1181 c = s->send_level_controllable (send);
1182 } else if (path[2] == X_("direction")) {
1183 /* XXX not implemented yet */
1185 } else if (path[2] == X_("enable")) {
1186 /* XXX not implemented yet */
1190 } else if (path[1] == X_("eq")) {
1192 /* /route/eq/enable */
1193 /* /route/eq/gain/<band> */
1194 /* /route/eq/freq/<band> */
1195 /* /route/eq/q/<band> */
1196 /* /route/eq/shape/<band> */
1198 if (path.size() == 3) {
1200 if (path[2] == X_("enable")) {
1201 c = s->eq_enable_controllable ();
1204 } else if (path.size() == 4) {
1206 int band = atoi (path[3]); /* band number */
1208 if (path[2] == X_("gain")) {
1209 c = s->eq_gain_controllable (band);
1210 } else if (path[2] == X_("freq")) {
1211 c = s->eq_freq_controllable (band);
1212 } else if (path[2] == X_("q")) {
1213 c = s->eq_q_controllable (band);
1214 } else if (path[2] == X_("shape")) {
1215 c = s->eq_shape_controllable (band);
1219 } else if (path[1] == X_("filter")) {
1221 /* /route/filter/hi/freq */
1223 if (path.size() == 4) {
1227 if (path[2] == X_("hi")) {
1228 filter = 1; /* high pass filter */
1230 filter = 0; /* low pass filter */
1233 if (path[3] == X_("enable")) {
1234 c = s->filter_enable_controllable (filter);
1235 } else if (path[3] == X_("freq")) {
1236 c = s->filter_freq_controllable (filter);
1237 } else if (path[3] == X_("slope")) {
1238 c = s->filter_slope_controllable (filter);
1243 } else if (path[1] == X_("compressor")) {
1245 if (path.size() == 3) {
1246 if (path[2] == X_("enable")) {
1247 c = s->comp_enable_controllable ();
1248 } else if (path[2] == X_("threshold")) {
1249 c = s->comp_threshold_controllable ();
1250 } else if (path[2] == X_("mode")) {
1251 c = s->comp_mode_controllable ();
1252 } else if (path[2] == X_("speed")) {
1253 c = s->comp_speed_controllable ();
1254 } else if (path[2] == X_("makeup")) {
1255 c = s->comp_makeup_controllable ();
1261 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("found controllable \"%1\"\n", c->name()));
1263 DEBUG_TRACE (DEBUG::GenericMidi, "no controllable found\n");
1270 GenericMidiControlProtocol::create_function (const XMLNode& node)
1272 const XMLProperty* prop;
1274 MIDI::byte detail = 0;
1275 MIDI::channel_t channel = 0;
1278 MIDI::byte* data = 0;
1279 uint32_t data_size = 0;
1282 if ((prop = node.property (X_("ctl"))) != 0) {
1283 ev = MIDI::controller;
1284 } else if ((prop = node.property (X_("note"))) != 0) {
1286 } else if ((prop = node.property (X_("pgm"))) != 0) {
1288 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
1290 if (prop->name() == X_("sysex")) {
1301 stringstream ss (prop->value());
1313 data = new MIDI::byte[cnt];
1317 stringstream ss (prop->value());
1322 data[cnt++] = (MIDI::byte) val;
1327 warning << "Binding ignored - unknown type" << endmsg;
1331 if (data_size == 0) {
1332 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1336 detail = (MIDI::byte) intval;
1338 if ((prop = node.property (X_("channel"))) == 0) {
1342 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1345 channel = (MIDI::channel_t) intval;
1346 /* adjust channel to zero-based counting */
1352 if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
1353 argument = prop->value ();
1356 prop = node.property (X_("function"));
1358 MIDIFunction* mf = new MIDIFunction (*_input_port->parser());
1360 if (mf->setup (*this, prop->value(), argument, data, data_size)) {
1365 mf->bind_midi (channel, ev, detail);
1371 GenericMidiControlProtocol::create_action (const XMLNode& node)
1373 const XMLProperty* prop;
1375 MIDI::byte detail = 0;
1376 MIDI::channel_t channel = 0;
1379 MIDI::byte* data = 0;
1380 uint32_t data_size = 0;
1382 if ((prop = node.property (X_("ctl"))) != 0) {
1383 ev = MIDI::controller;
1384 } else if ((prop = node.property (X_("note"))) != 0) {
1386 } else if ((prop = node.property (X_("pgm"))) != 0) {
1388 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
1390 if (prop->name() == X_("sysex")) {
1401 stringstream ss (prop->value());
1413 data = new MIDI::byte[cnt];
1417 stringstream ss (prop->value());
1422 data[cnt++] = (MIDI::byte) val;
1427 warning << "Binding ignored - unknown type" << endmsg;
1431 if (data_size == 0) {
1432 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1436 detail = (MIDI::byte) intval;
1438 if ((prop = node.property (X_("channel"))) == 0) {
1442 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1445 channel = (MIDI::channel_t) intval;
1446 /* adjust channel to zero-based counting */
1452 prop = node.property (X_("action"));
1454 MIDIAction* ma = new MIDIAction (*_input_port->parser());
1456 if (ma->init (*this, prop->value(), data, data_size)) {
1461 ma->bind_midi (channel, ev, detail);
1467 GenericMidiControlProtocol::set_current_bank (uint32_t b)
1470 reset_controllables ();
1474 GenericMidiControlProtocol::next_bank ()
1477 reset_controllables ();
1481 GenericMidiControlProtocol::prev_bank()
1483 if (_current_bank) {
1485 reset_controllables ();
1490 GenericMidiControlProtocol::set_motorised (bool m)
1496 GenericMidiControlProtocol::set_threshold (int t)
1502 GenericMidiControlProtocol::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
1504 if (!_input_port || !_output_port) {
1508 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
1509 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
1511 if (ni == name1 || ni == name2) {
1513 connection_state |= InputConnected;
1515 connection_state &= ~InputConnected;
1517 } else if (no == name1 || no == name2) {
1519 connection_state |= OutputConnected;
1521 connection_state &= ~OutputConnected;
1528 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
1530 /* XXX this is a horrible hack. Without a short sleep here,
1531 something prevents the device wakeup messages from being
1532 sent and/or the responses from being received.
1542 ConnectionChange (); /* emit signal for our GUI */
1544 return true; /* connection status changed */
1548 GenericMidiControlProtocol::connected ()
1552 boost::shared_ptr<Port>
1553 GenericMidiControlProtocol::output_port() const
1555 return _output_port;
1558 boost::shared_ptr<Port>
1559 GenericMidiControlProtocol::input_port() const
1565 GenericMidiControlProtocol::maybe_start_touch (Controllable* controllable)
1567 AutomationControl *actl = dynamic_cast<AutomationControl*> (controllable);
1569 actl->start_touch (session->audible_sample ());