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 "pbd/controllable_descriptor.h"
26 #include "pbd/error.h"
27 #include "pbd/failed_constructor.h"
28 #include "pbd/pathscanner.h"
29 #include "pbd/xml++.h"
31 #include "midi++/port.h"
32 #include "midi++/manager.h"
34 #include "ardour/filesystem_paths.h"
35 #include "ardour/session.h"
36 #include "ardour/route.h"
37 #include "ardour/midi_ui.h"
38 #include "ardour/rc_configuration.h"
40 #include "generic_midi_control_protocol.h"
41 #include "midicontrollable.h"
42 #include "midifunction.h"
43 #include "midiaction.h"
45 using namespace ARDOUR;
51 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
52 #define ui_bind(x) boost::protect (boost::bind ((x)))
54 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
55 : ControlProtocol (s, _("Generic MIDI"), midi_ui_context())
59 _input_port = MIDI::Manager::instance()->midi_input_port ();
60 _output_port = MIDI::Manager::instance()->midi_output_port ();
63 _feedback_interval = 10000; // microseconds
64 last_feedback_time = 0;
69 /* XXX is it right to do all these in the same thread as whatever emits the signal? */
71 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
72 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
73 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
74 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
76 Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
77 Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
82 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
88 static const char* const midi_map_dir_name = "midi_maps";
89 static const char* const midi_map_suffix = ".map";
92 system_midi_map_search_path ()
94 SearchPath spath(system_data_search_path());
95 spath.add_subdirectory_to_paths(midi_map_dir_name);
97 // just return the first directory in the search path that exists
98 SearchPath::const_iterator i = std::find_if(spath.begin(), spath.end(), sys::exists);
100 if (i == spath.end()) return sys::path();
106 user_midi_map_directory ()
108 sys::path p(user_config_directory());
109 p /= midi_map_dir_name;
115 midi_map_filter (const string &str, void */*arg*/)
117 return (str.length() > strlen(midi_map_suffix) &&
118 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
122 GenericMidiControlProtocol::reload_maps ()
124 vector<string *> *midi_maps;
126 SearchPath spath (system_midi_map_search_path());
127 spath += user_midi_map_directory ();
129 midi_maps = scanner (spath.to_string(), midi_map_filter, 0, false, true);
132 cerr << "No MIDI maps found using " << spath.to_string() << endl;
136 for (vector<string*>::iterator i = midi_maps->begin(); i != midi_maps->end(); ++i) {
137 string fullpath = *(*i);
141 if (!tree.read (fullpath.c_str())) {
147 XMLProperty* prop = tree.root()->property ("name");
153 mi.name = prop->value ();
156 map_info.push_back (mi);
163 GenericMidiControlProtocol::drop_all ()
165 Glib::Mutex::Lock lm (pending_lock);
166 Glib::Mutex::Lock lm2 (controllables_lock);
168 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
171 controllables.clear ();
173 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
176 pending_controllables.clear ();
178 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
183 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
190 GenericMidiControlProtocol::drop_bindings ()
192 Glib::Mutex::Lock lm2 (controllables_lock);
194 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
195 if (!(*i)->learned()) {
197 i = controllables.erase (i);
203 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
208 _current_binding = "";
214 GenericMidiControlProtocol::set_active (bool /*yn*/)
216 /* start/stop delivery/outbound thread */
221 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
223 _feedback_interval = ms;
227 GenericMidiControlProtocol::send_feedback ()
233 microseconds_t now = get_microseconds ();
235 if (last_feedback_time != 0) {
236 if ((now - last_feedback_time) < _feedback_interval) {
243 last_feedback_time = now;
247 GenericMidiControlProtocol::_send_feedback ()
249 const int32_t bufsize = 16 * 1024; /* XXX too big */
250 MIDI::byte buf[bufsize];
251 int32_t bsize = bufsize;
252 MIDI::byte* end = buf;
254 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
255 end = (*r)->write_feedback (end, bsize);
262 _output_port->write (buf, (int32_t) (end - buf), 0);
266 GenericMidiControlProtocol::start_learning (Controllable* c)
272 Glib::Mutex::Lock lm2 (controllables_lock);
274 MIDIControllables::iterator tmp;
275 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
278 if ((*i)->get_controllable() == c) {
280 controllables.erase (i);
286 Glib::Mutex::Lock lm (pending_lock);
288 MIDIPendingControllables::iterator ptmp;
289 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
292 if (((*i)->first)->get_controllable() == c) {
293 (*i)->second.disconnect();
296 pending_controllables.erase (i);
302 MIDIControllable* mc = 0;
304 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
305 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
312 mc = new MIDIControllable (*_input_port, *c, false);
316 Glib::Mutex::Lock lm (pending_lock);
318 MIDIPendingControllable* element = new MIDIPendingControllable;
320 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
322 pending_controllables.push_back (element);
325 mc->learn_about_external_control ();
330 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
332 Glib::Mutex::Lock lm (pending_lock);
333 Glib::Mutex::Lock lm2 (controllables_lock);
335 MIDIPendingControllables::iterator tmp;
337 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
341 if ( (*i)->first == mc) {
342 (*i)->second.disconnect();
344 pending_controllables.erase(i);
350 controllables.push_back (mc);
354 GenericMidiControlProtocol::stop_learning (Controllable* c)
356 Glib::Mutex::Lock lm (pending_lock);
357 Glib::Mutex::Lock lm2 (controllables_lock);
358 MIDIControllable* dptr = 0;
360 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
361 relevant MIDIControllable and remove it from the pending list.
364 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
365 if (((*i)->first)->get_controllable() == c) {
366 (*i)->first->stop_learning ();
368 (*i)->second.disconnect();
371 pending_controllables.erase (i);
380 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
383 Glib::Mutex::Lock lm2 (controllables_lock);
385 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
386 MIDIControllable* existingBinding = (*iter);
388 if (control == (existingBinding->get_controllable())) {
389 delete existingBinding;
390 iter = controllables.erase (iter);
400 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
402 if (control != NULL) {
403 Glib::Mutex::Lock lm2 (controllables_lock);
405 MIDI::channel_t channel = (pos & 0xf);
406 MIDI::byte value = control_number;
408 // Create a MIDIControllable
409 MIDIControllable* mc = new MIDIControllable (*_input_port, *control, false);
411 // Remove any old binding for this midi channel/type/value pair
412 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
413 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
414 MIDIControllable* existingBinding = (*iter);
416 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
417 existingBinding->get_control_additional() == value &&
418 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
420 delete existingBinding;
421 iter = controllables.erase (iter);
428 // Update the MIDI Controllable based on the the pos param
429 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
430 mc->bind_midi(channel, MIDI::controller, value);
432 controllables.push_back (mc);
437 GenericMidiControlProtocol::get_state ()
439 XMLNode* node = new XMLNode ("Protocol");
442 node->add_property (X_("name"), _name);
443 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
444 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
445 node->add_property (X_("feedback_interval"), buf);
447 if (!_current_binding.empty()) {
448 node->add_property ("binding", _current_binding);
451 XMLNode* children = new XMLNode (X_("Controls"));
453 node->add_child_nocopy (*children);
455 Glib::Mutex::Lock lm2 (controllables_lock);
456 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
458 /* we don't care about bindings that come from a bindings map, because
459 they will all be reset/recreated when we load the relevant bindings
463 if ((*i)->learned()) {
464 children->add_child_nocopy ((*i)->get_state());
472 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
475 XMLNodeConstIterator niter;
476 const XMLProperty* prop;
478 if ((prop = node.property ("feedback")) != 0) {
479 do_feedback = (bool) atoi (prop->value().c_str());
484 if ((prop = node.property ("feedback_interval")) != 0) {
485 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
486 _feedback_interval = 10000;
489 _feedback_interval = 10000;
492 boost::shared_ptr<Controllable> c;
495 Glib::Mutex::Lock lm (pending_lock);
496 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
499 pending_controllables.clear ();
503 Glib::Mutex::Lock lm2 (controllables_lock);
504 controllables.clear ();
505 nlist = node.children(); // "Controls"
511 nlist = nlist.front()->children ();
513 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
515 if ((prop = (*niter)->property ("id")) != 0) {
517 cerr << "Looking for MIDI Controllable with ID " << prop->value() << endl;
519 ID id = prop->value ();
520 Controllable* c = Controllable::by_id (id);
522 cerr << "\tresult = " << c << endl;
525 MIDIControllable* mc = new MIDIControllable (*_input_port, *c, false);
527 if (mc->set_state (**niter, version) == 0) {
528 controllables.push_back (mc);
532 warning << string_compose (
533 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
541 if ((prop = node.property ("binding")) != 0) {
542 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
543 if (prop->value() == (*x).name) {
544 load_bindings ((*x).path);
554 GenericMidiControlProtocol::set_feedback (bool yn)
557 last_feedback_time = 0;
562 GenericMidiControlProtocol::get_feedback () const
571 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
575 if (!state_tree.read (xmlpath.c_str())) {
576 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
580 XMLNode* root = state_tree.root();
582 if (root->name() != X_("ArdourMIDIBindings")) {
583 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
587 const XMLProperty* prop;
589 if ((prop = root->property ("version")) == 0) {
596 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
597 Stateful::loading_state_version = (major * 1000) + minor;
600 const XMLNodeList& children (root->children());
601 XMLNodeConstIterator citer;
602 XMLNodeConstIterator gciter;
604 MIDIControllable* mc;
608 for (citer = children.begin(); citer != children.end(); ++citer) {
610 if ((*citer)->name() == "DeviceInfo") {
611 const XMLProperty* prop;
613 if ((prop = (*citer)->property ("bank-size")) != 0) {
614 _bank_size = atoi (prop->value());
619 if ((*citer)->name() == "Binding") {
620 const XMLNode* child = *citer;
622 if (child->property ("uri")) {
625 if ((mc = create_binding (*child)) != 0) {
626 Glib::Mutex::Lock lm2 (controllables_lock);
627 controllables.push_back (mc);
630 } else if (child->property ("function")) {
635 if ((mf = create_function (*child)) != 0) {
636 functions.push_back (mf);
639 } else if (child->property ("action")) {
642 if ((ma = create_action (*child)) != 0) {
643 actions.push_back (ma);
649 if ((prop = root->property ("name")) != 0) {
650 _current_binding = prop->value ();
653 reset_controllables ();
659 GenericMidiControlProtocol::create_binding (const XMLNode& node)
661 const XMLProperty* prop;
663 MIDI::channel_t channel;
669 if ((prop = node.property (X_("ctl"))) != 0) {
670 ev = MIDI::controller;
671 } else if ((prop = node.property (X_("note"))) != 0) {
673 } else if ((prop = node.property (X_("pgm"))) != 0) {
679 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
683 detail = (MIDI::byte) intval;
685 if ((prop = node.property (X_("channel"))) == 0) {
689 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
692 channel = (MIDI::channel_t) intval;
693 /* adjust channel to zero-based counting */
698 if ((prop = node.property (X_("momentary"))) != 0) {
699 momentary = string_is_affirmative (prop->value());
704 prop = node.property (X_("uri"));
707 MIDIControllable* mc = new MIDIControllable (*_input_port, momentary);
709 if (mc->init (uri)) {
714 mc->bind_midi (channel, ev, detail);
720 GenericMidiControlProtocol::reset_controllables ()
722 Glib::Mutex::Lock lm2 (controllables_lock);
724 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
725 MIDIControllable* existingBinding = (*iter);
727 if (!existingBinding->learned()) {
728 ControllableDescriptor& desc (existingBinding->descriptor());
731 desc.set_bank_offset (_current_bank * _bank_size);
734 boost::shared_ptr<Controllable> c = session->controllable_by_descriptor (desc);
735 existingBinding->set_controllable (c.get());
741 GenericMidiControlProtocol::create_function (const XMLNode& node)
743 const XMLProperty* prop;
745 MIDI::byte detail = 0;
746 MIDI::channel_t channel = 0;
749 MIDI::byte* data = 0;
750 uint32_t data_size = 0;
752 if ((prop = node.property (X_("ctl"))) != 0) {
753 ev = MIDI::controller;
754 } else if ((prop = node.property (X_("note"))) != 0) {
756 } else if ((prop = node.property (X_("pgm"))) != 0) {
758 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
760 if (prop->name() == X_("sysex")) {
771 stringstream ss (prop->value());
783 data = new MIDI::byte[cnt];
787 stringstream ss (prop->value());
792 data[cnt++] = (MIDI::byte) val;
797 warning << "Binding ignored - unknown type" << endmsg;
801 if (data_size == 0) {
802 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
806 detail = (MIDI::byte) intval;
808 if ((prop = node.property (X_("channel"))) == 0) {
812 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
815 channel = (MIDI::channel_t) intval;
816 /* adjust channel to zero-based counting */
822 prop = node.property (X_("function"));
824 MIDIFunction* mf = new MIDIFunction (*_input_port);
826 if (mf->init (*this, prop->value(), data, data_size)) {
831 mf->bind_midi (channel, ev, detail);
837 GenericMidiControlProtocol::create_action (const XMLNode& node)
839 const XMLProperty* prop;
841 MIDI::byte detail = 0;
842 MIDI::channel_t channel = 0;
845 MIDI::byte* data = 0;
846 uint32_t data_size = 0;
848 if ((prop = node.property (X_("ctl"))) != 0) {
849 ev = MIDI::controller;
850 } else if ((prop = node.property (X_("note"))) != 0) {
852 } else if ((prop = node.property (X_("pgm"))) != 0) {
854 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
856 if (prop->name() == X_("sysex")) {
867 stringstream ss (prop->value());
879 data = new MIDI::byte[cnt];
883 stringstream ss (prop->value());
888 data[cnt++] = (MIDI::byte) val;
893 warning << "Binding ignored - unknown type" << endmsg;
897 if (data_size == 0) {
898 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
902 detail = (MIDI::byte) intval;
904 if ((prop = node.property (X_("channel"))) == 0) {
908 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
911 channel = (MIDI::channel_t) intval;
912 /* adjust channel to zero-based counting */
918 prop = node.property (X_("action"));
920 MIDIAction* ma = new MIDIAction (*_input_port);
922 if (ma->init (*this, prop->value(), data, data_size)) {
927 ma->bind_midi (channel, ev, detail);
933 GenericMidiControlProtocol::set_current_bank (uint32_t b)
936 reset_controllables ();
940 GenericMidiControlProtocol::next_bank ()
943 reset_controllables ();
947 GenericMidiControlProtocol::prev_bank()
951 reset_controllables ();