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 26 // This file provides interfaces for managing the internal configuration of Blocks 27 // and synchronises with the connected Block 28 29 using namespace BlocksProtocol; 30 31 using ConfigType = Block::ConfigMetaData::ConfigType; 32 33 /** Manages the configuration of blocks 34 35 @tags{Blocks} 36 */ 37 struct BlockConfigManager 38 { 39 /** Structure describing a configuration */ 40 struct ConfigDescription 41 { 42 ConfigItemId item; 43 int32 value; 44 int32 min; 45 int32 max; 46 bool isActive; 47 const char* name; 48 ConfigType type; 49 const char* optionNames[configMaxOptions]; 50 const char* group; 51 52 static_assert (configMaxOptions == Block::ConfigMetaData::numOptionNames, "Config options size and config metadata size should be the same"); 53 toConfigMetaDataBlockConfigManager::ConfigDescription54 Block::ConfigMetaData toConfigMetaData() const 55 { 56 return Block::ConfigMetaData ((uint32) item, value, { min, max }, isActive, name, type, (const char**) optionNames, group); 57 } 58 }; 59 BlockConfigManagerBlockConfigManager60 BlockConfigManager (Array<ConfigDescription> defaultConfig) 61 { 62 for (auto c : defaultConfig) 63 { 64 uint32 itemIndex; 65 66 if (getIndexForItem (c.item, itemIndex)) 67 configList[itemIndex] = c; 68 } 69 } 70 setDeviceIndexBlockConfigManager71 void setDeviceIndex (TopologyIndex newDeviceIndex) { deviceIndex = newDeviceIndex; } setDeviceCommsBlockConfigManager72 void setDeviceComms (PhysicalTopologySource::DeviceConnection* newConn) { deviceConnection = newConn; } 73 74 static constexpr uint32 numConfigItems = 69; 75 76 static constexpr const char* midiSettingsGroup = "MIDI Settings"; 77 static constexpr const char* pitchGroup = "Pitch"; 78 static constexpr const char* playGroup = "Play mode"; 79 static constexpr const char* sensitivityGroup = "Sensitivity"; 80 static constexpr const char* rhythmGroup = "Rhythm"; 81 static constexpr const char* coloursGroup = "Colors"; 82 83 ConfigDescription configList[numConfigItems] = 84 { 85 { midiStartChannel, 2, 1, 16, false, "MIDI Start Channel", ConfigType::integer, {}, midiSettingsGroup }, 86 { midiEndChannel, 16, 1, 16, false, "MIDI End Channel", ConfigType::integer, {}, midiSettingsGroup }, 87 { midiUseMPE, 1, 0, 2, false, "MIDI Mode", ConfigType::options, { "Multi Channel", 88 "MPE", 89 "Single Channel" }, midiSettingsGroup }, 90 { pitchBendRange, 48, 1, 96, false, "Pitch Bend Range", ConfigType::integer, {}, midiSettingsGroup }, 91 { midiChannelRange, 15, 1, 15, false, "No. MIDI Channels", ConfigType::integer, {}, midiSettingsGroup }, 92 { MPEZone, 0, 0, 1, false, "MPE Zone", ConfigType::options, { "Lower Zone", 93 "Upper Zone"}, midiSettingsGroup }, 94 { octave, 0, -4, 6, false, "Octave", ConfigType::integer, {}, pitchGroup }, 95 { transpose, 0, -11, 11, false, "Transpose", ConfigType::integer, {}, pitchGroup }, 96 { slideCC, 74, 0, 127, false, "Slide CC", ConfigType::integer, {}, playGroup }, 97 { slideMode, 0, 0, 2, false, "Slide Mode", ConfigType::options, { "Absolute", 98 "Relative Unipolar", 99 "Relative Bipolar" }, playGroup }, 100 { velocitySensitivity, 100, 0, 127, false, "Strike Sensitivity", ConfigType::integer, {}, sensitivityGroup }, 101 { glideSensitivity, 100, 0, 127, false, "Glide Sensitivity", ConfigType::integer, {}, sensitivityGroup }, 102 { slideSensitivity, 100, 0, 127, false, "Slide Sensitivity", ConfigType::integer, {}, sensitivityGroup }, 103 { pressureSensitivity, 100, 0, 127, false, "Pressure Sensitivity", ConfigType::integer, {}, sensitivityGroup }, 104 { liftSensitivity, 100, 0, 127, false, "Lift Sensitivity", ConfigType::integer, {}, sensitivityGroup }, 105 { fixedVelocity, 0, 0, 1, false, "Fixed Velocity", ConfigType::boolean, {}, sensitivityGroup }, 106 { fixedVelocityValue, 127, 1, 127, false, "Fixed Velocity Value", ConfigType::integer, {}, sensitivityGroup }, 107 { pianoMode, 0, 0, 1, false, "Piano Mode", ConfigType::boolean, {}, playGroup }, 108 { glideLock, 0, 0, 127, false, "Glide Rate", ConfigType::integer, {}, playGroup }, 109 { glideLockEnable, 0, 0, 1, false, "Glide Lock Enable", ConfigType::boolean, {}, playGroup }, 110 { mode, 4, 1, 5, false, "Mode", ConfigType::integer, {}, playGroup }, 111 { volume, 100, 0, 127, false, "Volume", ConfigType::integer, {}, playGroup }, 112 { scale, 0, 0, 18, false, "Scale", ConfigType::integer, {}, playGroup }, // NOTE: Should be options 113 { hideMode, 0, 0, 1, false, "Hide Mode", ConfigType::boolean, {}, playGroup }, 114 { chord, 0, 0, 127, false, "Chord", ConfigType::integer, {}, playGroup }, // NOTE: Should be options 115 { arpPattern, 0, 0, 127, false, "Arp Pattern", ConfigType::integer, {}, playGroup }, 116 { tempo, 120, 1, 300, false, "Tempo", ConfigType::integer, {}, rhythmGroup }, 117 { key, 0, 0, 11, false, "Key", ConfigType::options, { "C", "C#", "D", "D#", 118 "E", "F", "F#", "G", 119 "G#", "A", "A#", "B"}, playGroup }, 120 { autoTransposeToKey, 0, 0, 1, false, "Auto Transpose To Key",ConfigType::boolean, {}, pitchGroup }, 121 { xTrackingMode, 1, 1, 4, false, "Glide Tracking Mode", ConfigType::options, { "Multi-Channel", 122 "Last Played", 123 "Highest", 124 "Lowest", 125 "Disabled" }, playGroup }, 126 { yTrackingMode, 1, 1, 4, false, "Slide Tracking Mode", ConfigType::options, { "Multi-Channel", 127 "Last Played", 128 "Highest", 129 "Lowest", 130 "Disabled" }, playGroup }, 131 { zTrackingMode, 1, 0, 4, false, "Pressure Tracking Mode", ConfigType::options, { "Poly Aftertouch", 132 "Last Played", 133 "Highest", 134 "Lowest", 135 "Disabled", 136 "Hardest" }, playGroup }, 137 138 { gammaCorrection, 0, 0, 1, false, "Gamma Correction", ConfigType::boolean, {}, coloursGroup }, 139 { globalKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Global Key Color", ConfigType::colour, {}, coloursGroup }, 140 { rootKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Root Key Color" , ConfigType::colour, {}, coloursGroup }, 141 { brightness, 100, 0, 100, false, "Brightness", ConfigType::integer, {}, coloursGroup }, 142 143 // These can be defined for unique usage for a given Littlefoot script 144 { user0, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 145 { user1, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 146 { user2, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 147 { user3, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 148 { user4, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 149 { user5, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 150 { user6, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 151 { user7, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 152 { user8, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 153 { user9, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 154 { user10, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 155 { user11, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 156 { user12, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 157 { user13, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 158 { user14, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 159 { user15, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 160 { user16, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 161 { user17, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 162 { user18, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 163 { user19, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 164 { user20, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 165 { user21, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 166 { user22, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 167 { user23, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 168 { user24, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 169 { user25, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 170 { user26, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 171 { user27, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 172 { user28, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 173 { user29, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 174 { user30, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, 175 { user31, 0, 0, 127, false, {}, ConfigType::integer, {}, {} } 176 }; 177 178 //============================================================================== getItemValueBlockConfigManager179 int32 getItemValue (ConfigItemId item) 180 { 181 uint32 itemIndex; 182 183 if (getIndexForItem (item, itemIndex)) 184 return configList[itemIndex].value; 185 186 return 0; 187 } 188 setItemValueBlockConfigManager189 void setItemValue (ConfigItemId item, int32 value) 190 { 191 uint32 itemIndex; 192 193 if (getIndexForItem (item, itemIndex)) 194 configList[itemIndex].value = value; 195 196 setBlockConfig (item, value); 197 } 198 getItemMinBlockConfigManager199 int32 getItemMin (ConfigItemId item) 200 { 201 uint32 itemIndex; 202 203 if (getIndexForItem (item, itemIndex)) 204 return configList[itemIndex].min; 205 206 return 0; 207 } 208 setItemMinBlockConfigManager209 void setItemMin (ConfigItemId item, int32 min) 210 { 211 uint32 itemIndex; 212 213 if (getIndexForItem (item, itemIndex)) 214 configList[itemIndex].min = min; 215 } 216 getItemMaxBlockConfigManager217 int32 getItemMax (ConfigItemId item) 218 { 219 uint32 itemIndex; 220 221 if (getIndexForItem (item, itemIndex)) 222 return configList[itemIndex].max; 223 224 return 0; 225 } 226 setItemMaxBlockConfigManager227 void setItemMax (ConfigItemId item, int32 max) 228 { 229 uint32 itemIndex; 230 231 if (getIndexForItem (item, itemIndex)) 232 configList[itemIndex].max = max; 233 234 // Send updateConfig message to Block 235 } 236 getItemActiveBlockConfigManager237 bool getItemActive (ConfigItemId item) 238 { 239 uint32 itemIndex; 240 241 if (getIndexForItem (item, itemIndex)) 242 return configList[itemIndex].isActive; 243 244 return false; 245 } 246 setItemActiveBlockConfigManager247 void setItemActive (ConfigItemId item, bool isActive) 248 { 249 uint32 itemIndex; 250 251 if (getIndexForItem (item, itemIndex)) 252 configList[itemIndex].isActive = isActive; 253 254 // Send setConfigState message to Block 255 } 256 getOptionNameBlockConfigManager257 String getOptionName (ConfigItemId item, uint8 optionIndex) 258 { 259 uint32 itemIndex; 260 261 if (getIndexForItem (item, itemIndex) && optionIndex < configMaxOptions) 262 return configList[itemIndex].optionNames[optionIndex]; 263 264 return {}; 265 } 266 getMetaDataBlockConfigManager267 Block::ConfigMetaData getMetaData (ConfigItemId item) 268 { 269 uint32 itemIndex; 270 271 if (getIndexForItem (item, itemIndex)) 272 return configList[itemIndex].toConfigMetaData(); 273 274 return { static_cast<juce::uint32> (item) }; 275 } 276 resetConfigListActiveStatusBlockConfigManager277 void resetConfigListActiveStatus() 278 { 279 for (auto& i : configList) 280 i.isActive = false; 281 } 282 283 //============================================================================== 284 // Set Block Configuration setBlockConfigBlockConfigManager285 void setBlockConfig (ConfigItemId item, int32 value) 286 { 287 buildAndSendPacket ([item, value] (HostPacketBuilder<32>& p) { p.addConfigSetMessage (item, value); }); 288 } 289 requestBlockConfigBlockConfigManager290 void requestBlockConfig (ConfigItemId item) 291 { 292 buildAndSendPacket ([item] (HostPacketBuilder<32>& p) { p.addRequestMessage (item); }); 293 } 294 requestFactoryConfigSyncBlockConfigManager295 void requestFactoryConfigSync() 296 { 297 buildAndSendPacket ([] (HostPacketBuilder<32>& p) { p.addRequestFactorySyncMessage(); }); 298 } 299 requestUserConfigSyncBlockConfigManager300 void requestUserConfigSync() 301 { 302 buildAndSendPacket ([] (HostPacketBuilder<32>& p) { p.addRequestUserSyncMessage(); }); 303 } 304 handleConfigUpdateMessageBlockConfigManager305 void handleConfigUpdateMessage (int32 item, int32 value, int32 min, int32 max) 306 { 307 uint32 index; 308 309 if (getIndexForItem ((ConfigItemId) item, index)) 310 { 311 configList[index].value = value; 312 configList[index].min = min; 313 configList[index].max = max; 314 configList[index].isActive = true; 315 } 316 } 317 handleConfigSetMessageBlockConfigManager318 void handleConfigSetMessage(int32 item, int32 value) 319 { 320 uint32 index; 321 322 if (getIndexForItem ((ConfigItemId) item, index)) 323 configList[index].value = value; 324 } 325 326 private: getIndexForItemBlockConfigManager327 bool getIndexForItem (ConfigItemId item, uint32& index) 328 { 329 for (uint32 i = 0; i < numConfigItems; ++i) 330 { 331 if (configList[i].item == item) 332 { 333 index = i; 334 return true; 335 } 336 } 337 338 return false; 339 } 340 341 template <typename PacketBuildFn> buildAndSendPacketBlockConfigManager342 void buildAndSendPacket (PacketBuildFn buildFn) 343 { 344 if (deviceConnection == nullptr) 345 return; 346 347 HostPacketBuilder<32> packet; 348 packet.writePacketSysexHeaderBytes (deviceIndex); 349 buildFn (packet); 350 packet.writePacketSysexFooter(); 351 deviceConnection->sendMessageToDevice (packet.getData(), (size_t) packet.size()); 352 } 353 354 TopologyIndex deviceIndex {}; 355 PhysicalTopologySource::DeviceConnection* deviceConnection {}; 356 }; 357 358 } // namespace juce 359