NOOP, remove trailing tabs/whitespace.
[ardour.git] / libs / surfaces / generic_midi / 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 #include <glibmm/fileutils.h>
26 #include <glibmm/miscutils.h>
27
28 #include "pbd/controllable_descriptor.h"
29 #include "pbd/error.h"
30 #include "pbd/failed_constructor.h"
31 #include "pbd/file_utils.h"
32 #include "pbd/xml++.h"
33 #include "pbd/compose.h"
34
35 #include "midi++/port.h"
36
37 #include "ardour/audioengine.h"
38 #include "ardour/filesystem_paths.h"
39 #include "ardour/session.h"
40 #include "ardour/route.h"
41 #include "ardour/midi_ui.h"
42 #include "ardour/rc_configuration.h"
43 #include "ardour/midiport_manager.h"
44 #include "ardour/debug.h"
45
46 #include "generic_midi_control_protocol.h"
47 #include "midicontrollable.h"
48 #include "midifunction.h"
49 #include "midiaction.h"
50
51 using namespace ARDOUR;
52 using namespace PBD;
53 using namespace std;
54
55 #include "i18n.h"
56
57 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
58
59 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
60         : ControlProtocol (s, _("Generic MIDI"))
61         , _motorised (false)
62         , _threshold (10)
63         , gui (0)
64 {
65         _input_port = s.midi_input_port ();
66         _output_port = s.midi_output_port ();
67
68         do_feedback = false;
69         _feedback_interval = 10000; // microseconds
70         last_feedback_time = 0;
71
72         _current_bank = 0;
73         _bank_size = 0;
74
75         /* these signals are emitted by the MidiControlUI's event loop thread
76          * and we may as well handle them right there in the same the same
77          * thread
78          */
79
80         Controllable::StartLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::start_learning, this, _1));
81         Controllable::StopLearning.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::stop_learning, this, _1));
82         Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
83         Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
84
85         /* this signal is emitted by the process() callback, and if
86          * send_feedback() is going to do anything, it should do it in the
87          * context of the process() callback itself.
88          */
89
90         Session::SendFeedback.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this));
91         //Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
92
93         /* this one is cross-thread */
94
95         Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
96
97         reload_maps ();
98 }
99
100 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
101 {
102         drop_all ();
103         tear_down_gui ();
104 }
105
106 static const char * const midimap_env_variable_name = "ARDOUR_MIDIMAPS_PATH";
107 static const char* const midi_map_dir_name = "midi_maps";
108 static const char* const midi_map_suffix = ".map";
109
110 Searchpath
111 system_midi_map_search_path ()
112 {
113         bool midimap_path_defined = false;
114         std::string spath_env (Glib::getenv (midimap_env_variable_name, midimap_path_defined));
115
116         if (midimap_path_defined) {
117                 return spath_env;
118         }
119
120         Searchpath spath (ardour_data_search_path());
121         spath.add_subdirectory_to_paths(midi_map_dir_name);
122         return spath;
123 }
124
125 static std::string
126 user_midi_map_directory ()
127 {
128         return Glib::build_filename (user_config_directory(), midi_map_dir_name);
129 }
130
131 static bool
132 midi_map_filter (const string &str, void* /*arg*/)
133 {
134         return (str.length() > strlen(midi_map_suffix) &&
135                 str.find (midi_map_suffix) == (str.length() - strlen (midi_map_suffix)));
136 }
137
138 void
139 GenericMidiControlProtocol::reload_maps ()
140 {
141         vector<string> midi_maps;
142         Searchpath spath (system_midi_map_search_path());
143         spath += user_midi_map_directory ();
144
145         find_files_matching_filter (midi_maps, spath, midi_map_filter, 0, false, true);
146
147         if (midi_maps.empty()) {
148                 cerr << "No MIDI maps found using " << spath.to_string() << endl;
149                 return;
150         }
151
152         for (vector<string>::iterator i = midi_maps.begin(); i != midi_maps.end(); ++i) {
153                 string fullpath = *i;
154
155                 XMLTree tree;
156
157                 if (!tree.read (fullpath.c_str())) {
158                         continue;
159                 }
160
161                 MapInfo mi;
162
163                 XMLProperty* prop = tree.root()->property ("name");
164
165                 if (!prop) {
166                         continue;
167                 }
168
169                 mi.name = prop->value ();
170                 mi.path = fullpath;
171
172                 map_info.push_back (mi);
173         }
174 }
175
176 void
177 GenericMidiControlProtocol::drop_all ()
178 {
179         DEBUG_TRACE (DEBUG::GenericMidi, "Drop all bindings\n");
180         Glib::Threads::Mutex::Lock lm (pending_lock);
181         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
182
183         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
184                 delete *i;
185         }
186         controllables.clear ();
187
188         for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
189                 delete *i;
190         }
191         pending_controllables.clear ();
192
193         for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
194                 delete *i;
195         }
196         functions.clear ();
197
198         for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
199                 delete *i;
200         }
201         actions.clear ();
202 }
203
204 void
205 GenericMidiControlProtocol::drop_bindings ()
206 {
207         DEBUG_TRACE (DEBUG::GenericMidi, "Drop bindings, leave learned\n");
208         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
209
210         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
211                 if (!(*i)->learned()) {
212                         delete *i;
213                         i = controllables.erase (i);
214                 } else {
215                         ++i;
216                 }
217         }
218
219         for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) {
220                 delete *i;
221         }
222         functions.clear ();
223
224         _current_binding = "";
225         _bank_size = 0;
226         _current_bank = 0;
227 }
228
229 int
230 GenericMidiControlProtocol::set_active (bool /*yn*/)
231 {
232         /* start/stop delivery/outbound thread */
233         return 0;
234 }
235
236 void
237 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
238 {
239         _feedback_interval = ms;
240 }
241
242 void
243 GenericMidiControlProtocol::send_feedback ()
244 {
245         /* This is executed in RT "process" context", so no blocking calls
246          */
247
248         if (!do_feedback) {
249                 return;
250         }
251
252         microseconds_t now = get_microseconds ();
253
254         if (last_feedback_time != 0) {
255                 if ((now - last_feedback_time) < _feedback_interval) {
256                         return;
257                 }
258         }
259
260         _send_feedback ();
261
262         last_feedback_time = now;
263 }
264
265 void
266 GenericMidiControlProtocol::_send_feedback ()
267 {
268         /* This is executed in RT "process" context", so no blocking calls
269          */
270
271         const int32_t bufsize = 16 * 1024; /* XXX too big */
272         MIDI::byte buf[bufsize];
273         int32_t bsize = bufsize;
274
275         /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
276            writes for each controllable here; if we send more than one MIDI message
277            in a single jack_midi_event_write then some bridges will only pass the
278            first on to ALSA.
279         */
280
281         Glib::Threads::Mutex::Lock lm (controllables_lock, Glib::Threads::TRY_LOCK);
282         if (!lm.locked ()) {
283                 return;
284         }
285
286         for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
287                 MIDI::byte* end = (*r)->write_feedback (buf, bsize);
288                 if (end != buf) {
289                         _output_port->write (buf, (int32_t) (end - buf), 0);
290                 }
291         }
292 }
293
294 bool
295 GenericMidiControlProtocol::start_learning (Controllable* c)
296 {
297         if (c == 0) {
298                 return false;
299         }
300
301         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
302         DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Learn binding: Controlable number: %1\n", c));
303
304         MIDIControllables::iterator tmp;
305         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
306                 tmp = i;
307                 ++tmp;
308                 if ((*i)->get_controllable() == c) {
309                         delete (*i);
310                         controllables.erase (i);
311                 }
312                 i = tmp;
313         }
314
315         {
316                 Glib::Threads::Mutex::Lock lm (pending_lock);
317
318                 MIDIPendingControllables::iterator ptmp;
319                 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
320                         ptmp = i;
321                         ++ptmp;
322                         if (((*i)->first)->get_controllable() == c) {
323                                 (*i)->second.disconnect();
324                                 delete (*i)->first;
325                                 delete *i;
326                                 pending_controllables.erase (i);
327                         }
328                         i = ptmp;
329                 }
330         }
331
332         MIDIControllable* mc = 0;
333
334         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
335                 if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
336                         mc = *i;
337                         break;
338                 }
339         }
340
341         if (!mc) {
342                 mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
343         }
344
345         {
346                 Glib::Threads::Mutex::Lock lm (pending_lock);
347
348                 MIDIPendingControllable* element = new MIDIPendingControllable;
349                 element->first = mc;
350                 c->LearningFinished.connect_same_thread (element->second, boost::bind (&GenericMidiControlProtocol::learning_stopped, this, mc));
351
352                 pending_controllables.push_back (element);
353         }
354         mc->learn_about_external_control ();
355         return true;
356 }
357
358 void
359 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
360 {
361         Glib::Threads::Mutex::Lock lm (pending_lock);
362         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
363
364         MIDIPendingControllables::iterator tmp;
365
366         for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) {
367                 tmp = i;
368                 ++tmp;
369
370                 if ( (*i)->first == mc) {
371                         (*i)->second.disconnect();
372                         delete *i;
373                         pending_controllables.erase(i);
374                 }
375
376                 i = tmp;
377         }
378
379         controllables.push_back (mc);
380 }
381
382 void
383 GenericMidiControlProtocol::stop_learning (Controllable* c)
384 {
385         Glib::Threads::Mutex::Lock lm (pending_lock);
386         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
387         MIDIControllable* dptr = 0;
388
389         /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
390            relevant MIDIControllable and remove it from the pending list.
391         */
392
393         for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
394                 if (((*i)->first)->get_controllable() == c) {
395                         (*i)->first->stop_learning ();
396                         dptr = (*i)->first;
397                         (*i)->second.disconnect();
398
399                         delete *i;
400                         pending_controllables.erase (i);
401                         break;
402                 }
403         }
404
405         delete dptr;
406 }
407
408 void
409 GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
410 {
411         if (control != 0) {
412                 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
413
414                 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
415                         MIDIControllable* existingBinding = (*iter);
416
417                         if (control == (existingBinding->get_controllable())) {
418                                 delete existingBinding;
419                                 iter = controllables.erase (iter);
420                         } else {
421                                 ++iter;
422                         }
423
424                 }
425         }
426 }
427
428 // This next function seems unused
429 void
430 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
431 {
432         if (control != NULL) {
433                 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
434
435                 MIDI::channel_t channel = (pos & 0xf);
436                 MIDI::byte value = control_number;
437
438                 // Create a MIDIControllable
439                 MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *control, false);
440
441                 // Remove any old binding for this midi channel/type/value pair
442                 // Note:  can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
443                 for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
444                         MIDIControllable* existingBinding = (*iter);
445
446                         if ((existingBinding->get_control_channel() & 0xf ) == channel &&
447                             existingBinding->get_control_additional() == value &&
448                             (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
449
450                                 delete existingBinding;
451                                 iter = controllables.erase (iter);
452                         } else {
453                                 ++iter;
454                         }
455
456                 }
457
458                 // Update the MIDI Controllable based on the the pos param
459                 // Here is where a table lookup for user mappings could go; for now we'll just wing it...
460                 mc->bind_midi(channel, MIDI::controller, value);
461                 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Create binding: Channel: %1 Controller: %2 Value: %3 \n", channel, MIDI::controller, value));
462                 controllables.push_back (mc);
463         }
464 }
465
466 void
467 GenericMidiControlProtocol::check_used_event (int pos, int control_number)
468 {
469         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
470
471         MIDI::channel_t channel = (pos & 0xf);
472         MIDI::byte value = control_number;
473
474         DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("checking for used event: Channel: %1 Controller: %2 value: %3\n", (int) channel, (pos & 0xf0), (int) value));
475
476         // Remove any old binding for this midi channel/type/value pair
477         // Note:  can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
478         for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
479                 MIDIControllable* existingBinding = (*iter);
480                 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
481                         if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
482                                 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
483                                 delete existingBinding;
484                                 iter = controllables.erase (iter);
485                         } else {
486                                 ++iter;
487                         }
488                 } else {
489                         ++iter;
490                 }
491         }
492
493         for (MIDIFunctions::iterator iter = functions.begin(); iter != functions.end();) {
494                 MIDIFunction* existingBinding = (*iter);
495                 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
496                         if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
497                                 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
498                                 delete existingBinding;
499                                 iter = functions.erase (iter);
500                         } else {
501                                 ++iter;
502                         }
503                 } else {
504                         ++iter;
505                 }
506         }
507
508         for (MIDIActions::iterator iter = actions.begin(); iter != actions.end();) {
509                 MIDIAction* existingBinding = (*iter);
510                 if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
511                         if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
512                                 DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
513                                 delete existingBinding;
514                                 iter = actions.erase (iter);
515                         } else {
516                                 ++iter;
517                         }
518                 } else {
519                         ++iter;
520                 }
521         }
522
523 }
524
525 XMLNode&
526 GenericMidiControlProtocol::get_state ()
527 {
528         XMLNode& node (ControlProtocol::get_state());
529         char buf[32];
530
531         snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
532         node.add_property (X_("feedback_interval"), buf);
533         snprintf (buf, sizeof (buf), "%d", _threshold);
534         node.add_property (X_("threshold"), buf);
535
536         node.add_property (X_("motorized"), _motorised ? "yes" : "no");
537
538         if (!_current_binding.empty()) {
539                 node.add_property ("binding", _current_binding);
540         }
541
542         XMLNode* children = new XMLNode (X_("Controls"));
543
544         node.add_child_nocopy (*children);
545
546         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
547         for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
548
549                 /* we don't care about bindings that come from a bindings map, because
550                    they will all be reset/recreated when we load the relevant bindings
551                    file.
552                 */
553
554                 if ((*i)->get_controllable() && (*i)->learned()) {
555                         children->add_child_nocopy ((*i)->get_state());
556                 }
557         }
558
559         return node;
560 }
561
562 int
563 GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
564 {
565         XMLNodeList nlist;
566         XMLNodeConstIterator niter;
567         const XMLProperty* prop;
568
569         if (ControlProtocol::set_state (node, version)) {
570                 return -1;
571         }
572
573         if ((prop = node.property ("feedback_interval")) != 0) {
574                 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
575                         _feedback_interval = 10000;
576                 }
577         } else {
578                 _feedback_interval = 10000;
579         }
580
581         if ((prop = node.property ("threshold")) != 0) {
582                 if (sscanf (prop->value().c_str(), "%d", &_threshold) != 1) {
583                         _threshold = 10;
584                 }
585         } else {
586                 _threshold = 10;
587         }
588
589         if ((prop = node.property ("motorized")) != 0) {
590                 _motorised = string_is_affirmative (prop->value ());
591         } else {
592                 _motorised = false;
593         }
594
595         boost::shared_ptr<Controllable> c;
596
597         {
598                 Glib::Threads::Mutex::Lock lm (pending_lock);
599                 for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
600                         delete *i;
601                 }
602                 pending_controllables.clear ();
603         }
604
605         // midi map has to be loaded first so learned binding can go on top
606         if ((prop = node.property ("binding")) != 0) {
607                 for (list<MapInfo>::iterator x = map_info.begin(); x != map_info.end(); ++x) {
608                         if (prop->value() == (*x).name) {
609                                 load_bindings ((*x).path);
610                                 break;
611                         }
612                 }
613         }
614
615         /* Load up specific bindings from the
616          * <Controls><MidiControllable>...</MidiControllable><Controls> section
617          */
618
619         {
620                 Glib::Threads::Mutex::Lock lm2 (controllables_lock);
621                 nlist = node.children(); // "Controls"
622
623                 if (!nlist.empty()) {
624                         nlist = nlist.front()->children(); // "MIDIControllable" ...
625
626                         if (!nlist.empty()) {
627                                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
628
629                                         if ((prop = (*niter)->property ("id")) != 0) {
630
631                                                 ID id = prop->value ();
632                                                 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Relearned binding for session: Control ID: %1\n", id.to_s()));
633                                                 Controllable* c = Controllable::by_id (id);
634
635                                                 if (c) {
636                                                         MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *c, false);
637
638                                                         if (mc->set_state (**niter, version) == 0) {
639                                                                 controllables.push_back (mc);
640                                                         }
641
642                                                 } else {
643                                                         warning << string_compose (
644                                                                 _("Generic MIDI control: controllable %1 not found in session (ignored)"),
645                                                                 id.to_s()) << endmsg;
646                                                 }
647                                         }
648                                 }
649                         }
650                 }
651         }
652
653         return 0;
654 }
655
656 int
657 GenericMidiControlProtocol::set_feedback (bool yn)
658 {
659         do_feedback = yn;
660         last_feedback_time = 0;
661         return 0;
662 }
663
664 bool
665 GenericMidiControlProtocol::get_feedback () const
666 {
667         return do_feedback;
668 }
669
670 int
671 GenericMidiControlProtocol::load_bindings (const string& xmlpath)
672 {
673         DEBUG_TRACE (DEBUG::GenericMidi, "Load bindings: Reading midi map\n");
674         XMLTree state_tree;
675
676         if (!state_tree.read (xmlpath.c_str())) {
677                 error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
678                 return -1;
679         }
680
681         XMLNode* root = state_tree.root();
682
683         if (root->name() != X_("ArdourMIDIBindings")) {
684                 error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
685                 return -1;
686         }
687
688         const XMLProperty* prop;
689
690         if ((prop = root->property ("version")) == 0) {
691                 return -1;
692         } else {
693                 int major;
694                 int minor;
695                 int micro;
696
697                 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, &micro);
698                 Stateful::loading_state_version = (major * 1000) + minor;
699         }
700
701         const XMLNodeList& children (root->children());
702         XMLNodeConstIterator citer;
703         XMLNodeConstIterator gciter;
704
705         MIDIControllable* mc;
706
707         drop_all ();
708
709         DEBUG_TRACE (DEBUG::GenericMidi, "Loading bindings\n");
710         for (citer = children.begin(); citer != children.end(); ++citer) {
711
712                 if ((*citer)->name() == "DeviceInfo") {
713                         const XMLProperty* prop;
714
715                         if ((prop = (*citer)->property ("bank-size")) != 0) {
716                                 _bank_size = atoi (prop->value());
717                                 _current_bank = 0;
718                         }
719
720                         if ((prop = (*citer)->property ("motorized")) != 0) {
721                                 _motorised = string_is_affirmative (prop->value ());
722                         } else {
723                                 _motorised = false;
724                         }
725
726                         if ((prop = (*citer)->property ("threshold")) != 0) {
727                                 _threshold = atoi (prop->value ());
728                         } else {
729                                 _threshold = 10;
730                         }
731
732                 }
733
734                 if ((*citer)->name() == "Binding") {
735                         const XMLNode* child = *citer;
736
737                         if (child->property ("uri")) {
738                                 /* controllable */
739
740                                 if ((mc = create_binding (*child)) != 0) {
741                                         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
742                                         controllables.push_back (mc);
743                                 }
744
745                         } else if (child->property ("function")) {
746
747                                 /* function */
748                                 MIDIFunction* mf;
749
750                                 if ((mf = create_function (*child)) != 0) {
751                                         functions.push_back (mf);
752                                 }
753
754                         } else if (child->property ("action")) {
755                                 MIDIAction* ma;
756
757                                 if ((ma = create_action (*child)) != 0) {
758                                         actions.push_back (ma);
759                                 }
760                         }
761                 }
762         }
763
764         if ((prop = root->property ("name")) != 0) {
765                 _current_binding = prop->value ();
766         }
767
768         reset_controllables ();
769
770         return 0;
771 }
772
773 MIDIControllable*
774 GenericMidiControlProtocol::create_binding (const XMLNode& node)
775 {
776         const XMLProperty* prop;
777         MIDI::byte detail;
778         MIDI::channel_t channel;
779         string uri;
780         MIDI::eventType ev;
781         int intval;
782         bool momentary;
783         MIDIControllable::Encoder encoder = MIDIControllable::No_enc;
784
785         if ((prop = node.property (X_("ctl"))) != 0) {
786                 ev = MIDI::controller;
787         } else if ((prop = node.property (X_("note"))) != 0) {
788                 ev = MIDI::on;
789         } else if ((prop = node.property (X_("pgm"))) != 0) {
790                 ev = MIDI::program;
791         } else if ((prop = node.property (X_("pb"))) != 0) {
792                 ev = MIDI::pitchbend;
793         } else if ((prop = node.property (X_("enc-l"))) != 0) {
794                 encoder = MIDIControllable::Enc_L;
795                 ev = MIDI::controller;
796         } else if ((prop = node.property (X_("enc-r"))) != 0) {
797                 encoder = MIDIControllable::Enc_R;
798                 ev = MIDI::controller;
799         } else if ((prop = node.property (X_("enc-2"))) != 0) {
800                 encoder = MIDIControllable::Enc_2;
801                 ev = MIDI::controller;
802         } else if ((prop = node.property (X_("enc-b"))) != 0) {
803                 encoder = MIDIControllable::Enc_B;
804                 ev = MIDI::controller;
805         } else {
806                 return 0;
807         }
808
809         if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
810                 return 0;
811         }
812
813         detail = (MIDI::byte) intval;
814
815         if ((prop = node.property (X_("channel"))) == 0) {
816                 return 0;
817         }
818
819         if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
820                 return 0;
821         }
822         channel = (MIDI::channel_t) intval;
823         /* adjust channel to zero-based counting */
824         if (channel > 0) {
825                 channel -= 1;
826         }
827
828         if ((prop = node.property (X_("momentary"))) != 0) {
829                 momentary = string_is_affirmative (prop->value());
830         } else {
831                 momentary = false;
832         }
833
834         prop = node.property (X_("uri"));
835         uri = prop->value();
836
837         MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary);
838
839         if (mc->init (uri)) {
840                 delete mc;
841                 return 0;
842         }
843
844         mc->set_encoder (encoder);
845         mc->bind_midi (channel, ev, detail);
846
847         return mc;
848 }
849
850 void
851 GenericMidiControlProtocol::reset_controllables ()
852 {
853         Glib::Threads::Mutex::Lock lm2 (controllables_lock);
854
855         for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
856                 MIDIControllable* existingBinding = (*iter);
857                 MIDIControllables::iterator next = iter;
858                 ++next;
859
860                 if (!existingBinding->learned()) {
861                         ControllableDescriptor& desc (existingBinding->descriptor());
862
863                         if (desc.banked()) {
864                                 desc.set_bank_offset (_current_bank * _bank_size);
865                         }
866
867                         /* its entirely possible that the session doesn't have
868                          * the specified controllable (e.g. it has too few
869                          * tracks). if we find this to be the case, we just leave
870                          * the binding around, unbound, and it will do "late
871                          * binding" (or "lazy binding") if/when any data arrives.
872                          */
873
874                         existingBinding->lookup_controllable ();
875                 }
876
877                 iter = next;
878         }
879 }
880
881 boost::shared_ptr<Controllable>
882 GenericMidiControlProtocol::lookup_controllable (const ControllableDescriptor& desc) const
883 {
884         return session->controllable_by_descriptor (desc);
885 }
886
887 MIDIFunction*
888 GenericMidiControlProtocol::create_function (const XMLNode& node)
889 {
890         const XMLProperty* prop;
891         int intval;
892         MIDI::byte detail = 0;
893         MIDI::channel_t channel = 0;
894         string uri;
895         MIDI::eventType ev;
896         MIDI::byte* data = 0;
897         uint32_t data_size = 0;
898         string argument;
899
900         if ((prop = node.property (X_("ctl"))) != 0) {
901                 ev = MIDI::controller;
902         } else if ((prop = node.property (X_("note"))) != 0) {
903                 ev = MIDI::on;
904         } else if ((prop = node.property (X_("pgm"))) != 0) {
905                 ev = MIDI::program;
906         } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
907
908                 if (prop->name() == X_("sysex")) {
909                         ev = MIDI::sysex;
910                 } else {
911                         ev = MIDI::any;
912                 }
913
914                 int val;
915                 uint32_t cnt;
916
917                 {
918                         cnt = 0;
919                         stringstream ss (prop->value());
920                         ss << hex;
921
922                         while (ss >> val) {
923                                 cnt++;
924                         }
925                 }
926
927                 if (cnt == 0) {
928                         return 0;
929                 }
930
931                 data = new MIDI::byte[cnt];
932                 data_size = cnt;
933
934                 {
935                         stringstream ss (prop->value());
936                         ss << hex;
937                         cnt = 0;
938
939                         while (ss >> val) {
940                                 data[cnt++] = (MIDI::byte) val;
941                         }
942                 }
943
944         } else {
945                 warning << "Binding ignored - unknown type" << endmsg;
946                 return 0;
947         }
948
949         if (data_size == 0) {
950                 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
951                         return 0;
952                 }
953
954                 detail = (MIDI::byte) intval;
955
956                 if ((prop = node.property (X_("channel"))) == 0) {
957                         return 0;
958                 }
959
960                 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
961                         return 0;
962                 }
963                 channel = (MIDI::channel_t) intval;
964                 /* adjust channel to zero-based counting */
965                 if (channel > 0) {
966                         channel -= 1;
967                 }
968         }
969
970         if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
971                 argument = prop->value ();
972         }
973
974         prop = node.property (X_("function"));
975
976         MIDIFunction* mf = new MIDIFunction (*_input_port->parser());
977
978         if (mf->setup (*this, prop->value(), argument, data, data_size)) {
979                 delete mf;
980                 return 0;
981         }
982
983         mf->bind_midi (channel, ev, detail);
984
985         return mf;
986 }
987
988 MIDIAction*
989 GenericMidiControlProtocol::create_action (const XMLNode& node)
990 {
991         const XMLProperty* prop;
992         int intval;
993         MIDI::byte detail = 0;
994         MIDI::channel_t channel = 0;
995         string uri;
996         MIDI::eventType ev;
997         MIDI::byte* data = 0;
998         uint32_t data_size = 0;
999
1000         if ((prop = node.property (X_("ctl"))) != 0) {
1001                 ev = MIDI::controller;
1002         } else if ((prop = node.property (X_("note"))) != 0) {
1003                 ev = MIDI::on;
1004         } else if ((prop = node.property (X_("pgm"))) != 0) {
1005                 ev = MIDI::program;
1006         } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
1007
1008                 if (prop->name() == X_("sysex")) {
1009                         ev = MIDI::sysex;
1010                 } else {
1011                         ev = MIDI::any;
1012                 }
1013
1014                 int val;
1015                 uint32_t cnt;
1016
1017                 {
1018                         cnt = 0;
1019                         stringstream ss (prop->value());
1020                         ss << hex;
1021
1022                         while (ss >> val) {
1023                                 cnt++;
1024                         }
1025                 }
1026
1027                 if (cnt == 0) {
1028                         return 0;
1029                 }
1030
1031                 data = new MIDI::byte[cnt];
1032                 data_size = cnt;
1033
1034                 {
1035                         stringstream ss (prop->value());
1036                         ss << hex;
1037                         cnt = 0;
1038
1039                         while (ss >> val) {
1040                                 data[cnt++] = (MIDI::byte) val;
1041                         }
1042                 }
1043
1044         } else {
1045                 warning << "Binding ignored - unknown type" << endmsg;
1046                 return 0;
1047         }
1048
1049         if (data_size == 0) {
1050                 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1051                         return 0;
1052                 }
1053
1054                 detail = (MIDI::byte) intval;
1055
1056                 if ((prop = node.property (X_("channel"))) == 0) {
1057                         return 0;
1058                 }
1059
1060                 if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
1061                         return 0;
1062                 }
1063                 channel = (MIDI::channel_t) intval;
1064                 /* adjust channel to zero-based counting */
1065                 if (channel > 0) {
1066                         channel -= 1;
1067                 }
1068         }
1069
1070         prop = node.property (X_("action"));
1071
1072         MIDIAction* ma = new MIDIAction (*_input_port->parser());
1073
1074         if (ma->init (*this, prop->value(), data, data_size)) {
1075                 delete ma;
1076                 return 0;
1077         }
1078
1079         ma->bind_midi (channel, ev, detail);
1080
1081         return ma;
1082 }
1083
1084 void
1085 GenericMidiControlProtocol::set_current_bank (uint32_t b)
1086 {
1087         _current_bank = b;
1088         reset_controllables ();
1089 }
1090
1091 void
1092 GenericMidiControlProtocol::next_bank ()
1093 {
1094         _current_bank++;
1095         reset_controllables ();
1096 }
1097
1098 void
1099 GenericMidiControlProtocol::prev_bank()
1100 {
1101         if (_current_bank) {
1102                 _current_bank--;
1103                 reset_controllables ();
1104         }
1105 }
1106
1107 void
1108 GenericMidiControlProtocol::set_motorised (bool m)
1109 {
1110         _motorised = m;
1111 }
1112
1113 void
1114 GenericMidiControlProtocol::set_threshold (int t)
1115 {
1116         _threshold = t;
1117 }