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