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.

471 lines
18KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - 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. class MidiDeviceListConnectionBroadcaster;
  20. /**
  21. To find out when the available MIDI devices change, call MidiDeviceListConnection::make(),
  22. passing a lambda that will be called on each configuration change.
  23. To stop the lambda receiving callbacks, destroy the MidiDeviceListConnection instance returned
  24. from make(), or call reset() on it.
  25. @code
  26. // Start listening for configuration changes
  27. auto connection = MidiDeviceListConnection::make ([]
  28. {
  29. // This will print a message when devices are connected/disconnected
  30. DBG ("MIDI devices changed");
  31. });
  32. // Stop listening
  33. connection.reset();
  34. @endcode
  35. @tags{Audio}
  36. */
  37. class MidiDeviceListConnection
  38. {
  39. public:
  40. using Key = uint64_t;
  41. /** Constructs an inactive connection.
  42. */
  43. MidiDeviceListConnection() = default;
  44. MidiDeviceListConnection (const MidiDeviceListConnection&) = delete;
  45. MidiDeviceListConnection (MidiDeviceListConnection&& other) noexcept
  46. : broadcaster (std::exchange (other.broadcaster, nullptr)),
  47. key (std::exchange (other.key, Key{}))
  48. {
  49. }
  50. MidiDeviceListConnection& operator= (const MidiDeviceListConnection&) = delete;
  51. MidiDeviceListConnection& operator= (MidiDeviceListConnection&& other) noexcept
  52. {
  53. MidiDeviceListConnection (std::move (other)).swap (*this);
  54. return *this;
  55. }
  56. ~MidiDeviceListConnection() noexcept;
  57. /** Clears this connection.
  58. If this object had an active connection, that connection will be deactivated, and the
  59. corresponding callback will be removed from the MidiDeviceListConnectionBroadcaster.
  60. */
  61. void reset() noexcept
  62. {
  63. MidiDeviceListConnection().swap (*this);
  64. }
  65. /** Registers a function to be called whenever the midi device list changes.
  66. The callback will only be active for as long as the return MidiDeviceListConnection remains
  67. alive. To stop receiving device change notifications, destroy the Connection object, e.g.
  68. by allowing it to fall out of scope.
  69. */
  70. static MidiDeviceListConnection make (std::function<void()>);
  71. private:
  72. MidiDeviceListConnection (MidiDeviceListConnectionBroadcaster* b, const Key k)
  73. : broadcaster (b), key (k) {}
  74. void swap (MidiDeviceListConnection& other) noexcept
  75. {
  76. std::swap (other.broadcaster, broadcaster);
  77. std::swap (other.key, key);
  78. }
  79. MidiDeviceListConnectionBroadcaster* broadcaster = nullptr;
  80. Key key = {};
  81. };
  82. //==============================================================================
  83. /**
  84. This struct contains information about a MIDI input or output device.
  85. You can get one of these structs by calling the static getAvailableDevices() or
  86. getDefaultDevice() methods of MidiInput and MidiOutput or by calling getDeviceInfo()
  87. on an instance of these classes. Devices can be opened by passing the identifier to
  88. the openDevice() method.
  89. @tags{Audio}
  90. */
  91. struct MidiDeviceInfo
  92. {
  93. MidiDeviceInfo() = default;
  94. MidiDeviceInfo (const String& deviceName, const String& deviceIdentifier)
  95. : name (deviceName), identifier (deviceIdentifier)
  96. {
  97. }
  98. /** The name of this device.
  99. This will be provided by the OS unless the device has been created with the
  100. createNewDevice() method.
  101. Note that the name is not guaranteed to be unique and two devices with the
  102. same name will be indistinguishable. If you want to address a specific device
  103. it is better to use the identifier.
  104. */
  105. String name;
  106. /** The identifier for this device.
  107. This will be provided by the OS and it's format will differ on different systems
  108. e.g. on macOS it will be a number whereas on Windows it will be a long alphanumeric string.
  109. */
  110. String identifier;
  111. //==============================================================================
  112. auto tie() const { return std::tie (name, identifier); }
  113. bool operator== (const MidiDeviceInfo& other) const noexcept { return tie() == other.tie(); }
  114. bool operator!= (const MidiDeviceInfo& other) const noexcept { return tie() != other.tie(); }
  115. };
  116. class MidiInputCallback;
  117. //==============================================================================
  118. /**
  119. Represents a midi input device.
  120. To create one of these, use the static getAvailableDevices() method to find out what
  121. inputs are available, and then use the openDevice() method to try to open one.
  122. @see MidiOutput
  123. @tags{Audio}
  124. */
  125. class JUCE_API MidiInput final
  126. {
  127. public:
  128. //==============================================================================
  129. /** Returns a list of the available midi input devices.
  130. You can open one of the devices by passing its identifier into the openDevice() method.
  131. @see MidiDeviceInfo, getDevices, getDefaultDeviceIndex, openDevice
  132. */
  133. static Array<MidiDeviceInfo> getAvailableDevices();
  134. /** Returns the MidiDeviceInfo of the default midi input device to use. */
  135. static MidiDeviceInfo getDefaultDevice();
  136. /** Tries to open one of the midi input devices.
  137. This will return a MidiInput object if it manages to open it, you can then
  138. call start() and stop() on this device.
  139. If the device can't be opened, this will return an empty object.
  140. @param deviceIdentifier the ID of the device to open - use the getAvailableDevices() method to
  141. find the available devices that can be opened
  142. @param callback the object that will receive the midi messages from this device
  143. @see MidiInputCallback, getDevices
  144. */
  145. static std::unique_ptr<MidiInput> openDevice (const String& deviceIdentifier, MidiInputCallback* callback);
  146. #if JUCE_LINUX || JUCE_BSD || JUCE_MAC || JUCE_IOS || DOXYGEN
  147. /** This will try to create a new midi input device (only available on Linux, macOS and iOS).
  148. This will attempt to create a new midi input device with the specified name for other
  149. apps to connect to.
  150. NB - if you are calling this method on iOS you must have enabled the "Audio Background Capability"
  151. setting in the iOS exporter otherwise this method will fail.
  152. Returns an empty object if a device can't be created.
  153. @param deviceName the name of the device to create
  154. @param callback the object that will receive the midi messages from this device
  155. */
  156. static std::unique_ptr<MidiInput> createNewDevice (const String& deviceName, MidiInputCallback* callback);
  157. #endif
  158. //==============================================================================
  159. /** Destructor. */
  160. ~MidiInput();
  161. /** Starts the device running.
  162. After calling this, the device will start sending midi messages to the MidiInputCallback
  163. object that was specified when the openDevice() method was called.
  164. @see stop
  165. */
  166. void start();
  167. /** Stops the device running.
  168. @see start
  169. */
  170. void stop();
  171. /** Returns the MidiDeviceInfo struct containing some information about this device. */
  172. MidiDeviceInfo getDeviceInfo() const noexcept { return deviceInfo; }
  173. /** Returns the identifier of this device. */
  174. String getIdentifier() const noexcept { return deviceInfo.identifier; }
  175. /** Returns the name of this device. */
  176. String getName() const noexcept { return deviceInfo.name; }
  177. /** Sets a custom name for the device. */
  178. void setName (const String& newName) noexcept { deviceInfo.name = newName; }
  179. //==============================================================================
  180. #ifndef DOXYGEN
  181. [[deprecated ("Use getAvailableDevices instead.")]]
  182. static StringArray getDevices();
  183. [[deprecated ("Use getDefaultDevice instead.")]]
  184. static int getDefaultDeviceIndex();
  185. [[deprecated ("Use openDevice that takes a device identifier instead.")]]
  186. static std::unique_ptr<MidiInput> openDevice (int, MidiInputCallback*);
  187. #endif
  188. /** @internal */
  189. class Pimpl;
  190. private:
  191. //==============================================================================
  192. explicit MidiInput (const String&, const String&);
  193. MidiDeviceInfo deviceInfo;
  194. std::unique_ptr<Pimpl> internal;
  195. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInput)
  196. };
  197. //==============================================================================
  198. /**
  199. Receives incoming messages from a physical MIDI input device.
  200. This class is overridden to handle incoming midi messages. See the MidiInput
  201. class for more details.
  202. @see MidiInput
  203. @tags{Audio}
  204. */
  205. class JUCE_API MidiInputCallback
  206. {
  207. public:
  208. /** Destructor. */
  209. virtual ~MidiInputCallback() = default;
  210. /** Receives an incoming message.
  211. A MidiInput object will call this method when a midi event arrives. It'll be
  212. called on a high-priority system thread, so avoid doing anything time-consuming
  213. in here, and avoid making any UI calls. You might find the MidiBuffer class helpful
  214. for queueing incoming messages for use later.
  215. @param source the MidiInput object that generated the message
  216. @param message the incoming message. The message's timestamp is set to a value
  217. equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the
  218. time when the message arrived
  219. */
  220. virtual void handleIncomingMidiMessage (MidiInput* source,
  221. const MidiMessage& message) = 0;
  222. /** Notification sent each time a packet of a multi-packet sysex message arrives.
  223. If a long sysex message is broken up into multiple packets, this callback is made
  224. for each packet that arrives until the message is finished, at which point
  225. the normal handleIncomingMidiMessage() callback will be made with the entire
  226. message.
  227. The message passed in will contain the start of a sysex, but won't be finished
  228. with the terminating 0xf7 byte.
  229. */
  230. virtual void handlePartialSysexMessage (MidiInput* source,
  231. const uint8* messageData,
  232. int numBytesSoFar,
  233. double timestamp);
  234. };
  235. //==============================================================================
  236. /**
  237. Represents a midi output device.
  238. To create one of these, use the static getAvailableDevices() method to find out what
  239. outputs are available, and then use the openDevice() method to try to open one.
  240. @see MidiInput
  241. @tags{Audio}
  242. */
  243. class JUCE_API MidiOutput final : private Thread
  244. {
  245. public:
  246. //==============================================================================
  247. /** Returns a list of the available midi output devices.
  248. You can open one of the devices by passing its identifier into the openDevice() method.
  249. @see MidiDeviceInfo, getDevices, getDefaultDeviceIndex, openDevice
  250. */
  251. static Array<MidiDeviceInfo> getAvailableDevices();
  252. /** Returns the MidiDeviceInfo of the default midi output device to use. */
  253. static MidiDeviceInfo getDefaultDevice();
  254. /** Tries to open one of the midi output devices.
  255. This will return a MidiOutput object if it manages to open it, you can then
  256. send messages to this device.
  257. If the device can't be opened, this will return an empty object.
  258. @param deviceIdentifier the ID of the device to open - use the getAvailableDevices() method to
  259. find the available devices that can be opened
  260. @see getDevices
  261. */
  262. static std::unique_ptr<MidiOutput> openDevice (const String& deviceIdentifier);
  263. #if JUCE_LINUX || JUCE_BSD || JUCE_MAC || JUCE_IOS || DOXYGEN
  264. /** This will try to create a new midi output device (only available on Linux, macOS and iOS).
  265. This will attempt to create a new midi output device with the specified name that other
  266. apps can connect to and use as their midi input.
  267. NB - if you are calling this method on iOS you must have enabled the "Audio Background Capability"
  268. setting in the iOS exporter otherwise this method will fail.
  269. Returns an empty object if a device can't be created.
  270. @param deviceName the name of the device to create
  271. */
  272. static std::unique_ptr<MidiOutput> createNewDevice (const String& deviceName);
  273. #endif
  274. //==============================================================================
  275. /** Destructor. */
  276. ~MidiOutput() override;
  277. /** Returns the MidiDeviceInfo struct containing some information about this device. */
  278. MidiDeviceInfo getDeviceInfo() const noexcept { return deviceInfo; }
  279. /** Returns the identifier of this device. */
  280. String getIdentifier() const noexcept { return deviceInfo.identifier; }
  281. /** Returns the name of this device. */
  282. String getName() const noexcept { return deviceInfo.name; }
  283. /** Sets a custom name for the device. */
  284. void setName (const String& newName) noexcept { deviceInfo.name = newName; }
  285. //==============================================================================
  286. /** Sends out a MIDI message immediately. */
  287. void sendMessageNow (const MidiMessage& message);
  288. /** Sends out a sequence of MIDI messages immediately. */
  289. void sendBlockOfMessagesNow (const MidiBuffer& buffer);
  290. /** This lets you supply a block of messages that will be sent out at some point
  291. in the future.
  292. The MidiOutput class has an internal thread that can send out timestamped
  293. messages - this appends a set of messages to its internal buffer, ready for
  294. sending.
  295. This will only work if you've already started the thread with startBackgroundThread().
  296. A time is specified, at which the block of messages should be sent. This time uses
  297. the same time base as Time::getMillisecondCounter(), and must be in the future.
  298. The samplesPerSecondForBuffer parameter indicates the number of samples per second
  299. used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the
  300. samplesPerSecondForBuffer value is needed to convert this sample position to a
  301. real time.
  302. */
  303. void sendBlockOfMessages (const MidiBuffer& buffer,
  304. double millisecondCounterToStartAt,
  305. double samplesPerSecondForBuffer);
  306. /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). */
  307. void clearAllPendingMessages();
  308. /** Starts up a background thread so that the device can send blocks of data.
  309. Call this to get the device ready, before using sendBlockOfMessages().
  310. */
  311. void startBackgroundThread();
  312. /** Stops the background thread, and clears any pending midi events.
  313. @see startBackgroundThread
  314. */
  315. void stopBackgroundThread();
  316. /** Returns true if the background thread used to send blocks of data is running.
  317. @see startBackgroundThread, stopBackgroundThread
  318. */
  319. bool isBackgroundThreadRunning() const noexcept { return isThreadRunning(); }
  320. //==============================================================================
  321. #ifndef DOXYGEN
  322. [[deprecated ("Use getAvailableDevices instead.")]]
  323. static StringArray getDevices();
  324. [[deprecated ("Use getDefaultDevice instead.")]]
  325. static int getDefaultDeviceIndex();
  326. [[deprecated ("Use openDevice that takes a device identifier instead.")]]
  327. static std::unique_ptr<MidiOutput> openDevice (int);
  328. #endif
  329. /** @internal */
  330. class Pimpl;
  331. private:
  332. //==============================================================================
  333. struct PendingMessage
  334. {
  335. PendingMessage (const void* data, int len, double timeStamp)
  336. : message (data, len, timeStamp)
  337. {
  338. }
  339. MidiMessage message;
  340. PendingMessage* next;
  341. };
  342. //==============================================================================
  343. explicit MidiOutput (const String&, const String&);
  344. void run() override;
  345. MidiDeviceInfo deviceInfo;
  346. std::unique_ptr<Pimpl> internal;
  347. CriticalSection lock;
  348. PendingMessage* firstMessage = nullptr;
  349. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput)
  350. };
  351. } // namespace juce