/* ============================================================================== This file is part of the JUCE 7 technical preview. Copyright (c) 2022 - Raw Material Software Limited You may use this code under the terms of the GPL v3 (see www.gnu.org/licenses). For the technical preview this file cannot be licensed commercially. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ namespace juce { class ARADocumentControllerSpecialisation::ARADocumentControllerImpl : public ARADocumentController, private juce::Timer { public: ARADocumentControllerImpl (const ARA::PlugIn::PlugInEntry* entry, const ARA::ARADocumentControllerHostInstance* instance, ARADocumentControllerSpecialisation* spec) : ARADocumentController (entry, instance), specialisation (spec) { } template std::vector const& getPlaybackRenderers() const noexcept { return ARA::PlugIn::DocumentController::getPlaybackRenderers(); } template std::vector const& getEditorRenderers() const noexcept { return ARA::PlugIn::DocumentController::getEditorRenderers(); } template std::vector const& getEditorViews() const noexcept { return ARA::PlugIn::DocumentController::getEditorViews(); } auto getSpecialisation() { return specialisation; } protected: //============================================================================== bool doRestoreObjectsFromStream (ARAInputStream& input, const ARARestoreObjectsFilter* filter) noexcept { return specialisation->doRestoreObjectsFromStream (input, filter); } bool doStoreObjectsToStream (ARAOutputStream& output, const ARAStoreObjectsFilter* filter) noexcept { return specialisation->doStoreObjectsToStream (output, filter); } //============================================================================== // Model object creation ARA::PlugIn::Document* doCreateDocument () noexcept override; ARA::PlugIn::MusicalContext* doCreateMusicalContext (ARA::PlugIn::Document* document, ARA::ARAMusicalContextHostRef hostRef) noexcept override; ARA::PlugIn::RegionSequence* doCreateRegionSequence (ARA::PlugIn::Document* document, ARA::ARARegionSequenceHostRef hostRef) noexcept override; ARA::PlugIn::AudioSource* doCreateAudioSource (ARA::PlugIn::Document* document, ARA::ARAAudioSourceHostRef hostRef) noexcept override; ARA::PlugIn::AudioModification* doCreateAudioModification (ARA::PlugIn::AudioSource* audioSource, ARA::ARAAudioModificationHostRef hostRef, const ARA::PlugIn::AudioModification* optionalModificationToClone) noexcept override; ARA::PlugIn::PlaybackRegion* doCreatePlaybackRegion (ARA::PlugIn::AudioModification* modification, ARA::ARAPlaybackRegionHostRef hostRef) noexcept override; //============================================================================== // Plugin role implementation friend class ARAPlaybackRegionReader; ARA::PlugIn::PlaybackRenderer* doCreatePlaybackRenderer() noexcept override; ARA::PlugIn::EditorRenderer* doCreateEditorRenderer() noexcept override; ARA::PlugIn::EditorView* doCreateEditorView() noexcept override; //============================================================================== // ARAAudioSource content access bool doIsAudioSourceContentAvailable (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) noexcept override; ARA::ARAContentGrade doGetAudioSourceContentGrade (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) noexcept override; ARA::PlugIn::ContentReader* doCreateAudioSourceContentReader (ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) noexcept override; //============================================================================== // ARAAudioModification content access bool doIsAudioModificationContentAvailable (const ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type) noexcept override; ARA::ARAContentGrade doGetAudioModificationContentGrade (const ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type) noexcept override; ARA::PlugIn::ContentReader* doCreateAudioModificationContentReader (ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) noexcept override; //============================================================================== // ARAPlaybackRegion content access bool doIsPlaybackRegionContentAvailable (const ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type) noexcept override; ARA::ARAContentGrade doGetPlaybackRegionContentGrade (const ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type) noexcept override; ARA::PlugIn::ContentReader* doCreatePlaybackRegionContentReader (ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) noexcept override; //============================================================================== // ARAAudioSource analysis bool doIsAudioSourceContentAnalysisIncomplete (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) noexcept override; void doRequestAudioSourceContentAnalysis (ARA::PlugIn::AudioSource* audioSource, std::vector const& contentTypes) noexcept override; //============================================================================== // Analysis Algorithm selection ARA::ARAInt32 doGetProcessingAlgorithmsCount() noexcept override; const ARA::ARAProcessingAlgorithmProperties* doGetProcessingAlgorithmProperties (ARA::ARAInt32 algorithmIndex) noexcept override; ARA::ARAInt32 doGetProcessingAlgorithmForAudioSource (const ARA::PlugIn::AudioSource* audioSource) noexcept override; void doRequestProcessingAlgorithmForAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::ARAInt32 algorithmIndex) noexcept override; #ifndef DOXYGEN //============================================================================== bool doRestoreObjectsFromArchive (ARA::PlugIn::HostArchiveReader* archiveReader, const ARA::PlugIn::RestoreObjectsFilter* filter) noexcept override; bool doStoreObjectsToArchive (ARA::PlugIn::HostArchiveWriter* archiveWriter, const ARA::PlugIn::StoreObjectsFilter* filter) noexcept override; //============================================================================== // Document notifications void willBeginEditing() noexcept override; void didEndEditing() noexcept override; void willNotifyModelUpdates() noexcept override; void didNotifyModelUpdates() noexcept override; void willUpdateDocumentProperties (ARA::PlugIn::Document* document, ARADocument::PropertiesPtr newProperties) noexcept override; void didUpdateDocumentProperties (ARA::PlugIn::Document* document) noexcept override; void didAddMusicalContextToDocument (ARA::PlugIn::Document* document, ARA::PlugIn::MusicalContext* musicalContext) noexcept override; void willRemoveMusicalContextFromDocument (ARA::PlugIn::Document* document, ARA::PlugIn::MusicalContext* musicalContext) noexcept override; void didReorderMusicalContextsInDocument (ARA::PlugIn::Document* document) noexcept override; void didAddRegionSequenceToDocument (ARA::PlugIn::Document* document, ARA::PlugIn::RegionSequence* regionSequence) noexcept override; void willRemoveRegionSequenceFromDocument (ARA::PlugIn::Document* document, ARA::PlugIn::RegionSequence* regionSequence) noexcept override; void didReorderRegionSequencesInDocument (ARA::PlugIn::Document* document) noexcept override; void didAddAudioSourceToDocument (ARA::PlugIn::Document* document, ARA::PlugIn::AudioSource* audioSource) noexcept override; void willRemoveAudioSourceFromDocument (ARA::PlugIn::Document* document, ARA::PlugIn::AudioSource* audioSource) noexcept override; void willDestroyDocument (ARA::PlugIn::Document* document) noexcept override; //============================================================================== // MusicalContext notifications void willUpdateMusicalContextProperties (ARA::PlugIn::MusicalContext* musicalContext, ARAMusicalContext::PropertiesPtr newProperties) noexcept override; void didUpdateMusicalContextProperties (ARA::PlugIn::MusicalContext* musicalContext) noexcept override; void doUpdateMusicalContextContent (ARA::PlugIn::MusicalContext* musicalContext, const ARA::ARAContentTimeRange* range, ARA::ContentUpdateScopes flags) noexcept override; void didAddRegionSequenceToMusicalContext (ARA::PlugIn::MusicalContext* musicalContext, ARA::PlugIn::RegionSequence* regionSequence) noexcept override; void willRemoveRegionSequenceFromMusicalContext (ARA::PlugIn::MusicalContext* musicalContext, ARA::PlugIn::RegionSequence* regionSequence) noexcept override; void didReorderRegionSequencesInMusicalContext (ARA::PlugIn::MusicalContext* musicalContext) noexcept override; void willDestroyMusicalContext (ARA::PlugIn::MusicalContext* musicalContext) noexcept override; //============================================================================== // RegionSequence notifications, typically not overridden further void willUpdateRegionSequenceProperties (ARA::PlugIn::RegionSequence* regionSequence, ARARegionSequence::PropertiesPtr newProperties) noexcept override; void didUpdateRegionSequenceProperties (ARA::PlugIn::RegionSequence* regionSequence) noexcept override; void didAddPlaybackRegionToRegionSequence (ARA::PlugIn::RegionSequence* regionSequence, ARA::PlugIn::PlaybackRegion* playbackRegion) noexcept override; void willRemovePlaybackRegionFromRegionSequence (ARA::PlugIn::RegionSequence* regionSequence, ARA::PlugIn::PlaybackRegion* playbackRegion) noexcept override; void willDestroyRegionSequence (ARA::PlugIn::RegionSequence* regionSequence) noexcept override; //============================================================================== // AudioSource notifications void willUpdateAudioSourceProperties (ARA::PlugIn::AudioSource* audioSource, ARAAudioSource::PropertiesPtr newProperties) noexcept override; void didUpdateAudioSourceProperties (ARA::PlugIn::AudioSource* audioSource) noexcept override; void doUpdateAudioSourceContent (ARA::PlugIn::AudioSource* audioSource, const ARA::ARAContentTimeRange* range, ARA::ContentUpdateScopes flags) noexcept override; void willEnableAudioSourceSamplesAccess (ARA::PlugIn::AudioSource* audioSource, bool enable) noexcept override; void didEnableAudioSourceSamplesAccess (ARA::PlugIn::AudioSource* audioSource, bool enable) noexcept override; void didAddAudioModificationToAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::PlugIn::AudioModification* audioModification) noexcept override; void willRemoveAudioModificationFromAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::PlugIn::AudioModification* audioModification) noexcept override; void willDeactivateAudioSourceForUndoHistory (ARA::PlugIn::AudioSource* audioSource, bool deactivate) noexcept override; void didDeactivateAudioSourceForUndoHistory (ARA::PlugIn::AudioSource* audioSource, bool deactivate) noexcept override; void willDestroyAudioSource (ARA::PlugIn::AudioSource* audioSource) noexcept override; //============================================================================== // AudioModification notifications void willUpdateAudioModificationProperties (ARA::PlugIn::AudioModification* audioModification, ARAAudioModification::PropertiesPtr newProperties) noexcept override; void didUpdateAudioModificationProperties (ARA::PlugIn::AudioModification* audioModification) noexcept override; void didAddPlaybackRegionToAudioModification (ARA::PlugIn::AudioModification* audioModification, ARA::PlugIn::PlaybackRegion* playbackRegion) noexcept override; void willRemovePlaybackRegionFromAudioModification (ARA::PlugIn::AudioModification* audioModification, ARA::PlugIn::PlaybackRegion* playbackRegion) noexcept override; void willDeactivateAudioModificationForUndoHistory (ARA::PlugIn::AudioModification* audioModification, bool deactivate) noexcept override; void didDeactivateAudioModificationForUndoHistory (ARA::PlugIn::AudioModification* audioModification, bool deactivate) noexcept override; void willDestroyAudioModification (ARA::PlugIn::AudioModification* audioModification) noexcept override; //============================================================================== // PlaybackRegion notifications void willUpdatePlaybackRegionProperties (ARA::PlugIn::PlaybackRegion* playbackRegion, ARAPlaybackRegion::PropertiesPtr newProperties) noexcept override; void didUpdatePlaybackRegionProperties (ARA::PlugIn::PlaybackRegion* playbackRegion) noexcept override; void willDestroyPlaybackRegion (ARA::PlugIn::PlaybackRegion* playbackRegion) noexcept override; //============================================================================== // juce::Timer overrides void timerCallback() override; public: //============================================================================== /** @internal */ void internalNotifyAudioSourceAnalysisProgressStarted (ARAAudioSource* audioSource) override; /** @internal */ void internalNotifyAudioSourceAnalysisProgressUpdated (ARAAudioSource* audioSource, float progress) override; /** @internal */ void internalNotifyAudioSourceAnalysisProgressCompleted (ARAAudioSource* audioSource) override; /** @internal */ void internalDidUpdateAudioSourceAnalysisProgress (ARAAudioSource* audioSource, ARAAudioSource::ARAAnalysisProgressState state, float progress) override; //============================================================================== /** @internal */ void internalNotifyAudioSourceContentChanged (ARAAudioSource* audioSource, ARAContentUpdateScopes scopeFlags, bool notifyARAHost) override; /** @internal */ void internalNotifyAudioModificationContentChanged (ARAAudioModification* audioModification, ARAContentUpdateScopes scopeFlags, bool notifyARAHost) override; /** @internal */ void internalNotifyPlaybackRegionContentChanged (ARAPlaybackRegion* playbackRegion, ARAContentUpdateScopes scopeFlags, bool notifyARAHost) override; #endif private: //============================================================================== ARADocumentControllerSpecialisation* specialisation; std::atomic internalAnalysisProgressIsSynced { true }; ScopedJuceInitialiser_GUI libraryInitialiser; int activeAudioSourcesCount = 0; //============================================================================== template void notifyListeners (Function ModelObject::Listener::* function, ModelObject* modelObject, Ts... ts) { (specialisation->*function) (modelObject, ts...); modelObject->notifyListeners ([&] (auto& l) { try { (l.*function) (modelObject, ts...); } catch (...) { } }); } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ARADocumentControllerImpl) }; ARA::PlugIn::DocumentController* ARADocumentControllerSpecialisation::getDocumentController() noexcept { return documentController.get(); } //============================================================================== void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::internalNotifyAudioSourceAnalysisProgressStarted (ARAAudioSource* audioSource) { if (audioSource->internalAnalysisProgressTracker.updateProgress (ARA::kARAAnalysisProgressStarted, 0.0f)) internalAnalysisProgressIsSynced.store (false, std::memory_order_release); DocumentController::notifyAudioSourceAnalysisProgressStarted (audioSource); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::internalNotifyAudioSourceAnalysisProgressUpdated (ARAAudioSource* audioSource, float progress) { if (audioSource->internalAnalysisProgressTracker.updateProgress (ARA::kARAAnalysisProgressUpdated, progress)) internalAnalysisProgressIsSynced.store (false, std::memory_order_release); DocumentController::notifyAudioSourceAnalysisProgressUpdated (audioSource, progress); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::internalNotifyAudioSourceAnalysisProgressCompleted (ARAAudioSource* audioSource) { if (audioSource->internalAnalysisProgressTracker.updateProgress (ARA::kARAAnalysisProgressCompleted, 1.0f)) internalAnalysisProgressIsSynced.store (false, std::memory_order_release); DocumentController::notifyAudioSourceAnalysisProgressCompleted (audioSource); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::internalDidUpdateAudioSourceAnalysisProgress (ARAAudioSource* audioSource, ARAAudioSource::ARAAnalysisProgressState state, float progress) { specialisation->didUpdateAudioSourceAnalysisProgress (audioSource, state, progress); } //============================================================================== ARADocumentControllerSpecialisation* ARADocumentControllerSpecialisation::getSpecialisedDocumentControllerImpl (ARA::PlugIn::DocumentController* dc) { return static_cast (dc)->getSpecialisation(); } ARADocument* ARADocumentControllerSpecialisation::getDocumentImpl() { return documentController->getDocument(); } //============================================================================== // some helper macros to ease repeated declaration & implementation of notification functions below: JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wgnu-zero-variadic-macro-arguments") // no notification arguments #define OVERRIDE_TO_NOTIFY_1(function, ModelObjectType, modelObject) \ void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::function (ARA::PlugIn::ModelObjectType* modelObject) noexcept \ { \ notifyListeners (&ARA##ModelObjectType::Listener::function, static_cast (modelObject)); \ } // single notification argument, model object version #define OVERRIDE_TO_NOTIFY_2(function, ModelObjectType, modelObject, ArgumentType, argument) \ void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::function (ARA::PlugIn::ModelObjectType* modelObject, ARA::PlugIn::ArgumentType argument) noexcept \ { \ notifyListeners (&ARA##ModelObjectType::Listener::function, static_cast (modelObject), static_cast (argument)); \ } // single notification argument, non-model object version #define OVERRIDE_TO_NOTIFY_3(function, ModelObjectType, modelObject, ArgumentType, argument) \ void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::function (ARA::PlugIn::ModelObjectType* modelObject, ArgumentType argument) noexcept \ { \ notifyListeners (&ARA##ModelObjectType::Listener::function, static_cast (modelObject), argument); \ } //============================================================================== ARA::PlugIn::Document* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateDocument() noexcept { auto* document = specialisation->doCreateDocument(); // Your Document subclass must inherit from juce::ARADocument jassert (dynamic_cast (document)); return document; } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::willBeginEditing() noexcept { notifyListeners (&ARADocument::Listener::willBeginEditing, static_cast (getDocument())); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::didEndEditing() noexcept { notifyListeners (&ARADocument::Listener::didEndEditing, static_cast (getDocument())); if (isTimerRunning() && (activeAudioSourcesCount == 0)) stopTimer(); else if (! isTimerRunning() && (activeAudioSourcesCount > 0)) startTimerHz (20); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::willNotifyModelUpdates() noexcept { notifyListeners (&ARADocument::Listener::willNotifyModelUpdates, static_cast (getDocument())); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::didNotifyModelUpdates() noexcept { notifyListeners (&ARADocument::Listener::didNotifyModelUpdates, static_cast (getDocument())); } //============================================================================== bool ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doRestoreObjectsFromArchive (ARA::PlugIn::HostArchiveReader* archiveReader, const ARA::PlugIn::RestoreObjectsFilter* filter) noexcept { ARAInputStream reader (archiveReader); return doRestoreObjectsFromStream (reader, filter); } bool ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doStoreObjectsToArchive (ARA::PlugIn::HostArchiveWriter* archiveWriter, const ARA::PlugIn::StoreObjectsFilter* filter) noexcept { ARAOutputStream writer (archiveWriter); return doStoreObjectsToStream (writer, filter); } //============================================================================== OVERRIDE_TO_NOTIFY_3 (willUpdateDocumentProperties, Document, document, ARADocument::PropertiesPtr, newProperties) OVERRIDE_TO_NOTIFY_1 (didUpdateDocumentProperties, Document, document) OVERRIDE_TO_NOTIFY_2 (didAddMusicalContextToDocument, Document, document, MusicalContext*, musicalContext) OVERRIDE_TO_NOTIFY_2 (willRemoveMusicalContextFromDocument, Document, document, MusicalContext*, musicalContext) OVERRIDE_TO_NOTIFY_1 (didReorderMusicalContextsInDocument, Document, document) OVERRIDE_TO_NOTIFY_2 (didAddRegionSequenceToDocument, Document, document, RegionSequence*, regionSequence) OVERRIDE_TO_NOTIFY_2 (willRemoveRegionSequenceFromDocument, Document, document, RegionSequence*, regionSequence) OVERRIDE_TO_NOTIFY_1 (didReorderRegionSequencesInDocument, Document, document) OVERRIDE_TO_NOTIFY_2 (didAddAudioSourceToDocument, Document, document, AudioSource*, audioSource) OVERRIDE_TO_NOTIFY_2 (willRemoveAudioSourceFromDocument, Document, document, AudioSource*, audioSource) OVERRIDE_TO_NOTIFY_1 (willDestroyDocument, Document, document) //============================================================================== ARA::PlugIn::MusicalContext* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateMusicalContext (ARA::PlugIn::Document* document, ARA::ARAMusicalContextHostRef hostRef) noexcept { return specialisation->doCreateMusicalContext (static_cast (document), hostRef); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doUpdateMusicalContextContent (ARA::PlugIn::MusicalContext* musicalContext, const ARA::ARAContentTimeRange*, ARA::ContentUpdateScopes flags) noexcept { notifyListeners (&ARAMusicalContext::Listener::doUpdateMusicalContextContent, static_cast (musicalContext), flags); } OVERRIDE_TO_NOTIFY_3 (willUpdateMusicalContextProperties, MusicalContext, musicalContext, ARAMusicalContext::PropertiesPtr, newProperties) OVERRIDE_TO_NOTIFY_1 (didUpdateMusicalContextProperties, MusicalContext, musicalContext) OVERRIDE_TO_NOTIFY_2 (didAddRegionSequenceToMusicalContext, MusicalContext, musicalContext, RegionSequence*, regionSequence) OVERRIDE_TO_NOTIFY_2 (willRemoveRegionSequenceFromMusicalContext, MusicalContext, musicalContext, RegionSequence*, regionSequence) OVERRIDE_TO_NOTIFY_1 (didReorderRegionSequencesInMusicalContext, MusicalContext, musicalContext) OVERRIDE_TO_NOTIFY_1 (willDestroyMusicalContext, MusicalContext, musicalContext) //============================================================================== ARA::PlugIn::RegionSequence* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateRegionSequence (ARA::PlugIn::Document* document, ARA::ARARegionSequenceHostRef hostRef) noexcept { return specialisation->doCreateRegionSequence (static_cast (document), hostRef); } OVERRIDE_TO_NOTIFY_3 (willUpdateRegionSequenceProperties, RegionSequence, regionSequence, ARARegionSequence::PropertiesPtr, newProperties) OVERRIDE_TO_NOTIFY_1 (didUpdateRegionSequenceProperties, RegionSequence, regionSequence) OVERRIDE_TO_NOTIFY_2 (didAddPlaybackRegionToRegionSequence, RegionSequence, regionSequence, PlaybackRegion*, playbackRegion) OVERRIDE_TO_NOTIFY_2 (willRemovePlaybackRegionFromRegionSequence, RegionSequence, regionSequence, PlaybackRegion*, playbackRegion) OVERRIDE_TO_NOTIFY_1 (willDestroyRegionSequence, RegionSequence, regionSequence) //============================================================================== ARA::PlugIn::AudioSource* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateAudioSource (ARA::PlugIn::Document* document, ARA::ARAAudioSourceHostRef hostRef) noexcept { ++activeAudioSourcesCount; return specialisation->doCreateAudioSource (static_cast (document), hostRef); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doUpdateAudioSourceContent (ARA::PlugIn::AudioSource* audioSource, const ARA::ARAContentTimeRange*, ARA::ContentUpdateScopes flags) noexcept { notifyListeners (&ARAAudioSource::Listener::doUpdateAudioSourceContent, static_cast (audioSource), flags); } OVERRIDE_TO_NOTIFY_3 (willUpdateAudioSourceProperties, AudioSource, audioSource, ARAAudioSource::PropertiesPtr, newProperties) OVERRIDE_TO_NOTIFY_1 (didUpdateAudioSourceProperties, AudioSource, audioSource) OVERRIDE_TO_NOTIFY_3 (willEnableAudioSourceSamplesAccess, AudioSource, audioSource, bool, enable) OVERRIDE_TO_NOTIFY_3 (didEnableAudioSourceSamplesAccess, AudioSource, audioSource, bool, enable) OVERRIDE_TO_NOTIFY_2 (didAddAudioModificationToAudioSource, AudioSource, audioSource, AudioModification*, audioModification) OVERRIDE_TO_NOTIFY_2 (willRemoveAudioModificationFromAudioSource, AudioSource, audioSource, AudioModification*, audioModification) OVERRIDE_TO_NOTIFY_3 (willDeactivateAudioSourceForUndoHistory, AudioSource, audioSource, bool, deactivate) void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::didDeactivateAudioSourceForUndoHistory (ARA::PlugIn::AudioSource* audioSource, bool deactivate) noexcept { activeAudioSourcesCount += (deactivate ? -1 : 1); notifyListeners (&ARAAudioSource::Listener::didDeactivateAudioSourceForUndoHistory, static_cast (audioSource), deactivate); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::willDestroyAudioSource (ARA::PlugIn::AudioSource* audioSource) noexcept { if (! audioSource->isDeactivatedForUndoHistory()) --activeAudioSourcesCount; notifyListeners (&ARAAudioSource::Listener::willDestroyAudioSource, static_cast (audioSource)); } //============================================================================== ARA::PlugIn::AudioModification* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateAudioModification (ARA::PlugIn::AudioSource* audioSource, ARA::ARAAudioModificationHostRef hostRef, const ARA::PlugIn::AudioModification* optionalModificationToClone) noexcept { return specialisation->doCreateAudioModification (static_cast (audioSource), hostRef, static_cast (optionalModificationToClone)); } OVERRIDE_TO_NOTIFY_3 (willUpdateAudioModificationProperties, AudioModification, audioModification, ARAAudioModification::PropertiesPtr, newProperties) OVERRIDE_TO_NOTIFY_1 (didUpdateAudioModificationProperties, AudioModification, audioModification) OVERRIDE_TO_NOTIFY_2 (didAddPlaybackRegionToAudioModification, AudioModification, audioModification, PlaybackRegion*, playbackRegion) OVERRIDE_TO_NOTIFY_2 (willRemovePlaybackRegionFromAudioModification, AudioModification, audioModification, PlaybackRegion*, playbackRegion) OVERRIDE_TO_NOTIFY_3 (willDeactivateAudioModificationForUndoHistory, AudioModification, audioModification, bool, deactivate) OVERRIDE_TO_NOTIFY_3 (didDeactivateAudioModificationForUndoHistory, AudioModification, audioModification, bool, deactivate) OVERRIDE_TO_NOTIFY_1 (willDestroyAudioModification, AudioModification, audioModification) //============================================================================== ARA::PlugIn::PlaybackRegion* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreatePlaybackRegion (ARA::PlugIn::AudioModification* modification, ARA::ARAPlaybackRegionHostRef hostRef) noexcept { return specialisation->doCreatePlaybackRegion (static_cast (modification), hostRef); } OVERRIDE_TO_NOTIFY_3 (willUpdatePlaybackRegionProperties, PlaybackRegion, playbackRegion, ARAPlaybackRegion::PropertiesPtr, newProperties) OVERRIDE_TO_NOTIFY_1 (didUpdatePlaybackRegionProperties, PlaybackRegion, playbackRegion) OVERRIDE_TO_NOTIFY_1 (willDestroyPlaybackRegion, PlaybackRegion, playbackRegion) //============================================================================== void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::internalNotifyAudioSourceContentChanged (ARAAudioSource* audioSource, ARAContentUpdateScopes scopeFlags, bool notifyARAHost) { if (notifyARAHost) DocumentController::notifyAudioSourceContentChanged (audioSource, scopeFlags); notifyListeners (&ARAAudioSource::Listener::doUpdateAudioSourceContent, audioSource, scopeFlags); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::internalNotifyAudioModificationContentChanged (ARAAudioModification* audioModification, ARAContentUpdateScopes scopeFlags, bool notifyARAHost) { if (notifyARAHost) DocumentController::notifyAudioModificationContentChanged (audioModification, scopeFlags); notifyListeners (&ARAAudioModification::Listener::didUpdateAudioModificationContent, audioModification, scopeFlags); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::internalNotifyPlaybackRegionContentChanged (ARAPlaybackRegion* playbackRegion, ARAContentUpdateScopes scopeFlags, bool notifyARAHost) { if (notifyARAHost) DocumentController::notifyPlaybackRegionContentChanged (playbackRegion, scopeFlags); notifyListeners (&ARAPlaybackRegion::Listener::didUpdatePlaybackRegionContent, playbackRegion, scopeFlags); } //============================================================================== JUCE_END_IGNORE_WARNINGS_GCC_LIKE #undef OVERRIDE_TO_NOTIFY_1 #undef OVERRIDE_TO_NOTIFY_2 #undef OVERRIDE_TO_NOTIFY_3 //============================================================================== ARADocument* ARADocumentControllerSpecialisation::doCreateDocument() { return new ARADocument (static_cast (getDocumentController())); } ARAMusicalContext* ARADocumentControllerSpecialisation::doCreateMusicalContext (ARADocument* document, ARA::ARAMusicalContextHostRef hostRef) { return new ARAMusicalContext (static_cast (document), hostRef); } ARARegionSequence* ARADocumentControllerSpecialisation::doCreateRegionSequence (ARADocument* document, ARA::ARARegionSequenceHostRef hostRef) { return new ARARegionSequence (static_cast (document), hostRef); } ARAAudioSource* ARADocumentControllerSpecialisation::doCreateAudioSource (ARADocument* document, ARA::ARAAudioSourceHostRef hostRef) { return new ARAAudioSource (static_cast (document), hostRef); } ARAAudioModification* ARADocumentControllerSpecialisation::doCreateAudioModification ( ARAAudioSource* audioSource, ARA::ARAAudioModificationHostRef hostRef, const ARAAudioModification* optionalModificationToClone) { return new ARAAudioModification (static_cast (audioSource), hostRef, static_cast (optionalModificationToClone)); } ARAPlaybackRegion* ARADocumentControllerSpecialisation::doCreatePlaybackRegion (ARAAudioModification* modification, ARA::ARAPlaybackRegionHostRef hostRef) { return new ARAPlaybackRegion (static_cast (modification), hostRef); } //============================================================================== ARA::PlugIn::PlaybackRenderer* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreatePlaybackRenderer() noexcept { return specialisation->doCreatePlaybackRenderer(); } ARA::PlugIn::EditorRenderer* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateEditorRenderer() noexcept { return specialisation->doCreateEditorRenderer(); } ARA::PlugIn::EditorView* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateEditorView() noexcept { return specialisation->doCreateEditorView(); } bool ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doIsAudioSourceContentAvailable (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) noexcept { return specialisation->doIsAudioSourceContentAvailable (audioSource, type); } ARA::ARAContentGrade ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doGetAudioSourceContentGrade (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) noexcept { return specialisation->doGetAudioSourceContentGrade (audioSource, type); } ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateAudioSourceContentReader (ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) noexcept { return specialisation->doCreateAudioSourceContentReader (audioSource, type, range); } bool ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doIsAudioModificationContentAvailable (const ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type) noexcept { return specialisation->doIsAudioModificationContentAvailable (audioModification, type); } ARA::ARAContentGrade ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doGetAudioModificationContentGrade (const ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type) noexcept { return specialisation->doGetAudioModificationContentGrade (audioModification, type); } ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateAudioModificationContentReader (ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) noexcept { return specialisation->doCreateAudioModificationContentReader (audioModification, type, range); } bool ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doIsPlaybackRegionContentAvailable (const ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type) noexcept { return specialisation->doIsPlaybackRegionContentAvailable (playbackRegion, type); } ARA::ARAContentGrade ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doGetPlaybackRegionContentGrade (const ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type) noexcept { return specialisation->doGetPlaybackRegionContentGrade (playbackRegion, type); } ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreatePlaybackRegionContentReader (ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) noexcept { return specialisation->doCreatePlaybackRegionContentReader (playbackRegion, type, range); } bool ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doIsAudioSourceContentAnalysisIncomplete (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) noexcept { return specialisation->doIsAudioSourceContentAnalysisIncomplete (audioSource, type); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doRequestAudioSourceContentAnalysis (ARA::PlugIn::AudioSource* audioSource, std::vector const& contentTypes) noexcept { specialisation->doRequestAudioSourceContentAnalysis (audioSource, contentTypes); } ARA::ARAInt32 ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doGetProcessingAlgorithmsCount() noexcept { return specialisation->doGetProcessingAlgorithmsCount(); } const ARA::ARAProcessingAlgorithmProperties* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doGetProcessingAlgorithmProperties (ARA::ARAInt32 algorithmIndex) noexcept { return specialisation->doGetProcessingAlgorithmProperties (algorithmIndex); } ARA::ARAInt32 ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doGetProcessingAlgorithmForAudioSource (const ARA::PlugIn::AudioSource* audioSource) noexcept { return specialisation->doGetProcessingAlgorithmForAudioSource (audioSource); } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doRequestProcessingAlgorithmForAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::ARAInt32 algorithmIndex) noexcept { return specialisation->doRequestProcessingAlgorithmForAudioSource (audioSource, algorithmIndex); } //============================================================================== // Helper code for ARADocumentControllerSpecialisation::ARADocumentControllerImpl::timerCallback() to // rewire the host-related ARA SDK's progress tracker to our internal update mechanism. namespace ModelUpdateControllerProgressAdapter { using namespace ARA; static void ARA_CALL notifyAudioSourceAnalysisProgress (ARAModelUpdateControllerHostRef /*controllerHostRef*/, ARAAudioSourceHostRef audioSourceHostRef, ARAAnalysisProgressState state, float value) noexcept { auto audioSource = reinterpret_cast (audioSourceHostRef); audioSource->getDocumentController()->internalDidUpdateAudioSourceAnalysisProgress (audioSource, state, value); audioSource->notifyListeners ([&] (ARAAudioSource::Listener& l) { l.didUpdateAudioSourceAnalysisProgress (audioSource, state, value); }); } static void ARA_CALL notifyAudioSourceContentChanged (ARAModelUpdateControllerHostRef, ARAAudioSourceHostRef, const ARAContentTimeRange*, ARAContentUpdateFlags) noexcept { jassertfalse; // not to be called - this adapter only forwards analysis progress } static void ARA_CALL notifyAudioModificationContentChanged (ARAModelUpdateControllerHostRef, ARAAudioModificationHostRef, const ARAContentTimeRange*, ARAContentUpdateFlags) noexcept { jassertfalse; // not to be called - this adapter only forwards analysis progress } static void ARA_CALL notifyPlaybackRegionContentChanged (ARAModelUpdateControllerHostRef, ARAPlaybackRegionHostRef, const ARAContentTimeRange*, ARAContentUpdateFlags) noexcept { jassertfalse; // not to be called - this adapter only forwards analysis progress } static ARA::PlugIn::HostModelUpdateController* get() { static const auto modelUpdateControllerInterface = makeARASizedStruct (&ARA::ARAModelUpdateControllerInterface::notifyPlaybackRegionContentChanged, ModelUpdateControllerProgressAdapter::notifyAudioSourceAnalysisProgress, ModelUpdateControllerProgressAdapter::notifyAudioSourceContentChanged, ModelUpdateControllerProgressAdapter::notifyAudioModificationContentChanged, ModelUpdateControllerProgressAdapter::notifyPlaybackRegionContentChanged); static const auto instance = makeARASizedStruct (&ARA::ARADocumentControllerHostInstance::playbackControllerInterface, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &modelUpdateControllerInterface, nullptr, nullptr); static auto progressAdapter = ARA::PlugIn::HostModelUpdateController { &instance }; return &progressAdapter; } } void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::timerCallback() { if (! internalAnalysisProgressIsSynced.exchange (true, std::memory_order_release)) for (auto& audioSource : getDocument()->getAudioSources()) audioSource->internalAnalysisProgressTracker.notifyProgress (ModelUpdateControllerProgressAdapter::get(), reinterpret_cast (audioSource)); } //============================================================================== ARAInputStream::ARAInputStream (ARA::PlugIn::HostArchiveReader* reader) : archiveReader (reader), size ((int64) reader->getArchiveSize()) {} int ARAInputStream::read (void* destBuffer, int maxBytesToRead) { const auto bytesToRead = std::min ((int64) maxBytesToRead, size - position); if (bytesToRead > 0 && ! archiveReader->readBytesFromArchive ((ARA::ARASize) position, (ARA::ARASize) bytesToRead, static_cast (destBuffer))) { failure = true; return 0; } position += bytesToRead; return (int) bytesToRead; } bool ARAInputStream::setPosition (int64 newPosition) { position = jlimit ((int64) 0, size, newPosition); return true; } bool ARAInputStream::isExhausted() { return position >= size; } ARAOutputStream::ARAOutputStream (ARA::PlugIn::HostArchiveWriter* writer) : archiveWriter (writer) {} bool ARAOutputStream::write (const void* dataToWrite, size_t numberOfBytes) { if (! archiveWriter->writeBytesToArchive ((ARA::ARASize) position, numberOfBytes, (const ARA::ARAByte*) dataToWrite)) return false; position += numberOfBytes; return true; } bool ARAOutputStream::setPosition (int64 newPosition) { position = newPosition; return true; } //============================================================================== ARADocumentControllerSpecialisation::ARADocumentControllerSpecialisation ( const ARA::PlugIn::PlugInEntry* entry, const ARA::ARADocumentControllerHostInstance* instance) : documentController (std::make_unique (entry, instance, this)) { } ARADocumentControllerSpecialisation::~ARADocumentControllerSpecialisation() = default; ARAPlaybackRenderer* ARADocumentControllerSpecialisation::doCreatePlaybackRenderer() { return new ARAPlaybackRenderer (getDocumentController()); } ARAEditorRenderer* ARADocumentControllerSpecialisation::doCreateEditorRenderer() { return new ARAEditorRenderer (getDocumentController()); } ARAEditorView* ARADocumentControllerSpecialisation::doCreateEditorView() { return new ARAEditorView (getDocumentController()); } bool ARADocumentControllerSpecialisation::doIsAudioSourceContentAvailable (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) { juce::ignoreUnused (audioSource, type); return false; } ARA::ARAContentGrade ARADocumentControllerSpecialisation::doGetAudioSourceContentGrade (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) { // Overriding doIsAudioSourceContentAvailable() requires overriding // doGetAudioSourceContentGrade() accordingly! jassertfalse; juce::ignoreUnused (audioSource, type); return ARA::kARAContentGradeInitial; } ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::doCreateAudioSourceContentReader (ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) { // Overriding doIsAudioSourceContentAvailable() requires overriding // doCreateAudioSourceContentReader() accordingly! jassertfalse; juce::ignoreUnused (audioSource, type, range); return nullptr; } bool ARADocumentControllerSpecialisation::doIsAudioModificationContentAvailable (const ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type) { juce::ignoreUnused (audioModification, type); return false; } ARA::ARAContentGrade ARADocumentControllerSpecialisation::doGetAudioModificationContentGrade (const ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type) { // Overriding doIsAudioModificationContentAvailable() requires overriding // doGetAudioModificationContentGrade() accordingly! jassertfalse; juce::ignoreUnused (audioModification, type); return ARA::kARAContentGradeInitial; } ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::doCreateAudioModificationContentReader (ARA::PlugIn::AudioModification* audioModification, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) { // Overriding doIsAudioModificationContentAvailable() requires overriding // doCreateAudioModificationContentReader() accordingly! jassertfalse; juce::ignoreUnused (audioModification, type, range); return nullptr; } bool ARADocumentControllerSpecialisation::doIsPlaybackRegionContentAvailable (const ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type) { juce::ignoreUnused (playbackRegion, type); return false; } ARA::ARAContentGrade ARADocumentControllerSpecialisation::doGetPlaybackRegionContentGrade (const ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type) { // Overriding doIsPlaybackRegionContentAvailable() requires overriding // doGetPlaybackRegionContentGrade() accordingly! jassertfalse; juce::ignoreUnused (playbackRegion, type); return ARA::kARAContentGradeInitial; } ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::doCreatePlaybackRegionContentReader (ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) { // Overriding doIsPlaybackRegionContentAvailable() requires overriding // doCreatePlaybackRegionContentReader() accordingly! jassertfalse; juce::ignoreUnused (playbackRegion, type, range); return nullptr; } bool ARADocumentControllerSpecialisation::doIsAudioSourceContentAnalysisIncomplete (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) { juce::ignoreUnused (audioSource, type); return false; } void ARADocumentControllerSpecialisation::doRequestAudioSourceContentAnalysis (ARA::PlugIn::AudioSource* audioSource, std::vector const& contentTypes) { juce::ignoreUnused (audioSource, contentTypes); } ARA::ARAInt32 ARADocumentControllerSpecialisation::doGetProcessingAlgorithmsCount() { return 0; } const ARA::ARAProcessingAlgorithmProperties* ARADocumentControllerSpecialisation::doGetProcessingAlgorithmProperties (ARA::ARAInt32 algorithmIndex) { juce::ignoreUnused (algorithmIndex); return nullptr; } ARA::ARAInt32 ARADocumentControllerSpecialisation::doGetProcessingAlgorithmForAudioSource (const ARA::PlugIn::AudioSource* audioSource) { // doGetProcessingAlgorithmForAudioSource() must be implemented if the supported // algorithm count is greater than zero. if (getDocumentController()->getProcessingAlgorithmsCount() > 0) jassertfalse; juce::ignoreUnused (audioSource); return 0; } void ARADocumentControllerSpecialisation::doRequestProcessingAlgorithmForAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::ARAInt32 algorithmIndex) { // doRequestProcessingAlgorithmForAudioSource() must be implemented if the supported // algorithm count is greater than zero. if (getDocumentController()->getProcessingAlgorithmsCount() > 0) jassertfalse; juce::ignoreUnused (audioSource, algorithmIndex); } } // namespace juce