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"
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 MIDI::Manager* mm = MIDI::Manager::instance();
61 /* XXX it might be nice to run "control" through i18n, but thats a bit tricky because
62 the name is defined in ardour.rc which is likely not internationalized.
65 _port = mm->port (Config->get_midi_port_name());
68 error << string_compose (_("no MIDI port named \"%1\" exists - generic MIDI control disabled"),
69 Config->get_midi_port_name())
71 throw failed_constructor();
75 _feedback_interval = 10000; // microseconds
76 last_feedback_time = 0;
81 /* XXX is it right to do all these in the same thread as whatever emits the signal? */
83 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
84 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
85 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
86 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
88 Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
89 Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
94 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
100 static const char* const midi_map_dir_name = "midi_maps";
101 static const char* const midi_map_suffix = ".map";
104 system_midi_map_search_path ()
106 SearchPath spath(system_data_search_path());
107 spath.add_subdirectory_to_paths(midi_map_dir_name);
109 // just return the first directory in the search path that exists
110 SearchPath::const_iterator i = std::find_if(spath.begin(), spath.end(), sys::exists);
112 if (i == spath.end()) return sys::path();
118 user_midi_map_directory ()
120 sys::path p(user_config_directory());
121 p /= midi_map_dir_name;
127 midi_map_filter (const string &str, void */*arg*/)
129 return (str.length() > strlen(midi_map_suffix) &&
130 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
134 GenericMidiControlProtocol::reload_maps ()
136 vector<string *> *midi_maps;
138 SearchPath spath (system_midi_map_search_path());
139 spath += user_midi_map_directory ();
141 midi_maps = scanner (spath.to_string(), midi_map_filter, 0, false, true);
144 cerr << "No MIDI maps found using " << spath.to_string() << endl;
148 cerr << "Found " << midi_maps->size() << " MIDI maps along " << spath.to_string() << endl;
150 for (vector<string*>::iterator i = midi_maps->begin(); i != midi_maps->end(); ++i) {
151 string fullpath = *(*i);
155 if (!tree.read (fullpath.c_str())) {
161 XMLProperty* prop = tree.root()->property ("name");
167 mi.name = prop->value ();
170 map_info.push_back (mi);
177 GenericMidiControlProtocol::drop_all ()
179 Glib::Mutex::Lock lm (pending_lock);
180 Glib::Mutex::Lock lm2 (controllables_lock);
182 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
185 controllables.clear ();
187 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
190 pending_controllables.clear ();
192 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
199 GenericMidiControlProtocol::drop_bindings ()
201 Glib::Mutex::Lock lm2 (controllables_lock);
203 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
204 if (!(*i)->learned()) {
206 i = controllables.erase (i);
212 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
217 _current_binding = "";
223 GenericMidiControlProtocol::set_active (bool /*yn*/)
225 /* start/stop delivery/outbound thread */
230 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
232 _feedback_interval = ms;
236 GenericMidiControlProtocol::send_feedback ()
242 microseconds_t now = get_microseconds ();
244 if (last_feedback_time != 0) {
245 if ((now - last_feedback_time) < _feedback_interval) {
252 last_feedback_time = now;
256 GenericMidiControlProtocol::_send_feedback ()
258 const int32_t bufsize = 16 * 1024; /* XXX too big */
259 MIDI::byte buf[bufsize];
260 int32_t bsize = bufsize;
261 MIDI::byte* end = buf;
263 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
264 end = (*r)->write_feedback (end, bsize);
271 _port->write (buf, (int32_t) (end - buf), 0);
275 GenericMidiControlProtocol::start_learning (Controllable* c)
281 Glib::Mutex::Lock lm2 (controllables_lock);
283 MIDIControllables::iterator tmp;
284 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
287 if ((*i)->get_controllable() == c) {
289 controllables.erase (i);
295 Glib::Mutex::Lock lm (pending_lock);
297 MIDIPendingControllables::iterator ptmp;
298 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
301 if (((*i)->first)->get_controllable() == c) {
302 (*i)->second.disconnect();
305 pending_controllables.erase (i);
311 MIDIControllable* mc = 0;
313 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
314 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
321 mc = new MIDIControllable (*_port, *c, false);
325 Glib::Mutex::Lock lm (pending_lock);
327 MIDIPendingControllable* element = new MIDIPendingControllable;
329 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
331 pending_controllables.push_back (element);
334 mc->learn_about_external_control ();
339 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
341 Glib::Mutex::Lock lm (pending_lock);
342 Glib::Mutex::Lock lm2 (controllables_lock);
344 MIDIPendingControllables::iterator tmp;
346 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
350 if ( (*i)->first == mc) {
351 (*i)->second.disconnect();
353 pending_controllables.erase(i);
359 controllables.push_back (mc);
363 GenericMidiControlProtocol::stop_learning (Controllable* c)
365 Glib::Mutex::Lock lm (pending_lock);
366 Glib::Mutex::Lock lm2 (controllables_lock);
367 MIDIControllable* dptr = 0;
369 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
370 relevant MIDIControllable and remove it from the pending list.
373 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
374 if (((*i)->first)->get_controllable() == c) {
375 (*i)->first->stop_learning ();
377 (*i)->second.disconnect();
380 pending_controllables.erase (i);
389 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
392 Glib::Mutex::Lock lm2 (controllables_lock);
394 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
395 MIDIControllable* existingBinding = (*iter);
397 if (control == (existingBinding->get_controllable())) {
398 delete existingBinding;
399 iter = controllables.erase (iter);
409 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
411 if (control != NULL) {
412 Glib::Mutex::Lock lm2 (controllables_lock);
414 MIDI::channel_t channel = (pos & 0xf);
415 MIDI::byte value = control_number;
417 // Create a MIDIControllable
418 MIDIControllable* mc = new MIDIControllable (*_port, *control, false);
420 // Remove any old binding for this midi channel/type/value pair
421 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
422 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
423 MIDIControllable* existingBinding = (*iter);
425 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
426 existingBinding->get_control_additional() == value &&
427 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
429 delete existingBinding;
430 iter = controllables.erase (iter);
437 // Update the MIDI Controllable based on the the pos param
438 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
439 mc->bind_midi(channel, MIDI::controller, value);
441 controllables.push_back (mc);
446 GenericMidiControlProtocol::get_state ()
448 XMLNode* node = new XMLNode ("Protocol");
451 node->add_property (X_("name"), _name);
452 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
453 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
454 node->add_property (X_("feedback_interval"), buf);
456 if (!_current_binding.empty()) {
457 node->add_property ("binding", _current_binding);
460 XMLNode* children = new XMLNode (X_("controls"));
462 node->add_child_nocopy (*children);
464 Glib::Mutex::Lock lm2 (controllables_lock);
465 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
467 /* we don't care about bindings that come from a bindings map, because
468 they will all be reset/recreated when we load the relevant bindings
472 if ((*i)->learned()) {
473 children->add_child_nocopy ((*i)->get_state());
481 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
484 XMLNodeConstIterator niter;
485 const XMLProperty* prop;
487 if ((prop = node.property ("feedback")) != 0) {
488 do_feedback = (bool) atoi (prop->value().c_str());
493 if ((prop = node.property ("feedback_interval")) != 0) {
494 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
495 _feedback_interval = 10000;
498 _feedback_interval = 10000;
501 boost::shared_ptr<Controllable> c;
504 Glib::Mutex::Lock lm (pending_lock);
505 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
508 pending_controllables.clear ();
512 Glib::Mutex::Lock lm2 (controllables_lock);
513 controllables.clear ();
514 nlist = node.children(); // "controls"
520 nlist = nlist.front()->children ();
522 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
524 if ((prop = (*niter)->property ("id")) != 0) {
526 ID id = prop->value ();
527 c = session->controllable_by_id (id);
530 MIDIControllable* mc = new MIDIControllable (*_port, *c, false);
532 if (mc->set_state (**niter, version) == 0) {
533 controllables.push_back (mc);
537 warning << string_compose (
538 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
546 if ((prop = node.property ("binding")) != 0) {
547 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
548 if (prop->value() == (*x).name) {
549 load_bindings ((*x).path);
559 GenericMidiControlProtocol::set_feedback (bool yn)
562 last_feedback_time = 0;
567 GenericMidiControlProtocol::get_feedback () const
576 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
580 if (!state_tree.read (xmlpath.c_str())) {
581 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
585 XMLNode* root = state_tree.root();
587 if (root->name() != X_("ArdourMIDIBindings")) {
588 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
592 const XMLProperty* prop;
594 if ((prop = root->property ("version")) == 0) {
601 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
602 Stateful::loading_state_version = (major * 1000) + minor;
605 const XMLNodeList& children (root->children());
606 XMLNodeConstIterator citer;
607 XMLNodeConstIterator gciter;
609 MIDIControllable* mc;
613 for (citer = children.begin(); citer != children.end(); ++citer) {
615 if ((*citer)->name() == "DeviceInfo") {
616 const XMLProperty* prop;
618 if ((prop = (*citer)->property ("bank-size")) != 0) {
619 _bank_size = atoi (prop->value());
624 if ((*citer)->name() == "Binding") {
625 const XMLNode* child = *citer;
627 if (child->property ("uri")) {
630 if ((mc = create_binding (*child)) != 0) {
631 Glib::Mutex::Lock lm2 (controllables_lock);
632 controllables.push_back (mc);
635 } else if (child->property ("function")) {
640 if ((mf = create_function (*child)) != 0) {
641 functions.push_back (mf);
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 (*_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* sysex = 0;
748 uint32_t sysex_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) {
764 stringstream ss (prop->value());
776 sysex = new MIDI::byte[cnt];
780 stringstream ss (prop->value());
785 sysex[cnt++] = (MIDI::byte) val;
790 warning << "Binding ignored - unknown type" << endmsg;
794 if (sysex_size == 0) {
795 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
799 detail = (MIDI::byte) intval;
801 if ((prop = node.property (X_("channel"))) == 0) {
805 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
808 channel = (MIDI::channel_t) intval;
809 /* adjust channel to zero-based counting */
815 prop = node.property (X_("function"));
817 MIDIFunction* mf = new MIDIFunction (*_port);
819 if (mf->init (*this, prop->value(), sysex, sysex_size)) {
824 mf->bind_midi (channel, ev, detail);
830 GenericMidiControlProtocol::set_current_bank (uint32_t b)
833 reset_controllables ();
837 GenericMidiControlProtocol::next_bank ()
840 reset_controllables ();
844 GenericMidiControlProtocol::prev_bank()
848 reset_controllables ();