The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

569 lines
18KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. The code included in this file is provided under the terms of the ISC license
  8. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  9. To use, copy, modify, and/or distribute this software for any purpose with or
  10. without fee is hereby granted provided that the above copyright notice and
  11. this permission notice appear in all copies.
  12. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  13. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  14. DISCLAIMED.
  15. ==============================================================================
  16. */
  17. namespace juce
  18. {
  19. namespace BlocksProtocol
  20. {
  21. /** This value is incremented when the format of the API changes in a way which
  22. breaks compatibility.
  23. */
  24. static constexpr uint32 currentProtocolVersion = 1;
  25. using ProtocolVersion = IntegerWithBitSize<8>;
  26. //==============================================================================
  27. /** A timestamp for a packet, in milliseconds since device boot-up */
  28. using PacketTimestamp = IntegerWithBitSize<32>;
  29. /** This relative timestamp is for use inside a packet, and it represents a
  30. number of milliseconds that should be added to the packet's timestamp.
  31. */
  32. using PacketTimestampOffset = IntegerWithBitSize<5>;
  33. //==============================================================================
  34. /** Messages that a device may send to the host. */
  35. enum class MessageFromDevice
  36. {
  37. deviceTopology = 0x01,
  38. packetACK = 0x02,
  39. firmwareUpdateACK = 0x03,
  40. deviceTopologyExtend = 0x04,
  41. deviceTopologyEnd = 0x05,
  42. deviceVersion = 0x06,
  43. deviceName = 0x07,
  44. touchStart = 0x10,
  45. touchMove = 0x11,
  46. touchEnd = 0x12,
  47. touchStartWithVelocity = 0x13,
  48. touchMoveWithVelocity = 0x14,
  49. touchEndWithVelocity = 0x15,
  50. configMessage = 0x18,
  51. controlButtonDown = 0x20,
  52. controlButtonUp = 0x21,
  53. programEventMessage = 0x28,
  54. logMessage = 0x30
  55. };
  56. /** Messages that the host may send to a device. */
  57. enum class MessageFromHost
  58. {
  59. deviceCommandMessage = 0x01,
  60. sharedDataChange = 0x02,
  61. programEventMessage = 0x03,
  62. firmwareUpdatePacket = 0x04,
  63. configMessage = 0x10,
  64. factoryReset = 0x11,
  65. blockReset = 0x12,
  66. setName = 0x20
  67. };
  68. /** This is the first item in a BLOCKS message, identifying the message type. */
  69. using MessageType = IntegerWithBitSize<7>;
  70. //==============================================================================
  71. /** This is a type of index identifier used to refer to a block within a group.
  72. It refers to the index of a device in the list of devices that was most recently
  73. sent via a topology change message
  74. (It's not a global UID for a block unit).
  75. NB: to send a message to all devices, pass the getDeviceIndexForBroadcast() value.
  76. */
  77. using TopologyIndex = uint8;
  78. static constexpr int topologyIndexBits = 7;
  79. /** Use this value as the index if you want a message to be sent to all devices in
  80. the group.
  81. */
  82. static constexpr TopologyIndex topologyIndexForBroadcast = 63;
  83. using DeviceCount = IntegerWithBitSize<7>;
  84. using ConnectionCount = IntegerWithBitSize<8>;
  85. //==============================================================================
  86. /** Battery charge level. */
  87. using BatteryLevel = IntegerWithBitSize<5>;
  88. /** Battery charger connection flag. */
  89. using BatteryCharging = IntegerWithBitSize<1>;
  90. //==============================================================================
  91. /** ConnectorPort is an index, starting at 0 for the leftmost port on the
  92. top edge, and going clockwise.
  93. */
  94. using ConnectorPort = IntegerWithBitSize<5>;
  95. //==============================================================================
  96. /** Structure describing a block's serial number
  97. @tags{Blocks}
  98. */
  99. struct BlockSerialNumber
  100. {
  101. uint8 serial[16];
  102. bool isValid() const noexcept
  103. {
  104. for (auto c : serial)
  105. if (c == 0)
  106. return false;
  107. return isAnyControlBlock() || isPadBlock() || isSeaboardBlock();
  108. }
  109. bool isPadBlock() const noexcept { return hasPrefix ("LPB") || hasPrefix ("LPM"); }
  110. bool isLiveBlock() const noexcept { return hasPrefix ("LIC"); }
  111. bool isLoopBlock() const noexcept { return hasPrefix ("LOC"); }
  112. bool isDevCtrlBlock() const noexcept { return hasPrefix ("DCB"); }
  113. bool isTouchBlock() const noexcept { return hasPrefix ("TCB"); }
  114. bool isSeaboardBlock() const noexcept { return hasPrefix ("SBB"); }
  115. bool isAnyControlBlock() const noexcept { return isLiveBlock() || isLoopBlock() || isDevCtrlBlock() || isTouchBlock(); }
  116. bool hasPrefix (const char* prefix) const noexcept { return memcmp (serial, prefix, 3) == 0; }
  117. };
  118. //==============================================================================
  119. /** Structure for the version number
  120. @tags{Blocks}
  121. */
  122. struct VersionNumber
  123. {
  124. uint8 version[21] = {};
  125. uint8 length = 0;
  126. juce::String asString() const
  127. {
  128. return juce::String (reinterpret_cast<const char*> (version),
  129. std::min (sizeof (version), static_cast<size_t> (length)));
  130. }
  131. };
  132. //==============================================================================
  133. /** Structure for the block name
  134. @tags{Blocks}
  135. */
  136. struct BlockName
  137. {
  138. uint8 name[33] = {};
  139. uint8 length = 0;
  140. bool isValid() const { return length > 0; }
  141. juce::String asString() const
  142. {
  143. return juce::String (reinterpret_cast<const char*> (name),
  144. std::min (sizeof (name), static_cast<size_t> (length)));
  145. }
  146. };
  147. //==============================================================================
  148. /** Structure for the device status
  149. @tags{Blocks}
  150. */
  151. struct DeviceStatus
  152. {
  153. BlockSerialNumber serialNumber;
  154. TopologyIndex index;
  155. BatteryLevel batteryLevel;
  156. BatteryCharging batteryCharging;
  157. };
  158. //==============================================================================
  159. /** Structure for the device connection
  160. @tags{Blocks}
  161. */
  162. struct DeviceConnection
  163. {
  164. TopologyIndex device1, device2;
  165. ConnectorPort port1, port2;
  166. };
  167. //==============================================================================
  168. /** Structure for the device version
  169. @tags{Blocks}
  170. */
  171. struct DeviceVersion
  172. {
  173. TopologyIndex index;
  174. VersionNumber version;
  175. };
  176. //==============================================================================
  177. /** Structure used for the device name
  178. @tags{Blocks}
  179. */
  180. struct DeviceName
  181. {
  182. TopologyIndex index;
  183. BlockName name;
  184. };
  185. static constexpr uint8 maxBlocksInTopologyPacket = 6;
  186. static constexpr uint8 maxConnectionsInTopologyPacket = 24;
  187. //==============================================================================
  188. /** Configuration Item Identifiers. */
  189. enum ConfigItemId
  190. {
  191. // MIDI
  192. midiStartChannel = 0,
  193. midiEndChannel = 1,
  194. midiUseMPE = 2,
  195. pitchBendRange = 3,
  196. octave = 4,
  197. transpose = 5,
  198. slideCC = 6,
  199. slideMode = 7,
  200. octaveTopology = 8,
  201. midiChannelRange = 9,
  202. MPEZone = 40,
  203. // Touch
  204. velocitySensitivity = 10,
  205. glideSensitivity = 11,
  206. slideSensitivity = 12,
  207. pressureSensitivity = 13,
  208. liftSensitivity = 14,
  209. fixedVelocity = 15,
  210. fixedVelocityValue = 16,
  211. pianoMode = 17,
  212. glideLock = 18,
  213. glideLockEnable = 19,
  214. // Live
  215. mode = 20,
  216. volume = 21,
  217. scale = 22,
  218. hideMode = 23,
  219. chord = 24,
  220. arpPattern = 25,
  221. tempo = 26,
  222. // Tracking
  223. xTrackingMode = 30,
  224. yTrackingMode = 31,
  225. zTrackingMode = 32,
  226. // Graphics
  227. gammaCorrection = 33,
  228. // User
  229. user0 = 64,
  230. user1 = 65,
  231. user2 = 66,
  232. user3 = 67,
  233. user4 = 68,
  234. user5 = 69,
  235. user6 = 70,
  236. user7 = 71,
  237. user8 = 72,
  238. user9 = 73,
  239. user10 = 74,
  240. user11 = 75,
  241. user12 = 76,
  242. user13 = 77,
  243. user14 = 78,
  244. user15 = 79,
  245. user16 = 80,
  246. user17 = 81,
  247. user18 = 82,
  248. user19 = 83,
  249. user20 = 84,
  250. user21 = 85,
  251. user22 = 86,
  252. user23 = 87,
  253. user24 = 88,
  254. user25 = 89,
  255. user26 = 90,
  256. user27 = 91,
  257. user28 = 92,
  258. user29 = 93,
  259. user30 = 94,
  260. user31 = 95
  261. };
  262. static constexpr uint8 numberOfUserConfigs = 32;
  263. static constexpr uint8 maxConfigIndex = uint8 (ConfigItemId::user0) + numberOfUserConfigs;
  264. static constexpr uint8 configUserConfigNameLength = 32;
  265. static constexpr uint8 configMaxOptions = 8;
  266. static constexpr uint8 configOptionNameLength = 16;
  267. //==============================================================================
  268. /** The coordinates of a touch.
  269. @tags{Blocks}
  270. */
  271. struct TouchPosition
  272. {
  273. using Xcoord = IntegerWithBitSize<12>;
  274. using Ycoord = IntegerWithBitSize<12>;
  275. using Zcoord = IntegerWithBitSize<8>;
  276. Xcoord x;
  277. Ycoord y;
  278. Zcoord z;
  279. enum { bits = Xcoord::bits + Ycoord::bits + Zcoord::bits };
  280. };
  281. /** The velocities for each dimension of a touch.
  282. @tags{Blocks}
  283. */
  284. struct TouchVelocity
  285. {
  286. using VXcoord = IntegerWithBitSize<8>;
  287. using VYcoord = IntegerWithBitSize<8>;
  288. using VZcoord = IntegerWithBitSize<8>;
  289. VXcoord vx;
  290. VYcoord vy;
  291. VZcoord vz;
  292. enum { bits = VXcoord::bits + VYcoord::bits + VZcoord::bits };
  293. };
  294. /** The index of a touch, i.e. finger number. */
  295. using TouchIndex = IntegerWithBitSize<5>;
  296. using PacketCounter = IntegerWithBitSize<10>;
  297. //==============================================================================
  298. enum DeviceCommands
  299. {
  300. beginAPIMode = 0x00,
  301. requestTopologyMessage = 0x01,
  302. endAPIMode = 0x02,
  303. ping = 0x03,
  304. debugMode = 0x04,
  305. saveProgramAsDefault = 0x05
  306. };
  307. using DeviceCommand = IntegerWithBitSize<9>;
  308. //==============================================================================
  309. enum ConfigCommands
  310. {
  311. setConfig = 0x00,
  312. requestConfig = 0x01, // Request a config update
  313. requestFactorySync = 0x02, // Requests all active factory config data
  314. requestUserSync = 0x03, // Requests all active user config data
  315. updateConfig = 0x04, // Set value, min and max
  316. updateUserConfig = 0x05, // As above but contains user config metadata
  317. setConfigState = 0x06, // Set config activation state and whether it is saved in flash
  318. factorySyncEnd = 0x07,
  319. clusterConfigSync = 0x08,
  320. factorySyncReset = 0x09
  321. };
  322. using ConfigCommand = IntegerWithBitSize<4>;
  323. using ConfigItemIndex = IntegerWithBitSize<8>;
  324. using ConfigItemValue = IntegerWithBitSize<32>;
  325. //==============================================================================
  326. /** An ID for a control-block button type */
  327. using ControlButtonID = IntegerWithBitSize<12>;
  328. //==============================================================================
  329. using RotaryDialIndex = IntegerWithBitSize<7>;
  330. using RotaryDialAngle = IntegerWithBitSize<14>;
  331. using RotaryDialDelta = IntegerWithBitSize<14>;
  332. //==============================================================================
  333. enum DataChangeCommands
  334. {
  335. endOfPacket = 0,
  336. endOfChanges = 1,
  337. skipBytesFew = 2,
  338. skipBytesMany = 3,
  339. setSequenceOfBytes = 4,
  340. setFewBytesWithValue = 5,
  341. setFewBytesWithLastValue = 6,
  342. setManyBytesWithValue = 7
  343. };
  344. using PacketIndex = IntegerWithBitSize<16>;
  345. using DataChangeCommand = IntegerWithBitSize<3>;
  346. using ByteCountFew = IntegerWithBitSize<4>;
  347. using ByteCountMany = IntegerWithBitSize<8>;
  348. using ByteValue = IntegerWithBitSize<8>;
  349. using ByteSequenceContinues = IntegerWithBitSize<1>;
  350. using FirmwareUpdateACKCode = IntegerWithBitSize<7>;
  351. using FirmwareUpdateACKDetail = IntegerWithBitSize<32>;
  352. using FirmwareUpdatePacketSize = IntegerWithBitSize<7>;
  353. static constexpr uint32 numProgramMessageInts = 3;
  354. static constexpr uint32 apiModeHostPingTimeoutMs = 5000;
  355. static constexpr uint32 padBlockProgramAndHeapSize = 7200;
  356. static constexpr uint32 padBlockStackSize = 800;
  357. static constexpr uint32 controlBlockProgramAndHeapSize = 3000;
  358. static constexpr uint32 controlBlockStackSize = 800;
  359. //==============================================================================
  360. /** Contains the number of bits required to encode various items in the packets */
  361. enum BitSizes
  362. {
  363. topologyMessageHeader = MessageType::bits + ProtocolVersion::bits + DeviceCount::bits + ConnectionCount::bits,
  364. topologyDeviceInfo = sizeof (BlockSerialNumber) * 7 + BatteryLevel::bits + BatteryCharging::bits,
  365. topologyConnectionInfo = topologyIndexBits + ConnectorPort::bits + topologyIndexBits + ConnectorPort::bits,
  366. typeDeviceAndTime = MessageType::bits + PacketTimestampOffset::bits,
  367. touchMessage = typeDeviceAndTime + TouchIndex::bits + TouchPosition::bits,
  368. touchMessageWithVelocity = touchMessage + TouchVelocity::bits,
  369. programEventMessage = MessageType::bits + 32 * numProgramMessageInts,
  370. packetACK = MessageType::bits + PacketCounter::bits,
  371. firmwareUpdateACK = MessageType::bits + FirmwareUpdateACKCode::bits + FirmwareUpdateACKDetail::bits,
  372. controlButtonMessage = typeDeviceAndTime + ControlButtonID::bits,
  373. configSetMessage = MessageType::bits + ConfigCommand::bits + ConfigItemIndex::bits + ConfigItemValue::bits,
  374. configRespMessage = MessageType::bits + ConfigCommand::bits + ConfigItemIndex::bits + (ConfigItemValue::bits * 3),
  375. configSyncEndMessage = MessageType::bits + ConfigCommand::bits,
  376. };
  377. //==============================================================================
  378. // These are the littlefoot functions provided for use in BLOCKS programs
  379. static constexpr const char* ledProgramLittleFootFunctions[] =
  380. {
  381. "min/iii",
  382. "min/fff",
  383. "max/iii",
  384. "max/fff",
  385. "clamp/iiii",
  386. "clamp/ffff",
  387. "abs/ii",
  388. "abs/ff",
  389. "map/ffffff",
  390. "map/ffff",
  391. "mod/iii",
  392. "getRandomFloat/f",
  393. "getRandomInt/ii",
  394. "log/vi",
  395. "logHex/vi",
  396. "getMillisecondCounter/i",
  397. "getFirmwareVersion/i",
  398. "getTimeInCurrentFunctionCall/i",
  399. "getBatteryLevel/f",
  400. "isBatteryCharging/b",
  401. "isMasterBlock/b",
  402. "isConnectedToHost/b",
  403. "setStatusOverlayActive/vb",
  404. "getNumBlocksInTopology/i",
  405. "getBlockIDForIndex/ii",
  406. "getBlockIDOnPort/ii",
  407. "getPortToMaster/i",
  408. "getBlockTypeForID/ii",
  409. "sendMessageToBlock/viiii",
  410. "sendMessageToHost/viii",
  411. "getHorizontalDistFromMaster/i",
  412. "getVerticalDistFromMaster/i",
  413. "getAngleFromMaster/i",
  414. "setAutoRotate/vb",
  415. "getClusterIndex/i",
  416. "getClusterWidth/i",
  417. "getClusterHeight/i",
  418. "getClusterXpos/i",
  419. "getClusterYpos/i",
  420. "getNumBlocksInCurrentCluster/i",
  421. "getBlockIdForBlockInCluster/ii",
  422. "isMasterInCurrentCluster/b",
  423. "setClusteringActive/vb",
  424. "makeARGB/iiiii",
  425. "blendARGB/iii",
  426. "fillPixel/viii",
  427. "blendPixel/viii",
  428. "fillRect/viiiii",
  429. "blendRect/viiiii",
  430. "blendGradientRect/viiiiiiii",
  431. "blendCircle/vifffb",
  432. "addPressurePoint/vifff",
  433. "drawPressureMap/v",
  434. "fadePressureMap/v",
  435. "drawNumber/viiii",
  436. "clearDisplay/v",
  437. "clearDisplay/vi",
  438. "displayBatteryLevel/v",
  439. "sendMIDI/vi",
  440. "sendMIDI/vii",
  441. "sendMIDI/viii",
  442. "sendNoteOn/viii",
  443. "sendNoteOff/viii",
  444. "sendAftertouch/viii",
  445. "sendCC/viii",
  446. "sendPitchBend/vii",
  447. "sendPitchBend/viii",
  448. "sendChannelPressure/vii",
  449. "addPitchCorrectionPad/viiffff",
  450. "setPitchCorrectionEnabled/vb",
  451. "getPitchCorrectionPitchBend/iii",
  452. "setChannelRange/vbii",
  453. "assignChannel/ii",
  454. "deassignChannel/vii",
  455. "getControlChannel/i",
  456. "useMPEDuplicateFilter/vb",
  457. "getSensorValue/iii",
  458. "handleTouchAsSeaboard/vi",
  459. "setPowerSavingEnabled/vb",
  460. "getLocalConfig/ii",
  461. "setLocalConfig/vii",
  462. "requestRemoteConfig/vii",
  463. "setRemoteConfig/viii",
  464. "setLocalConfigItemRange/viii",
  465. "setLocalConfigActiveState/vibb",
  466. "linkBlockIDtoController/vi",
  467. "repaintControl/v",
  468. "onControlPress/vi",
  469. "onControlRelease/vi",
  470. "initControl/viiiiiiiii",
  471. "setButtonMode/vii",
  472. "setButtonType/viii",
  473. "setButtonMinMaxDefault/viiii",
  474. "setButtonColours/viii",
  475. "setButtonTriState/vii",
  476. nullptr
  477. };
  478. } // namespace BlocksProtocol
  479. } // namespace juce