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