1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    The code included in this file is provided under the terms of the ISC license
11    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12    To use, copy, modify, and/or distribute this software for any purpose with or
13    without fee is hereby granted provided that the above copyright notice and
14    this permission notice appear in all copies.
15 
16    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18    DISCLAIMED.
19 
20   ==============================================================================
21 */
22 
23 namespace juce
24 {
25 namespace BlocksProtocol
26 {
27 
28 #ifndef DOXYGEN
29 
30 // This file isn't part of the public API, it's where we encode the knowledge base
31 // of all the different types of block we know about..
32 struct BlockDataSheet
33 {
BlockDataSheetBlockDataSheet34     BlockDataSheet (const BlocksProtocol::BlockSerialNumber& serial)  : serialNumber (serial)
35     {
36         if (serialNumber.isPadBlock())          initialiseForPadBlock2x2();
37         if (serialNumber.isLiveBlock())         initialiseForControlBlockLive();
38         if (serialNumber.isLoopBlock())         initialiseForControlBlockLoop();
39         if (serialNumber.isDevCtrlBlock())      initialiseForControlBlockDeveloper();
40         if (serialNumber.isTouchBlock())        initialiseForControlBlockTouch();
41         if (serialNumber.isSeaboardBlock())     initialiseForSeaboardBlock();
42         if (serialNumber.isLumiKeysBlock())     initialiseForLumiKeysBlock();
43     }
44 
convertPortIndexToConnectorPortBlockDataSheet45     Block::ConnectionPort convertPortIndexToConnectorPort (BlocksProtocol::ConnectorPort port) const noexcept
46     {
47         return ports[(int) port.get()];
48     }
49 
50     const BlocksProtocol::BlockSerialNumber serialNumber;
51     Block::Type apiType = Block::Type::unknown;
52 
53     const char* description = nullptr;
54 
55     int widthUnits = 0, heightUnits = 0;
56 
57     int lightGridWidth = 0, lightGridHeight = 0, lightGridStartIndex = 0;
58 
59     bool hasTouchSurface = false;
60     int numKeywaves = 0;
61 
62     int numLEDRowLEDs = 0;
63 
64     uint32 programAndHeapSize = 0;
65 
66     struct ButtonInfo
67     {
68         ControlButton::ButtonFunction type;
69         float x, y;
70     };
71 
72     struct StatusLEDInfo
73     {
74         String name;
75         float x, y;
76     };
77 
78     Array<ButtonInfo> buttons;
79     Array<StatusLEDInfo> statusLEDs;
80     Array<Block::ConnectionPort> ports;
81     Array<const char*> dials;
82     Array<BlockConfigManager::ConfigDescription> defaultConfig;
83 
84 private:
85     //==============================================================================
initialiseForPadBlock2x2BlockDataSheet86     void initialiseForPadBlock2x2()
87     {
88         apiType = Block::Type::lightPadBlock;
89 
90         description = "Pad BLOCK (2x2)";
91 
92         widthUnits  = 2;
93         heightUnits = 2;
94 
95         lightGridWidth = 15;
96         lightGridHeight = 15;
97 
98         addPorts (2, 2, 2, 2);
99 
100         hasTouchSurface = true;
101         programAndHeapSize = BlocksProtocol::padBlockProgramAndHeapSize;
102 
103         addModeButton();
104     }
105 
initialiseForControlBlockLoopBlockDataSheet106     void initialiseForControlBlockLoop()
107     {
108         initialiseControlBlock ("Loop BLOCK", Block::Type::loopBlock,
109                                 ControlButton::ButtonFunction::mode,
110                                 ControlButton::ButtonFunction::volume,
111                                 ControlButton::ButtonFunction::click,
112                                 ControlButton::ButtonFunction::snap,
113                                 ControlButton::ButtonFunction::back,
114                                 ControlButton::ButtonFunction::playOrPause,
115                                 ControlButton::ButtonFunction::record,
116                                 ControlButton::ButtonFunction::learn,
117                                 ControlButton::ButtonFunction::down,
118                                 ControlButton::ButtonFunction::up);
119     }
120 
initialiseForControlBlockLiveBlockDataSheet121     void initialiseForControlBlockLive()
122     {
123         initialiseControlBlock ("Live BLOCK", Block::Type::liveBlock,
124                                 ControlButton::ButtonFunction::mode,
125                                 ControlButton::ButtonFunction::volume,
126                                 ControlButton::ButtonFunction::scale,
127                                 ControlButton::ButtonFunction::chord,
128                                 ControlButton::ButtonFunction::arp,
129                                 ControlButton::ButtonFunction::sustain,
130                                 ControlButton::ButtonFunction::octave,
131                                 ControlButton::ButtonFunction::love,
132                                 ControlButton::ButtonFunction::down,
133                                 ControlButton::ButtonFunction::up);
134     }
135 
initialiseForControlBlockDeveloperBlockDataSheet136     void initialiseForControlBlockDeveloper()
137     {
138         initialiseControlBlock ("Dev Ctrl BLOCK", Block::Type::developerControlBlock,
139                                 ControlButton::ButtonFunction::button0,
140                                 ControlButton::ButtonFunction::button1,
141                                 ControlButton::ButtonFunction::button2,
142                                 ControlButton::ButtonFunction::button3,
143                                 ControlButton::ButtonFunction::button4,
144                                 ControlButton::ButtonFunction::button5,
145                                 ControlButton::ButtonFunction::button6,
146                                 ControlButton::ButtonFunction::button7,
147                                 ControlButton::ButtonFunction::down,
148                                 ControlButton::ButtonFunction::up);
149     }
150 
initialiseForControlBlockTouchBlockDataSheet151     void initialiseForControlBlockTouch()
152     {
153         initialiseControlBlock ("Touch BLOCK", Block::Type::touchBlock,
154                                 ControlButton::ButtonFunction::velocitySensitivity,
155                                 ControlButton::ButtonFunction::glideSensitivity,
156                                 ControlButton::ButtonFunction::slideSensitivity,
157                                 ControlButton::ButtonFunction::pressSensitivity,
158                                 ControlButton::ButtonFunction::liftSensitivity,
159                                 ControlButton::ButtonFunction::fixedVelocity,
160                                 ControlButton::ButtonFunction::glideLock,
161                                 ControlButton::ButtonFunction::pianoMode,
162                                 ControlButton::ButtonFunction::down,
163                                 ControlButton::ButtonFunction::up);
164     }
165 
initialiseControlBlockBlockDataSheet166     void initialiseControlBlock (const char* name, Block::Type type,
167                                  ControlButton::ButtonFunction b1, ControlButton::ButtonFunction b2,
168                                  ControlButton::ButtonFunction b3, ControlButton::ButtonFunction b4,
169                                  ControlButton::ButtonFunction b5, ControlButton::ButtonFunction b6,
170                                  ControlButton::ButtonFunction b7, ControlButton::ButtonFunction b8,
171                                  ControlButton::ButtonFunction b9, ControlButton::ButtonFunction b10)
172     {
173         apiType = type;
174 
175         description = name;
176 
177         widthUnits  = 2;
178         heightUnits = 1;
179 
180         programAndHeapSize = BlocksProtocol::controlBlockProgramAndHeapSize;
181 
182         addPorts (2, 1, 2, 1);
183 
184         float x1 = 0.2f;
185         float x2 = 0.6f;
186         float x3 = 1.0f;
187         float x4 = 1.4f;
188         float x5 = 1.8f;
189         float y1 = 0.405f;
190         float y2 = 0.798f;
191 
192         addButtons (b1,  x1, y1,
193                     b2,  x2, y1,
194                     b3,  x3, y1,
195                     b4,  x4, y1,
196                     b5,  x5, y1,
197                     b6,  x1, y2,
198                     b7,  x2, y2,
199                     b8,  x3, y2,
200                     b9,  x4, y2,
201                     b10, x5, y2);
202 
203         numLEDRowLEDs = 15;
204     }
205 
initialiseForSeaboardBlockBlockDataSheet206     void initialiseForSeaboardBlock()
207     {
208         apiType = Block::Type::seaboardBlock;
209 
210         description = "Seaboard BLOCK (6x3)";
211 
212         widthUnits  = 6;
213         heightUnits = 3;
214 
215         lightGridWidth = 0;
216         lightGridHeight = 0;
217         numKeywaves = 24;
218 
219         addPortsSW (Block::ConnectionPort::DeviceEdge::west,  1);
220         addPortsNE (Block::ConnectionPort::DeviceEdge::north, 2);
221         addPortsNE (Block::ConnectionPort::DeviceEdge::east,  1);
222 
223         hasTouchSurface = true;
224         programAndHeapSize = BlocksProtocol::padBlockProgramAndHeapSize;
225 
226         addModeButton();
227     }
228 
initialiseForLumiKeysBlockBlockDataSheet229     void initialiseForLumiKeysBlock()
230     {
231         apiType = Block::Type::lumiKeysBlock;
232 
233         description = "LUMI Keys BLOCK (6x3)";
234 
235         widthUnits = 6;
236         heightUnits = 3;
237 
238         lightGridWidth = 0;
239         lightGridHeight = 0;
240         numKeywaves = 24;
241 
242         addButtons (ControlButton::ButtonFunction::mode, 0.2f, 0.2f,
243                     ControlButton::ButtonFunction::down, 0.6f, 0.2f,
244                     ControlButton::ButtonFunction::up, 1.0f, 0.2f);
245 
246         addPortsSW (Block::ConnectionPort::DeviceEdge::west, 2);
247         addPortsNE (Block::ConnectionPort::DeviceEdge::north, 4);
248         addPortsNE (Block::ConnectionPort::DeviceEdge::east, 2);
249 
250         hasTouchSurface = true;
251         programAndHeapSize = BlocksProtocol::padBlockProgramAndHeapSize;
252 
253         defaultConfig.add ({ mode, 0, 0, 3, false,
254                            "Color Mode", ConfigType::options,
255                            { "Multi-color Mode",
256                              "Single Color Mode",
257                              "Piano Mode",
258                              "Night Mode"
259                            },
260                            BlockConfigManager::playGroup });
261 
262         defaultConfig.add ({ zTrackingMode, 0, 0, 1, false,
263                             "Pressure Tracking Mode", ConfigType::options,
264                             { "Poly Aftertouch", "Channel Pressure" },
265                             BlockConfigManager::playGroup });
266     }
267 
268     //==============================================================================
addStatusLEDBlockDataSheet269     void addStatusLED (const char* name, float x, float y)
270     {
271         statusLEDs.add ({ name, x, y });
272     }
273 
274     template <typename... Args>
addButtonsBlockDataSheet275     void addButtons (ControlButton::ButtonFunction fn, float x, float y, Args... others)
276     {
277         addButtons (fn, x, y);
278         addButtons (others...);
279     }
280 
addButtonsBlockDataSheet281     void addButtons (ControlButton::ButtonFunction fn, float x, float y)
282     {
283         buttons.add ({ fn, x, y });
284     }
285 
addModeButtonBlockDataSheet286     void addModeButton()
287     {
288         addButtons (ControlButton::ButtonFunction::mode, -1.0f, -1.0f);
289     }
290 
addPortsBlockDataSheet291     void addPorts (int numNorth, int numEast, int numSouth, int numWest)
292     {
293         addPortsNE (Block::ConnectionPort::DeviceEdge::north, numNorth);
294         addPortsNE (Block::ConnectionPort::DeviceEdge::east,  numEast);
295         addPortsSW (Block::ConnectionPort::DeviceEdge::south, numSouth);
296         addPortsSW (Block::ConnectionPort::DeviceEdge::west,  numWest);
297     }
298 
addPortsNEBlockDataSheet299     void addPortsNE (Block::ConnectionPort::DeviceEdge edge, int num)
300     {
301         for (int i = 0; i < num; ++i)
302             ports.add ({ edge, i});
303     }
304 
addPortsSWBlockDataSheet305     void addPortsSW (Block::ConnectionPort::DeviceEdge edge, int num)
306     {
307         for (int i = 0; i < num; ++i)
308             ports.add ({ edge, num - i - 1});
309     }
310 };
311 
312 //==============================================================================
getButtonNameForFunction(ControlButton::ButtonFunction fn)313 static const char* getButtonNameForFunction (ControlButton::ButtonFunction fn) noexcept
314 {
315     using BF = ControlButton::ButtonFunction;
316 
317     switch (fn)
318     {
319         case BF::mode:          return "Mode";
320 
321         case BF::volume:        return "Volume";
322         case BF::up:            return "Up";
323         case BF::down:          return "Down";
324 
325         case BF::scale:         return "Scale";
326         case BF::chord:         return "Chord";
327         case BF::arp:           return "Arp";
328         case BF::sustain:       return "Sustain";
329         case BF::octave:        return "Octave";
330         case BF::love:          return "Love";
331 
332         case BF::click:         return "Click";
333         case BF::snap:          return "Snap";
334         case BF::back:          return "Back";
335         case BF::playOrPause:   return "Play/Pause";
336         case BF::record:        return "Record";
337         case BF::learn:         return "Learn";
338 
339         case BF::button0:       return "0";
340         case BF::button1:       return "1";
341         case BF::button2:       return "2";
342         case BF::button3:       return "3";
343         case BF::button4:       return "4";
344         case BF::button5:       return "5";
345         case BF::button6:       return "6";
346         case BF::button7:       return "7";
347 
348         case BF::velocitySensitivity:  return "Velocity Sensitivity";
349         case BF::glideSensitivity:     return "Glide Sensitivity";
350         case BF::slideSensitivity:     return "Slide Sensitivity";
351         case BF::pressSensitivity:     return "Press Sensitivity";
352         case BF::liftSensitivity:      return "Lift Sensitivity";
353         case BF::fixedVelocity:        return "Fixed Velocity";
354         case BF::glideLock:            return "Glide Lock";
355         case BF::pianoMode:            return "Piano Mode";
356 
357         default:  break;
358     }
359 
360     jassertfalse;
361     return nullptr;
362 }
363 
364 #endif
365 
366 } // namespace BlocksProtocol
367 } // namespace juce
368