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.

624 lines
20KB

  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. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. /*
  19. Namespace containing metadata about MIDI-CI message types, such as
  20. replies corresponding to inquiries, and serialization functions.
  21. @tags{Audio}
  22. */
  23. namespace juce::midi_ci::detail::MessageMeta
  24. {
  25. //==============================================================================
  26. /* The maximum CI version that can be parsed and generated by this implementation. */
  27. static constexpr std::byte implementationVersion { 0x02 };
  28. /* Wraps a pointer to a Span. Used to indicate to CI readers/writers that a particular field is
  29. of variable length, starting with a 16-bit or 32-bit byte count.
  30. */
  31. template <uint8_t NumBytes, typename T, bool isJson = false>
  32. struct SpanWithSizeBytes
  33. {
  34. T& span;
  35. };
  36. /* Creates a SpanWithSizeBytes with an appropriate template argument. */
  37. template <uint8_t NumBytes, typename T>
  38. static constexpr auto makeSpanWithSizeBytes ( Span<T>& span) { return SpanWithSizeBytes<NumBytes, Span<T>> { span }; }
  39. template <uint8_t NumBytes, typename T>
  40. static constexpr auto makeSpanWithSizeBytes (const Span<T>& span) { return SpanWithSizeBytes<NumBytes, const Span<T>> { span }; }
  41. template <uint8_t NumBytes, typename T>
  42. static constexpr auto makeJsonWithSizeBytes ( Span<T>& span) { return SpanWithSizeBytes<NumBytes, Span<T>, true> { span }; }
  43. template <uint8_t NumBytes, typename T>
  44. static constexpr auto makeJsonWithSizeBytes (const Span<T>& span) { return SpanWithSizeBytes<NumBytes, const Span<T>, true> { span }; }
  45. template <uint8_t SubID2, typename R = void>
  46. struct Metadata
  47. {
  48. static constexpr std::byte subID2 { SubID2 };
  49. using Reply = R;
  50. };
  51. template <typename T>
  52. struct Meta;
  53. template <>
  54. struct Meta<Message::DiscoveryResponse> : Metadata<0x71> {};
  55. template <>
  56. struct Meta<Message::Discovery> : Metadata<0x70, Message::DiscoveryResponse> {};
  57. template <>
  58. struct Meta<Message::EndpointInquiryResponse> : Metadata<0x73> {};
  59. template <>
  60. struct Meta<Message::EndpointInquiry> : Metadata<0x72, Message::EndpointInquiryResponse> {};
  61. template <>
  62. struct Meta<Message::InvalidateMUID> : Metadata<0x7e> {};
  63. template <>
  64. struct Meta<Message::ACK> : Metadata<0x7d> {};
  65. template <>
  66. struct Meta<Message::NAK> : Metadata<0x7f> {};
  67. template <>
  68. struct Meta<Message::ProfileInquiryResponse> : Metadata<0x21> {};
  69. template <>
  70. struct Meta<Message::ProfileInquiry> : Metadata<0x20, Message::ProfileInquiryResponse> {};
  71. template <>
  72. struct Meta<Message::ProfileAdded> : Metadata<0x26> {};
  73. template <>
  74. struct Meta<Message::ProfileRemoved> : Metadata<0x27> {};
  75. template <>
  76. struct Meta<Message::ProfileDetailsResponse> : Metadata<0x29> {};
  77. template <>
  78. struct Meta<Message::ProfileDetails> : Metadata<0x28, Message::ProfileDetailsResponse> {};
  79. template <>
  80. struct Meta<Message::ProfileOn> : Metadata<0x22> {};
  81. template <>
  82. struct Meta<Message::ProfileOff> : Metadata<0x23> {};
  83. template <>
  84. struct Meta<Message::ProfileEnabledReport> : Metadata<0x24> {};
  85. template <>
  86. struct Meta<Message::ProfileDisabledReport> : Metadata<0x25> {};
  87. template <>
  88. struct Meta<Message::ProfileSpecificData> : Metadata<0x2f> {};
  89. template <>
  90. struct Meta<Message::PropertyExchangeCapabilitiesResponse> : Metadata<0x31> {};
  91. template <>
  92. struct Meta<Message::PropertyExchangeCapabilities> : Metadata<0x30, Message::PropertyExchangeCapabilitiesResponse> {};
  93. template <>
  94. struct Meta<Message::StaticSizePropertyExchange> {};
  95. template <>
  96. struct Meta<Message::DynamicSizePropertyExchange> {};
  97. template <>
  98. struct Meta<Message::PropertyGetDataResponse> : Meta<Message::DynamicSizePropertyExchange>, Metadata<0x35> {};
  99. template <>
  100. struct Meta<Message::PropertyGetData> : Meta<Message::StaticSizePropertyExchange>, Metadata<0x34, Message::PropertyGetDataResponse> {};
  101. template <>
  102. struct Meta<Message::PropertySetDataResponse> : Meta<Message::StaticSizePropertyExchange>, Metadata<0x37> {};
  103. template <>
  104. struct Meta<Message::PropertySetData> : Meta<Message::DynamicSizePropertyExchange>, Metadata<0x36, Message::PropertySetDataResponse> {};
  105. template <>
  106. struct Meta<Message::PropertySubscribeResponse> : Meta<Message::DynamicSizePropertyExchange>, Metadata<0x39> {};
  107. template <>
  108. struct Meta<Message::PropertySubscribe> : Meta<Message::DynamicSizePropertyExchange>, Metadata<0x38, Message::PropertySubscribeResponse> {};
  109. template <>
  110. struct Meta<Message::PropertyNotify> : Meta<Message::DynamicSizePropertyExchange>, Metadata<0x3f> {};
  111. template <>
  112. struct Meta<Message::ProcessInquiryResponse> : Metadata<0x41> {};
  113. template <>
  114. struct Meta<Message::ProcessInquiry> : Metadata<0x40, Message::ProcessInquiryResponse> {};
  115. template <>
  116. struct Meta<Message::ProcessMidiMessageReportResponse> : Metadata<0x43> {};
  117. template <>
  118. struct Meta<Message::ProcessMidiMessageReport> : Metadata<0x42, Message::ProcessMidiMessageReportResponse> {};
  119. template <>
  120. struct Meta<Message::ProcessEndMidiMessageReport> : Metadata<0x44> {};
  121. } // namespace juce::midi_ci::detail::MessageMeta
  122. #ifndef DOXYGEN
  123. namespace juce
  124. {
  125. struct VersionBase
  126. {
  127. static constexpr auto marshallingVersion = (int) juce::midi_ci::detail::MessageMeta::implementationVersion;
  128. };
  129. template <uint8_t NumBytes, typename T, bool isJson>
  130. struct SerialisationTraits<midi_ci::detail::MessageMeta::SpanWithSizeBytes<NumBytes, T, isJson>>
  131. {
  132. static constexpr auto marshallingVersion = std::nullopt;
  133. template <typename This>
  134. static auto getSize (This& t)
  135. {
  136. if constexpr (NumBytes == 1)
  137. return (uint8_t) t.size();
  138. else if constexpr (NumBytes == 2)
  139. return (uint16_t) t.size();
  140. else if constexpr (NumBytes == 4)
  141. return (uint32_t) t.size();
  142. else if constexpr (NumBytes == 8)
  143. return (uint64_t) t.size();
  144. else
  145. static_assert (detail::delayStaticAssert<T>, "NumBytes is not a power of two");
  146. }
  147. template <typename Archive, typename This>
  148. static auto load (Archive&, This&)
  149. {
  150. }
  151. template <typename Archive, typename This>
  152. static auto save (Archive& archive, const This& t)
  153. {
  154. auto size = getSize (t.span);
  155. archive (serialisationSize (size));
  156. for (const auto& element : t.span)
  157. archive (element);
  158. }
  159. };
  160. template <>
  161. struct SerialisationTraits<ci::MUID> : VersionBase
  162. {
  163. template <typename Archive>
  164. static auto load (Archive& archive, ci::MUID& t)
  165. {
  166. uint32_t muid{};
  167. auto result = archive (muid);
  168. t = ci::MUID::makeUnchecked (muid);
  169. return result;
  170. }
  171. template <typename Archive>
  172. static auto save (Archive& archive, const ci::MUID& t)
  173. {
  174. return archive (t.get());
  175. }
  176. };
  177. template <>
  178. struct SerialisationTraits<ci::Message::Header> : VersionBase
  179. {
  180. template <typename Archive, typename This>
  181. static auto serialise (Archive& archive, This& t)
  182. {
  183. const std::byte universalSystemExclusive { 0x7e }, subID { 0x0d };
  184. return archive (universalSystemExclusive,
  185. t.deviceID,
  186. subID,
  187. t.category,
  188. t.version,
  189. t.source,
  190. t.destination);
  191. }
  192. };
  193. template <>
  194. struct SerialisationTraits<ci::Message::Generic> : VersionBase
  195. {
  196. template <typename Archive, typename This>
  197. static auto serialise (Archive& archive, This& t)
  198. {
  199. return archive (t.header, t.data);
  200. }
  201. };
  202. template <>
  203. struct SerialisationTraits<ci::Message::DiscoveryResponse> : VersionBase
  204. {
  205. template <typename Archive, typename This>
  206. static auto serialise (Archive& archive, This& t)
  207. {
  208. archive (named ("device", t.device),
  209. named ("capabilities", t.capabilities),
  210. named ("maximumSysexSize", t.maximumSysexSize));
  211. if (0x02 <= archive.getVersion())
  212. archive (named ("outputPathID", t.outputPathID), named ("functionBlock", t.functionBlock));
  213. }
  214. };
  215. template <>
  216. struct SerialisationTraits<ci::Message::Discovery> : VersionBase
  217. {
  218. template <typename Archive, typename This>
  219. static auto serialise (Archive& archive, This& t)
  220. {
  221. archive (named ("device", t.device),
  222. named ("capabilities", t.capabilities),
  223. named ("maximumSysexSize", t.maximumSysexSize));
  224. if (0x02 <= archive.getVersion())
  225. archive (named ("outputPathID", t.outputPathID));
  226. }
  227. };
  228. template <>
  229. struct SerialisationTraits<ci::Message::EndpointInquiryResponse> : VersionBase
  230. {
  231. template <typename Archive, typename This>
  232. static auto serialise (Archive& archive, This& t)
  233. {
  234. archive (named ("status", t.status),
  235. named ("data", midi_ci::detail::MessageMeta::makeSpanWithSizeBytes<2> (t.data)));
  236. }
  237. };
  238. template <>
  239. struct SerialisationTraits<ci::Message::EndpointInquiry> : VersionBase
  240. {
  241. template <typename Archive, typename This>
  242. static auto serialise (Archive& archive, This& t)
  243. {
  244. archive (named ("status", t.status));
  245. }
  246. };
  247. template <>
  248. struct SerialisationTraits<ci::Message::InvalidateMUID> : VersionBase
  249. {
  250. template <typename Archive, typename This>
  251. static auto serialise (Archive& archive, This& t)
  252. {
  253. archive (named ("target", t.target));
  254. }
  255. };
  256. template <>
  257. struct SerialisationTraits<ci::Message::ACK> : VersionBase
  258. {
  259. template <typename Archive, typename This>
  260. static auto serialise (Archive& archive, This& t)
  261. {
  262. archive (named ("originalCategory", t.originalCategory),
  263. named ("statusCode", t.statusCode),
  264. named ("statusData", t.statusData),
  265. named ("details", t.details),
  266. named ("messageText", midi_ci::detail::MessageMeta::makeSpanWithSizeBytes<2> (t.messageText)));
  267. }
  268. };
  269. template <>
  270. struct SerialisationTraits<ci::Message::NAK> : VersionBase
  271. {
  272. template <typename Archive, typename This>
  273. static auto serialise (Archive& archive, This& t)
  274. {
  275. if (0x02 <= archive.getVersion())
  276. {
  277. archive (named ("originalCategory", t.originalCategory),
  278. named ("statusCode", t.statusCode),
  279. named ("statusData", t.statusData),
  280. named ("details", t.details),
  281. named ("messageText", midi_ci::detail::MessageMeta::makeSpanWithSizeBytes<2> (t.messageText)));
  282. }
  283. }
  284. };
  285. template <>
  286. struct SerialisationTraits<ci::Message::ProfileInquiryResponse> : VersionBase
  287. {
  288. template <typename Archive, typename This>
  289. static auto serialise (Archive& archive, This& t)
  290. {
  291. archive (named ("enabledProfiles", midi_ci::detail::MessageMeta::makeSpanWithSizeBytes<2> (t.enabledProfiles)),
  292. named ("disabledProfiles", midi_ci::detail::MessageMeta::makeSpanWithSizeBytes<2> (t.disabledProfiles)));
  293. }
  294. };
  295. template <>
  296. struct SerialisationTraits<ci::Message::ProfileInquiry> : VersionBase
  297. {
  298. template <typename Archive, typename This>
  299. static auto serialise (Archive&, This&)
  300. {
  301. }
  302. };
  303. template <>
  304. struct SerialisationTraits<ci::Message::ProfileAdded> : VersionBase
  305. {
  306. template <typename Archive, typename This>
  307. static auto serialise (Archive& archive, This& t)
  308. {
  309. archive (named ("profile", t.profile));
  310. }
  311. };
  312. template <>
  313. struct SerialisationTraits<ci::Message::ProfileRemoved> : VersionBase
  314. {
  315. template <typename Archive, typename This>
  316. static auto serialise (Archive& archive, This& t)
  317. {
  318. archive (named ("profile", t.profile));
  319. }
  320. };
  321. template <>
  322. struct SerialisationTraits<ci::Message::ProfileDetailsResponse> : VersionBase
  323. {
  324. template <typename Archive, typename This>
  325. static auto serialise (Archive& archive, This& t)
  326. {
  327. archive (named ("profile", t.profile),
  328. named ("target", t.target),
  329. named ("data", midi_ci::detail::MessageMeta::makeSpanWithSizeBytes<2> (t.data)));
  330. }
  331. };
  332. template <>
  333. struct SerialisationTraits<ci::Message::ProfileDetails> : VersionBase
  334. {
  335. template <typename Archive, typename This>
  336. static auto serialise (Archive& archive, This& t)
  337. {
  338. archive (named ("profile", t.profile),
  339. named ("target", t.target));
  340. }
  341. };
  342. template <>
  343. struct SerialisationTraits<ci::Message::ProfileOn> : VersionBase
  344. {
  345. template <typename Archive, typename This>
  346. static auto serialise (Archive& archive, This& t)
  347. {
  348. archive (named ("profile", t.profile));
  349. if (0x02 <= archive.getVersion())
  350. archive (named ("numChannels", t.numChannels));
  351. }
  352. };
  353. template <>
  354. struct SerialisationTraits<ci::Message::ProfileOff> : VersionBase
  355. {
  356. template <typename Archive, typename This>
  357. static auto serialise (Archive& archive, This& t)
  358. {
  359. archive (named ("profile", t.profile));
  360. if (0x02 <= archive.getVersion())
  361. {
  362. uint16_t reserved{};
  363. archive (named ("reserved", reserved));
  364. }
  365. }
  366. };
  367. template <>
  368. struct SerialisationTraits<ci::Message::ProfileEnabledReport> : VersionBase
  369. {
  370. template <typename Archive, typename This>
  371. static auto serialise (Archive& archive, This& t)
  372. {
  373. archive (named ("profile", t.profile));
  374. if (0x02 <= archive.getVersion())
  375. archive (named ("numChannels", t.numChannels));
  376. }
  377. };
  378. template <>
  379. struct SerialisationTraits<ci::Message::ProfileDisabledReport> : VersionBase
  380. {
  381. template <typename Archive, typename This>
  382. static auto serialise (Archive& archive, This& t)
  383. {
  384. archive (named ("profile", t.profile));
  385. if (0x02 <= archive.getVersion())
  386. archive (named ("numChannels", t.numChannels));
  387. }
  388. };
  389. template <>
  390. struct SerialisationTraits<ci::Message::ProfileSpecificData> : VersionBase
  391. {
  392. template <typename Archive, typename This>
  393. static auto serialise (Archive& archive, This& t)
  394. {
  395. archive (named ("profile", t.profile), named ("data", midi_ci::detail::MessageMeta::makeSpanWithSizeBytes<4> (t.data)));
  396. }
  397. };
  398. template <>
  399. struct SerialisationTraits<ci::Message::PropertyExchangeCapabilitiesResponse> : VersionBase
  400. {
  401. template <typename Archive, typename This>
  402. static auto serialise (Archive& archive, This& t)
  403. {
  404. archive (named ("numRequests", t.numSimultaneousRequestsSupported));
  405. if (0x02 <= archive.getVersion())
  406. archive (named ("major", t.majorVersion), named ("minor", t.minorVersion));
  407. }
  408. };
  409. template <>
  410. struct SerialisationTraits<ci::Message::PropertyExchangeCapabilities> : VersionBase
  411. {
  412. template <typename Archive, typename This>
  413. static auto serialise (Archive& archive, This& t)
  414. {
  415. archive (named ("numRequests", t.numSimultaneousRequestsSupported));
  416. if (0x02 <= archive.getVersion())
  417. archive (named ("major", t.majorVersion), named ("minor", t.minorVersion));
  418. }
  419. };
  420. template <>
  421. struct SerialisationTraits<ci::Message::StaticSizePropertyExchange> : VersionBase
  422. {
  423. template <typename Archive, typename This>
  424. static auto serialise (Archive& archive, This& t)
  425. {
  426. const uint16_t chunkNum = 1, dataLength = 0;
  427. archive (named ("requestID", t.requestID),
  428. named ("header", midi_ci::detail::MessageMeta::makeJsonWithSizeBytes<2> (t.header)),
  429. named ("numChunks", chunkNum),
  430. named ("thisChunk", chunkNum),
  431. named ("length", dataLength));
  432. }
  433. };
  434. template <>
  435. struct SerialisationTraits<ci::Message::DynamicSizePropertyExchange> : VersionBase
  436. {
  437. template <typename Archive, typename This>
  438. static auto serialise (Archive& archive, This& t)
  439. {
  440. archive (named ("requestID", t.requestID),
  441. named ("header", midi_ci::detail::MessageMeta::makeJsonWithSizeBytes<2> (t.header)),
  442. named ("numChunks", t.totalNumChunks),
  443. named ("thisChunk", t.thisChunkNum),
  444. named ("data", midi_ci::detail::MessageMeta::makeSpanWithSizeBytes<2> (t.data)));
  445. }
  446. };
  447. template <>
  448. struct SerialisationTraits<ci::Message::PropertyGetDataResponse> : SerialisationTraits<ci::Message::DynamicSizePropertyExchange> {};
  449. template <>
  450. struct SerialisationTraits<ci::Message::PropertyGetData> : SerialisationTraits<ci::Message::StaticSizePropertyExchange> {};
  451. template <>
  452. struct SerialisationTraits<ci::Message::PropertySetDataResponse> : SerialisationTraits<ci::Message::StaticSizePropertyExchange> {};
  453. template <>
  454. struct SerialisationTraits<ci::Message::PropertySetData> : SerialisationTraits<ci::Message::DynamicSizePropertyExchange> {};
  455. template <>
  456. struct SerialisationTraits<ci::Message::PropertySubscribeResponse> : SerialisationTraits<ci::Message::DynamicSizePropertyExchange> {};
  457. template <>
  458. struct SerialisationTraits<ci::Message::PropertySubscribe> : SerialisationTraits<ci::Message::DynamicSizePropertyExchange> {};
  459. template <>
  460. struct SerialisationTraits<ci::Message::PropertyNotify> : SerialisationTraits<ci::Message::DynamicSizePropertyExchange> {};
  461. template <>
  462. struct SerialisationTraits<ci::Message::ProcessInquiryResponse> : VersionBase
  463. {
  464. template <typename Archive, typename This>
  465. static auto serialise (Archive& archive, This& t)
  466. {
  467. archive (t.supportedFeatures);
  468. }
  469. };
  470. template <>
  471. struct SerialisationTraits<ci::Message::ProcessInquiry> : VersionBase
  472. {
  473. template <typename Archive, typename This>
  474. static auto serialise (Archive&, This&)
  475. {
  476. }
  477. };
  478. template <>
  479. struct SerialisationTraits<ci::Message::ProcessMidiMessageReportResponse> : VersionBase
  480. {
  481. template <typename Archive, typename This>
  482. static auto serialise (Archive& archive, This& t)
  483. {
  484. std::byte reserved{};
  485. archive (named ("messageDataControl", t.messageDataControl),
  486. named ("requestedMessages", t.requestedMessages),
  487. named ("reserved", reserved),
  488. named ("channelControllerMessages", t.channelControllerMessages),
  489. named ("noteDataMessages", t.noteDataMessages));
  490. }
  491. };
  492. template <>
  493. struct SerialisationTraits<ci::Message::ProcessMidiMessageReport> : VersionBase
  494. {
  495. template <typename Archive, typename This>
  496. static auto serialise (Archive& archive, This& t)
  497. {
  498. std::byte reserved{};
  499. archive (named ("messageDataControl", t.messageDataControl),
  500. named ("requestedMessages", t.requestedMessages),
  501. named ("reserved", reserved),
  502. named ("channelControllerMessages", t.channelControllerMessages),
  503. named ("noteDataMessages", t.noteDataMessages));
  504. }
  505. };
  506. template <>
  507. struct SerialisationTraits<ci::Message::ProcessEndMidiMessageReport> : VersionBase
  508. {
  509. template <typename Archive, typename This>
  510. static auto serialise (Archive&, This&)
  511. {
  512. }
  513. };
  514. } // namespace juce
  515. #endif // ifndef DOXYGEN