Fix an invalid conversion from 'int' to non-scalar.
[ardour.git] / libs / surfaces / launch_control_xl / controllers.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 <algorithm>
20
21 #include "ardour/debug.h"
22 #include "ardour/mute_control.h"
23 #include "ardour/session.h"
24 #include "ardour/solo_control.h"
25 #include "ardour/solo_isolate_control.h"
26
27 #include "launch_control_xl.h"
28
29 using namespace ArdourSurface;
30 using namespace ARDOUR;
31 using namespace PBD;
32 using std::cerr;
33
34 void
35 LaunchControlXL::build_maps ()
36 {
37         /* Knobs */
38
39         boost::shared_ptr<Knob> knob;
40
41         #define MAKE_KNOB(i,cc, index) \
42                 knob.reset (new Knob ((i), (cc), (index), (*this))); \
43                 cc_knob_map.insert (std::make_pair (knob->controller_number(), knob)); \
44                 id_knob_map.insert (std::make_pair (knob->id(), knob))
45
46                 for (uint8_t n = 0; n < 8; ++n) {
47                         MAKE_KNOB (static_cast<KnobID>(n), (n + 13), n);
48                         MAKE_KNOB (static_cast<KnobID>(n + 8), (n + 29), (n + 8));
49                         MAKE_KNOB (static_cast<KnobID>(n + 16), (n + 49), (n + 16));
50                 }
51
52         /* Faders */
53
54         boost::shared_ptr<Fader> fader;
55
56         #define MAKE_FADER(i,cc) \
57                 fader.reset (new Fader ((i), (cc))); \
58                 cc_fader_map.insert (std::make_pair (fader->controller_number(), fader)); \
59                 id_fader_map.insert (std::make_pair (fader->id(), fader))
60
61                 for (uint8_t n = 0; n < 8; ++n) {
62                         MAKE_FADER (static_cast<FaderID>(n), (n + 77) );
63                 }
64
65         /* Buttons */
66
67         boost::shared_ptr<ControllerButton> controller_button;
68         boost::shared_ptr<NoteButton> note_button;
69
70
71         #define MAKE_TRACK_BUTTON_PRESS(i,nn,index,color,p) \
72                 note_button.reset (new TrackButton ((i), (nn), (index), (color), (p), (*this))); \
73                 nn_note_button_map.insert (std::make_pair (note_button->note_number(), note_button)); \
74                 id_note_button_map.insert (std::make_pair (note_button->id(), note_button))
75         #define MAKE_SELECT_BUTTON_PRESS(i,cc,index,p) \
76                 controller_button.reset (new SelectButton ((i), (cc), (index), (p), (*this))); \
77                 cc_controller_button_map.insert (std::make_pair (controller_button->controller_number(), controller_button)); \
78                 id_controller_button_map.insert (std::make_pair (controller_button->id(), controller_button))
79         #define MAKE_TRACK_STATE_BUTTON_PRESS(i,nn,index,p) \
80                 note_button.reset (new TrackStateButton ((i), (nn), (index), (p), (*this))); \
81                 nn_note_button_map.insert (std::make_pair (note_button->note_number(), note_button)); \
82                 id_note_button_map.insert (std::make_pair (note_button->id(), note_button))
83                 #define MAKE_TRACK_STATE_BUTTON_PRESS_RELEASE_LONG(i,nn,index, p,r,l) \
84                         note_button.reset (new TrackStateButton ((i), (nn), (index), (p), (r), (l), (*this))); \
85                         nn_note_button_map.insert (std::make_pair (note_button->note_number(), note_button)); \
86                         id_note_button_map.insert (std::make_pair (note_button->id(), note_button))
87
88
89         MAKE_TRACK_BUTTON_PRESS(Focus1, 41, 24, YellowLow, &LaunchControlXL::button_track_focus_1);
90         MAKE_TRACK_BUTTON_PRESS(Focus2, 42, 25, YellowLow, &LaunchControlXL::button_track_focus_2);
91         MAKE_TRACK_BUTTON_PRESS(Focus3, 43, 26, YellowLow, &LaunchControlXL::button_track_focus_3);
92         MAKE_TRACK_BUTTON_PRESS(Focus4, 44, 27, YellowLow, &LaunchControlXL::button_track_focus_4);
93         MAKE_TRACK_BUTTON_PRESS(Focus5, 57, 28, YellowLow, &LaunchControlXL::button_track_focus_5);
94         MAKE_TRACK_BUTTON_PRESS(Focus6, 58, 29, YellowLow, &LaunchControlXL::button_track_focus_6);
95         MAKE_TRACK_BUTTON_PRESS(Focus7, 59, 30, YellowLow, &LaunchControlXL::button_track_focus_7);
96         MAKE_TRACK_BUTTON_PRESS(Focus8, 60, 31, YellowLow, &LaunchControlXL::button_track_focus_8);
97         MAKE_TRACK_BUTTON_PRESS(Control1, 73, 32, AmberLow, &LaunchControlXL::button_track_control_1);
98         MAKE_TRACK_BUTTON_PRESS(Control2, 74, 33, AmberLow, &LaunchControlXL::button_track_control_2);
99         MAKE_TRACK_BUTTON_PRESS(Control3, 75, 34, AmberLow, &LaunchControlXL::button_track_control_3);
100         MAKE_TRACK_BUTTON_PRESS(Control4, 76, 35, AmberLow, &LaunchControlXL::button_track_control_4);
101         MAKE_TRACK_BUTTON_PRESS(Control5, 89, 36, AmberLow, &LaunchControlXL::button_track_control_5);
102         MAKE_TRACK_BUTTON_PRESS(Control6, 90, 37, AmberLow, &LaunchControlXL::button_track_control_6);
103         MAKE_TRACK_BUTTON_PRESS(Control7, 91, 38, AmberLow, &LaunchControlXL::button_track_control_7);
104         MAKE_TRACK_BUTTON_PRESS(Control8, 92, 39, AmberLow, &LaunchControlXL::button_track_control_8);
105
106         MAKE_SELECT_BUTTON_PRESS(SelectUp, 104, 44, &LaunchControlXL::button_select_up);
107         MAKE_SELECT_BUTTON_PRESS(SelectDown, 105, 45, &LaunchControlXL::button_select_down);
108         MAKE_SELECT_BUTTON_PRESS(SelectLeft, 106, 46, &LaunchControlXL::button_select_left);
109         MAKE_SELECT_BUTTON_PRESS(SelectRight, 107, 47, &LaunchControlXL::button_select_right);
110
111         MAKE_TRACK_STATE_BUTTON_PRESS_RELEASE_LONG(Device, 105, 40, &LaunchControlXL::relax, &LaunchControlXL::button_device, &LaunchControlXL::button_device_long_press);;
112         MAKE_TRACK_STATE_BUTTON_PRESS(Mute, 106, 41, &LaunchControlXL::button_mute);
113         MAKE_TRACK_STATE_BUTTON_PRESS(Solo, 107, 42, &LaunchControlXL::button_solo);
114         MAKE_TRACK_STATE_BUTTON_PRESS(Record, 108, 43, &LaunchControlXL::button_record);
115
116 }
117
118 std::string
119 LaunchControlXL::button_name_by_id (ButtonID id)
120 {
121         switch (id) {
122                 case Device:
123                         return "Device";
124                 case Mute:
125                         return "Mute";
126                 case Solo:
127                         return "Solo";
128                 case Record:
129                         return "Record";
130                 case SelectUp:
131                         return "Select Up";
132                 case SelectDown:
133                         return "Select Down";
134                 case SelectRight:
135                         return "Select Right";
136                 case SelectLeft:
137                         return "Select Left";
138                 case Focus1:
139                         return "Focus 1";
140                 case Focus2:
141                         return "Focus 2";
142                 case Focus3:
143                         return "Focus 3";
144                 case Focus4:
145                         return "Focus 4";
146                 case Focus5:
147                         return "Focus 5";
148                 case Focus6:
149                         return "Focus 6";
150                 case Focus7:
151                         return "Focus 7";
152                 case Focus8:
153                         return "Focus 8";
154                 case Control1:
155                         return "Control 1";
156                 case Control2:
157                         return "Control 2";
158                 case Control3:
159                         return "Control 3";
160                 case Control4:
161                         return "Control 4";
162                 case Control5:
163                         return "Control 5";
164                 case Control6:
165                         return "Control 6";
166                 case Control7:
167                         return "Control 7";
168                 case Control8:
169                         return "Control 8";
170         default:
171                 break;
172         }
173
174         return "???";
175 }
176
177 std::string
178 LaunchControlXL::knob_name_by_id (KnobID id)
179 {
180         switch (id) {
181                 case SendA1:
182                         return "SendA 1";
183                 case SendA2:
184                         return "SendA 2";
185                 case SendA3:
186                         return "SendA 3";
187                 case SendA4:
188                         return "SendA 4";
189                 case SendA5:
190                         return "SendA 5";
191                 case SendA6:
192                         return "SendA 6";
193                 case SendA7:
194                         return "SendA 7";
195                 case SendA8:
196                         return "SendA 8";
197                 case SendB1:
198                         return "SendB 1";
199                 case SendB2:
200                         return "SendB 2";
201                 case SendB3:
202                         return "SendB 3";
203                 case SendB4:
204                         return "SendB 4";
205                 case SendB5:
206                         return "SendB 5";
207                 case SendB6:
208                         return "SendB 6";
209                 case SendB7:
210                         return "SendB 7";
211                 case SendB8:
212                         return "SendB 8";
213                 case Pan1:
214                         return "Pan 1";
215                 case Pan2:
216                         return "Pan 2";
217                 case Pan3:
218                         return "Pan 3";
219                 case Pan4:
220                         return "Pan 4";
221                 case Pan5:
222                         return "Pan 5";
223                 case Pan6:
224                         return "Pan 6";
225                 case Pan7:
226                         return "Pan 7";
227                 case Pan8:
228                         return "Pan 8";
229         default:
230                 break;
231         }
232
233         return "???";
234 }
235
236 std::string
237 LaunchControlXL::fader_name_by_id (FaderID id)
238 {
239         switch (id) {
240                 case Fader1:
241                         return "Fader 1";
242                 case Fader2:
243                         return "Fader 2";
244                 case Fader3:
245                         return "Fader 3";
246                 case Fader4:
247                         return "Fader 4";
248                 case Fader5:
249                         return "Fader 5";
250                 case Fader6:
251                         return "Fader 6";
252                 case Fader7:
253                         return "Fader 7";
254                 case Fader8:
255                         return "Fader 8";
256         default:
257                 break;
258         }
259
260         return "???";
261 }
262
263 boost::shared_ptr<LaunchControlXL::TrackButton>
264 LaunchControlXL::track_button_by_range(uint8_t n, uint8_t first, uint8_t middle)
265 {
266         NNNoteButtonMap::iterator b;
267         if ( n < 4)     {
268                 b = nn_note_button_map.find (first + n);
269         } else {
270                 b = nn_note_button_map.find (middle + n - 4);
271         }
272
273         if (b != nn_note_button_map.end()) {
274                 return (b->second);
275         }
276
277         return boost::shared_ptr<LaunchControlXL::TrackButton>();
278 }
279
280 void
281 LaunchControlXL::update_track_focus_led(uint8_t n)
282 {
283         boost::shared_ptr<TrackButton> b = focus_button_by_column(n);
284
285         if (!b) {
286                 return;
287         }
288
289         if (stripable[n]) {
290                 if ( stripable[n]->is_selected() ) {
291                         b->set_color(YellowFull);
292                 } else {
293                         b->set_color(AmberLow);
294                 }
295         } else {
296                 b->set_color(Off);
297         }
298
299         write (b->state_msg());
300 }
301
302 void
303 LaunchControlXL::button_track_focus(uint8_t n)
304 {
305         if (buttons_down.find(Device) != buttons_down.end()) {
306                 DEBUG_TRACE (DEBUG::LaunchControlXL, "DEVICE BUTTON HOLD\n");
307                 if (stripable[n]->solo_isolate_control()) {
308                         bool solo_isolate_active = stripable[n]->solo_isolate_control()->get_value();
309                         stripable[n]->solo_isolate_control()->set_value (!solo_isolate_active, PBD::Controllable::UseGroup);
310                 }
311                 return;
312         }
313
314         if (stripable[n]) {
315                 if ( stripable[n]->is_selected() ) {
316                          ControlProtocol::RemoveStripableFromSelection (stripable[n]);
317                 } else {
318                         ControlProtocol::AddStripableToSelection (stripable[n]);
319                 }
320         } else {
321                 return;
322         }
323 }
324
325 boost::shared_ptr<AutomationControl>
326 LaunchControlXL::get_ac_by_state(uint8_t n) {
327                 boost::shared_ptr<AutomationControl> ac;
328
329                 switch(track_mode()) {
330                         case TrackMute:
331                                 ac = stripable[n]->mute_control();
332                                 break;
333
334                         case TrackSolo:
335                                 ac = stripable[n]->solo_control();
336                                 break;
337
338                         case TrackRecord:
339                                 ac = stripable[n]->rec_enable_control();
340                                 break;
341
342                         default:
343                         break;
344                 }
345                 return ac;
346 }
347
348 boost::shared_ptr<LaunchControlXL::Knob>*
349 LaunchControlXL::knobs_by_column(uint8_t col, boost::shared_ptr<Knob>* knob_col)
350 {
351         for (uint8_t n = 0; n < 3; ++n) {
352                 knob_col[n] = id_knob_map.find(static_cast<KnobID>(col+n*8))->second;
353         }
354
355         return knob_col;
356 }
357
358 void
359 LaunchControlXL::update_knob_led(uint8_t n)
360 {
361         LEDColor color;
362
363         uint32_t absolute_strip_num = (n + bank_start) % 8;
364
365         if (stripable[n]) {
366                 switch (absolute_strip_num) {
367                         case 0:
368                         case 4:
369                                 if (stripable[n]->is_selected()) {
370                                         color = RedFull;
371                                 } else {
372                                         color = RedLow;
373                                 }
374                                 break;
375
376                         case 1:
377                         case 5:
378                                 if (stripable[n]->is_selected()) {
379                                         color = YellowFull;
380                                 } else {
381                                         color = YellowLow;
382                                 }
383                                 break;
384
385                         case 2:
386                         case 6:
387                                 if (stripable[n]->is_selected()) {
388                                         color = GreenFull;
389                                 } else {
390                                         color = GreenLow;
391                                 }
392                                 break;
393
394                         case 3:
395                         case 7:
396                                 if (stripable[n]->is_master()) {
397                                         color = RedFull;
398                                 } else {
399                                         if (stripable[n]->is_selected()) {
400                                                 color = AmberFull;
401                                         } else {
402                                                 color = AmberLow;
403                                         }
404                                 }
405                 }
406         }
407
408         boost::shared_ptr<Knob> knobs_col[3];
409         knobs_by_column(n, knobs_col);
410
411         for  (uint8_t s = 0; s < 3; ++s)
412         {
413                 if (stripable[n]) {
414                         knobs_col[s]->set_color(color);
415                 } else {
416                         knobs_col[s]->set_color(Off);
417                 }
418                 write (knobs_col[s]->state_msg());
419         }
420 }
421
422 void
423 LaunchControlXL::update_track_control_led(uint8_t n)
424 {
425         boost::shared_ptr<TrackButton> b = control_button_by_column(n);
426
427         if (!b) {
428                 return;
429         }
430
431         if (stripable[n]) {
432                 boost::shared_ptr<AutomationControl> ac = get_ac_by_state(n);
433
434                 switch(track_mode()) {
435                         case TrackMute:
436                                 if (ac->get_value()) {
437                                         b->set_color(YellowFull);
438                                 } else {
439                                         b->set_color(AmberLow);
440                                 }
441                                 break;
442                         case TrackSolo:
443                                 if (ac && !(stripable[n]->is_master())) {
444                                         if (ac->get_value()) {
445                                                 b->set_color(GreenFull);
446                                         } else {
447                                                 b->set_color(GreenLow);
448                                         }
449                                 } else {
450                                         b->set_color(Off);
451                                 }
452                                 break;
453                         case TrackRecord:
454                                 if (ac) {
455                                         if (ac->get_value()) {
456                                                 b->set_color(RedFull);
457                                         } else {
458                                                 b->set_color(RedLow);
459                                         }
460                                 } else {
461                                         b->set_color(Off);
462                                 }
463                                 break;
464
465                         default:
466                         break;
467                 }
468         } else {
469                 b->set_color(Off);
470         }
471
472         write (b->state_msg());
473 }
474
475 void
476 LaunchControlXL::solo_mute_rec_changed(uint32_t n) {
477         if (!stripable[n]) {
478                 return;
479         }
480         update_track_control_led(n);
481 }
482
483 void
484 LaunchControlXL::solo_iso_changed(uint32_t n)
485 {
486         if (!stripable[n]) {
487                 return;
488         } else {
489                 solo_iso_led_bank();
490         }
491 }
492
493 void
494 LaunchControlXL::solo_iso_led_bank ()
495 {
496         int stripable_counter = get_amount_of_tracks();
497
498         if (!(buttons_down.find(Device) != buttons_down.end())) {
499                 return;
500         } else {
501                 for (int n = 0; n < stripable_counter; ++n) {
502                         boost::shared_ptr<TrackButton> b = focus_button_by_column(n);
503                         if (stripable[n] && stripable[n]->solo_isolate_control()) {
504                                 if (stripable[n]->solo_isolate_control()->get_value()) {
505                                         b->set_color(RedFull);
506                                 } else {
507                                         b->set_color(Off);
508                                 }
509                                 write (b->state_msg());
510                         }
511                 }
512                 LaunchControlXL::set_refresh_leds_flag(true);
513         }
514 }
515
516 #ifdef MIXBUS
517 void
518 LaunchControlXL::master_send_changed(uint32_t n)
519 {
520         if (!stripable[n]) {
521                 return;
522         } else {
523                 master_send_led_bank();
524         }
525
526 }
527
528 void
529 LaunchControlXL::master_send_led_bank ()
530 {
531         if (!(buttons_down.find(Device) != buttons_down.end())) {
532                 return;
533         } else {
534                 int stripable_counter = LaunchControlXL::get_amount_of_tracks();
535
536                 for (int n = 0; n < stripable_counter; ++n) {
537                         boost::shared_ptr<TrackButton> b = control_button_by_column(n);
538                         if (stripable[n] && stripable[n]->master_send_enable_controllable()) {
539                                 if (stripable[n]->master_send_enable_controllable()->get_value()) {
540                                         b->set_color(GreenFull);
541                                 } else {
542                                         b->set_color(Off);
543                                 }
544                         }
545                         write (b->state_msg());
546                 }
547                 LaunchControlXL::set_refresh_leds_flag(true);
548         }
549 }
550 # endif
551
552 void
553 LaunchControlXL::button_track_control(uint8_t n) {
554         if (!stripable[n]) {
555                 return;
556         }
557
558         if (buttons_down.find(Device) != buttons_down.end()) {
559                 DEBUG_TRACE (DEBUG::LaunchControlXL, "DEVICE BUTTON HOLD\n");
560 #ifdef MIXBUS
561                 if (stripable[n]->master_send_enable_controllable()) {
562                         bool master_send_active = stripable[n]->master_send_enable_controllable()->get_value();
563
564                         DEBUG_TRACE (DEBUG::LaunchControlXL, "MIXBUS Master Assign\n");
565                         stripable[n]->master_send_enable_controllable()->set_value (!master_send_active, PBD::Controllable::UseGroup);
566                 }
567
568 #else
569                 /* something useful for Ardour */
570 #endif
571                 return;
572         }
573
574         boost::shared_ptr<AutomationControl> ac = get_ac_by_state(n);
575
576         if (ac) {
577                 session->set_control (ac, !ac->get_value(), PBD::Controllable::UseGroup);
578         }
579 }
580
581 void
582 LaunchControlXL::button_track_mode(TrackMode state)
583 {
584                 set_track_mode(state);
585                 for (uint8_t n = 0; n < 8; ++n) {
586                         update_track_control_led(n);
587                 }
588
589                 boost::shared_ptr<TrackStateButton> mute = boost::dynamic_pointer_cast<TrackStateButton> (id_note_button_map[Mute]);
590                 boost::shared_ptr<TrackStateButton> solo = boost::dynamic_pointer_cast<TrackStateButton> (id_note_button_map[Solo]);
591                 boost::shared_ptr<TrackStateButton> record = boost::dynamic_pointer_cast<TrackStateButton> (id_note_button_map[Record]);
592
593                 write(mute->state_msg((state == TrackMute)));
594                 write(solo->state_msg((state == TrackSolo)));
595                 write(record->state_msg((state == TrackRecord)));
596 }
597
598 void
599 LaunchControlXL::button_select_left()
600 {
601         switch_bank (max (0, bank_start - (7 + (fader8master() ? 0 : 1))));
602 }
603
604 void
605 LaunchControlXL::button_select_right()
606 {
607         switch_bank (max (0, bank_start + 7 + (fader8master() ? 0 : 1)));
608 }
609
610 void
611 LaunchControlXL::button_select_up()
612 {
613
614 }
615
616 void
617 LaunchControlXL::button_select_down()
618 {
619
620 }
621
622 void
623 LaunchControlXL::button_device()
624 {
625
626 }
627
628 void
629 LaunchControlXL::button_device_long_press()
630 {
631         solo_iso_led_bank();
632 #ifdef MIXBUS
633         master_send_led_bank();
634 #endif
635 }
636
637 void
638 LaunchControlXL::button_mute()
639 {
640         if (buttons_down.find(Device) != buttons_down.end()) {
641                 access_action ("Editor/track-mute-toggle");
642         } else {
643                 button_track_mode(TrackMute);
644         }
645 }
646
647 void
648 LaunchControlXL::button_solo()
649 {
650         if (buttons_down.find(Device) != buttons_down.end()) {
651                 access_action ("Editor/track-solo-toggle");
652         } else {
653                 button_track_mode(TrackSolo);
654         }
655 }
656
657 void
658 LaunchControlXL::button_record()
659 {
660         if (buttons_down.find(Device) != buttons_down.end()) {
661                 access_action ("Editor/track-record-enable-toggle");
662         } else {
663                 button_track_mode(TrackRecord);
664         }
665 }
666
667 bool
668 LaunchControlXL::button_long_press_timeout (ButtonID id, boost::shared_ptr<Button> button)
669 {
670         if (buttons_down.find (id) != buttons_down.end()) {
671                 DEBUG_TRACE (DEBUG::LaunchControlXL, string_compose ("long press timeout for %1, invoking method\n", id));
672                 (this->*button->long_press_method) ();
673         } else {
674                 DEBUG_TRACE (DEBUG::LaunchControlXL, string_compose ("long press timeout for %1, expired/cancelled\n", id));
675                 /* release happened and somehow we were not cancelled */
676         }
677
678         /* whichever button this was, we've used it ... don't invoke the
679            release action.
680         */
681         consumed.insert (id);
682
683         return false; /* don't get called again */
684 }
685
686
687 void
688 LaunchControlXL::start_press_timeout (boost::shared_ptr<Button> button, ButtonID id)
689 {
690         Glib::RefPtr<Glib::TimeoutSource> timeout = Glib::TimeoutSource::create (500); // milliseconds
691         button->timeout_connection = timeout->connect (sigc::bind (sigc::mem_fun (*this, &LaunchControlXL::button_long_press_timeout), id, button));
692         timeout->attach (main_loop()->get_context());
693 }