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.

224 lines
6.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2016 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. /**
  18. Helper class for constructing a packet for sending to a BLOCKS device
  19. */
  20. template <int maxPacketBytes>
  21. struct HostPacketBuilder
  22. {
  23. HostPacketBuilder() noexcept {}
  24. HostPacketBuilder (const HostPacketBuilder&) = delete;
  25. HostPacketBuilder (HostPacketBuilder&&) = default;
  26. const void* getData() const noexcept { return data.getData(); }
  27. int size() const noexcept { return data.size(); }
  28. //==============================================================================
  29. void writePacketSysexHeaderBytes (TopologyIndex deviceIndex) noexcept
  30. {
  31. static_assert (maxPacketBytes > 10, "Not enough bytes for a sensible message!");
  32. jassert ((deviceIndex & 64) == 0);
  33. data.writeHeaderSysexBytes (deviceIndex);
  34. }
  35. void writePacketSysexFooter() noexcept
  36. {
  37. data.writePacketSysexFooter();
  38. }
  39. //==============================================================================
  40. bool deviceControlMessage (DeviceCommand command) noexcept
  41. {
  42. if (! data.hasCapacity (MessageType::bits + DeviceCommand::bits))
  43. return false;
  44. writeMessageType (MessageFromHost::deviceCommandMessage);
  45. data << command;
  46. return true;
  47. }
  48. //==============================================================================
  49. bool beginDataChanges (PacketIndex packetIndex) noexcept
  50. {
  51. if (! data.hasCapacity (MessageType::bits + PacketIndex::bits + DataChangeCommand::bits))
  52. return false;
  53. writeMessageType (MessageFromHost::sharedDataChange);
  54. data << packetIndex;
  55. return true;
  56. }
  57. bool endDataChanges (bool isLastChange) noexcept
  58. {
  59. if (! data.hasCapacity (DataChangeCommand::bits))
  60. return false;
  61. data << DataChangeCommand ((uint32) isLastChange ? endOfChanges : endOfPacket);
  62. return true;
  63. }
  64. bool skipBytes (int numToSkip) noexcept
  65. {
  66. if (numToSkip <= 0)
  67. return true;
  68. auto state = data.getState();
  69. while (numToSkip > ByteCountMany::maxValue)
  70. {
  71. if (! skipBytes (ByteCountMany::maxValue))
  72. {
  73. data.restore (state);
  74. return false;
  75. }
  76. numToSkip -= ByteCountMany::maxValue;
  77. }
  78. if (numToSkip > ByteCountFew::maxValue)
  79. {
  80. if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountMany::bits))
  81. {
  82. data.restore (state);
  83. return false;
  84. }
  85. data << DataChangeCommand ((uint32) skipBytesMany) << ByteCountMany ((uint32) numToSkip);
  86. return true;
  87. }
  88. if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits))
  89. {
  90. data.restore (state);
  91. return false;
  92. }
  93. data << DataChangeCommand ((uint32) skipBytesFew) << ByteCountFew ((uint32) numToSkip);
  94. return true;
  95. }
  96. bool setMultipleBytes (const uint8* values, int num) noexcept
  97. {
  98. if (num <= 0)
  99. return true;
  100. if (! data.hasCapacity (DataChangeCommand::bits * 2 + num * (1 + ByteValue::bits)))
  101. return false;
  102. data << DataChangeCommand ((uint32) setSequenceOfBytes);
  103. for (int i = 0; i < num; ++i)
  104. data << ByteValue ((uint32) values[i])
  105. << ByteSequenceContinues (i < num - 1 ? 1 : 0);
  106. return true;
  107. }
  108. bool setMultipleBytes (uint8 value, uint8 lastValue, int num) noexcept
  109. {
  110. if (num <= 0)
  111. return true;
  112. if (num == 1)
  113. return setMultipleBytes (&value, 1); // (this is a more compact message)
  114. auto state = data.getState();
  115. if (num > ByteCountMany::maxValue)
  116. {
  117. if (! setMultipleBytes (value, lastValue, ByteCountMany::maxValue))
  118. {
  119. data.restore (state);
  120. return false;
  121. }
  122. return setMultipleBytes (value, lastValue, num - ByteCountMany::maxValue);
  123. }
  124. if (num > ByteCountFew::maxValue)
  125. {
  126. if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountMany::bits + ByteValue::bits))
  127. {
  128. data.restore (state);
  129. return false;
  130. }
  131. data << DataChangeCommand ((uint32) setManyBytesWithValue)
  132. << ByteCountMany ((uint32) num)
  133. << ByteValue ((uint32) value);
  134. return true;
  135. }
  136. if (value == lastValue)
  137. {
  138. if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits))
  139. {
  140. data.restore (state);
  141. return false;
  142. }
  143. data << DataChangeCommand ((uint32) setFewBytesWithLastValue) << ByteCountFew ((uint32) num);
  144. return true;
  145. }
  146. if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits + ByteValue::bits))
  147. {
  148. data.restore (state);
  149. return false;
  150. }
  151. data << DataChangeCommand ((uint32) setFewBytesWithValue) << ByteCountFew ((uint32) num)
  152. << ByteValue ((uint32) value);
  153. return true;
  154. }
  155. bool addProgramEventMessage (const int32* messageData)
  156. {
  157. if (! data.hasCapacity (BitSizes::programEventMessage))
  158. return false;
  159. writeMessageType (MessageFromHost::programEventMessage);
  160. for (uint32 i = 0; i < numProgramMessageInts; ++i)
  161. data << IntegerWithBitSize<32> ((uint32) messageData[i]);
  162. return true;
  163. }
  164. //==============================================================================
  165. private:
  166. Packed7BitArrayBuilder<maxPacketBytes> data;
  167. void writeMessageType (MessageFromHost type) noexcept
  168. {
  169. data << MessageType ((uint32) type);
  170. }
  171. };