make Ben's cool range select hack work with Push 2
[ardour.git] / libs / surfaces / push2 / push2.cc
1 /*
2   Copyright (C) 2016 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 #include <stdlib.h>
20
21 #include "pbd/compose.h"
22 #include "pbd/convert.h"
23 #include "pbd/debug.h"
24 #include "pbd/failed_constructor.h"
25 #include "pbd/file_utils.h"
26 #include "pbd/search_path.h"
27 #include "pbd/enumwriter.h"
28
29 #include "midi++/parser.h"
30 #include "timecode/time.h"
31 #include "timecode/bbt_time.h"
32
33 #include "ardour/amp.h"
34 #include "ardour/async_midi_port.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/debug.h"
37 #include "ardour/midiport_manager.h"
38 #include "ardour/midi_track.h"
39 #include "ardour/midi_port.h"
40 #include "ardour/session.h"
41 #include "ardour/tempo.h"
42
43 #include "gtkmm2ext/gui_thread.h"
44 #include "gtkmm2ext/rgb_macros.h"
45
46 #include "canvas/colors.h"
47
48 #include "canvas.h"
49 #include "gui.h"
50 #include "layout.h"
51 #include "menu.h"
52 #include "mix.h"
53 #include "push2.h"
54 #include "scale.h"
55 #include "splash.h"
56 #include "track_mix.h"
57
58 #include "pbd/i18n.h"
59
60 #ifdef PLATFORM_WINDOWS
61 #define random() rand()
62 #endif
63
64 using namespace ARDOUR;
65 using namespace std;
66 using namespace PBD;
67 using namespace Glib;
68 using namespace ArdourSurface;
69
70 #include "pbd/abstract_ui.cc" // instantiate template
71
72 #define ABLETON 0x2982
73 #define PUSH2   0x1967
74
75 __attribute__((constructor)) static void
76 register_enums ()
77 {
78         EnumWriter& enum_writer (EnumWriter::instance());
79         vector<int> i;
80         vector<string> s;
81
82
83 #define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
84 #define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
85
86 }
87
88 Push2::Push2 (ARDOUR::Session& s)
89         : ControlProtocol (s, string (X_("Ableton Push 2")))
90         , AbstractUI<Push2Request> (name())
91         , handle (0)
92         , _modifier_state (None)
93         , splash_start (0)
94         , _current_layout (0)
95         , _previous_layout (0)
96         , connection_state (ConnectionState (0))
97         , gui (0)
98         , _mode (MusicalMode::IonianMajor)
99         , _scale_root (0)
100         , _root_octave (3)
101         , _in_key (true)
102         , octave_shift (0)
103         , percussion (false)
104         , _pressure_mode (AfterTouch)
105         , selection_color (LED::Green)
106         , contrast_color (LED::Green)
107         , in_range_select (false)
108 {
109
110         build_maps ();
111         build_color_map ();
112         fill_color_table ();
113
114         /* master cannot be removed, so no need to connect to going-away signal */
115         master = session->master_out ();
116
117         if (open ()) {
118                 throw failed_constructor ();
119         }
120
121         ControlProtocol::StripableSelectionChanged.connect (selection_connection, MISSING_INVALIDATOR, boost::bind (&Push2::stripable_selection_change, this, _1), this);
122
123         /* catch current selection, if any */
124         {
125                 StripableNotificationListPtr sp (new StripableNotificationList (ControlProtocol::last_selected()));
126                 stripable_selection_change (sp);
127         }
128
129         /* catch arrival and departure of Push2 itself */
130         ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect (port_reg_connection, MISSING_INVALIDATOR, boost::bind (&Push2::port_registration_handler, this), this);
131
132         /* Catch port connections and disconnections */
133         ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&Push2::connection_handler, this, _1, _2, _3, _4, _5), this);
134
135         /* ports might already be there */
136         port_registration_handler ();
137 }
138
139 Push2::~Push2 ()
140 {
141         stop ();
142
143         delete track_mix_layout;
144         delete mix_layout;
145         delete scale_layout;
146 }
147
148 void
149 Push2::port_registration_handler ()
150 {
151         if (!_async_in && !_async_out) {
152                 /* ports not registered yet */
153                 return;
154         }
155
156         if (_async_in->connected() && _async_out->connected()) {
157                 /* don't waste cycles here */
158                 return;
159         }
160
161         string input_port_name = X_("Ableton Push 2 MIDI 1 in");
162         string output_port_name = X_("Ableton Push 2 MIDI 1 out");
163         vector<string> in;
164         vector<string> out;
165
166         AudioEngine::instance()->get_ports (string_compose (".*%1", input_port_name), DataType::MIDI, PortFlags (IsPhysical|IsOutput), in);
167         AudioEngine::instance()->get_ports (string_compose (".*%1", output_port_name), DataType::MIDI, PortFlags (IsPhysical|IsInput), out);
168
169         if (!in.empty() && !out.empty()) {
170                 cerr << "Push2: both ports found\n";
171                 cerr << "\tconnecting to " << in.front() <<  " + " << out.front() << endl;
172                 if (!_async_in->connected()) {
173                         AudioEngine::instance()->connect (_async_in->name(), in.front());
174                 }
175                 if (!_async_out->connected()) {
176                         AudioEngine::instance()->connect (_async_out->name(), out.front());
177                 }
178         }
179 }
180
181 int
182 Push2::open ()
183 {
184         int err;
185
186         if (handle) {
187                 /* already open */
188                 return 0;
189         }
190
191         if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
192                 return -1;
193         }
194
195         if ((err = libusb_claim_interface (handle, 0x00))) {
196                 return -1;
197         }
198
199         try {
200                 _canvas = new Push2Canvas (*this, 960, 160);
201                 mix_layout = new MixLayout (*this, *session, "globalmix");
202                 scale_layout = new ScaleLayout (*this, *session, "scale");
203                 track_mix_layout = new TrackMixLayout (*this, *session, "trackmix");
204                 splash_layout = new SplashLayout (*this, *session, "splash");
205         } catch (...) {
206                 error << _("Cannot construct Canvas for display") << endmsg;
207                 libusb_release_interface (handle, 0x00);
208                 libusb_close (handle);
209                 handle = 0;
210                 return -1;
211         }
212
213         /* setup ports */
214
215         _async_in  = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("Push 2 in"), true);
216         _async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Push 2 out"), true);
217
218         if (_async_in == 0 || _async_out == 0) {
219                 return -1;
220         }
221
222         /* We do not add our ports to the input/output bundles because we don't
223          * want users wiring them by hand. They could use JACK tools if they
224          * really insist on that.
225          */
226
227         _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in).get();
228         _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out).get();
229
230         /* Create a shadow port where, depending on the state of the surface,
231          * we will make pad note on/off events appear. The surface code will
232          * automatically this port to the first selected MIDI track.
233          */
234
235         boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in)->add_shadow_port (string_compose (_("%1 Pads"), X_("Push 2")), boost::bind (&Push2::pad_filter, this, _1, _2));
236         boost::shared_ptr<MidiPort> shadow_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in)->shadow_port();
237
238         if (shadow_port) {
239
240                 _output_bundle.reset (new ARDOUR::Bundle (_("Push 2 Pads"), false));
241
242                 _output_bundle->add_channel (
243                         shadow_port->name(),
244                         ARDOUR::DataType::MIDI,
245                         session->engine().make_port_name_non_relative (shadow_port->name())
246                         );
247         }
248
249         session->BundleAddedOrRemoved ();
250
251         connect_to_parser ();
252
253         return 0;
254 }
255
256 list<boost::shared_ptr<ARDOUR::Bundle> >
257 Push2::bundles ()
258 {
259         list<boost::shared_ptr<ARDOUR::Bundle> > b;
260
261         if (_output_bundle) {
262                 b.push_back (_output_bundle);
263         }
264
265         return b;
266 }
267
268 int
269 Push2::close ()
270 {
271         init_buttons (false);
272         strip_buttons_off ();
273
274         /* wait for button data to be flushed */
275         AsyncMIDIPort* asp;
276         asp = dynamic_cast<AsyncMIDIPort*> (_output_port);
277         asp->drain (10000, 500000);
278
279         AudioEngine::instance()->unregister_port (_async_in);
280         AudioEngine::instance()->unregister_port (_async_out);
281
282         _async_in.reset ((ARDOUR::Port*) 0);
283         _async_out.reset ((ARDOUR::Port*) 0);
284         _input_port = 0;
285         _output_port = 0;
286
287         periodic_connection.disconnect ();
288         session_connections.drop_connections ();
289
290         if (_current_layout) {
291                 _canvas->root()->remove (_current_layout);
292                 _current_layout = 0;
293         }
294
295         delete mix_layout;
296         mix_layout = 0;
297         delete scale_layout;
298         scale_layout = 0;
299         delete splash_layout;
300         splash_layout = 0;
301
302         if (handle) {
303                 libusb_release_interface (handle, 0x00);
304                 libusb_close (handle);
305                 handle = 0;
306         }
307
308         return 0;
309 }
310
311 void
312 Push2::strip_buttons_off ()
313 {
314         ButtonID strip_buttons[] = { Upper1, Upper2, Upper3, Upper4, Upper5, Upper6, Upper7, Upper8,
315                                      Lower1, Lower2, Lower3, Lower4, Lower5, Lower6, Lower7, Lower8, };
316
317         for (size_t n = 0; n < sizeof (strip_buttons) / sizeof (strip_buttons[0]); ++n) {
318                 Button* b = id_button_map[strip_buttons[n]];
319
320                 b->set_color (LED::Black);
321                 b->set_state (LED::OneShot24th);
322                 write (b->state_msg());
323         }
324 }
325
326
327 void
328 Push2::init_buttons (bool startup)
329 {
330         /* This is a list of buttons that we want lit because they do something
331            in ardour related (loosely, sometimes) to their illuminated label.
332         */
333
334         ButtonID buttons[] = { Mute, Solo, Master, Up, Right, Left, Down, Note, Session, Mix, AddTrack, Delete, Undo,
335                                Metronome, Shift, Select, Play, RecordEnable, Automate, Repeat, Note, Session,
336                                Quantize, Duplicate, Browse, PageRight, PageLeft, OctaveUp, OctaveDown, Layout, Scale
337         };
338
339         for (size_t n = 0; n < sizeof (buttons) / sizeof (buttons[0]); ++n) {
340                 Button* b = id_button_map[buttons[n]];
341
342                 if (startup) {
343                         b->set_color (LED::White);
344                 } else {
345                         b->set_color (LED::Black);
346                 }
347                 b->set_state (LED::OneShot24th);
348                 write (b->state_msg());
349         }
350
351         if (startup) {
352
353                 /* all other buttons are off (black) */
354
355                 ButtonID off_buttons[] = { TapTempo, Setup, User, Stop, Convert, New, FixedLength,
356                                            Fwd32ndT, Fwd32nd, Fwd16thT, Fwd16th, Fwd8thT, Fwd8th, Fwd4trT, Fwd4tr,
357                                            Accent, Note, Session,  };
358
359                 for (size_t n = 0; n < sizeof (off_buttons) / sizeof (off_buttons[0]); ++n) {
360                         Button* b = id_button_map[off_buttons[n]];
361
362                         b->set_color (LED::Black);
363                         b->set_state (LED::OneShot24th);
364                         write (b->state_msg());
365                 }
366         }
367
368         if (!startup) {
369                 for (NNPadMap::iterator pi = nn_pad_map.begin(); pi != nn_pad_map.end(); ++pi) {
370                         Pad* pad = pi->second;
371
372                         pad->set_color (LED::Black);
373                         pad->set_state (LED::OneShot24th);
374                         write (pad->state_msg());
375                 }
376         }
377 }
378
379 bool
380 Push2::probe ()
381 {
382         libusb_device_handle *h;
383         libusb_init (NULL);
384
385         if ((h = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
386                 DEBUG_TRACE (DEBUG::Push2, "no Push2 device found\n");
387                 return false;
388         }
389
390         libusb_close (h);
391         DEBUG_TRACE (DEBUG::Push2, "Push2 device located\n");
392         return true;
393 }
394
395 void*
396 Push2::request_factory (uint32_t num_requests)
397 {
398         /* AbstractUI<T>::request_buffer_factory() is a template method only
399            instantiated in this source module. To provide something visible for
400            use in the interface/descriptor, we have this static method that is
401            template-free.
402         */
403         return request_buffer_factory (num_requests);
404 }
405
406 void
407 Push2::do_request (Push2Request * req)
408 {
409         if (req->type == CallSlot) {
410
411                 call_slot (MISSING_INVALIDATOR, req->the_slot);
412
413         } else if (req->type == Quit) {
414
415                 stop ();
416         }
417 }
418
419 int
420 Push2::stop ()
421 {
422         BaseUI::quit ();
423         close ();
424         return 0;
425 }
426
427
428 void
429 Push2::splash ()
430 {
431         set_current_layout (splash_layout);
432         splash_start = get_microseconds ();
433 }
434
435 bool
436 Push2::vblank ()
437 {
438         if (splash_start) {
439
440                 /* display splash for 2 seconds */
441
442                 if (get_microseconds() - splash_start > 2000000) {
443                         splash_start = 0;
444                         DEBUG_TRACE (DEBUG::Push2, "splash interval ended, switch to mix layout\n");
445                         set_current_layout (mix_layout);
446                 }
447         }
448
449         if (_current_layout) {
450                 _current_layout->update_meters ();
451                 _current_layout->update_clocks ();
452         }
453
454         _canvas->vblank();
455
456         return true;
457 }
458
459 int
460 Push2::set_active (bool yn)
461 {
462         DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active init with yn: '%1'\n", yn));
463
464         if (yn == active()) {
465                 return 0;
466         }
467
468         if (yn) {
469
470                 /* start event loop */
471
472                 BaseUI::run ();
473
474                 if (open ()) {
475                         DEBUG_TRACE (DEBUG::Push2, "device open failed\n");
476                         close ();
477                         return -1;
478                 }
479
480                 /* Connect input port to event loop */
481
482                 AsyncMIDIPort* asp;
483
484                 asp = dynamic_cast<AsyncMIDIPort*> (_input_port);
485                 asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port));
486                 asp->xthread().attach (main_loop()->get_context());
487
488                 connect_session_signals ();
489
490                 /* set up periodic task used to push a frame buffer to the
491                  * device (25fps). The device can handle 60fps, but we don't
492                  * need that frame rate.
493                  */
494
495                 Glib::RefPtr<Glib::TimeoutSource> vblank_timeout = Glib::TimeoutSource::create (40); // milliseconds
496                 vblank_connection = vblank_timeout->connect (sigc::mem_fun (*this, &Push2::vblank));
497                 vblank_timeout->attach (main_loop()->get_context());
498
499
500                 Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (1000); // milliseconds
501                 periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &Push2::periodic));
502                 periodic_timeout->attach (main_loop()->get_context());
503
504                 init_buttons (true);
505                 init_touch_strip ();
506                 set_pad_scale (_scale_root, _root_octave, _mode, _in_key);
507                 splash ();
508
509         } else {
510
511                 stop ();
512
513         }
514
515         ControlProtocol::set_active (yn);
516
517         DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active done with yn: '%1'\n", yn));
518
519         return 0;
520 }
521
522 void
523 Push2::init_touch_strip ()
524 {
525         MidiByteArray msg (9, 0xf0, 0x00, 0x21, 0x1d, 0x01, 0x01, 0x17, 0x00, 0xf7);
526         /* flags are the final byte (ignore end-of-sysex */
527
528         /* show bar, not point
529            autoreturn to center
530            bar starts at center
531         */
532         msg[7] = (1<<4) | (1<<5) | (1<<6);
533         write (msg);
534 }
535
536 void
537 Push2::write (const MidiByteArray& data)
538 {
539         /* immediate delivery */
540         _output_port->write (&data[0], data.size(), 0);
541 }
542
543 bool
544 Push2::midi_input_handler (IOCondition ioc, MIDI::Port* port)
545 {
546         if (ioc & ~IO_IN) {
547                 DEBUG_TRACE (DEBUG::Push2, "MIDI port closed\n");
548                 return false;
549         }
550
551         if (ioc & IO_IN) {
552
553                 // DEBUG_TRACE (DEBUG::Push2, string_compose ("something happend on  %1\n", port->name()));
554
555                 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
556                 if (asp) {
557                         asp->clear ();
558                 }
559
560                 //DEBUG_TRACE (DEBUG::Push2, string_compose ("data available on %1\n", port->name()));
561                 framepos_t now = AudioEngine::instance()->sample_time();
562                 port->parse (now);
563         }
564
565         return true;
566 }
567
568 bool
569 Push2::periodic ()
570 {
571         return true;
572 }
573
574 void
575 Push2::connect_to_parser ()
576 {
577         DEBUG_TRACE (DEBUG::Push2, string_compose ("Connecting to signals on port %2\n", _input_port->name()));
578
579         MIDI::Parser* p = _input_port->parser();
580
581         /* Incoming sysex */
582         p->sysex.connect_same_thread (*this, boost::bind (&Push2::handle_midi_sysex, this, _1, _2, _3));
583         /* V-Pot messages are Controller */
584         p->controller.connect_same_thread (*this, boost::bind (&Push2::handle_midi_controller_message, this, _1, _2));
585         /* Button messages are NoteOn */
586         p->note_on.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
587         /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
588         p->note_off.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
589         /* Fader messages are Pitchbend */
590         p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&Push2::handle_midi_pitchbend_message, this, _1, _2));
591 }
592
593 void
594 Push2::handle_midi_sysex (MIDI::Parser&, MIDI::byte* raw_bytes, size_t sz)
595 {
596         DEBUG_TRACE (DEBUG::Push2, string_compose ("Sysex, %1 bytes\n", sz));
597
598         if (sz < 8) {
599                 return;
600         }
601
602         MidiByteArray msg (sz, raw_bytes);
603         MidiByteArray push2_sysex_header (6, 0xF0, 0x00, 0x21, 0x1D, 0x01, 0x01);
604
605         if (!push2_sysex_header.compare_n (msg, 6)) {
606                 return;
607         }
608
609         switch (msg[6]) {
610         case 0x1f: /* pressure mode */
611                 if (msg[7] == 0x0) {
612                         _pressure_mode = AfterTouch;
613                         PressureModeChange (AfterTouch);
614                         cerr << "Pressure mode is after\n";
615                 } else {
616                         _pressure_mode = PolyPressure;
617                         PressureModeChange (PolyPressure);
618                         cerr << "Pressure mode is poly\n";
619                 }
620                 break;
621         }
622 }
623
624 void
625 Push2::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
626 {
627         DEBUG_TRACE (DEBUG::Push2, string_compose ("CC %1 (value %2)\n", (int) ev->controller_number, (int) ev->value));
628
629         CCButtonMap::iterator b = cc_button_map.find (ev->controller_number);
630
631         if (ev->value) {
632                 /* any press cancels any pending long press timeouts */
633                 for (set<ButtonID>::iterator x = buttons_down.begin(); x != buttons_down.end(); ++x) {
634                         Button* bb = id_button_map[*x];
635                         bb->timeout_connection.disconnect ();
636                 }
637         }
638
639         if (b != cc_button_map.end()) {
640
641                 Button* button = b->second;
642
643                 if (ev->value) {
644                         buttons_down.insert (button->id);
645                         start_press_timeout (*button, button->id);
646                 } else {
647                         buttons_down.erase (button->id);
648                         button->timeout_connection.disconnect ();
649                 }
650
651
652                 set<ButtonID>::iterator c = consumed.find (button->id);
653
654                 if (c == consumed.end()) {
655                         if (ev->value == 0) {
656                                 (this->*button->release_method)();
657                         } else {
658                                 (this->*button->press_method)();
659                         }
660                 } else {
661                         DEBUG_TRACE (DEBUG::Push2, "button was consumed, ignored\n");
662                         consumed.erase (c);
663                 }
664
665         } else {
666
667                 /* encoder/vpot */
668
669                 int delta = ev->value;
670
671                 if (delta > 63) {
672                         delta = -(128 - delta);
673                 }
674
675                 switch (ev->controller_number) {
676                 case 71:
677                         _current_layout->strip_vpot (0, delta);
678                         break;
679                 case 72:
680                         _current_layout->strip_vpot (1, delta);
681                         break;
682                 case 73:
683                         _current_layout->strip_vpot (2, delta);
684                         break;
685                 case 74:
686                         _current_layout->strip_vpot (3, delta);
687                         break;
688                 case 75:
689                         _current_layout->strip_vpot (4, delta);
690                         break;
691                 case 76:
692                         _current_layout->strip_vpot (5, delta);
693                         break;
694                 case 77:
695                         _current_layout->strip_vpot (6, delta);
696                         break;
697                 case 78:
698                         _current_layout->strip_vpot (7, delta);
699                         break;
700
701                         /* left side pair */
702                 case 14:
703                         other_vpot (8, delta);
704                         break;
705                 case 15:
706                         other_vpot (1, delta);
707                         break;
708
709                         /* right side */
710                 case 79:
711                         other_vpot (2, delta);
712                         break;
713                 }
714         }
715 }
716
717 void
718 Push2::handle_midi_note_on_message (MIDI::Parser& parser, MIDI::EventTwoBytes* ev)
719 {
720         // DEBUG_TRACE (DEBUG::Push2, string_compose ("Note On %1 (velocity %2)\n", (int) ev->note_number, (int) ev->velocity));
721
722         if (ev->velocity == 0) {
723                 handle_midi_note_off_message (parser, ev);
724                 return;
725         }
726
727         switch (ev->note_number) {
728         case 0:
729                 _current_layout->strip_vpot_touch (0, ev->velocity > 64);
730                 break;
731         case 1:
732                 _current_layout->strip_vpot_touch (1, ev->velocity > 64);
733                 break;
734         case 2:
735                 _current_layout->strip_vpot_touch (2, ev->velocity > 64);
736                 break;
737         case 3:
738                 _current_layout->strip_vpot_touch (3, ev->velocity > 64);
739                 break;
740         case 4:
741                 _current_layout->strip_vpot_touch (4, ev->velocity > 64);
742                 break;
743         case 5:
744                 _current_layout->strip_vpot_touch (5, ev->velocity > 64);
745                 break;
746         case 6:
747                 _current_layout->strip_vpot_touch (6, ev->velocity > 64);
748                 break;
749         case 7:
750                 _current_layout->strip_vpot_touch (7, ev->velocity > 64);
751                 break;
752
753                 /* left side */
754         case 10:
755                 other_vpot_touch (0, ev->velocity > 64);
756                 break;
757         case 9:
758                 other_vpot_touch (1, ev->velocity > 64);
759                 break;
760
761                 /* right side */
762         case 8:
763                 other_vpot_touch (3, ev->velocity > 64);
764                 break;
765
766                 /* touch strip */
767         case 12:
768                 if (ev->velocity < 64) {
769                         transport_stop ();
770                 }
771                 break;
772         }
773
774         if (ev->note_number < 11) {
775                 return;
776         }
777
778         /* Pad illuminations */
779
780         NNPadMap::const_iterator pm = nn_pad_map.find (ev->note_number);
781
782         if (pm == nn_pad_map.end()) {
783                 return;
784         }
785
786         const Pad * const pad_pressed = pm->second;
787
788         pair<FNPadMap::iterator,FNPadMap::iterator> pads_with_note = fn_pad_map.equal_range (pad_pressed->filtered);
789
790         if (pads_with_note.first == fn_pad_map.end()) {
791                 return;
792         }
793
794         for (FNPadMap::iterator pi = pads_with_note.first; pi != pads_with_note.second; ++pi) {
795                 Pad* pad = pi->second;
796
797                 pad->set_color (contrast_color);
798                 pad->set_state (LED::OneShot24th);
799                 write (pad->state_msg());
800         }
801 }
802
803 void
804 Push2::handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
805 {
806         // DEBUG_TRACE (DEBUG::Push2, string_compose ("Note Off %1 (velocity %2)\n", (int) ev->note_number, (int) ev->velocity));
807
808         if (ev->note_number < 11) {
809                 /* theoretically related to encoder touch start/end, but
810                  * actually they send note on with two different velocity
811                  * values (127 & 64).
812                  */
813                 return;
814         }
815
816         /* Pad illuminations */
817
818         NNPadMap::const_iterator pm = nn_pad_map.find (ev->note_number);
819
820         if (pm == nn_pad_map.end()) {
821                 return;
822         }
823
824         const Pad * const pad_pressed = pm->second;
825
826         pair<FNPadMap::iterator,FNPadMap::iterator> pads_with_note = fn_pad_map.equal_range (pad_pressed->filtered);
827
828         if (pads_with_note.first == fn_pad_map.end()) {
829                 return;
830         }
831
832         for (FNPadMap::iterator pi = pads_with_note.first; pi != pads_with_note.second; ++pi) {
833                 Pad* pad = pi->second;
834
835                 if (pad->do_when_pressed == Pad::FlashOn) {
836                         pad->set_color (LED::Black);
837                         pad->set_state (LED::OneShot24th);
838                         write (pad->state_msg());
839                 } else if (pad->do_when_pressed == Pad::FlashOff) {
840                         pad->set_color (pad->perma_color);
841                         pad->set_state (LED::OneShot24th);
842                         write (pad->state_msg());
843                 }
844         }
845 }
846
847 void
848 Push2::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb)
849 {
850 }
851
852 void
853 Push2::thread_init ()
854 {
855         struct sched_param rtparam;
856
857         pthread_set_name (event_loop_name().c_str());
858
859         PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
860         ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
861
862         memset (&rtparam, 0, sizeof (rtparam));
863         rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
864
865         if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
866                 // do we care? not particularly.
867         }
868 }
869
870 void
871 Push2::connect_session_signals()
872 {
873         // receive routes added
874         //session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_routes_added, this, _1), this);
875         // receive VCAs added
876         //session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_vca_added, this, _1), this);
877
878         // receive record state toggled
879         session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_record_state_changed, this), this);
880         // receive transport state changed
881         session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_transport_state_changed, this), this);
882         session->TransportLooped.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_loop_state_changed, this), this);
883         // receive punch-in and punch-out
884         Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
885         session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
886         // receive rude solo changed
887         session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_solo_active_changed, this, _1), this);
888 }
889
890 void
891 Push2::notify_record_state_changed ()
892 {
893         IDButtonMap::iterator b = id_button_map.find (RecordEnable);
894
895         if (b == id_button_map.end()) {
896                 return;
897         }
898
899         switch (session->record_status ()) {
900         case Session::Disabled:
901                 b->second->set_color (LED::White);
902                 b->second->set_state (LED::NoTransition);
903                 break;
904         case Session::Enabled:
905                 b->second->set_color (LED::Red);
906                 b->second->set_state (LED::Blinking4th);
907                 break;
908         case Session::Recording:
909                 b->second->set_color (LED::Red);
910                 b->second->set_state (LED::OneShot24th);
911                 break;
912         }
913
914         write (b->second->state_msg());
915 }
916
917 void
918 Push2::notify_transport_state_changed ()
919 {
920         Button* b = id_button_map[Play];
921
922         if (session->transport_rolling()) {
923                 b->set_state (LED::OneShot24th);
924                 b->set_color (LED::Green);
925         } else {
926
927                 /* disable any blink on FixedLength from pending edit range op */
928                 Button* fl = id_button_map[FixedLength];
929
930                 fl->set_color (LED::Black);
931                 fl->set_state (LED::NoTransition);
932                 write (fl->state_msg());
933
934                 b->set_color (LED::White);
935                 b->set_state (LED::NoTransition);
936         }
937
938         write (b->state_msg());
939 }
940
941 void
942 Push2::notify_loop_state_changed ()
943 {
944 }
945
946 void
947 Push2::notify_parameter_changed (std::string param)
948 {
949         IDButtonMap::iterator b;
950
951         if (param == "clicking") {
952                 if ((b = id_button_map.find (Metronome)) == id_button_map.end()) {
953                         return;
954                 }
955                 if (Config->get_clicking()) {
956                         b->second->set_state (LED::Blinking4th);
957                         b->second->set_color (LED::White);
958                 } else {
959                         b->second->set_color (LED::White);
960                         b->second->set_state (LED::NoTransition);
961                 }
962                 write (b->second->state_msg ());
963         }
964 }
965
966 void
967 Push2::notify_solo_active_changed (bool yn)
968 {
969         IDButtonMap::iterator b = id_button_map.find (Solo);
970
971         if (b == id_button_map.end()) {
972                 return;
973         }
974
975         if (yn) {
976                 b->second->set_state (LED::Blinking4th);
977                 b->second->set_color (LED::Red);
978         } else {
979                 b->second->set_state (LED::NoTransition);
980                 b->second->set_color (LED::White);
981         }
982
983         write (b->second->state_msg());
984 }
985
986 XMLNode&
987 Push2::get_state()
988 {
989         XMLNode& node (ControlProtocol::get_state());
990         XMLNode* child;
991
992         child = new XMLNode (X_("Input"));
993         child->add_child_nocopy (_async_in->get_state());
994         node.add_child_nocopy (*child);
995         child = new XMLNode (X_("Output"));
996         child->add_child_nocopy (_async_out->get_state());
997         node.add_child_nocopy (*child);
998
999         node.add_property (X_("root"), to_string (_scale_root, std::dec));
1000         node.add_property (X_("root_octave"), to_string (_root_octave, std::dec));
1001         node.add_property (X_("in_key"), _in_key ? X_("yes") : X_("no"));
1002         node.add_property (X_("mode"), enum_2_string (_mode));
1003
1004         return node;
1005 }
1006
1007 int
1008 Push2::set_state (const XMLNode & node, int version)
1009 {
1010         DEBUG_TRACE (DEBUG::Push2, string_compose ("Push2::set_state: active %1\n", active()));
1011
1012         int retval = 0;
1013
1014         if (ControlProtocol::set_state (node, version)) {
1015                 return -1;
1016         }
1017
1018         XMLNode* child;
1019
1020         if ((child = node.child (X_("Input"))) != 0) {
1021                 XMLNode* portnode = child->child (Port::state_node_name.c_str());
1022                 if (portnode) {
1023                         _async_in->set_state (*portnode, version);
1024                 }
1025         }
1026
1027         if ((child = node.child (X_("Output"))) != 0) {
1028                 XMLNode* portnode = child->child (Port::state_node_name.c_str());
1029                 if (portnode) {
1030                         _async_out->set_state (*portnode, version);
1031                 }
1032         }
1033
1034         XMLProperty const* prop;
1035
1036         if ((prop = node.property (X_("root"))) != 0) {
1037                 _scale_root = atoi (prop->value());
1038         }
1039
1040         if ((prop = node.property (X_("root_octave"))) != 0) {
1041                 _root_octave = atoi (prop->value());
1042         }
1043
1044         if ((prop = node.property (X_("in_key"))) != 0) {
1045                 _in_key = string_is_affirmative (prop->value());
1046         }
1047
1048         if ((prop = node.property (X_("mode"))) != 0) {
1049                 _mode = (MusicalMode::Type) string_2_enum (prop->value(), _mode);
1050         }
1051
1052         return retval;
1053 }
1054
1055 void
1056 Push2::other_vpot (int n, int delta)
1057 {
1058         boost::shared_ptr<Amp> click_gain;
1059         switch (n) {
1060         case 0:
1061                 /* tempo control */
1062                 break;
1063         case 1:
1064                 /* metronome gain control */
1065                 click_gain = session->click_gain();
1066                 if (click_gain) {
1067                         boost::shared_ptr<AutomationControl> ac = click_gain->gain_control();
1068                         if (ac) {
1069                                 ac->set_value (ac->interface_to_internal (
1070                                                        min (ac->upper(), max (ac->lower(), ac->internal_to_interface (ac->get_value()) + (delta/256.0)))),
1071                                                PBD::Controllable::UseGroup);
1072                         }
1073                 }
1074                 break;
1075         case 2:
1076                 /* master gain control */
1077                 if (master) {
1078                         boost::shared_ptr<AutomationControl> ac = master->gain_control();
1079                         if (ac) {
1080                                 ac->set_value (ac->interface_to_internal (
1081                                                        min (ac->upper(), max (ac->lower(), ac->internal_to_interface (ac->get_value()) + (delta/256.0)))),
1082                                                PBD::Controllable::UseGroup);
1083                         }
1084                 }
1085                 break;
1086         }
1087 }
1088
1089 void
1090 Push2::other_vpot_touch (int n, bool touching)
1091 {
1092         switch (n) {
1093         case 0:
1094                 break;
1095         case 1:
1096                 break;
1097         case 2:
1098                 if (master) {
1099                         boost::shared_ptr<AutomationControl> ac = master->gain_control();
1100                         if (ac) {
1101                                 if (touching) {
1102                                         ac->start_touch (session->audible_frame());
1103                                 } else {
1104                                         ac->stop_touch (true, session->audible_frame());
1105                                 }
1106                         }
1107                 }
1108         }
1109 }
1110
1111 void
1112 Push2::start_shift ()
1113 {
1114         cerr << "start shift\n";
1115         _modifier_state = ModifierState (_modifier_state | ModShift);
1116         Button* b = id_button_map[Shift];
1117         b->set_color (LED::White);
1118         b->set_state (LED::Blinking16th);
1119         write (b->state_msg());
1120 }
1121
1122 void
1123 Push2::end_shift ()
1124 {
1125         if (_modifier_state & ModShift) {
1126                 cerr << "end shift\n";
1127                 _modifier_state = ModifierState (_modifier_state & ~(ModShift));
1128                 Button* b = id_button_map[Shift];
1129                 b->timeout_connection.disconnect ();
1130                 b->set_color (LED::White);
1131                 b->set_state (LED::OneShot24th);
1132                 write (b->state_msg());
1133         }
1134 }
1135
1136 bool
1137 Push2::pad_filter (MidiBuffer& in, MidiBuffer& out) const
1138 {
1139         /* This filter is called asynchronously from a realtime process
1140            context. It must use atomics to check state, and must not block.
1141         */
1142
1143         bool matched = false;
1144
1145         for (MidiBuffer::iterator ev = in.begin(); ev != in.end(); ++ev) {
1146                 if ((*ev).is_note_on() || (*ev).is_note_off()) {
1147
1148                         /* encoder touch start/touch end use note
1149                          * 0-10. touchstrip uses note 12
1150                          */
1151
1152                         if ((*ev).note() > 10 && (*ev).note() != 12) {
1153
1154                                 const int n = (*ev).note ();
1155                                 NNPadMap::const_iterator nni = nn_pad_map.find (n);
1156
1157                                 if (nni != nn_pad_map.end()) {
1158                                         Pad const * pad = nni->second;
1159                                         /* shift for output to the shadow port */
1160                                         if (pad->filtered >= 0) {
1161                                                 (*ev).set_note (pad->filtered + (octave_shift*12));
1162                                                 out.push_back (*ev);
1163                                                 /* shift back so that the pads light correctly  */
1164                                                 (*ev).set_note (n);
1165                                         } else {
1166                                                 /* no mapping, don't send event */
1167                                         }
1168                                 } else {
1169                                         out.push_back (*ev);
1170                                 }
1171
1172                                 matched = true;
1173                         }
1174                 } else if ((*ev).is_pitch_bender() || (*ev).is_poly_pressure() || (*ev).is_channel_pressure()) {
1175                         out.push_back (*ev);
1176                 }
1177         }
1178
1179         return matched;
1180 }
1181
1182 bool
1183 Push2::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
1184 {
1185         DEBUG_TRACE (DEBUG::FaderPort, "FaderPort::connection_handler  start\n");
1186         if (!_input_port || !_output_port) {
1187                 return false;
1188         }
1189
1190         string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_async_in)->name());
1191         string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_async_out)->name());
1192
1193         if (ni == name1 || ni == name2) {
1194                 if (yn) {
1195                         connection_state |= InputConnected;
1196                 } else {
1197                         connection_state &= ~InputConnected;
1198                 }
1199         } else if (no == name1 || no == name2) {
1200                 if (yn) {
1201                         connection_state |= OutputConnected;
1202                 } else {
1203                         connection_state &= ~OutputConnected;
1204                 }
1205         } else {
1206                 DEBUG_TRACE (DEBUG::FaderPort, string_compose ("Connections between %1 and %2 changed, but I ignored it\n", name1, name2));
1207                 /* not our ports */
1208                 return false;
1209         }
1210
1211         if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
1212
1213                 /* XXX this is a horrible hack. Without a short sleep here,
1214                    something prevents the device wakeup messages from being
1215                    sent and/or the responses from being received.
1216                 */
1217
1218                 g_usleep (100000);
1219                 DEBUG_TRACE (DEBUG::FaderPort, "device now connected for both input and output\n");
1220                 connected ();
1221
1222         } else {
1223                 DEBUG_TRACE (DEBUG::FaderPort, "Device disconnected (input or output or both) or not yet fully connected\n");
1224         }
1225
1226         ConnectionChange (); /* emit signal for our GUI */
1227
1228         DEBUG_TRACE (DEBUG::FaderPort, "FaderPort::connection_handler  end\n");
1229
1230         return true; /* connection status changed */
1231 }
1232
1233 void
1234 Push2::connected ()
1235 {
1236         request_pressure_mode ();
1237 }
1238
1239 boost::shared_ptr<Port>
1240 Push2::output_port()
1241 {
1242         return _async_out;
1243 }
1244
1245 boost::shared_ptr<Port>
1246 Push2::input_port()
1247 {
1248         return _async_in;
1249 }
1250
1251 int
1252 Push2::pad_note (int row, int col) const
1253 {
1254         NNPadMap::const_iterator nni = nn_pad_map.find (36+(row*8)+col);
1255
1256         if (nni != nn_pad_map.end()) {
1257                 return nni->second->filtered;
1258         }
1259
1260         return 0;
1261 }
1262
1263 void
1264 Push2::update_selection_color ()
1265 {
1266         boost::shared_ptr<MidiTrack> current_midi_track = current_pad_target.lock();
1267
1268         if (!current_midi_track) {
1269                 return;
1270         }
1271
1272         selection_color = get_color_index (current_midi_track->presentation_info().color());
1273         contrast_color = get_color_index (ArdourCanvas::HSV (current_midi_track->presentation_info().color()).opposite().color());
1274
1275         reset_pad_colors ();
1276 }
1277
1278 void
1279 Push2::reset_pad_colors ()
1280 {
1281         set_pad_scale (_scale_root, _root_octave, _mode, _in_key);
1282 }
1283
1284 void
1285 Push2::set_pad_scale (int root, int octave, MusicalMode::Type mode, bool inkey)
1286 {
1287         MusicalMode m (mode);
1288         vector<float>::iterator interval;
1289         int note;
1290         const int original_root = root;
1291
1292         interval = m.steps.begin();
1293         root += (octave*12);
1294         note = root;
1295
1296         const int root_start = root;
1297
1298         set<int> mode_map; /* contains only notes in mode, O(logN) lookup */
1299         vector<int> mode_vector; /* sorted in note order */
1300
1301         mode_map.insert (note);
1302         mode_vector.push_back (note);
1303
1304         /* build a map of all notes in the mode, from the root to 127 */
1305
1306         while (note < 128) {
1307
1308                 if (interval == m.steps.end()) {
1309
1310                         /* last distance was the end of the scale,
1311                            so wrap, adding the next note at one
1312                            octave above the last root.
1313                         */
1314
1315                         interval = m.steps.begin();
1316                         root += 12;
1317                         mode_map.insert (root);
1318                         mode_vector.push_back (root);
1319
1320                 } else {
1321                         note = (int) floor (root + (2.0 * (*interval)));
1322                         interval++;
1323                         mode_map.insert (note);
1324                         mode_vector.push_back (note);
1325                 }
1326         }
1327
1328         fn_pad_map.clear ();
1329
1330         if (inkey) {
1331
1332                 vector<int>::iterator notei;
1333                 int row_offset = 0;
1334
1335                 for (int row = 0; row < 8; ++row) {
1336
1337                         /* Ableton's grid layout wraps the available notes in the scale
1338                          * by offsetting 3 notes per row (from the bottom)
1339                          */
1340
1341                         notei = mode_vector.begin();
1342                         notei += row_offset;
1343                         row_offset += 3;
1344
1345                         for (int col = 0; col < 8; ++col) {
1346                                 int index = 36 + (row*8) + col;
1347                                 Pad* pad = nn_pad_map[index];
1348                                 int notenum;
1349                                 if (notei != mode_vector.end()) {
1350
1351                                         notenum = *notei;
1352                                         pad->filtered = notenum;
1353
1354                                         fn_pad_map.insert (make_pair (notenum, pad));
1355
1356                                         if ((notenum % 12) == original_root) {
1357                                                 pad->set_color (selection_color);
1358                                                 pad->perma_color = selection_color;
1359                                         } else {
1360                                                 pad->set_color (LED::White);
1361                                                 pad->perma_color = LED::White;
1362                                         }
1363
1364                                         pad->do_when_pressed = Pad::FlashOff;
1365                                         notei++;
1366
1367                                 } else {
1368
1369                                         pad->set_color (LED::Black);
1370                                         pad->do_when_pressed = Pad::Nothing;
1371                                         pad->filtered = -1;
1372                                 }
1373
1374                                 pad->set_state (LED::OneShot24th);
1375                                 write (pad->state_msg());
1376                         }
1377                 }
1378
1379         } else {
1380
1381                 /* chromatic: all notes available, but highlight those in the scale */
1382
1383                 for (note = 36; note < 100; ++note) {
1384
1385                         Pad* pad = nn_pad_map[note];
1386
1387                         /* Chromatic: all pads play, half-tone steps. Light
1388                          * those in the scale, and highlight root notes
1389                          */
1390
1391                         pad->filtered = root_start + (note - 36);
1392
1393                         fn_pad_map.insert (make_pair (pad->filtered, pad));
1394
1395                         if (mode_map.find (note) != mode_map.end()) {
1396
1397                                 if ((note % 12) == original_root) {
1398                                         pad->set_color (selection_color);
1399                                         pad->perma_color = selection_color;
1400                                 } else {
1401                                         pad->set_color (LED::White);
1402                                         pad->perma_color = LED::White;
1403                                 }
1404
1405                                 pad->do_when_pressed = Pad::FlashOff;
1406
1407                         } else {
1408
1409                                 /* note is not in mode, turn it off */
1410
1411                                 pad->do_when_pressed = Pad::FlashOn;
1412                                 pad->set_color (LED::Black);
1413
1414                         }
1415
1416                         pad->set_state (LED::OneShot24th);
1417                         write (pad->state_msg());
1418                 }
1419         }
1420
1421         /* store state */
1422
1423         bool changed = false;
1424
1425         if (_scale_root != original_root) {
1426                 _scale_root = original_root;
1427                 changed = true;
1428         }
1429         if (_root_octave != octave) {
1430                 _root_octave = octave;
1431                 changed = true;
1432         }
1433         if (_in_key != inkey) {
1434                 _in_key = inkey;
1435                 changed = true;
1436         }
1437         if (_mode != mode) {
1438                 _mode = mode;
1439                 changed = true;
1440         }
1441
1442         if (changed) {
1443                 ScaleChange (); /* EMIT SIGNAL */
1444         }
1445 }
1446
1447 void
1448 Push2::set_percussive_mode (bool yn)
1449 {
1450         if (!yn) {
1451                 cerr << "back to scale\n";
1452                 set_pad_scale (_scale_root, _root_octave, _mode, _in_key);
1453                 percussion = false;
1454                 return;
1455         }
1456
1457         int drum_note = 36;
1458
1459         fn_pad_map.clear ();
1460
1461         for (int row = 0; row < 8; ++row) {
1462
1463                 for (int col = 0; col < 4; ++col) {
1464
1465                         int index = 36 + (row*8) + col;
1466                         Pad* pad = nn_pad_map[index];
1467
1468                         pad->filtered = drum_note;
1469                         drum_note++;
1470                 }
1471         }
1472
1473         for (int row = 0; row < 8; ++row) {
1474
1475                 for (int col = 4; col < 8; ++col) {
1476
1477                         int index = 36 + (row*8) + col;
1478                         Pad* pad = nn_pad_map[index];
1479
1480                         pad->filtered = drum_note;
1481                         drum_note++;
1482                 }
1483         }
1484
1485         percussion = true;
1486 }
1487
1488 Push2Layout*
1489 Push2::current_layout () const
1490 {
1491         Glib::Threads::Mutex::Lock lm (layout_lock);
1492         return _current_layout;
1493 }
1494
1495 void
1496 Push2::stripable_selection_change (StripableNotificationListPtr selected)
1497 {
1498         boost::shared_ptr<MidiPort> pad_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in)->shadow_port();
1499         boost::shared_ptr<MidiTrack> current_midi_track = current_pad_target.lock();
1500         boost::shared_ptr<MidiTrack> new_pad_target;
1501
1502         /* See if there's a MIDI track selected */
1503
1504         for (StripableNotificationList::iterator si = selected->begin(); si != selected->end(); ++si) {
1505
1506                 new_pad_target = boost::dynamic_pointer_cast<MidiTrack> ((*si).lock());
1507
1508                 if (new_pad_target) {
1509                         break;
1510                 }
1511         }
1512
1513         if (current_midi_track == new_pad_target) {
1514                 /* nothing to do */
1515                 return;
1516         }
1517
1518         if (!new_pad_target) {
1519                 /* leave existing connection alone */
1520                 return;
1521         }
1522
1523         /* disconnect from pad port, if appropriate */
1524
1525         if (current_midi_track && pad_port) {
1526
1527                 /* XXX this could possibly leave dangling MIDI notes.
1528                  *
1529                  * A general libardour fix is required. It isn't obvious
1530                  * how note resolution can be done unless disconnecting
1531                  * becomes "slow" (i.e. deferred for as long as it takes
1532                  * to resolve notes).
1533                  */
1534                 current_midi_track->input()->disconnect (current_midi_track->input()->nth(0), pad_port->name(), this);
1535         }
1536
1537         /* now connect the pad port to this (newly) selected midi
1538          * track, if indeed there is one.
1539          */
1540
1541         if (new_pad_target && pad_port) {
1542                 new_pad_target->input()->connect (new_pad_target->input()->nth (0), pad_port->name(), this);
1543                 current_pad_target = new_pad_target;
1544                 selection_color = get_color_index (new_pad_target->presentation_info().color());
1545                 contrast_color = get_color_index (ArdourCanvas::HSV (new_pad_target->presentation_info().color()).opposite().color());
1546         } else {
1547                 current_pad_target.reset ();
1548                 selection_color = LED::Green;
1549                 contrast_color = LED::Green;
1550         }
1551
1552         reset_pad_colors ();
1553 }
1554
1555 Push2::Button*
1556 Push2::button_by_id (ButtonID bid)
1557 {
1558         return id_button_map[bid];
1559 }
1560
1561 uint8_t
1562 Push2::get_color_index (ArdourCanvas::Color rgba)
1563 {
1564         ColorMap::iterator i = color_map.find (rgba);
1565
1566         if (i != color_map.end()) {
1567                 return i->second;
1568         }
1569
1570         double dr, dg, db, da;
1571         int r, g, b;
1572         ArdourCanvas::color_to_rgba (rgba, dr, dg, db, da);
1573         int w = 126; /* not sure where/when we should get this value */
1574
1575
1576         r = (int) floor (255.0 * dr);
1577         g = (int) floor (255.0 * dg);
1578         b = (int) floor (255.0 * db);
1579
1580         /* get a free index */
1581
1582         uint8_t index;
1583
1584         if (color_map_free_list.empty()) {
1585                 /* random replacement of any entry above zero and below 122 (where the
1586                  * Ableton standard colors live)
1587                  */
1588                 index = 1 + (random() % 121);
1589         } else {
1590                 index = color_map_free_list.top();
1591                 color_map_free_list.pop();
1592         }
1593
1594         MidiByteArray palette_msg (17,
1595                                    0xf0,
1596                                    0x00 , 0x21, 0x1d, 0x01, 0x01, 0x03, /* reset palette header */
1597                                    0x00, /* index = 7 */
1598                                    0x00, 0x00, /* r = 8 & 9 */
1599                                    0x00, 0x00, /* g = 10 & 11 */
1600                                    0x00, 0x00, /* b = 12 & 13 */
1601                                    0x00, 0x00, /* w (a?) = 14 & 15*/
1602                                    0xf7);
1603         palette_msg[7] = index;
1604         palette_msg[8] = r & 0x7f;
1605         palette_msg[9] = (r & 0x80) >> 7;
1606         palette_msg[10] = g & 0x7f;
1607         palette_msg[11] = (g & 0x80) >> 7;
1608         palette_msg[12] = b & 0x7f;
1609         palette_msg[13] = (b & 0x80) >> 7;
1610         palette_msg[14] = w & 0x7f;
1611         palette_msg[15] = w & 0x80;
1612
1613         write (palette_msg);
1614
1615         MidiByteArray update_pallette_msg (8, 0xf0, 0x00, 0x21, 0x1d, 0x01, 0x01, 0x05, 0xF7);
1616         write (update_pallette_msg);
1617
1618         color_map[rgba] = index;
1619
1620         return index;
1621 }
1622
1623 void
1624 Push2::build_color_map ()
1625 {
1626         /* These are "standard" colors that Ableton docs suggest will always be
1627            there. Put them in our color map so that when we look up these
1628            colors, we will use the Ableton indices for them.
1629         */
1630
1631         color_map.insert (make_pair (RGB_TO_UINT (0,0,0), 0));
1632         color_map.insert (make_pair (RGB_TO_UINT (204,204,204), 122));
1633         color_map.insert (make_pair (RGB_TO_UINT (64,64,64), 123));
1634         color_map.insert (make_pair (RGB_TO_UINT (20,20,20), 124));
1635         color_map.insert (make_pair (RGB_TO_UINT (0,0,255), 125));
1636         color_map.insert (make_pair (RGB_TO_UINT (0,255,0), 126));
1637         color_map.insert (make_pair (RGB_TO_UINT (255,0,0), 127));
1638
1639         for (uint8_t n = 1; n < 122; ++n) {
1640                 color_map_free_list.push (n);
1641         }
1642 }
1643
1644 void
1645 Push2::fill_color_table ()
1646 {
1647         colors.insert (make_pair (DarkBackground, ArdourCanvas::rgba_to_color (0, 0, 0, 1)));
1648         colors.insert (make_pair (LightBackground, ArdourCanvas::rgba_to_color (0.98, 0.98, 0.98, 1)));
1649
1650         colors.insert (make_pair (ParameterName, ArdourCanvas::rgba_to_color (0.98, 0.98, 0.98, 1)));
1651
1652         colors.insert (make_pair (KnobArcBackground, ArdourCanvas::rgba_to_color (0.3, 0.3, 0.3, 1.0)));
1653         colors.insert (make_pair (KnobArcStart, ArdourCanvas::rgba_to_color (1.0, 0.0, 0.0, 1.0)));
1654         colors.insert (make_pair (KnobArcEnd, ArdourCanvas::rgba_to_color (0.0, 1.0, 0.0, 1.0)));
1655
1656         colors.insert (make_pair (KnobLineShadow, ArdourCanvas::rgba_to_color  (0, 0, 0, 0.3)));
1657         colors.insert (make_pair (KnobLine, ArdourCanvas::rgba_to_color (1, 1, 1, 1)));
1658
1659         colors.insert (make_pair (KnobForeground, ArdourCanvas::rgba_to_color (0.2, 0.2, 0.2, 1)));
1660         colors.insert (make_pair (KnobBackground, ArdourCanvas::rgba_to_color (0.2, 0.2, 0.2, 1)));
1661         colors.insert (make_pair (KnobShadow, ArdourCanvas::rgba_to_color (0, 0, 0, 0.1)));
1662         colors.insert (make_pair (KnobBorder, ArdourCanvas::rgba_to_color (0, 0, 0, 1)));
1663
1664 }
1665
1666 ArdourCanvas::Color
1667 Push2::get_color (ColorName name)
1668 {
1669         Colors::iterator c = colors.find (name);
1670         if (c != colors.end()) {
1671                 return c->second;
1672         }
1673
1674         return random();
1675 }
1676
1677 void
1678 Push2::set_current_layout (Push2Layout* layout)
1679 {
1680         if (layout && layout == _current_layout) {
1681                 _current_layout->show ();
1682         } else {
1683
1684                 if (_current_layout) {
1685                         _current_layout->hide ();
1686                         _canvas->root()->remove (_current_layout);
1687                         _previous_layout = _current_layout;
1688                 }
1689
1690                 _current_layout = layout;
1691
1692                 if (_current_layout) {
1693                         _canvas->root()->add (_current_layout);
1694                         _current_layout->show ();
1695                 }
1696
1697
1698                 _canvas->request_redraw ();
1699         }
1700 }
1701
1702 void
1703 Push2::use_previous_layout ()
1704 {
1705         if (_previous_layout) {
1706                 set_current_layout (_previous_layout);
1707         }
1708 }
1709
1710 void
1711 Push2::request_pressure_mode ()
1712 {
1713         MidiByteArray msg (8, 0xF0, 0x00, 0x21, 0x1D, 0x01, 0x01, 0x1F, 0xF7);
1714         write (msg);
1715 }
1716
1717 void
1718 Push2::set_pressure_mode (PressureMode pm)
1719 {
1720         MidiByteArray msg (9, 0xF0, 0x00, 0x21, 0x1D, 0x01, 0x01, 0x1E, 0x0, 0xF7);
1721
1722         switch (pm) {
1723         case AfterTouch:
1724                 /* nothing to do, message is correct */
1725                 break;
1726         case PolyPressure:
1727                 msg[7] = 0x1;
1728                 break;
1729         default:
1730                 return;
1731         }
1732
1733         write (msg);
1734         cerr << "Sent PM message " << msg << endl;
1735 }