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.

200 lines
6.7KB

  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. #ifndef DOXYGEN
  18. namespace juce::universal_midi_packets
  19. {
  20. /**
  21. Parses a raw stream of uint32_t, and calls a user-provided callback every time
  22. a full Universal MIDI Packet is encountered.
  23. @tags{Audio}
  24. */
  25. class Dispatcher
  26. {
  27. public:
  28. /** Clears the dispatcher. */
  29. void reset() { currentPacketLen = 0; }
  30. /** Calls `callback` with a View of each packet encountered in the range delimited
  31. by `begin` and `end`.
  32. If the range ends part-way through a packet, the next call to `dispatch` will
  33. continue from that point in the packet (unless `reset` is called first).
  34. */
  35. template <typename PacketCallbackFunction>
  36. void dispatch (const uint32_t* begin,
  37. const uint32_t* end,
  38. double timeStamp,
  39. PacketCallbackFunction&& callback)
  40. {
  41. std::for_each (begin, end, [&] (uint32_t word)
  42. {
  43. nextPacket[currentPacketLen++] = word;
  44. if (currentPacketLen == Utils::getNumWordsForMessageType (nextPacket.front()))
  45. {
  46. callback (View (nextPacket.data()), timeStamp);
  47. currentPacketLen = 0;
  48. }
  49. });
  50. }
  51. private:
  52. std::array<uint32_t, 4> nextPacket;
  53. size_t currentPacketLen = 0;
  54. };
  55. //==============================================================================
  56. /**
  57. Parses a stream of bytes representing a sequence of bytestream-encoded MIDI 1.0 messages,
  58. converting the messages to UMP format and passing the packets to a user-provided callback
  59. as they become ready.
  60. @tags{Audio}
  61. */
  62. class BytestreamToUMPDispatcher
  63. {
  64. public:
  65. /** Initialises the dispatcher.
  66. Channel messages will be converted to the requested protocol format `pp`.
  67. `storageSize` bytes will be allocated to store incomplete messages.
  68. */
  69. explicit BytestreamToUMPDispatcher (PacketProtocol pp, int storageSize)
  70. : concatenator (storageSize),
  71. converter (pp)
  72. {}
  73. void reset()
  74. {
  75. concatenator.reset();
  76. converter.reset();
  77. }
  78. /** Calls `callback` with a View of each converted packet as it becomes ready.
  79. @param begin the first byte in a range of bytes representing bytestream-encoded MIDI messages.
  80. @param end one-past the last byte in a range of bytes representing bytestream-encoded MIDI messages.
  81. @param timestamp a timestamp to apply to the created packets.
  82. @param callback a callback which will be passed a View pointing to each new packet as it becomes ready.
  83. */
  84. template <typename PacketCallbackFunction>
  85. void dispatch (const uint8_t* begin,
  86. const uint8_t* end,
  87. double timestamp,
  88. PacketCallbackFunction&& callback)
  89. {
  90. using CallbackPtr = decltype (std::addressof (callback));
  91. #if JUCE_MINGW
  92. #define JUCE_MINGW_HIDDEN_VISIBILITY __attribute__ ((visibility ("hidden")))
  93. #else
  94. #define JUCE_MINGW_HIDDEN_VISIBILITY
  95. #endif
  96. struct JUCE_MINGW_HIDDEN_VISIBILITY Callback
  97. {
  98. Callback (BytestreamToUMPDispatcher& d, CallbackPtr c)
  99. : dispatch (d), callbackPtr (c) {}
  100. void handleIncomingMidiMessage (void*, const MidiMessage& msg) const
  101. {
  102. Conversion::toMidi1 (BytestreamMidiView (&msg), [&] (const View& view)
  103. {
  104. dispatch.converter.convert (view, *callbackPtr);
  105. });
  106. }
  107. void handlePartialSysexMessage (void*, const uint8_t*, int, double) const {}
  108. BytestreamToUMPDispatcher& dispatch;
  109. CallbackPtr callbackPtr = nullptr;
  110. };
  111. #undef JUCE_MINGW_HIDDEN_VISIBILITY
  112. Callback inputCallback { *this, &callback };
  113. concatenator.pushMidiData (begin, int (end - begin), timestamp, (void*) nullptr, inputCallback);
  114. }
  115. private:
  116. MidiDataConcatenator concatenator;
  117. GenericUMPConverter converter;
  118. };
  119. //==============================================================================
  120. /**
  121. Parses a stream of 32-bit words representing a sequence of UMP-encoded MIDI messages,
  122. converting the messages to MIDI 1.0 bytestream format and passing them to a user-provided
  123. callback as they become ready.
  124. @tags{Audio}
  125. */
  126. class ToBytestreamDispatcher
  127. {
  128. public:
  129. /** Initialises the dispatcher.
  130. `storageSize` bytes will be allocated to store incomplete messages.
  131. */
  132. explicit ToBytestreamDispatcher (int storageSize)
  133. : converter (storageSize) {}
  134. /** Clears the dispatcher. */
  135. void reset()
  136. {
  137. dispatcher.reset();
  138. converter.reset();
  139. }
  140. /** Calls `callback` with converted bytestream-formatted MidiMessage whenever
  141. a new message becomes available.
  142. @param begin the first word in a stream of words representing UMP-encoded MIDI packets.
  143. @param end one-past the last word in a stream of words representing UMP-encoded MIDI packets.
  144. @param timestamp a timestamp to apply to converted messages.
  145. @param callback a callback which will be passed a MidiMessage each time a new message becomes ready.
  146. */
  147. template <typename BytestreamMessageCallback>
  148. void dispatch (const uint32_t* begin,
  149. const uint32_t* end,
  150. double timestamp,
  151. BytestreamMessageCallback&& callback)
  152. {
  153. dispatcher.dispatch (begin, end, timestamp, [&] (const View& view, double time)
  154. {
  155. converter.convert (view, time, callback);
  156. });
  157. }
  158. private:
  159. Dispatcher dispatcher;
  160. ToBytestreamConverter converter;
  161. };
  162. } // namespace juce::universal_midi_packets
  163. #endif