LCXL: split track focus button and led code
[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         Knob* knob;
40
41         #define MAKE_KNOB(i,cc, index, color) \
42                 knob = new Knob ((i), (cc), (index), (color), (*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, RedFull);
48                         MAKE_KNOB (static_cast<KnobID>(n + 8), (n + 29), (n + 8), GreenFull);
49                         MAKE_KNOB (static_cast<KnobID>(n + 16), (n + 49), (n + 16), Yellow);
50                 }
51
52         /* Faders */
53
54         Fader* fader;
55
56         #define MAKE_FADER(i,cc) \
57                 fader = 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         ControllerButton *controller_button;
68         NoteButton *note_button;
69
70
71         #define MAKE_TRACK_BUTTON_PRESS(i,nn,index,color,p) \
72                 note_button = 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 = 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 = 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 = 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, GreenFull, &LaunchControlXL::button_track_focus_1);
90         MAKE_TRACK_BUTTON_PRESS(Focus2, 42, 25, GreenFull, &LaunchControlXL::button_track_focus_2);
91         MAKE_TRACK_BUTTON_PRESS(Focus3, 43, 26, GreenFull, &LaunchControlXL::button_track_focus_3);
92         MAKE_TRACK_BUTTON_PRESS(Focus4, 44, 27, GreenFull, &LaunchControlXL::button_track_focus_4);
93         MAKE_TRACK_BUTTON_PRESS(Focus5, 57, 28, GreenFull, &LaunchControlXL::button_track_focus_5);
94         MAKE_TRACK_BUTTON_PRESS(Focus6, 58, 29, GreenFull, &LaunchControlXL::button_track_focus_6);
95         MAKE_TRACK_BUTTON_PRESS(Focus7, 59, 30, GreenFull, &LaunchControlXL::button_track_focus_7);
96         MAKE_TRACK_BUTTON_PRESS(Focus8, 60, 31, GreenFull, &LaunchControlXL::button_track_focus_8);
97         MAKE_TRACK_BUTTON_PRESS(Control1, 73, 32, Yellow, &LaunchControlXL::button_track_control_1);
98         MAKE_TRACK_BUTTON_PRESS(Control2, 74, 33, Yellow, &LaunchControlXL::button_track_control_2);
99         MAKE_TRACK_BUTTON_PRESS(Control3, 75, 34, Yellow, &LaunchControlXL::button_track_control_3);
100         MAKE_TRACK_BUTTON_PRESS(Control4, 76, 35, Yellow, &LaunchControlXL::button_track_control_4);
101         MAKE_TRACK_BUTTON_PRESS(Control5, 89, 36, Yellow, &LaunchControlXL::button_track_control_5);
102         MAKE_TRACK_BUTTON_PRESS(Control6, 90, 37, Yellow, &LaunchControlXL::button_track_control_6);
103         MAKE_TRACK_BUTTON_PRESS(Control7, 91, 38, Yellow, &LaunchControlXL::button_track_control_7);
104         MAKE_TRACK_BUTTON_PRESS(Control8, 92, 39, Yellow, &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 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         TrackButton* button = 0;
274
275         if (b != nn_note_button_map.end()) {
276                 button = static_cast<TrackButton*>(b->second);
277         }
278
279         return button;
280
281 }
282
283 void
284 LaunchControlXL::update_track_focus_led(uint8_t n)
285 {
286         TrackButton* b = focus_button_by_collumn(n);
287
288         if (!b) {
289                 return;
290         }
291
292         if (stripable[n]) {
293                 if ( stripable[n]->is_selected() ) {
294                         b->set_color(AmberFull);
295                 } else {
296                         b->set_color(AmberLow);
297                 }
298         } else {
299                 b->set_color(Off);
300         }
301
302         write (b->state_msg());
303 }
304
305 void
306 LaunchControlXL::button_track_focus(uint8_t n)
307 {
308         if (stripable[n]) {
309                 if ( stripable[n]->is_selected() ) {
310                          ControlProtocol::RemoveStripableFromSelection (stripable[n]);
311                 } else {
312                         ControlProtocol::AddStripableToSelection (stripable[n]);
313                 }
314         } else {
315                 return;
316         }
317 }
318
319
320
321 boost::shared_ptr<AutomationControl>
322 LaunchControlXL::get_ac_by_state(uint8_t n) {
323                 boost::shared_ptr<AutomationControl> ac;
324
325                 switch(track_mode()) {
326                         case TrackMute:
327                                 ac = stripable[n]->mute_control();
328                                 break;
329
330                         case TrackSolo:
331                                 ac = stripable[n]->solo_control();
332                                 break;
333
334                         case TrackRecord:
335                                 ac = stripable[n]->rec_enable_control();
336                                 break;
337
338                         default:
339                         break;
340                 }
341                 return ac;
342 }
343
344
345 void
346 LaunchControlXL::update_track_control_led(uint8_t n)
347 {
348         TrackButton* b = control_button_by_collumn(n);
349
350         if (!b) {
351                 return;
352         }
353
354         if (stripable[n]) {
355                 boost::shared_ptr<AutomationControl> ac = get_ac_by_state(n);
356
357                 switch(track_mode()) {
358                         case TrackMute:
359                                 if (ac->get_value()) {
360                                         b->set_color(AmberFull);
361                                 } else {
362                                         b->set_color(AmberLow);
363                                 }
364                                 break;
365                         case TrackSolo:
366                                 if (ac && stripable[n] != master ) {
367                                         if (ac->get_value()) {
368                                                 b->set_color(GreenFull);
369                                         } else {
370                                                 b->set_color(GreenLow);
371                                         }
372                                 } else {
373                                         b->set_color(Off);
374                                 }
375                                 break;
376                         case TrackRecord:
377                                 if (ac) {
378                                         if (ac->get_value()) {
379                                                 b->set_color(RedFull);
380                                         } else {
381                                                 b->set_color(RedLow);
382                                         }
383                                 } else {
384                                         b->set_color(Off);
385                                 }
386                                 break;
387
388                         default:
389                         break;
390                 }
391         } else {
392                 b->set_color(Off);
393         }
394
395         write (b->state_msg());
396 }
397
398 void
399 LaunchControlXL::solo_mute_rec_changed(uint32_t n) {
400         if (!stripable[n]) {
401                 return;
402         }
403         update_track_control_led(n);
404 }
405
406 void
407 LaunchControlXL::button_track_control(uint8_t n) {
408         if (!stripable[n]) {
409                 return;
410         }
411         boost::shared_ptr<AutomationControl> ac = get_ac_by_state(n);
412
413         if (ac) {
414                 session->set_control (ac, !ac->get_value(), PBD::Controllable::UseGroup);
415         }
416 }
417
418 void
419 LaunchControlXL::button_track_mode(TrackMode state)
420 {
421                 set_track_mode(state);
422                 for (uint8_t n = 0; n < 8; ++n) {
423                         update_track_control_led(n);
424                 }
425
426                 TrackStateButton* mute = static_cast<TrackStateButton*>(id_note_button_map[Mute]);
427                 TrackStateButton* solo = static_cast<TrackStateButton*>(id_note_button_map[Solo]);
428                 TrackStateButton* record = static_cast<TrackStateButton*>(id_note_button_map[Record]);
429
430                 write(mute->state_msg((state == TrackMute)));
431                 write(solo->state_msg((state == TrackSolo)));
432                 write(record->state_msg((state == TrackRecord)));
433 }
434
435 void
436 LaunchControlXL::button_select_left()
437 {
438         switch_bank (max (0, bank_start - 1));
439 }
440
441 void
442 LaunchControlXL::button_select_right()
443 {
444         switch_bank (max (0, bank_start + 1));
445 }
446
447 void
448 LaunchControlXL::button_select_up()
449 {
450
451 }
452
453 void
454 LaunchControlXL::button_select_down()
455 {
456
457 }
458
459 void
460 LaunchControlXL::button_device()
461 {
462
463 }
464
465 void
466 LaunchControlXL::button_device_long_press()
467 {
468
469 }
470
471 void
472 LaunchControlXL::button_mute()
473 {
474         if (buttons_down.find(Device) != buttons_down.end()) {
475                 access_action ("Editor/track-mute-toggle");
476         } else {
477                 button_track_mode(TrackMute);
478         }
479 }
480
481 void
482 LaunchControlXL::button_solo()
483 {
484         if (buttons_down.find(Device) != buttons_down.end()) {
485                 access_action ("Editor/track-solo-toggle");
486         } else {
487                 button_track_mode(TrackSolo);
488         }
489 }
490
491 void
492 LaunchControlXL::button_record()
493 {
494         if (buttons_down.find(Device) != buttons_down.end()) {
495                 access_action ("Editor/track-record-enable-toggle");
496         } else {
497                 button_track_mode(TrackRecord);
498         }
499 }
500
501 bool
502 LaunchControlXL::button_long_press_timeout (ButtonID id, Button* button)
503 {
504         if (buttons_down.find (id) != buttons_down.end()) {
505                 DEBUG_TRACE (DEBUG::LaunchControlXL, string_compose ("long press timeout for %1, invoking method\n", id));
506                 (this->*button->long_press_method) ();
507         } else {
508                 DEBUG_TRACE (DEBUG::LaunchControlXL, string_compose ("long press timeout for %1, expired/cancelled\n", id));
509                 /* release happened and somehow we were not cancelled */
510         }
511
512         /* whichever button this was, we've used it ... don't invoke the
513            release action.
514         */
515         consumed.insert (id);
516
517         return false; /* don't get called again */
518 }
519
520
521 void
522 LaunchControlXL::start_press_timeout (Button* button, ButtonID id)
523 {
524         Glib::RefPtr<Glib::TimeoutSource> timeout = Glib::TimeoutSource::create (500); // milliseconds
525         button->timeout_connection = timeout->connect (sigc::bind (sigc::mem_fun (*this, &LaunchControlXL::button_long_press_timeout), id, button));
526         timeout->attach (main_loop()->get_context());
527 }