mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
ARAHosting: Move to juce_audio_processors_headless
This commit is contained in:
parent
9c88358e46
commit
edcc699aa8
6 changed files with 2 additions and 2 deletions
|
|
@ -1,488 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU) && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX))
|
||||
|
||||
#include <ARA_Library/Dispatch/ARAHostDispatch.cpp>
|
||||
|
||||
namespace juce
|
||||
{
|
||||
struct ARAEditGuardState
|
||||
{
|
||||
public:
|
||||
/* Returns true if this controller wasn't previously present. */
|
||||
bool add (ARA::Host::DocumentController& dc)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock (mutex);
|
||||
return ++counts[&dc] == 1;
|
||||
}
|
||||
|
||||
/* Returns true if this controller is no longer present. */
|
||||
bool remove (ARA::Host::DocumentController& dc)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock (mutex);
|
||||
return --counts[&dc] == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<ARA::Host::DocumentController*, int> counts;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
static ARAEditGuardState editGuardState;
|
||||
|
||||
ARAEditGuard::ARAEditGuard (ARA::Host::DocumentController& dcIn) : dc (dcIn)
|
||||
{
|
||||
if (editGuardState.add (dc))
|
||||
dc.beginEditing();
|
||||
}
|
||||
|
||||
ARAEditGuard::~ARAEditGuard()
|
||||
{
|
||||
if (editGuardState.remove (dc))
|
||||
dc.endEditing();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace ARAHostModel
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
AudioSource::AudioSource (ARA::ARAAudioSourceHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
const ARA::ARAAudioSourceProperties& props)
|
||||
: ManagedARAHandle (dc, [&]
|
||||
{
|
||||
const ARAEditGuard guard (dc);
|
||||
return dc.createAudioSource (hostRef, &props);
|
||||
}())
|
||||
{
|
||||
}
|
||||
|
||||
void AudioSource::update (const ARA::ARAAudioSourceProperties& props)
|
||||
{
|
||||
const ARAEditGuard guard (getDocumentController());
|
||||
getDocumentController().updateAudioSourceProperties (getPluginRef(), &props);
|
||||
}
|
||||
|
||||
void AudioSource::enableAudioSourceSamplesAccess (bool x)
|
||||
{
|
||||
const ARAEditGuard guard (getDocumentController());
|
||||
getDocumentController().enableAudioSourceSamplesAccess (getPluginRef(), x);
|
||||
}
|
||||
|
||||
void AudioSource::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
|
||||
{
|
||||
dc.destroyAudioSource (ptr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioModification::AudioModification (ARA::ARAAudioModificationHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
AudioSource& s,
|
||||
const ARA::ARAAudioModificationProperties& props)
|
||||
: ManagedARAHandle (dc, [&]
|
||||
{
|
||||
const ARAEditGuard guard (dc);
|
||||
return dc.createAudioModification (s.getPluginRef(), hostRef, &props);
|
||||
}()),
|
||||
source (s)
|
||||
{
|
||||
}
|
||||
|
||||
void AudioModification::update (const ARA::ARAAudioModificationProperties& props)
|
||||
{
|
||||
const ARAEditGuard guard (getDocumentController());
|
||||
getDocumentController().updateAudioModificationProperties (getPluginRef(), &props);
|
||||
}
|
||||
|
||||
void AudioModification::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
|
||||
{
|
||||
dc.destroyAudioModification (ptr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class PlaybackRegion::Impl : public ManagedARAHandle<Impl, ARA::ARAPlaybackRegionRef>,
|
||||
public DeletionListener
|
||||
{
|
||||
public:
|
||||
Impl (ARA::ARAPlaybackRegionHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
AudioModification& m,
|
||||
const ARA::ARAPlaybackRegionProperties& props);
|
||||
|
||||
~Impl() override
|
||||
{
|
||||
for (const auto& l : listeners)
|
||||
l->removeListener (*this);
|
||||
}
|
||||
|
||||
/* Updates the state of the corresponding %ARA model object.
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
You can use getEmptyProperties() to acquire a properties struct where the `structSize`
|
||||
field has already been correctly set.
|
||||
*/
|
||||
void update (const ARA::ARAPlaybackRegionProperties& props);
|
||||
|
||||
auto& getAudioModification() const { return modification; }
|
||||
|
||||
static void destroy (ARA::Host::DocumentController&, Ptr);
|
||||
|
||||
void addListener (DeletionListener& l) { listeners.insert (&l); }
|
||||
void removeListener (DeletionListener& l) noexcept override { listeners.erase (&l); }
|
||||
|
||||
private:
|
||||
AudioModification* modification = nullptr;
|
||||
std::unordered_set<DeletionListener*> listeners;
|
||||
};
|
||||
|
||||
PlaybackRegion::Impl::Impl (ARA::ARAPlaybackRegionHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
AudioModification& m,
|
||||
const ARA::ARAPlaybackRegionProperties& props)
|
||||
: ManagedARAHandle (dc, [&]
|
||||
{
|
||||
const ARAEditGuard guard (dc);
|
||||
return dc.createPlaybackRegion (m.getPluginRef(), hostRef, &props);
|
||||
}()),
|
||||
modification (&m)
|
||||
{
|
||||
}
|
||||
|
||||
PlaybackRegion::~PlaybackRegion() = default;
|
||||
|
||||
void PlaybackRegion::Impl::update (const ARA::ARAPlaybackRegionProperties& props)
|
||||
{
|
||||
const ARAEditGuard guard (getDocumentController());
|
||||
getDocumentController().updatePlaybackRegionProperties (getPluginRef(), &props);
|
||||
}
|
||||
|
||||
void PlaybackRegion::Impl::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
|
||||
{
|
||||
dc.destroyPlaybackRegion (ptr);
|
||||
}
|
||||
|
||||
PlaybackRegion::PlaybackRegion (ARA::ARAPlaybackRegionHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
AudioModification& m,
|
||||
const ARA::ARAPlaybackRegionProperties& props)
|
||||
: impl (std::make_unique<Impl> (hostRef, dc, m, props))
|
||||
{
|
||||
}
|
||||
|
||||
void PlaybackRegion::update (const ARA::ARAPlaybackRegionProperties& props) { impl->update (props); }
|
||||
|
||||
void PlaybackRegion::addListener (DeletionListener& x) { impl->addListener (x); }
|
||||
|
||||
auto& PlaybackRegion::getAudioModification() const { return impl->getAudioModification(); }
|
||||
|
||||
ARA::ARAPlaybackRegionRef PlaybackRegion::getPluginRef() const noexcept { return impl->getPluginRef(); }
|
||||
|
||||
DeletionListener& PlaybackRegion::getDeletionListener() const noexcept { return *impl.get(); }
|
||||
|
||||
//==============================================================================
|
||||
MusicalContext::MusicalContext (ARA::ARAMusicalContextHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
const ARA::ARAMusicalContextProperties& props)
|
||||
: ManagedARAHandle (dc, [&]
|
||||
{
|
||||
const ARAEditGuard guard (dc);
|
||||
return dc.createMusicalContext (hostRef, &props);
|
||||
}())
|
||||
{
|
||||
}
|
||||
|
||||
void MusicalContext::update (const ARA::ARAMusicalContextProperties& props)
|
||||
{
|
||||
const ARAEditGuard guard (getDocumentController());
|
||||
return getDocumentController().updateMusicalContextProperties (getPluginRef(), &props);
|
||||
}
|
||||
|
||||
void MusicalContext::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
|
||||
{
|
||||
dc.destroyMusicalContext (ptr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
RegionSequence::RegionSequence (ARA::ARARegionSequenceHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
const ARA::ARARegionSequenceProperties& props)
|
||||
: ManagedARAHandle (dc, [&]
|
||||
{
|
||||
const ARAEditGuard guard (dc);
|
||||
return dc.createRegionSequence (hostRef, &props);
|
||||
}())
|
||||
{
|
||||
}
|
||||
|
||||
void RegionSequence::update (const ARA::ARARegionSequenceProperties& props)
|
||||
{
|
||||
const ARAEditGuard guard (getDocumentController());
|
||||
return getDocumentController().updateRegionSequenceProperties (getPluginRef(), &props);
|
||||
}
|
||||
|
||||
void RegionSequence::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
|
||||
{
|
||||
dc.destroyRegionSequence (ptr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PlaybackRendererInterface PlugInExtensionInstance::getPlaybackRendererInterface() const
|
||||
{
|
||||
if (instance != nullptr)
|
||||
return PlaybackRendererInterface (instance->playbackRendererRef, instance->playbackRendererInterface);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
EditorRendererInterface PlugInExtensionInstance::getEditorRendererInterface() const
|
||||
{
|
||||
if (instance != nullptr)
|
||||
return EditorRendererInterface (instance->editorRendererRef, instance->editorRendererInterface);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace ARAHostModel
|
||||
|
||||
//==============================================================================
|
||||
class ARAHostDocumentController::Impl
|
||||
{
|
||||
public:
|
||||
Impl (ARAFactoryWrapper araFactoryIn,
|
||||
std::unique_ptr<ARA::Host::DocumentControllerHostInstance>&& dcHostInstanceIn,
|
||||
const ARA::ARADocumentControllerInstance* documentControllerInstance,
|
||||
std::unique_ptr<ARA::Host::AudioAccessControllerInterface>&& audioAccessControllerIn,
|
||||
std::unique_ptr<ARA::Host::ArchivingControllerInterface>&& archivingControllerIn,
|
||||
std::unique_ptr<ARA::Host::ContentAccessControllerInterface>&& contentAccessControllerIn,
|
||||
std::unique_ptr<ARA::Host::ModelUpdateControllerInterface>&& modelUpdateControllerIn,
|
||||
std::unique_ptr<ARA::Host::PlaybackControllerInterface>&& playbackControllerIn)
|
||||
: araFactory (std::move (araFactoryIn)),
|
||||
audioAccessController (std::move (audioAccessControllerIn)),
|
||||
archivingController (std::move (archivingControllerIn)),
|
||||
contentAccessController (std::move (contentAccessControllerIn)),
|
||||
modelUpdateController (std::move (modelUpdateControllerIn)),
|
||||
playbackController (std::move (playbackControllerIn)),
|
||||
dcHostInstance (std::move (dcHostInstanceIn)),
|
||||
documentController (documentControllerInstance)
|
||||
{
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
documentController.destroyDocumentController();
|
||||
}
|
||||
|
||||
static std::unique_ptr<Impl>
|
||||
createImpl (ARAFactoryWrapper araFactory,
|
||||
const String& documentName,
|
||||
std::unique_ptr<ARA::Host::AudioAccessControllerInterface>&& audioAccessController,
|
||||
std::unique_ptr<ARA::Host::ArchivingControllerInterface>&& archivingController,
|
||||
std::unique_ptr<ARA::Host::ContentAccessControllerInterface>&& contentAccessController,
|
||||
std::unique_ptr<ARA::Host::ModelUpdateControllerInterface>&& modelUpdateController,
|
||||
std::unique_ptr<ARA::Host::PlaybackControllerInterface>&& playbackController)
|
||||
{
|
||||
std::unique_ptr<ARA::Host::DocumentControllerHostInstance> dcHostInstance =
|
||||
std::make_unique<ARA::Host::DocumentControllerHostInstance> (audioAccessController.get(),
|
||||
archivingController.get(),
|
||||
contentAccessController.get(),
|
||||
modelUpdateController.get(),
|
||||
playbackController.get());
|
||||
|
||||
const auto documentProperties = makeARASizedStruct (&ARA::ARADocumentProperties::name, documentName.toRawUTF8());
|
||||
|
||||
if (auto* dci = araFactory.get()->createDocumentControllerWithDocument (dcHostInstance.get(), &documentProperties))
|
||||
return std::make_unique<Impl> (std::move (araFactory),
|
||||
std::move (dcHostInstance),
|
||||
dci,
|
||||
std::move (audioAccessController),
|
||||
std::move (archivingController),
|
||||
std::move (contentAccessController),
|
||||
std::move (modelUpdateController),
|
||||
std::move (playbackController));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ARAHostModel::PlugInExtensionInstance bindDocumentToPluginInstance (AudioPluginInstance& instance,
|
||||
ARA::ARAPlugInInstanceRoleFlags knownRoles,
|
||||
ARA::ARAPlugInInstanceRoleFlags assignedRoles)
|
||||
{
|
||||
|
||||
const auto makeVisitor = [] (auto vst3Fn, auto auFn)
|
||||
{
|
||||
using Vst3Fn = decltype (vst3Fn);
|
||||
using AuFn = decltype (auFn);
|
||||
|
||||
struct Visitor final : public ExtensionsVisitor, Vst3Fn, AuFn
|
||||
{
|
||||
explicit Visitor (Vst3Fn vst3Fn, AuFn auFn) : Vst3Fn (std::move (vst3Fn)), AuFn (std::move (auFn)) {}
|
||||
void visitVST3Client (const VST3Client& x) override { Vst3Fn::operator() (x); }
|
||||
void visitAudioUnitClient (const AudioUnitClient& x) override { AuFn::operator() (x); }
|
||||
};
|
||||
|
||||
return Visitor { std::move (vst3Fn), std::move (auFn) };
|
||||
};
|
||||
|
||||
const ARA::ARAPlugInExtensionInstance* pei = nullptr;
|
||||
auto visitor = makeVisitor ([this, &pei, knownRoles, assignedRoles] (const ExtensionsVisitor::VST3Client& vst3Client)
|
||||
{
|
||||
auto* iComponentPtr = vst3Client.getIComponentPtr();
|
||||
VSTComSmartPtr<ARA::IPlugInEntryPoint2> araEntryPoint;
|
||||
|
||||
if (araEntryPoint.loadFrom (iComponentPtr))
|
||||
pei = araEntryPoint->bindToDocumentControllerWithRoles (documentController.getRef(), knownRoles, assignedRoles);
|
||||
},
|
||||
#if JUCE_PLUGINHOST_AU && JUCE_MAC
|
||||
[this, &pei, knownRoles, assignedRoles] (const ExtensionsVisitor::AudioUnitClient& auClient)
|
||||
{
|
||||
auto audioUnit = auClient.getAudioUnitHandle();
|
||||
auto propertySize = (UInt32) sizeof (ARA::ARAAudioUnitPlugInExtensionBinding);
|
||||
const auto expectedPropertySize = propertySize;
|
||||
ARA::ARAAudioUnitPlugInExtensionBinding audioUnitBinding { ARA::kARAAudioUnitMagic,
|
||||
documentController.getRef(),
|
||||
nullptr,
|
||||
knownRoles,
|
||||
assignedRoles };
|
||||
|
||||
auto status = AudioUnitGetProperty (audioUnit,
|
||||
ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
&audioUnitBinding,
|
||||
&propertySize);
|
||||
|
||||
if (status == noErr
|
||||
&& propertySize == expectedPropertySize
|
||||
&& audioUnitBinding.inOutMagicNumber == ARA::kARAAudioUnitMagic
|
||||
&& audioUnitBinding.inDocumentControllerRef == documentController.getRef()
|
||||
&& audioUnitBinding.outPlugInExtension != nullptr)
|
||||
{
|
||||
pei = audioUnitBinding.outPlugInExtension;
|
||||
}
|
||||
else
|
||||
jassertfalse;
|
||||
}
|
||||
#else
|
||||
[] (const auto&) {}
|
||||
#endif
|
||||
);
|
||||
|
||||
instance.getExtensions (visitor);
|
||||
return ARAHostModel::PlugInExtensionInstance { pei };
|
||||
}
|
||||
|
||||
auto& getDocumentController() { return documentController; }
|
||||
|
||||
private:
|
||||
ARAFactoryWrapper araFactory;
|
||||
|
||||
std::unique_ptr<ARA::Host::AudioAccessControllerInterface> audioAccessController;
|
||||
std::unique_ptr<ARA::Host::ArchivingControllerInterface> archivingController;
|
||||
std::unique_ptr<ARA::Host::ContentAccessControllerInterface> contentAccessController;
|
||||
std::unique_ptr<ARA::Host::ModelUpdateControllerInterface> modelUpdateController;
|
||||
std::unique_ptr<ARA::Host::PlaybackControllerInterface> playbackController;
|
||||
|
||||
std::unique_ptr<ARA::Host::DocumentControllerHostInstance> dcHostInstance;
|
||||
ARA::Host::DocumentController documentController;
|
||||
};
|
||||
|
||||
ARAHostDocumentController::ARAHostDocumentController (std::unique_ptr<Impl>&& implIn)
|
||||
: impl { std::move (implIn) }
|
||||
{}
|
||||
|
||||
std::unique_ptr<ARAHostDocumentController> ARAHostDocumentController::create (ARAFactoryWrapper factory,
|
||||
const String& documentName,
|
||||
std::unique_ptr<ARA::Host::AudioAccessControllerInterface> audioAccessController,
|
||||
std::unique_ptr<ARA::Host::ArchivingControllerInterface> archivingController,
|
||||
std::unique_ptr<ARA::Host::ContentAccessControllerInterface> contentAccessController,
|
||||
std::unique_ptr<ARA::Host::ModelUpdateControllerInterface> modelUpdateController,
|
||||
std::unique_ptr<ARA::Host::PlaybackControllerInterface> playbackController)
|
||||
{
|
||||
if (auto impl = Impl::createImpl (std::move (factory),
|
||||
documentName,
|
||||
std::move (audioAccessController),
|
||||
std::move (archivingController),
|
||||
std::move (contentAccessController),
|
||||
std::move (modelUpdateController),
|
||||
std::move (playbackController)))
|
||||
{
|
||||
return rawToUniquePtr (new ARAHostDocumentController (std::move (impl)));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ARAHostDocumentController::~ARAHostDocumentController() = default;
|
||||
|
||||
ARA::Host::DocumentController& ARAHostDocumentController::getDocumentController() const
|
||||
{
|
||||
return impl->getDocumentController();
|
||||
}
|
||||
|
||||
ARAHostModel::PlugInExtensionInstance ARAHostDocumentController::bindDocumentToPluginInstance (AudioPluginInstance& instance,
|
||||
ARA::ARAPlugInInstanceRoleFlags knownRoles,
|
||||
ARA::ARAPlugInInstanceRoleFlags assignedRoles)
|
||||
{
|
||||
return impl->bindDocumentToPluginInstance (instance, knownRoles, assignedRoles);
|
||||
}
|
||||
|
||||
void createARAFactoryAsync (AudioPluginInstance& instance, std::function<void (ARAFactoryWrapper)> cb)
|
||||
{
|
||||
if (! instance.getPluginDescription().hasARAExtension)
|
||||
cb (ARAFactoryWrapper{});
|
||||
|
||||
struct Extensions final : public ExtensionsVisitor
|
||||
{
|
||||
Extensions (std::function<void (ARAFactoryWrapper)> callbackIn)
|
||||
: callback (std::move (callbackIn))
|
||||
{}
|
||||
|
||||
void visitARAClient (const ARAClient& araClient) override
|
||||
{
|
||||
araClient.createARAFactoryAsync (std::move (callback));
|
||||
}
|
||||
|
||||
std::function<void (ARAFactoryWrapper)> callback;
|
||||
};
|
||||
|
||||
Extensions extensions { std::move (cb) };
|
||||
instance.getExtensions (extensions);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#endif
|
||||
|
|
@ -1,786 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU) && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX)) || DOXYGEN
|
||||
|
||||
// Include ARA SDK headers
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wgnu-zero-variadic-macro-arguments")
|
||||
|
||||
#include <ARA_API/ARAInterface.h>
|
||||
#include <ARA_Library/Dispatch/ARAHostDispatch.h>
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
//==============================================================================
|
||||
namespace juce
|
||||
{
|
||||
/** Reference counting helper class to ensure that the DocumentController is in editable state.
|
||||
|
||||
When adding, removing or modifying %ARA model objects the enclosing DocumentController must be
|
||||
in editable state.
|
||||
|
||||
You can achieve this by using the %ARA Library calls
|
||||
ARA::Host::DocumentController::beginEditing() and ARA::Host::DocumentController::endEditing().
|
||||
|
||||
However, putting the DocumentController in and out of editable state is a potentially costly
|
||||
operation, thus it makes sense to group multiple modifications together and change the editable
|
||||
state only once.
|
||||
|
||||
ARAEditGuard keeps track of all scopes that want to edit a particular DocumentController and
|
||||
will trigger beginEditing() and endEditing() only for the outermost scope. This allows you to
|
||||
merge multiple editing operations into one by putting ARAEditGuard in their enclosing scope.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAEditGuard
|
||||
{
|
||||
public:
|
||||
explicit ARAEditGuard (ARA::Host::DocumentController& dcIn);
|
||||
~ARAEditGuard();
|
||||
|
||||
private:
|
||||
ARA::Host::DocumentController& dc;
|
||||
};
|
||||
|
||||
namespace ARAHostModel
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/** Allows converting, without warnings, between pointers of two unrelated types.
|
||||
|
||||
This is a bit like ARA_MAP_HOST_REF, but not macro-based.
|
||||
|
||||
To use it, add a line like this to a type that needs to deal in host references:
|
||||
@code
|
||||
using Converter = ConversionFunctions<ThisType*, ARAHostRef>;
|
||||
@endcode
|
||||
|
||||
Now, you can convert back and forth with host references by calling
|
||||
Converter::toHostRef() and Converter::fromHostRef().
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
template <typename A, typename B>
|
||||
struct ConversionFunctions
|
||||
{
|
||||
static_assert (sizeof (A) <= sizeof (B),
|
||||
"It is only possible to convert between types of the same size");
|
||||
|
||||
static B toHostRef (A value)
|
||||
{
|
||||
return readUnaligned<B> (&value);
|
||||
}
|
||||
|
||||
static A fromHostRef (B value)
|
||||
{
|
||||
return readUnaligned<A> (&value);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** This class is used by the various ARA model object helper classes, such as MusicalContext,
|
||||
AudioSource etc. It helps with deregistering the model objects from the DocumentController
|
||||
when the lifetime of the helper class object ends.
|
||||
|
||||
You shouldn't use this class directly but instead inherit from the helper classes.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
template <typename Base, typename PtrIn>
|
||||
class ManagedARAHandle
|
||||
{
|
||||
public:
|
||||
using Ptr = PtrIn;
|
||||
|
||||
/** Constructor. */
|
||||
ManagedARAHandle (ARA::Host::DocumentController& dc, Ptr ptr) noexcept
|
||||
: handle (ptr, Deleter { dc }) {}
|
||||
|
||||
/** Returns the host side DocumentController reference. */
|
||||
auto& getDocumentController() const { return handle.get_deleter().documentController; }
|
||||
|
||||
/** Returns the plugin side reference to the model object. */
|
||||
Ptr getPluginRef() const { return handle.get(); }
|
||||
|
||||
private:
|
||||
struct Deleter
|
||||
{
|
||||
void operator() (Ptr ptr) const noexcept
|
||||
{
|
||||
const ARAEditGuard guard (documentController);
|
||||
Base::destroy (documentController, ptr);
|
||||
}
|
||||
|
||||
ARA::Host::DocumentController& documentController;
|
||||
};
|
||||
|
||||
std::unique_ptr<std::remove_pointer_t<Ptr>, Deleter> handle;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Helper class for the host side implementation of the %ARA %AudioSource model object.
|
||||
|
||||
Its intended use is to add a member variable of this type to your host side %AudioSource
|
||||
implementation. Then it provides a RAII approach to managing the lifetime of the corresponding
|
||||
objects created inside the DocumentController. When the host side object is instantiated an ARA
|
||||
model object is also created in the DocumentController. When the host side object is deleted it
|
||||
will be removed from the DocumentController as well.
|
||||
|
||||
The class will automatically put the DocumentController into editable state for operations that
|
||||
mandate this e.g. creation, deletion or updating.
|
||||
|
||||
You can encapsulate multiple such operations into a scope with an ARAEditGuard in order to invoke
|
||||
the editable state of the DocumentController only once.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API AudioSource : public ManagedARAHandle<AudioSource, ARA::ARAAudioSourceRef>
|
||||
{
|
||||
public:
|
||||
/** Returns an %ARA versioned struct with the `structSize` correctly set for the currently
|
||||
used SDK version.
|
||||
|
||||
You should leave `structSize` unchanged, and fill out the rest of the fields appropriately
|
||||
for the host implementation of the %ARA model object.
|
||||
*/
|
||||
static constexpr auto getEmptyProperties() { return makeARASizedStruct (&ARA::ARAAudioSourceProperties::merits64BitSamples); }
|
||||
|
||||
/** Creates an AudioSource object. During construction it registers an %ARA %AudioSource model
|
||||
object with the DocumentController that refers to the provided hostRef. When this object
|
||||
is deleted the corresponding DocumentController model object will also be deregistered.
|
||||
|
||||
You can acquire a correctly versioned `ARA::ARAAudioSourceProperties` struct by calling
|
||||
getEmptyProperties().
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
@see ARAEditGuard
|
||||
*/
|
||||
AudioSource (ARA::ARAAudioSourceHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
const ARA::ARAAudioSourceProperties& props);
|
||||
|
||||
/** Destructor. Temporarily places the DocumentController in an editable state. */
|
||||
~AudioSource() = default;
|
||||
|
||||
/** Updates the state of the corresponding %ARA model object.
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
You can use getEmptyProperties() to acquire a properties struct where the `structSize`
|
||||
field has already been correctly set.
|
||||
*/
|
||||
void update (const ARA::ARAAudioSourceProperties& props);
|
||||
|
||||
/** Changes the plugin's access to the %AudioSource samples through the DocumentController.
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
*/
|
||||
void enableAudioSourceSamplesAccess (bool);
|
||||
|
||||
/** Called by ManagedARAHandle to deregister the model object during the destruction of
|
||||
AudioSource.
|
||||
|
||||
You shouldn't call this function manually.
|
||||
*/
|
||||
static void destroy (ARA::Host::DocumentController&, Ptr);
|
||||
};
|
||||
|
||||
/** Helper class for the host side implementation of the %ARA %AudioModification model object.
|
||||
|
||||
Its intended use is to add a member variable of this type to your host side %AudioModification
|
||||
implementation. Then it provides a RAII approach to managing the lifetime of the corresponding
|
||||
objects created inside the DocumentController. When the host side object is instantiated an ARA
|
||||
model object is also created in the DocumentController. When the host side object is deleted it
|
||||
will be removed from the DocumentController as well.
|
||||
|
||||
The class will automatically put the DocumentController into editable state for operations that
|
||||
mandate this e.g. creation, deletion or updating.
|
||||
|
||||
You can encapsulate multiple such operations into a scope with an ARAEditGuard in order to invoke
|
||||
the editable state of the DocumentController only once.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API AudioModification : public ManagedARAHandle<AudioModification, ARA::ARAAudioModificationRef>
|
||||
{
|
||||
public:
|
||||
/** Returns an %ARA versioned struct with the `structSize` correctly set for the currently
|
||||
used SDK version.
|
||||
|
||||
You should leave `structSize` unchanged, and fill out the rest of the fields appropriately
|
||||
for the host implementation of the %ARA model object.
|
||||
*/
|
||||
static constexpr auto getEmptyProperties()
|
||||
{
|
||||
return makeARASizedStruct (&ARA::ARAAudioModificationProperties::persistentID);
|
||||
}
|
||||
|
||||
/** Creates an AudioModification object. During construction it registers an %ARA %AudioModification model
|
||||
object with the DocumentController that refers to the provided hostRef. When this object
|
||||
is deleted the corresponding DocumentController model object will also be deregistered.
|
||||
|
||||
You can acquire a correctly versioned `ARA::ARAAudioModificationProperties` struct by calling
|
||||
getEmptyProperties().
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
@see ARAEditGuard
|
||||
*/
|
||||
AudioModification (ARA::ARAAudioModificationHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
AudioSource& s,
|
||||
const ARA::ARAAudioModificationProperties& props);
|
||||
|
||||
/** Updates the state of the corresponding %ARA model object.
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
You can use getEmptyProperties() to acquire a properties struct where the `structSize`
|
||||
field has already been correctly set.
|
||||
*/
|
||||
void update (const ARA::ARAAudioModificationProperties& props);
|
||||
|
||||
/** Returns the AudioSource containing this AudioModification. */
|
||||
auto& getAudioSource() const { return source; }
|
||||
|
||||
/** Called by ManagedARAHandle to deregister the model object during the destruction of
|
||||
AudioModification.
|
||||
|
||||
You shouldn't call this function manually.
|
||||
*/
|
||||
static void destroy (ARA::Host::DocumentController&, Ptr);
|
||||
|
||||
private:
|
||||
AudioSource& source;
|
||||
};
|
||||
|
||||
/** This class is used internally by PlaybackRegionRegistry to be notified when a PlaybackRegion
|
||||
object is deleted.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
struct JUCE_API DeletionListener
|
||||
{
|
||||
/** Destructor. */
|
||||
virtual ~DeletionListener() = default;
|
||||
|
||||
/** Removes another DeletionListener object from this DeletionListener. */
|
||||
virtual void removeListener (DeletionListener& other) noexcept = 0;
|
||||
};
|
||||
|
||||
/** Helper class for the host side implementation of the %ARA %PlaybackRegion model object.
|
||||
|
||||
Its intended use is to add a member variable of this type to your host side %PlaybackRegion
|
||||
implementation. Then it provides a RAII approach to managing the lifetime of the corresponding
|
||||
objects created inside the DocumentController. When the host side object is instantiated an ARA
|
||||
model object is also created in the DocumentController. When the host side object is deleted it
|
||||
will be removed from the DocumentController as well.
|
||||
|
||||
The class will automatically put the DocumentController into editable state for operations that
|
||||
mandate this e.g. creation, deletion or updating.
|
||||
|
||||
You can encapsulate multiple such operations into a scope with an ARAEditGuard in order to invoke
|
||||
the editable state of the DocumentController only once.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
struct JUCE_API PlaybackRegion
|
||||
{
|
||||
public:
|
||||
/** Returns an %ARA versioned struct with the `structSize` correctly set for the currently
|
||||
used SDK version.
|
||||
|
||||
You should leave `structSize` unchanged, and fill out the rest of the fields appropriately
|
||||
for the host implementation of the %ARA model object.
|
||||
*/
|
||||
static constexpr auto getEmptyProperties()
|
||||
{
|
||||
return makeARASizedStruct (&ARA::ARAPlaybackRegionProperties::color);
|
||||
}
|
||||
|
||||
PlaybackRegion (ARA::ARAPlaybackRegionHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
AudioModification& m,
|
||||
const ARA::ARAPlaybackRegionProperties& props);
|
||||
|
||||
~PlaybackRegion();
|
||||
|
||||
/** Updates the state of the corresponding %ARA model object.
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
You can use getEmptyProperties() to acquire a properties struct where the `structSize`
|
||||
field has already been correctly set.
|
||||
*/
|
||||
void update (const ARA::ARAPlaybackRegionProperties& props);
|
||||
|
||||
/** Adds a DeletionListener object that will be notified when the PlaybackRegion object
|
||||
is deleted.
|
||||
|
||||
Used by the PlaybackRegionRegistry.
|
||||
|
||||
@see PlaybackRendererInterface, EditorRendererInterface
|
||||
*/
|
||||
void addListener (DeletionListener& x);
|
||||
|
||||
/** Returns the AudioModification containing this PlaybackRegion. */
|
||||
auto& getAudioModification() const;
|
||||
|
||||
/** Returns the plugin side reference to the PlaybackRegion */
|
||||
ARA::ARAPlaybackRegionRef getPluginRef() const noexcept;
|
||||
DeletionListener& getDeletionListener() const noexcept;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
/** Helper class for the host side implementation of the %ARA %MusicalContext model object.
|
||||
|
||||
Its intended use is to add a member variable of this type to your host side %MusicalContext
|
||||
implementation. Then it provides a RAII approach to managing the lifetime of the corresponding
|
||||
objects created inside the DocumentController. When the host side object is instantiated an ARA
|
||||
model object is also created in the DocumentController. When the host side object is deleted it
|
||||
will be removed from the DocumentController as well.
|
||||
|
||||
The class will automatically put the DocumentController into editable state for operations that
|
||||
mandate this e.g. creation, deletion or updating.
|
||||
|
||||
You can encapsulate multiple such operations into a scope with an ARAEditGuard in order to invoke
|
||||
the editable state of the DocumentController only once.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API MusicalContext : public ManagedARAHandle<MusicalContext, ARA::ARAMusicalContextRef>
|
||||
{
|
||||
public:
|
||||
/** Returns an %ARA versioned struct with the `structSize` correctly set for the currently
|
||||
used SDK version.
|
||||
|
||||
You should leave `structSize` unchanged, and fill out the rest of the fields appropriately
|
||||
for the host implementation of the %ARA model object.
|
||||
*/
|
||||
static constexpr auto getEmptyProperties()
|
||||
{
|
||||
return makeARASizedStruct (&ARA::ARAMusicalContextProperties::color);
|
||||
}
|
||||
|
||||
/** Creates a MusicalContext object. During construction it registers an %ARA %MusicalContext model
|
||||
object with the DocumentController that refers to the provided hostRef. When this object
|
||||
is deleted the corresponding DocumentController model object will also be deregistered.
|
||||
|
||||
You can acquire a correctly versioned `ARA::ARAMusicalContextProperties` struct by calling
|
||||
getEmptyProperties().
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
@see ARAEditGuard
|
||||
*/
|
||||
MusicalContext (ARA::ARAMusicalContextHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
const ARA::ARAMusicalContextProperties& props);
|
||||
|
||||
/** Updates the state of the corresponding %ARA model object.
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
You can use getEmptyProperties() to acquire a properties struct where the `structSize`
|
||||
field has already been correctly set.
|
||||
*/
|
||||
void update (const ARA::ARAMusicalContextProperties& props);
|
||||
|
||||
/** Called by ManagedARAHandle to deregister the model object during the destruction of
|
||||
AudioModification.
|
||||
|
||||
You shouldn't call this function manually.
|
||||
*/
|
||||
static void destroy (ARA::Host::DocumentController&, Ptr);
|
||||
};
|
||||
|
||||
/** Helper class for the host side implementation of the %ARA %RegionSequence model object.
|
||||
|
||||
Its intended use is to add a member variable of this type to your host side %RegionSequence
|
||||
implementation. Then it provides a RAII approach to managing the lifetime of the corresponding
|
||||
objects created inside the DocumentController. When the host side object is instantiated an ARA
|
||||
model object is also created in the DocumentController. When the host side object is deleted it
|
||||
will be removed from the DocumentController as well.
|
||||
|
||||
The class will automatically put the DocumentController into editable state for operations that
|
||||
mandate this e.g. creation, deletion or updating.
|
||||
|
||||
You can encapsulate multiple such operations into a scope with an ARAEditGuard in order to invoke
|
||||
the editable state of the DocumentController only once.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API RegionSequence : public ManagedARAHandle<RegionSequence, ARA::ARARegionSequenceRef>
|
||||
{
|
||||
public:
|
||||
/** Returns an %ARA versioned struct with the `structSize` correctly set for the currently
|
||||
used SDK version.
|
||||
|
||||
You should leave `structSize` unchanged, and fill out the rest of the fields appropriately
|
||||
for the host implementation of the %ARA model object.
|
||||
*/
|
||||
static constexpr auto getEmptyProperties()
|
||||
{
|
||||
return makeARASizedStruct (&ARA::ARARegionSequenceProperties::color);
|
||||
}
|
||||
|
||||
/** Creates a RegionSequence object. During construction it registers an %ARA %RegionSequence model
|
||||
object with the DocumentController that refers to the provided hostRef. When this object
|
||||
is deleted the corresponding DocumentController model object will also be deregistered.
|
||||
|
||||
You can acquire a correctly versioned `ARA::ARARegionSequenceProperties` struct by calling
|
||||
getEmptyProperties().
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
@see ARAEditGuard
|
||||
*/
|
||||
RegionSequence (ARA::ARARegionSequenceHostRef hostRef,
|
||||
ARA::Host::DocumentController& dc,
|
||||
const ARA::ARARegionSequenceProperties& props);
|
||||
|
||||
/** Updates the state of the corresponding %ARA model object.
|
||||
|
||||
Places the DocumentController in editable state.
|
||||
|
||||
You can use getEmptyProperties() to acquire a properties struct where the `structSize`
|
||||
field has already been correctly set.
|
||||
*/
|
||||
void update (const ARA::ARARegionSequenceProperties& props);
|
||||
|
||||
/** Called by ManagedARAHandle to deregister the model object during the destruction of
|
||||
AudioModification.
|
||||
|
||||
You shouldn't call this function manually.
|
||||
*/
|
||||
static void destroy (ARA::Host::DocumentController&, Ptr);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Base class used by the ::PlaybackRendererInterface and ::EditorRendererInterface
|
||||
plugin extension interfaces.
|
||||
|
||||
Hosts will want to create one or typically more %ARA plugin extension instances per plugin for
|
||||
the purpose of playback and editor rendering. The PlaybackRegions created by the host then have
|
||||
to be assigned to these instances through the appropriate interfaces.
|
||||
|
||||
Whether a PlaybackRegion or an assigned RendererInterface is deleted first depends on the host
|
||||
implementation and exact use case.
|
||||
|
||||
By using these helper classes you can ensure that the %ARA DocumentController remains in a
|
||||
valid state in both situations. In order to use them acquire an object from
|
||||
PlugInExtensionInstance::getPlaybackRendererInterface() or
|
||||
PlugInExtensionInstance::getEditorRendererInterface().
|
||||
|
||||
Then call add() to register a PlaybackRegion with that particular PlugInExtensionInstance's
|
||||
interface.
|
||||
|
||||
Now when you delete that PlaybackRegion it will be deregistered from that extension instance.
|
||||
If however you want to delete the plugin extension instance before the PlaybackRegion, you can
|
||||
delete the PlaybackRegionRegistry instance before deleting the plugin extension instance, which
|
||||
takes care of deregistering all PlaybackRegions.
|
||||
|
||||
When adding or removing PlaybackRegions the plugin instance must be in an unprepared state i.e.
|
||||
before AudioProcessor::prepareToPlay() or after AudioProcessor::releaseResources().
|
||||
|
||||
@code
|
||||
auto playbackRenderer = std::make_unique<PlaybackRendererInterface> (plugInExtensionInstance.getPlaybackRendererInterface());
|
||||
auto playbackRegion = std::make_unique<PlaybackRegion> (documentController, regionSequence, audioModification, audioSource);
|
||||
|
||||
// Either of the following three code variations are valid
|
||||
// (1) ===================================================
|
||||
playbackRenderer.add (playbackRegion);
|
||||
playbackRenderer.remove (playbackRegion);
|
||||
|
||||
// (2) ===================================================
|
||||
playbackRenderer.add (playbackRegion);
|
||||
playbackRegion.reset();
|
||||
|
||||
// (3) ===================================================
|
||||
playbackRenderer.add (playbackRegion);
|
||||
playbackRenderer.reset();
|
||||
@endcode
|
||||
|
||||
@see PluginExtensionInstance
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
template <typename RendererRef, typename Interface>
|
||||
class PlaybackRegionRegistry
|
||||
{
|
||||
public:
|
||||
PlaybackRegionRegistry() = default;
|
||||
|
||||
PlaybackRegionRegistry (RendererRef rendererRefIn, const Interface* interfaceIn)
|
||||
: registry (std::make_unique<Registry> (rendererRefIn, interfaceIn))
|
||||
{
|
||||
}
|
||||
|
||||
/** Adds a PlaybackRegion to the corresponding ::PlaybackRendererInterface or ::EditorRendererInterface.
|
||||
|
||||
The plugin instance must be in an unprepared state i.e. before AudioProcessor::prepareToPlay() or
|
||||
after AudioProcessor::releaseResources().
|
||||
*/
|
||||
void add (PlaybackRegion& region) { registry->add (region); }
|
||||
|
||||
/** Removes a PlaybackRegion from the corresponding ::PlaybackRendererInterface or ::EditorRendererInterface.
|
||||
|
||||
The plugin instance must be in an unprepared state i.e. before AudioProcessor::prepareToPlay() or
|
||||
after AudioProcessor::releaseResources().
|
||||
*/
|
||||
void remove (PlaybackRegion& region) { registry->remove (region); }
|
||||
|
||||
/** Returns true if the underlying %ARA plugin extension instance fulfills the corresponding role. */
|
||||
bool isValid() { return registry->isValid(); }
|
||||
|
||||
private:
|
||||
class Registry : private DeletionListener
|
||||
{
|
||||
public:
|
||||
Registry (RendererRef rendererRefIn, const Interface* interfaceIn)
|
||||
: rendererRef (rendererRefIn), rendererInterface (interfaceIn)
|
||||
{
|
||||
}
|
||||
|
||||
Registry (const Registry&) = delete;
|
||||
Registry (Registry&&) noexcept = delete;
|
||||
|
||||
Registry& operator= (const Registry&) = delete;
|
||||
Registry& operator= (Registry&&) noexcept = delete;
|
||||
|
||||
~Registry() override
|
||||
{
|
||||
for (const auto& region : regions)
|
||||
doRemoveListener (*region.first);
|
||||
}
|
||||
|
||||
bool isValid() { return rendererRef != nullptr && rendererInterface != nullptr; }
|
||||
|
||||
void add (PlaybackRegion& region)
|
||||
{
|
||||
if (isValid())
|
||||
rendererInterface->addPlaybackRegion (rendererRef, region.getPluginRef());
|
||||
|
||||
regions.emplace (®ion.getDeletionListener(), region.getPluginRef());
|
||||
region.addListener (*this);
|
||||
}
|
||||
|
||||
void remove (PlaybackRegion& region)
|
||||
{
|
||||
doRemoveListener (region.getDeletionListener());
|
||||
}
|
||||
|
||||
private:
|
||||
void doRemoveListener (DeletionListener& listener) noexcept
|
||||
{
|
||||
listener.removeListener (*this);
|
||||
removeListener (listener);
|
||||
}
|
||||
|
||||
void removeListener (DeletionListener& listener) noexcept override
|
||||
{
|
||||
const auto it = regions.find (&listener);
|
||||
|
||||
if (it == regions.end())
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isValid())
|
||||
rendererInterface->removePlaybackRegion (rendererRef, it->second);
|
||||
|
||||
regions.erase (it);
|
||||
}
|
||||
|
||||
RendererRef rendererRef = nullptr;
|
||||
const Interface* rendererInterface = nullptr;
|
||||
std::map<DeletionListener*, ARA::ARAPlaybackRegionRef> regions;
|
||||
};
|
||||
|
||||
std::unique_ptr<Registry> registry;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Helper class for managing the lifetimes of %ARA plugin extension instances and PlaybackRegions.
|
||||
|
||||
You can read more about its usage at PlaybackRegionRegistry.
|
||||
|
||||
@see PlaybackRegion, PlaybackRegionRegistry
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
using PlaybackRendererInterface = PlaybackRegionRegistry<ARA::ARAPlaybackRendererRef, ARA::ARAPlaybackRendererInterface>;
|
||||
|
||||
//==============================================================================
|
||||
/** Helper class for managing the lifetimes of %ARA plugin extension instances and PlaybackRegions.
|
||||
|
||||
You can read more about its usage at PlaybackRegionRegistry.
|
||||
|
||||
@see PlaybackRegion, PlaybackRegionRegistry
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
using EditorRendererInterface = PlaybackRegionRegistry<ARA::ARAEditorRendererRef, ARA::ARAEditorRendererInterface>;
|
||||
|
||||
//==============================================================================
|
||||
/** Wrapper class for `ARA::ARAPlugInExtensionInstance*`.
|
||||
|
||||
Returned by ARAHostDocumentController::bindDocumentToPluginInstance(). The corresponding
|
||||
ARAHostDocumentController must remain valid as long as the plugin extension is in use.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API PlugInExtensionInstance final
|
||||
{
|
||||
public:
|
||||
/** Creates an empty PlugInExtensionInstance object.
|
||||
|
||||
Calling isValid() on such an object will return false.
|
||||
*/
|
||||
PlugInExtensionInstance() = default;
|
||||
|
||||
/** Creates a PlugInExtensionInstance object that wraps a `const ARA::ARAPlugInExtensionInstance*`.
|
||||
|
||||
The intended way to obtain a PlugInExtensionInstance object is to call
|
||||
ARAHostDocumentController::bindDocumentToPluginInstance(), which is using this constructor.
|
||||
*/
|
||||
explicit PlugInExtensionInstance (const ARA::ARAPlugInExtensionInstance* instanceIn)
|
||||
: instance (instanceIn)
|
||||
{
|
||||
}
|
||||
|
||||
/** Returns the PlaybackRendererInterface for the extension instance.
|
||||
|
||||
Depending on what roles were passed into
|
||||
ARAHostDocumentController::bindDocumentToPluginInstance() one particular instance may not
|
||||
fulfill a given role. You can use PlaybackRendererInterface::isValid() to see if this
|
||||
interface was provided by the instance.
|
||||
*/
|
||||
PlaybackRendererInterface getPlaybackRendererInterface() const;
|
||||
|
||||
/** Returns the EditorRendererInterface for the extension instance.
|
||||
|
||||
Depending on what roles were passed into
|
||||
ARAHostDocumentController::bindDocumentToPluginInstance() one particular instance may not
|
||||
fulfill a given role. You can use EditorRendererInterface::isValid() to see if this
|
||||
interface was provided by the instance.
|
||||
*/
|
||||
EditorRendererInterface getEditorRendererInterface() const;
|
||||
|
||||
/** Returns false if the PlugInExtensionInstance was default constructed and represents
|
||||
no binding to an ARAHostDocumentController.
|
||||
*/
|
||||
bool isValid() const noexcept { return instance != nullptr; }
|
||||
|
||||
private:
|
||||
const ARA::ARAPlugInExtensionInstance* instance = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ARAHostModel
|
||||
|
||||
//==============================================================================
|
||||
/** Wrapper class for `ARA::Host::DocumentController`.
|
||||
|
||||
In order to create an ARAHostDocumentController from an ARAFactoryWrapper you must
|
||||
provide at least two mandatory host side interfaces. You can create these implementations
|
||||
by inheriting from the base classes in the `ARA::Host` namespace.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAHostDocumentController final
|
||||
{
|
||||
public:
|
||||
/** Factory function.
|
||||
|
||||
You must check if the returned pointer is valid.
|
||||
*/
|
||||
static std::unique_ptr<ARAHostDocumentController>
|
||||
create (ARAFactoryWrapper factory,
|
||||
const String& documentName,
|
||||
std::unique_ptr<ARA::Host::AudioAccessControllerInterface> audioAccessController,
|
||||
std::unique_ptr<ARA::Host::ArchivingControllerInterface> archivingController,
|
||||
std::unique_ptr<ARA::Host::ContentAccessControllerInterface> contentAccessController = nullptr,
|
||||
std::unique_ptr<ARA::Host::ModelUpdateControllerInterface> modelUpdateController = nullptr,
|
||||
std::unique_ptr<ARA::Host::PlaybackControllerInterface> playbackController = nullptr);
|
||||
|
||||
~ARAHostDocumentController();
|
||||
|
||||
/** Returns the underlying ARA::Host::DocumentController reference. */
|
||||
ARA::Host::DocumentController& getDocumentController() const;
|
||||
|
||||
/** Binds the ARAHostDocumentController and its enclosed document to a plugin instance.
|
||||
|
||||
The resulting ARAHostModel::PlugInExtensionInstance is responsible for fulfilling the
|
||||
ARA specific roles of the plugin.
|
||||
|
||||
A single DocumentController can be bound to multiple plugin instances, which is a typical
|
||||
practice among hosts.
|
||||
*/
|
||||
ARAHostModel::PlugInExtensionInstance bindDocumentToPluginInstance (AudioPluginInstance& instance,
|
||||
ARA::ARAPlugInInstanceRoleFlags knownRoles,
|
||||
ARA::ARAPlugInInstanceRoleFlags assignedRoles);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
|
||||
explicit ARAHostDocumentController (std::unique_ptr<Impl>&& implIn);
|
||||
};
|
||||
|
||||
/** Calls the provided callback with an ARAFactoryWrapper object obtained from the provided
|
||||
AudioPluginInstance.
|
||||
|
||||
If the provided AudioPluginInstance has no ARA extensions, the callback will be called with an
|
||||
ARAFactoryWrapper that wraps a nullptr.
|
||||
|
||||
The object passed to the callback must be checked even if the plugin instance reports having
|
||||
ARA extensions.
|
||||
*/
|
||||
void JUCE_API createARAFactoryAsync (AudioPluginInstance& instance, std::function<void (ARAFactoryWrapper)> cb);
|
||||
|
||||
} // namespace juce
|
||||
|
||||
//==============================================================================
|
||||
#undef ARA_REF
|
||||
#undef ARA_HOST_REF
|
||||
|
||||
#endif
|
||||
|
|
@ -172,7 +172,6 @@ private:
|
|||
#include "format_types/juce_VSTPluginFormat.cpp"
|
||||
#include "format_types/juce_VST3PluginFormat.cpp"
|
||||
#include "format_types/juce_AudioUnitPluginFormat.mm"
|
||||
#include "format_types/juce_ARAHosting.cpp"
|
||||
#include "scanning/juce_KnownPluginList.cpp"
|
||||
#include "scanning/juce_PluginDirectoryScanner.cpp"
|
||||
#include "scanning/juce_PluginListComponent.cpp"
|
||||
|
|
|
|||
|
|
@ -148,7 +148,6 @@
|
|||
#include "format_types/juce_VST3PluginFormat.h"
|
||||
#include "format_types/juce_VSTMidiEventList.h"
|
||||
#include "format_types/juce_VSTPluginFormat.h"
|
||||
#include "format_types/juce_ARAHosting.h"
|
||||
#include "scanning/juce_PluginDirectoryScanner.h"
|
||||
#include "scanning/juce_PluginListComponent.h"
|
||||
#include "utilities/juce_ParameterAttachments.h"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue