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/miscutils.h>
27 #include "pbd/controllable_descriptor.h"
28 #include "pbd/error.h"
29 #include "pbd/failed_constructor.h"
30 #include "pbd/pathscanner.h"
31 #include "pbd/xml++.h"
33 #include "midi++/port.h"
34 #include "midi++/manager.h"
36 #include "ardour/filesystem_paths.h"
37 #include "ardour/session.h"
38 #include "ardour/route.h"
39 #include "ardour/midi_ui.h"
40 #include "ardour/rc_configuration.h"
42 #include "generic_midi_control_protocol.h"
43 #include "midicontrollable.h"
44 #include "midifunction.h"
45 #include "midiaction.h"
47 using namespace ARDOUR;
53 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
54 #define ui_bind(x) boost::protect (boost::bind ((x)))
56 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
57 : ControlProtocol (s, _("Generic MIDI"))
61 _input_port = MIDI::Manager::instance()->midi_input_port ();
62 _output_port = MIDI::Manager::instance()->midi_output_port ();
65 _feedback_interval = 10000; // microseconds
66 last_feedback_time = 0;
71 /* XXX is it right to do all these in the same thread as whatever emits the signal? */
73 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
74 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
75 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
76 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
78 Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
79 Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
84 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
90 static const char * const midimap_env_variable_name = "ARDOUR_MIDIMAPS_PATH";
91 static const char* const midi_map_dir_name = "midi_maps";
92 static const char* const midi_map_suffix = ".map";
95 system_midi_map_search_path ()
97 bool midimap_path_defined = false;
98 sys::path spath_env (Glib::getenv (midimap_env_variable_name, midimap_path_defined));
100 if (midimap_path_defined) {
104 SearchPath spath (system_data_search_path());
105 spath.add_subdirectory_to_paths(midi_map_dir_name);
107 // just return the first directory in the search path that exists
108 SearchPath::const_iterator i = std::find_if(spath.begin(), spath.end(), sys::exists);
110 if (i == spath.end()) return sys::path();
116 user_midi_map_directory ()
118 sys::path p(user_config_directory());
119 p /= midi_map_dir_name;
125 midi_map_filter (const string &str, void */*arg*/)
127 return (str.length() > strlen(midi_map_suffix) &&
128 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
132 GenericMidiControlProtocol::reload_maps ()
134 vector<string *> *midi_maps;
136 SearchPath spath (system_midi_map_search_path());
137 spath += user_midi_map_directory ();
139 midi_maps = scanner (spath.to_string(), midi_map_filter, 0, false, true);
142 cerr << "No MIDI maps found using " << spath.to_string() << endl;
146 for (vector<string*>::iterator i = midi_maps->begin(); i != midi_maps->end(); ++i) {
147 string fullpath = *(*i);
151 if (!tree.read (fullpath.c_str())) {
157 XMLProperty* prop = tree.root()->property ("name");
163 mi.name = prop->value ();
166 map_info.push_back (mi);
173 GenericMidiControlProtocol::drop_all ()
175 Glib::Mutex::Lock lm (pending_lock);
176 Glib::Mutex::Lock lm2 (controllables_lock);
178 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
181 controllables.clear ();
183 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
186 pending_controllables.clear ();
188 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
193 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
200 GenericMidiControlProtocol::drop_bindings ()
202 Glib::Mutex::Lock lm2 (controllables_lock);
204 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
205 if (!(*i)->learned()) {
207 i = controllables.erase (i);
213 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
218 _current_binding = "";
224 GenericMidiControlProtocol::set_active (bool /*yn*/)
226 /* start/stop delivery/outbound thread */
231 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
233 _feedback_interval = ms;
237 GenericMidiControlProtocol::send_feedback ()
243 microseconds_t now = get_microseconds ();
245 if (last_feedback_time != 0) {
246 if ((now - last_feedback_time) < _feedback_interval) {
253 last_feedback_time = now;
257 GenericMidiControlProtocol::_send_feedback ()
259 const int32_t bufsize = 16 * 1024; /* XXX too big */
260 MIDI::byte buf[bufsize];
261 int32_t bsize = bufsize;
263 /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
264 writes for each controllable here; if we send more than one MIDI message
265 in a single jack_midi_event_write then some bridges will only pass the
268 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
269 MIDI::byte* end = (*r)->write_feedback (buf, bsize);
271 _output_port->write (buf, (int32_t) (end - buf), 0);
277 GenericMidiControlProtocol::start_learning (Controllable* c)
283 Glib::Mutex::Lock lm2 (controllables_lock);
285 MIDIControllables::iterator tmp;
286 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
289 if ((*i)->get_controllable() == c) {
291 controllables.erase (i);
297 Glib::Mutex::Lock lm (pending_lock);
299 MIDIPendingControllables::iterator ptmp;
300 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
303 if (((*i)->first)->get_controllable() == c) {
304 (*i)->second.disconnect();
307 pending_controllables.erase (i);
313 MIDIControllable* mc = 0;
315 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
316 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
323 mc = new MIDIControllable (this, *_input_port, *c, false);
327 Glib::Mutex::Lock lm (pending_lock);
329 MIDIPendingControllable* element = new MIDIPendingControllable;
331 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
333 pending_controllables.push_back (element);
336 mc->learn_about_external_control ();
341 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
343 Glib::Mutex::Lock lm (pending_lock);
344 Glib::Mutex::Lock lm2 (controllables_lock);
346 MIDIPendingControllables::iterator tmp;
348 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
352 if ( (*i)->first == mc) {
353 (*i)->second.disconnect();
355 pending_controllables.erase(i);
361 controllables.push_back (mc);
365 GenericMidiControlProtocol::stop_learning (Controllable* c)
367 Glib::Mutex::Lock lm (pending_lock);
368 Glib::Mutex::Lock lm2 (controllables_lock);
369 MIDIControllable* dptr = 0;
371 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
372 relevant MIDIControllable and remove it from the pending list.
375 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
376 if (((*i)->first)->get_controllable() == c) {
377 (*i)->first->stop_learning ();
379 (*i)->second.disconnect();
382 pending_controllables.erase (i);
391 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
394 Glib::Mutex::Lock lm2 (controllables_lock);
396 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
397 MIDIControllable* existingBinding = (*iter);
399 if (control == (existingBinding->get_controllable())) {
400 delete existingBinding;
401 iter = controllables.erase (iter);
411 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
413 if (control != NULL) {
414 Glib::Mutex::Lock lm2 (controllables_lock);
416 MIDI::channel_t channel = (pos & 0xf);
417 MIDI::byte value = control_number;
419 // Create a MIDIControllable
420 MIDIControllable* mc = new MIDIControllable (this, *_input_port, *control, false);
422 // Remove any old binding for this midi channel/type/value pair
423 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
424 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
425 MIDIControllable* existingBinding = (*iter);
427 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
428 existingBinding->get_control_additional() == value &&
429 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
431 delete existingBinding;
432 iter = controllables.erase (iter);
439 // Update the MIDI Controllable based on the the pos param
440 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
441 mc->bind_midi(channel, MIDI::controller, value);
443 controllables.push_back (mc);
448 GenericMidiControlProtocol::get_state ()
450 XMLNode* node = new XMLNode ("Protocol");
453 node->add_property (X_("name"), _name);
454 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
455 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
456 node->add_property (X_("feedback_interval"), buf);
458 if (!_current_binding.empty()) {
459 node->add_property ("binding", _current_binding);
462 XMLNode* children = new XMLNode (X_("Controls"));
464 node->add_child_nocopy (*children);
466 Glib::Mutex::Lock lm2 (controllables_lock);
467 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
469 /* we don't care about bindings that come from a bindings map, because
470 they will all be reset/recreated when we load the relevant bindings
474 if ((*i)->learned()) {
475 children->add_child_nocopy ((*i)->get_state());
483 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
486 XMLNodeConstIterator niter;
487 const XMLProperty* prop;
489 if ((prop = node.property ("feedback")) != 0) {
490 do_feedback = (bool) atoi (prop->value().c_str());
495 if ((prop = node.property ("feedback_interval")) != 0) {
496 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
497 _feedback_interval = 10000;
500 _feedback_interval = 10000;
503 boost::shared_ptr<Controllable> c;
506 Glib::Mutex::Lock lm (pending_lock);
507 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
510 pending_controllables.clear ();
514 Glib::Mutex::Lock lm2 (controllables_lock);
515 controllables.clear ();
516 nlist = node.children(); // "Controls"
522 nlist = nlist.front()->children ();
524 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
526 if ((prop = (*niter)->property ("id")) != 0) {
528 cerr << "Looking for MIDI Controllable with ID " << prop->value() << endl;
530 ID id = prop->value ();
531 Controllable* c = Controllable::by_id (id);
533 cerr << "\tresult = " << c << endl;
536 MIDIControllable* mc = new MIDIControllable (this, *_input_port, *c, false);
538 if (mc->set_state (**niter, version) == 0) {
539 controllables.push_back (mc);
543 warning << string_compose (
544 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
552 if ((prop = node.property ("binding")) != 0) {
553 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
554 if (prop->value() == (*x).name) {
555 load_bindings ((*x).path);
565 GenericMidiControlProtocol::set_feedback (bool yn)
568 last_feedback_time = 0;
573 GenericMidiControlProtocol::get_feedback () const
579 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
583 if (!state_tree.read (xmlpath.c_str())) {
584 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
588 XMLNode* root = state_tree.root();
590 if (root->name() != X_("ArdourMIDIBindings")) {
591 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
595 const XMLProperty* prop;
597 if ((prop = root->property ("version")) == 0) {
604 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
605 Stateful::loading_state_version = (major * 1000) + minor;
608 const XMLNodeList& children (root->children());
609 XMLNodeConstIterator citer;
610 XMLNodeConstIterator gciter;
612 MIDIControllable* mc;
616 for (citer = children.begin(); citer != children.end(); ++citer) {
618 if ((*citer)->name() == "DeviceInfo") {
619 const XMLProperty* prop;
621 if ((prop = (*citer)->property ("bank-size")) != 0) {
622 _bank_size = atoi (prop->value());
626 if ((prop = (*citer)->property ("motorised")) != 0) {
627 _motorised = string_is_affirmative (prop->value ());
633 if ((*citer)->name() == "Binding") {
634 const XMLNode* child = *citer;
636 if (child->property ("uri")) {
639 if ((mc = create_binding (*child)) != 0) {
640 Glib::Mutex::Lock lm2 (controllables_lock);
641 controllables.push_back (mc);
644 } else if (child->property ("function")) {
649 if ((mf = create_function (*child)) != 0) {
650 functions.push_back (mf);
653 } else if (child->property ("action")) {
656 if ((ma = create_action (*child)) != 0) {
657 actions.push_back (ma);
663 if ((prop = root->property ("name")) != 0) {
664 _current_binding = prop->value ();
667 reset_controllables ();
673 GenericMidiControlProtocol::create_binding (const XMLNode& node)
675 const XMLProperty* prop;
677 MIDI::channel_t channel;
683 if ((prop = node.property (X_("ctl"))) != 0) {
684 ev = MIDI::controller;
685 } else if ((prop = node.property (X_("note"))) != 0) {
687 } else if ((prop = node.property (X_("pgm"))) != 0) {
689 } else if ((prop = node.property (X_("pb"))) != 0) {
690 ev = MIDI::pitchbend;
695 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
699 detail = (MIDI::byte) intval;
701 if ((prop = node.property (X_("channel"))) == 0) {
705 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
708 channel = (MIDI::channel_t) intval;
709 /* adjust channel to zero-based counting */
714 if ((prop = node.property (X_("momentary"))) != 0) {
715 momentary = string_is_affirmative (prop->value());
720 prop = node.property (X_("uri"));
723 MIDIControllable* mc = new MIDIControllable (this, *_input_port, momentary);
725 if (mc->init (uri)) {
730 mc->bind_midi (channel, ev, detail);
736 GenericMidiControlProtocol::reset_controllables ()
738 Glib::Mutex::Lock lm2 (controllables_lock);
740 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
741 MIDIControllable* existingBinding = (*iter);
742 MIDIControllables::iterator next = iter;
745 if (!existingBinding->learned()) {
746 ControllableDescriptor& desc (existingBinding->descriptor());
749 desc.set_bank_offset (_current_bank * _bank_size);
752 /* its entirely possible that the session doesn't have
753 * the specified controllable (e.g. it has too few
754 * tracks). if we find this to be the case, drop any
755 * bindings that would be left without controllables.
758 boost::shared_ptr<Controllable> c = session->controllable_by_descriptor (desc);
760 existingBinding->set_controllable (c.get());
762 controllables.erase (iter);
771 GenericMidiControlProtocol::create_function (const XMLNode& node)
773 const XMLProperty* prop;
775 MIDI::byte detail = 0;
776 MIDI::channel_t channel = 0;
779 MIDI::byte* data = 0;
780 uint32_t data_size = 0;
783 if ((prop = node.property (X_("ctl"))) != 0) {
784 ev = MIDI::controller;
785 } else if ((prop = node.property (X_("note"))) != 0) {
787 } else if ((prop = node.property (X_("pgm"))) != 0) {
789 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
791 if (prop->name() == X_("sysex")) {
802 stringstream ss (prop->value());
814 data = new MIDI::byte[cnt];
818 stringstream ss (prop->value());
823 data[cnt++] = (MIDI::byte) val;
828 warning << "Binding ignored - unknown type" << endmsg;
832 if (data_size == 0) {
833 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
837 detail = (MIDI::byte) intval;
839 if ((prop = node.property (X_("channel"))) == 0) {
843 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
846 channel = (MIDI::channel_t) intval;
847 /* adjust channel to zero-based counting */
853 if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
854 argument = prop->value ();
857 prop = node.property (X_("function"));
859 MIDIFunction* mf = new MIDIFunction (*_input_port);
861 if (mf->setup (*this, prop->value(), argument, data, data_size)) {
866 mf->bind_midi (channel, ev, detail);
872 GenericMidiControlProtocol::create_action (const XMLNode& node)
874 const XMLProperty* prop;
876 MIDI::byte detail = 0;
877 MIDI::channel_t channel = 0;
880 MIDI::byte* data = 0;
881 uint32_t data_size = 0;
883 if ((prop = node.property (X_("ctl"))) != 0) {
884 ev = MIDI::controller;
885 } else if ((prop = node.property (X_("note"))) != 0) {
887 } else if ((prop = node.property (X_("pgm"))) != 0) {
889 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
891 if (prop->name() == X_("sysex")) {
902 stringstream ss (prop->value());
914 data = new MIDI::byte[cnt];
918 stringstream ss (prop->value());
923 data[cnt++] = (MIDI::byte) val;
928 warning << "Binding ignored - unknown type" << endmsg;
932 if (data_size == 0) {
933 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
937 detail = (MIDI::byte) intval;
939 if ((prop = node.property (X_("channel"))) == 0) {
943 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
946 channel = (MIDI::channel_t) intval;
947 /* adjust channel to zero-based counting */
953 prop = node.property (X_("action"));
955 MIDIAction* ma = new MIDIAction (*_input_port);
957 if (ma->init (*this, prop->value(), data, data_size)) {
962 ma->bind_midi (channel, ev, detail);
968 GenericMidiControlProtocol::set_current_bank (uint32_t b)
971 reset_controllables ();
975 GenericMidiControlProtocol::next_bank ()
978 reset_controllables ();
982 GenericMidiControlProtocol::prev_bank()
986 reset_controllables ();
991 GenericMidiControlProtocol::set_motorised (bool m)