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"
33 #include "midi++/manager.h"
35 #include "ardour/filesystem_paths.h"
36 #include "ardour/session.h"
37 #include "ardour/route.h"
38 #include "ardour/midi_ui.h"
39 #include "ardour/rc_configuration.h"
41 #include "generic_midi_control_protocol.h"
42 #include "midicontrollable.h"
43 #include "midifunction.h"
44 #include "midiaction.h"
46 using namespace ARDOUR;
52 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
53 #define ui_bind(x) boost::protect (boost::bind ((x)))
55 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
56 : ControlProtocol (s, _("Generic MIDI"), midi_ui_context())
60 _input_port = MIDI::Manager::instance()->midi_input_port ();
61 _output_port = MIDI::Manager::instance()->midi_output_port ();
64 _feedback_interval = 10000; // microseconds
65 last_feedback_time = 0;
70 /* XXX is it right to do all these in the same thread as whatever emits the signal? */
72 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
73 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
74 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
75 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
77 Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
78 Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
83 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
89 static const char* const midi_map_dir_name = "midi_maps";
90 static const char* const midi_map_suffix = ".map";
93 system_midi_map_search_path ()
95 SearchPath spath(system_data_search_path());
96 spath.add_subdirectory_to_paths(midi_map_dir_name);
98 // just return the first directory in the search path that exists
99 SearchPath::const_iterator i = std::find_if(spath.begin(), spath.end(), sys::exists);
101 if (i == spath.end()) return sys::path();
107 user_midi_map_directory ()
109 sys::path p(user_config_directory());
110 p /= midi_map_dir_name;
116 midi_map_filter (const string &str, void */*arg*/)
118 return (str.length() > strlen(midi_map_suffix) &&
119 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
123 GenericMidiControlProtocol::reload_maps ()
125 vector<string *> *midi_maps;
127 SearchPath spath (system_midi_map_search_path());
128 spath += user_midi_map_directory ();
130 midi_maps = scanner (spath.to_string(), midi_map_filter, 0, false, true);
133 cerr << "No MIDI maps found using " << spath.to_string() << endl;
137 cerr << "Found " << midi_maps->size() << " MIDI maps along " << spath.to_string() << endl;
139 for (vector<string*>::iterator i = midi_maps->begin(); i != midi_maps->end(); ++i) {
140 string fullpath = *(*i);
144 if (!tree.read (fullpath.c_str())) {
150 XMLProperty* prop = tree.root()->property ("name");
156 mi.name = prop->value ();
159 map_info.push_back (mi);
166 GenericMidiControlProtocol::drop_all ()
168 Glib::Mutex::Lock lm (pending_lock);
169 Glib::Mutex::Lock lm2 (controllables_lock);
171 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
174 controllables.clear ();
176 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
179 pending_controllables.clear ();
181 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
186 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
193 GenericMidiControlProtocol::drop_bindings ()
195 Glib::Mutex::Lock lm2 (controllables_lock);
197 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
198 if (!(*i)->learned()) {
200 i = controllables.erase (i);
206 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
211 _current_binding = "";
217 GenericMidiControlProtocol::set_active (bool /*yn*/)
219 /* start/stop delivery/outbound thread */
224 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
226 _feedback_interval = ms;
230 GenericMidiControlProtocol::send_feedback ()
236 microseconds_t now = get_microseconds ();
238 if (last_feedback_time != 0) {
239 if ((now - last_feedback_time) < _feedback_interval) {
246 last_feedback_time = now;
250 GenericMidiControlProtocol::_send_feedback ()
252 const int32_t bufsize = 16 * 1024; /* XXX too big */
253 MIDI::byte buf[bufsize];
254 int32_t bsize = bufsize;
255 MIDI::byte* end = buf;
257 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
258 end = (*r)->write_feedback (end, bsize);
265 _output_port->write (buf, (int32_t) (end - buf), 0);
269 GenericMidiControlProtocol::start_learning (Controllable* c)
275 Glib::Mutex::Lock lm2 (controllables_lock);
277 MIDIControllables::iterator tmp;
278 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
281 if ((*i)->get_controllable() == c) {
283 controllables.erase (i);
289 Glib::Mutex::Lock lm (pending_lock);
291 MIDIPendingControllables::iterator ptmp;
292 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
295 if (((*i)->first)->get_controllable() == c) {
296 (*i)->second.disconnect();
299 pending_controllables.erase (i);
305 MIDIControllable* mc = 0;
307 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
308 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
315 mc = new MIDIControllable (*_input_port, *c, false);
319 Glib::Mutex::Lock lm (pending_lock);
321 MIDIPendingControllable* element = new MIDIPendingControllable;
323 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
325 pending_controllables.push_back (element);
328 mc->learn_about_external_control ();
333 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
335 Glib::Mutex::Lock lm (pending_lock);
336 Glib::Mutex::Lock lm2 (controllables_lock);
338 MIDIPendingControllables::iterator tmp;
340 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
344 if ( (*i)->first == mc) {
345 (*i)->second.disconnect();
347 pending_controllables.erase(i);
353 controllables.push_back (mc);
357 GenericMidiControlProtocol::stop_learning (Controllable* c)
359 Glib::Mutex::Lock lm (pending_lock);
360 Glib::Mutex::Lock lm2 (controllables_lock);
361 MIDIControllable* dptr = 0;
363 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
364 relevant MIDIControllable and remove it from the pending list.
367 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
368 if (((*i)->first)->get_controllable() == c) {
369 (*i)->first->stop_learning ();
371 (*i)->second.disconnect();
374 pending_controllables.erase (i);
383 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
386 Glib::Mutex::Lock lm2 (controllables_lock);
388 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
389 MIDIControllable* existingBinding = (*iter);
391 if (control == (existingBinding->get_controllable())) {
392 delete existingBinding;
393 iter = controllables.erase (iter);
403 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
405 if (control != NULL) {
406 Glib::Mutex::Lock lm2 (controllables_lock);
408 MIDI::channel_t channel = (pos & 0xf);
409 MIDI::byte value = control_number;
411 // Create a MIDIControllable
412 MIDIControllable* mc = new MIDIControllable (*_input_port, *control, false);
414 // Remove any old binding for this midi channel/type/value pair
415 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
416 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
417 MIDIControllable* existingBinding = (*iter);
419 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
420 existingBinding->get_control_additional() == value &&
421 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
423 delete existingBinding;
424 iter = controllables.erase (iter);
431 // Update the MIDI Controllable based on the the pos param
432 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
433 mc->bind_midi(channel, MIDI::controller, value);
435 controllables.push_back (mc);
440 GenericMidiControlProtocol::get_state ()
442 XMLNode* node = new XMLNode ("Protocol");
445 node->add_property (X_("name"), _name);
446 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
447 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
448 node->add_property (X_("feedback_interval"), buf);
450 if (!_current_binding.empty()) {
451 node->add_property ("binding", _current_binding);
454 XMLNode* children = new XMLNode (X_("controls"));
456 node->add_child_nocopy (*children);
458 Glib::Mutex::Lock lm2 (controllables_lock);
459 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
461 /* we don't care about bindings that come from a bindings map, because
462 they will all be reset/recreated when we load the relevant bindings
466 if ((*i)->learned()) {
467 children->add_child_nocopy ((*i)->get_state());
475 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
478 XMLNodeConstIterator niter;
479 const XMLProperty* prop;
481 if ((prop = node.property ("feedback")) != 0) {
482 do_feedback = (bool) atoi (prop->value().c_str());
487 if ((prop = node.property ("feedback_interval")) != 0) {
488 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
489 _feedback_interval = 10000;
492 _feedback_interval = 10000;
495 boost::shared_ptr<Controllable> c;
498 Glib::Mutex::Lock lm (pending_lock);
499 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
502 pending_controllables.clear ();
506 Glib::Mutex::Lock lm2 (controllables_lock);
507 controllables.clear ();
508 nlist = node.children(); // "controls"
514 nlist = nlist.front()->children ();
516 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
518 if ((prop = (*niter)->property ("id")) != 0) {
520 ID id = prop->value ();
521 c = session->controllable_by_id (id);
524 MIDIControllable* mc = new MIDIControllable (*_input_port, *c, false);
526 if (mc->set_state (**niter, version) == 0) {
527 controllables.push_back (mc);
531 warning << string_compose (
532 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
540 if ((prop = node.property ("binding")) != 0) {
541 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
542 if (prop->value() == (*x).name) {
543 load_bindings ((*x).path);
553 GenericMidiControlProtocol::set_feedback (bool yn)
556 last_feedback_time = 0;
561 GenericMidiControlProtocol::get_feedback () const
570 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
574 if (!state_tree.read (xmlpath.c_str())) {
575 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
579 XMLNode* root = state_tree.root();
581 if (root->name() != X_("ArdourMIDIBindings")) {
582 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
586 const XMLProperty* prop;
588 if ((prop = root->property ("version")) == 0) {
595 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
596 Stateful::loading_state_version = (major * 1000) + minor;
599 const XMLNodeList& children (root->children());
600 XMLNodeConstIterator citer;
601 XMLNodeConstIterator gciter;
603 MIDIControllable* mc;
607 for (citer = children.begin(); citer != children.end(); ++citer) {
609 if ((*citer)->name() == "DeviceInfo") {
610 const XMLProperty* prop;
612 if ((prop = (*citer)->property ("bank-size")) != 0) {
613 _bank_size = atoi (prop->value());
618 if ((*citer)->name() == "Binding") {
619 const XMLNode* child = *citer;
621 if (child->property ("uri")) {
624 if ((mc = create_binding (*child)) != 0) {
625 Glib::Mutex::Lock lm2 (controllables_lock);
626 controllables.push_back (mc);
629 } else if (child->property ("function")) {
634 if ((mf = create_function (*child)) != 0) {
635 functions.push_back (mf);
638 } else if (child->property ("action")) {
641 if ((ma = create_action (*child)) != 0) {
642 actions.push_back (ma);
648 if ((prop = root->property ("name")) != 0) {
649 _current_binding = prop->value ();
652 reset_controllables ();
658 GenericMidiControlProtocol::create_binding (const XMLNode& node)
660 const XMLProperty* prop;
662 MIDI::channel_t channel;
668 if ((prop = node.property (X_("ctl"))) != 0) {
669 ev = MIDI::controller;
670 } else if ((prop = node.property (X_("note"))) != 0) {
672 } else if ((prop = node.property (X_("pgm"))) != 0) {
678 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
682 detail = (MIDI::byte) intval;
684 if ((prop = node.property (X_("channel"))) == 0) {
688 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
691 channel = (MIDI::channel_t) intval;
692 /* adjust channel to zero-based counting */
697 if ((prop = node.property (X_("momentary"))) != 0) {
698 momentary = string_is_affirmative (prop->value());
703 prop = node.property (X_("uri"));
706 MIDIControllable* mc = new MIDIControllable (*_input_port, momentary);
708 if (mc->init (uri)) {
713 mc->bind_midi (channel, ev, detail);
719 GenericMidiControlProtocol::reset_controllables ()
721 Glib::Mutex::Lock lm2 (controllables_lock);
723 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
724 MIDIControllable* existingBinding = (*iter);
726 if (!existingBinding->learned()) {
727 ControllableDescriptor& desc (existingBinding->descriptor());
730 desc.set_bank_offset (_current_bank * _bank_size);
733 boost::shared_ptr<Controllable> c = session->controllable_by_descriptor (desc);
734 existingBinding->set_controllable (c.get());
740 GenericMidiControlProtocol::create_function (const XMLNode& node)
742 const XMLProperty* prop;
744 MIDI::byte detail = 0;
745 MIDI::channel_t channel = 0;
748 MIDI::byte* data = 0;
749 uint32_t data_size = 0;
751 if ((prop = node.property (X_("ctl"))) != 0) {
752 ev = MIDI::controller;
753 } else if ((prop = node.property (X_("note"))) != 0) {
755 } else if ((prop = node.property (X_("pgm"))) != 0) {
757 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
759 if (prop->name() == X_("sysex")) {
770 stringstream ss (prop->value());
782 data = new MIDI::byte[cnt];
786 stringstream ss (prop->value());
791 data[cnt++] = (MIDI::byte) val;
796 warning << "Binding ignored - unknown type" << endmsg;
800 if (data_size == 0) {
801 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
805 detail = (MIDI::byte) intval;
807 if ((prop = node.property (X_("channel"))) == 0) {
811 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
814 channel = (MIDI::channel_t) intval;
815 /* adjust channel to zero-based counting */
821 prop = node.property (X_("function"));
823 MIDIFunction* mf = new MIDIFunction (*_input_port);
825 if (mf->init (*this, prop->value(), data, data_size)) {
830 mf->bind_midi (channel, ev, detail);
836 GenericMidiControlProtocol::create_action (const XMLNode& node)
838 const XMLProperty* prop;
840 MIDI::byte detail = 0;
841 MIDI::channel_t channel = 0;
844 MIDI::byte* data = 0;
845 uint32_t data_size = 0;
847 if ((prop = node.property (X_("ctl"))) != 0) {
848 ev = MIDI::controller;
849 } else if ((prop = node.property (X_("note"))) != 0) {
851 } else if ((prop = node.property (X_("pgm"))) != 0) {
853 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
855 if (prop->name() == X_("sysex")) {
866 stringstream ss (prop->value());
878 data = new MIDI::byte[cnt];
882 stringstream ss (prop->value());
887 data[cnt++] = (MIDI::byte) val;
892 warning << "Binding ignored - unknown type" << endmsg;
896 if (data_size == 0) {
897 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
901 detail = (MIDI::byte) intval;
903 if ((prop = node.property (X_("channel"))) == 0) {
907 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
910 channel = (MIDI::channel_t) intval;
911 /* adjust channel to zero-based counting */
917 prop = node.property (X_("action"));
919 MIDIAction* ma = new MIDIAction (*_input_port);
921 if (ma->init (*this, prop->value(), data, data_size)) {
926 ma->bind_midi (channel, ev, detail);
932 GenericMidiControlProtocol::set_current_bank (uint32_t b)
935 reset_controllables ();
939 GenericMidiControlProtocol::next_bank ()
942 reset_controllables ();
946 GenericMidiControlProtocol::prev_bank()
950 reset_controllables ();