Only show user-presets in favorite sidebar
[ardour.git] / libs / surfaces / faderport8 / fp8_controls.cc
1 /* Faderport 8 Control Surface
2  * Abstraction of Surface Control Elements.
3  *
4  * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20
21 #include "fp8_controls.h"
22
23 using namespace ArdourSurface::FP_NAMESPACE;
24 using namespace ArdourSurface::FP_NAMESPACE::FP8Types;
25
26 bool FP8ButtonInterface::force_change = false;
27
28 #define NEWBUTTON(midi_id, button_id, color)            \
29   do {                                                  \
30   assert (_midimap.end() == _midimap.find (midi_id));   \
31   assert (_ctrlmap.end() == _ctrlmap.find (button_id)); \
32   FP8Button *t = new FP8Button (b, midi_id);            \
33   _midimap[midi_id] = t;                                \
34   _ctrlmap[button_id] = t;                              \
35   } while (0)
36
37
38 #define NEWTYPEBUTTON(TYPE, midi_id, button_id, color)  \
39   do {                                                  \
40   assert (_midimap.end() == _midimap.find (midi_id));   \
41   assert (_ctrlmap.end() == _ctrlmap.find (button_id)); \
42   TYPE *t = new TYPE (b, midi_id);                      \
43   _midimap[midi_id] = t;                                \
44   _ctrlmap[button_id] = t;                              \
45   } while (0)
46
47
48
49 #define NEWSHIFTBUTTON(midi_id, id1, id2, color)        \
50   do {                                                  \
51   assert (_midimap.end() == _midimap.find (midi_id));   \
52   assert (_ctrlmap.end() == _ctrlmap.find (id1));       \
53   assert (_ctrlmap.end() == _ctrlmap.find (id2));       \
54   FP8ShiftSensitiveButton *t =                          \
55     new FP8ShiftSensitiveButton (b, midi_id, color);    \
56   _midimap[midi_id] = t;                                \
57   _ctrlmap[id1] = t->button ();                         \
58   _ctrlmap[id2] = t->button_shift ();                   \
59   } while (0)
60
61
62 FP8Controls::FP8Controls (FP8Base& b)
63         : _fadermode (ModeTrack)
64 #ifdef FADERPORT2
65         , _navmode (NavScroll)
66 #else
67         , _navmode (NavMaster)
68 #endif
69         , _mixmode (MixAll)
70         , _display_timecode (false)
71 {
72         NEWBUTTON (0x56, BtnLoop, false);
73         NEWTYPEBUTTON (FP8RepeatButton, 0x5b, BtnRewind, false);
74         NEWTYPEBUTTON (FP8RepeatButton, 0x5c, BtnFastForward, false);
75         NEWBUTTON (0x5d, BtnStop, false);
76         NEWBUTTON (0x5e, BtnPlay, false);
77         NEWBUTTON (0x5f, BtnRecord, false);
78
79 #ifdef FADERPORT2
80
81         NEWSHIFTBUTTON (0x4a, BtnARead, BtnAOff, true);
82         NEWSHIFTBUTTON (0x4b, BtnAWrite, BtnATrim, true);
83         NEWSHIFTBUTTON (0x4d, BtnATouch, BtnALatch, true);
84
85         NEWSHIFTBUTTON (0x2e, BtnPrev, BtnUndo, false);
86         NEWSHIFTBUTTON (0x2f, BtnNext, BtnRedo, false);
87
88         NEWSHIFTBUTTON (0x2a, BtnPan, BtnFlip, true);  //TODO: Flip Pan knob to fader ...?
89
90         NEWSHIFTBUTTON (0x36, BtnChannel, BtnChanLock, true);
91
92         NEWSHIFTBUTTON (0x38, BtnScroll,  BtnZoom, true);
93
94         NEWSHIFTBUTTON (0x3a, BtnMaster,  BtnF1, false);
95         NEWSHIFTBUTTON (0x3b, BtnClick,   BtnF2, false);
96         NEWSHIFTBUTTON (0x3c, BtnSection, BtnF3, false);
97         NEWSHIFTBUTTON (0x3d, BtnMarker,  BtnF4, false);
98
99         //these buttons do not exist in FP2, but they need to exist in the ctrlmap:
100         NEWBUTTON (0x71, BtnBank, false);
101         NEWBUTTON (0x72, BtnF5, false);
102         NEWBUTTON (0x73, BtnF6, false);
103         NEWBUTTON (0x74, BtnF7, false);
104         NEWBUTTON (0x75, BtnF8, false);
105         NEWBUTTON (0x76, BtnUser1, false);
106         NEWBUTTON (0x77, BtnUser2, false);
107         NEWBUTTON (0x78, BtnUser3, false);
108         NEWBUTTON (0x79, BtnSave, false);
109
110 #else
111         NEWSHIFTBUTTON (0x4a, BtnARead, BtnUser3, true);
112         NEWSHIFTBUTTON (0x4b, BtnAWrite, BtnUser2, true);
113         NEWSHIFTBUTTON (0x4c, BtnATrim, BtnRedo, true);
114         NEWSHIFTBUTTON (0x4d, BtnATouch, BtnUser1, true);
115         NEWSHIFTBUTTON (0x4e, BtnALatch, BtnSave, true);
116         NEWSHIFTBUTTON (0x4f, BtnAOff, BtnUndo, true);
117
118         NEWBUTTON (0x2e, BtnPrev, false);
119         NEWBUTTON (0x2f, BtnNext, false);
120
121         NEWSHIFTBUTTON (0x36, BtnChannel, BtnF1, false);
122         NEWSHIFTBUTTON (0x37, BtnZoom,    BtnF2, false);
123         NEWSHIFTBUTTON (0x38, BtnScroll,  BtnF3, false);
124         NEWSHIFTBUTTON (0x39, BtnBank,    BtnF4, false);
125         NEWSHIFTBUTTON (0x3a, BtnMaster,  BtnF5, false);
126         NEWSHIFTBUTTON (0x3b, BtnClick,   BtnF6, false);
127         NEWSHIFTBUTTON (0x3c, BtnSection, BtnF7, false);
128         NEWSHIFTBUTTON (0x3d, BtnMarker,  BtnF8, false);
129
130         NEWBUTTON (0x2a, BtnPan, false);
131 #endif
132
133         NEWSHIFTBUTTON (0x28, BtnTrack, BtnTimecode, false);
134         NEWBUTTON (0x2b, BtnPlugins, false);
135         NEWBUTTON (0x29, BtnSend, false);
136
137         NEWSHIFTBUTTON (0x00, BtnArm, BtnArmAll, false);
138         NEWBUTTON (0x01, BtnSoloClear, false);
139         NEWBUTTON (0x02, BtnMuteClear, false);
140
141         NEWSHIFTBUTTON (0x03, BtnBypass, BtnBypassAll, true);
142         NEWSHIFTBUTTON (0x04, BtnMacro, BtnOpen, true);
143         NEWSHIFTBUTTON (0x05, BtnLink, BtnLock, true);
144
145         NEWSHIFTBUTTON (0x3e, BtnMAudio, BtnMInputs, true);
146         NEWSHIFTBUTTON (0x3f, BtnMVI, BtnMMIDI, true);
147         NEWSHIFTBUTTON (0x40, BtnMBus, BtnMOutputs, true);
148         NEWSHIFTBUTTON (0x41, BtnMVCA, BtnMFX, true);
149         NEWSHIFTBUTTON (0x42, BtnMAll, BtnMUser, true);
150
151         NEWTYPEBUTTON (FP8ReadOnlyButton, 0x53, BtnEncoder, false);
152         NEWTYPEBUTTON (FP8ReadOnlyButton, 0x20, BtnParam, false);
153         NEWTYPEBUTTON (FP8ReadOnlyButton, 0x66, BtnFootswitch, false);
154
155         /* internal bindings */
156
157 #define BindMethod(ID, CB) \
158         button (ID).released.connect_same_thread (button_connections, boost::bind (&FP8Controls:: CB, this));
159
160         BindMethod (FP8Controls::BtnTimecode, toggle_timecode);
161
162 #define BindNav(BTN, MODE)\
163         button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_nav_mode, this, MODE))
164
165         BindNav (BtnChannel, NavChannel);
166         BindNav (BtnZoom,    NavZoom);
167         BindNav (BtnScroll,  NavScroll);
168         BindNav (BtnBank,    NavBank);
169         BindNav (BtnMaster,  NavMaster);
170         BindNav (BtnSection, NavSection);
171         BindNav (BtnMarker,  NavMarker);
172 #ifdef FADERPORT2
173         BindNav (BtnPan,     NavPan);
174 #endif
175
176 #define BindFader(BTN, MODE)\
177         button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_fader_mode, this, MODE))
178
179         BindFader (BtnTrack,   ModeTrack);
180         BindFader (BtnPlugins, ModePlugins);
181         BindFader (BtnSend,    ModeSend);
182 #ifndef FADERPORT2
183         BindFader (BtnPan,     ModePan);
184 #endif
185
186
187 #define BindMix(BTN, MODE)\
188         button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_mix_mode, this, MODE))
189
190         BindMix (BtnMAudio,   MixAudio);
191         BindMix (BtnMVI,      MixInstrument);
192         BindMix (BtnMBus,     MixBus);
193         BindMix (BtnMVCA,     MixVCA);
194         BindMix (BtnMAll,     MixAll);
195         BindMix (BtnMInputs,  MixInputs);
196         BindMix (BtnMMIDI,    MixMIDI);
197         BindMix (BtnMOutputs, MixOutputs);
198         BindMix (BtnMFX,      MixFX);
199         BindMix (BtnMUser,    MixUser);
200
201         /* create channelstrips */
202         for (uint8_t id = 0; id < N_STRIPS; ++id) {
203                 chanstrip[id] = new FP8Strip (b, id);
204                 _midimap_strip[FP8Strip::midi_ctrl_id (FP8Strip::BtnSolo, id)] = &(chanstrip[id]->solo_button());
205                 _midimap_strip[FP8Strip::midi_ctrl_id (FP8Strip::BtnMute, id)] = &(chanstrip[id]->mute_button());
206                 _midimap_strip[FP8Strip::midi_ctrl_id (FP8Strip::BtnSelect, id)] = &(chanstrip[id]->selrec_button());
207         }
208
209         /* set User button names */
210
211 #define REGISTER_ENUM(ID, NAME) \
212         _user_str_to_enum[#ID] = ID; \
213         _user_enum_to_str[ID]  = #ID; \
214         _user_buttons[ID]      = NAME;
215
216 #ifdef FADERPORT2
217         REGISTER_ENUM (BtnF1        , "F1");
218         REGISTER_ENUM (BtnF2        , "F2");
219         REGISTER_ENUM (BtnF3        , "F3");
220         REGISTER_ENUM (BtnF4        , "F4");
221         REGISTER_ENUM (BtnFootswitch, "Footswitch");
222 #else
223         REGISTER_ENUM (BtnFootswitch, "Footswitch");
224         REGISTER_ENUM (BtnUser1     , "User 1");
225         REGISTER_ENUM (BtnUser2     , "User 2");
226         REGISTER_ENUM (BtnUser3     , "User 3");
227         REGISTER_ENUM (BtnF1        , "F1");
228         REGISTER_ENUM (BtnF2        , "F2");
229         REGISTER_ENUM (BtnF3        , "F3");
230         REGISTER_ENUM (BtnF4        , "F4");
231         REGISTER_ENUM (BtnF5        , "F5");
232         REGISTER_ENUM (BtnF6        , "F6");
233         REGISTER_ENUM (BtnF7        , "F7");
234         REGISTER_ENUM (BtnF8        , "F8");
235 #endif
236
237 #undef REGISTER_ENUM
238 }
239
240 FP8Controls::~FP8Controls ()
241 {
242         for (MidiButtonMap::const_iterator i = _midimap.begin (); i != _midimap.end (); ++i) {
243                 delete i->second;
244         }
245         for (uint8_t id = 0; id < N_STRIPS; ++id) {
246                 delete chanstrip[id];
247         }
248         _midimap_strip.clear ();
249         _ctrlmap.clear ();
250         _midimap.clear ();
251 }
252
253 bool
254 FP8Controls::button_name_to_enum (std::string const& n, ButtonId& id) const
255 {
256         std::map<std::string, ButtonId>::const_iterator i = _user_str_to_enum.find (n);
257         if (i == _user_str_to_enum.end()) {
258                 return false;
259         }
260         id = i->second;
261         return true;
262 }
263
264 bool
265 FP8Controls::button_enum_to_name (ButtonId id, std::string& n) const
266 {
267         std::map<ButtonId, std::string>::const_iterator i = _user_enum_to_str.find (id);
268         if (i == _user_enum_to_str.end()) {
269                 return false;
270         }
271         n = i->second;
272         return true;
273 }
274
275 void
276 FP8Controls::initialize ()
277 {
278         FP8ButtonInterface::force_change = true;
279         /* set RGB colors */
280         button (BtnUndo).set_color (0x00ff00ff);
281         button (BtnRedo).set_color (0x00ff00ff);
282
283         button (BtnAOff).set_color (0xffffffff);
284         button (BtnATrim).set_color (0x000030ff);
285         button (BtnARead).set_color (0x00ff00ff);
286         button (BtnAWrite).set_color (0xff0000ff);
287         button (BtnATouch).set_color (0xff8800ff);
288         button (BtnALatch).set_color (0xffff00ff);
289
290         button (BtnUser1).set_color (0x0000ffff);
291         button (BtnUser2).set_color (0x0000ffff);
292         button (BtnUser3).set_color (0x0000ffff);
293
294         button (BtnBypass).set_color (0x888888ff);
295         button (BtnBypassAll).set_color (0xffffffff);
296
297         button (BtnMacro).set_color (0x888888ff);
298         button (BtnOpen).set_color (0xffffffff);
299
300         button (BtnLink).set_color (0x888888ff);
301         button (BtnLock).set_color (0xffffffff);
302
303         button (BtnMAudio).set_color (0x0000ffff);
304         button (BtnMVI).set_color (0x0000ffff);
305         button (BtnMBus).set_color (0x0000ffff);
306         button (BtnMVCA).set_color (0x0000ffff);
307         button (BtnMAll).set_color (0x0000ffff);
308
309         button (BtnMInputs).set_color (0x0000ffff);
310         button (BtnMMIDI).set_color (0x0000ffff);
311         button (BtnMOutputs).set_color (0x0000ffff);
312         button (BtnMFX).set_color (0x0000ffff);
313         button (BtnMUser).set_color (0x0000ffff);
314
315 #ifdef FADERPORT2
316         /* encoder mode-switches are orange, to match the Master switch physical color */
317         button (BtnLink).set_color (0x000000ff);
318         button (BtnChannel).set_color (0x0000ffff);
319         button (BtnScroll).set_color (0x0000ffff);
320         button (BtnPan).set_color (0xffffffff);
321 #endif
322
323         for (uint8_t id = 0; id < N_STRIPS; ++id) {
324                 chanstrip[id]->initialize ();
325         }
326
327         /* initally turn all lights off */
328         all_lights_off ();
329
330         /* default modes */
331 #ifdef FADERPORT2
332         button (BtnScroll).set_active (true);
333 #else
334         button (BtnMaster).set_active (true);
335 #endif
336         button (BtnTrack).set_active (true);
337         button (BtnMAll).set_active (true);
338         button (BtnTimecode).set_active (_display_timecode);
339
340         FP8ButtonInterface::force_change = false;
341 }
342
343 void
344 FP8Controls::all_lights_off () const
345 {
346         for (CtrlButtonMap::const_iterator i = _ctrlmap.begin (); i != _ctrlmap.end (); ++i) {
347                 i->second->set_active (false);
348         }
349 }
350
351 FP8ButtonInterface&
352 FP8Controls::button (ButtonId id)
353 {
354         CtrlButtonMap::const_iterator i = _ctrlmap.find (id);
355         if (i == _ctrlmap.end()) {
356                 assert (0);
357                 return _dummy_button;
358         }
359         return *(i->second);
360 }
361
362 FP8Strip&
363 FP8Controls::strip (uint8_t id)
364 {
365         assert (id < N_STRIPS);
366         return *chanstrip[id];
367 }
368
369 /* *****************************************************************************
370  * Delegate MIDI events
371  */
372
373 bool
374 FP8Controls::midi_event (uint8_t id, uint8_t val)
375 {
376         MidiButtonMap::const_iterator i;
377
378         i = _midimap_strip.find (id);
379         if (i != _midimap_strip.end()) {
380                 return i->second->midi_event (val > 0x40);
381         }
382
383         i = _midimap.find (id);
384         if (i != _midimap.end()) {
385                 return i->second->midi_event (val > 0x40);
386         }
387         return false;
388 }
389
390 bool
391 FP8Controls::midi_touch (uint8_t id, uint8_t val)
392 {
393         assert (id < N_STRIPS);
394         return chanstrip[id]->midi_touch (val > 0x40);
395 }
396
397 bool
398 FP8Controls::midi_fader (uint8_t id, unsigned short val)
399 {
400         assert (id < N_STRIPS);
401         return chanstrip[id]->midi_fader ((val >> 4) / 1023.f);
402 }
403
404 /* *****************************************************************************
405  * Internal Model + View for Modes
406  */
407
408 void
409 FP8Controls::set_nav_mode (NavigationMode m)
410 {
411         if (_navmode == m) {
412                 return;
413         }
414         // TODO add special-cases:
415         // - master/monitor (blink when button is held + monitor section present)
416         // - "click" hold -> encoder sets click volume, encoder-press toggle rec-only-metro
417         button (BtnChannel).set_active (m == NavChannel);
418         button (BtnZoom).set_active (m == NavZoom);
419         button (BtnScroll).set_active (m == NavScroll);
420         button (BtnBank).set_active (m == NavBank);
421         button (BtnMaster).set_active (m == NavMaster);
422         button (BtnSection).set_active (m == NavSection);
423         button (BtnMarker).set_active (m == NavMarker);
424 #ifdef FADERPORT2
425         button (BtnPan).set_active (m == NavPan);
426 #endif
427         _navmode = m;
428 }
429
430 void
431 FP8Controls::set_fader_mode (FaderMode m)
432 {
433         if (_fadermode == m) {
434                 if (m == ModePlugins || m == ModeSend) {
435                         /* "Edit Plugins" while editing Plugin-params, returns back
436                          * to plugin selection.
437                          * "Sends" button banks through sends.
438                          */
439                         FaderModeChanged ();
440                 }
441                 return;
442         }
443         // set lights
444         button (BtnTrack).set_active (m == ModeTrack);
445         button (BtnPlugins).set_active (m == ModePlugins);
446         button (BtnSend).set_active (m == ModeSend);
447         button (BtnPan).set_active (m == ModePan);
448         _fadermode = m;
449         FaderModeChanged ();
450 }
451
452 void
453 FP8Controls::set_mix_mode (MixMode m)
454 {
455         if (_mixmode == m) {
456                 if (m == MixUser || m == MixInputs) {
457                         /* always re-assign:
458                          *  - MixUser: depends on selection
459                          *  - MixInputs: depends on rec-arm
460                          */
461                         MixModeChanged ();
462                 }
463                 return;
464         }
465         button (BtnMAudio).set_active (m == MixAudio);
466         button (BtnMVI).set_active (m == MixInstrument);
467         button (BtnMBus).set_active (m == MixBus);
468         button (BtnMVCA).set_active (m == MixVCA);
469         button (BtnMAll).set_active (m == MixAll);
470         button (BtnMInputs).set_active (m == MixInputs);
471         button (BtnMMIDI).set_active (m == MixMIDI);
472         button (BtnMOutputs).set_active (m == MixOutputs);
473         button (BtnMFX).set_active (m == MixFX);
474         button (BtnMUser).set_active (m == MixUser);
475
476         _mixmode = m;
477         MixModeChanged ();
478 }
479
480 void
481 FP8Controls::toggle_timecode ()
482 {
483         _display_timecode = !_display_timecode;
484         button (BtnTimecode).set_active (_display_timecode);
485 }