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.

553 lines
21KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  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. /**
  20. Represents an individual BLOCKS device.
  21. @tags{Blocks}
  22. */
  23. class Block : public ReferenceCountedObject
  24. {
  25. public:
  26. //==============================================================================
  27. /** Destructor. */
  28. ~Block() override;
  29. /** The different block types.
  30. @see Block::getType()
  31. */
  32. enum Type
  33. {
  34. unknown = 0, /**< Unknown block type. */
  35. lightPadBlock, /**< Lightpad block type. */
  36. liveBlock, /**< Live control block type. */
  37. loopBlock, /**< Loop control block type. */
  38. developerControlBlock, /**< Developer control block type. */
  39. touchBlock, /**< Touch control block type. */
  40. seaboardBlock, /**< Seaboard block type. */
  41. lumiKeysBlock /**< LUMI Keys block type */
  42. };
  43. /** The Block class is reference-counted, so always use a Block::Ptr when
  44. you are keeping references to them.
  45. */
  46. using Ptr = ReferenceCountedObjectPtr<Block>;
  47. /** The Block class is reference-counted, so Block::Array is useful when
  48. you are storing lists of them.
  49. */
  50. using Array = ReferenceCountedArray<Block>;
  51. /** The Block's serial number. */
  52. const String serialNumber;
  53. /** The Block's version number */
  54. String versionNumber;
  55. /** The Block's name */
  56. String name;
  57. /** This type is used for the unique block identifier. */
  58. using UID = uint64;
  59. /** This Block's UID.
  60. This will be globally unique, and remains constant for a particular device.
  61. */
  62. const UID uid;
  63. //==============================================================================
  64. /** Two blocks are considered equal if they have the same UID. */
  65. bool operator== (const Block& other) const noexcept { return uid == other.uid; }
  66. /** Two blocks are considered equal if they have the same UID. */
  67. bool operator!= (const Block& other) const noexcept { return uid != other.uid; }
  68. //==============================================================================
  69. /** Returns the type of this device.
  70. @see Block::Type
  71. */
  72. virtual Type getType() const = 0;
  73. /** Returns true if this a control block. **/
  74. bool isControlBlock() const;
  75. /** Returns true if Block::Type is a control block. */
  76. static bool isControlBlock (Block::Type);
  77. /** Returns a human-readable description of this device type. */
  78. virtual String getDeviceDescription() const = 0;
  79. /** Returns the battery level in the range 0.0 to 1.0. */
  80. virtual float getBatteryLevel() const = 0;
  81. /** Returns true if the battery is charging. */
  82. virtual bool isBatteryCharging() const = 0;
  83. //==============================================================================
  84. /** Returns true if this block is connected and active. */
  85. virtual bool isConnected() const = 0;
  86. /** Returns the time this block object was connected to the topology.
  87. Only valid when isConnected == true.
  88. @see Block::isConnected
  89. */
  90. virtual Time getConnectionTime() const = 0;
  91. /** Returns true if this block or the master block this block is connected to,
  92. is connected via bluetooth.
  93. Only valid when isConnected == true.
  94. @see Block::isConnected, Block::isMasterBlock
  95. */
  96. virtual bool isConnectedViaBluetooth() const = 0;
  97. /** Returns true if this block is directly connected to the application,
  98. as opposed to only being connected to a different block via a connection port.
  99. @see Block::ConnectionPort
  100. */
  101. virtual bool isMasterBlock() const = 0;
  102. /** Returns the UID of the master block this block is connected to. */
  103. virtual UID getConnectedMasterUID() const = 0;
  104. //==============================================================================
  105. /** Returns the width of the device in logical device units. */
  106. virtual int getWidth() const = 0;
  107. /** Returns the height of the device in logical device units. */
  108. virtual int getHeight() const = 0;
  109. /** Returns true if the device is a physical hardware block (i.e. not a virtual block). */
  110. virtual bool isHardwareBlock() const = 0;
  111. /** Returns the length of one logical device unit as physical millimeters. */
  112. virtual float getMillimetersPerUnit() const = 0;
  113. /** A simple struct representing the area of a block. */
  114. struct BlockArea
  115. {
  116. int x, y, width, height;
  117. };
  118. /** Returns the area that this block covers within the layout of the group as a whole.
  119. The coordinates are in logical block units, and are relative to the origin, which is the master block's top-left corner.
  120. */
  121. virtual BlockArea getBlockAreaWithinLayout() const = 0;
  122. /** Returns the rotation of this block relative to the master block in 90 degree steps clockwise. */
  123. virtual int getRotation() const = 0;
  124. //==============================================================================
  125. /** If this block has a grid of LEDs, this will return an object to control it.
  126. Note that the pointer that is returned belongs to this object, and the caller must
  127. neither delete it or use it after the lifetime of this Block object has finished.
  128. If there are no LEDs, then this method will return nullptr.
  129. */
  130. virtual LEDGrid* getLEDGrid() const = 0;
  131. /** If this block has a row of LEDs, this will return an object to control it.
  132. Note that the pointer that is returned belongs to this object, and the caller must
  133. neither delete it or use it after the lifetime of this Block object has finished.
  134. If there are no LEDs, then this method will return nullptr.
  135. */
  136. virtual LEDRow* getLEDRow() = 0;
  137. /** If this block has any status LEDs, this will return an array of objects to control them.
  138. Note that the objects in the array belong to this Block object, and the caller must
  139. neither delete them or use them after the lifetime of this Block object has finished.
  140. */
  141. virtual juce::Array<StatusLight*> getStatusLights() const = 0;
  142. /** If this block has a pressure-sensitive surface, this will return an object to
  143. access its data.
  144. Note that the pointer returned does is owned by this object, and the caller must
  145. neither delete it or use it after the lifetime of this Block object has finished.
  146. If the device is not touch-sensitive, then this method will return nullptr.
  147. */
  148. virtual TouchSurface* getTouchSurface() const = 0;
  149. /** If this block has any control buttons, this will return an array of objects to control them.
  150. Note that the objects in the array belong to this Block object, and the caller must
  151. neither delete them or use them after the lifetime of this Block object has finished.
  152. */
  153. virtual juce::Array<ControlButton*> getButtons() const = 0;
  154. //==============================================================================
  155. /** This returns true if the block supports generating graphics by drawing into a JUCE
  156. Graphics context. This should only be true for virtual on-screen blocks; hardware
  157. blocks will instead use the LED Grid for visuals.
  158. */
  159. virtual bool supportsGraphics() const = 0;
  160. //==============================================================================
  161. /** These are the edge-connectors that a device may have. */
  162. struct ConnectionPort
  163. {
  164. enum class DeviceEdge
  165. {
  166. north,
  167. south,
  168. east,
  169. west
  170. };
  171. /** The side of the device on which this port is located. */
  172. DeviceEdge edge;
  173. /** The index of this port along the device edge.
  174. For north and south edges, index 0 is the left-most port.
  175. For east and west edges, index 0 is the top-most port.
  176. */
  177. int index;
  178. bool operator== (const ConnectionPort&) const noexcept;
  179. bool operator!= (const ConnectionPort&) const noexcept;
  180. };
  181. /** Returns a list of the connectors that this device has. */
  182. virtual juce::Array<ConnectionPort> getPorts() const = 0;
  183. //==============================================================================
  184. /** A program that can be loaded onto a block. */
  185. struct Program
  186. {
  187. Program (Block&);
  188. virtual ~Program() = default;
  189. /** Returns the LittleFoot program to execute on the BLOCKS device. */
  190. virtual String getLittleFootProgram() = 0;
  191. /** Returns an array of search paths to use when resolving includes. **/
  192. virtual juce::Array<File> getSearchPaths() { return {}; }
  193. Block& block;
  194. };
  195. /** Sets the Program to run on this block.
  196. The supplied Program's lifetime will be managed by this class, so do not
  197. use the Program in other places in your code.
  198. Optional parameter to determine if program is set temporarily or saved
  199. to flash as the default prgram./
  200. */
  201. enum class ProgramPersistency { setAsTemp, setAsDefault };
  202. virtual Result setProgram (std::unique_ptr<Program>,
  203. ProgramPersistency persistency = ProgramPersistency::setAsTemp) = 0;
  204. /** Returns a pointer to the currently loaded program. */
  205. virtual Program* getProgram() const = 0;
  206. /** Listener interface to be informed of program loaded events*/
  207. struct ProgramLoadedListener
  208. {
  209. virtual ~ProgramLoadedListener() = default;
  210. /** Called whenever a program has been loaded. */
  211. virtual void handleProgramLoaded (Block&) = 0;
  212. };
  213. /** Adds a new listener for program load completions. */
  214. void addProgramLoadedListener (ProgramLoadedListener*);
  215. /** Removes a listener for program load completions. */
  216. void removeProgramLoadedListener (ProgramLoadedListener*);
  217. //==============================================================================
  218. /** A message that can be sent to the currently loaded program. */
  219. struct ProgramEventMessage
  220. {
  221. int32 values[3];
  222. };
  223. /** Sends a message to the currently loaded program.
  224. To receive the message the program must provide a littlefoot function called
  225. handleMessage with the following form:
  226. @code
  227. void handleMessage (int param1, int param2, int param3)
  228. {
  229. // Do something with the two integer parameters that the app has sent...
  230. }
  231. @endcode
  232. */
  233. virtual void sendProgramEvent (const ProgramEventMessage&) = 0;
  234. /** Interface for objects listening to custom program events. */
  235. struct ProgramEventListener
  236. {
  237. virtual ~ProgramEventListener() = default;
  238. /** Called whenever a message from a block is received. */
  239. virtual void handleProgramEvent (Block& source, const ProgramEventMessage&) = 0;
  240. };
  241. /** Adds a new listener for custom program events from the block. */
  242. void addProgramEventListener (ProgramEventListener*);
  243. /** Removes a listener for custom program events from the block. */
  244. void removeProgramEventListener (ProgramEventListener*);
  245. //==============================================================================
  246. /** Returns the overall memory of the block. */
  247. virtual uint32 getMemorySize() = 0;
  248. /** Returns the size of the data block that setDataByte and other functions can write to. */
  249. virtual uint32 getHeapMemorySize() = 0;
  250. /** Sets a single byte on the littlefoot heap. */
  251. virtual void setDataByte (size_t offset, uint8 value) = 0;
  252. /** Sets multiple bytes on the littlefoot heap. */
  253. virtual void setDataBytes (size_t offset, const void* data, size_t num) = 0;
  254. /** Sets multiple bits on the littlefoot heap. */
  255. virtual void setDataBits (uint32 startBit, uint32 numBits, uint32 value) = 0;
  256. /** Sets a single, 32 bit or less, value on the littlefoot heap. */
  257. template<typename Type>
  258. void setData (uint32 offset, Type value)
  259. {
  260. const auto numBytes = sizeof (Type);
  261. for (auto byte = numBytes; --byte > 0u;)
  262. {
  263. auto v = *reinterpret_cast<unsigned*> (&value);
  264. v = (v >> (numBytes - byte) * 8) & 0xFF;
  265. setDataByte (offset + byte, uint8 (v));
  266. }
  267. }
  268. /** Gets a byte from the littlefoot heap. */
  269. virtual uint8 getDataByte (size_t offset) = 0;
  270. /** Sets the current program as the block's default state. */
  271. virtual void saveProgramAsDefault() = 0;
  272. /** Resets the loaded program to the block's default state. */
  273. virtual void resetProgramToDefault() = 0;
  274. //==============================================================================
  275. /** Metadata for a given config item */
  276. struct ConfigMetaData
  277. {
  278. static constexpr int32 numOptionNames = 16;
  279. enum class ConfigType
  280. {
  281. integer,
  282. floating,
  283. boolean,
  284. colour,
  285. options
  286. };
  287. ConfigMetaData (uint32 itemIndex)
  288. : item (itemIndex)
  289. {}
  290. // Constructor to work around VS2015 bugs...
  291. ConfigMetaData (uint32 itemIndex,
  292. int32 itemValue,
  293. Range<int32> rangeToUse,
  294. bool active,
  295. const char* itemName,
  296. ConfigType itemType,
  297. const char* options[ConfigMetaData::numOptionNames],
  298. const char* groupName)
  299. : item (itemIndex),
  300. value (itemValue),
  301. range (rangeToUse),
  302. isActive (active),
  303. name (itemName),
  304. type (itemType),
  305. group (groupName)
  306. {
  307. for (int i = 0; i < numOptionNames; ++i)
  308. optionNames[i] = options[i];
  309. }
  310. ConfigMetaData (const ConfigMetaData& other)
  311. {
  312. *this = other;
  313. }
  314. const ConfigMetaData& operator= (const ConfigMetaData& other)
  315. {
  316. if (this != &other)
  317. {
  318. item = other.item;
  319. value = other.value;
  320. range = other.range;
  321. isActive = other.isActive;
  322. name = other.name;
  323. type = other.type;
  324. group = other.group;
  325. for (int i = 0; i < numOptionNames; ++i)
  326. optionNames[i] = other.optionNames[i];
  327. }
  328. return *this;
  329. }
  330. bool operator== (const ConfigMetaData& other) const
  331. {
  332. for (int32 optionIndex = 0; optionIndex < numOptionNames; ++optionIndex)
  333. if (optionNames[optionIndex] != other.optionNames[optionIndex])
  334. return false;
  335. return item == other.item
  336. && value == other.value
  337. && range == other.range
  338. && isActive == other.isActive
  339. && name == other.name
  340. && group == other.group;
  341. }
  342. bool operator != (const ConfigMetaData& other) const
  343. {
  344. return ! (*this == other);
  345. }
  346. uint32 item = 0;
  347. int32 value = 0;
  348. Range<int32> range;
  349. bool isActive = false;
  350. String name;
  351. ConfigType type = ConfigType::integer;
  352. String optionNames[numOptionNames] = {};
  353. String group;
  354. };
  355. /** Listener interface to be informed of block config changes */
  356. struct ConfigItemListener
  357. {
  358. virtual ~ConfigItemListener() = default;
  359. /** Called whenever a config changes. */
  360. virtual void handleConfigItemChanged (Block&, const ConfigMetaData&, uint32 index) = 0;
  361. /*-* Callled following a config sync request*/
  362. virtual void handleConfigSyncEnded (Block&) = 0;
  363. };
  364. /** Adds a new listener for config item changes. */
  365. void addConfigItemListener (ConfigItemListener*);
  366. /** Removes a listener for config item changes. */
  367. void removeConfigItemListener (ConfigItemListener*);
  368. /** Returns the maximum number of config items available */
  369. virtual uint32 getMaxConfigIndex() = 0;
  370. /** Determine if this is a valid config item index */
  371. virtual bool isValidUserConfigIndex (uint32 item) = 0;
  372. /** Get local config item value */
  373. virtual int32 getLocalConfigValue (uint32 item) = 0;
  374. /** Set local config item value */
  375. virtual void setLocalConfigValue (uint32 item, int32 value) = 0;
  376. /** Set local config item range */
  377. virtual void setLocalConfigRange (uint32 item, int32 min, int32 max) = 0;
  378. /** Set if config item is active or not */
  379. virtual void setLocalConfigItemActive (uint32 item, bool isActive) = 0;
  380. /** Determine if config item is active or not */
  381. virtual bool isLocalConfigItemActive (uint32 item) = 0;
  382. /** Get config item metadata */
  383. virtual ConfigMetaData getLocalConfigMetaData (uint32 item) = 0;
  384. /** Request sync of factory config with block */
  385. virtual void requestFactoryConfigSync() = 0;
  386. /** Reset all items active status */
  387. virtual void resetConfigListActiveStatus() = 0;
  388. /** Perform factory reset on Block */
  389. virtual void factoryReset() = 0;
  390. /** Reset this Block */
  391. virtual void blockReset() = 0;
  392. /** Set Block name */
  393. virtual bool setName (const String& name) = 0;
  394. //==============================================================================
  395. /** Allows the user to provide a function that will receive log messages from the block. */
  396. virtual void setLogger (std::function<void (const Block& block, const String&)> loggingCallback) = 0;
  397. /** Sends a firmware update packet to a block, and waits for a reply. Returns an error code. */
  398. virtual bool sendFirmwareUpdatePacket (const uint8* data, uint8 size,
  399. std::function<void (uint8, uint32)> packetAckCallback) = 0;
  400. //==============================================================================
  401. /** Interface for objects listening to input data port. */
  402. struct DataInputPortListener
  403. {
  404. virtual ~DataInputPortListener() = default;
  405. /** Called whenever a message from a block is received. */
  406. virtual void handleIncomingDataPortMessage (Block& source, const void* messageData, size_t messageSize) = 0;
  407. };
  408. /** Adds a new listener for the data input port. */
  409. virtual void addDataInputPortListener (DataInputPortListener*);
  410. /** Removes a listener for the data input port. */
  411. virtual void removeDataInputPortListener (DataInputPortListener*);
  412. /** Sends a message to the block. */
  413. virtual void sendMessage (const void* messageData, size_t messageSize) = 0;
  414. //==============================================================================
  415. /** This type is used for timestamping events. It represents a number of milliseconds since the block
  416. device was booted.
  417. */
  418. using Timestamp = uint32;
  419. protected:
  420. //==============================================================================
  421. Block (const String& serialNumberToUse);
  422. Block (const String& serial, const String& version, const String& name);
  423. ListenerList<ProgramLoadedListener> programLoadedListeners;
  424. ListenerList<ProgramEventListener> programEventListeners;
  425. ListenerList<ConfigItemListener> configItemListeners;
  426. ListenerList<DataInputPortListener> dataInputPortListeners;
  427. private:
  428. //==============================================================================
  429. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Block)
  430. };
  431. } // namespace juce