214c9fede7cdb0ba6cba77ac50c301d2ef6da10f
[ardour.git] / generic_midi_control_protocol.cc
1 /*
2     Copyright (C) 2006 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <stdint.h>
21
22 #include <sstream>
23 #include <algorithm>
24
25 #ifdef COMPILER_MSVC
26 #include <io.h> // Microsoft's nearest equivalent to <unistd.h>
27 #include <ardourext/misc.h>
28 #else
29 #include <regex.h>
30 #endif
31
32 #include <glibmm/fileutils.h>
33 #include <glibmm/miscutils.h>
34
35 #include "pbd/compose.h"
36 #include "pbd/convert.h"
37 #include "pbd/error.h"
38 #include "pbd/failed_constructor.h"
39 #include "pbd/file_utils.h"
40 #include "pbd/strsplit.h"
41 #include "pbd/types_convert.h"
42 #include "pbd/xml++.h"
43
44 #include "midi++/port.h"
45
46 #include "ardour/async_midi_port.h"
47 #include "ardour/audioengine.h"
48 #include "ardour/auditioner.h"
49 #include "ardour/filesystem_paths.h"
50 #include "ardour/session.h"
51 #include "ardour/midi_ui.h"
52 #include "ardour/plugin_insert.h"
53 #include "ardour/rc_configuration.h"
54 #include "ardour/midiport_manager.h"
55 #include "ardour/debug.h"
56
57 #include "generic_midi_control_protocol.h"
58 #include "midicontrollable.h"
59 #include "midifunction.h"
60 #include "midiaction.h"
61
62 using namespace ARDOUR;
63 using namespace PBD;
64 using namespace std;
65
66 #include "pbd/i18n.h"
67
68 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
69
70 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
71         : ControlProtocol (s, _("Generic MIDI"))
72         , connection_state (ConnectionState (0))
73         , _motorised (false)
74         , _threshold (10)
75         , gui (0)
76 {
77         _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort> (s.midi_input_port ());
78         _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort> (s.midi_output_port ());
79
80         _input_bundle.reset (new ARDOUR::Bundle (_("Generic MIDI Control In"), true));
81         _output_bundle.reset (new ARDOUR::Bundle (_("Generic MIDI Control Out"), false));
82
83         _input_bundle->add_channel (
84                 boost::static_pointer_cast<MidiPort>(_input_port)->name(),
85                 ARDOUR::DataType::MIDI,
86                 session->engine().make_port_name_non_relative (boost::static_pointer_cast<MidiPort>(_input_port)->name())
87                 );
88
89         _output_bundle->add_channel (
90                 boost::static_pointer_cast<MidiPort>(_output_port)->name(),
91                 ARDOUR::DataType::MIDI,
92                 session->engine().make_port_name_non_relative (boost::static_pointer_cast<MidiPort>(_output_port)->name())
93                 );
94
95         session->BundleAddedOrRemoved ();
96
97         do_feedback = false;
98         _feedback_interval = 10000; // microseconds
99         last_feedback_time = 0;
100
101         _current_bank = 0;
102         _bank_size = 0;
103
104         /* these signals are emitted by the MidiControlUI's event loop thread
105          * and we may as well handle them right there in the same the same
106          * thread
107          */
108
109         Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
110         Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
111         Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
112         Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
113
114         /* this signal is emitted by the process() callback, and if
115          * send_feedback() is going to do anything, it should do it in the
116          * context of the process() callback itself.
117          */
118
119         Session::SendFeedback.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this));
120         //Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
121
122         /* this one is cross-thread */
123
124         PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
125
126         /* Catch port connections and disconnections (cross-thread) */
127         ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR,
128                                                                               boost::bind (&GenericMidiControlProtocol::connection_handler, this, _1, _2, _3, _4, _5),
129                                                                               midi_ui_context());
130
131         reload_maps ();
132 }
133
134 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
135 {
136         drop_all ();
137         tear_down_gui ();
138 }
139
140 list<boost::shared_ptr<ARDOUR::Bundle> >
141 GenericMidiControlProtocol::bundles ()
142 {
143         list<boost::shared_ptr<ARDOUR::Bundle> > b;
144
145         if (_input_bundle) {
146                 b.push_back (_input_bundle);
147                 b.push_back (_output_bundle);
148         }
149
150         return b;
151 }
152
153
154 static const char * const midimap_env_variable_name = "ARDOUR_MIDIMAPS_PATH";
155 static const char* const midi_map_dir_name = "midi_maps";
156 static const char* const midi_map_suffix = ".map";
157
158 Searchpath
159 system_midi_map_search_path ()
160 {
161         bool midimap_path_defined = false;
162         std::string spath_env (Glib::getenv (midimap_env_variable_name, midimap_path_defined));
163
164         if (midimap_path_defined) {
165                 return spath_env;
166         }
167
168         Searchpath spath (ardour_data_search_path());
169         spath.add_subdirectory_to_paths(midi_map_dir_name);
170         return spath;
171 }
172
173 static std::string
174 user_midi_map_directory ()
175 {
176         return Glib::build_filename (user_config_directory(), midi_map_dir_name);
177 }
178
179 static bool
180 midi_map_filter (const string &str, void* /*arg*/)
181 {
182         return (str.length() > strlen(midi_map_suffix) &&
183                 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
184 }
185
186 void
187 GenericMidiControlProtocol::reload_maps ()
188 {
189         vector<string> midi_maps;
190         Searchpath spath (system_midi_map_search_path());
191         spath += user_midi_map_directory ();
192
193         find_files_matching_filter (midi_maps, spath, midi_map_filter, 0, false, true);
194
195         if (midi_maps.empty()) {
196                 cerr << "No MIDI maps found using " << spath.to_string() << endl;
197                 return;
198         }
199
200         for (vector<string>::iterator i = midi_maps.begin(); i != midi_maps.end(); ++i) {
201                 string fullpath = *i;
202
203                 XMLTree tree;
204
205                 if (!tree.read (fullpath.c_str())) {
206                         continue;
207                 }
208
209                 MapInfo mi;
210
211                 std::string str;
212                 if (!tree.root()->get_property ("name", str)) {
213                         continue;
214                 }
215
216                 mi.name = str;
217                 mi.path = fullpath;
218
219                 map_info.push_back (mi);
220         }
221 }
222
223 void
224 GenericMidiControlProtocol::drop_all ()
225 {
226         DEBUG_TRACE (DEBUG::GenericMidi, "Drop all bindings\n");
227         Glib::Threads::Mutex::Lock lm (pending_lock);
228         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
229
230         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
231                 delete *i;
232         }
233         controllables.clear ();
234
235         for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
236                 (*i)->connection.disconnect();
237                 if ((*i)->own_mc) {
238                         delete (*i)->mc;
239                 }
240                 delete *i;
241         }
242         pending_controllables.clear ();
243
244         for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
245                 delete *i;
246         }
247         functions.clear ();
248
249         for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
250                 delete *i;
251         }
252         actions.clear ();
253 }
254
255 void
256 GenericMidiControlProtocol::drop_bindings ()
257 {
258         DEBUG_TRACE (DEBUG::GenericMidi, "Drop bindings, leave learned\n");
259         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
260
261         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
262                 if (!(*i)->learned()) {
263                         delete *i;
264                         i = controllables.erase (i);
265                 } else {
266                         ++i;
267                 }
268         }
269
270         for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
271                 delete *i;
272         }
273         functions.clear ();
274
275         _current_binding = "";
276         _bank_size = 0;
277         _current_bank = 0;
278 }
279
280 int
281 GenericMidiControlProtocol::set_active (bool /*yn*/)
282 {
283         /* nothing to do here: the MIDI UI thread in libardour handles all our
284            I/O needs.
285         */
286         return 0;
287 }
288
289 void
290 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
291 {
292         _feedback_interval = ms;
293 }
294
295 void
296 GenericMidiControlProtocol::send_feedback ()
297 {
298         /* This is executed in RT "process" context", so no blocking calls
299          */
300
301         if (!do_feedback) {
302                 return;
303         }
304
305         microseconds_t now = get_microseconds ();
306
307         if (last_feedback_time != 0) {
308                 if ((now - last_feedback_time) < _feedback_interval) {
309                         return;
310                 }
311         }
312
313         _send_feedback ();
314
315         last_feedback_time = now;
316 }
317
318 void
319 GenericMidiControlProtocol::_send_feedback ()
320 {
321         /* This is executed in RT "process" context", so no blocking calls
322          */
323
324         const int32_t bufsize = 16 * 1024; /* XXX too big */
325         MIDI::byte buf[bufsize];
326         int32_t bsize = bufsize;
327
328         /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
329            writes for each controllable here; if we send more than one MIDI message
330            in a single jack_midi_event_write then some bridges will only pass the
331            first on to ALSA.
332         */
333
334         Glib::Threads::Mutex::Lock lm (controllables_lock, Glib::Threads::TRY_LOCK);
335         if (!lm.locked ()) {
336                 return;
337         }
338
339         for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
340                 MIDI::byte* end = (*r)->write_feedback (buf, bsize);
341                 if (end != buf) {
342                         _output_port->write (buf, (int32_t) (end - buf), 0);
343                 }
344         }
345 }
346
347 bool
348 GenericMidiControlProtocol::start_learning (Controllable* c)
349 {
350         if (c == 0) {
351                 return false;
352         }
353
354         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
355         DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Learn binding: Controlable number: %1\n", c));
356
357         /* drop any existing mappings for the same controllable for which
358          * learning has just started.
359          */
360
361         MIDIControllables::iterator tmp;
362         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
363                 tmp = i;
364                 ++tmp;
365                 if ((*i)->get_controllable() == c) {
366                         delete (*i);
367                         controllables.erase (i);
368                 }
369                 i = tmp;
370         }
371
372         /* check pending controllables (those for which a learn is underway) to
373          * see if it is for the same one for which learning has just started.
374          */
375
376         {
377                 Glib::Threads::Mutex::Lock lm (pending_lock);
378
379                 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
380                         if (((*i)->mc)->get_controllable() == c) {
381                                 (*i)->connection.disconnect();
382                                 if ((*i)->own_mc) {
383                                         delete (*i)->mc;
384                                 }
385                                 delete *i;
386                                 i = pending_controllables.erase (i);
387                         } else {
388                                 ++i;
389                         }
390                 }
391         }
392
393         MIDIControllable* mc = 0;
394         bool own_mc = false;
395
396         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
397                 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
398                         mc = *i;
399                         break;
400                 }
401         }
402
403         if (!mc) {
404                 mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
405                 own_mc = true;
406         }
407
408         /* stuff the new controllable into pending */
409
410         {
411                 Glib::Threads::Mutex::Lock lm (pending_lock);
412
413                 MIDIPendingControllable* element = new MIDIPendingControllable (mc, own_mc);
414                 c->LearningFinished.connect_same_thread (element->connection, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
415
416                 pending_controllables.push_back (element);
417         }
418         mc->learn_about_external_control ();
419         return true;
420 }
421
422 void
423 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
424 {
425         Glib::Threads::Mutex::Lock lm (pending_lock);
426         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
427
428         for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
429                 if ( (*i)->mc == mc) {
430                         (*i)->connection.disconnect();
431                         delete *i;
432                         i = pending_controllables.erase(i);
433                 } else {
434                         ++i;
435                 }
436         }
437
438         /* add the controllable for which learning stopped to our list of
439          * controllables
440          */
441
442         controllables.push_back (mc);
443 }
444
445 void
446 GenericMidiControlProtocol::stop_learning (Controllable* c)
447 {
448         Glib::Threads::Mutex::Lock lm (pending_lock);
449         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
450         MIDIControllable* dptr = 0;
451
452         /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
453            relevant MIDIControllable and remove it from the pending list.
454         */
455
456         for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
457                 if (((*i)->mc)->get_controllable() == c) {
458                         (*i)->mc->stop_learning ();
459                         dptr = (*i)->mc;
460                         (*i)->connection.disconnect();
461
462                         delete *i;
463                         pending_controllables.erase (i);
464                         break;
465                 }
466         }
467
468         delete dptr;
469 }
470
471 void
472 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
473 {
474         if (control != 0) {
475                 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
476
477                 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
478                         MIDIControllable* existingBinding = (*iter);
479
480                         if (control == (existingBinding->get_controllable())) {
481                                 delete existingBinding;
482                                 iter = controllables.erase (iter);
483                         } else {
484                                 ++iter;
485                         }
486
487                 }
488         }
489 }
490
491 // This next function seems unused
492 void
493 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
494 {
495         if (control != NULL) {
496                 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
497
498                 MIDI::channel_t channel = (pos & 0xf);
499                 MIDI::byte value = control_number;
500
501                 // Create a MIDIControllable
502                 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *control, false);
503
504                 // Remove any old binding for this midi channel/type/value pair
505                 // Note:  can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
506                 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
507                         MIDIControllable* existingBinding = (*iter);
508
509                         if ((existingBinding->get_control_channel() & 0xf ) == channel &&
510                             existingBinding->get_control_additional() == value &&
511                             (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
512
513                                 delete existingBinding;
514                                 iter = controllables.erase (iter);
515                         } else {
516                                 ++iter;
517                         }
518
519                 }
520
521                 // Update the MIDI Controllable based on the the pos param
522                 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
523                 mc->bind_midi(channel, MIDI::controller, value);
524                 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Create binding: Channel: %1 Controller: %2 Value: %3 \n", channel, MIDI::controller, value));
525                 controllables.push_back (mc);
526         }
527 }
528
529 void
530 GenericMidiControlProtocol::check_used_event (int pos, int control_number)
531 {
532         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
533
534         MIDI::channel_t channel = (pos & 0xf);
535         MIDI::byte value = control_number;
536
537         DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("checking for used event: Channel: %1 Controller: %2 value: %3\n", (int) channel, (pos & 0xf0), (int) value));
538
539         // Remove any old binding for this midi channel/type/value pair
540         // Note:  can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
541         for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
542                 MIDIControllable* existingBinding = (*iter);
543                 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
544                         if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
545                                 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
546                                 delete existingBinding;
547                                 iter = controllables.erase (iter);
548                         } else {
549                                 ++iter;
550                         }
551                 } else {
552                         ++iter;
553                 }
554         }
555
556         for (MIDIFunctions::iterator iter = functions.begin(); iter != functions.end();) {
557                 MIDIFunction* existingBinding = (*iter);
558                 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
559                         if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
560                                 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
561                                 delete existingBinding;
562                                 iter = functions.erase (iter);
563                         } else {
564                                 ++iter;
565                         }
566                 } else {
567                         ++iter;
568                 }
569         }
570
571         for (MIDIActions::iterator iter = actions.begin(); iter != actions.end();) {
572                 MIDIAction* existingBinding = (*iter);
573                 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
574                         if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
575                                 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
576                                 delete existingBinding;
577                                 iter = actions.erase (iter);
578                         } else {
579                                 ++iter;
580                         }
581                 } else {
582                         ++iter;
583                 }
584         }
585
586 }
587
588 XMLNode&
589 GenericMidiControlProtocol::get_state ()
590 {
591         XMLNode& node (ControlProtocol::get_state());
592
593         node.set_property (X_("feedback-interval"), _feedback_interval);
594         node.set_property (X_("threshold"), _threshold);
595         node.set_property (X_("motorized"), _motorised);
596
597         if (!_current_binding.empty()) {
598                 node.set_property ("binding", _current_binding);
599         }
600
601         XMLNode* children = new XMLNode (X_("Controls"));
602
603         node.add_child_nocopy (*children);
604
605         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
606         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
607
608                 /* we don't care about bindings that come from a bindings map, because
609                    they will all be reset/recreated when we load the relevant bindings
610                    file.
611                 */
612
613                 if ((*i)->get_controllable() && (*i)->learned()) {
614                         children->add_child_nocopy ((*i)->get_state());
615                 }
616         }
617
618         return node;
619 }
620
621 int
622 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
623 {
624         XMLNodeList nlist;
625         XMLNodeConstIterator niter;
626
627         if (ControlProtocol::set_state (node, version)) {
628                 return -1;
629         }
630
631         if (!node.get_property ("feedback-interval", _feedback_interval)) {
632                 _feedback_interval = 10000;
633         }
634
635         if (!node.get_property ("threshold", _threshold)) {
636                 _threshold = 10;
637         }
638
639         if (!node.get_property ("motorized", _motorised)) {
640                 _motorised = false;
641         }
642
643         boost::shared_ptr<Controllable> c;
644
645         {
646                 Glib::Threads::Mutex::Lock lm (pending_lock);
647                 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
648                         (*i)->connection.disconnect();
649                         if ((*i)->own_mc) {
650                                 delete (*i)->mc;
651                         }
652                         delete *i;
653                 }
654                 pending_controllables.clear ();
655         }
656
657         std::string str;
658         // midi map has to be loaded first so learned binding can go on top
659         if (node.get_property ("binding", str)) {
660                 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
661                         if (str == (*x).name) {
662                                 load_bindings ((*x).path);
663                                 break;
664                         }
665                 }
666         }
667
668         /* Load up specific bindings from the
669          * <Controls><MidiControllable>...</MidiControllable><Controls> section
670          */
671
672         bool load_dynamic_bindings = false;
673         node.get_property ("session-state", load_dynamic_bindings);
674
675         if (load_dynamic_bindings) {
676                 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
677                 nlist = node.children(); // "Controls"
678
679                 if (!nlist.empty()) {
680                         nlist = nlist.front()->children(); // "MIDIControllable" ...
681
682                         if (!nlist.empty()) {
683                                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
684
685                                         PBD::ID id;
686                                         if ((*niter)->get_property ("id", id)) {
687
688                                                 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Relearned binding for session: Control ID: %1\n", id.to_s()));
689                                                 Controllable* c = Controllable::by_id (id);
690
691                                                 if (c) {
692                                                         MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
693
694                                                         if (mc->set_state (**niter, version) == 0) {
695                                                                 controllables.push_back (mc);
696                                                         } else {
697                                                                 warning << string_compose ("Generic MIDI control: Failed to set state for Control ID: %1\n", id.to_s());
698                                                                 delete mc;
699                                                         }
700
701                                                 } else {
702                                                         warning << string_compose (
703                                                                 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
704                                                                 id.to_s()) << endmsg;
705                                                 }
706                                         }
707                                 }
708                         }
709                 }
710         }
711
712         return 0;
713 }
714
715 int
716 GenericMidiControlProtocol::set_feedback (bool yn)
717 {
718         do_feedback = yn;
719         last_feedback_time = 0;
720         return 0;
721 }
722
723 bool
724 GenericMidiControlProtocol::get_feedback () const
725 {
726         return do_feedback;
727 }
728
729 int
730 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
731 {
732         DEBUG_TRACE (DEBUG::GenericMidi, "Load bindings: Reading midi map\n");
733         XMLTree state_tree;
734
735         if (!state_tree.read (xmlpath.c_str())) {
736                 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
737                 return -1;
738         }
739
740         XMLNode* root = state_tree.root();
741
742         if (root->name() != X_("ArdourMIDIBindings")) {
743                 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
744                 return -1;
745         }
746
747         const XMLProperty* prop;
748
749         if ((prop = root->property ("version")) == 0) {
750                 return -1;
751         }
752
753         const XMLNodeList& children (root->children());
754         XMLNodeConstIterator citer;
755         XMLNodeConstIterator gciter;
756
757         MIDIControllable* mc;
758
759         drop_all ();
760
761         DEBUG_TRACE (DEBUG::GenericMidi, "Loading bindings\n");
762         for (citer = children.begin(); citer != children.end(); ++citer) {
763
764                 if ((*citer)->name() == "DeviceInfo") {
765
766                         if ((*citer)->get_property ("bank-size", _bank_size)) {
767                                 _current_bank = 0;
768                         }
769
770                         if (!(*citer)->get_property ("motorized", _motorised)) {
771                                 _motorised = false;
772                         }
773
774                         if (!(*citer)->get_property ("threshold", _threshold)) {
775                                 _threshold = 10;
776                         }
777                 }
778
779                 if ((*citer)->name() == "Binding") {
780                         const XMLNode* child = *citer;
781
782                         if (child->property ("uri")) {
783                                 /* controllable */
784
785                                 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
786                                 if ((mc = create_binding (*child)) != 0) {
787                                         controllables.push_back (mc);
788                                 }
789
790                         } else if (child->property ("function")) {
791
792                                 /* function */
793                                 MIDIFunction* mf;
794
795                                 if ((mf = create_function (*child)) != 0) {
796                                         functions.push_back (mf);
797                                 }
798
799                         } else if (child->property ("action")) {
800                                 MIDIAction* ma;
801
802                                 if ((ma = create_action (*child)) != 0) {
803                                         actions.push_back (ma);
804                                 }
805                         }
806                 }
807         }
808
809         if ((prop = root->property ("name")) != 0) {
810                 _current_binding = prop->value ();
811         }
812
813         reset_controllables ();
814
815         return 0;
816 }
817
818 MIDIControllable*
819 GenericMidiControlProtocol::create_binding (const XMLNode& node)
820 {
821         const XMLProperty* prop;
822         MIDI::byte detail;
823         MIDI::channel_t channel;
824         string uri;
825         MIDI::eventType ev;
826         int intval;
827         bool momentary;
828         MIDIControllable::CtlType ctltype;
829         MIDIControllable::Encoder encoder = MIDIControllable::No_enc;
830         bool rpn_value = false;
831         bool nrpn_value = false;
832         bool rpn_change = false;
833         bool nrpn_change = false;
834
835         if ((prop = node.property (X_("ctl"))) != 0) {
836                 ctltype = MIDIControllable::Ctl_Momentary;
837                 ev = MIDI::controller;
838         } else if ((prop = node.property (X_("ctl-toggle"))) !=0) {
839                 ctltype = MIDIControllable::Ctl_Toggle;
840                 ev = MIDI::controller;
841         } else if ((prop = node.property (X_("ctl-dial"))) !=0) {
842                 ctltype = MIDIControllable::Ctl_Dial;
843                 ev = MIDI::controller;
844         } else if ((prop = node.property (X_("note"))) != 0) {
845                 ev = MIDI::on;
846         } else if ((prop = node.property (X_("pgm"))) != 0) {
847                 ev = MIDI::program;
848         } else if ((prop = node.property (X_("pb"))) != 0) {
849                 ev = MIDI::pitchbend;
850         } else if ((prop = node.property (X_("enc-l"))) != 0) {
851                 encoder = MIDIControllable::Enc_L;
852                 ev = MIDI::controller;
853         } else if ((prop = node.property (X_("enc-r"))) != 0) {
854                 encoder = MIDIControllable::Enc_R;
855                 ev = MIDI::controller;
856         } else if ((prop = node.property (X_("enc-2"))) != 0) {
857                 encoder = MIDIControllable::Enc_2;
858                 ev = MIDI::controller;
859         } else if ((prop = node.property (X_("enc-b"))) != 0) {
860                 encoder = MIDIControllable::Enc_B;
861                 ev = MIDI::controller;
862         } else if ((prop = node.property (X_("rpn"))) != 0) {
863                 rpn_value = true;
864         } else if ((prop = node.property (X_("nrpn"))) != 0) {
865                 nrpn_value = true;
866         } else if ((prop = node.property (X_("rpn-delta"))) != 0) {
867                 rpn_change = true;
868         } else if ((prop = node.property (X_("nrpn-delta"))) != 0) {
869                 nrpn_change = true;
870         } else {
871                 return 0;
872         }
873
874         if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
875                 return 0;
876         }
877
878         detail = (MIDI::byte) intval;
879
880         if ((prop = node.property (X_("channel"))) == 0) {
881                 return 0;
882         }
883
884         if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
885                 return 0;
886         }
887         channel = (MIDI::channel_t) intval;
888         /* adjust channel to zero-based counting */
889         if (channel > 0) {
890                 channel -= 1;
891         }
892
893         if ((prop = node.property (X_("momentary"))) != 0) {
894                 momentary = string_to<bool> (prop->value());
895         } else {
896                 momentary = false;
897         }
898
899         prop = node.property (X_("uri"));
900         uri = prop->value();
901
902         MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary);
903
904         if (mc->init (uri)) {
905                 delete mc;
906                 return 0;
907         }
908
909         if (rpn_value) {
910                 mc->bind_rpn_value (channel, detail);
911         } else if (nrpn_value) {
912                 mc->bind_nrpn_value (channel, detail);
913         } else if (rpn_change) {
914                 mc->bind_rpn_change (channel, detail);
915         } else if (nrpn_change) {
916                 mc->bind_nrpn_change (channel, detail);
917         } else {
918                 mc->set_ctltype (ctltype);
919                 mc->set_encoder (encoder);
920                 mc->bind_midi (channel, ev, detail);
921         }
922
923         return mc;
924 }
925
926 void
927 GenericMidiControlProtocol::reset_controllables ()
928 {
929         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
930
931         for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
932                 MIDIControllable* existingBinding = (*iter);
933                 MIDIControllables::iterator next = iter;
934                 ++next;
935
936                 if (!existingBinding->learned()) {
937
938                         /* its entirely possible that the session doesn't have
939                          * the specified controllable (e.g. it has too few
940                          * tracks). if we find this to be the case, we just leave
941                          * the binding around, unbound, and it will do "late
942                          * binding" (or "lazy binding") if/when any data arrives.
943                          */
944
945                         existingBinding->lookup_controllable ();
946                 }
947
948                 iter = next;
949         }
950 }
951
952 boost::shared_ptr<Controllable>
953 GenericMidiControlProtocol::lookup_controllable (const string & str) const
954 {
955         boost::shared_ptr<Controllable> c;
956
957         DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("lookup controllable from \"%1\"\n", str));
958
959         if (!session) {
960                 DEBUG_TRACE (DEBUG::GenericMidi, "no session\n");
961                 return c;
962         }
963
964         /* step 1: split string apart */
965
966         string::size_type first_space = str.find_first_of (" ");
967
968         if (first_space == string::npos) {
969                 return c;
970         }
971
972         string front = str.substr (0, first_space);
973         vector<string> path;
974         split (front, path, '/');
975
976         if (path.size() < 2) {
977                 return c;
978         }
979
980         string back = str.substr (first_space);
981         vector<string> rest;
982         split (back, rest, ' ');
983
984         if (rest.empty()) {
985                 return c;
986         }
987
988         DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("parsed into path of %1, rest of %1\n", path.size(), rest.size()));
989
990         /* Step 2: analyse parts of the string to figure out what type of
991          * Stripable we're looking for
992          */
993
994         enum Type {
995                 Selection,
996                 PresentationOrder,
997                 Named,
998         };
999         Type type = Named;
1000         int id = 1;
1001         string name;
1002
1003         static regex_t compiled_pattern;
1004         static bool compiled = false;
1005
1006         if (!compiled) {
1007                 const char * const pattern = "^[BS]?[0-9]+";
1008                 /* this pattern compilation is not going to fail */
1009                 regcomp (&compiled_pattern, pattern, REG_EXTENDED|REG_NOSUB);
1010                 /* leak compiled pattern */
1011                 compiled = true;
1012         }
1013
1014         /* Step 3: identify what "rest" looks like - name, or simple nueric, or
1015          * banked/selection specifier
1016          */
1017
1018         bool matched = (regexec (&compiled_pattern, rest[0].c_str(), 0, 0, 0) == 0);
1019
1020         if (matched) {
1021                 bool banked = false;
1022
1023                 if (rest[0][0] == 'B') {
1024                         banked = true;
1025                         /* already matched digits, so we know atoi() will succeed */
1026                         id = atoi (rest[0].substr (1));
1027                         type = PresentationOrder;
1028                 } else if (rest[0][0] == 'S') {
1029                         /* already matched digits, so we know atoi() will succeed */
1030                         id = atoi (rest[0].substr (1));
1031                         type = Selection;
1032                 } else if (isdigit (rest[0][0])) {
1033                         /* already matched digits, so we know atoi() will succeed */
1034                         id = atoi (rest[0]);
1035                         type = PresentationOrder;
1036                 } else {
1037                         return c;
1038                 }
1039
1040                 id -= 1; /* order is zero-based, but maps use 1-based */
1041
1042                 if (banked) {
1043                         id += _current_bank * _bank_size;
1044                 }
1045
1046         } else {
1047
1048                 type = Named;
1049                 name = rest[0];
1050         }
1051
1052         /* step 4: find the reference Stripable */
1053
1054         boost::shared_ptr<Stripable> s;
1055
1056         if (path[0] == X_("route") || path[0] == X_("rid")) {
1057
1058                 std::string name;
1059
1060                 switch (type) {
1061                 case PresentationOrder:
1062                         s = session->get_remote_nth_stripable (id, PresentationInfo::Route);
1063                         break;
1064                 case Named:
1065                         /* name */
1066                         name = rest[0];
1067
1068                         if (name == "Master" || name == X_("master")) {
1069                                 s = session->master_out();
1070                         } else if (name == X_("control") || name == X_("listen") || name == X_("monitor") || name == "Monitor") {
1071                                 s = session->monitor_out();
1072                         } else if (name == X_("auditioner")) {
1073                                 s = session->the_auditioner();
1074                         } else {
1075                                 s = session->route_by_name (name);
1076                         }
1077                         break;
1078
1079                 case Selection:
1080                         s = session->route_by_selected_count (id);
1081                         break;
1082                 }
1083
1084         } else if (path[0] == X_("vca")) {
1085
1086                 s = session->get_remote_nth_stripable (id, PresentationInfo::VCA);
1087
1088         } else if (path[0] == X_("bus")) {
1089
1090                 switch (type) {
1091                 case Named:
1092                         s = session->route_by_name (name);
1093                         break;
1094                 default:
1095                         s = session->get_remote_nth_stripable (id, PresentationInfo::Bus);
1096                 }
1097
1098         } else if (path[0] == X_("track")) {
1099
1100                 switch (type) {
1101                 case Named:
1102                         s = session->route_by_name (name);
1103                         break;
1104                 default:
1105                         s = session->get_remote_nth_stripable (id, PresentationInfo::Track);
1106                 }
1107         }
1108
1109         if (!s) {
1110                 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("no stripable found for \"%1\"\n", str));
1111                 return c;
1112         }
1113
1114         DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("found stripable %1\n", s->name()));
1115
1116         /* step 5: find the referenced controllable for that stripable.
1117          *
1118          * Some controls exist only for Route, so we need that too
1119          */
1120
1121         boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1122
1123         if (path[1] == X_("gain")) {
1124                 c = s->gain_control();
1125         } else if (path[1] == X_("trim")) {
1126                 c = s->trim_control ();
1127         } else if (path[1] == X_("solo")) {
1128                 c = s->solo_control();
1129         } else if (path[1] == X_("mute")) {
1130                 c = s->mute_control();
1131         } else if (path[1] == X_("recenable")) {
1132                 c = s->rec_enable_control ();
1133         } else if (path[1] == X_("panwidth")) {
1134                 c = s->pan_width_control ();
1135         } else if (path[1] == X_("pandirection") || path[1] == X_("balance")) {
1136                 c = s->pan_azimuth_control ();
1137         } else if (path[1] == X_("plugin")) {
1138
1139                 /* /route/plugin/parameter */
1140
1141                 if (path.size() == 3 && rest.size() == 3) {
1142                         if (path[2] == X_("parameter")) {
1143
1144                                 int plugin = atoi (rest[1]);
1145                                 int parameter_index = atoi (rest[2]);
1146
1147                                 /* revert to zero based counting */
1148                                 if (plugin > 0) {
1149                                         --plugin;
1150                                 }
1151                                 if (parameter_index > 0) {
1152                                         --parameter_index;
1153                                 }
1154
1155                                 if (r) {
1156                                         boost::shared_ptr<Processor> proc = r->nth_plugin (plugin);
1157
1158                                         if (proc) {
1159                                                 boost::shared_ptr<PluginInsert> p = boost::dynamic_pointer_cast<PluginInsert> (proc);
1160                                                 if (p) {
1161                                                         uint32_t param;
1162                                                         bool ok;
1163                                                         param = p->plugin()->nth_parameter (parameter_index, ok);
1164                                                         if (ok) {
1165                                                                 c = boost::dynamic_pointer_cast<Controllable> (proc->control (Evoral::Parameter (PluginAutomation, 0, param)));
1166                                                         }
1167                                                 }
1168                                         }
1169                                 }
1170                         }
1171                 }
1172
1173         } else if (path[1] == X_("send")) {
1174
1175                 if (path.size() == 3 && rest.size() == 2) {
1176                         if (path[2] == X_("gain")) {
1177                                 uint32_t send = atoi (rest[1]);
1178                                 if (send > 0) {
1179                                         --send;
1180                                 }
1181                                 c = s->send_level_controllable (send);
1182                         } else if (path[2] == X_("direction")) {
1183                                 /* XXX not implemented yet */
1184
1185                         } else if (path[2] == X_("enable")) {
1186                                 /* XXX not implemented yet */
1187                         }
1188                 }
1189
1190         } else if (path[1] == X_("eq")) {
1191
1192                 /* /route/eq/enable */
1193                 /* /route/eq/gain/<band> */
1194                 /* /route/eq/freq/<band> */
1195                 /* /route/eq/q/<band> */
1196                 /* /route/eq/shape/<band> */
1197
1198                 if (path.size() == 3) {
1199
1200                         if (path[2] == X_("enable")) {
1201                                 c = s->eq_enable_controllable ();
1202                         }
1203
1204                 } else if (path.size() == 4) {
1205
1206                         int band = atoi (path[3]); /* band number */
1207
1208                         if (path[2] == X_("gain")) {
1209                                 c = s->eq_gain_controllable (band);
1210                         } else if (path[2] == X_("freq")) {
1211                                 c = s->eq_freq_controllable (band);
1212                         } else if (path[2] == X_("q")) {
1213                                 c = s->eq_q_controllable (band);
1214                         } else if (path[2] == X_("shape")) {
1215                                 c = s->eq_shape_controllable (band);
1216                         }
1217                 }
1218
1219         } else if (path[1] == X_("filter")) {
1220
1221                 /* /route/filter/hi/freq */
1222
1223                 if (path.size() == 4) {
1224
1225                         int filter;
1226
1227                         if (path[2] == X_("hi")) {
1228                                 filter = 1; /* high pass filter */
1229                         } else {
1230                                 filter = 0; /* low pass filter */
1231                         }
1232
1233                         if (path[3] == X_("enable")) {
1234                                 c = s->filter_enable_controllable (filter);
1235                         } else if (path[3] == X_("freq")) {
1236                                 c = s->filter_freq_controllable (filter);
1237                         } else if (path[3] == X_("slope")) {
1238                                 c = s->filter_slope_controllable (filter);
1239                         }
1240
1241                 }
1242
1243         } else if (path[1] == X_("compressor")) {
1244
1245                 if (path.size() == 3) {
1246                         if (path[2] == X_("enable")) {
1247                                 c = s->comp_enable_controllable ();
1248                         } else if (path[2] == X_("threshold")) {
1249                                 c = s->comp_threshold_controllable ();
1250                         } else if (path[2] == X_("mode")) {
1251                                 c = s->comp_mode_controllable ();
1252                         } else if (path[2] == X_("speed")) {
1253                                 c = s->comp_speed_controllable ();
1254                         } else if (path[2] == X_("makeup")) {
1255                                 c = s->comp_makeup_controllable ();
1256                         }
1257                 }
1258         }
1259
1260         if (c) {
1261                 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("found controllable \"%1\"\n", c->name()));
1262         } else {
1263                 DEBUG_TRACE (DEBUG::GenericMidi, "no controllable found\n");
1264         }
1265
1266         return c;
1267 }
1268
1269 MIDIFunction*
1270 GenericMidiControlProtocol::create_function (const XMLNode& node)
1271 {
1272         const XMLProperty* prop;
1273         int intval;
1274         MIDI::byte detail = 0;
1275         MIDI::channel_t channel = 0;
1276         string uri;
1277         MIDI::eventType ev;
1278         MIDI::byte* data = 0;
1279         uint32_t data_size = 0;
1280         string argument;
1281
1282         if ((prop = node.property (X_("ctl"))) != 0) {
1283                 ev = MIDI::controller;
1284         } else if ((prop = node.property (X_("note"))) != 0) {
1285                 ev = MIDI::on;
1286         } else if ((prop = node.property (X_("pgm"))) != 0) {
1287                 ev = MIDI::program;
1288         } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
1289
1290                 if (prop->name() == X_("sysex")) {
1291                         ev = MIDI::sysex;
1292                 } else {
1293                         ev = MIDI::any;
1294                 }
1295
1296                 int val;
1297                 uint32_t cnt;
1298
1299                 {
1300                         cnt = 0;
1301                         stringstream ss (prop->value());
1302                         ss << hex;
1303
1304                         while (ss >> val) {
1305                                 cnt++;
1306                         }
1307                 }
1308
1309                 if (cnt == 0) {
1310                         return 0;
1311                 }
1312
1313                 data = new MIDI::byte[cnt];
1314                 data_size = cnt;
1315
1316                 {
1317                         stringstream ss (prop->value());
1318                         ss << hex;
1319                         cnt = 0;
1320
1321                         while (ss >> val) {
1322                                 data[cnt++] = (MIDI::byte) val;
1323                         }
1324                 }
1325
1326         } else {
1327                 warning << "Binding ignored - unknown type" << endmsg;
1328                 return 0;
1329         }
1330
1331         if (data_size == 0) {
1332                 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1333                         return 0;
1334                 }
1335
1336                 detail = (MIDI::byte) intval;
1337
1338                 if ((prop = node.property (X_("channel"))) == 0) {
1339                         return 0;
1340                 }
1341
1342                 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1343                         return 0;
1344                 }
1345                 channel = (MIDI::channel_t) intval;
1346                 /* adjust channel to zero-based counting */
1347                 if (channel > 0) {
1348                         channel -= 1;
1349                 }
1350         }
1351
1352         if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
1353                 argument = prop->value ();
1354         }
1355
1356         prop = node.property (X_("function"));
1357
1358         MIDIFunction* mf = new MIDIFunction (*_input_port->parser());
1359
1360         if (mf->setup (*this, prop->value(), argument, data, data_size)) {
1361                 delete mf;
1362                 return 0;
1363         }
1364
1365         mf->bind_midi (channel, ev, detail);
1366
1367         return mf;
1368 }
1369
1370 MIDIAction*
1371 GenericMidiControlProtocol::create_action (const XMLNode& node)
1372 {
1373         const XMLProperty* prop;
1374         int intval;
1375         MIDI::byte detail = 0;
1376         MIDI::channel_t channel = 0;
1377         string uri;
1378         MIDI::eventType ev;
1379         MIDI::byte* data = 0;
1380         uint32_t data_size = 0;
1381
1382         if ((prop = node.property (X_("ctl"))) != 0) {
1383                 ev = MIDI::controller;
1384         } else if ((prop = node.property (X_("note"))) != 0) {
1385                 ev = MIDI::on;
1386         } else if ((prop = node.property (X_("pgm"))) != 0) {
1387                 ev = MIDI::program;
1388         } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
1389
1390                 if (prop->name() == X_("sysex")) {
1391                         ev = MIDI::sysex;
1392                 } else {
1393                         ev = MIDI::any;
1394                 }
1395
1396                 int val;
1397                 uint32_t cnt;
1398
1399                 {
1400                         cnt = 0;
1401                         stringstream ss (prop->value());
1402                         ss << hex;
1403
1404                         while (ss >> val) {
1405                                 cnt++;
1406                         }
1407                 }
1408
1409                 if (cnt == 0) {
1410                         return 0;
1411                 }
1412
1413                 data = new MIDI::byte[cnt];
1414                 data_size = cnt;
1415
1416                 {
1417                         stringstream ss (prop->value());
1418                         ss << hex;
1419                         cnt = 0;
1420
1421                         while (ss >> val) {
1422                                 data[cnt++] = (MIDI::byte) val;
1423                         }
1424                 }
1425
1426         } else {
1427                 warning << "Binding ignored - unknown type" << endmsg;
1428                 return 0;
1429         }
1430
1431         if (data_size == 0) {
1432                 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1433                         return 0;
1434                 }
1435
1436                 detail = (MIDI::byte) intval;
1437
1438                 if ((prop = node.property (X_("channel"))) == 0) {
1439                         return 0;
1440                 }
1441
1442                 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1443                         return 0;
1444                 }
1445                 channel = (MIDI::channel_t) intval;
1446                 /* adjust channel to zero-based counting */
1447                 if (channel > 0) {
1448                         channel -= 1;
1449                 }
1450         }
1451
1452         prop = node.property (X_("action"));
1453
1454         MIDIAction* ma = new MIDIAction (*_input_port->parser());
1455
1456         if (ma->init (*this, prop->value(), data, data_size)) {
1457                 delete ma;
1458                 return 0;
1459         }
1460
1461         ma->bind_midi (channel, ev, detail);
1462
1463         return ma;
1464 }
1465
1466 void
1467 GenericMidiControlProtocol::set_current_bank (uint32_t b)
1468 {
1469         _current_bank = b;
1470         reset_controllables ();
1471 }
1472
1473 void
1474 GenericMidiControlProtocol::next_bank ()
1475 {
1476         _current_bank++;
1477         reset_controllables ();
1478 }
1479
1480 void
1481 GenericMidiControlProtocol::prev_bank()
1482 {
1483         if (_current_bank) {
1484                 _current_bank--;
1485                 reset_controllables ();
1486         }
1487 }
1488
1489 void
1490 GenericMidiControlProtocol::set_motorised (bool m)
1491 {
1492         _motorised = m;
1493 }
1494
1495 void
1496 GenericMidiControlProtocol::set_threshold (int t)
1497 {
1498         _threshold = t;
1499 }
1500
1501 bool
1502 GenericMidiControlProtocol::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
1503 {
1504         if (!_input_port || !_output_port) {
1505                 return false;
1506         }
1507
1508         string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
1509         string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
1510
1511         if (ni == name1 || ni == name2) {
1512                 if (yn) {
1513                         connection_state |= InputConnected;
1514                 } else {
1515                         connection_state &= ~InputConnected;
1516                 }
1517         } else if (no == name1 || no == name2) {
1518                 if (yn) {
1519                         connection_state |= OutputConnected;
1520                 } else {
1521                         connection_state &= ~OutputConnected;
1522                 }
1523         } else {
1524                 /* not our ports */
1525                 return false;
1526         }
1527
1528         if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
1529
1530                 /* XXX this is a horrible hack. Without a short sleep here,
1531                    something prevents the device wakeup messages from being
1532                    sent and/or the responses from being received.
1533                 */
1534
1535                 g_usleep (100000);
1536                 connected ();
1537
1538         } else {
1539
1540         }
1541
1542         ConnectionChange (); /* emit signal for our GUI */
1543
1544         return true; /* connection status changed */
1545 }
1546
1547 void
1548 GenericMidiControlProtocol::connected ()
1549 {
1550 }
1551
1552 boost::shared_ptr<Port>
1553 GenericMidiControlProtocol::output_port() const
1554 {
1555         return _output_port;
1556 }
1557
1558 boost::shared_ptr<Port>
1559 GenericMidiControlProtocol::input_port() const
1560 {
1561         return _input_port;
1562 }
1563
1564 void
1565 GenericMidiControlProtocol::maybe_start_touch (Controllable* controllable)
1566 {
1567         AutomationControl *actl = dynamic_cast<AutomationControl*> (controllable);
1568         if (actl) {
1569                 actl->start_touch (session->audible_sample ());
1570         }
1571 }