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