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) {
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());
585 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
586 node.add_property (X_("feedback_interval"), buf);
587 snprintf (buf, sizeof (buf), "%d", _threshold);
588 node.add_property (X_("threshold"), buf);
590 node.add_property (X_("motorized"), _motorised ? "yes" : "no");
592 if (!_current_binding.empty()) {
593 node.add_property ("binding", _current_binding);
596 XMLNode* children = new XMLNode (X_("Controls"));
598 node.add_child_nocopy (*children);
600 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
601 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
603 /* we don't care about bindings that come from a bindings map, because
604 they will all be reset/recreated when we load the relevant bindings
608 if ((*i)->get_controllable() && (*i)->learned()) {
609 children->add_child_nocopy ((*i)->get_state());
617 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
620 XMLNodeConstIterator niter;
621 const XMLProperty* prop;
623 if (ControlProtocol::set_state (node, version)) {
627 if ((prop = node.property ("feedback_interval")) != 0) {
628 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
629 _feedback_interval = 10000;
632 _feedback_interval = 10000;
635 if ((prop = node.property ("threshold")) != 0) {
636 if (sscanf (prop->value().c_str(), "%d", &_threshold) != 1) {
643 if ((prop = node.property ("motorized")) != 0) {
644 _motorised = string_is_affirmative (prop->value ());
649 boost::shared_ptr<Controllable> c;
652 Glib::Threads::Mutex::Lock lm (pending_lock);
653 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
654 (*i)->connection.disconnect();
660 pending_controllables.clear ();
663 // midi map has to be loaded first so learned binding can go on top
664 if ((prop = node.property ("binding")) != 0) {
665 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
666 if (prop->value() == (*x).name) {
667 load_bindings ((*x).path);
673 /* Load up specific bindings from the
674 * <Controls><MidiControllable>...</MidiControllable><Controls> section
678 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
679 nlist = node.children(); // "Controls"
681 if (!nlist.empty()) {
682 nlist = nlist.front()->children(); // "MIDIControllable" ...
684 if (!nlist.empty()) {
685 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
687 if ((prop = (*niter)->property ("id")) != 0) {
689 ID id = prop->value ();
690 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Relearned binding for session: Control ID: %1\n", id.to_s()));
691 Controllable* c = Controllable::by_id (id);
694 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
696 if (mc->set_state (**niter, version) == 0) {
697 controllables.push_back (mc);
699 warning << string_compose ("Generic MIDI control: Failed to set state for Control ID: %1\n", id.to_s());
704 warning << string_compose (
705 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
706 id.to_s()) << endmsg;
718 GenericMidiControlProtocol::set_feedback (bool yn)
721 last_feedback_time = 0;
726 GenericMidiControlProtocol::get_feedback () const
732 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
734 DEBUG_TRACE (DEBUG::GenericMidi, "Load bindings: Reading midi map\n");
737 if (!state_tree.read (xmlpath.c_str())) {
738 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
742 XMLNode* root = state_tree.root();
744 if (root->name() != X_("ArdourMIDIBindings")) {
745 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
749 const XMLProperty* prop;
751 if ((prop = root->property ("version")) == 0) {
755 const XMLNodeList& children (root->children());
756 XMLNodeConstIterator citer;
757 XMLNodeConstIterator gciter;
759 MIDIControllable* mc;
763 DEBUG_TRACE (DEBUG::GenericMidi, "Loading bindings\n");
764 for (citer = children.begin(); citer != children.end(); ++citer) {
766 if ((*citer)->name() == "DeviceInfo") {
767 const XMLProperty* prop;
769 if ((prop = (*citer)->property ("bank-size")) != 0) {
770 _bank_size = atoi (prop->value());
774 if ((prop = (*citer)->property ("motorized")) != 0) {
775 _motorised = string_is_affirmative (prop->value ());
780 if ((prop = (*citer)->property ("threshold")) != 0) {
781 _threshold = atoi (prop->value ());
788 if ((*citer)->name() == "Binding") {
789 const XMLNode* child = *citer;
791 if (child->property ("uri")) {
794 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
795 if ((mc = create_binding (*child)) != 0) {
796 controllables.push_back (mc);
799 } else if (child->property ("function")) {
804 if ((mf = create_function (*child)) != 0) {
805 functions.push_back (mf);
808 } else if (child->property ("action")) {
811 if ((ma = create_action (*child)) != 0) {
812 actions.push_back (ma);
818 if ((prop = root->property ("name")) != 0) {
819 _current_binding = prop->value ();
822 reset_controllables ();
828 GenericMidiControlProtocol::create_binding (const XMLNode& node)
830 const XMLProperty* prop;
832 MIDI::channel_t channel;
837 MIDIControllable::Encoder encoder = MIDIControllable::No_enc;
838 bool rpn_value = false;
839 bool nrpn_value = false;
840 bool rpn_change = false;
841 bool nrpn_change = false;
843 if ((prop = node.property (X_("ctl"))) != 0) {
844 ev = MIDI::controller;
845 } else if ((prop = node.property (X_("note"))) != 0) {
847 } else if ((prop = node.property (X_("pgm"))) != 0) {
849 } else if ((prop = node.property (X_("pb"))) != 0) {
850 ev = MIDI::pitchbend;
851 } else if ((prop = node.property (X_("enc-l"))) != 0) {
852 encoder = MIDIControllable::Enc_L;
853 ev = MIDI::controller;
854 } else if ((prop = node.property (X_("enc-r"))) != 0) {
855 encoder = MIDIControllable::Enc_R;
856 ev = MIDI::controller;
857 } else if ((prop = node.property (X_("enc-2"))) != 0) {
858 encoder = MIDIControllable::Enc_2;
859 ev = MIDI::controller;
860 } else if ((prop = node.property (X_("enc-b"))) != 0) {
861 encoder = MIDIControllable::Enc_B;
862 ev = MIDI::controller;
863 } else if ((prop = node.property (X_("rpn"))) != 0) {
865 } else if ((prop = node.property (X_("nrpn"))) != 0) {
867 } else if ((prop = node.property (X_("rpn-delta"))) != 0) {
869 } else if ((prop = node.property (X_("nrpn-delta"))) != 0) {
875 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
879 detail = (MIDI::byte) intval;
881 if ((prop = node.property (X_("channel"))) == 0) {
885 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
888 channel = (MIDI::channel_t) intval;
889 /* adjust channel to zero-based counting */
894 if ((prop = node.property (X_("momentary"))) != 0) {
895 momentary = string_is_affirmative (prop->value());
900 prop = node.property (X_("uri"));
903 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary);
905 if (mc->init (uri)) {
911 mc->bind_rpn_value (channel, detail);
912 } else if (nrpn_value) {
913 mc->bind_nrpn_value (channel, detail);
914 } else if (rpn_change) {
915 mc->bind_rpn_change (channel, detail);
916 } else if (nrpn_change) {
917 mc->bind_nrpn_change (channel, detail);
919 mc->set_encoder (encoder);
920 mc->bind_midi (channel, ev, detail);
927 GenericMidiControlProtocol::reset_controllables ()
929 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
931 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
932 MIDIControllable* existingBinding = (*iter);
933 MIDIControllables::iterator next = iter;
936 if (!existingBinding->learned()) {
937 ControllableDescriptor& desc (existingBinding->descriptor());
940 desc.set_bank_offset (_current_bank * _bank_size);
943 /* its entirely possible that the session doesn't have
944 * the specified controllable (e.g. it has too few
945 * tracks). if we find this to be the case, we just leave
946 * the binding around, unbound, and it will do "late
947 * binding" (or "lazy binding") if/when any data arrives.
950 existingBinding->lookup_controllable ();
957 boost::shared_ptr<Controllable>
958 GenericMidiControlProtocol::lookup_controllable (const ControllableDescriptor& desc) const
960 return session->controllable_by_descriptor (desc);
964 GenericMidiControlProtocol::create_function (const XMLNode& node)
966 const XMLProperty* prop;
968 MIDI::byte detail = 0;
969 MIDI::channel_t channel = 0;
972 MIDI::byte* data = 0;
973 uint32_t data_size = 0;
976 if ((prop = node.property (X_("ctl"))) != 0) {
977 ev = MIDI::controller;
978 } else if ((prop = node.property (X_("note"))) != 0) {
980 } else if ((prop = node.property (X_("pgm"))) != 0) {
982 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
984 if (prop->name() == X_("sysex")) {
995 stringstream ss (prop->value());
1007 data = new MIDI::byte[cnt];
1011 stringstream ss (prop->value());
1016 data[cnt++] = (MIDI::byte) val;
1021 warning << "Binding ignored - unknown type" << endmsg;
1025 if (data_size == 0) {
1026 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1030 detail = (MIDI::byte) intval;
1032 if ((prop = node.property (X_("channel"))) == 0) {
1036 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1039 channel = (MIDI::channel_t) intval;
1040 /* adjust channel to zero-based counting */
1046 if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
1047 argument = prop->value ();
1050 prop = node.property (X_("function"));
1052 MIDIFunction* mf = new MIDIFunction (*_input_port->parser());
1054 if (mf->setup (*this, prop->value(), argument, data, data_size)) {
1059 mf->bind_midi (channel, ev, detail);
1065 GenericMidiControlProtocol::create_action (const XMLNode& node)
1067 const XMLProperty* prop;
1069 MIDI::byte detail = 0;
1070 MIDI::channel_t channel = 0;
1073 MIDI::byte* data = 0;
1074 uint32_t data_size = 0;
1076 if ((prop = node.property (X_("ctl"))) != 0) {
1077 ev = MIDI::controller;
1078 } else if ((prop = node.property (X_("note"))) != 0) {
1080 } else if ((prop = node.property (X_("pgm"))) != 0) {
1082 } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
1084 if (prop->name() == X_("sysex")) {
1095 stringstream ss (prop->value());
1107 data = new MIDI::byte[cnt];
1111 stringstream ss (prop->value());
1116 data[cnt++] = (MIDI::byte) val;
1121 warning << "Binding ignored - unknown type" << endmsg;
1125 if (data_size == 0) {
1126 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1130 detail = (MIDI::byte) intval;
1132 if ((prop = node.property (X_("channel"))) == 0) {
1136 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1139 channel = (MIDI::channel_t) intval;
1140 /* adjust channel to zero-based counting */
1146 prop = node.property (X_("action"));
1148 MIDIAction* ma = new MIDIAction (*_input_port->parser());
1150 if (ma->init (*this, prop->value(), data, data_size)) {
1155 ma->bind_midi (channel, ev, detail);
1161 GenericMidiControlProtocol::set_current_bank (uint32_t b)
1164 reset_controllables ();
1168 GenericMidiControlProtocol::next_bank ()
1171 reset_controllables ();
1175 GenericMidiControlProtocol::prev_bank()
1177 if (_current_bank) {
1179 reset_controllables ();
1184 GenericMidiControlProtocol::set_motorised (bool m)
1190 GenericMidiControlProtocol::set_threshold (int t)
1196 GenericMidiControlProtocol::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
1198 if (!_input_port || !_output_port) {
1202 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
1203 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
1205 if (ni == name1 || ni == name2) {
1207 connection_state |= InputConnected;
1209 connection_state &= ~InputConnected;
1211 } else if (no == name1 || no == name2) {
1213 connection_state |= OutputConnected;
1215 connection_state &= ~OutputConnected;
1222 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
1224 /* XXX this is a horrible hack. Without a short sleep here,
1225 something prevents the device wakeup messages from being
1226 sent and/or the responses from being received.
1236 ConnectionChange (); /* emit signal for our GUI */
1238 return true; /* connection status changed */
1242 GenericMidiControlProtocol::connected ()
1244 cerr << "Now connected\n";
1247 boost::shared_ptr<Port>
1248 GenericMidiControlProtocol::output_port() const
1250 return _output_port;
1253 boost::shared_ptr<Port>
1254 GenericMidiControlProtocol::input_port() const
1260 GenericMidiControlProtocol::maybe_start_touch (Controllable* controllable)
1262 AutomationControl *actl = dynamic_cast<AutomationControl*> (controllable);
1264 if (actl->automation_state() == Touch && !actl->touching()) {
1265 actl->start_touch (session->audible_frame ());