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