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