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