push2: splash screen
[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 <cairomm/context.h>
20 #include <cairomm/surface.h>
21 #include <pangomm/layout.h>
22
23 #include "pbd/compose.h"
24 #include "pbd/convert.h"
25 #include "pbd/debug.h"
26 #include "pbd/failed_constructor.h"
27 #include "pbd/file_utils.h"
28 #include "pbd/search_path.h"
29
30 #include "midi++/parser.h"
31 #include "timecode/time.h"
32 #include "timecode/bbt_time.h"
33
34 #include "ardour/async_midi_port.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/debug.h"
37 #include "ardour/filesystem_paths.h"
38 #include "ardour/midiport_manager.h"
39 #include "ardour/session.h"
40 #include "ardour/tempo.h"
41
42 #include "push2.h"
43
44 using namespace ARDOUR;
45 using namespace std;
46 using namespace PBD;
47 using namespace Glib;
48 using namespace ArdourSurface;
49
50 #include "i18n.h"
51
52 #include "pbd/abstract_ui.cc" // instantiate template
53
54 const int Push2::cols = 960;
55 const int Push2::rows = 160;
56 const int Push2::pixels_per_row = 1024;
57
58 #define ABLETON 0x2982
59 #define PUSH2   0x1967
60
61 Push2::Push2 (ARDOUR::Session& s)
62         : ControlProtocol (s, string (X_("Ableton Push 2")))
63         , AbstractUI<Push2Request> (name())
64         , handle (0)
65         , device_buffer (0)
66         , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows))
67         , modifier_state (None)
68         , splash_start (0)
69         , bank_start (0)
70 {
71         context = Cairo::Context::create (frame_buffer);
72         tc_clock_layout = Pango::Layout::create (context);
73         bbt_clock_layout = Pango::Layout::create (context);
74
75         Pango::FontDescription fd ("Sans Bold 24");
76         tc_clock_layout->set_font_description (fd);
77         bbt_clock_layout->set_font_description (fd);
78
79         Pango::FontDescription fd2 ("Sans 10");
80         for (int n = 0; n < 8; ++n) {
81                 upper_layout[n] = Pango::Layout::create (context);
82                 upper_layout[n]->set_font_description (fd2);
83                 upper_layout[n]->set_text ("solo");
84                 lower_layout[n] = Pango::Layout::create (context);
85                 lower_layout[n]->set_font_description (fd2);
86                 lower_layout[n]->set_text ("mute");
87         }
88
89         Pango::FontDescription fd3 ("Sans Bold 10");
90         for (int n = 0; n < 8; ++n) {
91                 mid_layout[n] = Pango::Layout::create (context);
92                 mid_layout[n]->set_font_description (fd3);
93         }
94
95         build_maps ();
96
97         if (open ()) {
98                 throw failed_constructor ();
99         }
100
101 }
102
103 Push2::~Push2 ()
104 {
105         stop ();
106 }
107
108 int
109 Push2::open ()
110 {
111         int err;
112
113         if (handle) {
114                 /* already open */
115                 return 0;
116         }
117
118         if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
119                 return -1;
120         }
121
122         if ((err = libusb_claim_interface (handle, 0x00))) {
123                 return -1;
124         }
125
126         device_frame_buffer = new uint16_t[rows*pixels_per_row];
127
128         memset (device_frame_buffer, 0, sizeof (uint16_t) * rows * pixels_per_row);
129
130         frame_header[0] = 0xef;
131         frame_header[1] = 0xcd;
132         frame_header[2] = 0xab;
133         frame_header[3] = 0x89;
134         memset (&frame_header[4], 0, 12);
135
136         /* setup ports */
137
138         _async_in  = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("push2 in"), true);
139         _async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("push2 out"), true);
140
141         if (_async_in == 0 || _async_out == 0) {
142                 return -1;
143         }
144
145         _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in).get();
146         _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out).get();
147
148         connect_to_parser ();
149
150         return 0;
151 }
152
153 int
154 Push2::close ()
155 {
156         init_buttons (false);
157
158         /* wait for button data to be flushed */
159         AsyncMIDIPort* asp;
160         asp = dynamic_cast<AsyncMIDIPort*> (_output_port);
161         asp->drain (10000, 500000);
162
163         AudioEngine::instance()->unregister_port (_async_in);
164         AudioEngine::instance()->unregister_port (_async_out);
165
166         _async_in.reset ((ARDOUR::Port*) 0);
167         _async_out.reset ((ARDOUR::Port*) 0);
168         _input_port = 0;
169         _output_port = 0;
170
171         vblank_connection.disconnect ();
172         periodic_connection.disconnect ();
173         session_connections.drop_connections ();
174         stripable_connections.drop_connections ();
175
176         if (handle) {
177                 libusb_release_interface (handle, 0x00);
178                 libusb_close (handle);
179                 handle = 0;
180         }
181
182         for (int n = 0; n < 8; ++n) {
183                 stripable[n].reset ();
184         }
185
186         delete [] device_frame_buffer;
187         device_frame_buffer = 0;
188
189         return 0;
190 }
191
192 void
193 Push2::init_buttons (bool startup)
194 {
195         /* This is a list of buttons that we want lit because they do something
196            in ardour related (loosely, sometimes) to their illuminated label.
197         */
198
199         ButtonID buttons[] = { Mute, Solo, Master, Up, Right, Left, Down, Note, Session, Mix, AddTrack, Delete, Undo,
200                                Metronome, Shift, Select, Play, RecordEnable, Automate, Repeat, Note, Session, DoubleLoop,
201                                Quantize, Duplicate, Browse, PageRight, PageLeft,
202         };
203
204         for (size_t n = 0; n < sizeof (buttons) / sizeof (buttons[0]); ++n) {
205                 Button* b = id_button_map[buttons[n]];
206
207                 if (startup) {
208                         b->set_color (LED::White);
209                 } else {
210                         b->set_color (LED::Black);
211                 }
212                 b->set_state (LED::OneShot24th);
213                 write (b->state_msg());
214         }
215
216         /* Strip buttons should all be off (black) by default. They will change
217          * color to reflect various conditions
218          */
219
220         ButtonID strip_buttons[] = { Upper1, Upper2, Upper3, Upper4, Upper5, Upper6, Upper7, Upper8,
221                                      Lower1, Lower2, Lower3, Lower4, Lower5, Lower6, Lower7, Lower8, };
222
223         for (size_t n = 0; n < sizeof (strip_buttons) / sizeof (strip_buttons[0]); ++n) {
224                 Button* b = id_button_map[strip_buttons[n]];
225
226                 b->set_color (LED::Black);
227                 b->set_state (LED::OneShot24th);
228                 write (b->state_msg());
229         }
230
231         if (startup) {
232
233                 /* all other buttons are off (black) */
234
235                 ButtonID off_buttons[] = { TapTempo, Setup, User, Stop, Convert, New, FixedLength,
236                                            Fwd32ndT, Fwd32nd, Fwd16thT, Fwd16th, Fwd8thT, Fwd8th, Fwd4trT, Fwd4tr,
237                                            Accent, Scale, Layout, Note, Session,  OctaveUp, OctaveDown, };
238
239                 for (size_t n = 0; n < sizeof (off_buttons) / sizeof (off_buttons[0]); ++n) {
240                         Button* b = id_button_map[off_buttons[n]];
241
242                         b->set_color (LED::Black);
243                         b->set_state (LED::OneShot24th);
244                         write (b->state_msg());
245                 }
246         }
247
248 }
249
250 bool
251 Push2::probe ()
252 {
253         libusb_device_handle *h;
254         libusb_init (NULL);
255
256         if ((h = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
257                 DEBUG_TRACE (DEBUG::Push2, "no Push2 device found\n");
258                 return false;
259         }
260
261         libusb_close (h);
262         DEBUG_TRACE (DEBUG::Push2, "Push2 device located\n");
263         return true;
264 }
265
266 void*
267 Push2::request_factory (uint32_t num_requests)
268 {
269         /* AbstractUI<T>::request_buffer_factory() is a template method only
270            instantiated in this source module. To provide something visible for
271            use in the interface/descriptor, we have this static method that is
272            template-free.
273         */
274         return request_buffer_factory (num_requests);
275 }
276
277 void
278 Push2::do_request (Push2Request * req)
279 {
280         DEBUG_TRACE (DEBUG::Push2, string_compose ("doing request type %1\n", req->type));
281         if (req->type == CallSlot) {
282
283                 call_slot (MISSING_INVALIDATOR, req->the_slot);
284
285         } else if (req->type == Quit) {
286
287                 stop ();
288         }
289 }
290
291 int
292 Push2::stop ()
293 {
294         BaseUI::quit ();
295         close ();
296         return 0;
297 }
298
299 /** render host-side frame buffer (a Cairo ImageSurface) to the current
300  * device-side frame buffer. The device frame buffer will be pushed to the
301  * device on the next call to vblank()
302  */
303
304 int
305 Push2::blit_to_device_frame_buffer ()
306 {
307         /* ensure that all drawing has been done before we fetch pixel data */
308
309         frame_buffer->flush ();
310
311         const int stride = 3840; /* bytes per row for Cairo::FORMAT_ARGB32 */
312         const uint8_t* data = frame_buffer->get_data ();
313
314         /* fill frame buffer (320kB) */
315
316         uint16_t* fb = (uint16_t*) device_frame_buffer;
317
318         for (int row = 0; row < rows; ++row) {
319
320                 const uint8_t* dp = data + row * stride;
321
322                 for (int col = 0; col < cols; ++col) {
323
324                         /* fetch r, g, b (range 0..255). Ignore alpha */
325
326                         const int r = (*((const uint32_t*)dp) >> 16) & 0xff;
327                         const int g = (*((const uint32_t*)dp) >> 8) & 0xff;
328                         const int b = *((const uint32_t*)dp) & 0xff;
329
330                         /* convert to 5 bits, 6 bits, 5 bits, respectively */
331                         /* generate 16 bit BGB565 value */
332
333                         *fb++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
334
335                         /* the push2 docs state that we should xor the pixel
336                          * data. Doing so doesn't work correctly, and not doing
337                          * so seems to work fine (colors roughly match intended
338                          * values).
339                          */
340
341                         dp += 4;
342                 }
343
344                 /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
345                    byte USB buffers
346                 */
347
348                 fb += 64; /* 128 bytes = 64 int16_t */
349         }
350
351         return 0;
352 }
353
354 bool
355 Push2::redraw ()
356 {
357         string tc_clock_text;
358         string bbt_clock_text;
359
360         if (splash_start) {
361                 if (get_microseconds() - splash_start > 4000000) {
362                         splash_start = 0;
363                 } else {
364                         return false;
365                 }
366         }
367
368         if (session) {
369                 framepos_t audible = session->audible_frame();
370                 Timecode::Time TC;
371                 bool negative = false;
372
373                 if (audible < 0) {
374                         audible = -audible;
375                         negative = true;
376                 }
377
378                 session->timecode_time (audible, TC);
379
380                 TC.negative = TC.negative || negative;
381
382                 tc_clock_text = Timecode::timecode_format_time(TC);
383
384                 Timecode::BBT_Time bbt = session->tempo_map().bbt_at_frame (audible);
385                 char buf[16];
386
387 #define BBT_BAR_CHAR "|"
388
389                 if (negative) {
390                         snprintf (buf, sizeof (buf), "-%03" PRIu32 BBT_BAR_CHAR "%02" PRIu32 BBT_BAR_CHAR "%04" PRIu32,
391                                   bbt.bars, bbt.beats, bbt.ticks);
392                 } else {
393                         snprintf (buf, sizeof (buf), " %03" PRIu32 BBT_BAR_CHAR "%02" PRIu32 BBT_BAR_CHAR "%04" PRIu32,
394                                   bbt.bars, bbt.beats, bbt.ticks);
395                 }
396
397                 bbt_clock_text = buf;
398         }
399
400         bool dirty = false;
401
402         if (tc_clock_text != tc_clock_layout->get_text()) {
403                 dirty = true;
404                 tc_clock_layout->set_text (tc_clock_text);
405         }
406
407         if (bbt_clock_text != tc_clock_layout->get_text()) {
408                 dirty = true;
409                 bbt_clock_layout->set_text (bbt_clock_text);
410         }
411
412         string mid_text;
413
414         for (int n = 0; n < 8; ++n) {
415                 if (stripable[n]) {
416                         mid_text = short_version (stripable[n]->name(), 10);
417                         if (mid_text != mid_layout[n]->get_text()) {
418                                 mid_layout[n]->set_text (mid_text);
419                                 dirty = true;
420                         }
421                 }
422         }
423
424         if (!dirty) {
425                 return false;
426         }
427
428         context->set_source_rgb (0.764, 0.882, 0.882);
429         context->rectangle (0, 0, 960, 160);
430         context->fill ();
431         context->set_source_rgb (0.23, 0.0, 0.349);
432         context->move_to (650, 25);
433         tc_clock_layout->update_from_cairo_context (context);
434         tc_clock_layout->show_in_cairo_context (context);
435         context->move_to (650, 60);
436         bbt_clock_layout->update_from_cairo_context (context);
437         bbt_clock_layout->show_in_cairo_context (context);
438
439         for (int n = 0; n < 8; ++n) {
440                 context->move_to (10 + (n*120), 2);
441                 upper_layout[n]->update_from_cairo_context (context);
442                 upper_layout[n]->show_in_cairo_context (context);
443         }
444
445         for (int n = 0; n < 8; ++n) {
446                 context->move_to (10 + (n*120), 140);
447                 lower_layout[n]->update_from_cairo_context (context);
448                 lower_layout[n]->show_in_cairo_context (context);
449         }
450
451         for (int n = 0; n < 8; ++n) {
452                 if (stripable[n] && stripable[n]->presentation_info().selected()) {
453                         context->rectangle (10 + (n*120) - 5, 115, 120, 22);
454                         context->set_source_rgb (1.0, 0.737, 0.172);
455                         context->fill();
456                 }
457                 context->set_source_rgb (0.0, 0.0, 0.0);
458                 context->move_to (10 + (n*120), 120);
459                 mid_layout[n]->update_from_cairo_context (context);
460                 mid_layout[n]->show_in_cairo_context (context);
461         }
462
463         /* render clock */
464         /* render foo */
465         /* render bar */
466
467         return true;
468 }
469
470 bool
471 Push2::vblank ()
472 {
473         int transferred = 0;
474         const int timeout_msecs = 1000;
475         int err;
476
477         if ((err = libusb_bulk_transfer (handle, 0x01, frame_header, sizeof (frame_header), &transferred, timeout_msecs))) {
478                 return false;
479         }
480
481         if (redraw()) {
482                 /* things changed */
483                 blit_to_device_frame_buffer ();
484         }
485
486         if ((err = libusb_bulk_transfer (handle, 0x01, (uint8_t*) device_frame_buffer , 2 * rows * pixels_per_row, &transferred, timeout_msecs))) {
487                 return false;
488         }
489
490         return true;
491 }
492
493 int
494 Push2::set_active (bool yn)
495 {
496         DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active init with yn: '%1'\n", yn));
497
498         if (yn == active()) {
499                 return 0;
500         }
501
502         if (yn) {
503
504                 /* start event loop */
505
506                 BaseUI::run ();
507
508                 if (open ()) {
509                         DEBUG_TRACE (DEBUG::Push2, "device open failed\n");
510                         close ();
511                         return -1;
512                 }
513
514                 /* Connect input port to event loop */
515
516                 AsyncMIDIPort* asp;
517
518                 asp = dynamic_cast<AsyncMIDIPort*> (_input_port);
519                 asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port));
520                 asp->xthread().attach (main_loop()->get_context());
521
522                 connect_session_signals ();
523
524                 /* set up periodic task used to push a frame buffer to the
525                  * device (25fps). The device can handle 60fps, but we don't
526                  * need that frame rate.
527                  */
528
529                 Glib::RefPtr<Glib::TimeoutSource> vblank_timeout = Glib::TimeoutSource::create (40); // milliseconds
530                 vblank_connection = vblank_timeout->connect (sigc::mem_fun (*this, &Push2::vblank));
531                 vblank_timeout->attach (main_loop()->get_context());
532
533
534                 Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (1000); // milliseconds
535                 periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &Push2::periodic));
536                 periodic_timeout->attach (main_loop()->get_context());
537
538                 init_buttons (true);
539                 init_touch_strip ();
540                 switch_bank (0);
541                 splash ();
542
543         } else {
544
545                 stop ();
546
547         }
548
549         ControlProtocol::set_active (yn);
550
551         DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active done with yn: '%1'\n", yn));
552
553         return 0;
554 }
555
556 void
557 Push2::init_touch_strip ()
558 {
559         MidiByteArray msg (9, 0xf0, 0x00, 0x21, 0x1d, 0x01, 0x01, 0x17, 0x00, 0xf7);
560         /* flags are the final byte (ignore end-of-sysex */
561
562         /* show bar, not point
563            autoreturn to center
564            bar starts at center
565         */
566         msg[7] = (1<<4) | (1<<5) | (1<<6);
567         write (msg);
568 }
569
570 void
571 Push2::write (const MidiByteArray& data)
572 {
573         /* immediate delivery */
574         _output_port->write (&data[0], data.size(), 0);
575 }
576
577 bool
578 Push2::midi_input_handler (IOCondition ioc, MIDI::Port* port)
579 {
580         if (ioc & ~IO_IN) {
581                 DEBUG_TRACE (DEBUG::Push2, "MIDI port closed\n");
582                 return false;
583         }
584
585         if (ioc & IO_IN) {
586
587                 // DEBUG_TRACE (DEBUG::Push2, string_compose ("something happend on  %1\n", port->name()));
588
589                 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
590                 if (asp) {
591                         asp->clear ();
592                 }
593
594                 //DEBUG_TRACE (DEBUG::Push2, string_compose ("data available on %1\n", port->name()));
595                 framepos_t now = AudioEngine::instance()->sample_time();
596                 port->parse (now);
597         }
598
599         return true;
600 }
601
602 bool
603 Push2::periodic ()
604 {
605         return true;
606 }
607
608 void
609 Push2::connect_to_parser ()
610 {
611         DEBUG_TRACE (DEBUG::Push2, string_compose ("Connecting to signals on port %2\n", _input_port->name()));
612
613         MIDI::Parser* p = _input_port->parser();
614
615         /* Incoming sysex */
616         p->sysex.connect_same_thread (*this, boost::bind (&Push2::handle_midi_sysex, this, _1, _2, _3));
617         /* V-Pot messages are Controller */
618         p->controller.connect_same_thread (*this, boost::bind (&Push2::handle_midi_controller_message, this, _1, _2));
619         /* Button messages are NoteOn */
620         p->note_on.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
621         /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
622         p->note_off.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
623         /* Fader messages are Pitchbend */
624         p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&Push2::handle_midi_pitchbend_message, this, _1, _2));
625 }
626
627 void
628 Push2::handle_midi_sysex (MIDI::Parser&, MIDI::byte* raw_bytes, size_t sz)
629 {
630         DEBUG_TRACE (DEBUG::Push2, string_compose ("Sysex, %1 bytes\n", sz));
631 }
632
633 void
634 Push2::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
635 {
636         DEBUG_TRACE (DEBUG::Push2, string_compose ("CC %1 (value %2)\n", (int) ev->controller_number, (int) ev->value));
637
638         CCButtonMap::iterator b = cc_button_map.find (ev->controller_number);
639
640         if (ev->value) {
641                 /* any press cancels any pending long press timeouts */
642                 for (set<ButtonID>::iterator x = buttons_down.begin(); x != buttons_down.end(); ++x) {
643                         Button* bb = id_button_map[*x];
644                         bb->timeout_connection.disconnect ();
645                 }
646         }
647
648         if (b != cc_button_map.end()) {
649
650                 Button* button = b->second;
651
652                 if (ev->value) {
653                         buttons_down.insert (button->id);
654                         start_press_timeout (*button, button->id);
655                 } else {
656                         buttons_down.erase (button->id);
657                         button->timeout_connection.disconnect ();
658                 }
659
660
661                 set<ButtonID>::iterator c = consumed.find (button->id);
662
663                 if (c == consumed.end()) {
664                         if (ev->value == 0) {
665                                 (this->*button->release_method)();
666                         } else {
667                                 (this->*button->press_method)();
668                         }
669                 } else {
670                         DEBUG_TRACE (DEBUG::Push2, "button was consumed, ignored\n");
671                         consumed.erase (c);
672                 }
673
674         } else {
675
676                 /* encoder/vpot */
677
678                 int delta = ev->value;
679
680                 if (delta > 63) {
681                         delta = -(128 - delta);
682                 }
683
684                 switch (ev->controller_number) {
685                 case 71:
686                         strip_vpot (0, delta);
687                         break;
688                 case 72:
689                         strip_vpot (1, delta);
690                         break;
691                 case 73:
692                         strip_vpot (2, delta);
693                         break;
694                 case 74:
695                         strip_vpot (3, delta);
696                         break;
697                 case 75:
698                         strip_vpot (4, delta);
699                         break;
700                 case 76:
701                         strip_vpot (5, delta);
702                         break;
703                 case 77:
704                         strip_vpot (6, delta);
705                         break;
706                 case 78:
707                         strip_vpot (7, delta);
708                         break;
709
710                         /* left side pair */
711                 case 14:
712                         strip_vpot (8, delta);
713                         break;
714                 case 15:
715                         other_vpot (1, delta);
716                         break;
717
718                         /* right side */
719                 case 79:
720                         other_vpot (2, delta);
721                         break;
722                 }
723         }
724 }
725
726 void
727 Push2::handle_midi_note_on_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
728 {
729         DEBUG_TRACE (DEBUG::Push2, string_compose ("Note On %1 (velocity %2)\n", (int) ev->note_number, (int) ev->velocity));
730
731         switch (ev->note_number) {
732         case 0:
733                 strip_vpot_touch (0, ev->velocity > 64);
734                 break;
735         case 1:
736                 strip_vpot_touch (1, ev->velocity > 64);
737                 break;
738         case 2:
739                 strip_vpot_touch (2, ev->velocity > 64);
740                 break;
741         case 3:
742                 strip_vpot_touch (3, ev->velocity > 64);
743                 break;
744         case 4:
745                 strip_vpot_touch (4, ev->velocity > 64);
746                 break;
747         case 5:
748                 strip_vpot_touch (5, ev->velocity > 64);
749                 break;
750         case 6:
751                 strip_vpot_touch (6, ev->velocity > 64);
752                 break;
753         case 7:
754                 strip_vpot_touch (7, ev->velocity > 64);
755                 break;
756
757                 /* left side */
758         case 10:
759                 other_vpot_touch (0, ev->velocity > 64);
760                 break;
761         case 9:
762                 other_vpot_touch (1, ev->velocity > 64);
763                 break;
764
765                 /* right side */
766         case 8:
767                 other_vpot_touch (3, ev->velocity > 64);
768                 break;
769
770                 /* touch strip */
771         case 12:
772                 if (ev->velocity < 64) {
773                         transport_stop ();
774                 }
775                 break;
776         }
777 }
778
779 void
780 Push2::handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
781 {
782         DEBUG_TRACE (DEBUG::Push2, string_compose ("Note Off %1 (velocity %2)\n", (int) ev->note_number, (int) ev->velocity));
783 }
784
785 void
786 Push2::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb)
787 {
788         if (!session) {
789                 return;
790         }
791
792         float speed;
793
794         /* range of +1 .. -1 */
795         speed = ((int32_t) pb - 8192) / 8192.0;
796         /* convert to range of +3 .. -3 */
797         session->request_transport_speed (speed * 3.0);
798 }
799
800 void
801 Push2::thread_init ()
802 {
803         struct sched_param rtparam;
804
805         pthread_set_name (event_loop_name().c_str());
806
807         PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
808         ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
809
810         memset (&rtparam, 0, sizeof (rtparam));
811         rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
812
813         if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
814                 // do we care? not particularly.
815         }
816 }
817
818 void
819 Push2::connect_session_signals()
820 {
821         // receive routes added
822         //session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_routes_added, this, _1), this);
823         // receive VCAs added
824         //session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_vca_added, this, _1), this);
825
826         // receive record state toggled
827         session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_record_state_changed, this), this);
828         // receive transport state changed
829         session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_transport_state_changed, this), this);
830         session->TransportLooped.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_loop_state_changed, this), this);
831         // receive punch-in and punch-out
832         Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
833         session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
834         // receive rude solo changed
835         session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_solo_active_changed, this, _1), this);
836 }
837
838 void
839 Push2::notify_record_state_changed ()
840 {
841         IDButtonMap::iterator b = id_button_map.find (RecordEnable);
842
843         if (b == id_button_map.end()) {
844                 return;
845         }
846
847         switch (session->record_status ()) {
848         case Session::Disabled:
849                 b->second->set_color (LED::White);
850                 b->second->set_state (LED::NoTransition);
851                 break;
852         case Session::Enabled:
853                 b->second->set_color (LED::Red);
854                 b->second->set_state (LED::Blinking4th);
855                 break;
856         case Session::Recording:
857                 b->second->set_color (LED::Red);
858                 b->second->set_state (LED::OneShot24th);
859                 break;
860         }
861
862         write (b->second->state_msg());
863 }
864
865 void
866 Push2::notify_transport_state_changed ()
867 {
868         Button* b = id_button_map[Play];
869
870         if (session->transport_rolling()) {
871                 b->set_state (LED::OneShot24th);
872                 b->set_color (LED::Green);
873         } else {
874
875                 /* disable any blink on FixedLength from pending edit range op */
876                 Button* fl = id_button_map[FixedLength];
877
878                 fl->set_color (LED::Black);
879                 fl->set_state (LED::NoTransition);
880                 write (fl->state_msg());
881
882                 b->set_color (LED::White);
883                 b->set_state (LED::NoTransition);
884         }
885
886         write (b->state_msg());
887 }
888
889 void
890 Push2::notify_loop_state_changed ()
891 {
892 }
893
894 void
895 Push2::notify_parameter_changed (std::string param)
896 {
897         IDButtonMap::iterator b;
898
899         if (param == "clicking") {
900                 if ((b = id_button_map.find (Metronome)) == id_button_map.end()) {
901                         return;
902                 }
903                 if (Config->get_clicking()) {
904                         b->second->set_state (LED::Blinking4th);
905                         b->second->set_color (LED::White);
906                 } else {
907                         b->second->set_color (LED::White);
908                         b->second->set_state (LED::NoTransition);
909                 }
910                 write (b->second->state_msg ());
911         }
912 }
913
914 void
915 Push2::notify_solo_active_changed (bool yn)
916 {
917         IDButtonMap::iterator b = id_button_map.find (Solo);
918
919         if (b == id_button_map.end()) {
920                 return;
921         }
922
923         if (yn) {
924                 b->second->set_state (LED::Blinking4th);
925                 b->second->set_color (LED::Red);
926         } else {
927                 b->second->set_state (LED::NoTransition);
928                 b->second->set_color (LED::White);
929         }
930
931         write (b->second->state_msg());
932 }
933
934 XMLNode&
935 Push2::get_state()
936 {
937         XMLNode& node (ControlProtocol::get_state());
938         XMLNode* child;
939
940         child = new XMLNode (X_("Input"));
941         child->add_child_nocopy (_async_in->get_state());
942         node.add_child_nocopy (*child);
943         child = new XMLNode (X_("Output"));
944         child->add_child_nocopy (_async_out->get_state());
945         node.add_child_nocopy (*child);
946
947         return node;
948 }
949
950 int
951 Push2::set_state (const XMLNode & node, int version)
952 {
953         DEBUG_TRACE (DEBUG::Push2, string_compose ("Push2::set_state: active %1\n", active()));
954
955         int retval = 0;
956
957         if (ControlProtocol::set_state (node, version)) {
958                 return -1;
959         }
960
961         XMLNode* child;
962
963         if ((child = node.child (X_("Input"))) != 0) {
964                 XMLNode* portnode = child->child (Port::state_node_name.c_str());
965                 if (portnode) {
966                         _async_in->set_state (*portnode, version);
967                 }
968         }
969
970         if ((child = node.child (X_("Output"))) != 0) {
971                 XMLNode* portnode = child->child (Port::state_node_name.c_str());
972                 if (portnode) {
973                         _async_out->set_state (*portnode, version);
974                 }
975         }
976
977         return retval;
978 }
979
980 void
981 Push2::switch_bank (uint32_t base)
982 {
983         if (!session) {
984                 return;
985         }
986
987         stripable_connections.drop_connections ();
988
989         /* try to get the first stripable for the requested bank */
990
991         stripable[0] = session->get_remote_nth_stripable (base, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
992
993         if (!stripable[0]) {
994                 return;
995         }
996
997         /* at least one stripable in this bank */
998         bank_start = base;
999
1000         stripable[1] = session->get_remote_nth_stripable (base+1, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
1001         stripable[2] = session->get_remote_nth_stripable (base+2, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
1002         stripable[3] = session->get_remote_nth_stripable (base+3, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
1003         stripable[4] = session->get_remote_nth_stripable (base+4, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
1004         stripable[5] = session->get_remote_nth_stripable (base+5, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
1005         stripable[6] = session->get_remote_nth_stripable (base+6, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
1006         stripable[7] = session->get_remote_nth_stripable (base+7, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
1007
1008
1009         for (int n = 0; n < 8; ++n) {
1010                 if (!stripable[n]) {
1011                         continue;
1012                 }
1013
1014                 /* stripable goes away? refill the bank, starting at the same point */
1015
1016                 stripable[n]->DropReferences.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Push2::switch_bank, this, bank_start), this);
1017                 boost::shared_ptr<AutomationControl> sc = stripable[n]->solo_control();
1018                 if (sc) {
1019                         sc->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Push2::solo_change, this, n), this);
1020                 }
1021
1022                 boost::shared_ptr<AutomationControl> mc = stripable[n]->mute_control();
1023                 if (mc) {
1024                         mc->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Push2::mute_change, this, n), this);
1025                 }
1026
1027                 stripable[n]->presentation_info().PropertyChanged.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Push2::stripable_property_change, this, _1, n), this);
1028
1029                 solo_change (n);
1030                 mute_change (n);
1031
1032         }
1033
1034         /* master cannot be removed, so no need to connect to going-away signal */
1035         master = session->master_out ();
1036 }
1037
1038 void
1039 Push2::stripable_property_change (PropertyChange const& what_changed, int which)
1040 {
1041         if (what_changed.contains (Properties::selected)) {
1042                 /* cancel string, which will cause a redraw on the next update
1043                  * cycle. The redraw will reflect selected status
1044                  */
1045                 mid_layout[which]->set_text (string());
1046         }
1047 }
1048
1049 void
1050 Push2::solo_change (int n)
1051 {
1052         ButtonID bid;
1053
1054         switch (n) {
1055         case 0:
1056                 bid = Upper1;
1057                 break;
1058         case 1:
1059                 bid = Upper2;
1060                 break;
1061         case 2:
1062                 bid = Upper3;
1063                 break;
1064         case 3:
1065                 bid = Upper4;
1066                 break;
1067         case 4:
1068                 bid = Upper5;
1069                 break;
1070         case 5:
1071                 bid = Upper6;
1072                 break;
1073         case 6:
1074                 bid = Upper7;
1075                 break;
1076         case 7:
1077                 bid = Upper8;
1078                 break;
1079         default:
1080                 return;
1081         }
1082
1083         boost::shared_ptr<SoloControl> ac = stripable[n]->solo_control ();
1084         if (!ac) {
1085                 return;
1086         }
1087
1088         Button* b = id_button_map[bid];
1089
1090         if (ac->soloed()) {
1091                 b->set_color (LED::Green);
1092         } else {
1093                 b->set_color (LED::Black);
1094         }
1095
1096         if (ac->soloed_by_others_upstream() || ac->soloed_by_others_downstream()) {
1097                 b->set_state (LED::Blinking4th);
1098         } else {
1099                 b->set_state (LED::OneShot24th);
1100         }
1101
1102         write (b->state_msg());
1103 }
1104
1105 void
1106 Push2::mute_change (int n)
1107 {
1108         ButtonID bid;
1109
1110         if (!stripable[n]) {
1111                 return;
1112         }
1113
1114         cerr << "Mute changed on " << n << ' ' << stripable[n]->name() << endl;
1115
1116         switch (n) {
1117         case 0:
1118                 bid = Lower1;
1119                 break;
1120         case 1:
1121                 bid = Lower2;
1122                 break;
1123         case 2:
1124                 bid = Lower3;
1125                 break;
1126         case 3:
1127                 bid = Lower4;
1128                 break;
1129         case 4:
1130                 bid = Lower5;
1131                 break;
1132         case 5:
1133                 bid = Lower6;
1134                 break;
1135         case 6:
1136                 bid = Lower7;
1137                 break;
1138         case 7:
1139                 bid = Lower8;
1140                 break;
1141         default:
1142                 return;
1143         }
1144
1145         boost::shared_ptr<MuteControl> mc = stripable[n]->mute_control ();
1146
1147         if (!mc) {
1148                 return;
1149         }
1150
1151         Button* b = id_button_map[bid];
1152
1153         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1154
1155                 if (mc->muted_by_self ()) {
1156                         /* full mute */
1157                         b->set_color (LED::Blue);
1158                         b->set_state (LED::OneShot24th);
1159                         cerr << "FULL MUTE1\n";
1160                 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1161                         /* this will reflect both solo mutes AND master mutes */
1162                         b->set_color (LED::Blue);
1163                         b->set_state (LED::Blinking4th);
1164                         cerr << "OTHER MUTE1\n";
1165                 } else {
1166                         /* no mute at all */
1167                         b->set_color (LED::Black);
1168                         b->set_state (LED::OneShot24th);
1169                         cerr << "NO MUTE1\n";
1170                 }
1171
1172         } else {
1173
1174                 if (mc->muted_by_self()) {
1175                         /* full mute */
1176                         b->set_color (LED::Blue);
1177                         b->set_state (LED::OneShot24th);
1178                         cerr << "FULL MUTE2\n";
1179                 } else if (mc->muted_by_masters ()) {
1180                         /* this shows only master mutes, not mute-by-others-soloing */
1181                         b->set_color (LED::Blue);
1182                         b->set_state (LED::Blinking4th);
1183                         cerr << "OTHER MUTE1\n";
1184                 } else {
1185                         /* no mute at all */
1186                         b->set_color (LED::Black);
1187                         b->set_state (LED::OneShot24th);
1188                         cerr << "NO MUTE2\n";
1189                 }
1190         }
1191
1192         write (b->state_msg());
1193 }
1194
1195 void
1196 Push2::strip_vpot (int n, int delta)
1197 {
1198         if (stripable[n]) {
1199                 boost::shared_ptr<AutomationControl> ac = stripable[n]->gain_control();
1200                 if (ac) {
1201                         ac->set_value (ac->get_value() + ((2.0/64.0) * delta), PBD::Controllable::UseGroup);
1202                 }
1203         }
1204 }
1205
1206 void
1207 Push2::strip_vpot_touch (int n, bool touching)
1208 {
1209         if (stripable[n]) {
1210                 boost::shared_ptr<AutomationControl> ac = stripable[n]->gain_control();
1211                 if (ac) {
1212                         if (touching) {
1213                                 ac->start_touch (session->audible_frame());
1214                         } else {
1215                                 ac->stop_touch (true, session->audible_frame());
1216                         }
1217                 }
1218         }
1219 }
1220
1221 void
1222 Push2::other_vpot (int n, int delta)
1223 {
1224         switch (n) {
1225         case 0:
1226                 break;
1227         case 1:
1228                 break;
1229         case 2:
1230                 /* master gain control */
1231                 if (master) {
1232                         boost::shared_ptr<AutomationControl> ac = master->gain_control();
1233                         if (ac) {
1234                                 ac->set_value (ac->get_value() + ((2.0/64.0) * delta), PBD::Controllable::UseGroup);
1235                         }
1236                 }
1237                 break;
1238         }
1239 }
1240
1241 void
1242 Push2::other_vpot_touch (int n, bool touching)
1243 {
1244         switch (n) {
1245         case 0:
1246                 break;
1247         case 1:
1248                 break;
1249         case 2:
1250                 if (master) {
1251                         boost::shared_ptr<AutomationControl> ac = master->gain_control();
1252                         if (ac) {
1253                                 if (touching) {
1254                                         ac->start_touch (session->audible_frame());
1255                                 } else {
1256                                         ac->stop_touch (true, session->audible_frame());
1257                                 }
1258                         }
1259                 }
1260         }
1261 }
1262
1263 void
1264 Push2::start_shift ()
1265 {
1266         cerr << "start shift\n";
1267         modifier_state = ModifierState (modifier_state | ModShift);
1268         Button* b = id_button_map[Shift];
1269         b->set_color (LED::White);
1270         b->set_state (LED::Blinking16th);
1271         write (b->state_msg());
1272 }
1273
1274 void
1275 Push2::end_shift ()
1276 {
1277         if (modifier_state & ModShift) {
1278                 cerr << "end shift\n";
1279                 modifier_state = ModifierState (modifier_state & ~(ModShift));
1280                 Button* b = id_button_map[Shift];
1281                 b->timeout_connection.disconnect ();
1282                 b->set_color (LED::White);
1283                 b->set_state (LED::OneShot24th);
1284                 write (b->state_msg());
1285         }
1286 }
1287
1288 void
1289 Push2::start_select ()
1290 {
1291         cerr << "start select\n";
1292         modifier_state = ModifierState (modifier_state | ModSelect);
1293         Button* b = id_button_map[Select];
1294         b->set_color (LED::White);
1295         b->set_state (LED::Blinking16th);
1296         write (b->state_msg());
1297 }
1298
1299 void
1300 Push2::end_select ()
1301 {
1302         if (modifier_state & ModSelect) {
1303                 cerr << "end select\n";
1304                 modifier_state = ModifierState (modifier_state & ~(ModSelect));
1305                 Button* b = id_button_map[Select];
1306                 b->timeout_connection.disconnect ();
1307                 b->set_color (LED::White);
1308                 b->set_state (LED::OneShot24th);
1309                 write (b->state_msg());
1310         }
1311 }
1312
1313 void
1314 Push2::splash ()
1315 {
1316         std::string splash_file;
1317
1318         Searchpath rc (ARDOUR::ardour_data_search_path());
1319         rc.add_subdirectory_to_paths ("resources");
1320
1321         if (!find_file (rc, PROGRAM_NAME "-splash.png", splash_file)) {
1322                 cerr << "Cannot find splash screen image file\n";
1323                 throw failed_constructor();
1324         }
1325
1326         Cairo::RefPtr<Cairo::ImageSurface> img = Cairo::ImageSurface::create_from_png (splash_file);
1327
1328         double x_ratio = (double) img->get_width() / (cols - 20);
1329         double y_ratio = (double) img->get_height() / (rows - 20);
1330         double scale = min (x_ratio, y_ratio);
1331
1332         /* background */
1333
1334         context->set_source_rgb (0.764, 0.882, 0.882);
1335         context->paint ();
1336
1337         /* image */
1338
1339         context->save ();
1340         context->translate (5, 5);
1341         context->scale (scale, scale);
1342         context->set_source (img, 0, 0);
1343         context->paint ();
1344         context->restore ();
1345
1346         /* text */
1347
1348         Glib::RefPtr<Pango::Layout> some_text = Pango::Layout::create (context);
1349
1350         Pango::FontDescription fd ("Sans 38");
1351         some_text->set_font_description (fd);
1352         some_text->set_text (string_compose ("%1 %2", PROGRAM_NAME, VERSIONSTRING));
1353
1354         context->move_to (200, 10);
1355         context->set_source_rgb (0, 0, 0);
1356         some_text->update_from_cairo_context (context);
1357         some_text->show_in_cairo_context (context);
1358
1359         Pango::FontDescription fd2 ("Sans Italic 18");
1360         some_text->set_font_description (fd2);
1361         some_text->set_text (_("Ableton Push 2 Support"));
1362
1363         context->move_to (200, 80);
1364         context->set_source_rgb (0, 0, 0);
1365         some_text->update_from_cairo_context (context);
1366         some_text->show_in_cairo_context (context);
1367
1368         splash_start = get_microseconds ();
1369         blit_to_device_frame_buffer ();
1370 }