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/types_convert.h"
32 #include "pbd/xml++.h"
33 #include "pbd/compose.h"
35 #include "midi++/port.h"
37 #include "ardour/async_midi_port.h"
38 #include "ardour/audioengine.h"
39 #include "ardour/audioengine.h"
40 #include "ardour/controllable_descriptor.h"
41 #include "ardour/filesystem_paths.h"
42 #include "ardour/session.h"
43 #include "ardour/midi_ui.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/midiport_manager.h"
46 #include "ardour/debug.h"
48 #include "generic_midi_control_protocol.h"
49 #include "midicontrollable.h"
50 #include "midifunction.h"
51 #include "midiaction.h"
53 using namespace ARDOUR;
59 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
61 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
62 : ControlProtocol (s, _("Generic MIDI"))
63 , connection_state (ConnectionState (0))
68 _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort> (s.midi_input_port ());
69 _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort> (s.midi_output_port ());
71 _input_bundle.reset (new ARDOUR::Bundle (_("Generic MIDI Control In"), true));
72 _output_bundle.reset (new ARDOUR::Bundle (_("Generic MIDI Control Out"), false));
74 _input_bundle->add_channel (
75 boost::static_pointer_cast<MidiPort>(_input_port)->name(),
76 ARDOUR::DataType::MIDI,
77 session->engine().make_port_name_non_relative (boost::static_pointer_cast<MidiPort>(_input_port)->name())
80 _output_bundle->add_channel (
81 boost::static_pointer_cast<MidiPort>(_output_port)->name(),
82 ARDOUR::DataType::MIDI,
83 session->engine().make_port_name_non_relative (boost::static_pointer_cast<MidiPort>(_output_port)->name())
86 session->BundleAddedOrRemoved ();
89 _feedback_interval = 10000; // microseconds
90 last_feedback_time = 0;
95 /* these signals are emitted by the MidiControlUI's event loop thread
96 * and we may as well handle them right there in the same the same
100 Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
101 Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
102 Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
103 Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
105 /* this signal is emitted by the process() callback, and if
106 * send_feedback() is going to do anything, it should do it in the
107 * context of the process() callback itself.
110 Session::SendFeedback.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this));
111 //Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
113 /* this one is cross-thread */
115 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
117 /* Catch port connections and disconnections (cross-thread) */
118 ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR,
119 boost::bind (&GenericMidiControlProtocol::connection_handler, this, _1, _2, _3, _4, _5),
125 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
131 list<boost::shared_ptr<ARDOUR::Bundle> >
132 GenericMidiControlProtocol::bundles ()
134 list<boost::shared_ptr<ARDOUR::Bundle> > b;
137 b.push_back (_input_bundle);
138 b.push_back (_output_bundle);
145 static const char * const midimap_env_variable_name = "ARDOUR_MIDIMAPS_PATH";
146 static const char* const midi_map_dir_name = "midi_maps";
147 static const char* const midi_map_suffix = ".map";
150 system_midi_map_search_path ()
152 bool midimap_path_defined = false;
153 std::string spath_env (Glib::getenv (midimap_env_variable_name, midimap_path_defined));
155 if (midimap_path_defined) {
159 Searchpath spath (ardour_data_search_path());
160 spath.add_subdirectory_to_paths(midi_map_dir_name);
165 user_midi_map_directory ()
167 return Glib::build_filename (user_config_directory(), midi_map_dir_name);
171 midi_map_filter (const string &str, void* /*arg*/)
173 return (str.length() > strlen(midi_map_suffix) &&
174 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
178 GenericMidiControlProtocol::reload_maps ()
180 vector<string> midi_maps;
181 Searchpath spath (system_midi_map_search_path());
182 spath += user_midi_map_directory ();
184 find_files_matching_filter (midi_maps, spath, midi_map_filter, 0, false, true);
186 if (midi_maps.empty()) {
187 cerr << "No MIDI maps found using " << spath.to_string() << endl;
191 for (vector<string>::iterator i = midi_maps.begin(); i != midi_maps.end(); ++i) {
192 string fullpath = *i;
196 if (!tree.read (fullpath.c_str())) {
203 if (!tree.root()->get_property ("name", str)) {
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) {
227 (*i)->connection.disconnect();
233 pending_controllables.clear ();
235 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
240 for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
247 GenericMidiControlProtocol::drop_bindings ()
249 DEBUG_TRACE (DEBUG::GenericMidi, "Drop bindings, leave learned\n");
250 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
252 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
253 if (!(*i)->learned()) {
255 i = controllables.erase (i);
261 for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
266 _current_binding = "";
272 GenericMidiControlProtocol::set_active (bool /*yn*/)
274 /* nothing to do here: the MIDI UI thread in libardour handles all our
281 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
283 _feedback_interval = ms;
287 GenericMidiControlProtocol::send_feedback ()
289 /* This is executed in RT "process" context", so no blocking calls
296 microseconds_t now = get_microseconds ();
298 if (last_feedback_time != 0) {
299 if ((now - last_feedback_time) < _feedback_interval) {
306 last_feedback_time = now;
310 GenericMidiControlProtocol::_send_feedback ()
312 /* This is executed in RT "process" context", so no blocking calls
315 const int32_t bufsize = 16 * 1024; /* XXX too big */
316 MIDI::byte buf[bufsize];
317 int32_t bsize = bufsize;
319 /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
320 writes for each controllable here; if we send more than one MIDI message
321 in a single jack_midi_event_write then some bridges will only pass the
325 Glib::Threads::Mutex::Lock lm (controllables_lock, Glib::Threads::TRY_LOCK);
330 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
331 MIDI::byte* end = (*r)->write_feedback (buf, bsize);
333 _output_port->write (buf, (int32_t) (end - buf), 0);
339 GenericMidiControlProtocol::start_learning (Controllable* c)
345 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
346 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Learn binding: Controlable number: %1\n", c));
348 /* drop any existing mappings for the same controllable for which
349 * learning has just started.
352 MIDIControllables::iterator tmp;
353 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
356 if ((*i)->get_controllable() == c) {
358 controllables.erase (i);
363 /* check pending controllables (those for which a learn is underway) to
364 * see if it is for the same one for which learning has just started.
368 Glib::Threads::Mutex::Lock lm (pending_lock);
370 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
371 if (((*i)->mc)->get_controllable() == c) {
372 (*i)->connection.disconnect();
377 i = pending_controllables.erase (i);
384 MIDIControllable* mc = 0;
387 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
388 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
395 mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
399 /* stuff the new controllable into pending */
402 Glib::Threads::Mutex::Lock lm (pending_lock);
404 MIDIPendingControllable* element = new MIDIPendingControllable (mc, own_mc);
405 c->LearningFinished.connect_same_thread (element->connection, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
407 pending_controllables.push_back (element);
409 mc->learn_about_external_control ();
414 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
416 Glib::Threads::Mutex::Lock lm (pending_lock);
417 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
419 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
420 if ( (*i)->mc == mc) {
421 (*i)->connection.disconnect();
423 i = pending_controllables.erase(i);
429 /* add the controllable for which learning stopped to our list of
433 controllables.push_back (mc);
437 GenericMidiControlProtocol::stop_learning (Controllable* c)
439 Glib::Threads::Mutex::Lock lm (pending_lock);
440 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
441 MIDIControllable* dptr = 0;
443 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
444 relevant MIDIControllable and remove it from the pending list.
447 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
448 if (((*i)->mc)->get_controllable() == c) {
449 (*i)->mc->stop_learning ();
451 (*i)->connection.disconnect();
454 pending_controllables.erase (i);
463 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
466 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
468 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
469 MIDIControllable* existingBinding = (*iter);
471 if (control == (existingBinding->get_controllable())) {
472 delete existingBinding;
473 iter = controllables.erase (iter);
482 // This next function seems unused
484 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
486 if (control != NULL) {
487 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
489 MIDI::channel_t channel = (pos & 0xf);
490 MIDI::byte value = control_number;
492 // Create a MIDIControllable
493 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *control, false);
495 // Remove any old binding for this midi channel/type/value pair
496 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
497 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
498 MIDIControllable* existingBinding = (*iter);
500 if ((existingBinding->get_control_channel() & 0xf ) == channel &&
501 existingBinding->get_control_additional() == value &&
502 (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
504 delete existingBinding;
505 iter = controllables.erase (iter);
512 // Update the MIDI Controllable based on the the pos param
513 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
514 mc->bind_midi(channel, MIDI::controller, value);
515 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Create binding: Channel: %1 Controller: %2 Value: %3 \n", channel, MIDI::controller, value));
516 controllables.push_back (mc);
521 GenericMidiControlProtocol::check_used_event (int pos, int control_number)
523 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
525 MIDI::channel_t channel = (pos & 0xf);
526 MIDI::byte value = control_number;
528 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("checking for used event: Channel: %1 Controller: %2 value: %3\n", (int) channel, (pos & 0xf0), (int) value));
530 // Remove any old binding for this midi channel/type/value pair
531 // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
532 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
533 MIDIControllable* existingBinding = (*iter);
534 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
535 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
536 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
537 delete existingBinding;
538 iter = controllables.erase (iter);
547 for (MIDIFunctions::iterator iter = functions.begin(); iter != functions.end();) {
548 MIDIFunction* existingBinding = (*iter);
549 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
550 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
551 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
552 delete existingBinding;
553 iter = functions.erase (iter);
562 for (MIDIActions::iterator iter = actions.begin(); iter != actions.end();) {
563 MIDIAction* existingBinding = (*iter);
564 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
565 if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
566 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
567 delete existingBinding;
568 iter = actions.erase (iter);
580 GenericMidiControlProtocol::get_state ()
582 XMLNode& node (ControlProtocol::get_state());
584 node.set_property (X_("feedback-interval"), _feedback_interval);
585 node.set_property (X_("threshold"), _threshold);
586 node.set_property (X_("motorized"), _motorised);
588 if (!_current_binding.empty()) {
589 node.set_property ("binding", _current_binding);
592 XMLNode* children = new XMLNode (X_("Controls"));
594 node.add_child_nocopy (*children);
596 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
597 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
599 /* we don't care about bindings that come from a bindings map, because
600 they will all be reset/recreated when we load the relevant bindings
604 if ((*i)->get_controllable() && (*i)->learned()) {
605 children->add_child_nocopy ((*i)->get_state());
613 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
616 XMLNodeConstIterator niter;
618 if (ControlProtocol::set_state (node, version)) {
622 if (!node.get_property ("feedback-interval", _feedback_interval)) {
623 _feedback_interval = 10000;
626 if (!node.get_property ("threshold", _threshold)) {
630 if (!node.get_property ("motorized", _motorised)) {
634 boost::shared_ptr<Controllable> c;
637 Glib::Threads::Mutex::Lock lm (pending_lock);
638 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
639 (*i)->connection.disconnect();
645 pending_controllables.clear ();
649 // midi map has to be loaded first so learned binding can go on top
650 if (node.get_property ("binding", str)) {
651 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
652 if (str == (*x).name) {
653 load_bindings ((*x).path);
659 /* Load up specific bindings from the
660 * <Controls><MidiControllable>...</MidiControllable><Controls> section
664 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
665 nlist = node.children(); // "Controls"
667 if (!nlist.empty()) {
668 nlist = nlist.front()->children(); // "MIDIControllable" ...
670 if (!nlist.empty()) {
671 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
674 if ((*niter)->get_property ("id", id)) {
676 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Relearned binding for session: Control ID: %1\n", id.to_s()));
677 Controllable* c = Controllable::by_id (id);
680 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
682 if (mc->set_state (**niter, version) == 0) {
683 controllables.push_back (mc);
685 warning << string_compose ("Generic MIDI control: Failed to set state for Control ID: %1\n", id.to_s());
690 warning << string_compose (
691 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
692 id.to_s()) << endmsg;
704 GenericMidiControlProtocol::set_feedback (bool yn)
707 last_feedback_time = 0;
712 GenericMidiControlProtocol::get_feedback () const
718 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
720 DEBUG_TRACE (DEBUG::GenericMidi, "Load bindings: Reading midi map\n");
723 if (!state_tree.read (xmlpath.c_str())) {
724 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
728 XMLNode* root = state_tree.root();
730 if (root->name() != X_("ArdourMIDIBindings")) {
731 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
735 const XMLProperty* prop;
737 if ((prop = root->property ("version")) == 0) {
741 const XMLNodeList& children (root->children());
742 XMLNodeConstIterator citer;
743 XMLNodeConstIterator gciter;
745 MIDIControllable* mc;
749 DEBUG_TRACE (DEBUG::GenericMidi, "Loading bindings\n");
750 for (citer = children.begin(); citer != children.end(); ++citer) {
752 if ((*citer)->name() == "DeviceInfo") {
754 if ((*citer)->get_property ("bank-size", _bank_size)) {
758 if (!(*citer)->get_property ("motorized", _motorised)) {
762 if (!(*citer)->get_property ("threshold", _threshold)) {
767 if ((*citer)->name() == "Binding") {
768 const XMLNode* child = *citer;
770 if (child->property ("uri")) {
773 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
774 if ((mc = create_binding (*child)) != 0) {
775 controllables.push_back (mc);
778 } else if (child->property ("function")) {
783 if ((mf = create_function (*child)) != 0) {
784 functions.push_back (mf);
787 } else if (child->property ("action")) {
790 if ((ma = create_action (*child)) != 0) {
791 actions.push_back (ma);
797 if ((prop = root->property ("name")) != 0) {
798 _current_binding = prop->value ();
801 reset_controllables ();
807 GenericMidiControlProtocol::create_binding (const XMLNode& node)
809 const XMLProperty* prop;
811 MIDI::channel_t channel;
816 MIDIControllable::Encoder encoder = MIDIControllable::No_enc;
817 bool rpn_value = false;
818 bool nrpn_value = false;
819 bool rpn_change = false;
820 bool nrpn_change = false;
822 if ((prop = node.property (X_("ctl"))) != 0) {
823 ev = MIDI::controller;
824 } else if ((prop = node.property (X_("note"))) != 0) {
826 } else if ((prop = node.property (X_("pgm"))) != 0) {
828 } else if ((prop = node.property (X_("pb"))) != 0) {
829 ev = MIDI::pitchbend;
830 } else if ((prop = node.property (X_("enc-l"))) != 0) {
831 encoder = MIDIControllable::Enc_L;
832 ev = MIDI::controller;
833 } else if ((prop = node.property (X_("enc-r"))) != 0) {
834 encoder = MIDIControllable::Enc_R;
835 ev = MIDI::controller;
836 } else if ((prop = node.property (X_("enc-2"))) != 0) {
837 encoder = MIDIControllable::Enc_2;
838 ev = MIDI::controller;
839 } else if ((prop = node.property (X_("enc-b"))) != 0) {
840 encoder = MIDIControllable::Enc_B;
841 ev = MIDI::controller;
842 } else if ((prop = node.property (X_("rpn"))) != 0) {
844 } else if ((prop = node.property (X_("nrpn"))) != 0) {
846 } else if ((prop = node.property (X_("rpn-delta"))) != 0) {
848 } else if ((prop = node.property (X_("nrpn-delta"))) != 0) {
854 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
858 detail = (MIDI::byte) intval;
860 if ((prop = node.property (X_("channel"))) == 0) {
864 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
867 channel = (MIDI::channel_t) intval;
868 /* adjust channel to zero-based counting */
873 if ((prop = node.property (X_("momentary"))) != 0) {
874 momentary = string_to<bool> (prop->value());
879 prop = node.property (X_("uri"));
882 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary);
884 if (mc->init (uri)) {
890 mc->bind_rpn_value (channel, detail);
891 } else if (nrpn_value) {
892 mc->bind_nrpn_value (channel, detail);
893 } else if (rpn_change) {
894 mc->bind_rpn_change (channel, detail);
895 } else if (nrpn_change) {
896 mc->bind_nrpn_change (channel, detail);
898 mc->set_encoder (encoder);
899 mc->bind_midi (channel, ev, detail);
906 GenericMidiControlProtocol::reset_controllables ()
908 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
910 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
911 MIDIControllable* existingBinding = (*iter);
912 MIDIControllables::iterator next = iter;
915 if (!existingBinding->learned()) {
916 ControllableDescriptor& desc (existingBinding->descriptor());
919 desc.set_bank_offset (_current_bank * _bank_size);
922 /* its entirely possible that the session doesn't have
923 * the specified controllable (e.g. it has too few
924 * tracks). if we find this to be the case, we just leave
925 * the binding around, unbound, and it will do "late
926 * binding" (or "lazy binding") if/when any data arrives.
929 existingBinding->lookup_controllable ();
936 boost::shared_ptr<Controllable>
937 GenericMidiControlProtocol::lookup_controllable (const ControllableDescriptor& desc) const
939 return session->controllable_by_descriptor (desc);
943 GenericMidiControlProtocol::create_function (const XMLNode& node)
945 const XMLProperty* prop;
947 MIDI::byte detail = 0;
948 MIDI::channel_t channel = 0;
951 MIDI::byte* data = 0;
952 uint32_t data_size = 0;
955 if ((prop = node.property (X_("ctl"))) != 0) {
956 ev = MIDI::controller;
957 } else if ((prop = node.property (X_("note"))) != 0) {
959 } else if ((prop = node.property (X_("pgm"))) != 0) {
961 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
963 if (prop->name() == X_("sysex")) {
974 stringstream ss (prop->value());
986 data = new MIDI::byte[cnt];
990 stringstream ss (prop->value());
995 data[cnt++] = (MIDI::byte) val;
1000 warning << "Binding ignored - unknown type" << endmsg;
1004 if (data_size == 0) {
1005 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1009 detail = (MIDI::byte) intval;
1011 if ((prop = node.property (X_("channel"))) == 0) {
1015 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1018 channel = (MIDI::channel_t) intval;
1019 /* adjust channel to zero-based counting */
1025 if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
1026 argument = prop->value ();
1029 prop = node.property (X_("function"));
1031 MIDIFunction* mf = new MIDIFunction (*_input_port->parser());
1033 if (mf->setup (*this, prop->value(), argument, data, data_size)) {
1038 mf->bind_midi (channel, ev, detail);
1044 GenericMidiControlProtocol::create_action (const XMLNode& node)
1046 const XMLProperty* prop;
1048 MIDI::byte detail = 0;
1049 MIDI::channel_t channel = 0;
1052 MIDI::byte* data = 0;
1053 uint32_t data_size = 0;
1055 if ((prop = node.property (X_("ctl"))) != 0) {
1056 ev = MIDI::controller;
1057 } else if ((prop = node.property (X_("note"))) != 0) {
1059 } else if ((prop = node.property (X_("pgm"))) != 0) {
1061 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
1063 if (prop->name() == X_("sysex")) {
1074 stringstream ss (prop->value());
1086 data = new MIDI::byte[cnt];
1090 stringstream ss (prop->value());
1095 data[cnt++] = (MIDI::byte) val;
1100 warning << "Binding ignored - unknown type" << endmsg;
1104 if (data_size == 0) {
1105 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1109 detail = (MIDI::byte) intval;
1111 if ((prop = node.property (X_("channel"))) == 0) {
1115 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1118 channel = (MIDI::channel_t) intval;
1119 /* adjust channel to zero-based counting */
1125 prop = node.property (X_("action"));
1127 MIDIAction* ma = new MIDIAction (*_input_port->parser());
1129 if (ma->init (*this, prop->value(), data, data_size)) {
1134 ma->bind_midi (channel, ev, detail);
1140 GenericMidiControlProtocol::set_current_bank (uint32_t b)
1143 reset_controllables ();
1147 GenericMidiControlProtocol::next_bank ()
1150 reset_controllables ();
1154 GenericMidiControlProtocol::prev_bank()
1156 if (_current_bank) {
1158 reset_controllables ();
1163 GenericMidiControlProtocol::set_motorised (bool m)
1169 GenericMidiControlProtocol::set_threshold (int t)
1175 GenericMidiControlProtocol::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
1177 if (!_input_port || !_output_port) {
1181 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
1182 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
1184 if (ni == name1 || ni == name2) {
1186 connection_state |= InputConnected;
1188 connection_state &= ~InputConnected;
1190 } else if (no == name1 || no == name2) {
1192 connection_state |= OutputConnected;
1194 connection_state &= ~OutputConnected;
1201 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
1203 /* XXX this is a horrible hack. Without a short sleep here,
1204 something prevents the device wakeup messages from being
1205 sent and/or the responses from being received.
1215 ConnectionChange (); /* emit signal for our GUI */
1217 return true; /* connection status changed */
1221 GenericMidiControlProtocol::connected ()
1223 cerr << "Now connected\n";
1226 boost::shared_ptr<Port>
1227 GenericMidiControlProtocol::output_port() const
1229 return _output_port;
1232 boost::shared_ptr<Port>
1233 GenericMidiControlProtocol::input_port() const
1239 GenericMidiControlProtocol::maybe_start_touch (Controllable* controllable)
1241 AutomationControl *actl = dynamic_cast<AutomationControl*> (controllable);
1243 if (actl->automation_state() == Touch && !actl->touching()) {
1244 actl->start_touch (session->audible_frame ());