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.
20 #define __STDC_FORMAT_MACROS 1
26 #include "pbd/controllable_descriptor.h"
27 #include "pbd/error.h"
28 #include "pbd/failed_constructor.h"
29 #include "pbd/pathscanner.h"
30 #include "pbd/xml++.h"
32 #include "midi++/port.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 = s.midi_input_port ();
60 _output_port = s.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 cerr << "Found " << midi_maps->size() << " MIDI maps along " << spath.to_string() << endl;
138 for (vector<string*>::iterator i = midi_maps->begin(); i != midi_maps->end(); ++i) {
139 string fullpath = *(*i);
143 if (!tree.read (fullpath.c_str())) {
149 XMLProperty* prop = tree.root()->property ("name");
155 mi.name = prop->value ();
158 map_info.push_back (mi);
165 GenericMidiControlProtocol::drop_all ()
167 Glib::Mutex::Lock lm (pending_lock);
168 Glib::Mutex::Lock lm2 (controllables_lock);
170 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
173 controllables.clear ();
175 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
178 pending_controllables.clear ();
180 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
185 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
192 GenericMidiControlProtocol::drop_bindings ()
194 Glib::Mutex::Lock lm2 (controllables_lock);
196 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
197 if (!(*i)->learned()) {
199 i = controllables.erase (i);
205 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
210 _current_binding = "";
216 GenericMidiControlProtocol::set_active (bool /*yn*/)
218 /* start/stop delivery/outbound thread */
223 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
225 _feedback_interval = ms;
229 GenericMidiControlProtocol::send_feedback ()
235 microseconds_t now = get_microseconds ();
237 if (last_feedback_time != 0) {
238 if ((now - last_feedback_time) < _feedback_interval) {
245 last_feedback_time = now;
249 GenericMidiControlProtocol::_send_feedback ()
251 const int32_t bufsize = 16 * 1024; /* XXX too big */
252 MIDI::byte buf[bufsize];
253 int32_t bsize = bufsize;
254 MIDI::byte* end = buf;
256 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
257 end = (*r)->write_feedback (end, bsize);
264 _output_port->write (buf, (int32_t) (end - buf), 0);
268 GenericMidiControlProtocol::start_learning (Controllable* c)
274 Glib::Mutex::Lock lm2 (controllables_lock);
276 MIDIControllables::iterator tmp;
277 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
280 if ((*i)->get_controllable() == c) {
282 controllables.erase (i);
288 Glib::Mutex::Lock lm (pending_lock);
290 MIDIPendingControllables::iterator ptmp;
291 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
294 if (((*i)->first)->get_controllable() == c) {
295 (*i)->second.disconnect();
298 pending_controllables.erase (i);
304 MIDIControllable* mc = 0;
306 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
307 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
314 mc = new MIDIControllable (*_input_port, *c, false);
318 Glib::Mutex::Lock lm (pending_lock);
320 MIDIPendingControllable* element = new MIDIPendingControllable;
322 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
324 pending_controllables.push_back (element);
327 mc->learn_about_external_control ();
332 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
334 Glib::Mutex::Lock lm (pending_lock);
335 Glib::Mutex::Lock lm2 (controllables_lock);
337 MIDIPendingControllables::iterator tmp;
339 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
343 if ( (*i)->first == mc) {
344 (*i)->second.disconnect();
346 pending_controllables.erase(i);
352 controllables.push_back (mc);
356 GenericMidiControlProtocol::stop_learning (Controllable* c)
358 Glib::Mutex::Lock lm (pending_lock);
359 Glib::Mutex::Lock lm2 (controllables_lock);
360 MIDIControllable* dptr = 0;
362 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
363 relevant MIDIControllable and remove it from the pending list.
366 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
367 if (((*i)->first)->get_controllable() == c) {
368 (*i)->first->stop_learning ();
370 (*i)->second.disconnect();
373 pending_controllables.erase (i);
382 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
385 Glib::Mutex::Lock lm2 (controllables_lock);
387 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
388 MIDIControllable* existingBinding = (*iter);
390 if (control == (existingBinding->get_controllable())) {
391 delete existingBinding;
392 iter = controllables.erase (iter);
402 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
404 if (control != NULL) {
405 Glib::Mutex::Lock lm2 (controllables_lock);
407 MIDI::channel_t channel = (pos & 0xf);
408 MIDI::byte value = control_number;
410 // Create a MIDIControllable
411 MIDIControllable* mc = new MIDIControllable (*_input_port, *control, false);
413 // Remove any old binding for this midi channel/type/value pair
414 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
415 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
416 MIDIControllable* existingBinding = (*iter);
418 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
419 existingBinding->get_control_additional() == value &&
420 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
422 delete existingBinding;
423 iter = controllables.erase (iter);
430 // Update the MIDI Controllable based on the the pos param
431 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
432 mc->bind_midi(channel, MIDI::controller, value);
434 controllables.push_back (mc);
439 GenericMidiControlProtocol::get_state ()
441 XMLNode* node = new XMLNode ("Protocol");
444 node->add_property (X_("name"), _name);
445 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
446 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
447 node->add_property (X_("feedback_interval"), buf);
449 if (!_current_binding.empty()) {
450 node->add_property ("binding", _current_binding);
453 XMLNode* children = new XMLNode (X_("controls"));
455 node->add_child_nocopy (*children);
457 Glib::Mutex::Lock lm2 (controllables_lock);
458 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
460 /* we don't care about bindings that come from a bindings map, because
461 they will all be reset/recreated when we load the relevant bindings
465 if ((*i)->learned()) {
466 children->add_child_nocopy ((*i)->get_state());
474 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
477 XMLNodeConstIterator niter;
478 const XMLProperty* prop;
480 if ((prop = node.property ("feedback")) != 0) {
481 do_feedback = (bool) atoi (prop->value().c_str());
486 if ((prop = node.property ("feedback_interval")) != 0) {
487 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
488 _feedback_interval = 10000;
491 _feedback_interval = 10000;
494 boost::shared_ptr<Controllable> c;
497 Glib::Mutex::Lock lm (pending_lock);
498 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
501 pending_controllables.clear ();
505 Glib::Mutex::Lock lm2 (controllables_lock);
506 controllables.clear ();
507 nlist = node.children(); // "controls"
513 nlist = nlist.front()->children ();
515 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
517 if ((prop = (*niter)->property ("id")) != 0) {
519 ID id = prop->value ();
520 c = session->controllable_by_id (id);
523 MIDIControllable* mc = new MIDIControllable (*_input_port, *c, false);
525 if (mc->set_state (**niter, version) == 0) {
526 controllables.push_back (mc);
530 warning << string_compose (
531 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
539 if ((prop = node.property ("binding")) != 0) {
540 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
541 if (prop->value() == (*x).name) {
542 load_bindings ((*x).path);
552 GenericMidiControlProtocol::set_feedback (bool yn)
555 last_feedback_time = 0;
560 GenericMidiControlProtocol::get_feedback () const
569 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
573 if (!state_tree.read (xmlpath.c_str())) {
574 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
578 XMLNode* root = state_tree.root();
580 if (root->name() != X_("ArdourMIDIBindings")) {
581 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
585 const XMLProperty* prop;
587 if ((prop = root->property ("version")) == 0) {
594 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
595 Stateful::loading_state_version = (major * 1000) + minor;
598 const XMLNodeList& children (root->children());
599 XMLNodeConstIterator citer;
600 XMLNodeConstIterator gciter;
602 MIDIControllable* mc;
606 for (citer = children.begin(); citer != children.end(); ++citer) {
608 if ((*citer)->name() == "DeviceInfo") {
609 const XMLProperty* prop;
611 if ((prop = (*citer)->property ("bank-size")) != 0) {
612 _bank_size = atoi (prop->value());
617 if ((*citer)->name() == "Binding") {
618 const XMLNode* child = *citer;
620 if (child->property ("uri")) {
623 if ((mc = create_binding (*child)) != 0) {
624 Glib::Mutex::Lock lm2 (controllables_lock);
625 controllables.push_back (mc);
628 } else if (child->property ("function")) {
633 if ((mf = create_function (*child)) != 0) {
634 functions.push_back (mf);
637 } else if (child->property ("action")) {
640 if ((ma = create_action (*child)) != 0) {
641 actions.push_back (ma);
647 if ((prop = root->property ("name")) != 0) {
648 _current_binding = prop->value ();
651 reset_controllables ();
657 GenericMidiControlProtocol::create_binding (const XMLNode& node)
659 const XMLProperty* prop;
661 MIDI::channel_t channel;
667 if ((prop = node.property (X_("ctl"))) != 0) {
668 ev = MIDI::controller;
669 } else if ((prop = node.property (X_("note"))) != 0) {
671 } else if ((prop = node.property (X_("pgm"))) != 0) {
677 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
681 detail = (MIDI::byte) intval;
683 if ((prop = node.property (X_("channel"))) == 0) {
687 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
690 channel = (MIDI::channel_t) intval;
691 /* adjust channel to zero-based counting */
696 if ((prop = node.property (X_("momentary"))) != 0) {
697 momentary = string_is_affirmative (prop->value());
702 prop = node.property (X_("uri"));
705 MIDIControllable* mc = new MIDIControllable (*_input_port, momentary);
707 if (mc->init (uri)) {
712 mc->bind_midi (channel, ev, detail);
718 GenericMidiControlProtocol::reset_controllables ()
720 Glib::Mutex::Lock lm2 (controllables_lock);
722 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
723 MIDIControllable* existingBinding = (*iter);
725 if (!existingBinding->learned()) {
726 ControllableDescriptor& desc (existingBinding->descriptor());
729 desc.set_bank_offset (_current_bank * _bank_size);
732 boost::shared_ptr<Controllable> c = session->controllable_by_descriptor (desc);
733 existingBinding->set_controllable (c.get());
739 GenericMidiControlProtocol::create_function (const XMLNode& node)
741 const XMLProperty* prop;
743 MIDI::byte detail = 0;
744 MIDI::channel_t channel = 0;
747 MIDI::byte* data = 0;
748 uint32_t data_size = 0;
750 if ((prop = node.property (X_("ctl"))) != 0) {
751 ev = MIDI::controller;
752 } else if ((prop = node.property (X_("note"))) != 0) {
754 } else if ((prop = node.property (X_("pgm"))) != 0) {
756 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
758 if (prop->name() == X_("sysex")) {
769 stringstream ss (prop->value());
781 data = new MIDI::byte[cnt];
785 stringstream ss (prop->value());
790 data[cnt++] = (MIDI::byte) val;
795 warning << "Binding ignored - unknown type" << endmsg;
799 if (data_size == 0) {
800 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
804 detail = (MIDI::byte) intval;
806 if ((prop = node.property (X_("channel"))) == 0) {
810 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
813 channel = (MIDI::channel_t) intval;
814 /* adjust channel to zero-based counting */
820 prop = node.property (X_("function"));
822 MIDIFunction* mf = new MIDIFunction (*_input_port);
824 if (mf->init (*this, prop->value(), data, data_size)) {
829 mf->bind_midi (channel, ev, detail);
835 GenericMidiControlProtocol::create_action (const XMLNode& node)
837 const XMLProperty* prop;
839 MIDI::byte detail = 0;
840 MIDI::channel_t channel = 0;
843 MIDI::byte* data = 0;
844 uint32_t data_size = 0;
846 if ((prop = node.property (X_("ctl"))) != 0) {
847 ev = MIDI::controller;
848 } else if ((prop = node.property (X_("note"))) != 0) {
850 } else if ((prop = node.property (X_("pgm"))) != 0) {
852 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
854 if (prop->name() == X_("sysex")) {
865 stringstream ss (prop->value());
877 data = new MIDI::byte[cnt];
881 stringstream ss (prop->value());
886 data[cnt++] = (MIDI::byte) val;
891 warning << "Binding ignored - unknown type" << endmsg;
895 if (data_size == 0) {
896 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
900 detail = (MIDI::byte) intval;
902 if ((prop = node.property (X_("channel"))) == 0) {
906 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
909 channel = (MIDI::channel_t) intval;
910 /* adjust channel to zero-based counting */
916 prop = node.property (X_("action"));
918 MIDIAction* ma = new MIDIAction (*_input_port);
920 if (ma->init (*this, prop->value(), data, data_size)) {
925 ma->bind_midi (channel, ev, detail);
931 GenericMidiControlProtocol::set_current_bank (uint32_t b)
934 reset_controllables ();
938 GenericMidiControlProtocol::next_bank ()
941 reset_controllables ();
945 GenericMidiControlProtocol::prev_bank()
949 reset_controllables ();