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"
40 #include "generic_midi_control_protocol.h"
41 #include "midicontrollable.h"
42 #include "midifunction.h"
44 using namespace ARDOUR;
50 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
51 #define ui_bind(x) boost::protect (boost::bind ((x)))
53 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
54 : ControlProtocol (s, _("Generic MIDI"), midi_ui_context())
58 MIDI::Manager* mm = MIDI::Manager::instance();
60 /* XXX it might be nice to run "control" through i18n, but thats a bit tricky because
61 the name is defined in ardour.rc which is likely not internationalized.
64 _port = mm->port (X_("control"));
67 error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg;
68 throw failed_constructor();
72 _feedback_interval = 10000; // microseconds
73 last_feedback_time = 0;
78 /* XXX is it right to do all these in the same thread as whatever emits the signal? */
80 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
81 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
82 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
83 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
85 Session::SendFeedback.connect (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
86 Route::RemoteControlIDChange.connect (*this, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
91 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
97 static const char* const midi_map_dir_name = "midi_maps";
98 static const char* const midi_map_suffix = ".map";
101 system_midi_map_search_path ()
103 SearchPath spath(system_data_search_path());
104 spath.add_subdirectory_to_paths(midi_map_dir_name);
106 // just return the first directory in the search path that exists
107 SearchPath::const_iterator i = std::find_if(spath.begin(), spath.end(), sys::exists);
109 if (i == spath.end()) return sys::path();
115 user_midi_map_directory ()
117 sys::path p(user_config_directory());
118 p /= midi_map_dir_name;
124 midi_map_filter (const string &str, void */*arg*/)
126 return (str.length() > strlen(midi_map_suffix) &&
127 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
131 GenericMidiControlProtocol::reload_maps ()
133 vector<string *> *midi_maps;
135 SearchPath spath (system_midi_map_search_path());
136 spath += user_midi_map_directory ();
138 midi_maps = scanner (spath.to_string(), midi_map_filter, 0, false, true);
141 cerr << "No MIDI maps found using " << spath.to_string() << endl;
145 cerr << "Found " << midi_maps->size() << " MIDI maps along " << spath.to_string() << endl;
147 for (vector<string*>::iterator i = midi_maps->begin(); i != midi_maps->end(); ++i) {
148 string fullpath = *(*i);
152 if (!tree.read (fullpath.c_str())) {
158 XMLProperty* prop = tree.root()->property ("name");
164 mi.name = prop->value ();
167 map_info.push_back (mi);
174 GenericMidiControlProtocol::drop_all ()
176 Glib::Mutex::Lock lm (pending_lock);
177 Glib::Mutex::Lock lm2 (controllables_lock);
179 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
182 controllables.clear ();
184 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
187 pending_controllables.clear ();
189 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
196 GenericMidiControlProtocol::drop_bindings ()
198 Glib::Mutex::Lock lm2 (controllables_lock);
200 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
201 if (!(*i)->learned()) {
203 i = controllables.erase (i);
209 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
214 _current_binding = "";
220 GenericMidiControlProtocol::set_active (bool /*yn*/)
222 /* start/stop delivery/outbound thread */
227 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
229 _feedback_interval = ms;
233 GenericMidiControlProtocol::send_feedback ()
239 microseconds_t now = get_microseconds ();
241 if (last_feedback_time != 0) {
242 if ((now - last_feedback_time) < _feedback_interval) {
249 last_feedback_time = now;
253 GenericMidiControlProtocol::_send_feedback ()
255 const int32_t bufsize = 16 * 1024; /* XXX too big */
256 MIDI::byte buf[bufsize];
257 int32_t bsize = bufsize;
258 MIDI::byte* end = buf;
260 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
261 end = (*r)->write_feedback (end, bsize);
268 _port->write (buf, (int32_t) (end - buf), 0);
272 GenericMidiControlProtocol::start_learning (Controllable* c)
278 Glib::Mutex::Lock lm2 (controllables_lock);
280 MIDIControllables::iterator tmp;
281 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
284 if ((*i)->get_controllable() == c) {
286 controllables.erase (i);
292 Glib::Mutex::Lock lm (pending_lock);
294 MIDIPendingControllables::iterator ptmp;
295 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
298 if (((*i)->first)->get_controllable() == c) {
299 (*i)->second.disconnect();
302 pending_controllables.erase (i);
308 MIDIControllable* mc = 0;
310 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
311 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
318 mc = new MIDIControllable (*_port, *c, false);
322 Glib::Mutex::Lock lm (pending_lock);
324 MIDIPendingControllable* element = new MIDIPendingControllable;
326 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
328 pending_controllables.push_back (element);
331 mc->learn_about_external_control ();
336 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
338 Glib::Mutex::Lock lm (pending_lock);
339 Glib::Mutex::Lock lm2 (controllables_lock);
341 MIDIPendingControllables::iterator tmp;
343 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
347 if ( (*i)->first == mc) {
348 (*i)->second.disconnect();
350 pending_controllables.erase(i);
356 controllables.push_back (mc);
360 GenericMidiControlProtocol::stop_learning (Controllable* c)
362 Glib::Mutex::Lock lm (pending_lock);
363 Glib::Mutex::Lock lm2 (controllables_lock);
364 MIDIControllable* dptr = 0;
366 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
367 relevant MIDIControllable and remove it from the pending list.
370 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
371 if (((*i)->first)->get_controllable() == c) {
372 (*i)->first->stop_learning ();
374 (*i)->second.disconnect();
377 pending_controllables.erase (i);
386 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
389 Glib::Mutex::Lock lm2 (controllables_lock);
391 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
392 MIDIControllable* existingBinding = (*iter);
394 if (control == (existingBinding->get_controllable())) {
395 delete existingBinding;
396 controllables.erase (iter);
404 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
406 if (control != NULL) {
407 Glib::Mutex::Lock lm2 (controllables_lock);
409 MIDI::channel_t channel = (pos & 0xf);
410 MIDI::byte value = control_number;
412 // Create a MIDIControllable
413 MIDIControllable* mc = new MIDIControllable (*_port, *control, false);
415 // Remove any old binding for this midi channel/type/value pair
416 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
417 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
418 MIDIControllable* existingBinding = (*iter);
420 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
421 existingBinding->get_control_additional() == value &&
422 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
424 delete existingBinding;
425 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 (*_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);
640 if ((prop = root->property ("name")) != 0) {
641 _current_binding = prop->value ();
644 reset_controllables ();
650 GenericMidiControlProtocol::create_binding (const XMLNode& node)
652 const XMLProperty* prop;
654 MIDI::channel_t channel;
660 if ((prop = node.property (X_("ctl"))) != 0) {
661 ev = MIDI::controller;
662 } else if ((prop = node.property (X_("note"))) != 0) {
664 } else if ((prop = node.property (X_("pgm"))) != 0) {
670 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
674 detail = (MIDI::byte) intval;
676 if ((prop = node.property (X_("channel"))) == 0) {
680 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
683 channel = (MIDI::channel_t) intval;
684 /* adjust channel to zero-based counting */
689 if ((prop = node.property (X_("momentary"))) != 0) {
690 momentary = string_is_affirmative (prop->value());
695 prop = node.property (X_("uri"));
698 MIDIControllable* mc = new MIDIControllable (*_port, momentary);
700 if (mc->init (uri)) {
705 mc->bind_midi (channel, ev, detail);
711 GenericMidiControlProtocol::reset_controllables ()
713 Glib::Mutex::Lock lm2 (controllables_lock);
715 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
716 MIDIControllable* existingBinding = (*iter);
718 if (!existingBinding->learned()) {
719 ControllableDescriptor& desc (existingBinding->descriptor());
722 desc.set_bank_offset (_current_bank * _bank_size);
725 boost::shared_ptr<Controllable> c = session->controllable_by_descriptor (desc);
726 existingBinding->set_controllable (c.get());
732 GenericMidiControlProtocol::create_function (const XMLNode& node)
734 const XMLProperty* prop;
736 MIDI::byte detail = 0;
737 MIDI::channel_t channel = 0;
740 MIDI::byte* sysex = 0;
741 uint32_t sysex_size = 0;
743 if ((prop = node.property (X_("ctl"))) != 0) {
744 ev = MIDI::controller;
745 } else if ((prop = node.property (X_("note"))) != 0) {
747 } else if ((prop = node.property (X_("pgm"))) != 0) {
749 } else if ((prop = node.property (X_("sysex"))) != 0) {
757 stringstream ss (prop->value());
769 sysex = new MIDI::byte[cnt];
773 stringstream ss (prop->value());
778 sysex[cnt++] = (MIDI::byte) val;
783 warning << "Binding ignored - unknown type" << endmsg;
787 if (sysex_size == 0) {
788 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
792 detail = (MIDI::byte) intval;
794 if ((prop = node.property (X_("channel"))) == 0) {
798 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
801 channel = (MIDI::channel_t) intval;
802 /* adjust channel to zero-based counting */
808 prop = node.property (X_("function"));
810 MIDIFunction* mf = new MIDIFunction (*_port);
812 if (mf->init (*this, prop->value(), sysex, sysex_size)) {
817 mf->bind_midi (channel, ev, detail);
823 GenericMidiControlProtocol::set_current_bank (uint32_t b)
826 reset_controllables ();
830 GenericMidiControlProtocol::next_bank ()
833 reset_controllables ();
837 GenericMidiControlProtocol::prev_bank()
841 reset_controllables ();