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.

521 lines
25KB

  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. #pragma once
  19. namespace juce
  20. {
  21. class ARAPlaybackRenderer;
  22. class ARAEditorRenderer;
  23. class ARAEditorView;
  24. class ARAInputStream;
  25. class ARAOutputStream;
  26. /** This class contains the customisation points for the JUCE provided ARA document controller
  27. implementation.
  28. Every ARA enabled plugin must provide its own document controller implementation. To do this,
  29. inherit from this class, and override its protected methods as needed. Then you need to
  30. implement a global function somewhere in your module called createARAFactory(). This function
  31. must return an ARAFactory* that will instantiate document controller objects using your
  32. specialisation. There are helper functions inside ARADocumentControllerSpecialisation, so the
  33. implementation of createARAFactory() can always be a simple one-liner. For example
  34. @code
  35. class MyDocumentController : public ARADocumentControllerSpecialisation
  36. {
  37. //...
  38. };
  39. const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory()
  40. {
  41. return juce::ARADocumentControllerSpecialisation::createARAFactory<MyDocumentController>();
  42. }
  43. @endcode
  44. Most member functions have a default implementation so you can build up your required feature
  45. set gradually. The protected functions of this class fall in three distinct groups:
  46. - interactive editing and playback,
  47. - analysis features provided by the plugin and utilised by the host, and
  48. - maintaining the ARA model graph.
  49. On top of the pure virtual functions, you will probably want to override
  50. doCreatePlaybackRenderer() at the very least if you want your plugin to play any sound. This
  51. function belongs to the first group.
  52. If your plugin has analysis capabilities and wants to allow the host to access these, functions
  53. in the second group should be overridden.
  54. The default implementation of the ARA model object classes - i.e. ARADocument, ARAMusicalContext,
  55. ARARegionSequence, ARAAudioSource, ARAAudioModification, ARAPlaybackRegion - should be sufficient
  56. for maintaining a representation of the ARA model graph, hence overriding the model object
  57. creation functions e.g. doCreateMusicalContext() is considered an advanced use case. Hence you
  58. should be able to get a lot done without overriding functions in the third group.
  59. In order to react to the various ARA state changes you can override any of the ARA model object
  60. Listener functions that ARADocumentControllerSpecialisation inherits from. Such listener
  61. functions can be attached to one particular model objects instance, but the listener functions
  62. inside ARADocumentControllerSpecialisation will respond to the events of all instances of the
  63. model objects.
  64. @tags{ARA}
  65. */
  66. class ARADocumentControllerSpecialisation : public ARADocument::Listener,
  67. public ARAMusicalContext::Listener,
  68. public ARARegionSequence::Listener,
  69. public ARAAudioSource::Listener,
  70. public ARAAudioModification::Listener,
  71. public ARAPlaybackRegion::Listener
  72. {
  73. public:
  74. //==============================================================================
  75. /** Constructor. Used internally by the ARAFactory implementation.
  76. */
  77. ARADocumentControllerSpecialisation (const ARA::PlugIn::PlugInEntry* entry,
  78. const ARA::ARADocumentControllerHostInstance* instance);
  79. /** Destructor. */
  80. virtual ~ARADocumentControllerSpecialisation();
  81. /** Returns the underlying DocumentController object that references this specialisation.
  82. */
  83. ARA::PlugIn::DocumentController* getDocumentController() noexcept;
  84. /** Helper function for implementing the global createARAFactory() function.
  85. For example
  86. @code
  87. class MyDocumentController : public ARADocumentControllerSpecialisation
  88. {
  89. //...
  90. };
  91. const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory()
  92. {
  93. return juce::ARADocumentControllerSpecialisation::createARAFactory<MyDocumentController>();
  94. }
  95. @endcode
  96. */
  97. template <typename SpecialisationType>
  98. static const ARA::ARAFactory* createARAFactory()
  99. {
  100. static_assert (std::is_base_of<ARADocumentControllerSpecialisation, SpecialisationType>::value,
  101. "DocumentController specialization types must inherit from ARADocumentControllerSpecialisation");
  102. return ARA::PlugIn::PlugInEntry::getPlugInEntry<FactoryConfig<SpecialisationType>>()->getFactory();
  103. }
  104. /** Returns a pointer to the ARADocumentControllerSpecialisation instance that is referenced
  105. by the provided DocumentController. You can use this function to access your specialisation
  106. from anywhere where you have access to ARA::PlugIn::DocumentController*.
  107. */
  108. template <typename Specialisation = ARADocumentControllerSpecialisation>
  109. static Specialisation* getSpecialisedDocumentController (ARA::PlugIn::DocumentController* dc)
  110. {
  111. return static_cast<Specialisation*> (getSpecialisedDocumentControllerImpl (dc));
  112. }
  113. /** Returns a pointer to the ARA document root maintained by this document controller. */
  114. template <typename DocumentType = ARADocument>
  115. DocumentType* getDocument()
  116. {
  117. return static_cast<DocumentType*> (getDocumentImpl());
  118. }
  119. protected:
  120. //==============================================================================
  121. /** Read an ARADocument archive from a juce::InputStream.
  122. @param input Data stream containing previously persisted data to be used when restoring the ARADocument
  123. @param filter A filter to be applied to the stream
  124. Return true if the operation is successful.
  125. @see ARADocumentControllerInterface::restoreObjectsFromArchive
  126. */
  127. virtual bool doRestoreObjectsFromStream (ARAInputStream& input, const ARARestoreObjectsFilter* filter) = 0;
  128. /** Write an ARADocument archive to a juce::OutputStream.
  129. @param output Data stream that should be used to write the persistent ARADocument data
  130. @param filter A filter to be applied to the stream
  131. Returns true if the operation is successful.
  132. @see ARADocumentControllerInterface::storeObjectsToArchive
  133. */
  134. virtual bool doStoreObjectsToStream (ARAOutputStream& output, const ARAStoreObjectsFilter* filter) = 0;
  135. //==============================================================================
  136. /** Override to return a custom subclass instance of ARAPlaybackRenderer. */
  137. virtual ARAPlaybackRenderer* doCreatePlaybackRenderer();
  138. /** Override to return a custom subclass instance of ARAEditorRenderer. */
  139. virtual ARAEditorRenderer* doCreateEditorRenderer();
  140. /** Override to return a custom subclass instance of ARAEditorView. */
  141. virtual ARAEditorView* doCreateEditorView();
  142. //==============================================================================
  143. // ARAAudioSource content access
  144. /** Override to implement isAudioSourceContentAvailable() for all your supported content types -
  145. the default implementation always returns false, preventing any calls to doGetAudioSourceContentGrade()
  146. and doCreateAudioSourceContentReader().
  147. This function's result is returned from
  148. ARA::PlugIn::DocumentControllerDelegate::doIsAudioSourceContentAvailable.
  149. */
  150. virtual bool doIsAudioSourceContentAvailable (const ARA::PlugIn::AudioSource* audioSource,
  151. ARA::ARAContentType type);
  152. /** Override to implement getAudioSourceContentGrade() for all your supported content types.
  153. This function's result is returned from
  154. ARA::PlugIn::DocumentControllerDelegate::doGetAudioSourceContentGrade.
  155. */
  156. virtual ARA::ARAContentGrade doGetAudioSourceContentGrade (const ARA::PlugIn::AudioSource* audioSource,
  157. ARA::ARAContentType type);
  158. /** Override to implement createAudioSourceContentReader() for all your supported content types,
  159. returning a custom subclass instance of ContentReader providing data of the requested type.
  160. This function's result is returned from
  161. ARA::PlugIn::DocumentControllerDelegate::doCreateAudioSourceContentReader.
  162. */
  163. virtual ARA::PlugIn::ContentReader* doCreateAudioSourceContentReader (ARA::PlugIn::AudioSource* audioSource,
  164. ARA::ARAContentType type,
  165. const ARA::ARAContentTimeRange* range);
  166. //==============================================================================
  167. // ARAAudioModification content access
  168. /** Override to implement isAudioModificationContentAvailable() for all your supported content types -
  169. the default implementation always returns false.
  170. For read-only data directly inherited from the underlying audio source you can just delegate the
  171. call to the audio source, but user-editable modification data must be specifically handled here.
  172. This function's result is returned from
  173. ARA::PlugIn::DocumentControllerDelegate::doIsAudioModificationContentAvailable.
  174. */
  175. virtual bool doIsAudioModificationContentAvailable (const ARA::PlugIn::AudioModification* audioModification,
  176. ARA::ARAContentType type);
  177. /** Override to implement getAudioModificationContentGrade() for all your supported content types.
  178. For read-only data directly inherited from the underlying audio source you can just delegate the
  179. call to the audio source, but user-editable modification data must be specifically handled here.
  180. This function's result is returned from
  181. ARA::PlugIn::DocumentControllerDelegate::doGetAudioModificationContentGrade.
  182. */
  183. virtual ARA::ARAContentGrade doGetAudioModificationContentGrade (const ARA::PlugIn::AudioModification* audioModification,
  184. ARA::ARAContentType type);
  185. /** Override to implement createAudioModificationContentReader() for all your supported content types,
  186. returning a custom subclass instance of ContentReader providing data of the requested \p type.
  187. For read-only data directly inherited from the underlying audio source you can just delegate the
  188. call to the audio source, but user-editable modification data must be specifically handled here.
  189. This function's result is returned from
  190. ARA::PlugIn::DocumentControllerDelegate::doCreateAudioModificationContentReader.
  191. */
  192. virtual ARA::PlugIn::ContentReader* doCreateAudioModificationContentReader (ARA::PlugIn::AudioModification* audioModification,
  193. ARA::ARAContentType type,
  194. const ARA::ARAContentTimeRange* range);
  195. //==============================================================================
  196. // ARAPlaybackRegion content access
  197. /** Override to implement isPlaybackRegionContentAvailable() for all your supported content types -
  198. the default implementation always returns false.
  199. Typically, this call can directly delegate to the underlying audio modification, since most
  200. plug-ins will apply their modification data to the playback region with a transformation that
  201. does not affect content availability.
  202. This function's result is returned from
  203. ARA::PlugIn::DocumentControllerDelegate::doIsPlaybackRegionContentAvailable.
  204. */
  205. virtual bool doIsPlaybackRegionContentAvailable (const ARA::PlugIn::PlaybackRegion* playbackRegion,
  206. ARA::ARAContentType type);
  207. /** Override to implement getPlaybackRegionContentGrade() for all your supported content types.
  208. Typically, this call can directly delegate to the underlying audio modification, since most
  209. plug-ins will apply their modification data to the playback region with a transformation that
  210. does not affect content grade.
  211. This function's result is returned from
  212. ARA::PlugIn::DocumentControllerDelegate::doGetPlaybackRegionContentGrade.
  213. */
  214. virtual ARA::ARAContentGrade doGetPlaybackRegionContentGrade (const ARA::PlugIn::PlaybackRegion* playbackRegion,
  215. ARA::ARAContentType type);
  216. /** Override to implement createPlaybackRegionContentReader() for all your supported content types,
  217. returning a custom subclass instance of ContentReader providing data of the requested type.
  218. This function's result is returned from
  219. ARA::PlugIn::DocumentControllerDelegate::doCreatePlaybackRegionContentReader.
  220. */
  221. virtual ARA::PlugIn::ContentReader* doCreatePlaybackRegionContentReader (ARA::PlugIn::PlaybackRegion* playbackRegion,
  222. ARA::ARAContentType type,
  223. const ARA::ARAContentTimeRange* range);
  224. //==============================================================================
  225. // ARAAudioSource analysis
  226. /** Override to implement isAudioSourceContentAnalysisIncomplete().
  227. This function's result is returned from
  228. ARA::PlugIn::DocumentControllerDelegate::doIsAudioSourceContentAnalysisIncomplete.
  229. */
  230. virtual bool doIsAudioSourceContentAnalysisIncomplete (const ARA::PlugIn::AudioSource* audioSource,
  231. ARA::ARAContentType type);
  232. /** Override to implement requestAudioSourceContentAnalysis().
  233. This function's called from
  234. ARA::PlugIn::DocumentControllerDelegate::doRequestAudioSourceContentAnalysis.
  235. */
  236. virtual void doRequestAudioSourceContentAnalysis (ARA::PlugIn::AudioSource* audioSource,
  237. std::vector<ARA::ARAContentType> const& contentTypes);
  238. //==============================================================================
  239. // Analysis Algorithm selection
  240. /** Override to implement getProcessingAlgorithmsCount().
  241. This function's result is returned from
  242. ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmsCount.
  243. */
  244. virtual ARA::ARAInt32 doGetProcessingAlgorithmsCount ();
  245. /** Override to implement getProcessingAlgorithmProperties().
  246. This function's result is returned from
  247. ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmProperties.
  248. */
  249. virtual const ARA::ARAProcessingAlgorithmProperties*
  250. doGetProcessingAlgorithmProperties (ARA::ARAInt32 algorithmIndex);
  251. /** Override to implement getProcessingAlgorithmForAudioSource().
  252. This function's result is returned from
  253. ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmForAudioSource.
  254. */
  255. virtual ARA::ARAInt32 doGetProcessingAlgorithmForAudioSource (const ARA::PlugIn::AudioSource* audioSource);
  256. /** Override to implement requestProcessingAlgorithmForAudioSource().
  257. This function's called from
  258. ARA::PlugIn::DocumentControllerDelegate::doRequestProcessingAlgorithmForAudioSource.
  259. */
  260. virtual void doRequestProcessingAlgorithmForAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::ARAInt32 algorithmIndex);
  261. //==============================================================================
  262. /** Override to return a custom subclass instance of ARADocument. */
  263. virtual ARADocument* doCreateDocument();
  264. /** Override to return a custom subclass instance of ARAMusicalContext. */
  265. virtual ARAMusicalContext* doCreateMusicalContext (ARADocument* document,
  266. ARA::ARAMusicalContextHostRef hostRef);
  267. /** Override to return a custom subclass instance of ARARegionSequence. */
  268. virtual ARARegionSequence* doCreateRegionSequence (ARADocument* document,
  269. ARA::ARARegionSequenceHostRef hostRef);
  270. /** Override to return a custom subclass instance of ARAAudioSource. */
  271. virtual ARAAudioSource* doCreateAudioSource (ARADocument* document,
  272. ARA::ARAAudioSourceHostRef hostRef);
  273. /** Override to return a custom subclass instance of ARAAudioModification. */
  274. virtual ARAAudioModification* doCreateAudioModification (ARAAudioSource* audioSource,
  275. ARA::ARAAudioModificationHostRef hostRef,
  276. const ARAAudioModification* optionalModificationToClone);
  277. /** Override to return a custom subclass instance of ARAPlaybackRegion. */
  278. virtual ARAPlaybackRegion* doCreatePlaybackRegion (ARAAudioModification* modification,
  279. ARA::ARAPlaybackRegionHostRef hostRef);
  280. private:
  281. //==============================================================================
  282. template <typename SpecialisationType>
  283. class FactoryConfig : public ARA::PlugIn::FactoryConfig
  284. {
  285. public:
  286. FactoryConfig() noexcept
  287. {
  288. const juce::String compatibleDocumentArchiveIDString = JucePlugin_ARACompatibleArchiveIDs;
  289. if (compatibleDocumentArchiveIDString.isNotEmpty())
  290. {
  291. compatibleDocumentArchiveIDStrings = juce::StringArray::fromLines (compatibleDocumentArchiveIDString);
  292. for (const auto& compatibleID : compatibleDocumentArchiveIDStrings)
  293. compatibleDocumentArchiveIDs.push_back (compatibleID.toRawUTF8());
  294. }
  295. // Update analyzeable content types
  296. static constexpr std::array<ARA::ARAContentType, 6> contentTypes {
  297. ARA::kARAContentTypeNotes,
  298. ARA::kARAContentTypeTempoEntries,
  299. ARA::kARAContentTypeBarSignatures,
  300. ARA::kARAContentTypeStaticTuning,
  301. ARA::kARAContentTypeKeySignatures,
  302. ARA::kARAContentTypeSheetChords
  303. };
  304. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6313)
  305. for (size_t i = 0; i < contentTypes.size(); ++i)
  306. if (JucePlugin_ARAContentTypes & (1 << i))
  307. analyzeableContentTypes.push_back (contentTypes[i]);
  308. JUCE_END_IGNORE_WARNINGS_MSVC
  309. // Update playback transformation flags
  310. static constexpr std::array<ARA::ARAPlaybackTransformationFlags, 4> playbackTransformationFlags {
  311. ARA::kARAPlaybackTransformationTimestretch,
  312. ARA::kARAPlaybackTransformationTimestretchReflectingTempo,
  313. ARA::kARAPlaybackTransformationContentBasedFadeAtTail,
  314. ARA::kARAPlaybackTransformationContentBasedFadeAtHead
  315. };
  316. supportedPlaybackTransformationFlags = 0;
  317. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6313)
  318. for (size_t i = 0; i < playbackTransformationFlags.size(); ++i)
  319. if (JucePlugin_ARATransformationFlags & (1 << i))
  320. supportedPlaybackTransformationFlags |= playbackTransformationFlags[i];
  321. JUCE_END_IGNORE_WARNINGS_MSVC
  322. }
  323. const char* getFactoryID() const noexcept override { return JucePlugin_ARAFactoryID; }
  324. const char* getPlugInName() const noexcept override { return JucePlugin_Name; }
  325. const char* getManufacturerName() const noexcept override { return JucePlugin_Manufacturer; }
  326. const char* getInformationURL() const noexcept override { return JucePlugin_ManufacturerWebsite; }
  327. const char* getVersion() const noexcept override { return JucePlugin_VersionString; }
  328. const char* getDocumentArchiveID() const noexcept override { return JucePlugin_ARADocumentArchiveID; }
  329. ARA::ARASize getCompatibleDocumentArchiveIDsCount() const noexcept override
  330. {
  331. return compatibleDocumentArchiveIDs.size();
  332. }
  333. const ARA::ARAPersistentID* getCompatibleDocumentArchiveIDs() const noexcept override
  334. {
  335. return compatibleDocumentArchiveIDs.empty() ? nullptr : compatibleDocumentArchiveIDs.data();
  336. }
  337. ARA::ARASize getAnalyzeableContentTypesCount() const noexcept override
  338. {
  339. return analyzeableContentTypes.size();
  340. }
  341. const ARA::ARAContentType* getAnalyzeableContentTypes() const noexcept override
  342. {
  343. return analyzeableContentTypes.empty() ? nullptr : analyzeableContentTypes.data();
  344. }
  345. ARA::ARAPlaybackTransformationFlags getSupportedPlaybackTransformationFlags() const noexcept override
  346. {
  347. return supportedPlaybackTransformationFlags;
  348. }
  349. ARA::PlugIn::DocumentController* createDocumentController (const ARA::PlugIn::PlugInEntry* entry,
  350. const ARA::ARADocumentControllerHostInstance* instance) const noexcept override
  351. {
  352. auto* spec = new SpecialisationType (entry, instance);
  353. return spec->getDocumentController();
  354. }
  355. void destroyDocumentController (ARA::PlugIn::DocumentController* controller) const noexcept override
  356. {
  357. delete getSpecialisedDocumentController (controller);
  358. }
  359. private:
  360. juce::StringArray compatibleDocumentArchiveIDStrings;
  361. std::vector<ARA::ARAPersistentID> compatibleDocumentArchiveIDs;
  362. std::vector<ARA::ARAContentType> analyzeableContentTypes;
  363. ARA::ARAPlaybackTransformationFlags supportedPlaybackTransformationFlags;
  364. };
  365. //==============================================================================
  366. static ARADocumentControllerSpecialisation* getSpecialisedDocumentControllerImpl (ARA::PlugIn::DocumentController*);
  367. ARADocument* getDocumentImpl();
  368. //==============================================================================
  369. class ARADocumentControllerImpl;
  370. std::unique_ptr<ARADocumentControllerImpl> documentController;
  371. };
  372. /** Used to read persisted ARA archives - see doRestoreObjectsFromStream() for details.
  373. @tags{ARA}
  374. */
  375. class ARAInputStream : public InputStream
  376. {
  377. public:
  378. explicit ARAInputStream (ARA::PlugIn::HostArchiveReader*);
  379. int64 getPosition() override { return position; }
  380. int64 getTotalLength() override { return size; }
  381. int read (void*, int) override;
  382. bool setPosition (int64) override;
  383. bool isExhausted() override;
  384. bool failed() const { return failure; }
  385. private:
  386. ARA::PlugIn::HostArchiveReader* archiveReader;
  387. int64 position = 0;
  388. int64 size;
  389. bool failure = false;
  390. };
  391. /** Used to write persistent ARA archives - see doStoreObjectsToStream() for details.
  392. @tags{ARA}
  393. */
  394. class ARAOutputStream : public OutputStream
  395. {
  396. public:
  397. explicit ARAOutputStream (ARA::PlugIn::HostArchiveWriter*);
  398. int64 getPosition() override { return position; }
  399. void flush() override {}
  400. bool write (const void*, size_t) override;
  401. bool setPosition (int64) override;
  402. private:
  403. ARA::PlugIn::HostArchiveWriter* archiveWriter;
  404. int64 position = 0;
  405. };
  406. } // namespace juce