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/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"
39 #include "generic_midi_control_protocol.h"
40 #include "midicontrollable.h"
41 #include "midifunction.h"
43 using namespace ARDOUR;
49 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
50 #define ui_bind(x) boost::protect (boost::bind ((x)))
52 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
53 : ControlProtocol (s, _("Generic MIDI"), midi_ui_context())
57 MIDI::Manager* mm = MIDI::Manager::instance();
59 /* XXX it might be nice to run "control" through i18n, but thats a bit tricky because
60 the name is defined in ardour.rc which is likely not internationalized.
63 _port = mm->port (X_("control"));
66 error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg;
67 throw failed_constructor();
71 _feedback_interval = 10000; // microseconds
72 last_feedback_time = 0;
77 /* XXX is it right to do all these in the same thread as whatever emits the signal? */
79 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
80 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
81 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
82 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
84 Session::SendFeedback.connect (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
85 Route::RemoteControlIDChange.connect (*this, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
90 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
96 static const char* const midi_map_dir_name = "midi_maps";
97 static const char* const midi_map_suffix = ".map";
100 system_midi_map_search_path ()
102 SearchPath spath(system_data_search_path());
103 spath.add_subdirectory_to_paths(midi_map_dir_name);
105 // just return the first directory in the search path that exists
106 SearchPath::const_iterator i = std::find_if(spath.begin(), spath.end(), sys::exists);
108 if (i == spath.end()) return sys::path();
114 user_midi_map_directory ()
116 sys::path p(user_config_directory());
117 p /= midi_map_dir_name;
123 midi_map_filter (const string &str, void */*arg*/)
125 return (str.length() > strlen(midi_map_suffix) &&
126 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
130 GenericMidiControlProtocol::reload_maps ()
132 vector<string *> *midi_maps;
134 SearchPath spath (system_midi_map_search_path());
135 spath += user_midi_map_directory ();
137 midi_maps = scanner (spath.to_string(), midi_map_filter, 0, false, true);
140 cerr << "No MIDI maps found using " << spath.to_string() << endl;
144 cerr << "Found " << midi_maps->size() << " MIDI maps along " << 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) {
195 GenericMidiControlProtocol::drop_bindings ()
197 Glib::Mutex::Lock lm2 (controllables_lock);
199 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
200 if (!(*i)->learned()) {
202 i = controllables.erase (i);
208 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
213 _current_binding = "";
219 GenericMidiControlProtocol::set_active (bool /*yn*/)
221 /* start/stop delivery/outbound thread */
226 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
228 _feedback_interval = ms;
232 GenericMidiControlProtocol::send_feedback ()
238 microseconds_t now = get_microseconds ();
240 if (last_feedback_time != 0) {
241 if ((now - last_feedback_time) < _feedback_interval) {
248 last_feedback_time = now;
252 GenericMidiControlProtocol::_send_feedback ()
254 const int32_t bufsize = 16 * 1024; /* XXX too big */
255 MIDI::byte buf[bufsize];
256 int32_t bsize = bufsize;
257 MIDI::byte* end = buf;
259 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
260 end = (*r)->write_feedback (end, bsize);
267 _port->write (buf, (int32_t) (end - buf), 0);
271 GenericMidiControlProtocol::start_learning (Controllable* c)
277 Glib::Mutex::Lock lm2 (controllables_lock);
279 MIDIControllables::iterator tmp;
280 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
283 if ((*i)->get_controllable() == c) {
285 controllables.erase (i);
291 Glib::Mutex::Lock lm (pending_lock);
293 MIDIPendingControllables::iterator ptmp;
294 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
297 if (((*i)->first)->get_controllable() == c) {
298 (*i)->second.disconnect();
301 pending_controllables.erase (i);
307 MIDIControllable* mc = 0;
309 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
310 if ((*i)->get_controllable()->id() == c->id()) {
317 mc = new MIDIControllable (*_port, *c);
321 Glib::Mutex::Lock lm (pending_lock);
323 MIDIPendingControllable* element = new MIDIPendingControllable;
325 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
327 pending_controllables.push_back (element);
330 mc->learn_about_external_control ();
335 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
337 Glib::Mutex::Lock lm (pending_lock);
338 Glib::Mutex::Lock lm2 (controllables_lock);
340 MIDIPendingControllables::iterator tmp;
342 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
346 if ( (*i)->first == mc) {
347 (*i)->second.disconnect();
349 pending_controllables.erase(i);
355 controllables.push_back (mc);
359 GenericMidiControlProtocol::stop_learning (Controllable* c)
361 Glib::Mutex::Lock lm (pending_lock);
362 Glib::Mutex::Lock lm2 (controllables_lock);
363 MIDIControllable* dptr = 0;
365 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
366 relevant MIDIControllable and remove it from the pending list.
369 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
370 if (((*i)->first)->get_controllable() == c) {
371 (*i)->first->stop_learning ();
373 (*i)->second.disconnect();
376 pending_controllables.erase (i);
385 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
388 Glib::Mutex::Lock lm2 (controllables_lock);
390 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
391 MIDIControllable* existingBinding = (*iter);
393 if (control == (existingBinding->get_controllable())) {
394 delete existingBinding;
395 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 (*_port, *control);
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(); ++iter) {
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 controllables.erase (iter);
429 // Update the MIDI Controllable based on the the pos param
430 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
431 mc->bind_midi(channel, MIDI::controller, value);
433 controllables.push_back (mc);
438 GenericMidiControlProtocol::get_state ()
440 XMLNode* node = new XMLNode ("Protocol");
443 node->add_property (X_("name"), _name);
444 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
445 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
446 node->add_property (X_("feedback_interval"), buf);
448 if (!_current_binding.empty()) {
449 node->add_property ("binding", _current_binding);
452 XMLNode* children = new XMLNode (X_("controls"));
454 node->add_child_nocopy (*children);
456 Glib::Mutex::Lock lm2 (controllables_lock);
457 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
459 /* we don't care about bindings that come from a bindings map, because
460 they will all be reset/recreated when we load the relevant bindings
464 if ((*i)->learned()) {
465 children->add_child_nocopy ((*i)->get_state());
473 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
476 XMLNodeConstIterator niter;
477 const XMLProperty* prop;
479 if ((prop = node.property ("feedback")) != 0) {
480 do_feedback = (bool) atoi (prop->value().c_str());
485 if ((prop = node.property ("feedback_interval")) != 0) {
486 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
487 _feedback_interval = 10000;
490 _feedback_interval = 10000;
493 boost::shared_ptr<Controllable> c;
496 Glib::Mutex::Lock lm (pending_lock);
497 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
500 pending_controllables.clear ();
504 Glib::Mutex::Lock lm2 (controllables_lock);
505 controllables.clear ();
506 nlist = node.children(); // "controls"
512 nlist = nlist.front()->children ();
514 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
516 if ((prop = (*niter)->property ("id")) != 0) {
518 ID id = prop->value ();
519 c = session->controllable_by_id (id);
522 MIDIControllable* mc = new MIDIControllable (*_port, *c);
524 if (mc->set_state (**niter, version) == 0) {
525 controllables.push_back (mc);
529 warning << string_compose (
530 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
538 if ((prop = node.property ("binding")) != 0) {
539 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
540 if (prop->value() == (*x).name) {
541 load_bindings ((*x).path);
551 GenericMidiControlProtocol::set_feedback (bool yn)
554 last_feedback_time = 0;
559 GenericMidiControlProtocol::get_feedback () const
568 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
572 if (!state_tree.read (xmlpath.c_str())) {
573 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
577 XMLNode* root = state_tree.root();
579 if (root->name() != X_("ArdourMIDIBindings")) {
580 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
584 const XMLProperty* prop;
586 if ((prop = root->property ("version")) == 0) {
593 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
594 Stateful::loading_state_version = (major * 1000) + minor;
597 const XMLNodeList& children (root->children());
598 XMLNodeConstIterator citer;
599 XMLNodeConstIterator gciter;
601 MIDIControllable* mc;
605 for (citer = children.begin(); citer != children.end(); ++citer) {
607 if ((*citer)->name() == "DeviceInfo") {
608 const XMLProperty* prop;
610 if ((prop = (*citer)->property ("bank-size")) != 0) {
611 _bank_size = atoi (prop->value());
616 if ((*citer)->name() == "Binding") {
617 const XMLNode* child = *citer;
619 if (child->property ("uri")) {
622 if ((mc = create_binding (*child)) != 0) {
623 Glib::Mutex::Lock lm2 (controllables_lock);
624 controllables.push_back (mc);
627 } else if (child->property ("function")) {
632 if ((mf = create_function (*child)) != 0) {
633 functions.push_back (mf);
639 if ((prop = root->property ("name")) != 0) {
640 _current_binding = prop->value ();
643 reset_controllables ();
649 GenericMidiControlProtocol::create_binding (const XMLNode& node)
651 const XMLProperty* prop;
653 MIDI::channel_t channel;
658 if ((prop = node.property (X_("ctl"))) != 0) {
659 ev = MIDI::controller;
660 } else if ((prop = node.property (X_("note"))) != 0) {
662 } else if ((prop = node.property (X_("pgm"))) != 0) {
668 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
672 detail = (MIDI::byte) intval;
674 if ((prop = node.property (X_("channel"))) == 0) {
678 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
681 channel = (MIDI::channel_t) intval;
682 /* adjust channel to zero-based counting */
687 prop = node.property (X_("uri"));
690 MIDIControllable* mc = new MIDIControllable (*_port, false);
692 if (mc->init (uri)) {
697 mc->bind_midi (channel, ev, detail);
699 cerr << "New MC with URI " << uri << " on channel " << (int) channel << " detail = " << (int) detail << endl;
705 GenericMidiControlProtocol::reset_controllables ()
708 Glib::Mutex::Lock lm2 (controllables_lock);
710 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
711 MIDIControllable* existingBinding = (*iter);
713 if (!existingBinding->learned()) {
714 uint32_t rid = existingBinding->rid();
715 if (existingBinding->bank_relative()) {
716 rid += _current_bank * _bank_size;
718 boost::shared_ptr<Controllable> c = session->controllable_by_rid_and_name (rid, existingBinding->what().c_str());
719 existingBinding->set_controllable (c.get());
725 GenericMidiControlProtocol::create_function (const XMLNode& node)
727 const XMLProperty* prop;
729 MIDI::byte detail = 0;
730 MIDI::channel_t channel = 0;
733 MIDI::byte* sysex = 0;
734 uint32_t sysex_size = 0;
736 if ((prop = node.property (X_("ctl"))) != 0) {
737 ev = MIDI::controller;
738 } else if ((prop = node.property (X_("note"))) != 0) {
740 } else if ((prop = node.property (X_("pgm"))) != 0) {
742 } else if ((prop = node.property (X_("sysex"))) != 0) {
750 stringstream ss (prop->value());
762 sysex = new MIDI::byte[cnt];
766 stringstream ss (prop->value());
771 sysex[cnt++] = (MIDI::byte) val;
776 warning << "Binding ignored - unknown type" << endmsg;
780 if (sysex_size == 0) {
781 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
785 detail = (MIDI::byte) intval;
787 if ((prop = node.property (X_("channel"))) == 0) {
791 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
794 channel = (MIDI::channel_t) intval;
795 /* adjust channel to zero-based counting */
801 prop = node.property (X_("function"));
803 MIDIFunction* mf = new MIDIFunction (*_port);
805 if (mf->init (*this, prop->value(), sysex, sysex_size)) {
810 cerr << "New MF with function = " << prop->value() << " on channel " << (int) channel << " detail = " << (int) detail << endl;
811 mf->bind_midi (channel, ev, detail);
818 GenericMidiControlProtocol::set_current_bank (uint32_t b)
821 reset_controllables ();
825 GenericMidiControlProtocol::next_bank ()
828 reset_controllables ();
832 GenericMidiControlProtocol::prev_bank()
836 reset_controllables ();