@@ -1088,6 +1088,7 @@ void AudioDeviceManager::setDefaultMidiOutputDevice (const String& identifier) | |||
{ | |||
if (defaultMidiOutputDeviceInfo.identifier != identifier) | |||
{ | |||
std::unique_ptr<MidiOutput> oldMidiPort; | |||
Array<AudioIODeviceCallback*> oldCallbacks; | |||
{ | |||
@@ -1099,7 +1100,7 @@ void AudioDeviceManager::setDefaultMidiOutputDevice (const String& identifier) | |||
for (int i = oldCallbacks.size(); --i >= 0;) | |||
oldCallbacks.getUnchecked (i)->audioDeviceStopped(); | |||
defaultMidiOutput.reset(); | |||
std::swap (oldMidiPort, defaultMidiOutput); | |||
if (identifier.isNotEmpty()) | |||
defaultMidiOutput = MidiOutput::openDevice (identifier); | |||
@@ -1119,7 +1120,7 @@ void AudioDeviceManager::setDefaultMidiOutputDevice (const String& identifier) | |||
} | |||
updateXml(); | |||
sendChangeMessage(); | |||
sendSynchronousChangeMessage(); | |||
} | |||
} | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -133,6 +140,18 @@ public: | |||
/** Returns true if instantiation of this plugin type must be done from a non-message thread. */ | |||
virtual bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const = 0; | |||
/** A callback lambda that is passed to getARAFactory() */ | |||
using ARAFactoryCreationCallback = std::function<void (ARAFactoryResult)>; | |||
/** Tries to create an ::ARAFactoryWrapper for this description. | |||
The result of the operation will be wrapped into an ARAFactoryResult, | |||
which will be passed to a callback object supplied by the caller. | |||
@see AudioPluginFormatManager::createARAFactoryAsync | |||
*/ | |||
virtual void createARAFactoryAsync (const PluginDescription&, ARAFactoryCreationCallback callback) { callback ({}); } | |||
protected: | |||
//============================================================================== | |||
friend class AudioPluginFormatManager; | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -129,6 +136,22 @@ std::unique_ptr<AudioPluginInstance> AudioPluginFormatManager::createPluginInsta | |||
return {}; | |||
} | |||
void AudioPluginFormatManager::createARAFactoryAsync (const PluginDescription& description, | |||
AudioPluginFormat::ARAFactoryCreationCallback callback) const | |||
{ | |||
String errorMessage; | |||
if (auto* format = findFormatForDescription (description, errorMessage)) | |||
{ | |||
format->createARAFactoryAsync (description, callback); | |||
} | |||
else | |||
{ | |||
errorMessage = NEEDS_TRANS ("Couldn't find format for the provided description"); | |||
callback ({ {}, std::move (errorMessage) }); | |||
} | |||
} | |||
void AudioPluginFormatManager::createPluginInstanceAsync (const PluginDescription& description, | |||
double initialSampleRate, int initialBufferSize, | |||
AudioPluginFormat::PluginCreationCallback callback) | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -102,6 +109,22 @@ public: | |||
double initialSampleRate, int initialBufferSize, | |||
AudioPluginFormat::PluginCreationCallback callback); | |||
/** Tries to create an ::ARAFactoryWrapper for this description. | |||
The result of the operation will be wrapped into an ARAFactoryResult, | |||
which will be passed to a callback object supplied by the caller. | |||
The operation may fail, in which case the callback will be called with | |||
with a result object where ARAFactoryResult::araFactory.get() will return | |||
a nullptr. | |||
In case of success the returned ::ARAFactoryWrapper will ensure that | |||
modules required for the correct functioning of the ARAFactory will remain | |||
loaded for the lifetime of the object. | |||
*/ | |||
void createARAFactoryAsync (const PluginDescription& description, | |||
AudioPluginFormat::ARAFactoryCreationCallback callback) const; | |||
/** Checks that the file or component for this plugin actually still exists. | |||
(This won't try to load the plugin) | |||
*/ | |||
@@ -6,10 +6,10 @@ | |||
# JUCE is an open source library subject to commercial or open-source | |||
# licensing. | |||
# | |||
# By using JUCE, you agree to the terms of both the JUCE 6 End-User License | |||
# Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). | |||
# By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
# Agreement and JUCE Privacy Policy. | |||
# | |||
# End User License Agreement: www.juce.com/juce-6-licence | |||
# End User License Agreement: www.juce.com/juce-7-licence | |||
# Privacy Policy: www.juce.com/juce-privacy-policy | |||
# | |||
# Or: You may also use this code under the terms of the GPL v3 (see | |||
@@ -57,10 +57,10 @@ FUNCTION_TEMPLATE = """/* | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License | |||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-6-licence | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -0,0 +1,76 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#if (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU) && (JUCE_MAC || JUCE_WINDOWS)) | |||
#include <ARA_Library/Debug/ARADebug.h> | |||
namespace juce | |||
{ | |||
static void dummyARAInterfaceAssert (ARA::ARAAssertCategory, const void*, const char*) | |||
{} | |||
static ARA::ARAInterfaceConfiguration createInterfaceConfig (const ARA::ARAFactory* araFactory) | |||
{ | |||
static auto* assertFunction = &dummyARAInterfaceAssert; | |||
#if ARA_VALIDATE_API_CALLS | |||
assertFunction = &::ARA::ARAInterfaceAssert; | |||
static std::once_flag flag; | |||
std::call_once (flag, [] { ARA::ARASetExternalAssertReference (&assertFunction); }); | |||
#endif | |||
return makeARASizedStruct (&ARA::ARAInterfaceConfiguration::assertFunctionAddress, | |||
jmin (araFactory->highestSupportedApiGeneration, (ARA::ARAAPIGeneration) ARA::kARAAPIGeneration_2_X_Draft), | |||
&assertFunction); | |||
} | |||
static std::shared_ptr<const ARA::ARAFactory> getOrCreateARAFactory (const ARA::ARAFactory* ptr, | |||
std::function<void (const ARA::ARAFactory*)> onDelete) | |||
{ | |||
JUCE_ASSERT_MESSAGE_THREAD | |||
static std::unordered_map<const ARA::ARAFactory*, std::weak_ptr<const ARA::ARAFactory>> cache; | |||
auto& cachePtr = cache[ptr]; | |||
if (const auto obj = cachePtr.lock()) | |||
return obj; | |||
const auto interfaceConfig = createInterfaceConfig (ptr); | |||
ptr->initializeARAWithConfiguration (&interfaceConfig); | |||
const auto obj = std::shared_ptr<const ARA::ARAFactory> (ptr, [deleter = std::move (onDelete)] (const ARA::ARAFactory* factory) | |||
{ | |||
factory->uninitializeARA(); | |||
deleter (factory); | |||
}); | |||
cachePtr = obj; | |||
return obj; | |||
} | |||
} | |||
#endif |
@@ -0,0 +1,85 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#pragma once | |||
namespace ARA | |||
{ | |||
struct ARAFactory; | |||
} | |||
namespace juce | |||
{ | |||
/** Encapsulates an ARAFactory pointer and makes sure that it remains in a valid state | |||
for the lifetime of the ARAFactoryWrapper object. | |||
@tags{ARA} | |||
*/ | |||
class ARAFactoryWrapper | |||
{ | |||
public: | |||
ARAFactoryWrapper() = default; | |||
/** @internal | |||
Used by the framework to encapsulate ARAFactory pointers loaded from plugins. | |||
*/ | |||
explicit ARAFactoryWrapper (std::shared_ptr<const ARA::ARAFactory> factoryIn) : factory (std::move (factoryIn)) {} | |||
/** Returns the contained ARAFactory pointer, which can be a nullptr. | |||
The validity of the returned pointer is only guaranteed for the lifetime of this wrapper. | |||
*/ | |||
const ARA::ARAFactory* get() const noexcept { return factory.get(); } | |||
private: | |||
std::shared_ptr<const ARA::ARAFactory> factory; | |||
}; | |||
/** Represents the result of AudioPluginFormatManager::createARAFactoryAsync(). | |||
If the operation fails then #araFactory will contain `nullptr`, and #errorMessage may | |||
contain a reason for the failure. | |||
The araFactory member ensures that the module necessary for the correct functioning | |||
of the factory will remain loaded. | |||
@tags{ARA} | |||
*/ | |||
struct ARAFactoryResult | |||
{ | |||
ARAFactoryWrapper araFactory; | |||
String errorMessage; | |||
}; | |||
template <typename Obj, typename Member, typename... Ts> | |||
constexpr Obj makeARASizedStruct (Member Obj::* member, Ts&&... ts) | |||
{ | |||
return { reinterpret_cast<uintptr_t> (&(static_cast<const Obj*> (nullptr)->*member)) + sizeof (Member), | |||
std::forward<Ts> (ts)... }; | |||
} | |||
} // namespace juce |
@@ -0,0 +1,458 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#if (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU) && (JUCE_MAC || JUCE_WINDOWS)) | |||
#include "juce_ARAHosting.h" | |||
#include <ARA_Library/Debug/ARADebug.h> | |||
#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) | |||
: araFactory (std::move (araFactoryIn)), | |||
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.release(), | |||
archivingController.release(), | |||
contentAccessController.release(), | |||
modelUpdateController.release(), | |||
playbackController.release()); | |||
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); | |||
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 : 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::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 : 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 |
@@ -0,0 +1,740 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#pragma once | |||
#if (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU) && (JUCE_MAC || JUCE_WINDOWS)) || 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 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); | |||
} | |||
}; | |||
//============================================================================== | |||
template <typename Base, typename PtrIn> | |||
class ManagedARAHandle | |||
{ | |||
public: | |||
using Ptr = PtrIn; | |||
ManagedARAHandle (ARA::Host::DocumentController& dc, Ptr ptr) noexcept | |||
: handle (ptr, Deleter { dc }) {} | |||
auto& getDocumentController() const { return handle.get_deleter().documentController; } | |||
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 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 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; | |||
}; | |||
struct DeletionListener | |||
{ | |||
virtual ~DeletionListener() = default; | |||
virtual void removeListener (DeletionListener& other) noexcept = 0; | |||
}; | |||
struct 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 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 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. | |||
*/ | |||
class 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 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 createARAFactoryAsync (AudioPluginInstance& instance, std::function<void (ARAFactoryWrapper)> cb); | |||
} // namespace juce | |||
//============================================================================== | |||
#undef ARA_REF | |||
#undef ARA_HOST_REF | |||
#endif |
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -47,6 +54,7 @@ public: | |||
StringArray searchPathsForPlugins (const FileSearchPath&, bool recursive, bool) override; | |||
bool doesPluginStillExist (const PluginDescription&) override; | |||
FileSearchPath getDefaultLocationsToSearch() override; | |||
void createARAFactoryAsync (const PluginDescription&, ARAFactoryCreationCallback callback) override; | |||
private: | |||
//============================================================================== | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -24,14 +31,15 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") | |||
#include <AudioUnit/AUCocoaUIView.h> | |||
#include <CoreAudioKit/AUGenericView.h> | |||
#include <AudioToolbox/AudioUnitUtilities.h> | |||
#endif | |||
#include <CoreMIDI/MIDIServices.h> | |||
#if JUCE_PLUGINHOST_ARA | |||
#include <ARA_API/ARAAudioUnit.h> | |||
#endif | |||
#if JUCE_SUPPORT_CARBON | |||
#include <AudioUnit/AudioUnitCarbonView.h> | |||
#endif | |||
#include <CoreMIDI/MIDIServices.h> | |||
#include <CoreAudioKit/AUViewController.h> | |||
#include <juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h> | |||
@@ -426,8 +434,198 @@ namespace AudioUnitFormatHelpers | |||
} | |||
} | |||
static bool hasARAExtension (AudioUnit audioUnit) | |||
{ | |||
#if JUCE_PLUGINHOST_ARA | |||
UInt32 propertySize = sizeof (ARA::ARAAudioUnitFactory); | |||
Boolean isWriteable = FALSE; | |||
OSStatus status = AudioUnitGetPropertyInfo (audioUnit, | |||
ARA::kAudioUnitProperty_ARAFactory, | |||
kAudioUnitScope_Global, | |||
0, | |||
&propertySize, | |||
&isWriteable); | |||
if ((status == noErr) && (propertySize == sizeof (ARA::ARAAudioUnitFactory)) && ! isWriteable) | |||
return true; | |||
#else | |||
ignoreUnused (audioUnit); | |||
#endif | |||
return false; | |||
} | |||
struct AudioUnitDeleter | |||
{ | |||
void operator() (AudioUnit au) const { AudioComponentInstanceDispose (au); } | |||
}; | |||
using AudioUnitUniquePtr = std::unique_ptr<std::remove_pointer_t<AudioUnit>, AudioUnitDeleter>; | |||
using AudioUnitSharedPtr = std::shared_ptr<std::remove_pointer_t<AudioUnit>>; | |||
using AudioUnitWeakPtr = std::weak_ptr<std::remove_pointer_t<AudioUnit>>; | |||
static std::shared_ptr<const ARA::ARAFactory> getARAFactory (AudioUnitSharedPtr audioUnit) | |||
{ | |||
#if JUCE_PLUGINHOST_ARA | |||
jassert (audioUnit != nullptr); | |||
UInt32 propertySize = sizeof (ARA::ARAAudioUnitFactory); | |||
ARA::ARAAudioUnitFactory audioUnitFactory { ARA::kARAAudioUnitMagic, nullptr }; | |||
if (hasARAExtension (audioUnit.get())) | |||
{ | |||
OSStatus status = AudioUnitGetProperty (audioUnit.get(), | |||
ARA::kAudioUnitProperty_ARAFactory, | |||
kAudioUnitScope_Global, | |||
0, | |||
&audioUnitFactory, | |||
&propertySize); | |||
if ((status == noErr) | |||
&& (propertySize == sizeof (ARA::ARAAudioUnitFactory)) | |||
&& (audioUnitFactory.inOutMagicNumber == ARA::kARAAudioUnitMagic)) | |||
{ | |||
jassert (audioUnitFactory.outFactory != nullptr); | |||
return getOrCreateARAFactory (audioUnitFactory.outFactory, | |||
[owningAuPtr = std::move (audioUnit)] (const ARA::ARAFactory*) {}); | |||
} | |||
} | |||
#else | |||
ignoreUnused (audioUnit); | |||
#endif | |||
return {}; | |||
} | |||
struct VersionedAudioComponent | |||
{ | |||
AudioComponent audioComponent = nullptr; | |||
bool isAUv3 = false; | |||
bool operator< (const VersionedAudioComponent& other) const { return audioComponent < other.audioComponent; } | |||
}; | |||
using AudioUnitCreationCallback = std::function<void (AudioUnit, OSStatus)>; | |||
static void createAudioUnit (VersionedAudioComponent versionedComponent, AudioUnitCreationCallback callback) | |||
{ | |||
struct AUAsyncInitializationCallback | |||
{ | |||
typedef void (^AUCompletionCallbackBlock)(AudioComponentInstance, OSStatus); | |||
explicit AUAsyncInitializationCallback (AudioUnitCreationCallback inOriginalCallback) | |||
: originalCallback (std::move (inOriginalCallback)) | |||
{ | |||
block = CreateObjCBlock (this, &AUAsyncInitializationCallback::completion); | |||
} | |||
AUCompletionCallbackBlock getBlock() noexcept { return block; } | |||
void completion (AudioComponentInstance audioUnit, OSStatus err) | |||
{ | |||
originalCallback (audioUnit, err); | |||
delete this; | |||
} | |||
double sampleRate; | |||
int framesPerBuffer; | |||
AudioUnitCreationCallback originalCallback; | |||
ObjCBlock<AUCompletionCallbackBlock> block; | |||
}; | |||
auto callbackBlock = new AUAsyncInitializationCallback (std::move (callback)); | |||
if (versionedComponent.isAUv3) | |||
{ | |||
if (@available (macOS 10.11, *)) | |||
{ | |||
AudioComponentInstantiate (versionedComponent.audioComponent, kAudioComponentInstantiation_LoadOutOfProcess, | |||
callbackBlock->getBlock()); | |||
return; | |||
} | |||
} | |||
AudioComponentInstance audioUnit; | |||
auto err = AudioComponentInstanceNew (versionedComponent.audioComponent, &audioUnit); | |||
callbackBlock->completion (err != noErr ? nullptr : audioUnit, err); | |||
} | |||
struct AudioComponentResult | |||
{ | |||
explicit AudioComponentResult (String error) : errorMessage (std::move (error)) {} | |||
explicit AudioComponentResult (VersionedAudioComponent auComponent) : component (std::move (auComponent)) {} | |||
bool isValid() const { return component.audioComponent != nullptr; } | |||
VersionedAudioComponent component; | |||
String errorMessage; | |||
}; | |||
static AudioComponentResult getAudioComponent (AudioUnitPluginFormat& format, const PluginDescription& desc) | |||
{ | |||
using namespace AudioUnitFormatHelpers; | |||
AudioUnitPluginFormat audioUnitPluginFormat; | |||
if (! format.fileMightContainThisPluginType (desc.fileOrIdentifier)) | |||
return AudioComponentResult { NEEDS_TRANS ("Plug-in description is not an AudioUnit plug-in") }; | |||
String pluginName, version, manufacturer; | |||
AudioComponentDescription componentDesc; | |||
AudioComponent auComponent; | |||
String errMessage = NEEDS_TRANS ("Cannot find AudioUnit from description"); | |||
if (! getComponentDescFromIdentifier (desc.fileOrIdentifier, componentDesc, pluginName, version, manufacturer) | |||
&& ! getComponentDescFromFile (desc.fileOrIdentifier, componentDesc, pluginName, version, manufacturer)) | |||
{ | |||
return AudioComponentResult { errMessage }; | |||
} | |||
if ((auComponent = AudioComponentFindNext (nullptr, &componentDesc)) == nullptr) | |||
{ | |||
return AudioComponentResult { errMessage }; | |||
} | |||
if (AudioComponentGetDescription (auComponent, &componentDesc) != noErr) | |||
{ | |||
return AudioComponentResult { errMessage }; | |||
} | |||
const bool isAUv3 = AudioUnitFormatHelpers::isPluginAUv3 (componentDesc); | |||
return AudioComponentResult { { auComponent, isAUv3 } }; | |||
} | |||
static void getOrCreateARAAudioUnit (VersionedAudioComponent auComponent, std::function<void (AudioUnitSharedPtr)> callback) | |||
{ | |||
static std::map<VersionedAudioComponent, AudioUnitWeakPtr> audioUnitARACache; | |||
if (auto audioUnit = audioUnitARACache[auComponent].lock()) | |||
{ | |||
callback (std::move (audioUnit)); | |||
return; | |||
} | |||
createAudioUnit (auComponent, [auComponent, cb = std::move (callback)] (AudioUnit audioUnit, OSStatus err) | |||
{ | |||
cb ([auComponent, audioUnit, err]() -> AudioUnitSharedPtr | |||
{ | |||
if (err != noErr) | |||
return nullptr; | |||
AudioUnitSharedPtr auPtr { AudioUnitUniquePtr { audioUnit } }; | |||
audioUnitARACache[auComponent] = auPtr; | |||
return auPtr; | |||
}()); | |||
}); | |||
} | |||
//============================================================================== | |||
class AudioUnitPluginWindowCarbon; | |||
class AudioUnitPluginWindowCocoa; | |||
//============================================================================== | |||
@@ -979,6 +1177,23 @@ public: | |||
desc.numInputChannels = getTotalNumInputChannels(); | |||
desc.numOutputChannels = getTotalNumOutputChannels(); | |||
desc.isInstrument = (componentDesc.componentType == kAudioUnitType_MusicDevice); | |||
#if JUCE_PLUGINHOST_ARA | |||
desc.hasARAExtension = [&] | |||
{ | |||
UInt32 propertySize = sizeof (ARA::ARAAudioUnitFactory); | |||
Boolean isWriteable = FALSE; | |||
OSStatus status = AudioUnitGetPropertyInfo (audioUnit, | |||
ARA::kAudioUnitProperty_ARAFactory, | |||
kAudioUnitScope_Global, | |||
0, | |||
&propertySize, | |||
&isWriteable); | |||
return (status == noErr) && (propertySize == sizeof (ARA::ARAAudioUnitFactory)) && ! isWriteable; | |||
}(); | |||
#endif | |||
} | |||
void getExtensions (ExtensionsVisitor& visitor) const override | |||
@@ -993,6 +1208,33 @@ public: | |||
}; | |||
visitor.visitAudioUnitClient (Extensions { this }); | |||
#ifdef JUCE_PLUGINHOST_ARA | |||
struct ARAExtensions : public ExtensionsVisitor::ARAClient | |||
{ | |||
explicit ARAExtensions (const AudioUnitPluginInstance* instanceIn) : instance (instanceIn) {} | |||
void createARAFactoryAsync (std::function<void (ARAFactoryWrapper)> cb) const override | |||
{ | |||
getOrCreateARAAudioUnit ({ instance->auComponent, instance->isAUv3 }, | |||
[origCb = std::move (cb)] (auto dylibKeepAliveAudioUnit) | |||
{ | |||
origCb ([&]() -> ARAFactoryWrapper | |||
{ | |||
if (dylibKeepAliveAudioUnit != nullptr) | |||
return ARAFactoryWrapper { ::juce::getARAFactory (std::move (dylibKeepAliveAudioUnit)) }; | |||
return ARAFactoryWrapper { nullptr }; | |||
}()); | |||
}); | |||
} | |||
const AudioUnitPluginInstance* instance = nullptr; | |||
}; | |||
if (hasARAExtension (audioUnit)) | |||
visitor.visitARAClient (ARAExtensions (this)); | |||
#endif | |||
} | |||
void* getPlatformSpecificData() override { return audioUnit; } | |||
@@ -1124,9 +1366,9 @@ public: | |||
{ | |||
if (prepared) | |||
{ | |||
AudioUnitUninitialize (audioUnit); | |||
resetBuses(); | |||
AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0); | |||
AudioUnitUninitialize (audioUnit); | |||
outputBufferList.clear(); | |||
prepared = false; | |||
@@ -1615,7 +1857,6 @@ public: | |||
private: | |||
//============================================================================== | |||
friend class AudioUnitPluginWindowCarbon; | |||
friend class AudioUnitPluginWindowCocoa; | |||
friend class AudioUnitPluginFormat; | |||
@@ -2594,162 +2835,12 @@ private: | |||
} | |||
}; | |||
#if JUCE_SUPPORT_CARBON | |||
//============================================================================== | |||
class AudioUnitPluginWindowCarbon : public AudioProcessorEditor | |||
{ | |||
public: | |||
AudioUnitPluginWindowCarbon (AudioUnitPluginInstance& p) | |||
: AudioProcessorEditor (&p), | |||
plugin (p), | |||
audioComponent (nullptr), | |||
viewComponent (nullptr) | |||
{ | |||
innerWrapper.reset (new InnerWrapperComponent (*this)); | |||
addAndMakeVisible (innerWrapper.get()); | |||
setOpaque (true); | |||
setVisible (true); | |||
setSize (400, 300); | |||
UInt32 propertySize; | |||
if (AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_GetUIComponentList, | |||
kAudioUnitScope_Global, 0, &propertySize, NULL) == noErr | |||
&& propertySize > 0) | |||
{ | |||
HeapBlock<AudioComponentDescription> views (propertySize / sizeof (AudioComponentDescription)); | |||
if (AudioUnitGetProperty (plugin.audioUnit, kAudioUnitProperty_GetUIComponentList, | |||
kAudioUnitScope_Global, 0, &views[0], &propertySize) == noErr) | |||
{ | |||
audioComponent = AudioComponentFindNext (nullptr, &views[0]); | |||
} | |||
} | |||
} | |||
~AudioUnitPluginWindowCarbon() | |||
{ | |||
innerWrapper = nullptr; | |||
if (isValid()) | |||
plugin.editorBeingDeleted (this); | |||
} | |||
bool isValid() const noexcept { return audioComponent != nullptr; } | |||
//============================================================================== | |||
void paint (Graphics& g) override | |||
{ | |||
g.fillAll (Colours::black); | |||
} | |||
void resized() override | |||
{ | |||
if (innerWrapper != nullptr) | |||
innerWrapper->setSize (getWidth(), getHeight()); | |||
} | |||
//============================================================================== | |||
bool keyStateChanged (bool) override { return false; } | |||
bool keyPressed (const KeyPress&) override { return false; } | |||
//============================================================================== | |||
AudioUnit getAudioUnit() const { return plugin.audioUnit; } | |||
AudioUnitCarbonView getViewComponent() | |||
{ | |||
if (viewComponent == nullptr && audioComponent != nullptr) | |||
AudioComponentInstanceNew (audioComponent, &viewComponent); | |||
return viewComponent; | |||
} | |||
void closeViewComponent() | |||
{ | |||
if (viewComponent != nullptr) | |||
{ | |||
JUCE_AU_LOG ("Closing AU GUI: " + plugin.getName()); | |||
AudioComponentInstanceDispose (viewComponent); | |||
viewComponent = nullptr; | |||
} | |||
} | |||
private: | |||
//============================================================================== | |||
AudioUnitPluginInstance& plugin; | |||
AudioComponent audioComponent; | |||
AudioUnitCarbonView viewComponent; | |||
//============================================================================== | |||
class InnerWrapperComponent : public CarbonViewWrapperComponent | |||
{ | |||
public: | |||
InnerWrapperComponent (AudioUnitPluginWindowCarbon& w) : owner (w) {} | |||
~InnerWrapperComponent() | |||
{ | |||
deleteWindow(); | |||
} | |||
HIViewRef attachView (WindowRef windowRef, HIViewRef rootView) override | |||
{ | |||
JUCE_AU_LOG ("Opening AU GUI: " + owner.plugin.getName()); | |||
AudioUnitCarbonView carbonView = owner.getViewComponent(); | |||
if (carbonView == 0) | |||
return 0; | |||
Float32Point pos = { 0, 0 }; | |||
Float32Point size = { 250, 200 }; | |||
HIViewRef pluginView = 0; | |||
AudioUnitCarbonViewCreate (carbonView, owner.getAudioUnit(), windowRef, rootView, | |||
&pos, &size, (ControlRef*) &pluginView); | |||
return pluginView; | |||
} | |||
void removeView (HIViewRef) override | |||
{ | |||
owner.closeViewComponent(); | |||
} | |||
private: | |||
AudioUnitPluginWindowCarbon& owner; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InnerWrapperComponent) | |||
}; | |||
friend class InnerWrapperComponent; | |||
std::unique_ptr<InnerWrapperComponent> innerWrapper; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioUnitPluginWindowCarbon) | |||
}; | |||
#endif | |||
//============================================================================== | |||
AudioProcessorEditor* AudioUnitPluginInstance::createEditor() | |||
{ | |||
std::unique_ptr<AudioProcessorEditor> w (new AudioUnitPluginWindowCocoa (*this, false)); | |||
if (! static_cast<AudioUnitPluginWindowCocoa*> (w.get())->isValid()) | |||
w.reset(); | |||
#if JUCE_SUPPORT_CARBON | |||
if (w == nullptr) | |||
{ | |||
w.reset (new AudioUnitPluginWindowCarbon (*this)); | |||
if (! static_cast<AudioUnitPluginWindowCarbon*> (w.get())->isValid()) | |||
w.reset(); | |||
} | |||
#endif | |||
if (w == nullptr) | |||
w.reset (new AudioUnitPluginWindowCocoa (*this, true)); // use AUGenericView as a fallback | |||
return w.release(); | |||
@@ -2795,95 +2886,54 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
double rate, int blockSize, | |||
PluginCreationCallback callback) | |||
{ | |||
using namespace AudioUnitFormatHelpers; | |||
auto auComponentResult = getAudioComponent (*this, desc); | |||
if (fileMightContainThisPluginType (desc.fileOrIdentifier)) | |||
if (! auComponentResult.isValid()) | |||
{ | |||
String pluginName, version, manufacturer; | |||
AudioComponentDescription componentDesc; | |||
AudioComponent auComponent; | |||
String errMessage = NEEDS_TRANS ("Cannot find AudioUnit from description"); | |||
if ((! getComponentDescFromIdentifier (desc.fileOrIdentifier, componentDesc, pluginName, version, manufacturer)) | |||
&& (! getComponentDescFromFile (desc.fileOrIdentifier, componentDesc, pluginName, version, manufacturer))) | |||
{ | |||
callback (nullptr, errMessage); | |||
return; | |||
} | |||
if ((auComponent = AudioComponentFindNext (nullptr, &componentDesc)) == nullptr) | |||
{ | |||
callback (nullptr, errMessage); | |||
return; | |||
} | |||
if (AudioComponentGetDescription (auComponent, &componentDesc) != noErr) | |||
{ | |||
callback (nullptr, errMessage); | |||
return; | |||
} | |||
struct AUAsyncInitializationCallback | |||
{ | |||
typedef void (^AUCompletionCallbackBlock)(AudioComponentInstance, OSStatus); | |||
AUAsyncInitializationCallback (double inSampleRate, int inFramesPerBuffer, | |||
PluginCreationCallback inOriginalCallback) | |||
: sampleRate (inSampleRate), framesPerBuffer (inFramesPerBuffer), | |||
originalCallback (std::move (inOriginalCallback)) | |||
{ | |||
block = CreateObjCBlock (this, &AUAsyncInitializationCallback::completion); | |||
} | |||
AUCompletionCallbackBlock getBlock() noexcept { return block; } | |||
void completion (AudioComponentInstance audioUnit, OSStatus err) | |||
{ | |||
if (err == noErr) | |||
{ | |||
std::unique_ptr<AudioUnitPluginInstance> instance (new AudioUnitPluginInstance (audioUnit)); | |||
callback (nullptr, std::move (auComponentResult.errorMessage)); | |||
return; | |||
} | |||
if (instance->initialise (sampleRate, framesPerBuffer)) | |||
originalCallback (std::move (instance), {}); | |||
else | |||
originalCallback (nullptr, NEEDS_TRANS ("Unable to initialise the AudioUnit plug-in")); | |||
} | |||
else | |||
{ | |||
auto errMsg = TRANS ("An OS error occurred during initialisation of the plug-in (XXX)"); | |||
originalCallback (nullptr, errMsg.replace ("XXX", String (err))); | |||
} | |||
createAudioUnit (auComponentResult.component, | |||
[rate, blockSize, origCallback = std::move (callback)] (AudioUnit audioUnit, OSStatus err) | |||
{ | |||
if (err == noErr) | |||
{ | |||
auto instance = std::make_unique<AudioUnitPluginInstance> (audioUnit); | |||
delete this; | |||
} | |||
if (instance->initialise (rate, blockSize)) | |||
origCallback (std::move (instance), {}); | |||
else | |||
origCallback (nullptr, NEEDS_TRANS ("Unable to initialise the AudioUnit plug-in")); | |||
} | |||
else | |||
{ | |||
auto errMsg = TRANS ("An OS error occurred during initialisation of the plug-in (XXX)"); | |||
origCallback (nullptr, errMsg.replace ("XXX", String (err))); | |||
} | |||
}); | |||
} | |||
double sampleRate; | |||
int framesPerBuffer; | |||
PluginCreationCallback originalCallback; | |||
ObjCBlock<AUCompletionCallbackBlock> block; | |||
}; | |||
void AudioUnitPluginFormat::createARAFactoryAsync (const PluginDescription& desc, ARAFactoryCreationCallback callback) | |||
{ | |||
auto auComponentResult = getAudioComponent (*this, desc); | |||
auto callbackBlock = new AUAsyncInitializationCallback (rate, blockSize, std::move (callback)); | |||
if (! auComponentResult.isValid()) | |||
{ | |||
callback ({ {}, "Failed to create AudioComponent for " + desc.descriptiveName }); | |||
return; | |||
} | |||
if (AudioUnitFormatHelpers::isPluginAUv3 (componentDesc)) | |||
{ | |||
if (@available (macOS 10.11, *)) | |||
getOrCreateARAAudioUnit (auComponentResult.component, [cb = std::move (callback)] (auto dylibKeepAliveAudioUnit) | |||
{ | |||
cb ([&]() -> ARAFactoryResult | |||
{ | |||
AudioComponentInstantiate (auComponent, kAudioComponentInstantiation_LoadOutOfProcess, | |||
callbackBlock->getBlock()); | |||
if (dylibKeepAliveAudioUnit != nullptr) | |||
return { ARAFactoryWrapper { ::juce::getARAFactory (std::move (dylibKeepAliveAudioUnit)) }, "" }; | |||
return; | |||
} | |||
} | |||
AudioComponentInstance audioUnit; | |||
auto err = AudioComponentInstanceNew(auComponent, &audioUnit); | |||
callbackBlock->completion (err != noErr ? nullptr : audioUnit, err); | |||
} | |||
else | |||
{ | |||
callback (nullptr, NEEDS_TRANS ("Plug-in description is not an AudioUnit plug-in")); | |||
} | |||
return { {}, "Failed to create ARAFactory from the provided AudioUnit" }; | |||
}()); | |||
}); | |||
} | |||
bool AudioUnitPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription& desc) const | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -19,6 +26,7 @@ | |||
#pragma once | |||
#include "juce_lv2_config.h" | |||
#include "juce_core/containers/juce_Optional.h" | |||
#ifdef Bool | |||
#undef Bool // previously defined in X11/Xlib.h | |||
@@ -127,61 +135,61 @@ struct ObjectTraits { static constexpr auto construct = lv2_atom_forge_object; | |||
using SequenceFrame = ScopedFrame<SequenceTraits>; | |||
using ObjectFrame = ScopedFrame<ObjectTraits>; | |||
template <typename Value, typename Callback> | |||
bool withValue (const Optional<Value>& opt, Callback&& callback) | |||
{ | |||
if (! opt.hasValue()) | |||
return false; | |||
callback (*opt); | |||
return true; | |||
} | |||
struct NumericAtomParser | |||
{ | |||
explicit NumericAtomParser (LV2_URID_Map mapFeatureIn) | |||
: mapFeature (mapFeatureIn) {} | |||
template <typename Type> | |||
struct ParseResult | |||
{ | |||
ParseResult (Type type) : value (type), successful (true) {} | |||
ParseResult() : value(), successful (false) {} | |||
template <typename Fn> | |||
ParseResult andThen (Fn&& fn) const | |||
{ | |||
if (successful) | |||
fn (value); | |||
template <typename T> struct Tag { LV2_URID urid; }; | |||
return *this; | |||
} | |||
template <typename Target, typename... Types> | |||
static Optional<Target> tryParse (const LV2_Atom&, const void*) | |||
{ | |||
return {}; | |||
} | |||
operator bool() const noexcept { return successful; } | |||
template <typename Target, typename Head, typename... Tail> | |||
static Optional<Target> tryParse (const LV2_Atom& atom, const void* data, Tag<Head> head, Tag<Tail>... tail) | |||
{ | |||
if (atom.type == head.urid && atom.size == sizeof (Head)) | |||
return static_cast<Target> (*reinterpret_cast<const Head*> (data)); | |||
Type value; | |||
bool successful; | |||
}; | |||
return tryParse<Target> (atom, data, tail...); | |||
} | |||
template <typename Target> | |||
ParseResult<Target> parseNumericAtom (const LV2_Atom* atom, const void* data) const | |||
Optional<Target> parseNumericAtom (const LV2_Atom* atom, const void* data) const | |||
{ | |||
if (atom == nullptr) | |||
return {}; | |||
if (atom->type == mLV2_ATOM__Int && atom->size == sizeof (int32_t)) | |||
return { static_cast<Target> (*static_cast<const int32_t*> (data)) }; | |||
if (atom->type == mLV2_ATOM__Long && atom->size == sizeof (int64_t)) | |||
return { static_cast<Target> (*static_cast<const int64_t*> (data)) }; | |||
if (atom->type == mLV2_ATOM__Float && atom->size == sizeof (float)) | |||
return { static_cast<Target> (*static_cast<const float*> (data)) }; | |||
if (atom->type == mLV2_ATOM__Double && atom->size == sizeof (double)) | |||
return { static_cast<Target> (*static_cast<const double*> (data)) }; | |||
return {}; | |||
return tryParse<Target> (*atom, | |||
data, | |||
Tag<int32_t> { mLV2_ATOM__Bool }, | |||
Tag<int32_t> { mLV2_ATOM__Int }, | |||
Tag<int64_t> { mLV2_ATOM__Long }, | |||
Tag<float> { mLV2_ATOM__Float }, | |||
Tag<double> { mLV2_ATOM__Double }); | |||
} | |||
template <typename Target> | |||
ParseResult<Target> parseNumericAtom (const LV2_Atom* atom) const | |||
Optional<Target> parseNumericAtom (const LV2_Atom* atom) const | |||
{ | |||
return parseNumericAtom<Target> (atom, atom + 1); | |||
} | |||
template <typename Target> | |||
ParseResult<Target> parseNumericOption (const LV2_Options_Option* option) const | |||
Optional<Target> parseNumericOption (const LV2_Options_Option* option) const | |||
{ | |||
if (option != nullptr) | |||
{ | |||
@@ -240,8 +248,10 @@ struct PatchSetHelper | |||
lv2_atom_object_query (object, query); | |||
if (isPlugin (subject)) | |||
setPluginProperty (property, value, std::forward<Callback> (callback)); | |||
if (! isPlugin (subject)) | |||
return; | |||
setPluginProperty (property, value, std::forward<Callback> (callback)); | |||
} | |||
template <typename Callback> | |||
@@ -270,14 +280,14 @@ struct PatchSetHelper | |||
const auto parseResult = parser.parseNumericAtom<float> (value); | |||
if (! parseResult.successful) | |||
if (! parseResult.hasValue()) | |||
{ | |||
// Didn't understand the type of this atom. | |||
jassertfalse; | |||
return; | |||
} | |||
callback.setParameter (reinterpret_cast<const LV2_Atom_URID*> (property)->body, parseResult.value); | |||
callback.setParameter (reinterpret_cast<const LV2_Atom_URID*> (property)->body, *parseResult); | |||
} | |||
NumericAtomParser parser; | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -30,12 +37,11 @@ namespace juce | |||
namespace lv2_host | |||
{ | |||
template <typename Struct, typename Member, typename Value> | |||
auto with (Struct&& s, Member&& member, Value&& value) noexcept | |||
template <typename Struct, typename Value> | |||
auto with (Struct s, Value Struct::* member, Value value) noexcept | |||
{ | |||
auto copy = std::forward<Struct> (s); | |||
copy.*member = std::forward<Value> (value); | |||
return copy; | |||
s.*member = std::move (value); | |||
return s; | |||
} | |||
/* Converts a void* to an LV2_Atom* if the buffer looks like it holds a well-formed Atom, or | |||
@@ -1682,7 +1688,7 @@ private: | |||
template <size_t Alignment> | |||
static SingleSizeAlignedStorage<Alignment> grow (SingleSizeAlignedStorage<Alignment> storage, size_t size) | |||
{ | |||
if (storage.size() <= size) | |||
if (size <= storage.size()) | |||
return storage; | |||
SingleSizeAlignedStorage<Alignment> newStorage { jmax (size, (storage.size() * 3) / 2) }; | |||
@@ -2122,6 +2128,8 @@ private: | |||
JUCE_LEAK_DETECTOR (PortMap) | |||
}; | |||
struct FreeString { void operator() (void* ptr) const noexcept { lilv_free (ptr); } }; | |||
class PluginState | |||
{ | |||
public: | |||
@@ -2140,7 +2148,6 @@ public: | |||
std::string toString (LilvWorld* world, LV2_URID_Map* map, LV2_URID_Unmap* unmap, const char* uri) const | |||
{ | |||
struct FreeString { void operator() (void* ptr) const noexcept { lilv_free (ptr); } }; | |||
std::unique_ptr<char, FreeString> result { lilv_state_to_string (world, | |||
map, | |||
unmap, | |||
@@ -2256,17 +2263,16 @@ struct UiDescriptorLibrary | |||
class UiDescriptorArgs | |||
{ | |||
public: | |||
const char* libraryPath = nullptr; | |||
const char* uiUri = nullptr; | |||
String libraryPath; | |||
String uiUri; | |||
auto withLibraryPath (const char* v) const noexcept { return with (&UiDescriptorArgs::libraryPath, v); } | |||
auto withUiUri (const char* v) const noexcept { return with (&UiDescriptorArgs::uiUri, v); } | |||
auto withLibraryPath (String v) const noexcept { return with (&UiDescriptorArgs::libraryPath, v); } | |||
auto withUiUri (String v) const noexcept { return with (&UiDescriptorArgs::uiUri, v); } | |||
private: | |||
template <typename Member> | |||
UiDescriptorArgs with (Member&& member, const char* value) const noexcept | |||
UiDescriptorArgs with (String UiDescriptorArgs::* member, String value) const noexcept | |||
{ | |||
return juce::lv2_host::with (*this, std::forward<Member> (member), value); | |||
return juce::lv2_host::with (*this, member, std::move (value)); | |||
} | |||
}; | |||
@@ -2280,7 +2286,7 @@ public: | |||
explicit UiDescriptor (const UiDescriptorArgs& args) | |||
: library (args.libraryPath), | |||
descriptor (extractUiDescriptor (library, args.uiUri)) | |||
descriptor (extractUiDescriptor (library, args.uiUri.toRawUTF8())) | |||
{} | |||
void portEvent (LV2UI_Handle ui, | |||
@@ -2342,8 +2348,7 @@ private: | |||
JUCE_LEAK_DETECTOR (UiDescriptor) | |||
}; | |||
enum class UpdateUi { no, yes }; | |||
enum class UpdateProcessor { no, yes }; | |||
enum class Update { no, yes }; | |||
/* A bit like the FlaggedFloatCache used by the VST3 host/client. | |||
@@ -2366,12 +2371,12 @@ public: | |||
size_t size() const noexcept { return values.size(); } | |||
void set (size_t index, float value, UpdateUi updateUi, UpdateProcessor updateProcessor) | |||
void set (size_t index, float value, Update update) | |||
{ | |||
jassert (index < size()); | |||
values[index].store (value, std::memory_order_relaxed); | |||
needsUiUpdate .set (index, updateUi == UpdateUi::yes ? 1 : 0); | |||
needsProcessorUpdate.set (index, updateProcessor == UpdateProcessor::yes ? 1 : 0); | |||
needsUiUpdate .set (index, update == Update::yes ? 1 : 0); | |||
needsProcessorUpdate.set (index, update == Update::yes ? 1 : 0); | |||
} | |||
float get (size_t index) const noexcept | |||
@@ -2431,18 +2436,18 @@ public: | |||
void setValue (float f) override | |||
{ | |||
cache.set ((size_t) getParameterIndex(), range.convertFrom0to1 (f), UpdateUi::yes, UpdateProcessor::yes); | |||
cache.set ((size_t) getParameterIndex(), range.convertFrom0to1 (f), Update::yes); | |||
} | |||
void setDenormalisedValueFromUi (float denormalised) | |||
void setDenormalisedValue (float denormalised) | |||
{ | |||
cache.set ((size_t) getParameterIndex(), denormalised, UpdateUi::no, UpdateProcessor::yes); | |||
cache.set ((size_t) getParameterIndex(), denormalised, Update::yes); | |||
sendValueChangedMessageToListeners (range.convertTo0to1 (denormalised)); | |||
} | |||
void setDenormalisedValueWithoutTriggeringUpdate (float denormalised) | |||
{ | |||
cache.set ((size_t) getParameterIndex(), denormalised, UpdateUi::no, UpdateProcessor::no); | |||
cache.set ((size_t) getParameterIndex(), denormalised, Update::no); | |||
sendValueChangedMessageToListeners (range.convertTo0to1 (denormalised)); | |||
} | |||
@@ -2564,20 +2569,25 @@ private: | |||
class UiInstanceArgs | |||
{ | |||
public: | |||
const char* bundlePath = nullptr; | |||
const char* pluginUri = nullptr; | |||
File bundlePath; | |||
URL pluginUri; | |||
auto withBundlePath (const char* v) const noexcept { return with (&UiInstanceArgs::bundlePath, v); } | |||
auto withPluginUri (const char* v) const noexcept { return with (&UiInstanceArgs::pluginUri, v); } | |||
auto withBundlePath (File v) const noexcept { return with (&UiInstanceArgs::bundlePath, std::move (v)); } | |||
auto withPluginUri (URL v) const noexcept { return with (&UiInstanceArgs::pluginUri, std::move (v)); } | |||
private: | |||
template <typename Member> | |||
UiInstanceArgs with (Member&& member, const char* value) const noexcept | |||
UiInstanceArgs with (Member UiInstanceArgs::* member, Member value) const noexcept | |||
{ | |||
return juce::lv2_host::with (*this, std::forward<Member> (member), value); | |||
return juce::lv2_host::with (*this, member, std::move (value)); | |||
} | |||
}; | |||
static File bundlePathFromUri (const char* uri) | |||
{ | |||
return File { std::unique_ptr<char, FreeString> { lilv_file_uri_parse (uri, nullptr) }.get() }; | |||
} | |||
/* | |||
Creates and holds a UI instance for a plugin with a specific URI, using the provided descriptor. | |||
*/ | |||
@@ -2665,14 +2675,14 @@ private: | |||
using Instance = std::unique_ptr<void, void (*) (LV2UI_Handle)>; | |||
using Idle = int (*) (LV2UI_Handle); | |||
Instance makeInstance (const char* pluginUri, const char* bundlePath, const LV2_Feature* const* features) | |||
Instance makeInstance (const URL& pluginUri, const File& bundlePath, const LV2_Feature* const* features) | |||
{ | |||
if (descriptor->get() == nullptr) | |||
return { nullptr, [] (LV2UI_Handle) {} }; | |||
return Instance { descriptor->get()->instantiate (descriptor->get(), | |||
pluginUri, | |||
bundlePath, | |||
pluginUri.toString (false).toRawUTF8(), | |||
File::addTrailingSeparator (bundlePath.getFullPathName()).toRawUTF8(), | |||
writeFunction, | |||
this, | |||
&widget, | |||
@@ -2752,10 +2762,9 @@ public: | |||
auto withSampleRate (float v) const { return with (&UiFeaturesDataOptions::sampleRate, v); } | |||
private: | |||
template <typename Member, typename Value> | |||
UiFeaturesDataOptions with (Member&& member, Value&& value) const | |||
UiFeaturesDataOptions with (float UiFeaturesDataOptions::* member, float value) const | |||
{ | |||
return juce::lv2_host::with (*this, std::forward<Member> (member), std::forward<Value> (value)); | |||
return juce::lv2_host::with (*this, member, value); | |||
} | |||
}; | |||
@@ -3034,8 +3043,8 @@ public: | |||
*this, | |||
touchListener, | |||
&uiDescriptor, | |||
UiInstanceArgs{}.withBundlePath (uiBundleUri.toRawUTF8()) | |||
.withPluginUri (instance.instance.getUri()), | |||
UiInstanceArgs{}.withBundlePath (bundlePathFromUri (uiBundleUri.toRawUTF8())) | |||
.withPluginUri (URL (instance.instance.getUri())), | |||
viewComponent.getWidget(), | |||
instance, | |||
opts)), | |||
@@ -3168,14 +3177,6 @@ private: | |||
float getEffectiveScale() const { return nativeScaleFactor * userScaleFactor; } | |||
float getTopLevelDesktopScale() const | |||
{ | |||
if (auto* comp = getTopLevelComponent()) | |||
return comp->getDesktopScaleFactor(); | |||
return 1.0f; | |||
} | |||
// If possible, try to keep platform-specific handing restricted to the implementation of | |||
// ViewComponent. Keep the interface of ViewComponent consistent on all platforms. | |||
#if JUCE_LINUX || JUCE_BSD | |||
@@ -4107,11 +4108,14 @@ static SupportedParameter getInfoForPatchParameter (World& worldIn, | |||
jassertfalse; // A ScalePoint must have both a rdfs:label and a rdf:value | |||
} | |||
const auto minimum = getValue (LV2_CORE__minimum, 0.0f); | |||
const auto maximum = getValue (LV2_CORE__maximum, 1.0f); | |||
return { { std::move (parsedScalePoints), | |||
"des:" + String::fromUTF8 (property.getTyped()), | |||
getValue (LV2_CORE__default, 0.0f), | |||
getValue (LV2_CORE__minimum, 0.0f), | |||
getValue (LV2_CORE__maximum, 1.0f), | |||
getValue (LV2_CORE__default, (minimum + maximum) * 0.5f), | |||
minimum, | |||
maximum, | |||
typeUrid == urids.mLV2_ATOM__Bool || hasPortProperty (LV2_CORE__toggled), | |||
typeUrid == urids.mLV2_ATOM__Int || typeUrid == urids.mLV2_ATOM__Long, | |||
hasPortProperty (LV2_CORE__enumeration) }, | |||
@@ -4402,7 +4406,8 @@ public: | |||
numSamples, | |||
sampleRate); | |||
setStateInformation (mb.getData(), (int) mb.getSize()); | |||
// prepareToPlay is *guaranteed* not to be called concurrently with processBlock | |||
setStateInformationImpl (mb.getData(), (int) mb.getSize(), ConcurrentWithAudioCallback::no); | |||
jassert (numSamples == instance->features.getMaxBlockSize()); | |||
@@ -4487,7 +4492,8 @@ public: | |||
return; | |||
lastAppliedPreset = newProgram; | |||
applyStateWithAppropriateLocking (loadStateWithUri (presetUris[(size_t) newProgram])); | |||
applyStateWithAppropriateLocking (loadStateWithUri (presetUris[(size_t) newProgram]), | |||
ConcurrentWithAudioCallback::yes); | |||
} | |||
const String getProgramName (int program) override | |||
@@ -4524,16 +4530,7 @@ public: | |||
void setStateInformation (const void* data, int size) override | |||
{ | |||
JUCE_ASSERT_MESSAGE_THREAD; | |||
if (data == nullptr || size == 0) | |||
return; | |||
auto begin = static_cast<const char*> (data); | |||
std::vector<char> copy (begin, begin + size); | |||
copy.push_back (0); | |||
auto mapFeature = instance->symap->getMapFeature(); | |||
applyStateWithAppropriateLocking (PluginState { lilv_state_new_from_string (world->get(), &mapFeature, copy.data()) }); | |||
setStateInformationImpl (data, size, ConcurrentWithAudioCallback::yes); | |||
} | |||
void setNonRealtime (bool newValue) noexcept override | |||
@@ -4573,6 +4570,8 @@ public: | |||
AudioProcessorParameter* getBypassParameter() const override { return bypassParam; } | |||
private: | |||
enum class ConcurrentWithAudioCallback { no, yes }; | |||
LV2AudioPluginInstance (std::shared_ptr<World> worldIn, | |||
const Plugin& pluginIn, | |||
std::unique_ptr<InstanceWithSupports>&& in, | |||
@@ -4593,7 +4592,22 @@ private: | |||
std::move (uiDescriptorIn), | |||
[this] { postChangedParametersToUi(); }) | |||
{ | |||
applyStateWithAppropriateLocking (std::move (stateToApply)); | |||
applyStateWithAppropriateLocking (std::move (stateToApply), ConcurrentWithAudioCallback::no); | |||
} | |||
void setStateInformationImpl (const void* data, int size, ConcurrentWithAudioCallback concurrent) | |||
{ | |||
JUCE_ASSERT_MESSAGE_THREAD; | |||
if (data == nullptr || size == 0) | |||
return; | |||
auto begin = static_cast<const char*> (data); | |||
std::vector<char> copy (begin, begin + size); | |||
copy.push_back (0); | |||
auto mapFeature = instance->symap->getMapFeature(); | |||
applyStateWithAppropriateLocking (PluginState { lilv_state_new_from_string (world->get(), &mapFeature, copy.data()) }, | |||
concurrent); | |||
} | |||
// This does *not* destroy the editor component. | |||
@@ -4691,13 +4705,13 @@ private: | |||
return instance.get(); | |||
} | |||
void applyStateWithAppropriateLocking (PluginState&& state) | |||
void applyStateWithAppropriateLocking (PluginState&& state, ConcurrentWithAudioCallback concurrent) | |||
{ | |||
PortMap portStateManager (instance->ports); | |||
// If a plugin supports threadSafeRestore, its restore method is thread-safe | |||
// and may be called concurrently with audio class functions. | |||
if (hasThreadSafeRestore) | |||
if (hasThreadSafeRestore || concurrent == ConcurrentWithAudioCallback::no) | |||
{ | |||
state.restore (*instance, portStateManager); | |||
} | |||
@@ -4841,7 +4855,7 @@ private: | |||
if (auto* param = parameterValues.getParamByPortIndex (header.portIndex)) | |||
{ | |||
param->setDenormalisedValueFromUi (value); | |||
param->setDenormalisedValue (value); | |||
} | |||
else if (auto* port = controlPortStructure.getControlPortByIndex (header.portIndex)) | |||
{ | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1040,24 +1047,18 @@ public: | |||
} | |||
} | |||
static void hostToPluginEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer, | |||
Steinberg::Vst::IParameterChanges* parameterChanges, | |||
const StoredMidiMapping& midiMapping) | |||
template <typename Callback> | |||
static void hostToPluginEventList (Steinberg::Vst::IEventList& result, | |||
MidiBuffer& midiBuffer, | |||
StoredMidiMapping& mapping, | |||
Callback&& callback) | |||
{ | |||
toEventList (result, | |||
midiBuffer, | |||
parameterChanges, | |||
&midiMapping, | |||
EventConversionKind::hostToPlugin); | |||
toEventList (result, midiBuffer, &mapping, callback); | |||
} | |||
static void pluginToHostEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer) | |||
{ | |||
toEventList (result, | |||
midiBuffer, | |||
nullptr, | |||
nullptr, | |||
EventConversionKind::pluginToHost); | |||
toEventList (result, midiBuffer, nullptr, [] (auto&&...) {}); | |||
} | |||
private: | |||
@@ -1073,48 +1074,70 @@ private: | |||
pluginToHost | |||
}; | |||
static void toEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer, | |||
Steinberg::Vst::IParameterChanges* parameterChanges, | |||
const StoredMidiMapping* midiMapping, | |||
EventConversionKind kind) | |||
template <typename Callback> | |||
static bool sendMappedParameter (const MidiMessage& msg, | |||
StoredMidiMapping* midiMapping, | |||
Callback&& callback) | |||
{ | |||
enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once | |||
int numEvents = 0; | |||
if (midiMapping == nullptr) | |||
return false; | |||
for (const auto metadata : midiBuffer) | |||
{ | |||
if (++numEvents > maxNumEvents) | |||
break; | |||
const auto controlEvent = toVst3ControlEvent (msg); | |||
auto msg = metadata.getMessage(); | |||
if (! controlEvent.hasValue()) | |||
return false; | |||
if (midiMapping != nullptr && parameterChanges != nullptr) | |||
{ | |||
Vst3MidiControlEvent controlEvent; | |||
const auto controlParamID = midiMapping->getMapping (createSafeChannel (msg.getChannel()), | |||
controlEvent->controllerNumber); | |||
if (toVst3ControlEvent (msg, controlEvent)) | |||
{ | |||
const auto controlParamID = midiMapping->getMapping (createSafeChannel (msg.getChannel()), | |||
controlEvent.controllerNumber); | |||
if (controlParamID != Steinberg::Vst::kNoParamId) | |||
callback (controlParamID, controlEvent->paramValue); | |||
if (controlParamID != Steinberg::Vst::kNoParamId) | |||
{ | |||
Steinberg::int32 ignore; | |||
return true; | |||
} | |||
if (auto* queue = parameterChanges->addParameterData (controlParamID, ignore)) | |||
queue->addPoint (metadata.samplePosition, controlEvent.paramValue, ignore); | |||
} | |||
template <typename Callback> | |||
static void processMidiMessage (Steinberg::Vst::IEventList& result, | |||
const MidiMessageMetadata metadata, | |||
StoredMidiMapping* midiMapping, | |||
Callback&& callback) | |||
{ | |||
const auto msg = metadata.getMessage(); | |||
continue; | |||
} | |||
} | |||
if (sendMappedParameter (msg, midiMapping, std::forward<Callback> (callback))) | |||
return; | |||
if (auto maybeEvent = createVstEvent (msg, metadata.data, kind)) | |||
{ | |||
maybeEvent->busIndex = 0; | |||
maybeEvent->sampleOffset = metadata.samplePosition; | |||
result.addEvent (*maybeEvent); | |||
} | |||
const auto kind = midiMapping != nullptr ? EventConversionKind::hostToPlugin | |||
: EventConversionKind::pluginToHost; | |||
auto maybeEvent = createVstEvent (msg, metadata.data, kind); | |||
if (! maybeEvent.hasValue()) | |||
return; | |||
maybeEvent->busIndex = 0; | |||
maybeEvent->sampleOffset = metadata.samplePosition; | |||
result.addEvent (*maybeEvent); | |||
} | |||
/* If mapping is non-null, the conversion is assumed to be host-to-plugin, or otherwise | |||
plugin-to-host. | |||
*/ | |||
template <typename Callback> | |||
static void toEventList (Steinberg::Vst::IEventList& result, | |||
MidiBuffer& midiBuffer, | |||
StoredMidiMapping* midiMapping, | |||
Callback&& callback) | |||
{ | |||
enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once | |||
int numEvents = 0; | |||
for (const auto metadata : midiBuffer) | |||
{ | |||
if (++numEvents > maxNumEvents) | |||
break; | |||
processMidiMessage (result, metadata, midiMapping, std::forward<Callback> (callback)); | |||
} | |||
} | |||
@@ -1361,28 +1384,18 @@ private: | |||
Steinberg::Vst::ParamValue paramValue; | |||
}; | |||
static bool toVst3ControlEvent (const MidiMessage& msg, Vst3MidiControlEvent& result) | |||
static Optional<Vst3MidiControlEvent> toVst3ControlEvent (const MidiMessage& msg) | |||
{ | |||
if (msg.isController()) | |||
{ | |||
result = { (Steinberg::Vst::CtrlNumber) msg.getControllerNumber(), msg.getControllerValue() / 127.0}; | |||
return true; | |||
} | |||
return Vst3MidiControlEvent { (Steinberg::Vst::CtrlNumber) msg.getControllerNumber(), msg.getControllerValue() / 127.0 }; | |||
if (msg.isPitchWheel()) | |||
{ | |||
result = { Steinberg::Vst::kPitchBend, msg.getPitchWheelValue() / 16383.0}; | |||
return true; | |||
} | |||
return Vst3MidiControlEvent { Steinberg::Vst::kPitchBend, msg.getPitchWheelValue() / 16383.0}; | |||
if (msg.isChannelPressure()) | |||
{ | |||
result = { Steinberg::Vst::kAfterTouch, msg.getChannelPressureValue() / 127.0}; | |||
return true; | |||
} | |||
return Vst3MidiControlEvent { Steinberg::Vst::kAfterTouch, msg.getChannelPressureValue() / 127.0}; | |||
result.controllerNumber = -1; | |||
return false; | |||
return {}; | |||
} | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiEventList) | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -100,6 +107,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", | |||
#include <public.sdk/source/common/memorystream.h> | |||
#include <public.sdk/source/vst/vsteditcontroller.h> | |||
#include <public.sdk/source/vst/vstpresetfile.h> | |||
#include "pslextensions/ipslviewembedding.h" | |||
#else | |||
// needed for VST_VERSION | |||
#include <pluginterfaces/vst/vsttypes.h> | |||
@@ -150,6 +159,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", | |||
#include <public.sdk/source/vst/hosting/pluginterfacesupport.cpp> | |||
#endif | |||
#include "pslextensions/ipslviewembedding.h" | |||
//============================================================================== | |||
namespace Steinberg | |||
{ | |||
@@ -172,6 +183,12 @@ namespace Steinberg | |||
DEF_CLASS_IID (Linux::IEventHandler) | |||
#endif | |||
} | |||
namespace Presonus | |||
{ | |||
DEF_CLASS_IID (IPlugInViewEmbedding) | |||
} | |||
#endif // JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY | |||
JUCE_END_IGNORE_WARNINGS_MSVC | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -20,6 +27,18 @@ | |||
#include "juce_VST3Headers.h" | |||
#include "juce_VST3Common.h" | |||
#include "juce_ARACommon.h" | |||
#if JUCE_PLUGINHOST_ARA && (JUCE_MAC || JUCE_WINDOWS) | |||
#include <ARA_API/ARAVST3.h> | |||
namespace ARA | |||
{ | |||
DEF_CLASS_IID (IMainFactory) | |||
DEF_CLASS_IID (IPlugInEntryPoint) | |||
DEF_CLASS_IID (IPlugInEntryPoint2) | |||
} | |||
#endif | |||
namespace juce | |||
{ | |||
@@ -804,6 +823,20 @@ struct DescriptionFactory | |||
auto numClasses = factory->countClasses(); | |||
// Every ARA::IMainFactory must have a matching Steinberg::IComponent. | |||
// The match is determined by the two classes having the same name. | |||
std::unordered_set<String> araMainFactoryClassNames; | |||
#if JUCE_PLUGINHOST_ARA && (JUCE_MAC || JUCE_WINDOWS) | |||
for (Steinberg::int32 i = 0; i < numClasses; ++i) | |||
{ | |||
PClassInfo info; | |||
factory->getClassInfo (i, &info); | |||
if (std::strcmp (info.category, kARAMainFactoryClass) == 0) | |||
araMainFactoryClassNames.insert (info.name); | |||
} | |||
#endif | |||
for (Steinberg::int32 i = 0; i < numClasses; ++i) | |||
{ | |||
PClassInfo info; | |||
@@ -867,6 +900,9 @@ struct DescriptionFactory | |||
} | |||
} | |||
if (araMainFactoryClassNames.find (name) != araMainFactoryClassNames.end()) | |||
desc.hasARAExtension = true; | |||
if (desc.uniqueId != 0) | |||
result = performOnDescription (desc); | |||
@@ -1330,6 +1366,72 @@ private: | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3ModuleHandle) | |||
}; | |||
template <typename Type, size_t N> | |||
static int compareWithString (Type (&charArray)[N], const String& str) | |||
{ | |||
return std::strncmp (str.toRawUTF8(), | |||
charArray, | |||
std::min (str.getNumBytesAsUTF8(), (size_t) numElementsInArray (charArray))); | |||
} | |||
template <typename Callback> | |||
static void forEachARAFactory (IPluginFactory* pluginFactory, Callback&& cb) | |||
{ | |||
#if JUCE_PLUGINHOST_ARA && (JUCE_MAC || JUCE_WINDOWS) | |||
const auto numClasses = pluginFactory->countClasses(); | |||
for (Steinberg::int32 i = 0; i < numClasses; ++i) | |||
{ | |||
PClassInfo info; | |||
pluginFactory->getClassInfo (i, &info); | |||
if (std::strcmp (info.category, kARAMainFactoryClass) == 0) | |||
{ | |||
const bool keepGoing = cb (info); | |||
if (! keepGoing) | |||
break; | |||
} | |||
} | |||
#else | |||
ignoreUnused (pluginFactory, cb); | |||
#endif | |||
} | |||
static std::shared_ptr<const ARA::ARAFactory> getARAFactory (Steinberg::IPluginFactory* pluginFactory, const String& pluginName) | |||
{ | |||
std::shared_ptr<const ARA::ARAFactory> factory; | |||
#if JUCE_PLUGINHOST_ARA && (JUCE_MAC || JUCE_WINDOWS) | |||
forEachARAFactory (pluginFactory, | |||
[&pluginFactory, &pluginName, &factory] (const auto& pcClassInfo) | |||
{ | |||
if (compareWithString (pcClassInfo.name, pluginName) == 0) | |||
{ | |||
ARA::IMainFactory* source; | |||
if (pluginFactory->createInstance (pcClassInfo.cid, ARA::IMainFactory::iid, (void**) &source) | |||
== Steinberg::kResultOk) | |||
{ | |||
factory = getOrCreateARAFactory (source->getFactory(), | |||
[source] (const ARA::ARAFactory*) { source->release(); }); | |||
return false; | |||
} | |||
jassert (source == nullptr); | |||
} | |||
return true; | |||
}); | |||
#else | |||
ignoreUnused (pluginFactory, pluginName); | |||
#endif | |||
return factory; | |||
} | |||
static std::shared_ptr<const ARA::ARAFactory> getARAFactory (VST3ModuleHandle& module) | |||
{ | |||
auto* pluginFactory = module.getPluginFactory(); | |||
return getARAFactory (pluginFactory, module.getName()); | |||
} | |||
//============================================================================== | |||
struct VST3PluginWindow : public AudioProcessorEditor, | |||
private ComponentMovementWatcher, | |||
@@ -1677,6 +1779,27 @@ private: | |||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) // warning about overriding deprecated methods | |||
//============================================================================== | |||
static bool hasARAExtension (IPluginFactory* pluginFactory, const String& pluginClassName) | |||
{ | |||
bool result = false; | |||
forEachARAFactory (pluginFactory, | |||
[&pluginClassName, &result] (const auto& pcClassInfo) | |||
{ | |||
if (compareWithString (pcClassInfo.name, pluginClassName) == 0) | |||
{ | |||
result = true; | |||
return false; | |||
} | |||
return true; | |||
}); | |||
return result; | |||
} | |||
//============================================================================== | |||
struct VST3ComponentHolder | |||
{ | |||
@@ -1802,6 +1925,8 @@ struct VST3ComponentHolder | |||
totalNumInputChannels, | |||
totalNumOutputChannels); | |||
description.hasARAExtension = hasARAExtension (factory, description.name); | |||
return; | |||
} | |||
@@ -2082,18 +2207,6 @@ public: | |||
void setValue (float newValue) override | |||
{ | |||
pluginInstance.cachedParamValues.set (vstParamIndex, newValue); | |||
pluginInstance.parameterDispatcher.push (vstParamIndex, newValue); | |||
} | |||
/* If the editor set the value, there's no need to notify it that the parameter | |||
value changed. Instead, we set the cachedValue (which will be read by the | |||
processor during the next processBlock) and notify listeners that the parameter | |||
has changed. | |||
*/ | |||
void setValueFromEditor (float newValue) | |||
{ | |||
pluginInstance.cachedParamValues.set (vstParamIndex, newValue); | |||
sendValueChangedMessageToListeners (newValue); | |||
} | |||
/* If we're syncing the editor to the processor, the processor won't need to | |||
@@ -2292,7 +2405,8 @@ public: | |||
void getExtensions (ExtensionsVisitor& visitor) const override | |||
{ | |||
struct Extensions : public ExtensionsVisitor::VST3Client | |||
struct Extensions : public ExtensionsVisitor::VST3Client, | |||
public ExtensionsVisitor::ARAClient | |||
{ | |||
explicit Extensions (const VST3PluginInstance* instanceIn) : instance (instanceIn) {} | |||
@@ -2305,10 +2419,21 @@ public: | |||
return instance->setStateFromPresetFile (rawData); | |||
} | |||
void createARAFactoryAsync (std::function<void (ARAFactoryWrapper)> cb) const noexcept override | |||
{ | |||
cb (ARAFactoryWrapper { ::juce::getARAFactory (*(instance->holder->module)) }); | |||
} | |||
const VST3PluginInstance* instance = nullptr; | |||
}; | |||
visitor.visitVST3Client (Extensions { this }); | |||
Extensions extensions { this }; | |||
visitor.visitVST3Client (extensions); | |||
if (::juce::getARAFactory (*(holder->module))) | |||
{ | |||
visitor.visitARAClient (extensions); | |||
} | |||
} | |||
void* getPlatformSpecificData() override { return holder->component; } | |||
@@ -2559,6 +2684,11 @@ public: | |||
inputParameterChanges->set (cachedParamValues.getParamID (index), value); | |||
}); | |||
inputParameterChanges->forEach ([&] (Steinberg::int32 index, float value) | |||
{ | |||
parameterDispatcher.push (index, value); | |||
}); | |||
processor->process (data); | |||
outputParameterChanges->forEach ([&] (Steinberg::int32 index, float value) | |||
@@ -3024,7 +3154,9 @@ private: | |||
{ | |||
Steinberg::MemoryStream stream; | |||
if (object->getState (&stream) == kResultTrue) | |||
const auto result = object->getState (&stream); | |||
if (result == kResultTrue) | |||
{ | |||
MemoryBlock info (stream.getData(), (size_t) stream.getSize()); | |||
head.createNewChildElement (identifier)->addTextElement (info.toBase64Encoding()); | |||
@@ -3112,7 +3244,7 @@ private: | |||
if ((paramInfo.flags & Vst::ParameterInfo::kIsBypass) != 0) | |||
bypassParam = param; | |||
std::function<AudioProcessorParameterGroup*(Vst::UnitID)> findOrCreateGroup; | |||
std::function<AudioProcessorParameterGroup* (Vst::UnitID)> findOrCreateGroup; | |||
findOrCreateGroup = [&groupMap, &infoMap, &findOrCreateGroup] (Vst::UnitID groupID) | |||
{ | |||
auto existingGroup = groupMap.find (groupID); | |||
@@ -3322,8 +3454,12 @@ private: | |||
{ | |||
MidiEventList::hostToPluginEventList (*midiInputs, | |||
midiBuffer, | |||
destination.inputParameterChanges, | |||
storedMidiMapping); | |||
storedMidiMapping, | |||
[this] (const auto controlID, const auto paramValue) | |||
{ | |||
if (auto* param = this->getParameterForID (controlID)) | |||
param->setValueNotifyingHost ((float) paramValue); | |||
}); | |||
} | |||
destination.inputEvents = midiInputs; | |||
@@ -3468,7 +3604,7 @@ tresult VST3HostContext::performEdit (Vst::ParamID paramID, Vst::ParamValue valu | |||
if (auto* param = plugin->getParameterForID (paramID)) | |||
{ | |||
param->setValueFromEditor ((float) valueNormalised); | |||
param->setValueNotifyingHost ((float) valueNormalised); | |||
// did the plug-in already update the parameter internally | |||
if (plugin->editController->getParamNormalized (paramID) != (float) valueNormalised) | |||
@@ -3670,6 +3806,22 @@ void VST3PluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& resul | |||
} | |||
} | |||
void VST3PluginFormat::createARAFactoryAsync (const PluginDescription& description, ARAFactoryCreationCallback callback) | |||
{ | |||
if (! description.hasARAExtension) | |||
{ | |||
jassertfalse; | |||
callback ({ {}, "The provided plugin does not support ARA features" }); | |||
} | |||
File file (description.fileOrIdentifier); | |||
VSTComSmartPtr<IPluginFactory> pluginFactory ( | |||
DLLHandleCache::getInstance()->findOrCreateHandle (file.getFullPathName()).getPluginFactory()); | |||
const auto* pluginName = description.name.toRawUTF8(); | |||
callback ({ ARAFactoryWrapper { ::juce::getARAFactory (pluginFactory, pluginName) }, {} }); | |||
} | |||
void VST3PluginFormat::createPluginInstance (const PluginDescription& description, | |||
double, int, PluginCreationCallback callback) | |||
{ | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -61,6 +68,7 @@ public: | |||
StringArray searchPathsForPlugins (const FileSearchPath&, bool recursive, bool) override; | |||
bool doesPluginStillExist (const PluginDescription&) override; | |||
FileSearchPath getDefaultLocationsToSearch() override; | |||
void createARAFactoryAsync (const PluginDescription&, ARAFactoryCreationCallback callback) override; | |||
private: | |||
//============================================================================== | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1208,10 +1215,6 @@ struct VSTPluginInstance final : public AudioPluginInstance, | |||
wantsMidiMessages = pluginCanDo ("receiveVstMidiEvent") > 0 || isSynthPlugin(); | |||
#if JUCE_MAC && JUCE_SUPPORT_CARBON | |||
usesCocoaNSView = ((unsigned int) pluginCanDo ("hasCockosViewAsConfig") & 0xffff0000ul) == 0xbeef0000ul; | |||
#endif | |||
setLatencySamples (vstEffect->latency); | |||
} | |||
@@ -1949,7 +1952,6 @@ struct VSTPluginInstance final : public AudioPluginInstance, | |||
ModuleHandle::Ptr vstModule; | |||
std::unique_ptr<VSTPluginFormat::ExtraFunctions> extraFunctions; | |||
bool usesCocoaNSView = false; | |||
private: | |||
//============================================================================== | |||
@@ -2719,18 +2721,8 @@ public: | |||
#elif JUCE_MAC | |||
ignoreUnused (recursiveResize, pluginRefusesToResize, alreadyInside); | |||
#if JUCE_SUPPORT_CARBON | |||
if (! plug.usesCocoaNSView) | |||
{ | |||
carbonWrapper.reset (new CarbonWrapperComponent (*this)); | |||
addAndMakeVisible (carbonWrapper.get()); | |||
} | |||
else | |||
#endif | |||
{ | |||
cocoaWrapper.reset (new NSViewComponentWithParent (plugin)); | |||
addAndMakeVisible (cocoaWrapper.get()); | |||
} | |||
cocoaWrapper.reset (new NSViewComponentWithParent (plugin)); | |||
addAndMakeVisible (cocoaWrapper.get()); | |||
#endif | |||
activeVSTWindows.add (this); | |||
@@ -2756,9 +2748,6 @@ public: | |||
closePluginWindow(); | |||
#if JUCE_MAC | |||
#if JUCE_SUPPORT_CARBON | |||
carbonWrapper.reset(); | |||
#endif | |||
cocoaWrapper.reset(); | |||
#endif | |||
@@ -2787,11 +2776,6 @@ public: | |||
setSize (correctedBounds.getWidth(), correctedBounds.getHeight()); | |||
#if JUCE_MAC | |||
#if JUCE_SUPPORT_CARBON | |||
if (carbonWrapper != nullptr) | |||
carbonWrapper->setSize (correctedBounds.getWidth(), correctedBounds.getHeight()); | |||
#endif | |||
if (cocoaWrapper != nullptr) | |||
cocoaWrapper->setSize (correctedBounds.getWidth(), correctedBounds.getHeight()); | |||
#endif | |||
@@ -2807,25 +2791,19 @@ public: | |||
void visibilityChanged() override | |||
{ | |||
if (cocoaWrapper != nullptr) | |||
{ | |||
if (isShowing()) | |||
openPluginWindow ((NSView*) cocoaWrapper->getView()); | |||
else | |||
closePluginWindow(); | |||
} | |||
if (isShowing()) | |||
openPluginWindow ((NSView*) cocoaWrapper->getView()); | |||
else | |||
closePluginWindow(); | |||
} | |||
void childBoundsChanged (Component*) override | |||
{ | |||
if (cocoaWrapper != nullptr) | |||
{ | |||
auto w = cocoaWrapper->getWidth(); | |||
auto h = cocoaWrapper->getHeight(); | |||
auto w = cocoaWrapper->getWidth(); | |||
auto h = cocoaWrapper->getHeight(); | |||
if (w != getWidth() || h != getHeight()) | |||
setSize (w, h); | |||
} | |||
if (w != getWidth() || h != getHeight()) | |||
setSize (w, h); | |||
} | |||
void parentHierarchyChanged() override { visibilityChanged(); } | |||
@@ -3304,86 +3282,6 @@ private: | |||
//============================================================================== | |||
#if JUCE_MAC | |||
#if JUCE_SUPPORT_CARBON | |||
struct CarbonWrapperComponent : public CarbonViewWrapperComponent | |||
{ | |||
CarbonWrapperComponent (VSTPluginWindow& w) : owner (w) | |||
{ | |||
keepPluginWindowWhenHidden = w.shouldAvoidDeletingWindow(); | |||
setRepaintsChildHIViewWhenCreated (w.shouldRepaintCarbonWindowWhenCreated()); | |||
} | |||
~CarbonWrapperComponent() | |||
{ | |||
deleteWindow(); | |||
} | |||
HIViewRef attachView (WindowRef windowRef, HIViewRef /*rootView*/) override | |||
{ | |||
owner.openPluginWindow (windowRef); | |||
return {}; | |||
} | |||
void removeView (HIViewRef) override | |||
{ | |||
if (owner.isOpen) | |||
{ | |||
owner.isOpen = false; | |||
owner.dispatch (Vst2::plugInOpcodeCloseEditor, 0, 0, 0, 0); | |||
owner.dispatch (Vst2::plugInOpcodeSleepEditor, 0, 0, 0, 0); | |||
} | |||
} | |||
bool getEmbeddedViewSize (int& w, int& h) override | |||
{ | |||
Vst2::VstEditorBounds* rect = nullptr; | |||
owner.dispatch (Vst2::plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); | |||
w = rect->rightmost - rect->leftmost; | |||
h = rect->lower - rect->upper; | |||
return true; | |||
} | |||
void handleMouseDown (int x, int y) override | |||
{ | |||
if (! alreadyInside) | |||
{ | |||
alreadyInside = true; | |||
getTopLevelComponent()->toFront (true); | |||
owner.dispatch (Vst2::plugInOpcodeGetMouse, x, y, 0, 0); | |||
alreadyInside = false; | |||
} | |||
else | |||
{ | |||
PostEvent (::mouseDown, 0); | |||
} | |||
} | |||
void handlePaint() override | |||
{ | |||
if (auto* peer = getPeer()) | |||
{ | |||
auto pos = peer->globalToLocal (getScreenPosition()); | |||
Vst2::VstEditorBounds r; | |||
r.leftmost = (int16) pos.getX(); | |||
r.upper = (int16) pos.getY(); | |||
r.rightmost = (int16) (r.leftmost + getWidth()); | |||
r.lower = (int16) (r.upper + getHeight()); | |||
owner.dispatch (Vst2::plugInOpcodeDrawEditor, 0, 0, &r, 0); | |||
} | |||
} | |||
private: | |||
VSTPluginWindow& owner; | |||
bool alreadyInside = false; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CarbonWrapperComponent) | |||
}; | |||
friend struct CarbonWrapperComponent; | |||
std::unique_ptr<CarbonWrapperComponent> carbonWrapper; | |||
#endif | |||
std::unique_ptr<NSViewComponentWithParent> cocoaWrapper; | |||
void resized() override | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -0,0 +1,190 @@ | |||
//************************************************************************************************ | |||
// | |||
// PreSonus Plug-In Extensions | |||
// Written and placed in the PUBLIC DOMAIN by PreSonus Software Ltd. | |||
// | |||
// Filename : ipslcontextinfo.h | |||
// Created by : PreSonus Software Ltd., 08/2013, last updated 11/2016 | |||
// Description : Context Information Interface | |||
// | |||
//************************************************************************************************ | |||
/* | |||
DISCLAIMER: | |||
The PreSonus Plug-In Extensions are host-specific extensions of existing proprietary technologies, | |||
provided to the community on an AS IS basis. They are not part of any official 3rd party SDK and | |||
PreSonus is not affiliated with the owner of the underlying technology in any way. | |||
*/ | |||
//************************************************************************************************ | |||
#ifndef _ipslcontextinfo_h | |||
#define _ipslcontextinfo_h | |||
#include "pluginterfaces/vst/vsttypes.h" | |||
#include "pluginterfaces/base/falignpush.h" | |||
namespace Presonus { | |||
//************************************************************************************************ | |||
// IContextInfoProvider | |||
/** Callback interface to access context information from the host. Implemented by the host | |||
as extension of Steinberg::Vst::IComponentHandler. | |||
The host might not be able to report all available attributes at all times. Please check the | |||
return value of getContextInfoValue() and getContextInfoString(). It's not required to implement | |||
IContextInfoHandler on the plug-in side, but we recommend to do so. The host will then call | |||
notifyContextInfoChange() during initialization to inform the plug-in about the initial state of | |||
the available attributes. | |||
Usage Example: | |||
IComponentHandler* handler; | |||
FUnknownPtr<IContextInfoProvider> contextInfoProvider (handler); | |||
void PLUGIN_API MyEditController::notifyContextInfoChange () | |||
{ | |||
int32 channelIndex = 0; | |||
contextInfoProvider->getContextInfoValue (channelIndex, ContextInfo::kIndex); | |||
TChar channelName[128] = {0}; | |||
contextInfoProvider->getContextInfoString (channelName, 128, ContextInfo::kName); | |||
} | |||
*/ | |||
//************************************************************************************************ | |||
struct IContextInfoProvider: Steinberg::FUnknown | |||
{ | |||
/** Get context information by identifier. */ | |||
virtual Steinberg::tresult PLUGIN_API getContextInfoValue (Steinberg::int32& value, Steinberg::FIDString id) = 0; | |||
/** Get context information by identifier. */ | |||
virtual Steinberg::tresult PLUGIN_API getContextInfoString (Steinberg::Vst::TChar* string, Steinberg::int32 maxCharCount, Steinberg::FIDString id) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IContextInfoProvider, 0x483e61ea, 0x17994494, 0x8199a35a, 0xebb35e3c) | |||
//************************************************************************************************ | |||
// IContextInfoProvider2 | |||
/** Extension to IContextInfoProvider enabling the plug-in to modify host context information. | |||
Values like volume or pan support both, numeric and string representation for get and set.*/ | |||
//************************************************************************************************ | |||
struct IContextInfoProvider2: IContextInfoProvider | |||
{ | |||
using IContextInfoProvider::getContextInfoValue; | |||
/** Get context information by identifier (floating-point). */ | |||
virtual Steinberg::tresult PLUGIN_API getContextInfoValue (double& value, Steinberg::FIDString id) = 0; | |||
/** Set context information by identifier (floating-point). */ | |||
virtual Steinberg::tresult PLUGIN_API setContextInfoValue (Steinberg::FIDString id, double value) = 0; | |||
/** Set context information by identifier (integer). */ | |||
virtual Steinberg::tresult PLUGIN_API setContextInfoValue (Steinberg::FIDString id, Steinberg::int32 value) = 0; | |||
/** Set context information by identifier (string). */ | |||
virtual Steinberg::tresult PLUGIN_API setContextInfoString (Steinberg::FIDString id, Steinberg::Vst::TChar* string) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IContextInfoProvider2, 0x61e45968, 0x3d364f39, 0xb15e1733, 0x4944172b) | |||
//************************************************************************************************ | |||
// IContextInfoHandler | |||
/** Notification interface for context information changes. Implemented by the plug-in as extension of | |||
Steinberg::Vst::IEditController. */ | |||
//************************************************************************************************ | |||
struct IContextInfoHandler: Steinberg::FUnknown | |||
{ | |||
/** Called by the host if context information has changed. */ | |||
virtual void PLUGIN_API notifyContextInfoChange () = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IContextInfoHandler, 0xc3b17bc0, 0x2c174494, 0x80293402, 0xfbc4bbf8) | |||
//************************************************************************************************ | |||
// IContextInfoHandler2 | |||
/** Replacement of IContextInfoHandler passing additional information about what changed on the host-side. | |||
This interface will be preferred if implemented by the plug-in. It is required to | |||
receive certain notifications like volume, pan, etc. */ | |||
//************************************************************************************************ | |||
struct IContextInfoHandler2: Steinberg::FUnknown | |||
{ | |||
/** Called by the host if context information has changed. | |||
The identifier (id) is empty for the inital update. */ | |||
virtual void PLUGIN_API notifyContextInfoChange (Steinberg::FIDString id) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IContextInfoHandler2, 0x31e29a7a, 0xe55043ad, 0x8b95b9b8, 0xda1fbe1e) | |||
//************************************************************************************************ | |||
// Context Information Attributes | |||
//************************************************************************************************ | |||
namespace ContextInfo | |||
{ | |||
/** Channel types. */ | |||
enum ChannelType | |||
{ | |||
kTrack = 0, ///< audio track | |||
kBus, ///< audio bus | |||
kFX, ///< FX channel | |||
kSynth, ///< output of virtual instrument | |||
kIn, ///< input from audio driver | |||
kOut ///< output to audio driver (main or sub-out) | |||
}; | |||
/** Channel index mode. */ | |||
enum ChannelIndexMode | |||
{ | |||
kFlatIndex = 0, ///< channel indices are contiguous (example: track 1, track 2, bus 3, bus 4) | |||
kPerTypeIndex ///< channel indices restarts at zero for each type (example: track 1, track 2, bus 1, bus 2) | |||
}; | |||
// per instance | |||
const Steinberg::FIDString kID = "id"; ///< (R) channel identifier, use to compare identity (string) | |||
const Steinberg::FIDString kName = "name"; ///< (R/W) channel name, can be displayed to the user (string) | |||
const Steinberg::FIDString kType = "type"; ///< (R) channel type (int32, see ChannelType enumeration) | |||
const Steinberg::FIDString kMain = "main"; ///< (R) channel is main output (int32, 0: false, 1: true) | |||
const Steinberg::FIDString kIndex = "index"; ///< (R) channel index (int32, starts at zero) | |||
const Steinberg::FIDString kColor = "color"; ///< (R/W) channel color (int32: RGBA) | |||
const Steinberg::FIDString kVisibility = "visibility"; ///< (R) channel visibility (int32, 0: false, 1: true) | |||
const Steinberg::FIDString kSelected = "selected"; ///< (R/W) selection state, channel is selected exlusively and scrolled into view on write (int32, 0: false, 1: true) | |||
const Steinberg::FIDString kMultiSelect = "multiselect"; ///< (W) select channel without unselecting others (int32, 0: false, 1: true) | |||
const Steinberg::FIDString kFocused = "focused"; ///< (R) focus for user input when multiple channels are selected (int32, 0: false, 1: true) | |||
const Steinberg::FIDString kRegionName = "regionName"; ///< (R) name of region/event for region/event-based effects (string) | |||
const Steinberg::FIDString kRegionSelected = "regionSelected"; ///< (R) selection state of region/event for region/event-based effects (int32, 0: false, 1: true) | |||
// per instance (requires IContextInfoHandler2 on plug-in side) | |||
const Steinberg::FIDString kVolume = "volume"; ///< (R/W) volume factor [float, 0. = -oo dB, 1. = 0dB, etc.], also available as string | |||
const Steinberg::FIDString kMaxVolume = "maxVolume"; ///< (R) maximum volume factor [float, 1. = 0dB], also available as string | |||
const Steinberg::FIDString kPan = "pan"; ///< (R/W) stereo panning [float, < 0.5 = (L), 0.5 = (C), > 0.5 = (R)], also available as string | |||
const Steinberg::FIDString kMute = "mute"; ///< (R/W) mute (int32, 0: false, 1: true) | |||
const Steinberg::FIDString kSolo = "solo"; ///< (R/W) solo (int32, 0: false, 1: true) | |||
const Steinberg::FIDString kSendCount = "sendcount"; ///< (R) send count [int] | |||
const Steinberg::FIDString kSendLevel = "sendlevel"; ///< (R/W) send level factor, index is appended to id (e.g. "sendlevel0" for first), also available as string | |||
const Steinberg::FIDString kMaxSendLevel = "maxSendlevel"; ///< (R) maximum send level factor, also available as string | |||
// global | |||
const Steinberg::FIDString kActiveDocumentID = "activeDocumentID"; ///< (R) active document identifier, use to get identity of the active document (string) | |||
const Steinberg::FIDString kDocumentID = "documentID"; ///< (R) document identifier, use to compare identity (string) | |||
const Steinberg::FIDString kDocumentName = "documentName"; ///< (R) document name, can be displayed to user (string) | |||
const Steinberg::FIDString kDocumentFolder = "documentFolder"; ///< (R) document folder (string) | |||
const Steinberg::FIDString kAudioFolder = "audioFolder"; ///< (R) folder for audio files (string) | |||
const Steinberg::FIDString kIndexMode = "indexMode"; ///< (R) channel index mode (default is flat, see ChannelIndexMode enumeration) | |||
} | |||
} // namespace Presonus | |||
#include "pluginterfaces/base/falignpop.h" | |||
#endif // _ipslcontextinfo_h |
@@ -0,0 +1,108 @@ | |||
//************************************************************************************************ | |||
// | |||
// PreSonus Plug-In Extensions | |||
// Written and placed in the PUBLIC DOMAIN by PreSonus Software Ltd. | |||
// | |||
// Filename : ipsleditcontroller.h | |||
// Created by : PreSonus Software Ltd., 02/2017, last updated 10/2017 | |||
// Description : Plug-in Edit Controller Extension Interface | |||
// | |||
//************************************************************************************************ | |||
/* | |||
DISCLAIMER: | |||
The PreSonus Plug-In Extensions are host-specific extensions of existing proprietary technologies, | |||
provided to the community on an AS IS basis. They are not part of any official 3rd party SDK and | |||
PreSonus is not affiliated with the owner of the underlying technology in any way. | |||
*/ | |||
//************************************************************************************************ | |||
#ifndef _ipsleditcontroller_h | |||
#define _ipsleditcontroller_h | |||
#include "pluginterfaces/vst/vsttypes.h" | |||
#include "pluginterfaces/base/funknown.h" | |||
#include "pluginterfaces/base/falignpush.h" | |||
namespace Steinberg { | |||
namespace Vst { | |||
class IEditController; }} | |||
namespace Presonus { | |||
/** Parameter extra flags. Used with IEditControllerExtra. */ | |||
enum ParamExtraFlags | |||
{ | |||
kParamFlagMicroEdit = 1<<0 ///< parameter should be displayed in host micro view | |||
}; | |||
/** Automation mode. Used with IEditControllerExtra. */ | |||
enum AutomationMode | |||
{ | |||
kAutomationNone = 0, ///< no automation data available | |||
kAutomationOff, ///< data available, but mode is set to off | |||
kAutomationRead, ///< data + read mode | |||
kAutomationTouch, ///< data + touch mode | |||
kAutomationLatch, ///< data + latch mode | |||
kAutomationWrite ///< data + write mode | |||
}; | |||
/** Slave mode. Used with ISlaveControllerHandler. */ | |||
enum SlaveMode | |||
{ | |||
kSlaveModeNormal, ///< plug-in used in different location following given master | |||
kSlaveModeLowLatencyClone ///< plug-in used as hidden slave for low latency processing following given master | |||
}; | |||
//************************************************************************************************ | |||
// IEditControllerExtra | |||
/** Extension to Steinberg::Vst::IEditController with additonal flags and notifications | |||
not available in the standard edit controller interface. */ | |||
//************************************************************************************************ | |||
struct IEditControllerExtra: Steinberg::FUnknown | |||
{ | |||
/** Get extra flags for given parameter (see ParamExtraFlags). */ | |||
virtual Steinberg::int32 PLUGIN_API getParamExtraFlags (Steinberg::Vst::ParamID id) = 0; | |||
/** Set automation mode for given parameter (see AutomationMode). */ | |||
virtual Steinberg::tresult PLUGIN_API setParamAutomationMode (Steinberg::Vst::ParamID id, Steinberg::int32 automationMode) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IEditControllerExtra, 0x50553fd9, 0x1d2c4c24, 0xb410f484, 0xc5fb9f3f) | |||
//************************************************************************************************ | |||
// ISlaveControllerHandler | |||
/** Extension to Steinberg::Vst::IEditController used to notify the plug-in about slave instances. | |||
The host might decide to use "cloned" (slave) instances in various scenarios, e.g. to process | |||
audio paths with different latencies simultaneously or to synchronize grouped plug-in instances | |||
between multiple mixer channels - see SlaveMode. In this case multiple plug-in instances are active | |||
at the same time even though it looks like one to the user, i.e. only the editor of the master | |||
instance is visible and can be used to change parameters. The edit controller implementation has | |||
to synchronize parameter changes between instances that aren't visible to the host internally. | |||
*/ | |||
//************************************************************************************************ | |||
struct ISlaveControllerHandler: Steinberg::FUnknown | |||
{ | |||
/** Add slave edit controller. Implementation must sync non-automatable parameters between | |||
this instance (master) and given slave instance internally, i.e. when the master (this) | |||
changes update all connected slaves. | |||
*/ | |||
virtual Steinberg::tresult PLUGIN_API addSlave (Steinberg::Vst::IEditController* slave, Steinberg::int32 slaveMode) = 0; | |||
/** Remove slave edit controller. */ | |||
virtual Steinberg::tresult PLUGIN_API removeSlave (Steinberg::Vst::IEditController* slave) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (ISlaveControllerHandler, 0xd93894bd, 0x67454c29, 0x977ae2f5, 0xdb380434) | |||
} // namespace Presonus | |||
#include "pluginterfaces/base/falignpop.h" | |||
#endif // _ipsleditcontroller_h |
@@ -0,0 +1,53 @@ | |||
//************************************************************************************************ | |||
// | |||
// PreSonus Plug-In Extensions | |||
// Written and placed in the PUBLIC DOMAIN by PreSonus Software Ltd. | |||
// | |||
// Filename : ipslgainreduction.h | |||
// Created by : PreSonus Software Ltd., 03/2015 | |||
// Description : Plug-in Gain Reduction Interface | |||
// | |||
//************************************************************************************************ | |||
/* | |||
DISCLAIMER: | |||
The PreSonus Plug-In Extensions are host-specific extensions of existing proprietary technologies, | |||
provided to the community on an AS IS basis. They are not part of any official 3rd party SDK and | |||
PreSonus is not affiliated with the owner of the underlying technology in any way. | |||
*/ | |||
//************************************************************************************************ | |||
#ifndef _ipslgainreduction_h | |||
#define _ipslgainreduction_h | |||
#include "pluginterfaces/base/funknown.h" | |||
#include "pluginterfaces/base/falignpush.h" | |||
namespace Presonus { | |||
//************************************************************************************************ | |||
// IGainReductionInfo | |||
/** Interface to report gain reduction imposed to the audio signal by the plug-in to the | |||
host for display in the UI. Implemented by the VST3 edit controller class. | |||
*/ | |||
//************************************************************************************************ | |||
struct IGainReductionInfo: Steinberg::FUnknown | |||
{ | |||
/** Get current gain reduction for display. The returned value in dB is either 0.0 (no reduction) | |||
or negative. The host calls this function periodically while the plug-in is active. | |||
The value is used AS IS for UI display purposes, without imposing additional ballistics or | |||
presentation latency compensation. Be sure to return zero if processing is bypassed internally. | |||
For multiple reduction stages, please report the sum in dB here. | |||
*/ | |||
virtual double PLUGIN_API getGainReductionValueInDb () = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IGainReductionInfo, 0x8e3c292c, 0x95924f9d, 0xb2590b1e, 0x100e4198) | |||
} // namespace Presonus | |||
#include "pluginterfaces/base/falignpop.h" | |||
#endif // _ipslgainreduction_h |
@@ -0,0 +1,121 @@ | |||
//************************************************************************************************ | |||
// | |||
// PreSonus Plug-In Extensions | |||
// Written and placed in the PUBLIC DOMAIN by PreSonus Software Ltd. | |||
// | |||
// Filename : ipslhostcommands.h | |||
// Created by : PreSonus Software Ltd., 11/2009 | |||
// Description : Host Command Interface | |||
// | |||
//************************************************************************************************ | |||
/* | |||
DISCLAIMER: | |||
The PreSonus Plug-In Extensions are host-specific extensions of existing proprietary technologies, | |||
provided to the community on an AS IS basis. They are not part of any official 3rd party SDK and | |||
PreSonus is not affiliated with the owner of the underlying technology in any way. | |||
*/ | |||
//************************************************************************************************ | |||
#ifndef _ipslhostcommands_h | |||
#define _ipslhostcommands_h | |||
#include "pluginterfaces/vst/vsttypes.h" | |||
#include "pluginterfaces/base/funknown.h" | |||
#include "pluginterfaces/base/falignpush.h" | |||
namespace Steinberg { | |||
class IPlugView; } | |||
namespace Presonus { | |||
struct ICommandList; | |||
//************************************************************************************************ | |||
// IHostCommandHandler | |||
/** Callback interface to access host-specific parameter commands to be integrated | |||
into a context menu inside the plug-in editor. Implemented as extension of | |||
Steinberg::Vst::IComponentHandler. | |||
Please note that the intention of this set of interfaces is not to allow a generic menu | |||
implementation. This is the responsibility of a GUI toolkit. It basically provides | |||
a way to enumerate and execute commands anonymously, i.e. the plug-in does not have to | |||
know the exact sematics of the commands and the host does not break the consistency of | |||
the plug-in GUI. | |||
Usage Example: | |||
IComponentHandler* handler; | |||
FUnknownPtr<IHostCommandHandler> commandHandler (handler); | |||
if(commandHandler) | |||
if(ICommandList* commandList = commandHandler->createParamCommands (kMyParamId)) | |||
{ | |||
FReleaser commandListReleaser (commandList); | |||
commandHandler->popupCommandMenu (commandList, xPos, yPos); | |||
} | |||
*/ | |||
//************************************************************************************************ | |||
struct IHostCommandHandler: Steinberg::FUnknown | |||
{ | |||
/** Create list of currently available host commands for given parameter. | |||
The command list has a short lifecycle, it is recreated whenever | |||
a context menu should appear. The returned pointer can be null, otherwise | |||
it has to be released. */ | |||
virtual ICommandList* PLUGIN_API createParamCommands (Steinberg::Vst::ParamID tag) = 0; | |||
/** Helper to popup a command menu at given position. | |||
Coordinates are relative to view or in screen coordintes if view is null. | |||
Can be used for testing purpose, if the plug-in does not have its own context menu implementation | |||
or if it wants to use the look & feel of the host menu. This method is not supposed | |||
to support command lists implemented by the plug-in. */ | |||
virtual Steinberg::tresult PLUGIN_API popupCommandMenu (ICommandList* commandList, Steinberg::int32 xPos, Steinberg::int32 yPos, Steinberg::IPlugView* view = 0) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IHostCommandHandler, 0xF92032CD, 0x7A84407C, 0xABE6F863, 0x058EA6C2) | |||
//************************************************************************************************ | |||
// CommandInfo | |||
/** Describes a single command. */ | |||
//************************************************************************************************ | |||
struct CommandInfo | |||
{ | |||
Steinberg::Vst::String128 title; ///< command title (possibly localized into active host language) | |||
Steinberg::int32 flags; ///< command flags | |||
enum CommandFlags | |||
{ | |||
kCanExecute = 1<<0, ///< used to display command enabled/disabled | |||
kIsSeparator = 1<<1, ///< not a command, it's a separator | |||
kIsChecked = 1<<2 ///< used to display command with a check mark | |||
}; | |||
}; | |||
//************************************************************************************************ | |||
// ICommandList | |||
/** Describes a list of commands. */ | |||
//************************************************************************************************ | |||
struct ICommandList: Steinberg::FUnknown | |||
{ | |||
/** Returns the number of commands. */ | |||
virtual Steinberg::int32 PLUGIN_API getCommandCount () = 0; | |||
/** Get command information for a given index. */ | |||
virtual Steinberg::tresult PLUGIN_API getCommandInfo (Steinberg::int32 index, CommandInfo& info) = 0; | |||
/** Execute command at given index. */ | |||
virtual Steinberg::tresult PLUGIN_API executeCommand (Steinberg::int32 index) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (ICommandList, 0xC5A687DB, 0x82F344E9, 0xB378254A, 0x47C4D712) | |||
} // namespace Presonus | |||
#include "pluginterfaces/base/falignpop.h" | |||
#endif // _ipslhostcommands_h |
@@ -0,0 +1,53 @@ | |||
//************************************************************************************************ | |||
// | |||
// PreSonus Plug-In Extensions | |||
// Written and placed in the PUBLIC DOMAIN by PreSonus Software Ltd. | |||
// | |||
// Filename : ipslviewembedding.h | |||
// Created by : PreSonus Software Ltd., 05/2012 | |||
// Description : Plug-in View Embedding Interface | |||
// | |||
//************************************************************************************************ | |||
/* | |||
DISCLAIMER: | |||
The PreSonus Plug-In Extensions are host-specific extensions of existing proprietary technologies, | |||
provided to the community on an AS IS basis. They are not part of any official 3rd party SDK and | |||
PreSonus is not affiliated with the owner of the underlying technology in any way. | |||
*/ | |||
//************************************************************************************************ | |||
#ifndef _ipslviewembedding_h | |||
#define _ipslviewembedding_h | |||
#include "pluginterfaces/base/funknown.h" | |||
#include "pluginterfaces/base/falignpush.h" | |||
namespace Steinberg { | |||
class IPlugView; } | |||
namespace Presonus { | |||
//************************************************************************************************ | |||
// IPlugInViewEmbedding | |||
/** Support for plug-in view embedding, to be implemented by the VST3 controller class. */ | |||
//************************************************************************************************ | |||
class IPlugInViewEmbedding: public Steinberg::FUnknown | |||
{ | |||
public: | |||
/** Check if view embedding is supported. */ | |||
virtual Steinberg::TBool PLUGIN_API isViewEmbeddingSupported () = 0; | |||
/** Inform plug-in that its view will be embedded. */ | |||
virtual Steinberg::tresult PLUGIN_API setViewIsEmbedded (Steinberg::IPlugView* view, Steinberg::TBool embedded) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IPlugInViewEmbedding, 0xda57e6d1, 0x1f3242d1, 0xad9c1a82, 0xfdb95695) | |||
} // namespace Presonus | |||
#include "pluginterfaces/base/falignpop.h" | |||
#endif // _ipslviewembedding_h |
@@ -0,0 +1,67 @@ | |||
//************************************************************************************************ | |||
// | |||
// PreSonus Plug-In Extensions | |||
// Written and placed in the PUBLIC DOMAIN by PreSonus Software Ltd. | |||
// | |||
// Filename : ipslviewscaling.h | |||
// Created by : PreSonus Software Ltd., 03/2015 | |||
// Description : Plug-in View DPI Scaling Interface | |||
// | |||
//************************************************************************************************ | |||
/* | |||
DISCLAIMER: | |||
The PreSonus Plug-In Extensions are host-specific extensions of existing proprietary technologies, | |||
provided to the community on an AS IS basis. They are not part of any official 3rd party SDK and | |||
PreSonus is not affiliated with the owner of the underlying technology in any way. | |||
*/ | |||
//************************************************************************************************ | |||
#ifndef _ipslviewscaling_h | |||
#define _ipslviewscaling_h | |||
#include "pluginterfaces/base/funknown.h" | |||
#include "pluginterfaces/base/falignpush.h" | |||
namespace Presonus { | |||
//************************************************************************************************ | |||
// IPlugInViewScaling | |||
/** Support for plug-in view content scaling, to be implemented by the VST3 IPlugView class. | |||
On Windows, if a process is "DPI-aware" and the system DPI setting is different from the default | |||
value of 96 DPI, the application is responsible to scale the contents of its windows accordingly, | |||
including child windows provided by 3rd party plug-ins. | |||
This interface is used by the host to inform the plug-in about the current scaling factor. | |||
The scaling factor is used to convert user space coordinates aka DIPs (device-independent pixels) | |||
to physical pixels on screen. | |||
The plug-in has to be prepared to deal with the following scaling factors: | |||
96 DPI = 100% scaling (factor = 1.0) | |||
120 DPI = 125% scaling (factor = 1.25) | |||
144 DPI = 150% scaling (factor = 1.5) | |||
192 DPI = 200% scaling (factor = 2.0) | |||
On Windows 8.1 or later DPI settings are per monitor. The scaling factor for a window can change | |||
when it is moved between screens. | |||
*/ | |||
//************************************************************************************************ | |||
struct IPlugInViewScaling: Steinberg::FUnknown | |||
{ | |||
/** Inform the view about the current content scaling factor. The scaling factor can change | |||
if the window is moved between screens. | |||
*/ | |||
virtual Steinberg::tresult PLUGIN_API setContentScaleFactor (float factor) = 0; | |||
static const Steinberg::FUID iid; | |||
}; | |||
DECLARE_CLASS_IID (IPlugInViewScaling, 0x65ed9690, 0x8ac44525, 0x8aadef7a, 0x72ea703f) | |||
} // namespace Presonus | |||
#include "pluginterfaces/base/falignpop.h" | |||
#endif // _ipslviewscaling_h |
@@ -0,0 +1,57 @@ | |||
//************************************************************************************************ | |||
// | |||
// PreSonus Plug-In Extensions | |||
// Written and placed in the PUBLIC DOMAIN by PreSonus Software Ltd. | |||
// | |||
// Filename : pslauextensions.h | |||
// Created by : PreSonus Software Ltd., 08/2017, last updated 10/2017 | |||
// Description : PreSonus-specific AU API Extensions | |||
// | |||
//************************************************************************************************ | |||
/* | |||
DISCLAIMER: | |||
The PreSonus Plug-In Extensions are host-specific extensions of existing proprietary technologies, | |||
provided to the community on an AS IS basis. They are not part of any official 3rd party SDK and | |||
PreSonus is not affiliated with the owner of the underlying technology in any way. | |||
*/ | |||
//************************************************************************************************ | |||
#ifndef _pslauextensions_h | |||
#define _pslauextensions_h | |||
#ifdef __cplusplus | |||
namespace Presonus { | |||
#endif | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Property IDs | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
/** This AU property in the global scope is of type CFArrayRef and is writable by the host. | |||
The elements of the array are of type CFDataRef which encapsulate SlaveMode structures. | |||
For more details, please check the documentation of Presonus::ISlaveControllerHandler. */ | |||
static const AudioUnitPropertyID kSlaveEffectsPropID = 0x50534C01; | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Data types | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
enum SlaveMode | |||
{ | |||
kSlaveModeNormal, ///< plug-in used in different location following given master | |||
kSlaveModeLowLatencyClone ///< plug-in used as hidden slave for low latency processing following given master | |||
}; | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
struct SlaveEffect | |||
{ | |||
AudioUnit unit; ///< Audio Unit reference | |||
SInt32 mode; ///< SlaveMode | |||
}; | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif // _pslauextensions_h |
@@ -0,0 +1,111 @@ | |||
//************************************************************************************************ | |||
// | |||
// PreSonus Plug-In Extensions | |||
// Written and placed in the PUBLIC DOMAIN by PreSonus Software Ltd. | |||
// | |||
// Filename : pslvst2extensions.h | |||
// Created by : PreSonus Software Ltd., 05/2012, last updated 08/2017 | |||
// Description : PreSonus-specific VST2 API Extensions | |||
// | |||
//************************************************************************************************ | |||
/* | |||
DISCLAIMER: | |||
The PreSonus Plug-In Extensions are host-specific extensions of existing proprietary technologies, | |||
provided to the community on an AS IS basis. They are not part of any official 3rd party SDK and | |||
PreSonus is not affiliated with the owner of the underlying technology in any way. | |||
*/ | |||
//************************************************************************************************ | |||
#ifndef _pslvst2extensions_h | |||
#define _pslvst2extensions_h | |||
namespace Presonus { | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// CanDo Strings | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
/** Identifiers to be passed to VST2's canDo() method. */ | |||
namespace PlugCanDos | |||
{ | |||
/** Check if view can be resized by the host. */ | |||
static const char* canDoViewResize = "supportsViewResize"; | |||
/** Check if view can be embedded by the host. */ | |||
static const char* canDoViewEmbedding = "supportsViewEmbedding"; | |||
/** Check if view scaling for high-DPI is supported by the plug-in. */ | |||
static const char* canDoViewDpiScaling = "supportsViewDpiScaling"; | |||
/** Check if gain reduction reporting is supported by the plug-in. */ | |||
static const char* canDoGainReductionInfo = "supportsGainReductionInfo"; | |||
/** Check if slave effects are supported by plug-in. */ | |||
static const char* canDoSlaveEffects = "supportsSlaveEffects"; | |||
} | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Opcodes | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
/** Vendor-specific opcodes a VST2 plug-in can implement to add non-standard features like | |||
embedding its views as subview into the host, resizing from the host, high-DPI scaling, etc. | |||
Embedding corresponds to the Presonus::IPlugInViewEmbedding VST3 extended interface. | |||
Resizing works like VST3's checkSizeConstraint() and onSize() methods, VST3's canResize() | |||
is defined via canDoViewResize. | |||
For "DPI-aware" host applications on the Windows platform a similar mimic to the | |||
Presonus::IPlugInViewScaling VST3 extended interface is defined here. | |||
Gain reduction reporting corresponds to the Presonus::IGainReductionInfo VST3 interface. | |||
Slave effect handling corresponds to the Presonus::ISlaveControllerHandler VST3 interface. | |||
*/ | |||
enum Opcodes | |||
{ | |||
/** PreSonus vendor ID - distinguishes our calls from other VST2 extensions. | |||
Pass this vendor ID as "index" (aka "lArg1") parameter for vendor specific calls. */ | |||
kVendorID = 'PreS', | |||
/** The host can suggest a new editor size, and the plug-in can modify the suggested | |||
size to a suitable value if it cannot resize to the given values. | |||
The ptrArg is a ERect* to the input/output rect. This differs from the ERect** | |||
used by effEditGetRect, because here the rect is owned by the host, not the plug-in. | |||
The result is 0 on failure, 1 on success. */ | |||
kEffEditCheckSizeConstraints = 'AeCc', | |||
/** The host can set a new size after negotiating the size via the above | |||
kEffEditCheckSizeConstraints, triggering the actual resizing. | |||
The ptrArg is a ERect* to the input/output rect. This differs from the ERect** | |||
used by effEditGetRect, because here the rect is owned by the host, not the plug-in. | |||
The result is 0 on failure, 1 on success. */ | |||
kEffEditSetRect = 'AeSr', | |||
/** When the view is embedded, it may need to adjust its UI, e.g. by suppressing | |||
its built-in resizing facility because this is then controlled by the host. | |||
The ptrArg is a VstInt32*, pointing to 0 to disable or to 1 to enable embedding. | |||
Per default, embedding is disabled until the host calls this to indicate otherwise. */ | |||
kEffEditSetEmbedded = 'AeEm', | |||
/** Inform the view about the current content scaling factor. The factor is passed in the opt argument. | |||
For more details, please check the documentation of Presonus::IPlugInViewScaling. */ | |||
kEffEditSetContentScaleFactor = 'AeCs', | |||
/** Get current gain reduction for display. The ptrArg is a float* to be set to the dB value. | |||
For more details, please check the documentation of Presonus::IGainReductionInfo. */ | |||
kEffGetGainReductionValueInDb = 'GRdB', | |||
/** Add slave effect. The ptrArg is a pointer to the slave AEffect, the 'opt' float transmits the mode (see enum SlaveMode). | |||
For more details, please check the documentation of Presonus::ISlaveControllerHandler. */ | |||
kEffAddSlave = 'AdSl', | |||
/** Remove slave effect. The ptrArg is a pointer to the slave AEffect. | |||
For more details, please check the documentation of Presonus::ISlaveControllerHandler. */ | |||
kEffRemoveSlave = 'RmSl' | |||
}; | |||
} // namespace Presonus | |||
#endif // _pslvst2extensions_h |
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -27,7 +34,9 @@ | |||
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 | |||
#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 | |||
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 | |||
#endif | |||
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1 | |||
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1 | |||
@@ -36,14 +45,7 @@ | |||
#include <juce_core/containers/juce_Optional.h> | |||
//============================================================================== | |||
#if JUCE_MAC | |||
#if JUCE_SUPPORT_CARBON && (JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_AU) | |||
#include <Carbon/Carbon.h> | |||
#include <juce_gui_extra/native/juce_mac_CarbonViewWrapperComponent.h> | |||
#endif | |||
#endif | |||
#if (JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_VST3) && (JUCE_LINUX || JUCE_BSD) | |||
#if (JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_VST3) && (JUCE_LINUX || JUCE_BSD) && ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
#include <X11/Xlib.h> | |||
#include <X11/Xutil.h> | |||
#include <sys/utsname.h> | |||
@@ -202,17 +204,23 @@ private: | |||
#include "format_types/juce_LegacyAudioParameter.cpp" | |||
#include "processors/juce_AudioProcessor.cpp" | |||
#include "processors/juce_AudioPluginInstance.cpp" | |||
#include "processors/juce_AudioProcessorEditor.cpp" | |||
#include "processors/juce_AudioProcessorGraph.cpp" | |||
#include "processors/juce_GenericAudioProcessorEditor.cpp" | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
#include "processors/juce_AudioProcessorEditor.cpp" | |||
#include "processors/juce_GenericAudioProcessorEditor.cpp" | |||
#endif | |||
#include "processors/juce_PluginDescription.cpp" | |||
#include "format_types/juce_ARACommon.cpp" | |||
#include "format_types/juce_LADSPAPluginFormat.cpp" | |||
#include "format_types/juce_VSTPluginFormat.cpp" | |||
#include "format_types/juce_VST3PluginFormat.cpp" | |||
#include "format_types/juce_AudioUnitPluginFormat.mm" | |||
#include "scanning/juce_KnownPluginList.cpp" | |||
#include "scanning/juce_PluginDirectoryScanner.cpp" | |||
#include "scanning/juce_PluginListComponent.cpp" | |||
#include "format_types/juce_ARAHosting.cpp" | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
#include "scanning/juce_KnownPluginList.cpp" | |||
#include "scanning/juce_PluginDirectoryScanner.cpp" | |||
#include "scanning/juce_PluginListComponent.cpp" | |||
#endif | |||
#include "processors/juce_AudioProcessorParameterGroup.cpp" | |||
#include "utilities/juce_AudioProcessorParameterWithID.cpp" | |||
#include "utilities/juce_RangedAudioParameter.cpp" | |||
@@ -220,10 +228,13 @@ private: | |||
#include "utilities/juce_AudioParameterInt.cpp" | |||
#include "utilities/juce_AudioParameterBool.cpp" | |||
#include "utilities/juce_AudioParameterChoice.cpp" | |||
#include "utilities/juce_ParameterAttachments.cpp" | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
#include "utilities/juce_ParameterAttachments.cpp" | |||
#endif | |||
#include "utilities/juce_AudioProcessorValueTreeState.cpp" | |||
#include "utilities/juce_PluginHostType.cpp" | |||
#include "utilities/juce_NativeScaleFactorNotifier.cpp" | |||
#include "utilities/ARA/juce_ARA_utils.cpp" | |||
#include "format_types/juce_LV2PluginFormat.cpp" | |||
@@ -231,3 +242,8 @@ private: | |||
#include "format_types/juce_VST3PluginFormat_test.cpp" | |||
#include "format_types/juce_LV2PluginFormat_test.cpp" | |||
#endif | |||
#if JUCE_AUDIOPROCESSOR_NO_GUI | |||
// commonly used classes in DSP code | |||
namespace juce { Colour::Colour(juce::uint32) noexcept {} } | |||
#endif |
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -94,6 +101,17 @@ | |||
#define JUCE_PLUGINHOST_LV2 0 | |||
#endif | |||
/** Config: JUCE_PLUGINHOST_ARA | |||
Enables the ARA plugin extension hosting classes. You will need to download the ARA SDK and specify the | |||
path to it either in the Projucer, using juce_set_ara_sdk_path() in your CMake project file. | |||
The directory can be obtained by recursively cloning https://github.com/Celemony/ARA_SDK and checking out | |||
the tag releases/2.1.0. | |||
*/ | |||
#ifndef JUCE_PLUGINHOST_ARA | |||
#define JUCE_PLUGINHOST_ARA 0 | |||
#endif | |||
/** Config: JUCE_CUSTOM_VST3_SDK | |||
If enabled, the embedded VST3 SDK in JUCE will not be added to the project and instead you should | |||
add the path to your custom VST3 SDK to the project's header search paths. Most users shouldn't | |||
@@ -107,10 +125,6 @@ | |||
// #error "You need to set either the JUCE_PLUGINHOST_AU and/or JUCE_PLUGINHOST_VST and/or JUCE_PLUGINHOST_VST3 and/or JUCE_PLUGINHOST_LADSPA flags if you're using this module!" | |||
#endif | |||
#if ! (defined (JUCE_SUPPORT_CARBON) || JUCE_64BIT || JUCE_IOS) | |||
#define JUCE_SUPPORT_CARBON 1 | |||
#endif | |||
#ifndef JUCE_SUPPORT_LEGACY_AUDIOPROCESSOR | |||
#define JUCE_SUPPORT_LEGACY_AUDIOPROCESSOR 1 | |||
#endif | |||
@@ -119,18 +133,23 @@ | |||
#include "utilities/juce_VSTCallbackHandler.h" | |||
#include "utilities/juce_VST3ClientExtensions.h" | |||
#include "utilities/juce_NativeScaleFactorNotifier.h" | |||
#include "format_types/juce_ARACommon.h" | |||
#include "utilities/juce_ExtensionsVisitor.h" | |||
#include "processors/juce_AudioProcessorParameter.h" | |||
#include "processors/juce_HostedAudioProcessorParameter.h" | |||
#include "processors/juce_AudioProcessorEditorHostContext.h" | |||
#include "processors/juce_AudioProcessorEditor.h" | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
#include "processors/juce_AudioProcessorEditor.h" | |||
#endif | |||
#include "processors/juce_AudioProcessorListener.h" | |||
#include "processors/juce_AudioProcessorParameterGroup.h" | |||
#include "processors/juce_AudioProcessor.h" | |||
#include "processors/juce_PluginDescription.h" | |||
#include "processors/juce_AudioPluginInstance.h" | |||
#include "processors/juce_AudioProcessorGraph.h" | |||
#include "processors/juce_GenericAudioProcessorEditor.h" | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
#include "processors/juce_GenericAudioProcessorEditor.h" | |||
#endif | |||
#include "format/juce_AudioPluginFormat.h" | |||
#include "format/juce_AudioPluginFormatManager.h" | |||
#include "scanning/juce_KnownPluginList.h" | |||
@@ -140,6 +159,7 @@ | |||
#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_AudioProcessorParameterWithID.h" | |||
@@ -148,11 +168,23 @@ | |||
#include "utilities/juce_AudioParameterInt.h" | |||
#include "utilities/juce_AudioParameterBool.h" | |||
#include "utilities/juce_AudioParameterChoice.h" | |||
#include "utilities/juce_ParameterAttachments.h" | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
#include "utilities/juce_ParameterAttachments.h" | |||
#endif | |||
#include "utilities/juce_AudioProcessorValueTreeState.h" | |||
#include "utilities/juce_PluginHostType.h" | |||
#include "utilities/ARA/juce_ARA_utils.h" | |||
//============================================================================== | |||
// These declarations are here to avoid missing-prototype warnings in user code. | |||
// This is here to avoid missing-prototype warnings in user code. | |||
// If you're implementing a plugin, you should supply a body for | |||
// this function in your own code. | |||
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter(); | |||
// If you are implementing an ARA enabled plugin, you need to | |||
// implement this function somewhere in the codebase by returning | |||
// SubclassOfARADocumentControllerSpecialisation::createARAFactory<SubclassOfARADocumentControllerSpecialisation>(); | |||
#if JucePlugin_Enable_ARA | |||
const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory(); | |||
#endif |
@@ -0,0 +1,40 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#include <juce_core/system/juce_CompilerWarnings.h> | |||
#include <juce_core/system/juce_TargetPlatform.h> | |||
/* Having WIN32_LEAN_AND_MEAN defined at the point of including ARADebug.c will produce warnings. | |||
To prevent such problems it's easiest to have it in its own translation unit. | |||
*/ | |||
#if (JucePlugin_Enable_ARA || (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU))) && (JUCE_MAC || JUCE_WINDOWS) | |||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wgnu-zero-variadic-macro-arguments", "-Wmissing-prototypes") | |||
#include <ARA_Library/Debug/ARADebug.c> | |||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
#endif |
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -43,12 +50,14 @@ AudioProcessor::AudioProcessor (const BusesProperties& ioConfig) | |||
AudioProcessor::~AudioProcessor() | |||
{ | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
{ | |||
const ScopedLock sl (activeEditorLock); | |||
// ooh, nasty - the editor should have been deleted before its AudioProcessor. | |||
jassert (activeEditor == nullptr); | |||
} | |||
#endif | |||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING | |||
// This will fail if you've called beginParameterChangeGesture() for one | |||
@@ -867,6 +876,7 @@ void AudioProcessor::audioIOChanged (bool busNumberChanged, bool channelNumChang | |||
processorLayoutsChanged(); | |||
} | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
//============================================================================== | |||
void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) noexcept | |||
{ | |||
@@ -903,6 +913,7 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() | |||
return ed; | |||
} | |||
#endif | |||
//============================================================================== | |||
void AudioProcessor::getCurrentProgramStateInformation (juce::MemoryBlock& destData) | |||
@@ -1241,7 +1252,6 @@ const char* AudioProcessor::getWrapperTypeDescription (AudioProcessor::WrapperTy | |||
case AudioProcessor::wrapperType_VST3: return "VST3"; | |||
case AudioProcessor::wrapperType_AudioUnit: return "AU"; | |||
case AudioProcessor::wrapperType_AudioUnitv3: return "AUv3"; | |||
case AudioProcessor::wrapperType_RTAS: return "RTAS"; | |||
case AudioProcessor::wrapperType_AAX: return "AAX"; | |||
case AudioProcessor::wrapperType_Standalone: return "Standalone"; | |||
case AudioProcessor::wrapperType_Unity: return "Unity"; | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -24,7 +31,7 @@ namespace juce | |||
Base class for audio processing classes or plugins. | |||
This is intended to act as a base class of audio processor that is general enough | |||
to be wrapped as a VST, AU, RTAS, etc, or used internally. | |||
to be wrapped as a VST, AU, AAX, etc, or used internally. | |||
It is also used by the plugin hosting code as the wrapper around an instance | |||
of a loaded plugin. | |||
@@ -71,6 +78,12 @@ public: | |||
doublePrecision | |||
}; | |||
enum class Realtime | |||
{ | |||
no, | |||
yes | |||
}; | |||
using ChangeDetails = AudioProcessorListener::ChangeDetails; | |||
//============================================================================== | |||
@@ -916,11 +929,27 @@ public: | |||
*/ | |||
bool isNonRealtime() const noexcept { return nonRealtime; } | |||
/** Returns no if the processor is being run in an offline mode for rendering. | |||
If the processor is being run live on realtime signals, this returns yes. | |||
If the mode is unknown, this will assume it's realtime and return yes. | |||
This value may be unreliable until the prepareToPlay() method has been called, | |||
and could change each time prepareToPlay() is called. | |||
@see setNonRealtime() | |||
*/ | |||
Realtime isRealtime() const noexcept | |||
{ | |||
return isNonRealtime() ? Realtime::no : Realtime::yes; | |||
} | |||
/** Called by the host to tell this processor whether it's being used in a non-realtime | |||
capacity for offline rendering or bouncing. | |||
*/ | |||
virtual void setNonRealtime (bool isNonRealtime) noexcept; | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
//============================================================================== | |||
/** Creates the processor's GUI. | |||
@@ -970,6 +999,7 @@ public: | |||
This may call createEditor() internally to create the component. | |||
*/ | |||
AudioProcessorEditor* createEditorIfNeeded(); | |||
#endif | |||
//============================================================================== | |||
/** Returns the default number of steps for a parameter. | |||
@@ -1231,9 +1261,11 @@ public: | |||
virtual CurveData getResponseCurve (CurveData::Type /*curveType*/) const { return {}; } | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
//============================================================================== | |||
/** Not for public use - this is called before deleting an editor component. */ | |||
void editorBeingDeleted (AudioProcessorEditor*) noexcept; | |||
#endif | |||
/** Flags to indicate the type of plugin context in which a processor is being used. */ | |||
enum WrapperType | |||
@@ -1243,7 +1275,6 @@ public: | |||
wrapperType_VST3, | |||
wrapperType_AudioUnit, | |||
wrapperType_AudioUnitv3, | |||
wrapperType_RTAS, | |||
wrapperType_AAX, | |||
wrapperType_Standalone, | |||
wrapperType_Unity, | |||
@@ -1264,7 +1295,9 @@ public: | |||
struct TrackProperties | |||
{ | |||
String name; // The name of the track - this will be empty if the track name is not known | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
Colour colour; // The colour of the track - this will be transparentBlack if the colour is not known | |||
#endif | |||
// other properties may be added in the future | |||
}; | |||
@@ -1513,7 +1546,9 @@ private: | |||
//============================================================================== | |||
Array<AudioProcessorListener*> listeners; | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
Component::SafePointer<AudioProcessorEditor> activeEditor; | |||
#endif | |||
double currentSampleRate = 0; | |||
int blockSize = 0, latencySamples = 0; | |||
bool suspended = false; | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1575,8 +1582,10 @@ bool AudioProcessorGraph::AudioGraphIOProcessor::producesMidi() const | |||
bool AudioProcessorGraph::AudioGraphIOProcessor::isInput() const noexcept { return type == audioInputNode || type == midiInputNode; } | |||
bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const noexcept { return type == audioOutputNode || type == midiOutputNode; } | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
bool AudioProcessorGraph::AudioGraphIOProcessor::hasEditor() const { return false; } | |||
AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() { return nullptr; } | |||
#endif | |||
int AudioProcessorGraph::AudioGraphIOProcessor::getNumPrograms() { return 0; } | |||
int AudioProcessorGraph::AudioGraphIOProcessor::getCurrentProgram() { return 0; } | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -357,8 +364,10 @@ public: | |||
bool acceptsMidi() const override; | |||
bool producesMidi() const override; | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
bool hasEditor() const override; | |||
AudioProcessorEditor* createEditor() override; | |||
#endif | |||
int getNumPrograms() override; | |||
int getCurrentProgram() override; | |||
@@ -394,8 +403,10 @@ public: | |||
bool acceptsMidi() const override; | |||
bool producesMidi() const override; | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
bool hasEditor() const override { return false; } | |||
AudioProcessorEditor* createEditor() override { return nullptr; } | |||
#endif | |||
int getNumPrograms() override { return 0; } | |||
int getCurrentProgram() override { return 0; } | |||
void setCurrentProgram (int) override { } | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -72,6 +79,7 @@ std::unique_ptr<XmlElement> PluginDescription::createXml() const | |||
e->setAttribute ("numInputs", numInputChannels); | |||
e->setAttribute ("numOutputs", numOutputChannels); | |||
e->setAttribute ("isShell", hasSharedContainer); | |||
e->setAttribute ("hasARAExtension", hasARAExtension); | |||
e->setAttribute ("uid", String::toHexString (deprecatedUid)); | |||
@@ -95,6 +103,7 @@ bool PluginDescription::loadFromXml (const XmlElement& xml) | |||
numInputChannels = xml.getIntAttribute ("numInputs"); | |||
numOutputChannels = xml.getIntAttribute ("numOutputs"); | |||
hasSharedContainer = xml.getBoolAttribute ("isShell", false); | |||
hasARAExtension = xml.getBoolAttribute ("hasARAExtension", false); | |||
deprecatedUid = xml.getStringAttribute ("uid").getHexValue32(); | |||
uniqueId = xml.getStringAttribute ("uniqueId", "0").getHexValue32(); | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -122,6 +129,9 @@ public: | |||
/** True if the plug-in is part of a multi-type container, e.g. a VST Shell. */ | |||
bool hasSharedContainer = false; | |||
/** True if the plug-in is ARA enabled and can supply a valid ARAFactoryWrapper. */ | |||
bool hasARAExtension = false; | |||
/** Returns true if the two descriptions refer to the same plug-in. | |||
This isn't quite as simple as them just having the same file (because of | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -0,0 +1,971 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
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 <typename PlaybackRenderer_t = ARAPlaybackRenderer> | |||
std::vector<PlaybackRenderer_t*> const& getPlaybackRenderers() const noexcept | |||
{ | |||
return ARA::PlugIn::DocumentController::getPlaybackRenderers<PlaybackRenderer_t>(); | |||
} | |||
template <typename EditorRenderer_t = ARAEditorRenderer> | |||
std::vector<EditorRenderer_t*> const& getEditorRenderers() const noexcept | |||
{ | |||
return ARA::PlugIn::DocumentController::getEditorRenderers<EditorRenderer_t>(); | |||
} | |||
template <typename EditorView_t = ARAEditorView> | |||
std::vector<EditorView_t*> const& getEditorViews() const noexcept | |||
{ | |||
return ARA::PlugIn::DocumentController::getEditorViews<EditorView_t>(); | |||
} | |||
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<ARA::ARAContentType> 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<bool> internalAnalysisProgressIsSynced { true }; | |||
ScopedJuceInitialiser_GUI libraryInitialiser; | |||
int activeAudioSourcesCount = 0; | |||
//============================================================================== | |||
template <typename ModelObject, typename Function, typename... Ts> | |||
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<ARADocumentControllerImpl*> (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<ARA##ModelObjectType*> (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<ARA##ModelObjectType*> (modelObject), static_cast<ARA##ArgumentType> (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<ARA##ModelObjectType*> (modelObject), argument); \ | |||
} | |||
//============================================================================== | |||
ARA::PlugIn::Document* ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doCreateDocument() noexcept | |||
{ | |||
auto* document = specialisation->doCreateDocument(); | |||
// Your Document subclass must inherit from juce::ARADocument | |||
jassert (dynamic_cast<ARADocument*> (document)); | |||
return document; | |||
} | |||
void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::willBeginEditing() noexcept | |||
{ | |||
notifyListeners (&ARADocument::Listener::willBeginEditing, static_cast<ARADocument*> (getDocument())); | |||
} | |||
void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::didEndEditing() noexcept | |||
{ | |||
notifyListeners (&ARADocument::Listener::didEndEditing, static_cast<ARADocument*> (getDocument())); | |||
if (isTimerRunning() && (activeAudioSourcesCount == 0)) | |||
stopTimer(); | |||
else if (! isTimerRunning() && (activeAudioSourcesCount > 0)) | |||
startTimerHz (20); | |||
} | |||
void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::willNotifyModelUpdates() noexcept | |||
{ | |||
notifyListeners (&ARADocument::Listener::willNotifyModelUpdates, static_cast<ARADocument*> (getDocument())); | |||
} | |||
void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::didNotifyModelUpdates() noexcept | |||
{ | |||
notifyListeners (&ARADocument::Listener::didNotifyModelUpdates, static_cast<ARADocument*> (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<ARADocument*> (document), hostRef); | |||
} | |||
void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doUpdateMusicalContextContent (ARA::PlugIn::MusicalContext* musicalContext, | |||
const ARA::ARAContentTimeRange*, | |||
ARA::ContentUpdateScopes flags) noexcept | |||
{ | |||
notifyListeners (&ARAMusicalContext::Listener::doUpdateMusicalContextContent, | |||
static_cast<ARAMusicalContext*> (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<ARADocument*> (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<ARADocument*> (document), hostRef); | |||
} | |||
void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doUpdateAudioSourceContent (ARA::PlugIn::AudioSource* audioSource, | |||
const ARA::ARAContentTimeRange*, | |||
ARA::ContentUpdateScopes flags) noexcept | |||
{ | |||
notifyListeners (&ARAAudioSource::Listener::doUpdateAudioSourceContent, static_cast<ARAAudioSource*> (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<ARAAudioSource*> (audioSource), | |||
deactivate); | |||
} | |||
void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::willDestroyAudioSource (ARA::PlugIn::AudioSource* audioSource) noexcept | |||
{ | |||
if (! audioSource->isDeactivatedForUndoHistory()) | |||
--activeAudioSourcesCount; | |||
notifyListeners (&ARAAudioSource::Listener::willDestroyAudioSource, static_cast<ARAAudioSource*> (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<ARAAudioSource*> (audioSource), | |||
hostRef, | |||
static_cast<const ARAAudioModification*> (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<ARAAudioModification*> (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<ARADocumentControllerImpl*> (getDocumentController())); | |||
} | |||
ARAMusicalContext* ARADocumentControllerSpecialisation::doCreateMusicalContext (ARADocument* document, | |||
ARA::ARAMusicalContextHostRef hostRef) | |||
{ | |||
return new ARAMusicalContext (static_cast<ARADocument*> (document), hostRef); | |||
} | |||
ARARegionSequence* ARADocumentControllerSpecialisation::doCreateRegionSequence (ARADocument* document, | |||
ARA::ARARegionSequenceHostRef hostRef) | |||
{ | |||
return new ARARegionSequence (static_cast<ARADocument*> (document), hostRef); | |||
} | |||
ARAAudioSource* ARADocumentControllerSpecialisation::doCreateAudioSource (ARADocument* document, | |||
ARA::ARAAudioSourceHostRef hostRef) | |||
{ | |||
return new ARAAudioSource (static_cast<ARADocument*> (document), hostRef); | |||
} | |||
ARAAudioModification* ARADocumentControllerSpecialisation::doCreateAudioModification ( | |||
ARAAudioSource* audioSource, | |||
ARA::ARAAudioModificationHostRef hostRef, | |||
const ARAAudioModification* optionalModificationToClone) | |||
{ | |||
return new ARAAudioModification (static_cast<ARAAudioSource*> (audioSource), | |||
hostRef, | |||
static_cast<const ARAAudioModification*> (optionalModificationToClone)); | |||
} | |||
ARAPlaybackRegion* | |||
ARADocumentControllerSpecialisation::doCreatePlaybackRegion (ARAAudioModification* modification, | |||
ARA::ARAPlaybackRegionHostRef hostRef) | |||
{ | |||
return new ARAPlaybackRegion (static_cast<ARAAudioModification*> (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<ARA::ARAContentType> 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<ARAAudioSource*> (audioSourceHostRef); | |||
audioSource->getDocumentController<ARADocumentController>()->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<ARA::ARAAudioSourceHostRef> (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<ARA::ARAByte*> (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<ARADocumentControllerImpl> (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<ARA::ARAContentType> 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 |
@@ -0,0 +1,520 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#pragma once | |||
namespace juce | |||
{ | |||
class ARAPlaybackRenderer; | |||
class ARAEditorRenderer; | |||
class ARAEditorView; | |||
class ARAInputStream; | |||
class ARAOutputStream; | |||
/** This class contains the customisation points for the JUCE provided ARA document controller | |||
implementation. | |||
Every ARA enabled plugin must provide its own document controller implementation. To do this, | |||
inherit from this class, and override its protected methods as needed. Then you need to | |||
implement a global function somewhere in your module called createARAFactory(). This function | |||
must return an ARAFactory* that will instantiate document controller objects using your | |||
specialisation. There are helper functions inside ARADocumentControllerSpecialisation, so the | |||
implementation of createARAFactory() can always be a simple one-liner. For example | |||
@code | |||
class MyDocumentController : public ARADocumentControllerSpecialisation | |||
{ | |||
//... | |||
}; | |||
const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory() | |||
{ | |||
return juce::ARADocumentControllerSpecialisation::createARAFactory<MyDocumentController>(); | |||
} | |||
@endcode | |||
Most member functions have a default implementation so you can build up your required feature | |||
set gradually. The protected functions of this class fall in three distinct groups: | |||
- interactive editing and playback, | |||
- analysis features provided by the plugin and utilised by the host, and | |||
- maintaining the ARA model graph. | |||
On top of the pure virtual functions, you will probably want to override | |||
doCreatePlaybackRenderer() at the very least if you want your plugin to play any sound. This | |||
function belongs to the first group. | |||
If your plugin has analysis capabilities and wants to allow the host to access these, functions | |||
in the second group should be overridden. | |||
The default implementation of the ARA model object classes - i.e. ARADocument, ARAMusicalContext, | |||
ARARegionSequence, ARAAudioSource, ARAAudioModification, ARAPlaybackRegion - should be sufficient | |||
for maintaining a representation of the ARA model graph, hence overriding the model object | |||
creation functions e.g. doCreateMusicalContext() is considered an advanced use case. Hence you | |||
should be able to get a lot done without overriding functions in the third group. | |||
In order to react to the various ARA state changes you can override any of the ARA model object | |||
Listener functions that ARADocumentControllerSpecialisation inherits from. Such listener | |||
functions can be attached to one particular model objects instance, but the listener functions | |||
inside ARADocumentControllerSpecialisation will respond to the events of all instances of the | |||
model objects. | |||
@tags{ARA} | |||
*/ | |||
class ARADocumentControllerSpecialisation : public ARADocument::Listener, | |||
public ARAMusicalContext::Listener, | |||
public ARARegionSequence::Listener, | |||
public ARAAudioSource::Listener, | |||
public ARAAudioModification::Listener, | |||
public ARAPlaybackRegion::Listener | |||
{ | |||
public: | |||
//============================================================================== | |||
/** Constructor. Used internally by the ARAFactory implementation. | |||
*/ | |||
ARADocumentControllerSpecialisation (const ARA::PlugIn::PlugInEntry* entry, | |||
const ARA::ARADocumentControllerHostInstance* instance); | |||
/** Destructor. */ | |||
virtual ~ARADocumentControllerSpecialisation(); | |||
/** Returns the underlying DocumentController object that references this specialisation. | |||
*/ | |||
ARA::PlugIn::DocumentController* getDocumentController() noexcept; | |||
/** Helper function for implementing the global createARAFactory() function. | |||
For example | |||
@code | |||
class MyDocumentController : public ARADocumentControllerSpecialisation | |||
{ | |||
//... | |||
}; | |||
const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory() | |||
{ | |||
return juce::ARADocumentControllerSpecialisation::createARAFactory<MyDocumentController>(); | |||
} | |||
@endcode | |||
*/ | |||
template <typename SpecialisationType> | |||
static const ARA::ARAFactory* createARAFactory() | |||
{ | |||
static_assert (std::is_base_of<ARADocumentControllerSpecialisation, SpecialisationType>::value, | |||
"DocumentController specialization types must inherit from ARADocumentControllerSpecialisation"); | |||
return ARA::PlugIn::PlugInEntry::getPlugInEntry<FactoryConfig<SpecialisationType>>()->getFactory(); | |||
} | |||
/** Returns a pointer to the ARADocumentControllerSpecialisation instance that is referenced | |||
by the provided DocumentController. You can use this function to access your specialisation | |||
from anywhere where you have access to ARA::PlugIn::DocumentController*. | |||
*/ | |||
template <typename Specialisation = ARADocumentControllerSpecialisation> | |||
static Specialisation* getSpecialisedDocumentController (ARA::PlugIn::DocumentController* dc) | |||
{ | |||
return static_cast<Specialisation*> (getSpecialisedDocumentControllerImpl (dc)); | |||
} | |||
/** Returns a pointer to the ARA document root maintained by this document controller. */ | |||
template <typename DocumentType = ARADocument> | |||
DocumentType* getDocument() | |||
{ | |||
return static_cast<DocumentType*> (getDocumentImpl()); | |||
} | |||
protected: | |||
//============================================================================== | |||
/** Read an ARADocument archive from a juce::InputStream. | |||
@param input Data stream containing previously persisted data to be used when restoring the ARADocument | |||
@param filter A filter to be applied to the stream | |||
Return true if the operation is successful. | |||
@see ARADocumentControllerInterface::restoreObjectsFromArchive | |||
*/ | |||
virtual bool doRestoreObjectsFromStream (ARAInputStream& input, const ARARestoreObjectsFilter* filter) = 0; | |||
/** Write an ARADocument archive to a juce::OutputStream. | |||
@param output Data stream that should be used to write the persistent ARADocument data | |||
@param filter A filter to be applied to the stream | |||
Returns true if the operation is successful. | |||
@see ARADocumentControllerInterface::storeObjectsToArchive | |||
*/ | |||
virtual bool doStoreObjectsToStream (ARAOutputStream& output, const ARAStoreObjectsFilter* filter) = 0; | |||
//============================================================================== | |||
/** Override to return a custom subclass instance of ARAPlaybackRenderer. */ | |||
virtual ARAPlaybackRenderer* doCreatePlaybackRenderer(); | |||
/** Override to return a custom subclass instance of ARAEditorRenderer. */ | |||
virtual ARAEditorRenderer* doCreateEditorRenderer(); | |||
/** Override to return a custom subclass instance of ARAEditorView. */ | |||
virtual ARAEditorView* doCreateEditorView(); | |||
//============================================================================== | |||
// ARAAudioSource content access | |||
/** Override to implement isAudioSourceContentAvailable() for all your supported content types - | |||
the default implementation always returns false, preventing any calls to doGetAudioSourceContentGrade() | |||
and doCreateAudioSourceContentReader(). | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doIsAudioSourceContentAvailable. | |||
*/ | |||
virtual bool doIsAudioSourceContentAvailable (const ARA::PlugIn::AudioSource* audioSource, | |||
ARA::ARAContentType type); | |||
/** Override to implement getAudioSourceContentGrade() for all your supported content types. | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doGetAudioSourceContentGrade. | |||
*/ | |||
virtual ARA::ARAContentGrade doGetAudioSourceContentGrade (const ARA::PlugIn::AudioSource* audioSource, | |||
ARA::ARAContentType type); | |||
/** Override to implement createAudioSourceContentReader() for all your supported content types, | |||
returning a custom subclass instance of ContentReader providing data of the requested type. | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doCreateAudioSourceContentReader. | |||
*/ | |||
virtual ARA::PlugIn::ContentReader* doCreateAudioSourceContentReader (ARA::PlugIn::AudioSource* audioSource, | |||
ARA::ARAContentType type, | |||
const ARA::ARAContentTimeRange* range); | |||
//============================================================================== | |||
// ARAAudioModification content access | |||
/** Override to implement isAudioModificationContentAvailable() for all your supported content types - | |||
the default implementation always returns false. | |||
For read-only data directly inherited from the underlying audio source you can just delegate the | |||
call to the audio source, but user-editable modification data must be specifically handled here. | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doIsAudioModificationContentAvailable. | |||
*/ | |||
virtual bool doIsAudioModificationContentAvailable (const ARA::PlugIn::AudioModification* audioModification, | |||
ARA::ARAContentType type); | |||
/** Override to implement getAudioModificationContentGrade() for all your supported content types. | |||
For read-only data directly inherited from the underlying audio source you can just delegate the | |||
call to the audio source, but user-editable modification data must be specifically handled here. | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doGetAudioModificationContentGrade. | |||
*/ | |||
virtual ARA::ARAContentGrade doGetAudioModificationContentGrade (const ARA::PlugIn::AudioModification* audioModification, | |||
ARA::ARAContentType type); | |||
/** Override to implement createAudioModificationContentReader() for all your supported content types, | |||
returning a custom subclass instance of ContentReader providing data of the requested \p type. | |||
For read-only data directly inherited from the underlying audio source you can just delegate the | |||
call to the audio source, but user-editable modification data must be specifically handled here. | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doCreateAudioModificationContentReader. | |||
*/ | |||
virtual ARA::PlugIn::ContentReader* doCreateAudioModificationContentReader (ARA::PlugIn::AudioModification* audioModification, | |||
ARA::ARAContentType type, | |||
const ARA::ARAContentTimeRange* range); | |||
//============================================================================== | |||
// ARAPlaybackRegion content access | |||
/** Override to implement isPlaybackRegionContentAvailable() for all your supported content types - | |||
the default implementation always returns false. | |||
Typically, this call can directly delegate to the underlying audio modification, since most | |||
plug-ins will apply their modification data to the playback region with a transformation that | |||
does not affect content availability. | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doIsPlaybackRegionContentAvailable. | |||
*/ | |||
virtual bool doIsPlaybackRegionContentAvailable (const ARA::PlugIn::PlaybackRegion* playbackRegion, | |||
ARA::ARAContentType type); | |||
/** Override to implement getPlaybackRegionContentGrade() for all your supported content types. | |||
Typically, this call can directly delegate to the underlying audio modification, since most | |||
plug-ins will apply their modification data to the playback region with a transformation that | |||
does not affect content grade. | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doGetPlaybackRegionContentGrade. | |||
*/ | |||
virtual ARA::ARAContentGrade doGetPlaybackRegionContentGrade (const ARA::PlugIn::PlaybackRegion* playbackRegion, | |||
ARA::ARAContentType type); | |||
/** Override to implement createPlaybackRegionContentReader() for all your supported content types, | |||
returning a custom subclass instance of ContentReader providing data of the requested type. | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doCreatePlaybackRegionContentReader. | |||
*/ | |||
virtual ARA::PlugIn::ContentReader* doCreatePlaybackRegionContentReader (ARA::PlugIn::PlaybackRegion* playbackRegion, | |||
ARA::ARAContentType type, | |||
const ARA::ARAContentTimeRange* range); | |||
//============================================================================== | |||
// ARAAudioSource analysis | |||
/** Override to implement isAudioSourceContentAnalysisIncomplete(). | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doIsAudioSourceContentAnalysisIncomplete. | |||
*/ | |||
virtual bool doIsAudioSourceContentAnalysisIncomplete (const ARA::PlugIn::AudioSource* audioSource, | |||
ARA::ARAContentType type); | |||
/** Override to implement requestAudioSourceContentAnalysis(). | |||
This function's called from | |||
ARA::PlugIn::DocumentControllerDelegate::doRequestAudioSourceContentAnalysis. | |||
*/ | |||
virtual void doRequestAudioSourceContentAnalysis (ARA::PlugIn::AudioSource* audioSource, | |||
std::vector<ARA::ARAContentType> const& contentTypes); | |||
//============================================================================== | |||
// Analysis Algorithm selection | |||
/** Override to implement getProcessingAlgorithmsCount(). | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmsCount. | |||
*/ | |||
virtual ARA::ARAInt32 doGetProcessingAlgorithmsCount (); | |||
/** Override to implement getProcessingAlgorithmProperties(). | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmProperties. | |||
*/ | |||
virtual const ARA::ARAProcessingAlgorithmProperties* | |||
doGetProcessingAlgorithmProperties (ARA::ARAInt32 algorithmIndex); | |||
/** Override to implement getProcessingAlgorithmForAudioSource(). | |||
This function's result is returned from | |||
ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmForAudioSource. | |||
*/ | |||
virtual ARA::ARAInt32 doGetProcessingAlgorithmForAudioSource (const ARA::PlugIn::AudioSource* audioSource); | |||
/** Override to implement requestProcessingAlgorithmForAudioSource(). | |||
This function's called from | |||
ARA::PlugIn::DocumentControllerDelegate::doRequestProcessingAlgorithmForAudioSource. | |||
*/ | |||
virtual void doRequestProcessingAlgorithmForAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::ARAInt32 algorithmIndex); | |||
//============================================================================== | |||
/** Override to return a custom subclass instance of ARADocument. */ | |||
ARADocument* doCreateDocument(); | |||
/** Override to return a custom subclass instance of ARAMusicalContext. */ | |||
ARAMusicalContext* doCreateMusicalContext (ARADocument* document, | |||
ARA::ARAMusicalContextHostRef hostRef); | |||
/** Override to return a custom subclass instance of ARARegionSequence. */ | |||
ARARegionSequence* doCreateRegionSequence (ARADocument* document, | |||
ARA::ARARegionSequenceHostRef hostRef); | |||
/** Override to return a custom subclass instance of ARAAudioSource. */ | |||
ARAAudioSource* doCreateAudioSource (ARADocument* document, | |||
ARA::ARAAudioSourceHostRef hostRef); | |||
/** Override to return a custom subclass instance of ARAAudioModification. */ | |||
ARAAudioModification* doCreateAudioModification (ARAAudioSource* audioSource, | |||
ARA::ARAAudioModificationHostRef hostRef, | |||
const ARAAudioModification* optionalModificationToClone); | |||
/** Override to return a custom subclass instance of ARAPlaybackRegion. */ | |||
ARAPlaybackRegion* doCreatePlaybackRegion (ARAAudioModification* modification, | |||
ARA::ARAPlaybackRegionHostRef hostRef); | |||
private: | |||
//============================================================================== | |||
template <typename SpecialisationType> | |||
class FactoryConfig : public ARA::PlugIn::FactoryConfig | |||
{ | |||
public: | |||
FactoryConfig() noexcept | |||
{ | |||
const juce::String compatibleDocumentArchiveIDString = JucePlugin_ARACompatibleArchiveIDs; | |||
if (compatibleDocumentArchiveIDString.isNotEmpty()) | |||
{ | |||
compatibleDocumentArchiveIDStrings = juce::StringArray::fromLines (compatibleDocumentArchiveIDString); | |||
for (const auto& compatibleID : compatibleDocumentArchiveIDStrings) | |||
compatibleDocumentArchiveIDs.push_back (compatibleID.toRawUTF8()); | |||
} | |||
// Update analyzeable content types | |||
static constexpr std::array<ARA::ARAContentType, 6> contentTypes { | |||
ARA::kARAContentTypeNotes, | |||
ARA::kARAContentTypeTempoEntries, | |||
ARA::kARAContentTypeBarSignatures, | |||
ARA::kARAContentTypeStaticTuning, | |||
ARA::kARAContentTypeKeySignatures, | |||
ARA::kARAContentTypeSheetChords | |||
}; | |||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6313) | |||
for (size_t i = 0; i < contentTypes.size(); ++i) | |||
if (JucePlugin_ARAContentTypes & (1 << i)) | |||
analyzeableContentTypes.push_back (contentTypes[i]); | |||
JUCE_END_IGNORE_WARNINGS_MSVC | |||
// Update playback transformation flags | |||
static constexpr std::array<ARA::ARAPlaybackTransformationFlags, 4> playbackTransformationFlags { | |||
ARA::kARAPlaybackTransformationTimestretch, | |||
ARA::kARAPlaybackTransformationTimestretchReflectingTempo, | |||
ARA::kARAPlaybackTransformationContentBasedFadeAtTail, | |||
ARA::kARAPlaybackTransformationContentBasedFadeAtHead | |||
}; | |||
supportedPlaybackTransformationFlags = 0; | |||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6313) | |||
for (size_t i = 0; i < playbackTransformationFlags.size(); ++i) | |||
if (JucePlugin_ARATransformationFlags & (1 << i)) | |||
supportedPlaybackTransformationFlags |= playbackTransformationFlags[i]; | |||
JUCE_END_IGNORE_WARNINGS_MSVC | |||
} | |||
const char* getFactoryID() const noexcept override { return JucePlugin_ARAFactoryID; } | |||
const char* getPlugInName() const noexcept override { return JucePlugin_Name; } | |||
const char* getManufacturerName() const noexcept override { return JucePlugin_Manufacturer; } | |||
const char* getInformationURL() const noexcept override { return JucePlugin_ManufacturerWebsite; } | |||
const char* getVersion() const noexcept override { return JucePlugin_VersionString; } | |||
const char* getDocumentArchiveID() const noexcept override { return JucePlugin_ARADocumentArchiveID; } | |||
ARA::ARASize getCompatibleDocumentArchiveIDsCount() const noexcept override | |||
{ | |||
return compatibleDocumentArchiveIDs.size(); | |||
} | |||
const ARA::ARAPersistentID* getCompatibleDocumentArchiveIDs() const noexcept override | |||
{ | |||
return compatibleDocumentArchiveIDs.empty() ? nullptr : compatibleDocumentArchiveIDs.data(); | |||
} | |||
ARA::ARASize getAnalyzeableContentTypesCount() const noexcept override | |||
{ | |||
return analyzeableContentTypes.size(); | |||
} | |||
const ARA::ARAContentType* getAnalyzeableContentTypes() const noexcept override | |||
{ | |||
return analyzeableContentTypes.empty() ? nullptr : analyzeableContentTypes.data(); | |||
} | |||
ARA::ARAPlaybackTransformationFlags getSupportedPlaybackTransformationFlags() const noexcept override | |||
{ | |||
return supportedPlaybackTransformationFlags; | |||
} | |||
ARA::PlugIn::DocumentController* createDocumentController (const ARA::PlugIn::PlugInEntry* entry, | |||
const ARA::ARADocumentControllerHostInstance* instance) const noexcept override | |||
{ | |||
auto* spec = new SpecialisationType (entry, instance); | |||
return spec->getDocumentController(); | |||
} | |||
void destroyDocumentController (ARA::PlugIn::DocumentController* controller) const noexcept override | |||
{ | |||
delete getSpecialisedDocumentController (controller); | |||
} | |||
private: | |||
juce::StringArray compatibleDocumentArchiveIDStrings; | |||
std::vector<ARA::ARAPersistentID> compatibleDocumentArchiveIDs; | |||
std::vector<ARA::ARAContentType> analyzeableContentTypes; | |||
ARA::ARAPlaybackTransformationFlags supportedPlaybackTransformationFlags; | |||
}; | |||
//============================================================================== | |||
static ARADocumentControllerSpecialisation* getSpecialisedDocumentControllerImpl (ARA::PlugIn::DocumentController*); | |||
ARADocument* getDocumentImpl(); | |||
//============================================================================== | |||
class ARADocumentControllerImpl; | |||
std::unique_ptr<ARADocumentControllerImpl> documentController; | |||
}; | |||
/** Used to read persisted ARA archives - see doRestoreObjectsFromStream() for details. | |||
@tags{ARA} | |||
*/ | |||
class ARAInputStream : public InputStream | |||
{ | |||
public: | |||
explicit ARAInputStream (ARA::PlugIn::HostArchiveReader*); | |||
int64 getPosition() override { return position; } | |||
int64 getTotalLength() override { return size; } | |||
int read (void*, int) override; | |||
bool setPosition (int64) override; | |||
bool isExhausted() override; | |||
bool failed() const { return failure; } | |||
private: | |||
ARA::PlugIn::HostArchiveReader* archiveReader; | |||
int64 position = 0; | |||
int64 size; | |||
bool failure = false; | |||
}; | |||
/** Used to write persistent ARA archives - see doStoreObjectsToStream() for details. | |||
@tags{ARA} | |||
*/ | |||
class ARAOutputStream : public OutputStream | |||
{ | |||
public: | |||
explicit ARAOutputStream (ARA::PlugIn::HostArchiveWriter*); | |||
int64 getPosition() override { return position; } | |||
void flush() override {} | |||
bool write (const void*, size_t) override; | |||
bool setPosition (int64) override; | |||
private: | |||
ARA::PlugIn::HostArchiveWriter* archiveWriter; | |||
int64 position = 0; | |||
}; | |||
} // namespace juce |
@@ -0,0 +1,71 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
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 ARADocumentController : public ARA::PlugIn::DocumentController | |||
{ | |||
public: | |||
using ARA::PlugIn::DocumentController::DocumentController; | |||
template <typename Document_t = ARADocument> | |||
Document_t* getDocument() const noexcept { return ARA::PlugIn::DocumentController::getDocument<Document_t>(); } | |||
//============================================================================== | |||
/** @internal */ | |||
virtual void internalNotifyAudioSourceAnalysisProgressStarted (ARAAudioSource* audioSource) = 0; | |||
/** @internal */ | |||
virtual void internalNotifyAudioSourceAnalysisProgressUpdated (ARAAudioSource* audioSource, float progress) = 0; | |||
/** @internal */ | |||
virtual void internalNotifyAudioSourceAnalysisProgressCompleted (ARAAudioSource* audioSource) = 0; | |||
/** @internal */ | |||
virtual void internalDidUpdateAudioSourceAnalysisProgress (ARAAudioSource* audioSource, | |||
ARAAudioSource::ARAAnalysisProgressState state, | |||
float progress) = 0; | |||
//============================================================================== | |||
/** @internal */ | |||
virtual void internalNotifyAudioSourceContentChanged (ARAAudioSource* audioSource, | |||
ARAContentUpdateScopes scopeFlags, | |||
bool notifyARAHost) = 0; | |||
/** @internal */ | |||
virtual void internalNotifyAudioModificationContentChanged (ARAAudioModification* audioModification, | |||
ARAContentUpdateScopes scopeFlags, | |||
bool notifyARAHost) = 0; | |||
/** @internal */ | |||
virtual void internalNotifyPlaybackRegionContentChanged (ARAPlaybackRegion* playbackRegion, | |||
ARAContentUpdateScopes scopeFlags, | |||
bool notifyARAHost) = 0; | |||
friend class ARAPlaybackRegionReader; | |||
}; | |||
} // namespace juce |
@@ -0,0 +1,199 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
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 | |||
{ | |||
//============================================================================== | |||
size_t ARADocument::getNumChildren() const noexcept | |||
{ | |||
return getMusicalContexts().size() + getRegionSequences().size() + getAudioSources().size(); | |||
} | |||
ARAObject* ARADocument::getChild (size_t index) | |||
{ | |||
auto& musicalContexts = getMusicalContexts(); | |||
if (index < musicalContexts.size()) | |||
return musicalContexts[index]; | |||
const auto numMusicalContexts = musicalContexts.size(); | |||
auto& regionSequences = getRegionSequences(); | |||
if (index < numMusicalContexts + regionSequences.size()) | |||
return regionSequences[index - numMusicalContexts]; | |||
const auto numMusicalContextsAndRegionSequences = numMusicalContexts + regionSequences.size(); | |||
auto& audioSources = getAudioSources(); | |||
if (index < numMusicalContextsAndRegionSequences + audioSources.size()) | |||
return getAudioSources()[index - numMusicalContextsAndRegionSequences]; | |||
return nullptr; | |||
} | |||
//============================================================================== | |||
size_t ARARegionSequence::getNumChildren() const noexcept | |||
{ | |||
return 0; | |||
} | |||
ARAObject* ARARegionSequence::getChild (size_t) | |||
{ | |||
return nullptr; | |||
} | |||
Range<double> ARARegionSequence::getTimeRange (ARAPlaybackRegion::IncludeHeadAndTail includeHeadAndTail) const | |||
{ | |||
if (getPlaybackRegions().empty()) | |||
return {}; | |||
auto startTime = std::numeric_limits<double>::max(); | |||
auto endTime = std::numeric_limits<double>::lowest(); | |||
for (const auto& playbackRegion : getPlaybackRegions()) | |||
{ | |||
const auto regionTimeRange = playbackRegion->getTimeRange (includeHeadAndTail); | |||
startTime = jmin (startTime, regionTimeRange.getStart()); | |||
endTime = jmax (endTime, regionTimeRange.getEnd()); | |||
} | |||
return { startTime, endTime }; | |||
} | |||
double ARARegionSequence::getCommonSampleRate() const | |||
{ | |||
const auto getSampleRate = [] (auto* playbackRegion) | |||
{ | |||
return playbackRegion->getAudioModification()->getAudioSource()->getSampleRate(); | |||
}; | |||
const auto range = getPlaybackRegions(); | |||
const auto sampleRate = range.size() > 0 ? getSampleRate (range.front()) : 0.0; | |||
if (std::any_of (range.begin(), range.end(), [&] (auto& x) { return getSampleRate (x) != sampleRate; })) | |||
return 0.0; | |||
return sampleRate; | |||
} | |||
//============================================================================== | |||
size_t ARAAudioSource::getNumChildren() const noexcept | |||
{ | |||
return getAudioModifications().size(); | |||
} | |||
ARAObject* ARAAudioSource::getChild (size_t index) | |||
{ | |||
return getAudioModifications()[index]; | |||
} | |||
void ARAAudioSource::notifyAnalysisProgressStarted() | |||
{ | |||
getDocumentController<ARADocumentController>()->internalNotifyAudioSourceAnalysisProgressStarted (this); | |||
} | |||
void ARAAudioSource::notifyAnalysisProgressUpdated (float progress) | |||
{ | |||
getDocumentController<ARADocumentController>()->internalNotifyAudioSourceAnalysisProgressUpdated (this, progress); | |||
} | |||
void ARAAudioSource::notifyAnalysisProgressCompleted() | |||
{ | |||
getDocumentController<ARADocumentController>()->internalNotifyAudioSourceAnalysisProgressCompleted (this); | |||
} | |||
void ARAAudioSource::notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost) | |||
{ | |||
getDocumentController<ARADocumentController>()->internalNotifyAudioSourceContentChanged (this, | |||
scopeFlags, | |||
notifyARAHost); | |||
} | |||
//============================================================================== | |||
size_t ARAAudioModification::getNumChildren() const noexcept | |||
{ | |||
return getPlaybackRegions().size(); | |||
} | |||
ARAObject* ARAAudioModification::getChild (size_t index) | |||
{ | |||
return getPlaybackRegions()[index]; | |||
} | |||
void ARAAudioModification::notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost) | |||
{ | |||
getDocumentController<ARADocumentController>()->internalNotifyAudioModificationContentChanged (this, | |||
scopeFlags, | |||
notifyARAHost); | |||
} | |||
//============================================================================== | |||
ARAObject* ARAPlaybackRegion::getParent() { return getAudioModification(); } | |||
Range<double> ARAPlaybackRegion::getTimeRange (IncludeHeadAndTail includeHeadAndTail) const | |||
{ | |||
auto startTime = getStartInPlaybackTime(); | |||
auto endTime = getEndInPlaybackTime(); | |||
if (includeHeadAndTail == IncludeHeadAndTail::yes) | |||
{ | |||
ARA::ARATimeDuration headTime {}, tailTime {}; | |||
getDocumentController()->getPlaybackRegionHeadAndTailTime (toRef (this), &headTime, &tailTime); | |||
startTime -= headTime; | |||
endTime += tailTime; | |||
} | |||
return { startTime, endTime }; | |||
} | |||
Range<int64> ARAPlaybackRegion::getSampleRange (double sampleRate, IncludeHeadAndTail includeHeadAndTail) const | |||
{ | |||
const auto timeRange = getTimeRange (includeHeadAndTail); | |||
return { ARA::samplePositionAtTime (timeRange.getStart(), sampleRate), | |||
ARA::samplePositionAtTime (timeRange.getEnd(), sampleRate) }; | |||
} | |||
double ARAPlaybackRegion::getHeadTime() const | |||
{ | |||
ARA::ARATimeDuration headTime {}, tailTime {}; | |||
getDocumentController()->getPlaybackRegionHeadAndTailTime (toRef (this), &headTime, &tailTime); | |||
return headTime; | |||
} | |||
double ARAPlaybackRegion::getTailTime() const | |||
{ | |||
ARA::ARATimeDuration headTime {}, tailTime {}; | |||
getDocumentController()->getPlaybackRegionHeadAndTailTime (toRef (this), &headTime, &tailTime); | |||
return tailTime; | |||
} | |||
void ARAPlaybackRegion::notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost) | |||
{ | |||
getDocumentController<ARADocumentController>()->internalNotifyPlaybackRegionContentChanged (this, | |||
scopeFlags, | |||
notifyARAHost); | |||
} | |||
} // namespace juce |
@@ -0,0 +1,92 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#include "juce_ARAPlugInInstanceRoles.h" | |||
namespace juce | |||
{ | |||
bool ARARenderer::processBlock (AudioBuffer<double>& buffer, | |||
AudioProcessor::Realtime realtime, | |||
const AudioPlayHead::CurrentPositionInfo& positionInfo) noexcept | |||
{ | |||
ignoreUnused (buffer, realtime, positionInfo); | |||
// If you hit this assertion then either the caller called the double | |||
// precision version of processBlock on a processor which does not support it | |||
// (i.e. supportsDoublePrecisionProcessing() returns false), or the implementation | |||
// of the ARARenderer forgot to override the double precision version of this method | |||
jassertfalse; | |||
return false; | |||
} | |||
//============================================================================== | |||
#if ARA_VALIDATE_API_CALLS | |||
void ARAPlaybackRenderer::addPlaybackRegion (ARA::ARAPlaybackRegionRef playbackRegionRef) noexcept | |||
{ | |||
if (araExtension) | |||
ARA_VALIDATE_API_STATE (! araExtension->isPrepared); | |||
ARA::PlugIn::PlaybackRenderer::addPlaybackRegion (playbackRegionRef); | |||
} | |||
void ARAPlaybackRenderer::removePlaybackRegion (ARA::ARAPlaybackRegionRef playbackRegionRef) noexcept | |||
{ | |||
if (araExtension) | |||
ARA_VALIDATE_API_STATE (! araExtension->isPrepared); | |||
ARA::PlugIn::PlaybackRenderer::removePlaybackRegion (playbackRegionRef); | |||
} | |||
#endif | |||
//============================================================================== | |||
void ARAEditorView::doNotifySelection (const ARA::PlugIn::ViewSelection* viewSelection) noexcept | |||
{ | |||
listeners.call ([&] (Listener& l) | |||
{ | |||
l.onNewSelection (*viewSelection); | |||
}); | |||
} | |||
void ARAEditorView::doNotifyHideRegionSequences (std::vector<ARA::PlugIn::RegionSequence*> const& regionSequences) noexcept | |||
{ | |||
listeners.call ([&] (Listener& l) | |||
{ | |||
l.onHideRegionSequences (ARA::vector_cast<ARARegionSequence*> (regionSequences)); | |||
}); | |||
} | |||
void ARAEditorView::addListener (Listener* l) | |||
{ | |||
listeners.add (l); | |||
} | |||
void ARAEditorView::removeListener (Listener* l) | |||
{ | |||
listeners.remove (l); | |||
} | |||
} // namespace juce |
@@ -0,0 +1,271 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#pragma once | |||
namespace juce | |||
{ | |||
//============================================================================== | |||
/** Base class for a renderer fulfilling either the ARAPlaybackRenderer or the ARAEditorRenderer role. | |||
Instances of either subclass are constructed by the DocumentController. | |||
@tags{ARA} | |||
*/ | |||
class JUCE_API ARARenderer | |||
{ | |||
public: | |||
enum class AlwaysNonRealtime { no, yes }; | |||
virtual ~ARARenderer() = default; | |||
/** Initialises the renderer for playback. | |||
@param sampleRate The sample rate that will be used for the data that is sent | |||
to the renderer | |||
@param maximumSamplesPerBlock The maximum number of samples that will be in the blocks | |||
sent to process() method | |||
@param numChannels The number of channels that the process() method will be | |||
expected to handle | |||
@param precision This should be the same as the result of getProcessingPrecision() | |||
for the enclosing AudioProcessor | |||
@param alwaysNonRealtime yes if this renderer is never used in realtime (e.g. if | |||
providing data for views only) | |||
*/ | |||
virtual void prepareToPlay (double sampleRate, | |||
int maximumSamplesPerBlock, | |||
int numChannels, | |||
AudioProcessor::ProcessingPrecision precision, | |||
AlwaysNonRealtime alwaysNonRealtime = AlwaysNonRealtime::no) | |||
{ | |||
ignoreUnused (sampleRate, maximumSamplesPerBlock, numChannels, precision, alwaysNonRealtime); | |||
} | |||
/** Frees render resources allocated in prepareToPlay(). */ | |||
virtual void releaseResources() {} | |||
/** Resets the internal state variables of the renderer. */ | |||
virtual void reset() {} | |||
/** Renders the output into the given buffer. Returns true if rendering executed without error, | |||
false otherwise. | |||
@param buffer The output buffer for the rendering. ARAPlaybackRenderers will | |||
replace the sample data, while ARAEditorRenderer will add to it. | |||
@param realtime Indicates whether the call is executed under real time constraints. | |||
The value of this parameter may change from one call to the next, | |||
and if the value is yes, the rendering may fail if the required | |||
samples cannot be obtained in time. | |||
@param positionInfo Current song position, playback state and playback loop location. | |||
There should be no need to access the bpm, timeSig and ppqPosition | |||
members in any ARA renderer since ARA provides that information with | |||
random access in its model graph. | |||
Returns false if non-ARA fallback rendering is required and true otherwise. | |||
*/ | |||
virtual bool processBlock (AudioBuffer<float>& buffer, | |||
AudioProcessor::Realtime realtime, | |||
const AudioPlayHead::CurrentPositionInfo& positionInfo) noexcept = 0; | |||
/** Renders the output into the given buffer. Returns true if rendering executed without error, | |||
false otherwise. | |||
@param buffer The output buffer for the rendering. ARAPlaybackRenderers will | |||
replace the sample data, while ARAEditorRenderer will add to it. | |||
@param realtime Indicates whether the call is executed under real time constraints. | |||
The value of this parameter may change from one call to the next, | |||
and if the value is yes, the rendering may fail if the required | |||
samples cannot be obtained in time. | |||
@param positionInfo Current song position, playback state and playback loop location. | |||
There should be no need to access the bpm, timeSig and ppqPosition | |||
members in any ARA renderer since ARA provides that information with | |||
random access in its model graph. | |||
Returns false if non-ARA fallback rendering is required and true otherwise. | |||
*/ | |||
virtual bool processBlock (AudioBuffer<double>& buffer, | |||
AudioProcessor::Realtime realtime, | |||
const AudioPlayHead::CurrentPositionInfo& positionInfo) noexcept; | |||
}; | |||
//============================================================================== | |||
/** Base class for a renderer fulfilling the ARAPlaybackRenderer role as described in the ARA SDK. | |||
Instances of this class are constructed by the DocumentController. If you are subclassing | |||
ARAPlaybackRenderer, make sure to call the base class implementation of any overridden function, | |||
except for processBlock. | |||
@tags{ARA} | |||
*/ | |||
class JUCE_API ARAPlaybackRenderer : public ARA::PlugIn::PlaybackRenderer, | |||
public ARARenderer | |||
{ | |||
public: | |||
using ARA::PlugIn::PlaybackRenderer::PlaybackRenderer; | |||
bool processBlock (AudioBuffer<float>& buffer, | |||
AudioProcessor::Realtime realtime, | |||
const AudioPlayHead::CurrentPositionInfo& positionInfo) noexcept override | |||
{ | |||
ignoreUnused (buffer, realtime, positionInfo); | |||
return false; | |||
} | |||
// Shadowing templated getters to default to JUCE versions of the returned classes | |||
/** Returns the PlaybackRegions | |||
* | |||
* @tparam PlaybackRegion_t | |||
* @return | |||
*/ | |||
template <typename PlaybackRegion_t = ARAPlaybackRegion> | |||
std::vector<PlaybackRegion_t*> const& getPlaybackRegions() const noexcept | |||
{ | |||
return ARA::PlugIn::PlaybackRenderer::getPlaybackRegions<PlaybackRegion_t>(); | |||
} | |||
#if ARA_VALIDATE_API_CALLS | |||
void addPlaybackRegion (ARA::ARAPlaybackRegionRef playbackRegionRef) noexcept override; | |||
void removePlaybackRegion (ARA::ARAPlaybackRegionRef playbackRegionRef) noexcept override; | |||
AudioProcessorARAExtension* araExtension {}; | |||
#endif | |||
private: | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ARAPlaybackRenderer) | |||
}; | |||
//============================================================================== | |||
/** Base class for a renderer fulfilling the ARAEditorRenderer role as described in the ARA SDK. | |||
Instances of this class are constructed by the DocumentController. If you are subclassing | |||
ARAEditorRenderer, make sure to call the base class implementation of any overridden function, | |||
except for processBlock. | |||
@tags{ARA} | |||
*/ | |||
class JUCE_API ARAEditorRenderer : public ARA::PlugIn::EditorRenderer, | |||
public ARARenderer | |||
{ | |||
public: | |||
using ARA::PlugIn::EditorRenderer::EditorRenderer; | |||
// Shadowing templated getters to default to JUCE versions of the returned classes | |||
template <typename PlaybackRegion_t = ARAPlaybackRegion> | |||
std::vector<PlaybackRegion_t*> const& getPlaybackRegions() const noexcept | |||
{ | |||
return ARA::PlugIn::EditorRenderer::getPlaybackRegions<PlaybackRegion_t>(); | |||
} | |||
template <typename RegionSequence_t = ARARegionSequence> | |||
std::vector<RegionSequence_t*> const& getRegionSequences() const noexcept | |||
{ | |||
return ARA::PlugIn::EditorRenderer::getRegionSequences<RegionSequence_t>(); | |||
} | |||
// By default, editor renderers will just let the signal pass through unaltered. | |||
// If you're overriding this to implement actual audio preview, remember to check | |||
// isNonRealtime of the process context - typically preview is limited to realtime. | |||
bool processBlock (AudioBuffer<float>& buffer, | |||
AudioProcessor::Realtime isNonRealtime, | |||
const AudioPlayHead::CurrentPositionInfo& positionInfo) noexcept override | |||
{ | |||
ignoreUnused (buffer, isNonRealtime, positionInfo); | |||
return true; | |||
} | |||
private: | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ARAEditorRenderer) | |||
}; | |||
//============================================================================== | |||
/** Base class for a renderer fulfilling the ARAEditorView role as described in the ARA SDK. | |||
Instances of this class are constructed by the DocumentController. If you are subclassing | |||
ARAEditorView, make sure to call the base class implementation of overridden functions. | |||
@tags{ARA} | |||
*/ | |||
class JUCE_API ARAEditorView : public ARA::PlugIn::EditorView | |||
{ | |||
public: | |||
using ARA::PlugIn::EditorView::EditorView; | |||
// Shadowing templated getters to default to JUCE versions of the returned classes | |||
template <typename RegionSequence_t = ARARegionSequence> | |||
std::vector<RegionSequence_t*> const& getHiddenRegionSequences() const noexcept | |||
{ | |||
return ARA::PlugIn::EditorView::getHiddenRegionSequences<RegionSequence_t>(); | |||
} | |||
// Base class implementation must be called if overridden | |||
void doNotifySelection (const ARA::PlugIn::ViewSelection* currentSelection) noexcept override; | |||
// Base class implementation must be called if overridden | |||
void doNotifyHideRegionSequences (std::vector<ARA::PlugIn::RegionSequence*> const& regionSequences) noexcept override; | |||
/** A base class for listeners that want to know about changes to an ARAEditorView object. | |||
Use ARAEditorView::addListener() to register your listener with an ARAEditorView. | |||
*/ | |||
class JUCE_API Listener | |||
{ | |||
public: | |||
/** Destructor. */ | |||
virtual ~Listener() = default; | |||
ARA_DISABLE_UNREFERENCED_PARAMETER_WARNING_BEGIN | |||
/** Called when the editor view's selection changes. | |||
@param viewSelection The current selection state | |||
*/ | |||
virtual void onNewSelection (const ARA::PlugIn::ViewSelection& viewSelection) | |||
{ | |||
ignoreUnused (viewSelection); | |||
} | |||
/** Called when region sequences are flagged as hidden in the host UI. | |||
@param regionSequences A vector containing all hidden region sequences. | |||
*/ | |||
virtual void onHideRegionSequences (std::vector<ARARegionSequence*> const& regionSequences) | |||
{ | |||
ignoreUnused (regionSequences); | |||
} | |||
ARA_DISABLE_UNREFERENCED_PARAMETER_WARNING_END | |||
}; | |||
/** \copydoc ARAListenableModelClass::addListener */ | |||
void addListener (Listener* l); | |||
/** \copydoc ARAListenableModelClass::removeListener */ | |||
void removeListener (Listener* l); | |||
private: | |||
ListenerList<Listener> listeners; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ARAEditorView) | |||
}; | |||
} |
@@ -0,0 +1,32 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#if JucePlugin_Enable_ARA | |||
#include "juce_ARADocumentControllerCommon.cpp" | |||
#include "juce_ARADocumentController.cpp" | |||
#include "juce_ARAModelObjects.cpp" | |||
#include "juce_ARAPlugInInstanceRoles.cpp" | |||
#include "juce_AudioProcessor_ARAExtensions.cpp" | |||
#endif |
@@ -0,0 +1,85 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#if JucePlugin_Enable_ARA | |||
// Include ARA SDK headers | |||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wgnu-zero-variadic-macro-arguments", | |||
"-Wunused-parameter") | |||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6387) | |||
#include <ARA_Library/PlugIn/ARAPlug.h> | |||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
JUCE_END_IGNORE_WARNINGS_MSVC | |||
namespace juce | |||
{ | |||
using ARAViewSelection = ARA::PlugIn::ViewSelection; | |||
using ARAContentUpdateScopes = ARA::ContentUpdateScopes; | |||
using ARARestoreObjectsFilter = ARA::PlugIn::RestoreObjectsFilter; | |||
using ARAStoreObjectsFilter = ARA::PlugIn::StoreObjectsFilter; | |||
/** Converts an ARA::ARAUtf8String to a JUCE String. */ | |||
inline String convertARAString (ARA::ARAUtf8String str) | |||
{ | |||
return String (CharPointer_UTF8 (str)); | |||
} | |||
/** Converts a potentially NULL ARA::ARAUtf8String to a JUCE String. | |||
Returns the JUCE equivalent of the provided string if it's not nullptr, and the fallback string | |||
otherwise. | |||
*/ | |||
inline String convertOptionalARAString (ARA::ARAUtf8String str, const String& fallbackString = String()) | |||
{ | |||
return (str != nullptr) ? convertARAString (str) : fallbackString; | |||
} | |||
/** Converts an ARA::ARAColor* to a JUCE Colour. */ | |||
inline Colour convertARAColour (const ARA::ARAColor* colour) | |||
{ | |||
return Colour::fromFloatRGBA (colour->r, colour->g, colour->b, 1.0f); | |||
} | |||
/** Converts a potentially NULL ARA::ARAColor* to a JUCE Colour. | |||
Returns the JUCE equivalent of the provided colour if it's not nullptr, and the fallback colour | |||
otherwise. | |||
*/ | |||
inline Colour convertOptionalARAColour (const ARA::ARAColor* colour, const Colour& fallbackColour = Colour()) | |||
{ | |||
return (colour != nullptr) ? convertARAColour (colour) : fallbackColour; | |||
} | |||
} // namespace juce | |||
#include "juce_ARAModelObjects.h" | |||
#include "juce_ARADocumentController.h" | |||
#include "juce_AudioProcessor_ARAExtensions.h" | |||
#include "juce_ARAPlugInInstanceRoles.h" | |||
#endif |
@@ -0,0 +1,156 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#include "juce_AudioProcessor_ARAExtensions.h" | |||
namespace juce | |||
{ | |||
//============================================================================== | |||
bool AudioProcessorARAExtension::getTailLengthSecondsForARA (double& tailLength) const | |||
{ | |||
if (! isBoundToARA()) | |||
return false; | |||
tailLength = 0.0; | |||
if (auto playbackRenderer = getPlaybackRenderer()) | |||
for (const auto& playbackRegion : playbackRenderer->getPlaybackRegions()) | |||
tailLength = jmax (tailLength, playbackRegion->getTailTime()); | |||
return true; | |||
} | |||
bool AudioProcessorARAExtension::prepareToPlayForARA (double sampleRate, | |||
int samplesPerBlock, | |||
int numChannels, | |||
AudioProcessor::ProcessingPrecision precision) | |||
{ | |||
#if ARA_VALIDATE_API_CALLS | |||
isPrepared = true; | |||
#endif | |||
if (! isBoundToARA()) | |||
return false; | |||
if (auto playbackRenderer = getPlaybackRenderer()) | |||
playbackRenderer->prepareToPlay (sampleRate, samplesPerBlock, numChannels, precision); | |||
if (auto editorRenderer = getEditorRenderer()) | |||
editorRenderer->prepareToPlay (sampleRate, samplesPerBlock, numChannels, precision); | |||
return true; | |||
} | |||
bool AudioProcessorARAExtension::releaseResourcesForARA() | |||
{ | |||
#if ARA_VALIDATE_API_CALLS | |||
isPrepared = false; | |||
#endif | |||
if (! isBoundToARA()) | |||
return false; | |||
if (auto playbackRenderer = getPlaybackRenderer()) | |||
playbackRenderer->releaseResources(); | |||
if (auto editorRenderer = getEditorRenderer()) | |||
editorRenderer->releaseResources(); | |||
return true; | |||
} | |||
bool AudioProcessorARAExtension::processBlockForARA (AudioBuffer<float>& buffer, | |||
AudioProcessor::Realtime realtime, | |||
const AudioPlayHead::CurrentPositionInfo& positionInfo) | |||
{ | |||
// validate that the host has prepared us before processing | |||
ARA_VALIDATE_API_STATE (isPrepared); | |||
if (! isBoundToARA()) | |||
return false; | |||
// Render our ARA playback regions for this buffer. | |||
if (auto playbackRenderer = getPlaybackRenderer()) | |||
playbackRenderer->processBlock (buffer, realtime, positionInfo); | |||
// Render our ARA editor regions and sequences for this buffer. | |||
// This example does not support editor rendering and thus uses the default implementation, | |||
// which is a no-op and could be omitted in actual plug-ins to optimize performance. | |||
if (auto editorRenderer = getEditorRenderer()) | |||
editorRenderer->processBlock (buffer, realtime, positionInfo); | |||
return true; | |||
} | |||
bool AudioProcessorARAExtension::processBlockForARA (AudioBuffer<float>& buffer, | |||
juce::AudioProcessor::Realtime realtime, | |||
AudioPlayHead* playhead) | |||
{ | |||
AudioPlayHead::CurrentPositionInfo positionInfo; | |||
if (! isBoundToARA() || ! playhead || ! playhead->getCurrentPosition (positionInfo)) | |||
positionInfo.resetToDefault(); | |||
return processBlockForARA (buffer, realtime, positionInfo); | |||
} | |||
//============================================================================== | |||
void AudioProcessorARAExtension::didBindToARA() noexcept | |||
{ | |||
// validate that the ARA binding is not established by the host while prepared to play | |||
#if ARA_VALIDATE_API_CALLS | |||
ARA_VALIDATE_API_STATE (! isPrepared); | |||
if (auto playbackRenderer = getPlaybackRenderer()) | |||
playbackRenderer->araExtension = this; | |||
#endif | |||
#if (! JUCE_DISABLE_ASSERTIONS) | |||
// validate proper subclassing of the instance role classes | |||
if (auto playbackRenderer = getPlaybackRenderer()) | |||
jassert (dynamic_cast<ARAPlaybackRenderer*> (playbackRenderer) != nullptr); | |||
if (auto editorRenderer = getEditorRenderer()) | |||
jassert (dynamic_cast<ARAEditorRenderer*> (editorRenderer) != nullptr); | |||
if (auto editorView = getEditorView()) | |||
jassert (dynamic_cast<ARAEditorView*> (editorView) != nullptr); | |||
#endif | |||
} | |||
//============================================================================== | |||
AudioProcessorEditorARAExtension::AudioProcessorEditorARAExtension (AudioProcessor* audioProcessor) | |||
: araProcessorExtension (dynamic_cast<AudioProcessorARAExtension*> (audioProcessor)) | |||
{ | |||
if (isARAEditorView()) | |||
getARAEditorView()->setEditorOpen (true); | |||
} | |||
AudioProcessorEditorARAExtension::~AudioProcessorEditorARAExtension() | |||
{ | |||
if (isARAEditorView()) | |||
getARAEditorView()->setEditorOpen (false); | |||
} | |||
} // namespace juce |
@@ -0,0 +1,204 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#pragma once | |||
namespace juce | |||
{ | |||
class AudioProcessor; | |||
class ARAPlaybackRenderer; | |||
class ARAEditorRenderer; | |||
class ARAEditorView; | |||
//============================================================================== | |||
/** Extension class meant to be subclassed by the plugin's implementation of @see AudioProcessor. | |||
Subclassing AudioProcessorARAExtension allows access to the three possible plugin instance | |||
roles as defined by the ARA SDK. Hosts can assign any subset of roles to each plugin instance. | |||
@tags{ARA} | |||
*/ | |||
class JUCE_API AudioProcessorARAExtension : public ARA::PlugIn::PlugInExtension | |||
{ | |||
public: | |||
AudioProcessorARAExtension() = default; | |||
//============================================================================== | |||
/** Returns the result of ARA::PlugIn::PlugInExtension::getPlaybackRenderer() with the pointer | |||
cast to ARAPlaybackRenderer*. | |||
If you have overridden ARADocumentControllerSpecialisation::doCreatePlaybackRenderer(), | |||
then you can use the template parameter to cast the pointers to your subclass of | |||
ARAPlaybackRenderer. | |||
*/ | |||
template <typename PlaybackRenderer_t = ARAPlaybackRenderer> | |||
PlaybackRenderer_t* getPlaybackRenderer() const noexcept | |||
{ | |||
return ARA::PlugIn::PlugInExtension::getPlaybackRenderer<PlaybackRenderer_t>(); | |||
} | |||
/** Returns the result of ARA::PlugIn::PlugInExtension::getEditorRenderer() with the pointer | |||
cast to ARAEditorRenderer*. | |||
If you have overridden ARADocumentControllerSpecialisation::doCreateEditorRenderer(), | |||
then you can use the template parameter to cast the pointers to your subclass of | |||
ARAEditorRenderer. | |||
*/ | |||
template <typename EditorRenderer_t = ARAEditorRenderer> | |||
EditorRenderer_t* getEditorRenderer() const noexcept | |||
{ | |||
return ARA::PlugIn::PlugInExtension::getEditorRenderer<EditorRenderer_t>(); | |||
} | |||
/** Returns the result of ARA::PlugIn::PlugInExtension::getEditorView() with the pointer | |||
cast to ARAEditorView*. | |||
If you have overridden ARADocumentControllerSpecialisation::doCreateEditorView(), | |||
then you can use the template parameter to cast the pointers to your subclass of | |||
ARAEditorView. | |||
*/ | |||
template <typename EditorView_t = ARAEditorView> | |||
EditorView_t* getEditorView() const noexcept | |||
{ | |||
return ARA::PlugIn::PlugInExtension::getEditorView<EditorView_t>(); | |||
} | |||
//============================================================================== | |||
/** Returns true if plugin instance fulfills the ARAPlaybackRenderer role. */ | |||
bool isPlaybackRenderer() const noexcept | |||
{ | |||
return ARA::PlugIn::PlugInExtension::getPlaybackRenderer() != nullptr; | |||
} | |||
/** Returns true if plugin instance fulfills the ARAEditorRenderer role. */ | |||
bool isEditorRenderer() const noexcept | |||
{ | |||
return ARA::PlugIn::PlugInExtension::getEditorRenderer() != nullptr; | |||
} | |||
/** Returns true if plugin instance fulfills the ARAEditorView role. */ | |||
bool isEditorView() const noexcept | |||
{ | |||
return ARA::PlugIn::PlugInExtension::getEditorView() != nullptr; | |||
} | |||
//============================================================================== | |||
#if ARA_VALIDATE_API_CALLS | |||
bool isPrepared { false }; | |||
#endif | |||
protected: | |||
/** Implementation helper for AudioProcessor::getTailLengthSeconds(). | |||
If bound to ARA, this traverses the instance roles to retrieve the respective tail time | |||
and returns true. Otherwise returns false and leaves tailLength unmodified. | |||
*/ | |||
bool getTailLengthSecondsForARA (double& tailLength) const; | |||
/** Implementation helper for AudioProcessor::prepareToPlay(). | |||
If bound to ARA, this traverses the instance roles to prepare them for play and returns | |||
true. Otherwise returns false and does nothing. | |||
*/ | |||
bool prepareToPlayForARA (double sampleRate, | |||
int samplesPerBlock, | |||
int numChannels, | |||
AudioProcessor::ProcessingPrecision precision); | |||
/** Implementation helper for AudioProcessor::releaseResources(). | |||
If bound to ARA, this traverses the instance roles to let them release resources and returns | |||
true. Otherwise returns false and does nothing. | |||
*/ | |||
bool releaseResourcesForARA(); | |||
/** Implementation helper for AudioProcessor::processBlock(). | |||
If bound to ARA, this traverses the instance roles to let them process the block and returns | |||
true. Otherwise returns false and does nothing. | |||
Use this overload if your rendering code already has a current positionInfo available. | |||
*/ | |||
bool processBlockForARA (AudioBuffer<float>& buffer, | |||
AudioProcessor::Realtime realtime, | |||
const AudioPlayHead::CurrentPositionInfo& positionInfo); | |||
/** Implementation helper for AudioProcessor::processBlock(). | |||
If bound to ARA, this traverses the instance roles to let them process the block and returns | |||
true. Otherwise returns false and does nothing. | |||
Use this overload if your rendering code does not have a current positionInfo available. | |||
*/ | |||
bool processBlockForARA (AudioBuffer<float>& buffer, AudioProcessor::Realtime isNonRealtime, AudioPlayHead* playhead); | |||
//============================================================================== | |||
/** Optional hook for derived classes to perform any additional initialization that may be needed. | |||
If overriding this, make sure you call the base class implementation from your override. | |||
*/ | |||
void didBindToARA() noexcept override; | |||
private: | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorARAExtension) | |||
}; | |||
//============================================================================== | |||
/** Extension class meant to be subclassed by the plugin's implementation of @see AudioProcessorEditor. | |||
Subclassing AudioProcessorARAExtension allows access to the ARAEditorView instance role as | |||
described by the ARA SDK. | |||
@tags{ARA} | |||
*/ | |||
class JUCE_API AudioProcessorEditorARAExtension | |||
{ | |||
public: | |||
/** Constructor. */ | |||
explicit AudioProcessorEditorARAExtension (AudioProcessor* audioProcessor); | |||
/** \copydoc AudioProcessorARAExtension::getEditorView */ | |||
template <typename EditorView_t = ARAEditorView> | |||
EditorView_t* getARAEditorView() const noexcept | |||
{ | |||
return (this->araProcessorExtension != nullptr) ? this->araProcessorExtension->getEditorView<EditorView_t>() | |||
: nullptr; | |||
} | |||
/** \copydoc AudioProcessorARAExtension::isEditorView */ | |||
bool isARAEditorView() const noexcept { return getARAEditorView() != nullptr; } | |||
protected: | |||
/** Destructor. */ | |||
~AudioProcessorEditorARAExtension(); | |||
private: | |||
AudioProcessorARAExtension* araProcessorExtension; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorEditorARAExtension) | |||
}; | |||
} // namespace juce |
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -466,6 +473,7 @@ void AudioProcessorValueTreeState::timerCallback() | |||
} | |||
//============================================================================== | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
template <typename Attachment, typename Control> | |||
std::unique_ptr<Attachment> makeAttachment (const AudioProcessorValueTreeState& stateToUse, | |||
const String& parameterID, | |||
@@ -498,6 +506,7 @@ AudioProcessorValueTreeState::ButtonAttachment::ButtonAttachment (AudioProcessor | |||
: attachment (makeAttachment<ButtonParameterAttachment> (stateToUse, parameterID, button)) | |||
{ | |||
} | |||
#endif | |||
//============================================================================== | |||
//============================================================================== | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -519,6 +526,7 @@ public: | |||
friend class AudioProcessorValueTreeState::ParameterAdapter; | |||
}; | |||
#if ! JUCE_AUDIOPROCESSOR_NO_GUI | |||
//============================================================================== | |||
/** An object of this class maintains a connection between a Slider and a parameter | |||
in an AudioProcessorValueTreeState. | |||
@@ -586,6 +594,7 @@ public: | |||
std::unique_ptr<ButtonParameterAttachment> attachment; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonAttachment) | |||
}; | |||
#endif | |||
private: | |||
//============================================================================== | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -30,7 +37,7 @@ namespace Steinberg | |||
#endif | |||
//============================================================================== | |||
#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || (defined(AUDIOCOMPONENT_NOCARBONINSTANCES) && AUDIOCOMPONENT_NOCARBONINSTANCES) | |||
#if TARGET_OS_IPHONE | |||
struct OpaqueAudioComponentInstance; | |||
typedef struct OpaqueAudioComponentInstance* AudioComponentInstance; | |||
#else | |||
@@ -108,6 +115,13 @@ struct ExtensionsVisitor | |||
virtual AEffect* getAEffectPtr() const noexcept = 0; | |||
}; | |||
/** Can be used to retrieve information about a plugin that provides ARA extensions. */ | |||
struct ARAClient | |||
{ | |||
virtual ~ARAClient() = default; | |||
virtual void createARAFactoryAsync (std::function<void (ARAFactoryWrapper)>) const = 0; | |||
}; | |||
virtual ~ExtensionsVisitor() = default; | |||
/** Will be called if there is no platform specific information available. */ | |||
@@ -121,6 +135,9 @@ struct ExtensionsVisitor | |||
/** Called with AU-specific information. */ | |||
virtual void visitAudioUnitClient (const AudioUnitClient&) {} | |||
/** Called with ARA-specific information. */ | |||
virtual void visitARAClient (const ARAClient&) {} | |||
}; | |||
} // namespace juce |
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
@@ -1,13 +1,20 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE 7 technical preview. | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
You may use this code under the terms of the GPL v3 | |||
(see www.gnu.org/licenses). | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
For the technical preview this file cannot be licensed commercially. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||