1 /* Faderport 8 Control Surface
2 * Abstraction of Surface Control Elements.
4 * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
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.
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.
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.
21 #include "fp8_controls.h"
23 using namespace ArdourSurface;
24 using namespace ArdourSurface::FP8Types;
26 bool FP8ButtonInterface::force_change = false;
28 #define NEWBUTTON(midi_id, button_id, color) \
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; \
38 #define NEWTYPEBUTTON(TYPE, midi_id, button_id, color) \
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; \
49 #define NEWSHIFTBUTTON(midi_id, id1, id2, color) \
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 (); \
62 FP8Controls::FP8Controls (FP8Base& b)
63 : _fadermode (ModeTrack)
64 , _navmode (NavMaster)
66 , _display_timecode (false)
68 NEWBUTTON (0x56, BtnLoop, false);
69 NEWTYPEBUTTON (FP8RepeatButton, 0x5b, BtnRewind, false);
70 NEWTYPEBUTTON (FP8RepeatButton, 0x5c, BtnFastForward, false);
71 NEWBUTTON (0x5d, BtnStop, false);
72 NEWBUTTON (0x5e, BtnPlay, false);
73 NEWBUTTON (0x5f, BtnRecord, false);
75 NEWSHIFTBUTTON (0x4a, BtnARead, BtnUser3, true);
76 NEWSHIFTBUTTON (0x4b, BtnAWrite, BtnUser2, true);
77 NEWSHIFTBUTTON (0x4c, BtnATrim, BtnRedo, true);
78 NEWSHIFTBUTTON (0x4d, BtnATouch, BtnUser1, true);
79 NEWSHIFTBUTTON (0x4e, BtnALatch, BtnSave, true);
80 NEWSHIFTBUTTON (0x4f, BtnAOff, BtnUndo, true);
82 NEWBUTTON (0x2e, BtnPrev, false);
83 NEWBUTTON (0x2f, BtnNext, false);
85 NEWSHIFTBUTTON (0x36, BtnChannel, BtnF1, false);
86 NEWSHIFTBUTTON (0x37, BtnZoom, BtnF2, false);
87 NEWSHIFTBUTTON (0x38, BtnScroll, BtnF3, false);
88 NEWSHIFTBUTTON (0x39, BtnBank, BtnF4, false);
89 NEWSHIFTBUTTON (0x3a, BtnMaster, BtnF5, false);
90 NEWSHIFTBUTTON (0x3b, BtnClick, BtnF6, false);
91 NEWSHIFTBUTTON (0x3c, BtnSection, BtnF7, false);
92 NEWSHIFTBUTTON (0x3d, BtnMarker, BtnF8, false);
94 NEWSHIFTBUTTON (0x28, BtnTrack, BtnTimecode, false);
95 NEWBUTTON (0x2b, BtnPlugins, false);
96 NEWBUTTON (0x29, BtnSend, false);
97 NEWBUTTON (0x2a, BtnPan, false);
99 NEWSHIFTBUTTON (0x00, BtnArm, BtnArmAll, false);
100 NEWBUTTON (0x01, BtnSoloClear, false);
101 NEWBUTTON (0x02, BtnMuteClear, false);
103 NEWSHIFTBUTTON (0x03, BtnBypass, BtnBypassAll, true);
104 NEWSHIFTBUTTON (0x04, BtnMacro, BtnOpen, true);
105 NEWSHIFTBUTTON (0x05, BtnLink, BtnLock, true);
107 NEWSHIFTBUTTON (0x3e, BtnMAudio, BtnMInputs, true);
108 NEWSHIFTBUTTON (0x3f, BtnMVI, BtnMMIDI, true);
109 NEWSHIFTBUTTON (0x40, BtnMBus, BtnMOutputs, true);
110 NEWSHIFTBUTTON (0x41, BtnMVCA, BtnMFX, true);
111 NEWSHIFTBUTTON (0x42, BtnMAll, BtnMUser, true);
113 NEWTYPEBUTTON (FP8ReadOnlyButton, 0x53, BtnEncoder, false);
114 NEWTYPEBUTTON (FP8ReadOnlyButton, 0x20, BtnParam, false);
115 NEWTYPEBUTTON (FP8ReadOnlyButton, 0x66, BtnFootswitch, false);
117 /* internal bindings */
119 #define BindMethod(ID, CB) \
120 button (ID).released.connect_same_thread (button_connections, boost::bind (&FP8Controls:: CB, this));
122 BindMethod (FP8Controls::BtnTimecode, toggle_timecode);
124 #define BindNav(BTN, MODE)\
125 button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_nav_mode, this, MODE))
127 BindNav (BtnChannel, NavChannel);
128 BindNav (BtnZoom, NavZoom);
129 BindNav (BtnScroll, NavScroll);
130 BindNav (BtnBank, NavBank);
131 BindNav (BtnMaster, NavMaster);
132 BindNav (BtnSection, NavSection);
133 BindNav (BtnMarker, NavMarker);
135 #define BindFader(BTN, MODE)\
136 button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_fader_mode, this, MODE))
138 BindFader (BtnTrack, ModeTrack);
139 BindFader (BtnPlugins, ModePlugins);
140 BindFader (BtnSend, ModeSend);
141 BindFader (BtnPan, ModePan);
144 #define BindMix(BTN, MODE)\
145 button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_mix_mode, this, MODE))
147 BindMix (BtnMAudio, MixAudio);
148 BindMix (BtnMVI, MixInstrument);
149 BindMix (BtnMBus, MixBus);
150 BindMix (BtnMVCA, MixVCA);
151 BindMix (BtnMAll, MixAll);
152 BindMix (BtnMInputs, MixInputs);
153 BindMix (BtnMMIDI, MixMIDI);
154 BindMix (BtnMOutputs, MixOutputs);
155 BindMix (BtnMFX, MixFX);
156 BindMix (BtnMUser, MixUser);
158 /* create channelstrips */
159 for (uint8_t id = 0; id < 8; ++id) {
160 chanstrip[id] = new FP8Strip (b, id);
161 _midimap_strip[0x08 + id] = &(chanstrip[id]->solo_button());
162 _midimap_strip[0x10 + id] = &(chanstrip[id]->mute_button());
163 _midimap_strip[0x18 + id] = &(chanstrip[id]->selrec_button());
166 /* set User button names */
168 #define REGISTER_ENUM(ID, NAME) \
169 _user_str_to_enum[#ID] = ID; \
170 _user_enum_to_str[ID] = #ID; \
171 _user_buttons[ID] = NAME;
173 REGISTER_ENUM (BtnFootswitch, "Footswitch");
174 REGISTER_ENUM (BtnUser1 , "User 1");
175 REGISTER_ENUM (BtnUser2 , "User 2");
176 REGISTER_ENUM (BtnUser3 , "User 3");
177 REGISTER_ENUM (BtnF1 , "F1");
178 REGISTER_ENUM (BtnF2 , "F2");
179 REGISTER_ENUM (BtnF3 , "F3");
180 REGISTER_ENUM (BtnF4 , "F4");
181 REGISTER_ENUM (BtnF5 , "F5");
182 REGISTER_ENUM (BtnF6 , "F6");
183 REGISTER_ENUM (BtnF7 , "F7");
184 REGISTER_ENUM (BtnF8 , "F8");
188 FP8Controls::~FP8Controls ()
190 for (MidiButtonMap::const_iterator i = _midimap.begin (); i != _midimap.end (); ++i) {
193 for (uint8_t id = 0; id < 8; ++id) {
194 delete chanstrip[id];
196 _midimap_strip.clear ();
202 FP8Controls::button_name_to_enum (std::string const& n, ButtonId& id) const
204 std::map<std::string, ButtonId>::const_iterator i = _user_str_to_enum.find (n);
205 if (i == _user_str_to_enum.end()) {
213 FP8Controls::button_enum_to_name (ButtonId id, std::string& n) const
215 std::map<ButtonId, std::string>::const_iterator i = _user_enum_to_str.find (id);
216 if (i == _user_enum_to_str.end()) {
224 FP8Controls::initialize ()
226 FP8ButtonInterface::force_change = true;
228 button (BtnUndo).set_color (0x00ff00ff);
229 button (BtnRedo).set_color (0x00ff00ff);
231 button (BtnAOff).set_color (0xffffffff);
232 button (BtnATrim).set_color (0x000030ff);
233 button (BtnARead).set_color (0x00ff00ff);
234 button (BtnAWrite).set_color (0xff0000ff);
235 button (BtnATouch).set_color (0xff8800ff);
237 button (BtnUser1).set_color (0x0000ffff);
238 button (BtnUser2).set_color (0x0000ffff);
239 button (BtnUser3).set_color (0x0000ffff);
241 button (BtnALatch).set_color (0x0000ffff);
243 button (BtnBypass).set_color (0x888888ff);
244 button (BtnBypassAll).set_color (0xffffffff);
246 button (BtnMacro).set_color (0x888888ff);
247 button (BtnOpen).set_color (0xffffffff);
249 button (BtnLink).set_color (0x888888ff);
250 button (BtnLock).set_color (0xffffffff);
252 button (BtnMAudio).set_color (0x0000ffff);
253 button (BtnMVI).set_color (0x0000ffff);
254 button (BtnMBus).set_color (0x0000ffff);
255 button (BtnMVCA).set_color (0x0000ffff);
256 button (BtnMAll).set_color (0x0000ffff);
258 button (BtnMInputs).set_color (0x0000ffff);
259 button (BtnMMIDI).set_color (0x0000ffff);
260 button (BtnMOutputs).set_color (0x0000ffff);
261 button (BtnMFX).set_color (0x0000ffff);
262 button (BtnMUser).set_color (0x0000ffff);
264 for (uint8_t id = 0; id < 8; ++id) {
265 chanstrip[id]->initialize ();
268 /* initally turn all lights off */
272 button (BtnMaster).set_active (true);
273 button (BtnTrack).set_active (true);
274 button (BtnMAll).set_active (true);
275 button (BtnTimecode).set_active (_display_timecode);
277 FP8ButtonInterface::force_change = false;
281 FP8Controls::all_lights_off () const
283 for (CtrlButtonMap::const_iterator i = _ctrlmap.begin (); i != _ctrlmap.end (); ++i) {
284 i->second->set_active (false);
289 FP8Controls::button (ButtonId id)
291 CtrlButtonMap::const_iterator i = _ctrlmap.find (id);
292 if (i == _ctrlmap.end()) {
294 return _dummy_button;
300 FP8Controls::strip (uint8_t id)
303 return *chanstrip[id];
306 /* *****************************************************************************
307 * Delegate MIDI events
311 FP8Controls::midi_event (uint8_t id, uint8_t val)
313 MidiButtonMap::const_iterator i;
315 i = _midimap_strip.find (id);
316 if (i != _midimap_strip.end()) {
317 return i->second->midi_event (val > 0x40);
320 i = _midimap.find (id);
321 if (i != _midimap.end()) {
322 return i->second->midi_event (val > 0x40);
328 FP8Controls::midi_touch (uint8_t id, uint8_t val)
331 return chanstrip[id]->midi_touch (val > 0x40);
335 FP8Controls::midi_fader (uint8_t id, unsigned short val)
338 return chanstrip[id]->midi_fader ((val >> 4) / 1023.f);
341 /* *****************************************************************************
342 * Internal Model + View for Modes
346 FP8Controls::set_nav_mode (NavigationMode m)
351 // TODO add special-cases:
352 // - master/monitor (blink when button is held + monitor section present)
353 // - "click" hold -> encoder sets click volume, encoder-press toggle rec-only-metro
354 button (BtnChannel).set_active (m == NavChannel);
355 button (BtnZoom).set_active (m == NavZoom);
356 button (BtnScroll).set_active (m == NavScroll);
357 button (BtnBank).set_active (m == NavBank);
358 button (BtnMaster).set_active (m == NavMaster);
359 button (BtnSection).set_active (m == NavSection);
360 button (BtnMarker).set_active (m == NavMarker);
365 FP8Controls::set_fader_mode (FaderMode m)
367 if (_fadermode == m) {
368 if (m == ModePlugins || m == ModeSend) {
369 /* "Edit Plugins" while editing Plugin-params, returns back
370 * to plugin selection.
371 * "Sends" button banks through sends.
378 button (BtnTrack).set_active (m == ModeTrack);
379 button (BtnPlugins).set_active (m == ModePlugins);
380 button (BtnSend).set_active (m == ModeSend);
381 button (BtnPan).set_active (m == ModePan);
387 FP8Controls::set_mix_mode (MixMode m)
390 if (m == MixUser || m == MixInputs) {
392 * - MixUser: depends on selection
393 * - MixInputs: depends on rec-arm
399 button (BtnMAudio).set_active (m == MixAudio);
400 button (BtnMVI).set_active (m == MixInstrument);
401 button (BtnMBus).set_active (m == MixBus);
402 button (BtnMVCA).set_active (m == MixVCA);
403 button (BtnMAll).set_active (m == MixAll);
404 button (BtnMInputs).set_active (m == MixInputs);
405 button (BtnMMIDI).set_active (m == MixMIDI);
406 button (BtnMOutputs).set_active (m == MixOutputs);
407 button (BtnMFX).set_active (m == MixFX);
408 button (BtnMUser).set_active (m == MixUser);
415 FP8Controls::toggle_timecode ()
417 _display_timecode = !_display_timecode;
418 button (BtnTimecode).set_active (_display_timecode);