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>
28 #include "pbd/controllable_descriptor.h"
29 #include "pbd/error.h"
30 #include "pbd/failed_constructor.h"
31 #include "pbd/pathscanner.h"
32 #include "pbd/xml++.h"
34 #include "midi++/port.h"
35 #include "midi++/manager.h"
37 #include "ardour/filesystem_paths.h"
38 #include "ardour/session.h"
39 #include "ardour/route.h"
40 #include "ardour/midi_ui.h"
41 #include "ardour/rc_configuration.h"
43 #include "generic_midi_control_protocol.h"
44 #include "midicontrollable.h"
45 #include "midifunction.h"
46 #include "midiaction.h"
48 using namespace ARDOUR;
54 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
56 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
57 : ControlProtocol (s, _("Generic MIDI"))
62 _input_port = MIDI::Manager::instance()->midi_input_port ();
63 _output_port = MIDI::Manager::instance()->midi_output_port ();
66 _feedback_interval = 10000; // microseconds
67 last_feedback_time = 0;
72 /* these signals are emitted by the MidiControlUI's event loop thread
73 * and we may as well handle them right there in the same the same
77 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
78 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
79 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
80 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
82 Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
84 /* XXXX SOMETHING GOES WRONG HERE (april 2012) - STILL DEBUGGING */
85 /* this signal is emitted by the process() callback, and if
86 * send_feedback() is going to do anything, it should do it in the
87 * context of the process() callback itself.
90 Session::SendFeedback.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this));
92 /* this one is cross-thread */
94 Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
99 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
105 static const char * const midimap_env_variable_name = "ARDOUR_MIDIMAPS_PATH";
106 static const char* const midi_map_dir_name = "midi_maps";
107 static const char* const midi_map_suffix = ".map";
110 system_midi_map_search_path ()
112 bool midimap_path_defined = false;
113 std::string spath_env (Glib::getenv (midimap_env_variable_name, midimap_path_defined));
115 if (midimap_path_defined) {
119 SearchPath spath (ardour_data_search_path());
120 spath.add_subdirectory_to_paths(midi_map_dir_name);
122 // just return the first directory in the search path that exists
123 for (SearchPath::const_iterator i = spath.begin(); i != spath.end(); ++i) {
124 if (Glib::file_test (*i, Glib::FILE_TEST_EXISTS)) {
128 return std::string();
132 user_midi_map_directory ()
134 return Glib::build_filename (user_config_directory(), midi_map_dir_name);
138 midi_map_filter (const string &str, void */*arg*/)
140 return (str.length() > strlen(midi_map_suffix) &&
141 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
145 GenericMidiControlProtocol::reload_maps ()
147 vector<string *> *midi_maps;
149 SearchPath spath (system_midi_map_search_path());
150 spath += user_midi_map_directory ();
152 midi_maps = scanner (spath.to_string(), midi_map_filter, 0, false, true);
155 cerr << "No MIDI maps found using " << spath.to_string() << endl;
159 for (vector<string*>::iterator i = midi_maps->begin(); i != midi_maps->end(); ++i) {
160 string fullpath = *(*i);
164 if (!tree.read (fullpath.c_str())) {
170 XMLProperty* prop = tree.root()->property ("name");
176 mi.name = prop->value ();
179 map_info.push_back (mi);
186 GenericMidiControlProtocol::drop_all ()
188 Glib::Mutex::Lock lm (pending_lock);
189 Glib::Mutex::Lock lm2 (controllables_lock);
191 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
194 controllables.clear ();
196 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
199 pending_controllables.clear ();
201 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
206 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
213 GenericMidiControlProtocol::drop_bindings ()
215 Glib::Mutex::Lock lm2 (controllables_lock);
217 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
218 if (!(*i)->learned()) {
220 i = controllables.erase (i);
226 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
231 _current_binding = "";
237 GenericMidiControlProtocol::set_active (bool /*yn*/)
239 /* start/stop delivery/outbound thread */
244 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
246 _feedback_interval = ms;
250 GenericMidiControlProtocol::send_feedback ()
252 /* This is executed in RT "process" context", so no blocking calls
259 microseconds_t now = get_microseconds ();
261 if (last_feedback_time != 0) {
262 if ((now - last_feedback_time) < _feedback_interval) {
269 last_feedback_time = now;
273 GenericMidiControlProtocol::_send_feedback ()
275 /* This is executed in RT "process" context", so no blocking calls
278 const int32_t bufsize = 16 * 1024; /* XXX too big */
279 MIDI::byte buf[bufsize];
280 int32_t bsize = bufsize;
282 /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
283 writes for each controllable here; if we send more than one MIDI message
284 in a single jack_midi_event_write then some bridges will only pass the
287 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
288 MIDI::byte* end = (*r)->write_feedback (buf, bsize);
290 _output_port->write (buf, (int32_t) (end - buf), 0);
296 GenericMidiControlProtocol::start_learning (Controllable* c)
302 Glib::Mutex::Lock lm2 (controllables_lock);
304 MIDIControllables::iterator tmp;
305 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
308 if ((*i)->get_controllable() == c) {
310 controllables.erase (i);
316 Glib::Mutex::Lock lm (pending_lock);
318 MIDIPendingControllables::iterator ptmp;
319 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
322 if (((*i)->first)->get_controllable() == c) {
323 (*i)->second.disconnect();
326 pending_controllables.erase (i);
332 MIDIControllable* mc = 0;
334 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
335 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
342 mc = new MIDIControllable (this, *_input_port, *c, false);
346 Glib::Mutex::Lock lm (pending_lock);
348 MIDIPendingControllable* element = new MIDIPendingControllable;
350 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
352 pending_controllables.push_back (element);
355 mc->learn_about_external_control ();
360 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
362 Glib::Mutex::Lock lm (pending_lock);
363 Glib::Mutex::Lock lm2 (controllables_lock);
365 MIDIPendingControllables::iterator tmp;
367 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
371 if ( (*i)->first == mc) {
372 (*i)->second.disconnect();
374 pending_controllables.erase(i);
380 controllables.push_back (mc);
384 GenericMidiControlProtocol::stop_learning (Controllable* c)
386 Glib::Mutex::Lock lm (pending_lock);
387 Glib::Mutex::Lock lm2 (controllables_lock);
388 MIDIControllable* dptr = 0;
390 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
391 relevant MIDIControllable and remove it from the pending list.
394 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
395 if (((*i)->first)->get_controllable() == c) {
396 (*i)->first->stop_learning ();
398 (*i)->second.disconnect();
401 pending_controllables.erase (i);
410 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
413 Glib::Mutex::Lock lm2 (controllables_lock);
415 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
416 MIDIControllable* existingBinding = (*iter);
418 if (control == (existingBinding->get_controllable())) {
419 delete existingBinding;
420 iter = controllables.erase (iter);
430 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
432 if (control != NULL) {
433 Glib::Mutex::Lock lm2 (controllables_lock);
435 MIDI::channel_t channel = (pos & 0xf);
436 MIDI::byte value = control_number;
438 // Create a MIDIControllable
439 MIDIControllable* mc = new MIDIControllable (this, *_input_port, *control, false);
441 // Remove any old binding for this midi channel/type/value pair
442 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
443 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
444 MIDIControllable* existingBinding = (*iter);
446 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
447 existingBinding->get_control_additional() == value &&
448 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
450 delete existingBinding;
451 iter = controllables.erase (iter);
458 // Update the MIDI Controllable based on the the pos param
459 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
460 mc->bind_midi(channel, MIDI::controller, value);
462 controllables.push_back (mc);
467 GenericMidiControlProtocol::get_state ()
469 XMLNode* node = new XMLNode ("Protocol");
472 node->add_property (X_("name"), _name);
473 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
474 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
475 node->add_property (X_("feedback_interval"), buf);
477 if (!_current_binding.empty()) {
478 node->add_property ("binding", _current_binding);
481 XMLNode* children = new XMLNode (X_("Controls"));
483 node->add_child_nocopy (*children);
485 Glib::Mutex::Lock lm2 (controllables_lock);
486 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
488 /* we don't care about bindings that come from a bindings map, because
489 they will all be reset/recreated when we load the relevant bindings
493 if ((*i)->learned()) {
494 children->add_child_nocopy ((*i)->get_state());
502 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
505 XMLNodeConstIterator niter;
506 const XMLProperty* prop;
508 if ((prop = node.property ("feedback")) != 0) {
509 do_feedback = (bool) atoi (prop->value().c_str());
514 if ((prop = node.property ("feedback_interval")) != 0) {
515 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
516 _feedback_interval = 10000;
519 _feedback_interval = 10000;
522 boost::shared_ptr<Controllable> c;
525 Glib::Mutex::Lock lm (pending_lock);
526 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
529 pending_controllables.clear ();
533 Glib::Mutex::Lock lm2 (controllables_lock);
534 controllables.clear ();
535 nlist = node.children(); // "Controls"
541 nlist = nlist.front()->children ();
543 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
545 if ((prop = (*niter)->property ("id")) != 0) {
547 ID id = prop->value ();
548 Controllable* c = Controllable::by_id (id);
551 MIDIControllable* mc = new MIDIControllable (this, *_input_port, *c, false);
553 if (mc->set_state (**niter, version) == 0) {
554 controllables.push_back (mc);
558 warning << string_compose (
559 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
567 if ((prop = node.property ("binding")) != 0) {
568 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
569 if (prop->value() == (*x).name) {
570 load_bindings ((*x).path);
580 GenericMidiControlProtocol::set_feedback (bool yn)
583 last_feedback_time = 0;
588 GenericMidiControlProtocol::get_feedback () const
594 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
598 if (!state_tree.read (xmlpath.c_str())) {
599 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
603 XMLNode* root = state_tree.root();
605 if (root->name() != X_("ArdourMIDIBindings")) {
606 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
610 const XMLProperty* prop;
612 if ((prop = root->property ("version")) == 0) {
619 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
620 Stateful::loading_state_version = (major * 1000) + minor;
623 const XMLNodeList& children (root->children());
624 XMLNodeConstIterator citer;
625 XMLNodeConstIterator gciter;
627 MIDIControllable* mc;
631 for (citer = children.begin(); citer != children.end(); ++citer) {
633 if ((*citer)->name() == "DeviceInfo") {
634 const XMLProperty* prop;
636 if ((prop = (*citer)->property ("bank-size")) != 0) {
637 _bank_size = atoi (prop->value());
641 if ((prop = (*citer)->property ("motorised")) != 0) {
642 _motorised = string_is_affirmative (prop->value ());
647 if ((prop = (*citer)->property ("threshold")) != 0) {
648 _threshold = atoi (prop->value ());
655 if ((*citer)->name() == "Binding") {
656 const XMLNode* child = *citer;
658 if (child->property ("uri")) {
661 if ((mc = create_binding (*child)) != 0) {
662 Glib::Mutex::Lock lm2 (controllables_lock);
663 controllables.push_back (mc);
666 } else if (child->property ("function")) {
671 if ((mf = create_function (*child)) != 0) {
672 functions.push_back (mf);
675 } else if (child->property ("action")) {
678 if ((ma = create_action (*child)) != 0) {
679 actions.push_back (ma);
685 if ((prop = root->property ("name")) != 0) {
686 _current_binding = prop->value ();
689 reset_controllables ();
695 GenericMidiControlProtocol::create_binding (const XMLNode& node)
697 const XMLProperty* prop;
699 MIDI::channel_t channel;
705 if ((prop = node.property (X_("ctl"))) != 0) {
706 ev = MIDI::controller;
707 } else if ((prop = node.property (X_("note"))) != 0) {
709 } else if ((prop = node.property (X_("pgm"))) != 0) {
711 } else if ((prop = node.property (X_("pb"))) != 0) {
712 ev = MIDI::pitchbend;
717 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
721 detail = (MIDI::byte) intval;
723 if ((prop = node.property (X_("channel"))) == 0) {
727 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
730 channel = (MIDI::channel_t) intval;
731 /* adjust channel to zero-based counting */
736 if ((prop = node.property (X_("momentary"))) != 0) {
737 momentary = string_is_affirmative (prop->value());
742 prop = node.property (X_("uri"));
745 MIDIControllable* mc = new MIDIControllable (this, *_input_port, momentary);
747 if (mc->init (uri)) {
752 mc->bind_midi (channel, ev, detail);
758 GenericMidiControlProtocol::reset_controllables ()
760 Glib::Mutex::Lock lm2 (controllables_lock);
762 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
763 MIDIControllable* existingBinding = (*iter);
764 MIDIControllables::iterator next = iter;
767 if (!existingBinding->learned()) {
768 ControllableDescriptor& desc (existingBinding->descriptor());
771 desc.set_bank_offset (_current_bank * _bank_size);
774 /* its entirely possible that the session doesn't have
775 * the specified controllable (e.g. it has too few
776 * tracks). if we find this to be the case, we just leave
777 * the binding around, unbound, and it will do "late
778 * binding" (or "lazy binding") if/when any data arrives.
781 boost::shared_ptr<Controllable> c = session->controllable_by_descriptor (desc);
783 existingBinding->set_controllable (c.get());
791 boost::shared_ptr<Controllable>
792 GenericMidiControlProtocol::lookup_controllable (const ControllableDescriptor& desc) const
794 return session->controllable_by_descriptor (desc);
798 GenericMidiControlProtocol::create_function (const XMLNode& node)
800 const XMLProperty* prop;
802 MIDI::byte detail = 0;
803 MIDI::channel_t channel = 0;
806 MIDI::byte* data = 0;
807 uint32_t data_size = 0;
810 if ((prop = node.property (X_("ctl"))) != 0) {
811 ev = MIDI::controller;
812 } else if ((prop = node.property (X_("note"))) != 0) {
814 } else if ((prop = node.property (X_("pgm"))) != 0) {
816 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
818 if (prop->name() == X_("sysex")) {
829 stringstream ss (prop->value());
841 data = new MIDI::byte[cnt];
845 stringstream ss (prop->value());
850 data[cnt++] = (MIDI::byte) val;
855 warning << "Binding ignored - unknown type" << endmsg;
859 if (data_size == 0) {
860 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
864 detail = (MIDI::byte) intval;
866 if ((prop = node.property (X_("channel"))) == 0) {
870 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
873 channel = (MIDI::channel_t) intval;
874 /* adjust channel to zero-based counting */
880 if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
881 argument = prop->value ();
884 prop = node.property (X_("function"));
886 MIDIFunction* mf = new MIDIFunction (*_input_port);
888 if (mf->setup (*this, prop->value(), argument, data, data_size)) {
893 mf->bind_midi (channel, ev, detail);
899 GenericMidiControlProtocol::create_action (const XMLNode& node)
901 const XMLProperty* prop;
903 MIDI::byte detail = 0;
904 MIDI::channel_t channel = 0;
907 MIDI::byte* data = 0;
908 uint32_t data_size = 0;
910 if ((prop = node.property (X_("ctl"))) != 0) {
911 ev = MIDI::controller;
912 } else if ((prop = node.property (X_("note"))) != 0) {
914 } else if ((prop = node.property (X_("pgm"))) != 0) {
916 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
918 if (prop->name() == X_("sysex")) {
929 stringstream ss (prop->value());
941 data = new MIDI::byte[cnt];
945 stringstream ss (prop->value());
950 data[cnt++] = (MIDI::byte) val;
955 warning << "Binding ignored - unknown type" << endmsg;
959 if (data_size == 0) {
960 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
964 detail = (MIDI::byte) intval;
966 if ((prop = node.property (X_("channel"))) == 0) {
970 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
973 channel = (MIDI::channel_t) intval;
974 /* adjust channel to zero-based counting */
980 prop = node.property (X_("action"));
982 MIDIAction* ma = new MIDIAction (*_input_port);
984 if (ma->init (*this, prop->value(), data, data_size)) {
989 ma->bind_midi (channel, ev, detail);
995 GenericMidiControlProtocol::set_current_bank (uint32_t b)
998 reset_controllables ();
1002 GenericMidiControlProtocol::next_bank ()
1005 reset_controllables ();
1009 GenericMidiControlProtocol::prev_bank()
1011 if (_current_bank) {
1013 reset_controllables ();
1018 GenericMidiControlProtocol::set_motorised (bool m)
1024 GenericMidiControlProtocol::set_threshold (int t)