9b6d84dbe3a5510c1bc5641597a7f61956cb0fef
[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/debug.h"
25 #include "pbd/failed_constructor.h"
26
27 #include "midi++/parser.h"
28
29 #include "ardour/async_midi_port.h"
30 #include "ardour/audioengine.h"
31 #include "ardour/debug.h"
32 #include "ardour/midiport_manager.h"
33 #include "ardour/session.h"
34 #include "push2.h"
35
36 using namespace ARDOUR;
37 using namespace std;
38 using namespace PBD;
39 using namespace Glib;
40 using namespace ArdourSurface;
41
42 #include "i18n.h"
43
44 #include "pbd/abstract_ui.cc" // instantiate template
45
46 const int Push2::cols = 960;
47 const int Push2::rows = 160;
48 const int Push2::pixels_per_row = 1024;
49
50 #define ABLETON 0x2982
51 #define PUSH2   0x1967
52
53 Push2::Push2 (ARDOUR::Session& s)
54         : ControlProtocol (s, string (X_("Ableton Push 2")))
55         , AbstractUI<Push2Request> (name())
56         , handle (0)
57         , device_buffer (0)
58         , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows))
59 {
60         build_maps ();
61 }
62
63 Push2::~Push2 ()
64 {
65         close ();
66 }
67
68 int
69 Push2::open ()
70 {
71         int err;
72
73         if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
74                 return -1;
75         }
76
77         if ((err = libusb_claim_interface (handle, 0x00))) {
78                 return -1;
79         }
80
81         device_frame_buffer[0] = new uint16_t[rows*pixels_per_row];
82         device_frame_buffer[1] = new uint16_t[rows*pixels_per_row];
83
84         memset (device_frame_buffer[0], 0, sizeof (uint16_t) * rows * pixels_per_row);
85         memset (device_frame_buffer[1], 0, sizeof (uint16_t) * rows * pixels_per_row);
86
87         frame_header[0] = 0xef;
88         frame_header[1] = 0xcd;
89         frame_header[2] = 0xab;
90         frame_header[3] = 0x89;
91         memset (&frame_header[4], 0, 12);
92
93         /* setup ports */
94
95         _async_in[0]  = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("push2 in1"), true);
96         _async_out[0] = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("push2 out1"), true);
97
98         if (_async_in[0] == 0 || _async_out[0] == 0) {
99                 return -1;
100         }
101
102         _input_port[0] = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in[0]).get();
103         _output_port[0] = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out[0]).get();
104
105         _async_in[1]  = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("push2 in2"), true);
106         _async_out[1] = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("push2 out2"), true);
107
108         if (_async_in[1] == 0 || _async_out[1] == 0) {
109                 return -1;
110         }
111
112         _input_port[1] = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in[1]).get();
113         _output_port[1] = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out[1]).get();
114
115         AsyncMIDIPort* asp;
116
117         asp = dynamic_cast<AsyncMIDIPort*> (_input_port[0]);
118         asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port[0]));
119         asp->xthread().attach (main_loop()->get_context());
120
121         asp = dynamic_cast<AsyncMIDIPort*> (_input_port[1]);
122         asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port[1]));
123         asp->xthread().attach (main_loop()->get_context());
124
125         connect_to_parser ();
126
127         return 0;
128 }
129
130 int
131 Push2::close ()
132 {
133         AudioEngine::instance()->unregister_port (_async_in[0]);
134         AudioEngine::instance()->unregister_port (_async_out[0]);
135         AudioEngine::instance()->unregister_port (_async_in[1]);
136         AudioEngine::instance()->unregister_port (_async_out[1]);
137
138         _async_in[0].reset ((ARDOUR::Port*) 0);
139         _async_out[0].reset ((ARDOUR::Port*) 0);
140         _async_in[1].reset ((ARDOUR::Port*) 0);
141         _async_out[1].reset ((ARDOUR::Port*) 0);
142
143         vblank_connection.disconnect ();
144         periodic_connection.disconnect ();
145         session_connections.drop_connections ();
146
147         if (handle) {
148                 libusb_release_interface (handle, 0x00);
149                 libusb_close (handle);
150         }
151
152         delete [] device_frame_buffer[0];
153         device_frame_buffer[0] = 0;
154
155         delete [] device_frame_buffer[1];
156         device_frame_buffer[1] = 0;
157
158         return 0;
159 }
160
161 bool
162 Push2::probe ()
163 {
164         libusb_device_handle *h;
165         libusb_init (NULL);
166
167         if ((h = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
168                 DEBUG_TRACE (DEBUG::Push2, "no Push2 device found\n");
169                 return false;
170         }
171
172         libusb_close (h);
173         DEBUG_TRACE (DEBUG::Push2, "Push2 device located\n");
174         return true;
175 }
176
177 void*
178 Push2::request_factory (uint32_t num_requests)
179 {
180         /* AbstractUI<T>::request_buffer_factory() is a template method only
181            instantiated in this source module. To provide something visible for
182            use in the interface/descriptor, we have this static method that is
183            template-free.
184         */
185         return request_buffer_factory (num_requests);
186 }
187
188 void
189 Push2::do_request (Push2Request * req)
190 {
191         DEBUG_TRACE (DEBUG::Push2, string_compose ("doing request type %1\n", req->type));
192         if (req->type == CallSlot) {
193
194                 call_slot (MISSING_INVALIDATOR, req->the_slot);
195
196         } else if (req->type == Quit) {
197
198                 stop ();
199         }
200 }
201
202 int
203 Push2::stop ()
204 {
205         BaseUI::quit ();
206         close ();
207         return 0;
208 }
209
210 /** render host-side frame buffer (a Cairo ImageSurface) to the current
211  * device-side frame buffer. The device frame buffer will be pushed to the
212  * device on the next call to vblank()
213  */
214
215 int
216 Push2::render ()
217 {
218         /* ensure that all drawing has been done before we fetch pixel data */
219
220         frame_buffer->flush ();
221
222         const int stride = 3840; /* bytes per row for Cairo::FORMAT_ARGB32 */
223         const uint8_t* data = frame_buffer->get_data ();
224
225         /* fill frame buffer (320kB) */
226
227         Glib::Threads::Mutex::Lock lm (fb_lock);
228
229         uint16_t* fb = (uint16_t*) device_frame_buffer[device_buffer];
230
231         for (int row = 0; row < rows; ++row) {
232
233                 const uint8_t* dp = data + row * stride;
234
235                 for (int col = 0; col < cols; ++col) {
236
237                         /* fetch r, g, b (range 0..255). Ignore alpha */
238
239                         const int r = (*((const uint32_t*)dp) >> 16) & 0xff;
240                         const int g = (*((const uint32_t*)dp) >> 8) & 0xff;
241                         const int b = *((const uint32_t*)dp) & 0xff;
242
243                         /* convert to 5 bits, 6 bits, 5 bits, respectively */
244                         /* generate 16 bit BGB565 value */
245
246                         *fb++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
247
248                         dp += 4;
249                 }
250
251                 /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
252                    byte USB buffers
253                 */
254
255                 fb += 64; /* 128 bytes = 64 int16_t */
256         }
257
258         /* swap buffers (under lock protection) */
259         // device_buffer = (device_buffer ? 0 : 1);
260
261         return 0;
262 }
263
264 bool
265 Push2::vblank ()
266 {
267         int transferred = 0;
268         const int timeout_msecs = 1000;
269         int err;
270
271         if ((err = libusb_bulk_transfer (handle, 0x01, frame_header, sizeof (frame_header), &transferred, timeout_msecs))) {
272                 return false;
273         }
274
275         {
276                 Glib::Threads::Mutex::Lock lm (fb_lock);
277
278                 if ((err = libusb_bulk_transfer (handle, 0x01, (uint8_t*) device_frame_buffer[device_buffer] , 2 * rows * pixels_per_row, &transferred, timeout_msecs))) {
279                         return false;
280                 }
281         }
282
283         return true;
284 }
285
286 int
287 Push2::set_active (bool yn)
288 {
289         DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active init with yn: '%1'\n", yn));
290
291         if (yn == active()) {
292                 return 0;
293         }
294
295         if (yn) {
296
297                 /* start event loop */
298
299                 BaseUI::run ();
300
301                 if (open ()) {
302                         DEBUG_TRACE (DEBUG::Push2, "device open failed\n");
303                         close ();
304                         return -1;
305                 }
306
307                 connect_session_signals ();
308
309                 /* say hello */
310
311                 Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create (frame_buffer);
312                 if (!context) {
313                         cerr << "Cannot create context\n";
314                         return -1;
315                 }
316                 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create (context);
317                 if (!layout) {
318                         cerr << "Cannot create layout\n";
319                         return -1;
320                 }
321
322                 layout->set_text ("hello, Ardour");
323                 Pango::FontDescription fd ("Sans Bold 12");
324                 layout->set_font_description (fd);
325
326                 context->set_source_rgb (0.0, 1.0, 1.0);
327                 context->rectangle (0, 0, 960, 160);
328                 context->fill ();
329                 context->set_source_rgb (0.0, 0.0, 0.0);
330                 context->rectangle (50, 50, 860, 60);
331                 context->fill ();
332                 context->move_to (60, 60);
333                 context->set_source_rgb ((random()%255) / 255.0, (random()%255) / 255.0, (random()%255) / 255.0);
334                 layout->update_from_cairo_context (context);
335                 layout->show_in_cairo_context (context);
336
337                 render ();
338
339                 /* set up periodic task used to push a frame buffer to the
340                  * device (25fps). The device can handle 60fps, but we don't
341                  * need that frame rate.
342                  */
343
344                 Glib::RefPtr<Glib::TimeoutSource> vblank_timeout = Glib::TimeoutSource::create (40); // milliseconds
345                 vblank_connection = vblank_timeout->connect (sigc::mem_fun (*this, &Push2::vblank));
346                 vblank_timeout->attach (main_loop()->get_context());
347
348
349                 Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (1000); // milliseconds
350                 periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &Push2::periodic));
351                 periodic_timeout->attach (main_loop()->get_context());
352
353         } else {
354
355                 stop ();
356
357         }
358
359         ControlProtocol::set_active (yn);
360
361         DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active done with yn: '%1'\n", yn));
362
363         return 0;
364 }
365
366 void
367 Push2::write (int port, const MidiByteArray& data)
368 {
369         /* immediate delivery */
370         cerr << data << endl;
371         _output_port[port]->write (&data[0], data.size(), 0);
372 }
373
374 bool
375 Push2::midi_input_handler (IOCondition ioc, MIDI::Port* port)
376 {
377         if (ioc & ~IO_IN) {
378                 DEBUG_TRACE (DEBUG::Push2, "MIDI port closed\n");
379                 return false;
380         }
381
382         if (ioc & IO_IN) {
383
384                 // DEBUG_TRACE (DEBUG::Push2, string_compose ("something happend on  %1\n", port->name()));
385
386                 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
387                 if (asp) {
388                         asp->clear ();
389                 }
390
391                 //DEBUG_TRACE (DEBUG::Push2, string_compose ("data available on %1\n", port->name()));
392                 framepos_t now = AudioEngine::instance()->sample_time();
393                 port->parse (now);
394         }
395
396         return true;
397 }
398
399 bool
400 Push2::periodic ()
401 {
402         return true;
403 }
404
405 void
406 Push2::connect_to_parser ()
407 {
408         DEBUG_TRACE (DEBUG::Push2, string_compose ("Connecting to signals on port %2\n", _input_port[0]->name()));
409
410         MIDI::Parser* p = _input_port[0]->parser();
411
412         /* Incoming sysex */
413         p->sysex.connect_same_thread (*this, boost::bind (&Push2::handle_midi_sysex, this, _1, _2, _3));
414         /* V-Pot messages are Controller */
415         p->controller.connect_same_thread (*this, boost::bind (&Push2::handle_midi_controller_message, this, _1, _2));
416         /* Button messages are NoteOn */
417         p->note_on.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
418         /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
419         p->note_off.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
420         /* Fader messages are Pitchbend */
421         p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&Push2::handle_midi_pitchbend_message, this, _1, _2));
422 }
423
424 void
425 Push2::handle_midi_sysex (MIDI::Parser&, MIDI::byte* raw_bytes, size_t sz)
426 {
427         cerr << "sysex, " << sz << " bytes\n";
428 }
429
430 void
431 Push2::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
432 {
433         cerr << "controller " << (int) ev->controller_number << " = " << (int) ev->value << endl;
434         CCButtonMap::iterator b = cc_button_map.find (ev->controller_number);
435         if (b != cc_button_map.end()) {
436                 if (ev->value == 0) {
437                         (this->*b->second->release_method)();
438                 } else {
439                         (this->*b->second->press_method)();
440                 }
441         }
442 }
443
444 void
445 Push2::handle_midi_note_on_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
446 {
447         cerr << "note on" << (int) ev->note_number << ", velocity " << (int) ev->velocity << endl;
448 }
449
450 void
451 Push2::handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
452 {
453         cerr << "note on" << (int) ev->note_number << ", velocity " << (int) ev->velocity << endl;
454 }
455
456 void
457 Push2::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb)
458 {
459         cerr << "pitchbend @ " << pb << endl;
460 }
461
462 void
463 Push2::build_maps ()
464 {
465         /* Pads */
466
467         Pad* pad;
468
469 #define MAKE_PAD(x,y,nn) \
470         pad = new Pad ((x), (y), (nn)); \
471         nn_pad_map.insert (make_pair (pad->extra(), pad)); \
472         coord_pad_map.insert (make_pair (pad->coord(), pad));
473
474         MAKE_PAD (0, 1, 93);
475         MAKE_PAD (0, 2, 94);
476         MAKE_PAD (0, 3, 95);
477         MAKE_PAD (0, 4, 96);
478         MAKE_PAD (0, 5, 97);
479         MAKE_PAD (0, 6, 98);
480         MAKE_PAD (0, 7, 90);
481         MAKE_PAD (1, 0, 84);
482         MAKE_PAD (1, 1, 85);
483         MAKE_PAD (1, 2, 86);
484         MAKE_PAD (1, 3, 87);
485         MAKE_PAD (1, 4, 88);
486         MAKE_PAD (1, 5, 89);
487         MAKE_PAD (1, 6, 90);
488         MAKE_PAD (1, 7, 91);
489         MAKE_PAD (2, 0, 76);
490         MAKE_PAD (2, 1, 77);
491         MAKE_PAD (2, 2, 78);
492         MAKE_PAD (2, 3, 79);
493         MAKE_PAD (2, 4, 80);
494         MAKE_PAD (2, 5, 81);
495         MAKE_PAD (2, 6, 82);
496         MAKE_PAD (2, 7, 83);
497         MAKE_PAD (3, 0, 68);
498         MAKE_PAD (3, 1, 69);
499         MAKE_PAD (3, 2, 70);
500         MAKE_PAD (3, 3, 71);
501         MAKE_PAD (3, 4, 72);
502         MAKE_PAD (3, 5, 73);
503         MAKE_PAD (3, 6, 74);
504         MAKE_PAD (3, 7, 75);
505         MAKE_PAD (4, 0, 60);
506         MAKE_PAD (4, 1, 61);
507         MAKE_PAD (4, 2, 62);
508         MAKE_PAD (4, 3, 63);
509         MAKE_PAD (4, 4, 64);
510         MAKE_PAD (4, 5, 65);
511         MAKE_PAD (4, 6, 66);
512         MAKE_PAD (4, 7, 67);
513         MAKE_PAD (5, 0, 52);
514         MAKE_PAD (5, 1, 53);
515         MAKE_PAD (5, 2, 54);
516         MAKE_PAD (5, 3, 56);
517         MAKE_PAD (5, 4, 56);
518         MAKE_PAD (5, 5, 57);
519         MAKE_PAD (5, 6, 58);
520         MAKE_PAD (5, 7, 59);
521         MAKE_PAD (6, 0, 44);
522         MAKE_PAD (6, 1, 45);
523         MAKE_PAD (6, 2, 46);
524         MAKE_PAD (6, 3, 47);
525         MAKE_PAD (6, 4, 48);
526         MAKE_PAD (6, 5, 49);
527         MAKE_PAD (6, 6, 50);
528         MAKE_PAD (6, 7, 51);
529         MAKE_PAD (7, 0, 36);
530         MAKE_PAD (7, 1, 37);
531         MAKE_PAD (7, 2, 38);
532         MAKE_PAD (7, 3, 39);
533         MAKE_PAD (7, 4, 40);
534         MAKE_PAD (7, 5, 41);
535         MAKE_PAD (7, 6, 42);
536         MAKE_PAD (7, 7, 43);
537
538         /* Now color buttons */
539
540         Button *button;
541
542 #define MAKE_COLOR_BUTTON(i,cc) \
543         button = new ColorButton ((i), (cc)); \
544         cc_button_map.insert (make_pair (button->controller_number(), button)); \
545         id_button_map.insert (make_pair (button->id, button));
546 #define MAKE_COLOR_BUTTON_PRESS(i,cc,p)\
547         button = new ColorButton ((i), (cc), (p)); \
548         cc_button_map.insert (make_pair (button->controller_number(), button)); \
549         id_button_map.insert (make_pair (button->id, button))
550
551         MAKE_COLOR_BUTTON (Upper1, 102);
552         MAKE_COLOR_BUTTON (Upper2, 103);
553         MAKE_COLOR_BUTTON (Upper3, 104);
554         MAKE_COLOR_BUTTON (Upper4, 105);
555         MAKE_COLOR_BUTTON (Upper5, 106);
556         MAKE_COLOR_BUTTON (Upper6, 107);
557         MAKE_COLOR_BUTTON (Upper7, 108);
558         MAKE_COLOR_BUTTON (Upper8, 109);
559         MAKE_COLOR_BUTTON (Lower1, 21);
560         MAKE_COLOR_BUTTON (Lower2, 22);
561         MAKE_COLOR_BUTTON (Lower3, 23);
562         MAKE_COLOR_BUTTON (Lower4, 24);
563         MAKE_COLOR_BUTTON (Lower5, 25);
564         MAKE_COLOR_BUTTON (Lower6, 26);
565         MAKE_COLOR_BUTTON (Lower7, 27);
566         MAKE_COLOR_BUTTON (Mute, 60);
567         MAKE_COLOR_BUTTON (Solo, 61);
568         MAKE_COLOR_BUTTON (Stop, 29);
569         MAKE_COLOR_BUTTON (Fwd32ndT, 43);
570         MAKE_COLOR_BUTTON (Fwd32nd,42 );
571         MAKE_COLOR_BUTTON (Fwd16thT, 41);
572         MAKE_COLOR_BUTTON (Fwd16th, 40);
573         MAKE_COLOR_BUTTON (Fwd8thT, 39 );
574         MAKE_COLOR_BUTTON (Fwd8th, 38);
575         MAKE_COLOR_BUTTON (Fwd4trT, 37);
576         MAKE_COLOR_BUTTON (Fwd4tr, 36);
577         MAKE_COLOR_BUTTON (Automate, 89);
578         MAKE_COLOR_BUTTON_PRESS (RecordEnable, 86, &Push::button_recenable);
579         MAKE_COLOR_BUTTON_PRESS (Play, 85, &Push2::button_play);
580
581 #define MAKE_WHITE_BUTTON(i,cc)\
582         button = new WhiteButton ((i), (cc)); \
583         cc_button_map.insert (make_pair (button->controller_number(), button)); \
584         id_button_map.insert (make_pair (button->id, button))
585 #define MAKE_WHITE_BUTTON_PRESS(i,cc,p)\
586         button = new WhiteButton ((i), (cc), (p)); \
587         cc_button_map.insert (make_pair (button->controller_number(), button)); \
588         id_button_map.insert (make_pair (button->id, button))
589
590         MAKE_WHITE_BUTTON (TapTempo, 3);
591         MAKE_WHITE_BUTTON (Metronome, 9);
592         MAKE_WHITE_BUTTON (Setup, 30);
593         MAKE_WHITE_BUTTON (User, 59);
594         MAKE_WHITE_BUTTON (Delete, 118);
595         MAKE_WHITE_BUTTON (AddDevice, 52);
596         MAKE_WHITE_BUTTON (Device, 110);
597         MAKE_WHITE_BUTTON (Mix, 112);
598         MAKE_WHITE_BUTTON (Undo, 119);
599         MAKE_WHITE_BUTTON (AddTrack, 53);
600         MAKE_WHITE_BUTTON (Browse, 113);
601         MAKE_WHITE_BUTTON (Convert, 35);
602         MAKE_WHITE_BUTTON (DoubleLoop, 117);
603         MAKE_WHITE_BUTTON (Quantize, 116);
604         MAKE_WHITE_BUTTON (Duplicate, 88);
605         MAKE_WHITE_BUTTON (New, 87);
606         MAKE_WHITE_BUTTON (FixedLength, 90);
607         MAKE_WHITE_BUTTON_PRESS (Up, 46, &Push2::button_up);
608         MAKE_WHITE_BUTTON (Right, 45);
609         MAKE_WHITE_BUTTON_PRESS (Down, 47, &Push2::button_down);
610         MAKE_WHITE_BUTTON (Left, 44);
611         MAKE_WHITE_BUTTON (Repeat, 56);
612         MAKE_WHITE_BUTTON (Accent, 57);
613         MAKE_WHITE_BUTTON (Scale, 58);
614         MAKE_WHITE_BUTTON (Layout, 31);
615         MAKE_WHITE_BUTTON (OctaveUp, 55);
616         MAKE_WHITE_BUTTON (PageRight, 63);
617         MAKE_WHITE_BUTTON (OctaveDown, 54);
618         MAKE_WHITE_BUTTON (PageLeft, 62);
619         MAKE_WHITE_BUTTON (Shift, 49);
620         MAKE_WHITE_BUTTON (Select, 48);
621 }
622
623 void
624 Push2::thread_init ()
625 {
626         struct sched_param rtparam;
627
628         pthread_set_name (event_loop_name().c_str());
629
630         PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
631         ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
632
633         memset (&rtparam, 0, sizeof (rtparam));
634         rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
635
636         if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
637                 // do we care? not particularly.
638         }
639 }
640
641 void
642 Push2::connect_session_signals()
643 {
644         // receive routes added
645         //session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_routes_added, this, _1), this);
646         // receive VCAs added
647         //session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_vca_added, this, _1), this);
648
649         // receive record state toggled
650         session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_record_state_changed, this), this);
651         // receive transport state changed
652         session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_transport_state_changed, this), this);
653         session->TransportLooped.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_loop_state_changed, this), this);
654         // receive punch-in and punch-out
655         Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
656         session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
657         // receive rude solo changed
658         session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_solo_active_changed, this, _1), this);
659 }
660
661 void
662 Push2::notify_record_state_changed ()
663 {
664         IDButtonMap::iterator b = id_button_map.find (RecordEnable);
665
666         if (b == id_button_map.end()) {
667                 return;
668         }
669
670         if (session->actively_recording ()) {
671                 b->second->set_state (LED::OneShot24th);
672                 b->second->set_color (127);
673         } else {
674                 b->second->set_state (LED::Off);
675         }
676
677         write (0, b->second->state_msg());
678 }
679
680 void
681 Push2::notify_transport_state_changed ()
682 {
683         cerr << "ts change, id button map holds " << id_button_map.size() << endl;
684
685         IDButtonMap::iterator b = id_button_map.find (Play);
686
687         if (b == id_button_map.end()) {
688                 cerr << " no button\n";
689                 return;
690         }
691
692         if (session->transport_rolling()) {
693                 b->second->set_state (LED::OneShot24th);
694                 b->second->set_color (125);
695         } else {
696                 b->second->set_state (LED::Off);
697         }
698
699         write (0, b->second->state_msg());
700 }
701
702 void
703 Push2::notify_loop_state_changed ()
704 {
705 }
706
707 void
708 Push2::notify_parameter_changed (std::string)
709 {
710 }
711
712 void
713 Push2::notify_solo_active_changed (bool yn)
714 {
715         IDButtonMap::iterator b = id_button_map.find (Solo);
716
717         if (b == id_button_map.end()) {
718                 return;
719         }
720
721         if (yn) {
722                 b->second->set_state (LED::Blinking24th);
723         } else {
724                 b->second->set_state (LED::Off);
725         }
726
727         write (0, b->second->state_msg());
728 }
729
730 XMLNode&
731 Push2::get_state()
732 {
733         XMLNode& node (ControlProtocol::get_state());
734
735         DEBUG_TRACE (DEBUG::Push2, "Push2::get_state done\n");
736
737         return node;
738 }
739
740 int
741 Push2::set_state (const XMLNode & node, int version)
742 {
743         DEBUG_TRACE (DEBUG::Push2, string_compose ("Push2::set_state: active %1\n", active()));
744
745         int retval = 0;
746
747         if (ControlProtocol::set_state (node, version)) {
748                 return -1;
749         }
750
751
752         return retval;
753 }