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.
25 #include <glibmm/fileutils.h>
26 #include <glibmm/miscutils.h>
27 #include <glibmm/thread.h>
29 #include "pbd/controllable_descriptor.h"
30 #include "pbd/error.h"
31 #include "pbd/failed_constructor.h"
32 #include "pbd/pathscanner.h"
33 #include "pbd/xml++.h"
35 #include "midi++/port.h"
36 #include "midi++/manager.h"
38 #include "ardour/filesystem_paths.h"
39 #include "ardour/session.h"
40 #include "ardour/route.h"
41 #include "ardour/midi_ui.h"
42 #include "ardour/rc_configuration.h"
44 #include "generic_midi_control_protocol.h"
45 #include "midicontrollable.h"
46 #include "midifunction.h"
47 #include "midiaction.h"
49 using namespace ARDOUR;
55 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
57 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
58 : ControlProtocol (s, _("Generic MIDI"))
63 _input_port = MIDI::Manager::instance()->midi_input_port ();
64 _output_port = MIDI::Manager::instance()->midi_output_port ();
67 _feedback_interval = 10000; // microseconds
68 last_feedback_time = 0;
73 /* these signals are emitted by the MidiControlUI's event loop thread
74 * and we may as well handle them right there in the same the same
78 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
79 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
80 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
81 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
83 Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
85 /* XXXX SOMETHING GOES WRONG HERE (april 2012) - STILL DEBUGGING */
86 /* this signal is emitted by the process() callback, and if
87 * send_feedback() is going to do anything, it should do it in the
88 * context of the process() callback itself.
91 Session::SendFeedback.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this));
93 /* this one is cross-thread */
95 Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
100 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
106 static const char * const midimap_env_variable_name = "ARDOUR_MIDIMAPS_PATH";
107 static const char* const midi_map_dir_name = "midi_maps";
108 static const char* const midi_map_suffix = ".map";
111 system_midi_map_search_path ()
113 bool midimap_path_defined = false;
114 std::string spath_env (Glib::getenv (midimap_env_variable_name, midimap_path_defined));
116 if (midimap_path_defined) {
120 SearchPath spath (ardour_data_search_path());
121 spath.add_subdirectory_to_paths(midi_map_dir_name);
123 // just return the first directory in the search path that exists
124 for (SearchPath::const_iterator i = spath.begin(); i != spath.end(); ++i) {
125 if (Glib::file_test (*i, Glib::FILE_TEST_EXISTS)) {
129 return std::string();
133 user_midi_map_directory ()
135 return Glib::build_filename (user_config_directory(), midi_map_dir_name);
139 midi_map_filter (const string &str, void */*arg*/)
141 return (str.length() > strlen(midi_map_suffix) &&
142 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
146 GenericMidiControlProtocol::reload_maps ()
148 vector<string *> *midi_maps;
150 SearchPath spath (system_midi_map_search_path());
151 spath += user_midi_map_directory ();
153 midi_maps = scanner (spath.to_string(), midi_map_filter, 0, false, true);
156 cerr << "No MIDI maps found using " << spath.to_string() << endl;
160 for (vector<string*>::iterator i = midi_maps->begin(); i != midi_maps->end(); ++i) {
161 string fullpath = *(*i);
165 if (!tree.read (fullpath.c_str())) {
171 XMLProperty* prop = tree.root()->property ("name");
177 mi.name = prop->value ();
180 map_info.push_back (mi);
187 GenericMidiControlProtocol::drop_all ()
189 Glib::Mutex::Lock lm (pending_lock);
190 Glib::Mutex::Lock lm2 (controllables_lock);
192 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
195 controllables.clear ();
197 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
200 pending_controllables.clear ();
202 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
207 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
214 GenericMidiControlProtocol::drop_bindings ()
216 Glib::Mutex::Lock lm2 (controllables_lock);
218 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
219 if (!(*i)->learned()) {
221 i = controllables.erase (i);
227 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
232 _current_binding = "";
238 GenericMidiControlProtocol::set_active (bool /*yn*/)
240 /* start/stop delivery/outbound thread */
245 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
247 _feedback_interval = ms;
251 GenericMidiControlProtocol::send_feedback ()
253 /* This is executed in RT "process" context", so no blocking calls
260 microseconds_t now = get_microseconds ();
262 if (last_feedback_time != 0) {
263 if ((now - last_feedback_time) < _feedback_interval) {
270 last_feedback_time = now;
274 GenericMidiControlProtocol::_send_feedback ()
276 /* This is executed in RT "process" context", so no blocking calls
279 const int32_t bufsize = 16 * 1024; /* XXX too big */
280 MIDI::byte buf[bufsize];
281 int32_t bsize = bufsize;
283 /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
284 writes for each controllable here; if we send more than one MIDI message
285 in a single jack_midi_event_write then some bridges will only pass the
289 Glib::Mutex::Lock lm (controllables_lock, Glib::TRY_LOCK);
294 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
295 MIDI::byte* end = (*r)->write_feedback (buf, bsize);
297 _output_port->write (buf, (int32_t) (end - buf), 0);
303 GenericMidiControlProtocol::start_learning (Controllable* c)
309 Glib::Mutex::Lock lm2 (controllables_lock);
311 MIDIControllables::iterator tmp;
312 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
315 if ((*i)->get_controllable() == c) {
317 controllables.erase (i);
323 Glib::Mutex::Lock lm (pending_lock);
325 MIDIPendingControllables::iterator ptmp;
326 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
329 if (((*i)->first)->get_controllable() == c) {
330 (*i)->second.disconnect();
333 pending_controllables.erase (i);
339 MIDIControllable* mc = 0;
341 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
342 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
349 mc = new MIDIControllable (this, *_input_port, *c, false);
353 Glib::Mutex::Lock lm (pending_lock);
355 MIDIPendingControllable* element = new MIDIPendingControllable;
357 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
359 pending_controllables.push_back (element);
362 mc->learn_about_external_control ();
367 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
369 Glib::Mutex::Lock lm (pending_lock);
370 Glib::Mutex::Lock lm2 (controllables_lock);
372 MIDIPendingControllables::iterator tmp;
374 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
378 if ( (*i)->first == mc) {
379 (*i)->second.disconnect();
381 pending_controllables.erase(i);
387 controllables.push_back (mc);
391 GenericMidiControlProtocol::stop_learning (Controllable* c)
393 Glib::Mutex::Lock lm (pending_lock);
394 Glib::Mutex::Lock lm2 (controllables_lock);
395 MIDIControllable* dptr = 0;
397 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
398 relevant MIDIControllable and remove it from the pending list.
401 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
402 if (((*i)->first)->get_controllable() == c) {
403 (*i)->first->stop_learning ();
405 (*i)->second.disconnect();
408 pending_controllables.erase (i);
417 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
420 Glib::Mutex::Lock lm2 (controllables_lock);
422 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
423 MIDIControllable* existingBinding = (*iter);
425 if (control == (existingBinding->get_controllable())) {
426 delete existingBinding;
427 iter = controllables.erase (iter);
437 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
439 if (control != NULL) {
440 Glib::Mutex::Lock lm2 (controllables_lock);
442 MIDI::channel_t channel = (pos & 0xf);
443 MIDI::byte value = control_number;
445 // Create a MIDIControllable
446 MIDIControllable* mc = new MIDIControllable (this, *_input_port, *control, false);
448 // Remove any old binding for this midi channel/type/value pair
449 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
450 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
451 MIDIControllable* existingBinding = (*iter);
453 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
454 existingBinding->get_control_additional() == value &&
455 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
457 delete existingBinding;
458 iter = controllables.erase (iter);
465 // Update the MIDI Controllable based on the the pos param
466 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
467 mc->bind_midi(channel, MIDI::controller, value);
469 controllables.push_back (mc);
474 GenericMidiControlProtocol::get_state ()
476 XMLNode* node = new XMLNode ("Protocol");
479 node->add_property (X_("name"), _name);
480 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
481 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
482 node->add_property (X_("feedback_interval"), buf);
484 if (!_current_binding.empty()) {
485 node->add_property ("binding", _current_binding);
488 XMLNode* children = new XMLNode (X_("Controls"));
490 node->add_child_nocopy (*children);
492 Glib::Mutex::Lock lm2 (controllables_lock);
493 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
495 /* we don't care about bindings that come from a bindings map, because
496 they will all be reset/recreated when we load the relevant bindings
500 if ((*i)->learned()) {
501 children->add_child_nocopy ((*i)->get_state());
509 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
512 XMLNodeConstIterator niter;
513 const XMLProperty* prop;
515 if ((prop = node.property ("feedback")) != 0) {
516 do_feedback = (bool) atoi (prop->value().c_str());
521 if ((prop = node.property ("feedback_interval")) != 0) {
522 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
523 _feedback_interval = 10000;
526 _feedback_interval = 10000;
529 boost::shared_ptr<Controllable> c;
532 Glib::Mutex::Lock lm (pending_lock);
533 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
536 pending_controllables.clear ();
540 Glib::Mutex::Lock lm2 (controllables_lock);
541 controllables.clear ();
542 nlist = node.children(); // "Controls"
548 nlist = nlist.front()->children ();
550 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
552 if ((prop = (*niter)->property ("id")) != 0) {
554 ID id = prop->value ();
555 Controllable* c = Controllable::by_id (id);
558 MIDIControllable* mc = new MIDIControllable (this, *_input_port, *c, false);
560 if (mc->set_state (**niter, version) == 0) {
561 controllables.push_back (mc);
565 warning << string_compose (
566 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
574 if ((prop = node.property ("binding")) != 0) {
575 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
576 if (prop->value() == (*x).name) {
577 load_bindings ((*x).path);
587 GenericMidiControlProtocol::set_feedback (bool yn)
590 last_feedback_time = 0;
595 GenericMidiControlProtocol::get_feedback () const
601 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
605 if (!state_tree.read (xmlpath.c_str())) {
606 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
610 XMLNode* root = state_tree.root();
612 if (root->name() != X_("ArdourMIDIBindings")) {
613 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
617 const XMLProperty* prop;
619 if ((prop = root->property ("version")) == 0) {
626 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
627 Stateful::loading_state_version = (major * 1000) + minor;
630 const XMLNodeList& children (root->children());
631 XMLNodeConstIterator citer;
632 XMLNodeConstIterator gciter;
634 MIDIControllable* mc;
638 for (citer = children.begin(); citer != children.end(); ++citer) {
640 if ((*citer)->name() == "DeviceInfo") {
641 const XMLProperty* prop;
643 if ((prop = (*citer)->property ("bank-size")) != 0) {
644 _bank_size = atoi (prop->value());
648 if ((prop = (*citer)->property ("motorised")) != 0 || ((prop = (*citer)->property ("motorized")) != 0)) {
649 _motorised = string_is_affirmative (prop->value ());
654 if ((prop = (*citer)->property ("threshold")) != 0) {
655 _threshold = atoi (prop->value ());
662 if ((*citer)->name() == "Binding") {
663 const XMLNode* child = *citer;
665 if (child->property ("uri")) {
668 if ((mc = create_binding (*child)) != 0) {
669 Glib::Mutex::Lock lm2 (controllables_lock);
670 controllables.push_back (mc);
673 } else if (child->property ("function")) {
678 if ((mf = create_function (*child)) != 0) {
679 functions.push_back (mf);
682 } else if (child->property ("action")) {
685 if ((ma = create_action (*child)) != 0) {
686 actions.push_back (ma);
692 if ((prop = root->property ("name")) != 0) {
693 _current_binding = prop->value ();
696 reset_controllables ();
702 GenericMidiControlProtocol::create_binding (const XMLNode& node)
704 const XMLProperty* prop;
706 MIDI::channel_t channel;
712 if ((prop = node.property (X_("ctl"))) != 0) {
713 ev = MIDI::controller;
714 } else if ((prop = node.property (X_("note"))) != 0) {
716 } else if ((prop = node.property (X_("pgm"))) != 0) {
718 } else if ((prop = node.property (X_("pb"))) != 0) {
719 ev = MIDI::pitchbend;
724 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
728 detail = (MIDI::byte) intval;
730 if ((prop = node.property (X_("channel"))) == 0) {
734 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
737 channel = (MIDI::channel_t) intval;
738 /* adjust channel to zero-based counting */
743 if ((prop = node.property (X_("momentary"))) != 0) {
744 momentary = string_is_affirmative (prop->value());
749 prop = node.property (X_("uri"));
752 MIDIControllable* mc = new MIDIControllable (this, *_input_port, momentary);
754 if (mc->init (uri)) {
759 mc->bind_midi (channel, ev, detail);
765 GenericMidiControlProtocol::reset_controllables ()
767 Glib::Mutex::Lock lm2 (controllables_lock);
769 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
770 MIDIControllable* existingBinding = (*iter);
771 MIDIControllables::iterator next = iter;
774 if (!existingBinding->learned()) {
775 ControllableDescriptor& desc (existingBinding->descriptor());
778 desc.set_bank_offset (_current_bank * _bank_size);
781 /* its entirely possible that the session doesn't have
782 * the specified controllable (e.g. it has too few
783 * tracks). if we find this to be the case, we just leave
784 * the binding around, unbound, and it will do "late
785 * binding" (or "lazy binding") if/when any data arrives.
788 existingBinding->lookup_controllable ();
795 boost::shared_ptr<Controllable>
796 GenericMidiControlProtocol::lookup_controllable (const ControllableDescriptor& desc) const
798 return session->controllable_by_descriptor (desc);
802 GenericMidiControlProtocol::create_function (const XMLNode& node)
804 const XMLProperty* prop;
806 MIDI::byte detail = 0;
807 MIDI::channel_t channel = 0;
810 MIDI::byte* data = 0;
811 uint32_t data_size = 0;
814 if ((prop = node.property (X_("ctl"))) != 0) {
815 ev = MIDI::controller;
816 } else if ((prop = node.property (X_("note"))) != 0) {
818 } else if ((prop = node.property (X_("pgm"))) != 0) {
820 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
822 if (prop->name() == X_("sysex")) {
833 stringstream ss (prop->value());
845 data = new MIDI::byte[cnt];
849 stringstream ss (prop->value());
854 data[cnt++] = (MIDI::byte) val;
859 warning << "Binding ignored - unknown type" << endmsg;
863 if (data_size == 0) {
864 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
868 detail = (MIDI::byte) intval;
870 if ((prop = node.property (X_("channel"))) == 0) {
874 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
877 channel = (MIDI::channel_t) intval;
878 /* adjust channel to zero-based counting */
884 if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
885 argument = prop->value ();
888 prop = node.property (X_("function"));
890 MIDIFunction* mf = new MIDIFunction (*_input_port);
892 if (mf->setup (*this, prop->value(), argument, data, data_size)) {
897 mf->bind_midi (channel, ev, detail);
903 GenericMidiControlProtocol::create_action (const XMLNode& node)
905 const XMLProperty* prop;
907 MIDI::byte detail = 0;
908 MIDI::channel_t channel = 0;
911 MIDI::byte* data = 0;
912 uint32_t data_size = 0;
914 if ((prop = node.property (X_("ctl"))) != 0) {
915 ev = MIDI::controller;
916 } else if ((prop = node.property (X_("note"))) != 0) {
918 } else if ((prop = node.property (X_("pgm"))) != 0) {
920 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
922 if (prop->name() == X_("sysex")) {
933 stringstream ss (prop->value());
945 data = new MIDI::byte[cnt];
949 stringstream ss (prop->value());
954 data[cnt++] = (MIDI::byte) val;
959 warning << "Binding ignored - unknown type" << endmsg;
963 if (data_size == 0) {
964 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
968 detail = (MIDI::byte) intval;
970 if ((prop = node.property (X_("channel"))) == 0) {
974 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
977 channel = (MIDI::channel_t) intval;
978 /* adjust channel to zero-based counting */
984 prop = node.property (X_("action"));
986 MIDIAction* ma = new MIDIAction (*_input_port);
988 if (ma->init (*this, prop->value(), data, data_size)) {
993 ma->bind_midi (channel, ev, detail);
999 GenericMidiControlProtocol::set_current_bank (uint32_t b)
1002 reset_controllables ();
1006 GenericMidiControlProtocol::next_bank ()
1009 reset_controllables ();
1013 GenericMidiControlProtocol::prev_bank()
1015 if (_current_bank) {
1017 reset_controllables ();
1022 GenericMidiControlProtocol::set_motorised (bool m)
1028 GenericMidiControlProtocol::set_threshold (int t)