2 * Copyright (C) 2017-2018 Robin Gareus <robin@gareus.org>
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.
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.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "fp8_controls.h"
21 using namespace ArdourSurface::FP_NAMESPACE;
22 using namespace ArdourSurface::FP_NAMESPACE::FP8Types;
24 bool FP8ButtonInterface::force_change = false;
26 #define NEWBUTTON(midi_id, button_id, color) \
28 assert (_midimap.end() == _midimap.find (midi_id)); \
29 assert (_ctrlmap.end() == _ctrlmap.find (button_id)); \
30 FP8Button *t = new FP8Button (b, midi_id); \
31 _midimap[midi_id] = t; \
32 _ctrlmap[button_id] = t; \
36 #define NEWTYPEBUTTON(TYPE, midi_id, button_id, color) \
38 assert (_midimap.end() == _midimap.find (midi_id)); \
39 assert (_ctrlmap.end() == _ctrlmap.find (button_id)); \
40 TYPE *t = new TYPE (b, midi_id); \
41 _midimap[midi_id] = t; \
42 _ctrlmap[button_id] = t; \
47 #define NEWSHIFTBUTTON(midi_id, id1, id2, color) \
49 assert (_midimap.end() == _midimap.find (midi_id)); \
50 assert (_ctrlmap.end() == _ctrlmap.find (id1)); \
51 assert (_ctrlmap.end() == _ctrlmap.find (id2)); \
52 FP8ShiftSensitiveButton *t = \
53 new FP8ShiftSensitiveButton (b, midi_id, color); \
54 _midimap[midi_id] = t; \
55 _ctrlmap[id1] = t->button (); \
56 _ctrlmap[id2] = t->button_shift (); \
60 FP8Controls::FP8Controls (FP8Base& b)
61 : _fadermode (ModeTrack)
63 , _navmode (NavScroll)
65 , _navmode (NavMaster)
68 , _display_timecode (false)
70 NEWBUTTON (0x56, BtnLoop, false);
71 NEWTYPEBUTTON (FP8RepeatButton, 0x5b, BtnRewind, false);
72 NEWTYPEBUTTON (FP8RepeatButton, 0x5c, BtnFastForward, false);
73 NEWBUTTON (0x5d, BtnStop, false);
74 NEWBUTTON (0x5e, BtnPlay, false);
75 NEWBUTTON (0x5f, BtnRecord, false);
79 NEWSHIFTBUTTON (0x4a, BtnARead, BtnAOff, true);
80 NEWSHIFTBUTTON (0x4b, BtnAWrite, BtnATrim, true);
81 NEWSHIFTBUTTON (0x4d, BtnATouch, BtnALatch, true);
83 NEWSHIFTBUTTON (0x2e, BtnPrev, BtnUndo, false);
84 NEWSHIFTBUTTON (0x2f, BtnNext, BtnRedo, false);
86 NEWSHIFTBUTTON (0x2a, BtnPan, BtnFlip, true); //TODO: Flip Pan knob to fader ...?
88 NEWSHIFTBUTTON (0x36, BtnChannel, BtnChanLock, true);
90 NEWSHIFTBUTTON (0x38, BtnScroll, BtnZoom, true);
92 NEWSHIFTBUTTON (0x3a, BtnMaster, BtnF1, false);
93 NEWSHIFTBUTTON (0x3b, BtnClick, BtnF2, false);
94 NEWSHIFTBUTTON (0x3c, BtnSection, BtnF3, false);
95 NEWSHIFTBUTTON (0x3d, BtnMarker, BtnF4, false);
97 //these buttons do not exist in FP2, but they need to exist in the ctrlmap:
98 NEWBUTTON (0x71, BtnBank, false);
99 NEWBUTTON (0x72, BtnF5, false);
100 NEWBUTTON (0x73, BtnF6, false);
101 NEWBUTTON (0x74, BtnF7, false);
102 NEWBUTTON (0x75, BtnF8, false);
103 NEWBUTTON (0x76, BtnUser1, false);
104 NEWBUTTON (0x77, BtnUser2, false);
105 NEWBUTTON (0x78, BtnUser3, false);
106 NEWBUTTON (0x79, BtnSave, false);
109 NEWSHIFTBUTTON (0x4a, BtnARead, BtnUser3, true);
110 NEWSHIFTBUTTON (0x4b, BtnAWrite, BtnUser2, true);
111 NEWSHIFTBUTTON (0x4c, BtnATrim, BtnRedo, true);
112 NEWSHIFTBUTTON (0x4d, BtnATouch, BtnUser1, true);
113 NEWSHIFTBUTTON (0x4e, BtnALatch, BtnSave, true);
114 NEWSHIFTBUTTON (0x4f, BtnAOff, BtnUndo, true);
116 NEWBUTTON (0x2e, BtnPrev, false);
117 NEWBUTTON (0x2f, BtnNext, false);
119 NEWSHIFTBUTTON (0x36, BtnChannel, BtnF1, false);
120 NEWSHIFTBUTTON (0x37, BtnZoom, BtnF2, false);
121 NEWSHIFTBUTTON (0x38, BtnScroll, BtnF3, false);
122 NEWSHIFTBUTTON (0x39, BtnBank, BtnF4, false);
123 NEWSHIFTBUTTON (0x3a, BtnMaster, BtnF5, false);
124 NEWSHIFTBUTTON (0x3b, BtnClick, BtnF6, false);
125 NEWSHIFTBUTTON (0x3c, BtnSection, BtnF7, false);
126 NEWSHIFTBUTTON (0x3d, BtnMarker, BtnF8, false);
128 NEWBUTTON (0x2a, BtnPan, false);
131 NEWSHIFTBUTTON (0x28, BtnTrack, BtnTimecode, false);
132 NEWBUTTON (0x2b, BtnPlugins, false);
133 NEWBUTTON (0x29, BtnSend, false);
135 NEWSHIFTBUTTON (0x00, BtnArm, BtnArmAll, false);
136 NEWBUTTON (0x01, BtnSoloClear, false);
137 NEWBUTTON (0x02, BtnMuteClear, false);
139 NEWSHIFTBUTTON (0x03, BtnBypass, BtnBypassAll, true);
140 NEWSHIFTBUTTON (0x04, BtnMacro, BtnOpen, true);
141 NEWSHIFTBUTTON (0x05, BtnLink, BtnLock, true);
143 NEWSHIFTBUTTON (0x3e, BtnMAudio, BtnMInputs, true);
144 NEWSHIFTBUTTON (0x3f, BtnMVI, BtnMMIDI, true);
145 NEWSHIFTBUTTON (0x40, BtnMBus, BtnMOutputs, true);
146 NEWSHIFTBUTTON (0x41, BtnMVCA, BtnMFX, true);
147 NEWSHIFTBUTTON (0x42, BtnMAll, BtnMUser, true);
149 NEWTYPEBUTTON (FP8ReadOnlyButton, 0x53, BtnEncoder, false);
150 NEWTYPEBUTTON (FP8ReadOnlyButton, 0x20, BtnParam, false);
151 NEWTYPEBUTTON (FP8ReadOnlyButton, 0x66, BtnFootswitch, false);
153 /* internal bindings */
155 #define BindMethod(ID, CB) \
156 button (ID).released.connect_same_thread (button_connections, boost::bind (&FP8Controls:: CB, this));
158 BindMethod (FP8Controls::BtnTimecode, toggle_timecode);
160 #define BindNav(BTN, MODE)\
161 button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_nav_mode, this, MODE))
163 BindNav (BtnChannel, NavChannel);
164 BindNav (BtnZoom, NavZoom);
165 BindNav (BtnScroll, NavScroll);
166 BindNav (BtnBank, NavBank);
167 BindNav (BtnMaster, NavMaster);
168 BindNav (BtnSection, NavSection);
169 BindNav (BtnMarker, NavMarker);
171 BindNav (BtnPan, NavPan);
174 #define BindFader(BTN, MODE)\
175 button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_fader_mode, this, MODE))
177 BindFader (BtnTrack, ModeTrack);
178 BindFader (BtnPlugins, ModePlugins);
179 BindFader (BtnSend, ModeSend);
181 BindFader (BtnPan, ModePan);
185 #define BindMix(BTN, MODE)\
186 button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_mix_mode, this, MODE))
188 BindMix (BtnMAudio, MixAudio);
189 BindMix (BtnMVI, MixInstrument);
190 BindMix (BtnMBus, MixBus);
191 BindMix (BtnMVCA, MixVCA);
192 BindMix (BtnMAll, MixAll);
193 BindMix (BtnMInputs, MixInputs);
194 BindMix (BtnMMIDI, MixMIDI);
195 BindMix (BtnMOutputs, MixOutputs);
196 BindMix (BtnMFX, MixFX);
197 BindMix (BtnMUser, MixUser);
199 /* create channelstrips */
200 for (uint8_t id = 0; id < N_STRIPS; ++id) {
201 chanstrip[id] = new FP8Strip (b, id);
202 _midimap_strip[FP8Strip::midi_ctrl_id (FP8Strip::BtnSolo, id)] = &(chanstrip[id]->solo_button());
203 _midimap_strip[FP8Strip::midi_ctrl_id (FP8Strip::BtnMute, id)] = &(chanstrip[id]->mute_button());
204 _midimap_strip[FP8Strip::midi_ctrl_id (FP8Strip::BtnSelect, id)] = &(chanstrip[id]->selrec_button());
207 /* set User button names */
209 #define REGISTER_ENUM(ID, NAME) \
210 _user_str_to_enum[#ID] = ID; \
211 _user_enum_to_str[ID] = #ID; \
212 _user_buttons[ID] = NAME;
215 REGISTER_ENUM (BtnF1 , "F1");
216 REGISTER_ENUM (BtnF2 , "F2");
217 REGISTER_ENUM (BtnF3 , "F3");
218 REGISTER_ENUM (BtnF4 , "F4");
219 REGISTER_ENUM (BtnFootswitch, "Footswitch");
221 REGISTER_ENUM (BtnFootswitch, "Footswitch");
222 REGISTER_ENUM (BtnUser1 , "User 1");
223 REGISTER_ENUM (BtnUser2 , "User 2");
224 REGISTER_ENUM (BtnUser3 , "User 3");
225 REGISTER_ENUM (BtnF1 , "F1");
226 REGISTER_ENUM (BtnF2 , "F2");
227 REGISTER_ENUM (BtnF3 , "F3");
228 REGISTER_ENUM (BtnF4 , "F4");
229 REGISTER_ENUM (BtnF5 , "F5");
230 REGISTER_ENUM (BtnF6 , "F6");
231 REGISTER_ENUM (BtnF7 , "F7");
232 REGISTER_ENUM (BtnF8 , "F8");
238 FP8Controls::~FP8Controls ()
240 for (MidiButtonMap::const_iterator i = _midimap.begin (); i != _midimap.end (); ++i) {
243 for (uint8_t id = 0; id < N_STRIPS; ++id) {
244 delete chanstrip[id];
246 _midimap_strip.clear ();
252 FP8Controls::button_name_to_enum (std::string const& n, ButtonId& id) const
254 std::map<std::string, ButtonId>::const_iterator i = _user_str_to_enum.find (n);
255 if (i == _user_str_to_enum.end()) {
263 FP8Controls::button_enum_to_name (ButtonId id, std::string& n) const
265 std::map<ButtonId, std::string>::const_iterator i = _user_enum_to_str.find (id);
266 if (i == _user_enum_to_str.end()) {
274 FP8Controls::initialize ()
276 FP8ButtonInterface::force_change = true;
278 button (BtnUndo).set_color (0x00ff00ff);
279 button (BtnRedo).set_color (0x00ff00ff);
281 button (BtnAOff).set_color (0xffffffff);
282 button (BtnATrim).set_color (0x000030ff);
283 button (BtnARead).set_color (0x00ff00ff);
284 button (BtnAWrite).set_color (0xff0000ff);
285 button (BtnATouch).set_color (0xff8800ff);
286 button (BtnALatch).set_color (0xffff00ff);
288 button (BtnUser1).set_color (0x0000ffff);
289 button (BtnUser2).set_color (0x0000ffff);
290 button (BtnUser3).set_color (0x0000ffff);
292 button (BtnBypass).set_color (0x888888ff);
293 button (BtnBypassAll).set_color (0xffffffff);
295 button (BtnMacro).set_color (0x888888ff);
296 button (BtnOpen).set_color (0xffffffff);
298 button (BtnLink).set_color (0x888888ff);
299 button (BtnLock).set_color (0xffffffff);
301 button (BtnMAudio).set_color (0x0000ffff);
302 button (BtnMVI).set_color (0x0000ffff);
303 button (BtnMBus).set_color (0x0000ffff);
304 button (BtnMVCA).set_color (0x0000ffff);
305 button (BtnMAll).set_color (0x0000ffff);
307 button (BtnMInputs).set_color (0x0000ffff);
308 button (BtnMMIDI).set_color (0x0000ffff);
309 button (BtnMOutputs).set_color (0x0000ffff);
310 button (BtnMFX).set_color (0x0000ffff);
311 button (BtnMUser).set_color (0x0000ffff);
314 /* encoder mode-switches are orange, to match the Master switch physical color */
315 button (BtnLink).set_color (0x000000ff);
316 button (BtnChannel).set_color (0x0000ffff);
317 button (BtnScroll).set_color (0x0000ffff);
318 button (BtnPan).set_color (0xffffffff);
321 for (uint8_t id = 0; id < N_STRIPS; ++id) {
322 chanstrip[id]->initialize ();
325 /* initally turn all lights off */
330 button (BtnScroll).set_active (true);
332 button (BtnMaster).set_active (true);
334 button (BtnTrack).set_active (true);
335 button (BtnMAll).set_active (true);
336 button (BtnTimecode).set_active (_display_timecode);
338 FP8ButtonInterface::force_change = false;
342 FP8Controls::all_lights_off () const
344 for (CtrlButtonMap::const_iterator i = _ctrlmap.begin (); i != _ctrlmap.end (); ++i) {
345 i->second->set_active (false);
350 FP8Controls::button (ButtonId id)
352 CtrlButtonMap::const_iterator i = _ctrlmap.find (id);
353 if (i == _ctrlmap.end()) {
355 return _dummy_button;
361 FP8Controls::strip (uint8_t id)
363 assert (id < N_STRIPS);
364 return *chanstrip[id];
367 /* *****************************************************************************
368 * Delegate MIDI events
372 FP8Controls::midi_event (uint8_t id, uint8_t val)
374 MidiButtonMap::const_iterator i;
376 i = _midimap_strip.find (id);
377 if (i != _midimap_strip.end()) {
378 return i->second->midi_event (val > 0x40);
381 i = _midimap.find (id);
382 if (i != _midimap.end()) {
383 return i->second->midi_event (val > 0x40);
389 FP8Controls::midi_touch (uint8_t id, uint8_t val)
391 assert (id < N_STRIPS);
392 return chanstrip[id]->midi_touch (val > 0x40);
396 FP8Controls::midi_fader (uint8_t id, unsigned short val)
398 assert (id < N_STRIPS);
399 return chanstrip[id]->midi_fader ((val >> 4) / 1023.f);
402 /* *****************************************************************************
403 * Internal Model + View for Modes
407 FP8Controls::set_nav_mode (NavigationMode m)
412 // TODO add special-cases:
413 // - master/monitor (blink when button is held + monitor section present)
414 // - "click" hold -> encoder sets click volume, encoder-press toggle rec-only-metro
415 button (BtnChannel).set_active (m == NavChannel);
416 button (BtnZoom).set_active (m == NavZoom);
417 button (BtnScroll).set_active (m == NavScroll);
418 button (BtnBank).set_active (m == NavBank);
419 button (BtnMaster).set_active (m == NavMaster);
420 button (BtnSection).set_active (m == NavSection);
421 button (BtnMarker).set_active (m == NavMarker);
423 button (BtnPan).set_active (m == NavPan);
429 FP8Controls::set_fader_mode (FaderMode m)
431 if (_fadermode == m) {
432 if (m == ModePlugins || m == ModeSend) {
433 /* "Edit Plugins" while editing Plugin-params, returns back
434 * to plugin selection.
435 * "Sends" button banks through sends.
442 button (BtnTrack).set_active (m == ModeTrack);
443 button (BtnPlugins).set_active (m == ModePlugins);
444 button (BtnSend).set_active (m == ModeSend);
445 button (BtnPan).set_active (m == ModePan);
451 FP8Controls::set_mix_mode (MixMode m)
454 if (m == MixUser || m == MixInputs) {
456 * - MixUser: depends on selection
457 * - MixInputs: depends on rec-arm
463 button (BtnMAudio).set_active (m == MixAudio);
464 button (BtnMVI).set_active (m == MixInstrument);
465 button (BtnMBus).set_active (m == MixBus);
466 button (BtnMVCA).set_active (m == MixVCA);
467 button (BtnMAll).set_active (m == MixAll);
468 button (BtnMInputs).set_active (m == MixInputs);
469 button (BtnMMIDI).set_active (m == MixMIDI);
470 button (BtnMOutputs).set_active (m == MixOutputs);
471 button (BtnMFX).set_active (m == MixFX);
472 button (BtnMUser).set_active (m == MixUser);
479 FP8Controls::toggle_timecode ()
481 _display_timecode = !_display_timecode;
482 button (BtnTimecode).set_active (_display_timecode);