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.
25 #include <glibmm/fileutils.h>
26 #include <glibmm/miscutils.h>
28 #include "pbd/error.h"
29 #include "pbd/failed_constructor.h"
30 #include "pbd/file_utils.h"
31 #include "pbd/xml++.h"
32 #include "pbd/compose.h"
34 #include "midi++/port.h"
36 #include "ardour/async_midi_port.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/audioengine.h"
39 #include "ardour/controllable_descriptor.h"
40 #include "ardour/filesystem_paths.h"
41 #include "ardour/session.h"
42 #include "ardour/midi_ui.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/midiport_manager.h"
45 #include "ardour/debug.h"
47 #include "generic_midi_control_protocol.h"
48 #include "midicontrollable.h"
49 #include "midifunction.h"
50 #include "midiaction.h"
52 using namespace ARDOUR;
58 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
60 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
61 : ControlProtocol (s, _("Generic MIDI"))
62 , connection_state (ConnectionState (0))
67 _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort> (s.midi_input_port ());
68 _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort> (s.midi_output_port ());
70 _input_bundle.reset (new ARDOUR::Bundle (_("Generic MIDI Control In"), true));
71 _output_bundle.reset (new ARDOUR::Bundle (_("Generic MIDI Control Out"), false));
73 _input_bundle->add_channel (
74 boost::static_pointer_cast<MidiPort>(_input_port)->name(),
75 ARDOUR::DataType::MIDI,
76 session->engine().make_port_name_non_relative (boost::static_pointer_cast<MidiPort>(_input_port)->name())
79 _output_bundle->add_channel (
80 boost::static_pointer_cast<MidiPort>(_output_port)->name(),
81 ARDOUR::DataType::MIDI,
82 session->engine().make_port_name_non_relative (boost::static_pointer_cast<MidiPort>(_output_port)->name())
85 session->BundleAddedOrRemoved ();
88 _feedback_interval = 10000; // microseconds
89 last_feedback_time = 0;
94 /* these signals are emitted by the MidiControlUI's event loop thread
95 * and we may as well handle them right there in the same the same
99 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
100 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
101 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
102 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
104 /* this signal is emitted by the process() callback, and if
105 * send_feedback() is going to do anything, it should do it in the
106 * context of the process() callback itself.
109 Session::SendFeedback.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this));
110 //Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
112 /* this one is cross-thread */
114 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
116 /* Catch port connections and disconnections (cross-thread) */
117 ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR,
118 boost::bind (&GenericMidiControlProtocol::connection_handler, this, _1, _2, _3, _4, _5),
124 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
130 list<boost::shared_ptr<ARDOUR::Bundle> >
131 GenericMidiControlProtocol::bundles ()
133 list<boost::shared_ptr<ARDOUR::Bundle> > b;
136 b.push_back (_input_bundle);
137 b.push_back (_output_bundle);
144 static const char * const midimap_env_variable_name = "ARDOUR_MIDIMAPS_PATH";
145 static const char* const midi_map_dir_name = "midi_maps";
146 static const char* const midi_map_suffix = ".map";
149 system_midi_map_search_path ()
151 bool midimap_path_defined = false;
152 std::string spath_env (Glib::getenv (midimap_env_variable_name, midimap_path_defined));
154 if (midimap_path_defined) {
158 Searchpath spath (ardour_data_search_path());
159 spath.add_subdirectory_to_paths(midi_map_dir_name);
164 user_midi_map_directory ()
166 return Glib::build_filename (user_config_directory(), midi_map_dir_name);
170 midi_map_filter (const string &str, void* /*arg*/)
172 return (str.length() > strlen(midi_map_suffix) &&
173 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
177 GenericMidiControlProtocol::reload_maps ()
179 vector<string> midi_maps;
180 Searchpath spath (system_midi_map_search_path());
181 spath += user_midi_map_directory ();
183 find_files_matching_filter (midi_maps, spath, midi_map_filter, 0, false, true);
185 if (midi_maps.empty()) {
186 cerr << "No MIDI maps found using " << spath.to_string() << endl;
190 for (vector<string>::iterator i = midi_maps.begin(); i != midi_maps.end(); ++i) {
191 string fullpath = *i;
195 if (!tree.read (fullpath.c_str())) {
201 XMLProperty const * prop = tree.root()->property ("name");
207 mi.name = prop->value ();
210 map_info.push_back (mi);
215 GenericMidiControlProtocol::drop_all ()
217 DEBUG_TRACE (DEBUG::GenericMidi, "Drop all bindings\n");
218 Glib::Threads::Mutex::Lock lm (pending_lock);
219 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
221 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
224 controllables.clear ();
226 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
229 pending_controllables.clear ();
231 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
236 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
243 GenericMidiControlProtocol::drop_bindings ()
245 DEBUG_TRACE (DEBUG::GenericMidi, "Drop bindings, leave learned\n");
246 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
248 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
249 if (!(*i)->learned()) {
251 i = controllables.erase (i);
257 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
262 _current_binding = "";
268 GenericMidiControlProtocol::set_active (bool /*yn*/)
270 /* nothing to do here: the MIDI UI thread in libardour handles all our
277 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
279 _feedback_interval = ms;
283 GenericMidiControlProtocol::send_feedback ()
285 /* This is executed in RT "process" context", so no blocking calls
292 microseconds_t now = get_microseconds ();
294 if (last_feedback_time != 0) {
295 if ((now - last_feedback_time) < _feedback_interval) {
302 last_feedback_time = now;
306 GenericMidiControlProtocol::_send_feedback ()
308 /* This is executed in RT "process" context", so no blocking calls
311 const int32_t bufsize = 16 * 1024; /* XXX too big */
312 MIDI::byte buf[bufsize];
313 int32_t bsize = bufsize;
315 /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
316 writes for each controllable here; if we send more than one MIDI message
317 in a single jack_midi_event_write then some bridges will only pass the
321 Glib::Threads::Mutex::Lock lm (controllables_lock, Glib::Threads::TRY_LOCK);
326 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
327 MIDI::byte* end = (*r)->write_feedback (buf, bsize);
329 _output_port->write (buf, (int32_t) (end - buf), 0);
335 GenericMidiControlProtocol::start_learning (Controllable* c)
341 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
342 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Learn binding: Controlable number: %1\n", c));
344 MIDIControllables::iterator tmp;
345 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
348 if ((*i)->get_controllable() == c) {
350 controllables.erase (i);
356 Glib::Threads::Mutex::Lock lm (pending_lock);
358 MIDIPendingControllables::iterator ptmp;
359 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
362 if (((*i)->mc)->get_controllable() == c) {
366 (*i)->connection.disconnect();
368 pending_controllables.erase (i);
374 MIDIControllable* mc = 0;
377 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
378 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
385 mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
390 Glib::Threads::Mutex::Lock lm (pending_lock);
392 MIDIPendingControllable* element = new MIDIPendingControllable (mc, own_mc);
393 c->LearningFinished.connect_same_thread (element->connection, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
395 pending_controllables.push_back (element);
397 mc->learn_about_external_control ();
402 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
404 Glib::Threads::Mutex::Lock lm (pending_lock);
405 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
407 MIDIPendingControllables::iterator tmp;
409 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
413 if ( (*i)->mc == mc) {
414 (*i)->connection.disconnect();
416 pending_controllables.erase(i);
422 controllables.push_back (mc);
426 GenericMidiControlProtocol::stop_learning (Controllable* c)
428 Glib::Threads::Mutex::Lock lm (pending_lock);
429 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
430 MIDIControllable* dptr = 0;
432 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
433 relevant MIDIControllable and remove it from the pending list.
436 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
437 if (((*i)->mc)->get_controllable() == c) {
438 (*i)->mc->stop_learning ();
440 (*i)->connection.disconnect();
443 pending_controllables.erase (i);
452 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
455 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
457 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
458 MIDIControllable* existingBinding = (*iter);
460 if (control == (existingBinding->get_controllable())) {
461 delete existingBinding;
462 iter = controllables.erase (iter);
471 // This next function seems unused
473 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
475 if (control != NULL) {
476 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
478 MIDI::channel_t channel = (pos & 0xf);
479 MIDI::byte value = control_number;
481 // Create a MIDIControllable
482 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *control, false);
484 // Remove any old binding for this midi channel/type/value pair
485 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
486 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
487 MIDIControllable* existingBinding = (*iter);
489 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
490 existingBinding->get_control_additional() == value &&
491 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
493 delete existingBinding;
494 iter = controllables.erase (iter);
501 // Update the MIDI Controllable based on the the pos param
502 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
503 mc->bind_midi(channel, MIDI::controller, value);
504 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Create binding: Channel: %1 Controller: %2 Value: %3 \n", channel, MIDI::controller, value));
505 controllables.push_back (mc);
510 GenericMidiControlProtocol::check_used_event (int pos, int control_number)
512 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
514 MIDI::channel_t channel = (pos & 0xf);
515 MIDI::byte value = control_number;
517 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("checking for used event: Channel: %1 Controller: %2 value: %3\n", (int) channel, (pos & 0xf0), (int) value));
519 // Remove any old binding for this midi channel/type/value pair
520 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
521 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
522 MIDIControllable* existingBinding = (*iter);
523 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
524 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
525 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
526 delete existingBinding;
527 iter = controllables.erase (iter);
536 for (MIDIFunctions::iterator iter = functions.begin(); iter != functions.end();) {
537 MIDIFunction* existingBinding = (*iter);
538 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
539 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
540 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
541 delete existingBinding;
542 iter = functions.erase (iter);
551 for (MIDIActions::iterator iter = actions.begin(); iter != actions.end();) {
552 MIDIAction* existingBinding = (*iter);
553 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
554 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
555 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
556 delete existingBinding;
557 iter = actions.erase (iter);
569 GenericMidiControlProtocol::get_state ()
571 XMLNode& node (ControlProtocol::get_state());
574 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
575 node.add_property (X_("feedback_interval"), buf);
576 snprintf (buf, sizeof (buf), "%d", _threshold);
577 node.add_property (X_("threshold"), buf);
579 node.add_property (X_("motorized"), _motorised ? "yes" : "no");
581 if (!_current_binding.empty()) {
582 node.add_property ("binding", _current_binding);
585 XMLNode* children = new XMLNode (X_("Controls"));
587 node.add_child_nocopy (*children);
589 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
590 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
592 /* we don't care about bindings that come from a bindings map, because
593 they will all be reset/recreated when we load the relevant bindings
597 if ((*i)->get_controllable() && (*i)->learned()) {
598 children->add_child_nocopy ((*i)->get_state());
606 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
609 XMLNodeConstIterator niter;
610 const XMLProperty* prop;
612 if (ControlProtocol::set_state (node, version)) {
616 if ((prop = node.property ("feedback_interval")) != 0) {
617 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
618 _feedback_interval = 10000;
621 _feedback_interval = 10000;
624 if ((prop = node.property ("threshold")) != 0) {
625 if (sscanf (prop->value().c_str(), "%d", &_threshold) != 1) {
632 if ((prop = node.property ("motorized")) != 0) {
633 _motorised = string_is_affirmative (prop->value ());
638 boost::shared_ptr<Controllable> c;
641 Glib::Threads::Mutex::Lock lm (pending_lock);
642 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
645 pending_controllables.clear ();
648 // midi map has to be loaded first so learned binding can go on top
649 if ((prop = node.property ("binding")) != 0) {
650 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
651 if (prop->value() == (*x).name) {
652 load_bindings ((*x).path);
658 /* Load up specific bindings from the
659 * <Controls><MidiControllable>...</MidiControllable><Controls> section
663 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
664 nlist = node.children(); // "Controls"
666 if (!nlist.empty()) {
667 nlist = nlist.front()->children(); // "MIDIControllable" ...
669 if (!nlist.empty()) {
670 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
672 if ((prop = (*niter)->property ("id")) != 0) {
674 ID id = prop->value ();
675 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Relearned binding for session: Control ID: %1\n", id.to_s()));
676 Controllable* c = Controllable::by_id (id);
679 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
681 if (mc->set_state (**niter, version) == 0) {
682 controllables.push_back (mc);
686 warning << string_compose (
687 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
688 id.to_s()) << endmsg;
700 GenericMidiControlProtocol::set_feedback (bool yn)
703 last_feedback_time = 0;
708 GenericMidiControlProtocol::get_feedback () const
714 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
716 DEBUG_TRACE (DEBUG::GenericMidi, "Load bindings: Reading midi map\n");
719 if (!state_tree.read (xmlpath.c_str())) {
720 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
724 XMLNode* root = state_tree.root();
726 if (root->name() != X_("ArdourMIDIBindings")) {
727 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
731 const XMLProperty* prop;
733 if ((prop = root->property ("version")) == 0) {
740 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
741 Stateful::loading_state_version = (major * 1000) + minor;
744 const XMLNodeList& children (root->children());
745 XMLNodeConstIterator citer;
746 XMLNodeConstIterator gciter;
748 MIDIControllable* mc;
752 DEBUG_TRACE (DEBUG::GenericMidi, "Loading bindings\n");
753 for (citer = children.begin(); citer != children.end(); ++citer) {
755 if ((*citer)->name() == "DeviceInfo") {
756 const XMLProperty* prop;
758 if ((prop = (*citer)->property ("bank-size")) != 0) {
759 _bank_size = atoi (prop->value());
763 if ((prop = (*citer)->property ("motorized")) != 0) {
764 _motorised = string_is_affirmative (prop->value ());
769 if ((prop = (*citer)->property ("threshold")) != 0) {
770 _threshold = atoi (prop->value ());
777 if ((*citer)->name() == "Binding") {
778 const XMLNode* child = *citer;
780 if (child->property ("uri")) {
783 if ((mc = create_binding (*child)) != 0) {
784 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
785 controllables.push_back (mc);
788 } else if (child->property ("function")) {
793 if ((mf = create_function (*child)) != 0) {
794 functions.push_back (mf);
797 } else if (child->property ("action")) {
800 if ((ma = create_action (*child)) != 0) {
801 actions.push_back (ma);
807 if ((prop = root->property ("name")) != 0) {
808 _current_binding = prop->value ();
811 reset_controllables ();
817 GenericMidiControlProtocol::create_binding (const XMLNode& node)
819 const XMLProperty* prop;
821 MIDI::channel_t channel;
826 MIDIControllable::Encoder encoder = MIDIControllable::No_enc;
827 bool rpn_value = false;
828 bool nrpn_value = false;
829 bool rpn_change = false;
830 bool nrpn_change = false;
832 if ((prop = node.property (X_("ctl"))) != 0) {
833 ev = MIDI::controller;
834 } else if ((prop = node.property (X_("note"))) != 0) {
836 } else if ((prop = node.property (X_("pgm"))) != 0) {
838 } else if ((prop = node.property (X_("pb"))) != 0) {
839 ev = MIDI::pitchbend;
840 } else if ((prop = node.property (X_("enc-l"))) != 0) {
841 encoder = MIDIControllable::Enc_L;
842 ev = MIDI::controller;
843 } else if ((prop = node.property (X_("enc-r"))) != 0) {
844 encoder = MIDIControllable::Enc_R;
845 ev = MIDI::controller;
846 } else if ((prop = node.property (X_("enc-2"))) != 0) {
847 encoder = MIDIControllable::Enc_2;
848 ev = MIDI::controller;
849 } else if ((prop = node.property (X_("enc-b"))) != 0) {
850 encoder = MIDIControllable::Enc_B;
851 ev = MIDI::controller;
852 } else if ((prop = node.property (X_("rpn"))) != 0) {
854 } else if ((prop = node.property (X_("nrpn"))) != 0) {
856 } else if ((prop = node.property (X_("rpn-delta"))) != 0) {
858 } else if ((prop = node.property (X_("nrpn-delta"))) != 0) {
864 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
868 detail = (MIDI::byte) intval;
870 if ((prop = node.property (X_("channel"))) == 0) {
874 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
877 channel = (MIDI::channel_t) intval;
878 /* adjust channel to zero-based counting */
883 if ((prop = node.property (X_("momentary"))) != 0) {
884 momentary = string_is_affirmative (prop->value());
889 prop = node.property (X_("uri"));
892 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary);
894 if (mc->init (uri)) {
900 mc->bind_rpn_value (channel, detail);
901 } else if (nrpn_value) {
902 mc->bind_nrpn_value (channel, detail);
903 } else if (rpn_change) {
904 mc->bind_rpn_change (channel, detail);
905 } else if (nrpn_change) {
906 mc->bind_nrpn_change (channel, detail);
908 mc->set_encoder (encoder);
909 mc->bind_midi (channel, ev, detail);
916 GenericMidiControlProtocol::reset_controllables ()
918 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
920 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
921 MIDIControllable* existingBinding = (*iter);
922 MIDIControllables::iterator next = iter;
925 if (!existingBinding->learned()) {
926 ControllableDescriptor& desc (existingBinding->descriptor());
929 desc.set_bank_offset (_current_bank * _bank_size);
932 /* its entirely possible that the session doesn't have
933 * the specified controllable (e.g. it has too few
934 * tracks). if we find this to be the case, we just leave
935 * the binding around, unbound, and it will do "late
936 * binding" (or "lazy binding") if/when any data arrives.
939 existingBinding->lookup_controllable ();
946 boost::shared_ptr<Controllable>
947 GenericMidiControlProtocol::lookup_controllable (const ControllableDescriptor& desc) const
949 return session->controllable_by_descriptor (desc);
953 GenericMidiControlProtocol::create_function (const XMLNode& node)
955 const XMLProperty* prop;
957 MIDI::byte detail = 0;
958 MIDI::channel_t channel = 0;
961 MIDI::byte* data = 0;
962 uint32_t data_size = 0;
965 if ((prop = node.property (X_("ctl"))) != 0) {
966 ev = MIDI::controller;
967 } else if ((prop = node.property (X_("note"))) != 0) {
969 } else if ((prop = node.property (X_("pgm"))) != 0) {
971 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
973 if (prop->name() == X_("sysex")) {
984 stringstream ss (prop->value());
996 data = new MIDI::byte[cnt];
1000 stringstream ss (prop->value());
1005 data[cnt++] = (MIDI::byte) val;
1010 warning << "Binding ignored - unknown type" << endmsg;
1014 if (data_size == 0) {
1015 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1019 detail = (MIDI::byte) intval;
1021 if ((prop = node.property (X_("channel"))) == 0) {
1025 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1028 channel = (MIDI::channel_t) intval;
1029 /* adjust channel to zero-based counting */
1035 if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
1036 argument = prop->value ();
1039 prop = node.property (X_("function"));
1041 MIDIFunction* mf = new MIDIFunction (*_input_port->parser());
1043 if (mf->setup (*this, prop->value(), argument, data, data_size)) {
1048 mf->bind_midi (channel, ev, detail);
1054 GenericMidiControlProtocol::create_action (const XMLNode& node)
1056 const XMLProperty* prop;
1058 MIDI::byte detail = 0;
1059 MIDI::channel_t channel = 0;
1062 MIDI::byte* data = 0;
1063 uint32_t data_size = 0;
1065 if ((prop = node.property (X_("ctl"))) != 0) {
1066 ev = MIDI::controller;
1067 } else if ((prop = node.property (X_("note"))) != 0) {
1069 } else if ((prop = node.property (X_("pgm"))) != 0) {
1071 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
1073 if (prop->name() == X_("sysex")) {
1084 stringstream ss (prop->value());
1096 data = new MIDI::byte[cnt];
1100 stringstream ss (prop->value());
1105 data[cnt++] = (MIDI::byte) val;
1110 warning << "Binding ignored - unknown type" << endmsg;
1114 if (data_size == 0) {
1115 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1119 detail = (MIDI::byte) intval;
1121 if ((prop = node.property (X_("channel"))) == 0) {
1125 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1128 channel = (MIDI::channel_t) intval;
1129 /* adjust channel to zero-based counting */
1135 prop = node.property (X_("action"));
1137 MIDIAction* ma = new MIDIAction (*_input_port->parser());
1139 if (ma->init (*this, prop->value(), data, data_size)) {
1144 ma->bind_midi (channel, ev, detail);
1150 GenericMidiControlProtocol::set_current_bank (uint32_t b)
1153 reset_controllables ();
1157 GenericMidiControlProtocol::next_bank ()
1160 reset_controllables ();
1164 GenericMidiControlProtocol::prev_bank()
1166 if (_current_bank) {
1168 reset_controllables ();
1173 GenericMidiControlProtocol::set_motorised (bool m)
1179 GenericMidiControlProtocol::set_threshold (int t)
1185 GenericMidiControlProtocol::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
1187 if (!_input_port || !_output_port) {
1191 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
1192 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
1194 if (ni == name1 || ni == name2) {
1196 connection_state |= InputConnected;
1198 connection_state &= ~InputConnected;
1200 } else if (no == name1 || no == name2) {
1202 connection_state |= OutputConnected;
1204 connection_state &= ~OutputConnected;
1211 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
1213 /* XXX this is a horrible hack. Without a short sleep here,
1214 something prevents the device wakeup messages from being
1215 sent and/or the responses from being received.
1225 ConnectionChange (); /* emit signal for our GUI */
1227 return true; /* connection status changed */
1231 GenericMidiControlProtocol::connected ()
1233 cerr << "Now connected\n";
1236 boost::shared_ptr<Port>
1237 GenericMidiControlProtocol::output_port() const
1239 return _output_port;
1242 boost::shared_ptr<Port>
1243 GenericMidiControlProtocol::input_port() const