build(deps): vendor JUCE 7.0.12
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
||||
#include <juce_core/system/juce_PlatformDefs.h>
|
||||
|
||||
#ifndef JUCE_API
|
||||
#define JUCE_API
|
||||
#endif
|
||||
|
||||
#if (JucePlugin_Enable_ARA || (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU))) && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX)
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
#if (JUCE_DEBUG && ! JUCE_DISABLE_ASSERTIONS) || JUCE_LOG_ASSERTIONS
|
||||
#define ARA_ENABLE_INTERNAL_ASSERTS 1
|
||||
#else
|
||||
#define ARA_ENABLE_INTERNAL_ASSERTS 0
|
||||
#endif // (JUCE_DEBUG && ! JUCE_DISABLE_ASSERTIONS) || JUCE_LOG_ASSERTIONS
|
||||
|
||||
//==============================================================================
|
||||
#if ARA_ENABLE_INTERNAL_ASSERTS
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE handleARAAssertion (const char* file, const int line, const char* diagnosis) noexcept;
|
||||
|
||||
#if !defined(ARA_HANDLE_ASSERT)
|
||||
#define ARA_HANDLE_ASSERT(file, line, diagnosis) juce::handleARAAssertion (file, line, diagnosis)
|
||||
#endif
|
||||
|
||||
#if JUCE_LOG_ASSERTIONS
|
||||
#define ARA_ENABLE_DEBUG_OUTPUT 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wgnu-zero-variadic-macro-arguments", "-Wmissing-prototypes")
|
||||
#include <ARA_Library/Debug/ARADebug.h>
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#endif
|
||||
Vendored
+976
@@ -0,0 +1,976 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
void doGetPlaybackRegionHeadAndTailTime (const ARA::PlugIn::PlaybackRegion* playbackRegion,
|
||||
ARA::ARATimeDuration* headTime,
|
||||
ARA::ARATimeDuration* tailTime) 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;
|
||||
|
||||
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;
|
||||
std::optional<TimedCallback> analysisTimer;
|
||||
|
||||
void analysisTimerCallback();
|
||||
|
||||
//==============================================================================
|
||||
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 (activeAudioSourcesCount == 0)
|
||||
{
|
||||
analysisTimer.reset();
|
||||
}
|
||||
else if (! analysisTimer.has_value() && (activeAudioSourcesCount > 0))
|
||||
{
|
||||
analysisTimer.emplace ([this] { analysisTimerCallback(); });
|
||||
analysisTimer->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);
|
||||
}
|
||||
|
||||
void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doGetPlaybackRegionHeadAndTailTime (const ARA::PlugIn::PlaybackRegion* playbackRegion,
|
||||
ARA::ARATimeDuration* headTime,
|
||||
ARA::ARATimeDuration* tailTime) noexcept
|
||||
{
|
||||
specialisation->doGetPlaybackRegionHeadAndTailTime (playbackRegion, headTime, tailTime);
|
||||
}
|
||||
|
||||
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::analysisTimerCallback()
|
||||
{
|
||||
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 += (int64) 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 ([[maybe_unused]] const ARA::PlugIn::AudioSource* audioSource,
|
||||
[[maybe_unused]] ARA::ARAContentType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ARA::ARAContentGrade ARADocumentControllerSpecialisation::doGetAudioSourceContentGrade ([[maybe_unused]] const ARA::PlugIn::AudioSource* audioSource,
|
||||
[[maybe_unused]] ARA::ARAContentType type)
|
||||
{
|
||||
// Overriding doIsAudioSourceContentAvailable() requires overriding
|
||||
// doGetAudioSourceContentGrade() accordingly!
|
||||
jassertfalse;
|
||||
|
||||
return ARA::kARAContentGradeInitial;
|
||||
}
|
||||
|
||||
ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::doCreateAudioSourceContentReader ([[maybe_unused]] ARA::PlugIn::AudioSource* audioSource,
|
||||
[[maybe_unused]] ARA::ARAContentType type,
|
||||
[[maybe_unused]] const ARA::ARAContentTimeRange* range)
|
||||
{
|
||||
// Overriding doIsAudioSourceContentAvailable() requires overriding
|
||||
// doCreateAudioSourceContentReader() accordingly!
|
||||
jassertfalse;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ARADocumentControllerSpecialisation::doIsAudioModificationContentAvailable ([[maybe_unused]] const ARA::PlugIn::AudioModification* audioModification,
|
||||
[[maybe_unused]] ARA::ARAContentType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ARA::ARAContentGrade ARADocumentControllerSpecialisation::doGetAudioModificationContentGrade ([[maybe_unused]] const ARA::PlugIn::AudioModification* audioModification,
|
||||
[[maybe_unused]] ARA::ARAContentType type)
|
||||
{
|
||||
// Overriding doIsAudioModificationContentAvailable() requires overriding
|
||||
// doGetAudioModificationContentGrade() accordingly!
|
||||
jassertfalse;
|
||||
|
||||
return ARA::kARAContentGradeInitial;
|
||||
}
|
||||
|
||||
ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::doCreateAudioModificationContentReader ([[maybe_unused]] ARA::PlugIn::AudioModification* audioModification,
|
||||
[[maybe_unused]] ARA::ARAContentType type,
|
||||
[[maybe_unused]] const ARA::ARAContentTimeRange* range)
|
||||
{
|
||||
// Overriding doIsAudioModificationContentAvailable() requires overriding
|
||||
// doCreateAudioModificationContentReader() accordingly!
|
||||
jassertfalse;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ARADocumentControllerSpecialisation::doIsPlaybackRegionContentAvailable ([[maybe_unused]] const ARA::PlugIn::PlaybackRegion* playbackRegion,
|
||||
[[maybe_unused]] ARA::ARAContentType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ARA::ARAContentGrade ARADocumentControllerSpecialisation::doGetPlaybackRegionContentGrade ([[maybe_unused]] const ARA::PlugIn::PlaybackRegion* playbackRegion,
|
||||
[[maybe_unused]] ARA::ARAContentType type)
|
||||
{
|
||||
// Overriding doIsPlaybackRegionContentAvailable() requires overriding
|
||||
// doGetPlaybackRegionContentGrade() accordingly!
|
||||
jassertfalse;
|
||||
|
||||
return ARA::kARAContentGradeInitial;
|
||||
}
|
||||
|
||||
ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::doCreatePlaybackRegionContentReader ([[maybe_unused]] ARA::PlugIn::PlaybackRegion* playbackRegion,
|
||||
[[maybe_unused]] ARA::ARAContentType type,
|
||||
[[maybe_unused]] const ARA::ARAContentTimeRange* range)
|
||||
{
|
||||
// Overriding doIsPlaybackRegionContentAvailable() requires overriding
|
||||
// doCreatePlaybackRegionContentReader() accordingly!
|
||||
jassertfalse;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ARADocumentControllerSpecialisation::doGetPlaybackRegionHeadAndTailTime ([[maybe_unused]] const ARA::PlugIn::PlaybackRegion* playbackRegion,
|
||||
ARA::ARATimeDuration* headTime,
|
||||
ARA::ARATimeDuration* tailTime)
|
||||
{
|
||||
*headTime = 0.0;
|
||||
*tailTime = 0.0;
|
||||
}
|
||||
|
||||
bool ARADocumentControllerSpecialisation::doIsAudioSourceContentAnalysisIncomplete ([[maybe_unused]] const ARA::PlugIn::AudioSource* audioSource,
|
||||
[[maybe_unused]] ARA::ARAContentType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ARADocumentControllerSpecialisation::doRequestAudioSourceContentAnalysis ([[maybe_unused]] ARA::PlugIn::AudioSource* audioSource,
|
||||
[[maybe_unused]] std::vector<ARA::ARAContentType> const& contentTypes)
|
||||
{
|
||||
}
|
||||
|
||||
ARA::ARAInt32 ARADocumentControllerSpecialisation::doGetProcessingAlgorithmsCount() { return 0; }
|
||||
|
||||
const ARA::ARAProcessingAlgorithmProperties*
|
||||
ARADocumentControllerSpecialisation::doGetProcessingAlgorithmProperties ([[maybe_unused]] ARA::ARAInt32 algorithmIndex)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ARA::ARAInt32 ARADocumentControllerSpecialisation::doGetProcessingAlgorithmForAudioSource ([[maybe_unused]] const ARA::PlugIn::AudioSource* audioSource)
|
||||
{
|
||||
// doGetProcessingAlgorithmForAudioSource() must be implemented if the supported
|
||||
// algorithm count is greater than zero.
|
||||
if (getDocumentController()->getProcessingAlgorithmsCount() > 0)
|
||||
jassertfalse;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ARADocumentControllerSpecialisation::doRequestProcessingAlgorithmForAudioSource ([[maybe_unused]] ARA::PlugIn::AudioSource* audioSource,
|
||||
[[maybe_unused]] ARA::ARAInt32 algorithmIndex)
|
||||
{
|
||||
// doRequestProcessingAlgorithmForAudioSource() must be implemented if the supported
|
||||
// algorithm count is greater than zero.
|
||||
jassert (getDocumentController()->getProcessingAlgorithmsCount() <= 0);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
+529
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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_v<ARADocumentControllerSpecialisation, SpecialisationType>,
|
||||
"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);
|
||||
|
||||
/** Override to implement getPlaybackRegionHeadAndTailTime().
|
||||
|
||||
This function is called within
|
||||
ARA::PlugIn::DocumentControllerDelegate::doGetPlaybackRegionHeadAndTailTime.
|
||||
*/
|
||||
virtual void doGetPlaybackRegionHeadAndTailTime (const ARA::PlugIn::PlaybackRegion* playbackRegion,
|
||||
ARA::ARATimeDuration* headTime,
|
||||
ARA::ARATimeDuration* tailTime);
|
||||
|
||||
//==============================================================================
|
||||
// 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. */
|
||||
virtual ARADocument* doCreateDocument();
|
||||
|
||||
/** Override to return a custom subclass instance of ARAMusicalContext. */
|
||||
virtual ARAMusicalContext* doCreateMusicalContext (ARADocument* document,
|
||||
ARA::ARAMusicalContextHostRef hostRef);
|
||||
|
||||
/** Override to return a custom subclass instance of ARARegionSequence. */
|
||||
virtual ARARegionSequence* doCreateRegionSequence (ARADocument* document,
|
||||
ARA::ARARegionSequenceHostRef hostRef);
|
||||
|
||||
/** Override to return a custom subclass instance of ARAAudioSource. */
|
||||
virtual ARAAudioSource* doCreateAudioSource (ARADocument* document,
|
||||
ARA::ARAAudioSourceHostRef hostRef);
|
||||
|
||||
/** Override to return a custom subclass instance of ARAAudioModification. */
|
||||
virtual ARAAudioModification* doCreateAudioModification (ARAAudioSource* audioSource,
|
||||
ARA::ARAAudioModificationHostRef hostRef,
|
||||
const ARAAudioModification* optionalModificationToClone);
|
||||
|
||||
/** Override to return a custom subclass instance of ARAPlaybackRegion. */
|
||||
virtual 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
|
||||
Vendored
+71
@@ -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
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ! exactlyEqual (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);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ARADocumentListener::willBeginEditing ([[maybe_unused]] ARADocument* document) {}
|
||||
void ARADocumentListener::didEndEditing ([[maybe_unused]] ARADocument* document) {}
|
||||
void ARADocumentListener::willNotifyModelUpdates ([[maybe_unused]] ARADocument* document) {}
|
||||
void ARADocumentListener::didNotifyModelUpdates ([[maybe_unused]] ARADocument* document) {}
|
||||
void ARADocumentListener::willUpdateDocumentProperties ([[maybe_unused]] ARADocument* document,
|
||||
[[maybe_unused]] ARA::PlugIn::PropertiesPtr<ARA::ARADocumentProperties> newProperties) {}
|
||||
void ARADocumentListener::didUpdateDocumentProperties ([[maybe_unused]] ARADocument* document) {}
|
||||
void ARADocumentListener::didAddMusicalContextToDocument ([[maybe_unused]] ARADocument* document,
|
||||
[[maybe_unused]] ARAMusicalContext* musicalContext) {}
|
||||
void ARADocumentListener::willRemoveMusicalContextFromDocument ([[maybe_unused]] ARADocument* document,
|
||||
[[maybe_unused]] ARAMusicalContext* musicalContext) {}
|
||||
void ARADocumentListener::didReorderMusicalContextsInDocument ([[maybe_unused]] ARADocument* document) {}
|
||||
void ARADocumentListener::didAddRegionSequenceToDocument ([[maybe_unused]] ARADocument* document,
|
||||
[[maybe_unused]] ARARegionSequence* regionSequence) {}
|
||||
void ARADocumentListener::willRemoveRegionSequenceFromDocument ([[maybe_unused]] ARADocument* document,
|
||||
[[maybe_unused]] ARARegionSequence* regionSequence) {}
|
||||
void ARADocumentListener::didReorderRegionSequencesInDocument ([[maybe_unused]] ARADocument* document) {}
|
||||
void ARADocumentListener::didAddAudioSourceToDocument ([[maybe_unused]] ARADocument* document,
|
||||
[[maybe_unused]] ARAAudioSource* audioSource) {}
|
||||
void ARADocumentListener::willRemoveAudioSourceFromDocument ([[maybe_unused]] ARADocument* document,
|
||||
[[maybe_unused]] ARAAudioSource* audioSource) {}
|
||||
void ARADocumentListener::willDestroyDocument ([[maybe_unused]] ARADocument* document) {}
|
||||
|
||||
//==============================================================================
|
||||
void ARAMusicalContextListener::willUpdateMusicalContextProperties ([[maybe_unused]] ARAMusicalContext* musicalContext,
|
||||
[[maybe_unused]] ARA::PlugIn::PropertiesPtr<ARA::ARAMusicalContextProperties> newProperties) {}
|
||||
void ARAMusicalContextListener::didUpdateMusicalContextProperties ([[maybe_unused]] ARAMusicalContext* musicalContext) {}
|
||||
void ARAMusicalContextListener::doUpdateMusicalContextContent ([[maybe_unused]] ARAMusicalContext* musicalContext,
|
||||
[[maybe_unused]] ARAContentUpdateScopes scopeFlags) {}
|
||||
void ARAMusicalContextListener::didAddRegionSequenceToMusicalContext ([[maybe_unused]] ARAMusicalContext* musicalContext,
|
||||
[[maybe_unused]] ARARegionSequence* regionSequence) {}
|
||||
void ARAMusicalContextListener::willRemoveRegionSequenceFromMusicalContext ([[maybe_unused]] ARAMusicalContext* musicalContext,
|
||||
[[maybe_unused]] ARARegionSequence* regionSequence) {}
|
||||
void ARAMusicalContextListener::didReorderRegionSequencesInMusicalContext ([[maybe_unused]] ARAMusicalContext* musicalContext) {}
|
||||
void ARAMusicalContextListener::willDestroyMusicalContext ([[maybe_unused]] ARAMusicalContext* musicalContext) {}
|
||||
|
||||
//==============================================================================
|
||||
void ARAPlaybackRegionListener::willUpdatePlaybackRegionProperties ([[maybe_unused]] ARAPlaybackRegion* playbackRegion,
|
||||
[[maybe_unused]] ARA::PlugIn::PropertiesPtr<ARA::ARAPlaybackRegionProperties> newProperties) {}
|
||||
void ARAPlaybackRegionListener::didUpdatePlaybackRegionProperties ([[maybe_unused]] ARAPlaybackRegion* playbackRegion) {}
|
||||
void ARAPlaybackRegionListener::didUpdatePlaybackRegionContent ([[maybe_unused]] ARAPlaybackRegion* playbackRegion,
|
||||
[[maybe_unused]] ARAContentUpdateScopes scopeFlags) {}
|
||||
void ARAPlaybackRegionListener::willDestroyPlaybackRegion ([[maybe_unused]] ARAPlaybackRegion* playbackRegion) {}
|
||||
|
||||
//==============================================================================
|
||||
void ARARegionSequenceListener::willUpdateRegionSequenceProperties ([[maybe_unused]] ARARegionSequence* regionSequence,
|
||||
[[maybe_unused]] ARA::PlugIn::PropertiesPtr<ARA::ARARegionSequenceProperties> newProperties) {}
|
||||
void ARARegionSequenceListener::didUpdateRegionSequenceProperties ([[maybe_unused]] ARARegionSequence* regionSequence) {}
|
||||
void ARARegionSequenceListener::willRemovePlaybackRegionFromRegionSequence ([[maybe_unused]] ARARegionSequence* regionSequence,
|
||||
[[maybe_unused]] ARAPlaybackRegion* playbackRegion) {}
|
||||
void ARARegionSequenceListener::didAddPlaybackRegionToRegionSequence ([[maybe_unused]] ARARegionSequence* regionSequence,
|
||||
[[maybe_unused]] ARAPlaybackRegion* playbackRegion) {}
|
||||
void ARARegionSequenceListener::willDestroyRegionSequence ([[maybe_unused]] ARARegionSequence* regionSequence) {}
|
||||
|
||||
//==============================================================================
|
||||
void ARAAudioSourceListener::willUpdateAudioSourceProperties ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] ARA::PlugIn::PropertiesPtr<ARA::ARAAudioSourceProperties> newProperties) {}
|
||||
void ARAAudioSourceListener::didUpdateAudioSourceProperties ([[maybe_unused]] ARAAudioSource* audioSource) {}
|
||||
void ARAAudioSourceListener::doUpdateAudioSourceContent ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] ARAContentUpdateScopes scopeFlags) {}
|
||||
void ARAAudioSourceListener::didUpdateAudioSourceAnalysisProgress ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] ARA::ARAAnalysisProgressState state,
|
||||
[[maybe_unused]] float progress) {}
|
||||
void ARAAudioSourceListener::willEnableAudioSourceSamplesAccess ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] bool enable) {}
|
||||
void ARAAudioSourceListener::didEnableAudioSourceSamplesAccess ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] bool enable) {}
|
||||
void ARAAudioSourceListener::willDeactivateAudioSourceForUndoHistory ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] bool deactivate) {}
|
||||
void ARAAudioSourceListener::didDeactivateAudioSourceForUndoHistory ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] bool deactivate) {}
|
||||
void ARAAudioSourceListener::didAddAudioModificationToAudioSource ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] ARAAudioModification* audioModification) {}
|
||||
void ARAAudioSourceListener::willRemoveAudioModificationFromAudioSource ([[maybe_unused]] ARAAudioSource* audioSource,
|
||||
[[maybe_unused]] ARAAudioModification* audioModification) {}
|
||||
void ARAAudioSourceListener::willDestroyAudioSource ([[maybe_unused]] ARAAudioSource* audioSource) {}
|
||||
|
||||
//==============================================================================
|
||||
void ARAAudioModificationListener::willUpdateAudioModificationProperties ([[maybe_unused]] ARAAudioModification* audioModification,
|
||||
[[maybe_unused]] ARA::PlugIn::PropertiesPtr<ARA::ARAAudioModificationProperties> newProperties) {}
|
||||
void ARAAudioModificationListener::didUpdateAudioModificationProperties ([[maybe_unused]] ARAAudioModification* audioModification) {}
|
||||
void ARAAudioModificationListener::didUpdateAudioModificationContent ([[maybe_unused]] ARAAudioModification* audioModification,
|
||||
[[maybe_unused]] ARAContentUpdateScopes scopeFlags) {}
|
||||
void ARAAudioModificationListener::willDeactivateAudioModificationForUndoHistory ([[maybe_unused]] ARAAudioModification* audioModification,
|
||||
[[maybe_unused]] bool deactivate) {}
|
||||
void ARAAudioModificationListener::didDeactivateAudioModificationForUndoHistory ([[maybe_unused]] ARAAudioModification* audioModification,
|
||||
[[maybe_unused]] bool deactivate) {}
|
||||
void ARAAudioModificationListener::didAddPlaybackRegionToAudioModification ([[maybe_unused]] ARAAudioModification* audioModification,
|
||||
[[maybe_unused]] ARAPlaybackRegion* playbackRegion) {}
|
||||
void ARAAudioModificationListener::willRemovePlaybackRegionFromAudioModification ([[maybe_unused]] ARAAudioModification* audioModification,
|
||||
[[maybe_unused]] ARAPlaybackRegion* playbackRegion) {}
|
||||
void ARAAudioModificationListener::willDestroyAudioModification ([[maybe_unused]] ARAAudioModification* audioModification) {}
|
||||
|
||||
} // namespace juce
|
||||
+974
@@ -0,0 +1,974 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ARADocumentController;
|
||||
class ARADocument;
|
||||
class ARAMusicalContext;
|
||||
class ARARegionSequence;
|
||||
class ARAAudioSource;
|
||||
class ARAAudioModification;
|
||||
class ARAPlaybackRegion;
|
||||
|
||||
/** Base class used by the JUCE ARA model objects to provide listenable interfaces.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
template <class ListenerType>
|
||||
class JUCE_API ARAListenableModelClass
|
||||
{
|
||||
public:
|
||||
/** Constructor. */
|
||||
ARAListenableModelClass() = default;
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~ARAListenableModelClass() = default;
|
||||
|
||||
/** Subscribe \p l to notified by changes to the object.
|
||||
@param l The listener instance.
|
||||
*/
|
||||
void addListener (ListenerType* l) { listeners.add (l); }
|
||||
|
||||
/** Unsubscribe \p l from object notifications.
|
||||
@param l The listener instance.
|
||||
*/
|
||||
void removeListener (ListenerType* l) { listeners.remove (l); }
|
||||
|
||||
/** Call the provided callback for each of the added listeners. */
|
||||
template <typename Callback>
|
||||
void notifyListeners (Callback&& callback)
|
||||
{
|
||||
listeners.call (callback);
|
||||
}
|
||||
|
||||
private:
|
||||
ListenerList<ListenerType> listeners;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ARAListenableModelClass)
|
||||
};
|
||||
|
||||
/** Create a derived implementation of this class and pass it to ARAObject::visit() to retrieve the
|
||||
concrete type of a model object.
|
||||
|
||||
Combined with ARAObject::traverse() on the ARADocument object it is possible to discover the
|
||||
entire model graph.
|
||||
|
||||
Note that the references passed to the visit member functions are only guaranteed to live for
|
||||
the duration of the function call, so don't store pointers to these objects!
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class ARAObjectVisitor
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~ARAObjectVisitor() = default;
|
||||
|
||||
/** Called when visiting an ARADocument object. */
|
||||
virtual void visitDocument (juce::ARADocument&) {}
|
||||
|
||||
/** Called when visiting an ARAMusicalContext object. */
|
||||
virtual void visitMusicalContext (juce::ARAMusicalContext&) {}
|
||||
|
||||
/** Called when visiting an ARARegionSequence object. */
|
||||
virtual void visitRegionSequence (juce::ARARegionSequence&) {}
|
||||
|
||||
/** Called when visiting an ARAPlaybackRegion object. */
|
||||
virtual void visitPlaybackRegion (juce::ARAPlaybackRegion&) {}
|
||||
|
||||
/** Called when visiting an ARAAudioModification object. */
|
||||
virtual void visitAudioModification (juce::ARAAudioModification&) {}
|
||||
|
||||
/** Called when visiting an ARAAudioSource object. */
|
||||
virtual void visitAudioSource (juce::ARAAudioSource&) {}
|
||||
};
|
||||
|
||||
/** Common base class for all JUCE ARA model objects to aid with the discovery and traversal of the
|
||||
entire ARA model graph.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class ARAObject
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~ARAObject() = default;
|
||||
|
||||
/** Returns the number of ARA model objects aggregated by this object. Objects that are merely
|
||||
referred to, but not aggregated by the current object are not included in this count, e.g.
|
||||
a referenced RegionSequence does not count as a child of the referring PlaybackRegion.
|
||||
|
||||
See the ARA documentation's ARA Model Graph Overview for more details.
|
||||
*/
|
||||
virtual size_t getNumChildren() const noexcept = 0;
|
||||
|
||||
/** Returns the child object associated with the given index.
|
||||
|
||||
The index should be smaller than the value returned by getNumChildren().
|
||||
|
||||
Note that the index of a particular object may change when the ARA model graph is edited.
|
||||
*/
|
||||
virtual ARAObject* getChild (size_t index) = 0;
|
||||
|
||||
/** Returns the ARA model object that aggregates this object.
|
||||
|
||||
Returns nullptr for the ARADocument root object.
|
||||
*/
|
||||
virtual ARAObject* getParent() = 0;
|
||||
|
||||
/** Implements a depth first traversal of the ARA model graph starting from the current object,
|
||||
and visiting its children recursively.
|
||||
|
||||
The provided function should accept a single ARAObject& parameter.
|
||||
*/
|
||||
template <typename Fn>
|
||||
void traverse (Fn&& fn)
|
||||
{
|
||||
fn (*this);
|
||||
|
||||
for (size_t i = 0; i < getNumChildren(); ++i)
|
||||
{
|
||||
getChild (i)->traverse (fn);
|
||||
}
|
||||
}
|
||||
|
||||
/** Allows the retrieval of the concrete type of a model object.
|
||||
|
||||
To use this, create a new class derived from ARAObjectVisitor and override its functions
|
||||
depending on which concrete types you are interested in.
|
||||
|
||||
Calling this function inside the function passed to ARAObject::traverse() allows you to
|
||||
map the entire ARA model graph.
|
||||
*/
|
||||
virtual void visit (ARAObjectVisitor& visitor) = 0;
|
||||
};
|
||||
|
||||
/** A base class for listeners that want to know about changes to an ARADocument object.
|
||||
|
||||
Use ARADocument::addListener() to register your listener with an ARADocument.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARADocumentListener
|
||||
{
|
||||
public:
|
||||
/** Destructor */
|
||||
virtual ~ARADocumentListener() = default;
|
||||
|
||||
/** Called before the document enters an editing state.
|
||||
@param document The document about to enter an editing state.
|
||||
*/
|
||||
virtual void willBeginEditing (ARADocument* document);
|
||||
|
||||
/** Called after the document exits an editing state.
|
||||
@param document The document about exit an editing state.
|
||||
*/
|
||||
virtual void didEndEditing (ARADocument* document);
|
||||
|
||||
/** Called before sending model updates do the host.
|
||||
@param document The document whose model updates are about to be sent.
|
||||
*/
|
||||
virtual void willNotifyModelUpdates (ARADocument* document);
|
||||
|
||||
/** Called after sending model updates do the host.
|
||||
@param document The document whose model updates have just been sent.
|
||||
*/
|
||||
virtual void didNotifyModelUpdates (ARADocument* document);
|
||||
|
||||
/** Called before the document's properties are updated.
|
||||
@param document The document whose properties will be updated.
|
||||
@param newProperties The document properties that will be assigned to \p document.
|
||||
*/
|
||||
virtual void willUpdateDocumentProperties (ARADocument* document,
|
||||
ARA::PlugIn::PropertiesPtr<ARA::ARADocumentProperties> newProperties);
|
||||
|
||||
/** Called after the document's properties are updated.
|
||||
@param document The document whose properties were updated.
|
||||
*/
|
||||
virtual void didUpdateDocumentProperties (ARADocument* document);
|
||||
|
||||
/** Called after a musical context is added to the document.
|
||||
@param document The document that \p musicalContext was added to.
|
||||
@param musicalContext The musical context that was added to \p document.
|
||||
*/
|
||||
virtual void didAddMusicalContextToDocument (ARADocument* document, ARAMusicalContext* musicalContext);
|
||||
|
||||
/** Called before a musical context is removed from the document.
|
||||
@param document The document that \p musicalContext will be removed from.
|
||||
@param musicalContext The musical context that will be removed from \p document.
|
||||
*/
|
||||
virtual void willRemoveMusicalContextFromDocument (ARADocument* document, ARAMusicalContext* musicalContext);
|
||||
|
||||
/** Called after the musical contexts are reordered in an ARA document
|
||||
|
||||
Musical contexts are sorted by their order index -
|
||||
this callback signals a change in this ordering within the document.
|
||||
|
||||
@param document The document with reordered musical contexts.
|
||||
*/
|
||||
virtual void didReorderMusicalContextsInDocument (ARADocument* document);
|
||||
|
||||
/** Called after a region sequence is added to the document.
|
||||
@param document The document that \p regionSequence was added to.
|
||||
@param regionSequence The region sequence that was added to \p document.
|
||||
*/
|
||||
virtual void didAddRegionSequenceToDocument (ARADocument* document, ARARegionSequence* regionSequence);
|
||||
|
||||
/** Called before a region sequence is removed from the document.
|
||||
@param document The document that \p regionSequence will be removed from.
|
||||
@param regionSequence The region sequence that will be removed from \p document.
|
||||
*/
|
||||
virtual void willRemoveRegionSequenceFromDocument (ARADocument* document, ARARegionSequence* regionSequence);
|
||||
|
||||
/** Called after the region sequences are reordered in an ARA document
|
||||
|
||||
Region sequences are sorted by their order index -
|
||||
this callback signals a change in this ordering within the document.
|
||||
|
||||
@param document The document with reordered region sequences.
|
||||
*/
|
||||
virtual void didReorderRegionSequencesInDocument (ARADocument* document);
|
||||
|
||||
/** Called after an audio source is added to the document.
|
||||
@param document The document that \p audioSource was added to.
|
||||
@param audioSource The audio source that was added to \p document.
|
||||
*/
|
||||
virtual void didAddAudioSourceToDocument (ARADocument* document, ARAAudioSource* audioSource);
|
||||
|
||||
/** Called before an audio source is removed from the document.
|
||||
@param document The document that \p audioSource will be removed from .
|
||||
@param audioSource The audio source that will be removed from \p document.
|
||||
*/
|
||||
virtual void willRemoveAudioSourceFromDocument (ARADocument* document, ARAAudioSource* audioSource);
|
||||
|
||||
/** Called before the document is destroyed by the ARA host.
|
||||
@param document The document that will be destroyed.
|
||||
*/
|
||||
virtual void willDestroyDocument (ARADocument* document);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Base class representing an ARA document.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARADocument : public ARA::PlugIn::Document,
|
||||
public ARAListenableModelClass<ARADocumentListener>,
|
||||
public ARAObject
|
||||
{
|
||||
public:
|
||||
using PropertiesPtr = ARA::PlugIn::PropertiesPtr<ARA::ARADocumentProperties>;
|
||||
using Listener = ARADocumentListener;
|
||||
|
||||
using ARA::PlugIn::Document::Document;
|
||||
|
||||
/** Returns the result of ARA::PlugIn::Document::getAudioSources() with the pointers within
|
||||
cast to ARAAudioSource*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateAudioSource(), then
|
||||
you can use the template parameter to cast the pointers to your subclass of ARAAudioSource.
|
||||
*/
|
||||
template <typename AudioSource_t = ARAAudioSource>
|
||||
const std::vector<AudioSource_t*>& getAudioSources() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::Document::getAudioSources<AudioSource_t>();
|
||||
}
|
||||
|
||||
/** Returns the result of ARA::PlugIn::Document::getMusicalContexts() with the pointers within
|
||||
cast to ARAMusicalContext*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateMusicalContext(), then
|
||||
you can use the template parameter to cast the pointers to your subclass of ARAMusicalContext.
|
||||
*/
|
||||
template <typename MusicalContext_t = ARAMusicalContext>
|
||||
const std::vector<MusicalContext_t*>& getMusicalContexts() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::Document::getMusicalContexts<MusicalContext_t>();
|
||||
}
|
||||
|
||||
/** Returns the result of ARA::PlugIn::Document::getRegionSequences() with the pointers within
|
||||
cast to ARARegionSequence*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateRegionSequence(), then
|
||||
you can use the template parameter to cast the pointers to your subclass of ARARegionSequence.
|
||||
*/
|
||||
template <typename RegionSequence_t = ARARegionSequence>
|
||||
const std::vector<RegionSequence_t*>& getRegionSequences() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::Document::getRegionSequences<RegionSequence_t>();
|
||||
}
|
||||
|
||||
size_t getNumChildren() const noexcept override;
|
||||
|
||||
ARAObject* getChild (size_t index) override;
|
||||
|
||||
ARAObject* getParent() override { return nullptr; }
|
||||
|
||||
void visit (ARAObjectVisitor& visitor) override { visitor.visitDocument (*this); }
|
||||
};
|
||||
|
||||
/** A base class for listeners that want to know about changes to an ARAMusicalContext object.
|
||||
|
||||
Use ARAMusicalContext::addListener() to register your listener with an ARAMusicalContext.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAMusicalContextListener
|
||||
{
|
||||
public:
|
||||
virtual ~ARAMusicalContextListener() = default;
|
||||
|
||||
/** Called before the musical context's properties are updated.
|
||||
@param musicalContext The musical context whose properties will be updated.
|
||||
@param newProperties The musical context properties that will be assigned to \p musicalContext.
|
||||
*/
|
||||
virtual void willUpdateMusicalContextProperties (ARAMusicalContext* musicalContext,
|
||||
ARA::PlugIn::PropertiesPtr<ARA::ARAMusicalContextProperties> newProperties);
|
||||
|
||||
/** Called after the musical context's properties are updated by the host.
|
||||
@param musicalContext The musical context whose properties were updated.
|
||||
*/
|
||||
virtual void didUpdateMusicalContextProperties (ARAMusicalContext* musicalContext);
|
||||
|
||||
/** Called when the musical context's content (i.e tempo entries or chords) changes.
|
||||
@param musicalContext The musical context with updated content.
|
||||
@param scopeFlags The scope of the content update indicating what has changed.
|
||||
*/
|
||||
virtual void doUpdateMusicalContextContent (ARAMusicalContext* musicalContext, ARAContentUpdateScopes scopeFlags);
|
||||
|
||||
/** Called after a region sequence is added to the musical context.
|
||||
@param musicalContext The musical context that \p regionSequence was added to.
|
||||
@param regionSequence The region sequence that was added to \p musicalContext.
|
||||
*/
|
||||
virtual void didAddRegionSequenceToMusicalContext (ARAMusicalContext* musicalContext, ARARegionSequence* regionSequence);
|
||||
|
||||
/** Called before a region sequence is removed from the musical context.
|
||||
@param musicalContext The musical context that \p regionSequence will be removed from.
|
||||
@param regionSequence The region sequence that will be removed from \p musicalContext.
|
||||
*/
|
||||
virtual void willRemoveRegionSequenceFromMusicalContext (ARAMusicalContext* musicalContext,
|
||||
ARARegionSequence* regionSequence);
|
||||
|
||||
/** Called after the region sequences are reordered in an ARA MusicalContext
|
||||
|
||||
Region sequences are sorted by their order index -
|
||||
this callback signals a change in this ordering within the musical context.
|
||||
|
||||
@param musicalContext The musical context with reordered region sequences.
|
||||
*/
|
||||
virtual void didReorderRegionSequencesInMusicalContext (ARAMusicalContext* musicalContext);
|
||||
|
||||
/** Called before the musical context is destroyed.
|
||||
@param musicalContext The musical context that will be destroyed.
|
||||
*/
|
||||
virtual void willDestroyMusicalContext (ARAMusicalContext* musicalContext);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Base class representing an ARA musical context.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAMusicalContext : public ARA::PlugIn::MusicalContext,
|
||||
public ARAListenableModelClass<ARAMusicalContextListener>,
|
||||
public ARAObject
|
||||
{
|
||||
public:
|
||||
using PropertiesPtr = ARA::PlugIn::PropertiesPtr<ARA::ARAMusicalContextProperties>;
|
||||
using Listener = ARAMusicalContextListener;
|
||||
|
||||
using ARA::PlugIn::MusicalContext::MusicalContext;
|
||||
|
||||
/** Returns the result of ARA::PlugIn::MusicalContext::getDocument() with the pointer cast
|
||||
to ARADocument*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateDocument(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARADocument.
|
||||
*/
|
||||
template <typename Document_t = ARADocument>
|
||||
Document_t* getDocument() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::MusicalContext::getDocument<Document_t>();
|
||||
}
|
||||
|
||||
/** Returns the result of ARA::PlugIn::MusicalContext::getRegionSequences() with the pointers
|
||||
within cast to ARARegionSequence*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateRegionSequence(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARARegionSequence.
|
||||
*/
|
||||
template <typename RegionSequence_t = ARARegionSequence>
|
||||
const std::vector<RegionSequence_t*>& getRegionSequences() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::MusicalContext::getRegionSequences<RegionSequence_t>();
|
||||
}
|
||||
|
||||
size_t getNumChildren() const noexcept override { return 0; }
|
||||
|
||||
ARAObject* getChild (size_t) override { return nullptr; }
|
||||
|
||||
ARAObject* getParent() override { return getDocument(); }
|
||||
|
||||
void visit (ARAObjectVisitor& visitor) override { visitor.visitMusicalContext (*this); }
|
||||
};
|
||||
|
||||
/** A base class for listeners that want to know about changes to an ARAPlaybackRegion object.
|
||||
|
||||
Use ARAPlaybackRegion::addListener() to register your listener with an ARAPlaybackRegion.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAPlaybackRegionListener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~ARAPlaybackRegionListener() = default;
|
||||
|
||||
/** Called before the playback region's properties are updated.
|
||||
@param playbackRegion The playback region whose properties will be updated.
|
||||
@param newProperties The playback region properties that will be assigned to \p playbackRegion.
|
||||
*/
|
||||
virtual void willUpdatePlaybackRegionProperties (ARAPlaybackRegion* playbackRegion,
|
||||
ARA::PlugIn::PropertiesPtr<ARA::ARAPlaybackRegionProperties> newProperties);
|
||||
|
||||
/** Called after the playback region's properties are updated.
|
||||
@param playbackRegion The playback region whose properties were updated.
|
||||
*/
|
||||
virtual void didUpdatePlaybackRegionProperties (ARAPlaybackRegion* playbackRegion);
|
||||
|
||||
/** Called when the playback region's content (i.e. samples or notes) changes.
|
||||
@param playbackRegion The playback region with updated content.
|
||||
@param scopeFlags The scope of the content update.
|
||||
*/
|
||||
virtual void didUpdatePlaybackRegionContent (ARAPlaybackRegion* playbackRegion,
|
||||
ARAContentUpdateScopes scopeFlags);
|
||||
|
||||
/** Called before the playback region is destroyed.
|
||||
@param playbackRegion The playback region that will be destroyed.
|
||||
*/
|
||||
virtual void willDestroyPlaybackRegion (ARAPlaybackRegion* playbackRegion);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Base class representing an ARA playback region.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAPlaybackRegion : public ARA::PlugIn::PlaybackRegion,
|
||||
public ARAListenableModelClass<ARAPlaybackRegionListener>,
|
||||
public ARAObject
|
||||
{
|
||||
public:
|
||||
using PropertiesPtr = ARA::PlugIn::PropertiesPtr<ARA::ARAPlaybackRegionProperties>;
|
||||
using Listener = ARAPlaybackRegionListener;
|
||||
|
||||
using ARA::PlugIn::PlaybackRegion::PlaybackRegion;
|
||||
|
||||
/** Returns the result of ARA::PlugIn::PlaybackRegion::getAudioModification() with the pointer cast
|
||||
to ARAAudioModification*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateAudioModification(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARAAudioModification.
|
||||
*/
|
||||
template <typename AudioModification_t = ARAAudioModification>
|
||||
AudioModification_t* getAudioModification() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::PlaybackRegion::getAudioModification<AudioModification_t>();
|
||||
}
|
||||
|
||||
/** Returns the result of ARA::PlugIn::PlaybackRegion::getRegionSequence() with the pointer cast
|
||||
to ARARegionSequence*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateRegionSequence(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARARegionSequence.
|
||||
*/
|
||||
template <typename RegionSequence_t = ARARegionSequence>
|
||||
RegionSequence_t* getRegionSequence() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::PlaybackRegion::getRegionSequence<RegionSequence_t>();
|
||||
}
|
||||
|
||||
size_t getNumChildren() const noexcept override { return 0; }
|
||||
|
||||
ARAObject* getChild (size_t) override { return nullptr; }
|
||||
|
||||
ARAObject* getParent() override;
|
||||
|
||||
void visit (ARAObjectVisitor& visitor) override { visitor.visitPlaybackRegion (*this); }
|
||||
|
||||
/** Used in getTimeRange to indicate whether the head and tail times should be included in the result.
|
||||
*/
|
||||
enum class IncludeHeadAndTail { no, yes };
|
||||
|
||||
/** Returns the playback time range of this playback region.
|
||||
@param includeHeadAndTail Whether or not the range includes the head and tail
|
||||
time of all playback regions in the sequence.
|
||||
*/
|
||||
Range<double> getTimeRange (IncludeHeadAndTail includeHeadAndTail = IncludeHeadAndTail::no) const;
|
||||
|
||||
/** Returns the playback sample range of this playback region.
|
||||
@param sampleRate The rate at which the sample position should be calculated from
|
||||
the time range.
|
||||
@param includeHeadAndTail Whether or not the range includes the head and tail
|
||||
time of all playback regions in the sequence.
|
||||
*/
|
||||
Range<int64> getSampleRange (double sampleRate, IncludeHeadAndTail includeHeadAndTail = IncludeHeadAndTail::no) const;
|
||||
|
||||
/** Get the head length in seconds before the start of the region's playback time. */
|
||||
double getHeadTime() const;
|
||||
|
||||
/** Get the tail length in seconds after the end of the region's playback time. */
|
||||
double getTailTime() const;
|
||||
|
||||
/** Notify the ARA host and any listeners of a content update initiated by the plug-in.
|
||||
This must be called by the plug-in model management code on the message thread whenever updating
|
||||
the internal content representation, such as after the user edited the pitch of a note in the
|
||||
underlying audio modification.
|
||||
Listeners will be notified immediately. If \p notifyARAHost is true, a notification to the host
|
||||
will be enqueued and sent out the next time it polls for updates.
|
||||
|
||||
@param scopeFlags The scope of the content update.
|
||||
@param notifyARAHost If true, the ARA host will be notified of the content change.
|
||||
*/
|
||||
void notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost);
|
||||
};
|
||||
|
||||
/** A base class for listeners that want to know about changes to an ARARegionSequence object.
|
||||
|
||||
Use ARARegionSequence::addListener() to register your listener with an ARARegionSequence.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARARegionSequenceListener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~ARARegionSequenceListener() = default;
|
||||
|
||||
/** Called before the region sequence's properties are updated.
|
||||
@param regionSequence The region sequence whose properties will be updated.
|
||||
@param newProperties The region sequence properties that will be assigned to \p regionSequence.
|
||||
*/
|
||||
virtual void willUpdateRegionSequenceProperties (ARARegionSequence* regionSequence,
|
||||
ARA::PlugIn::PropertiesPtr<ARA::ARARegionSequenceProperties> newProperties);
|
||||
|
||||
/** Called after the region sequence's properties are updated.
|
||||
@param regionSequence The region sequence whose properties were updated.
|
||||
*/
|
||||
virtual void didUpdateRegionSequenceProperties (ARARegionSequence* regionSequence);
|
||||
|
||||
/** Called before a playback region is removed from the region sequence.
|
||||
@param regionSequence The region sequence that \p playbackRegion will be removed from.
|
||||
@param playbackRegion The playback region that will be removed from \p regionSequence.
|
||||
*/
|
||||
virtual void willRemovePlaybackRegionFromRegionSequence (ARARegionSequence* regionSequence,
|
||||
ARAPlaybackRegion* playbackRegion);
|
||||
|
||||
/** Called after a playback region is added to the region sequence.
|
||||
@param regionSequence The region sequence that \p playbackRegion was added to.
|
||||
@param playbackRegion The playback region that was added to \p regionSequence.
|
||||
*/
|
||||
virtual void didAddPlaybackRegionToRegionSequence (ARARegionSequence* regionSequence,
|
||||
ARAPlaybackRegion* playbackRegion);
|
||||
|
||||
/** Called before the region sequence is destroyed.
|
||||
@param regionSequence The region sequence that will be destroyed.
|
||||
*/
|
||||
virtual void willDestroyRegionSequence (ARARegionSequence* regionSequence);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Base class representing an ARA region sequence.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARARegionSequence : public ARA::PlugIn::RegionSequence,
|
||||
public ARAListenableModelClass<ARARegionSequenceListener>,
|
||||
public ARAObject
|
||||
{
|
||||
public:
|
||||
using PropertiesPtr = ARA::PlugIn::PropertiesPtr<ARA::ARARegionSequenceProperties>;
|
||||
using Listener = ARARegionSequenceListener;
|
||||
|
||||
using ARA::PlugIn::RegionSequence::RegionSequence;
|
||||
|
||||
/** Returns the result of ARA::PlugIn::RegionSequence::getDocument() with the pointer cast
|
||||
to ARADocument*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateDocument(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARADocument.
|
||||
*/
|
||||
template <typename Document_t = ARADocument>
|
||||
Document_t* getDocument() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::RegionSequence::getDocument<Document_t>();
|
||||
}
|
||||
|
||||
/** Returns the result of ARA::PlugIn::RegionSequence::getMusicalContext() with the pointer cast
|
||||
to ARAMusicalContext*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateMusicalContext(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARAMusicalContext.
|
||||
*/
|
||||
template <typename MusicalContext_t = ARAMusicalContext>
|
||||
MusicalContext_t* getMusicalContext() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::RegionSequence::getMusicalContext<MusicalContext_t>();
|
||||
}
|
||||
|
||||
/** Returns the result of ARA::PlugIn::RegionSequence::getPlaybackRegions() with the pointers within cast
|
||||
to ARAPlaybackRegion*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreatePlaybackRegion(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARAPlaybackRegion.
|
||||
*/
|
||||
template <typename PlaybackRegion_t = ARAPlaybackRegion>
|
||||
const std::vector<PlaybackRegion_t*>& getPlaybackRegions() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::RegionSequence::getPlaybackRegions<PlaybackRegion_t>();
|
||||
}
|
||||
|
||||
size_t getNumChildren() const noexcept override;
|
||||
|
||||
ARAObject* getChild (size_t index) override;
|
||||
|
||||
ARAObject* getParent() override { return getDocument(); }
|
||||
|
||||
void visit (ARAObjectVisitor& visitor) override { visitor.visitRegionSequence (*this); }
|
||||
|
||||
/** Returns the playback time range covered by the regions in this sequence.
|
||||
@param includeHeadAndTail Whether or not the range includes the playback region's head and tail time.
|
||||
*/
|
||||
Range<double> getTimeRange (ARAPlaybackRegion::IncludeHeadAndTail includeHeadAndTail = ARAPlaybackRegion::IncludeHeadAndTail::no) const;
|
||||
|
||||
/** If all audio sources used by the playback regions in this region sequence have the same
|
||||
sample rate, this rate is returned here, otherwise 0.0 is returned.
|
||||
|
||||
If the region sequence has no playback regions, this also returns 0.0.
|
||||
*/
|
||||
double getCommonSampleRate() const;
|
||||
};
|
||||
|
||||
/** A base class for listeners that want to know about changes to an ARAAudioSource object.
|
||||
|
||||
Use ARAAudioSource::addListener() to register your listener with an ARAAudioSource.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAAudioSourceListener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~ARAAudioSourceListener() = default;
|
||||
|
||||
/** Called before the audio source's properties are updated.
|
||||
@param audioSource The audio source whose properties will be updated.
|
||||
@param newProperties The audio source properties that will be assigned to \p audioSource.
|
||||
*/
|
||||
virtual void willUpdateAudioSourceProperties (ARAAudioSource* audioSource,
|
||||
ARA::PlugIn::PropertiesPtr<ARA::ARAAudioSourceProperties> newProperties);
|
||||
|
||||
/** Called after the audio source's properties are updated.
|
||||
@param audioSource The audio source whose properties were updated.
|
||||
*/
|
||||
virtual void didUpdateAudioSourceProperties (ARAAudioSource* audioSource);
|
||||
|
||||
/** Called when the audio source's content (i.e. samples or notes) changes.
|
||||
@param audioSource The audio source with updated content.
|
||||
@param scopeFlags The scope of the content update.
|
||||
*/
|
||||
virtual void doUpdateAudioSourceContent (ARAAudioSource* audioSource, ARAContentUpdateScopes scopeFlags);
|
||||
|
||||
/** Called to notify progress when an audio source is being analyzed.
|
||||
@param audioSource The audio source being analyzed.
|
||||
@param state Indicates start, intermediate update or completion of the analysis.
|
||||
@param progress Progress normalized to the 0..1 range.
|
||||
*/
|
||||
virtual void didUpdateAudioSourceAnalysisProgress (ARAAudioSource* audioSource,
|
||||
ARA::ARAAnalysisProgressState state,
|
||||
float progress);
|
||||
|
||||
/** Called before access to an audio source's samples is enabled or disabled.
|
||||
@param audioSource The audio source whose sample access state will be changed.
|
||||
@param enable A bool indicating whether or not sample access will be enabled or disabled.
|
||||
*/
|
||||
virtual void willEnableAudioSourceSamplesAccess (ARAAudioSource* audioSource,
|
||||
bool enable);
|
||||
|
||||
/** Called after access to an audio source's samples is enabled or disabled.
|
||||
@param audioSource The audio source whose sample access state was changed.
|
||||
@param enable A bool indicating whether or not sample access was enabled or disabled.
|
||||
*/
|
||||
virtual void didEnableAudioSourceSamplesAccess (ARAAudioSource* audioSource,
|
||||
bool enable);
|
||||
|
||||
/** Called before an audio source is activated or deactivated when being removed / added from the host's undo history.
|
||||
@param audioSource The audio source that will be activated or deactivated
|
||||
@param deactivate A bool indicating whether \p audioSource was deactivated or activated.
|
||||
*/
|
||||
virtual void willDeactivateAudioSourceForUndoHistory (ARAAudioSource* audioSource,
|
||||
bool deactivate);
|
||||
|
||||
/** Called after an audio source is activated or deactivated when being removed / added from the host's undo history.
|
||||
@param audioSource The audio source that was activated or deactivated
|
||||
@param deactivate A bool indicating whether \p audioSource was deactivated or activated.
|
||||
*/
|
||||
virtual void didDeactivateAudioSourceForUndoHistory (ARAAudioSource* audioSource,
|
||||
bool deactivate);
|
||||
|
||||
/** Called after an audio modification is added to the audio source.
|
||||
@param audioSource The region sequence that \p audioModification was added to.
|
||||
@param audioModification The playback region that was added to \p audioSource.
|
||||
*/
|
||||
virtual void didAddAudioModificationToAudioSource (ARAAudioSource* audioSource,
|
||||
ARAAudioModification* audioModification);
|
||||
|
||||
/** Called before an audio modification is removed from the audio source.
|
||||
@param audioSource The audio source that \p audioModification will be removed from.
|
||||
@param audioModification The audio modification that will be removed from \p audioSource.
|
||||
*/
|
||||
virtual void willRemoveAudioModificationFromAudioSource (ARAAudioSource* audioSource,
|
||||
ARAAudioModification* audioModification);
|
||||
|
||||
/** Called before the audio source is destroyed.
|
||||
@param audioSource The audio source that will be destroyed.
|
||||
*/
|
||||
virtual void willDestroyAudioSource (ARAAudioSource* audioSource);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Base class representing an ARA audio source.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAAudioSource : public ARA::PlugIn::AudioSource,
|
||||
public ARAListenableModelClass<ARAAudioSourceListener>,
|
||||
public ARAObject
|
||||
{
|
||||
public:
|
||||
using PropertiesPtr = ARA::PlugIn::PropertiesPtr<ARA::ARAAudioSourceProperties>;
|
||||
using ARAAnalysisProgressState = ARA::ARAAnalysisProgressState;
|
||||
using Listener = ARAAudioSourceListener;
|
||||
|
||||
using ARA::PlugIn::AudioSource::AudioSource;
|
||||
|
||||
/** Returns the result of ARA::PlugIn::AudioSource::getDocument() with the pointer cast
|
||||
to ARADocument*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateDocument(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARADocument.
|
||||
*/
|
||||
template <typename Document_t = ARADocument>
|
||||
Document_t* getDocument() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::AudioSource::getDocument<Document_t>();
|
||||
}
|
||||
|
||||
/** Returns the result of ARA::PlugIn::AudioSource::getAudioModifications() with the pointers
|
||||
within cast to ARAAudioModification*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateAudioModification(),
|
||||
then you can use the template parameter to cast the pointers to your subclass of
|
||||
ARAAudioModification.
|
||||
*/
|
||||
template <typename AudioModification_t = ARAAudioModification>
|
||||
const std::vector<AudioModification_t*>& getAudioModifications() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::AudioSource::getAudioModifications<AudioModification_t>();
|
||||
}
|
||||
|
||||
size_t getNumChildren() const noexcept override;
|
||||
|
||||
ARAObject* getChild (size_t index) override;
|
||||
|
||||
ARAObject* getParent() override { return getDocument(); }
|
||||
|
||||
void visit (ARAObjectVisitor& visitor) override { visitor.visitAudioSource (*this); }
|
||||
|
||||
/** Notify the ARA host and any listeners of analysis progress.
|
||||
Contrary to most ARA functions, this call can be made from any thread.
|
||||
The implementation will enqueue these notifications and later post them from the message thread.
|
||||
Calling code must ensure start and completion state are always balanced,
|
||||
and must send updates in ascending order.
|
||||
*/
|
||||
void notifyAnalysisProgressStarted();
|
||||
|
||||
/** \copydoc notifyAnalysisProgressStarted
|
||||
@param progress Progress normalized to the 0..1 range.
|
||||
*/
|
||||
void notifyAnalysisProgressUpdated (float progress);
|
||||
|
||||
/** \copydoc notifyAnalysisProgressStarted
|
||||
*/
|
||||
void notifyAnalysisProgressCompleted();
|
||||
|
||||
/** Notify the ARA host and any listeners of a content update initiated by the plug-in.
|
||||
This must be called by the plug-in model management code on the message thread whenever updating
|
||||
the internal content representation, such as after successfully analyzing a new tempo map.
|
||||
Listeners will be notified immediately. If \p notifyARAHost is true, a notification to the host
|
||||
will be enqueued and sent out the next time it polls for updates.
|
||||
\p notifyARAHost must be false if the update was triggered by the host via doUpdateAudioSourceContent().
|
||||
Furthermore, \p notifyARAHost must be false if the updated content is being restored from an archive.
|
||||
|
||||
@param scopeFlags The scope of the content update.
|
||||
@param notifyARAHost If true, the ARA host will be notified of the content change.
|
||||
*/
|
||||
void notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost);
|
||||
|
||||
public:
|
||||
friend ARADocumentController;
|
||||
ARA::PlugIn::AnalysisProgressTracker internalAnalysisProgressTracker;
|
||||
};
|
||||
|
||||
/** A base class for listeners that want to know about changes to an ARAAudioModification object.
|
||||
|
||||
Use ARAAudioModification::addListener() to register your listener with an ARAAudioModification.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAAudioModificationListener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~ARAAudioModificationListener() = default;
|
||||
|
||||
/** Called before the audio modification's properties are updated.
|
||||
@param audioModification The audio modification whose properties will be updated.
|
||||
@param newProperties The audio modification properties that will be assigned to \p audioModification.
|
||||
*/
|
||||
virtual void willUpdateAudioModificationProperties (ARAAudioModification* audioModification,
|
||||
ARA::PlugIn::PropertiesPtr<ARA::ARAAudioModificationProperties> newProperties);
|
||||
|
||||
/** Called after the audio modification's properties are updated.
|
||||
@param audioModification The audio modification whose properties were updated.
|
||||
*/
|
||||
virtual void didUpdateAudioModificationProperties (ARAAudioModification* audioModification);
|
||||
|
||||
/** Called when the audio modification's content (i.e. samples or notes) changes.
|
||||
@param audioModification The audio modification with updated content.
|
||||
@param scopeFlags The scope of the content update.
|
||||
*/
|
||||
virtual void didUpdateAudioModificationContent (ARAAudioModification* audioModification,
|
||||
ARAContentUpdateScopes scopeFlags);
|
||||
|
||||
/** Called before an audio modification is activated or deactivated when being removed / added from the host's undo history.
|
||||
@param audioModification The audio modification that was activated or deactivated
|
||||
@param deactivate A bool indicating whether \p audioModification was deactivated or activated.
|
||||
*/
|
||||
virtual void willDeactivateAudioModificationForUndoHistory (ARAAudioModification* audioModification,
|
||||
bool deactivate);
|
||||
|
||||
/** Called after an audio modification is activated or deactivated when being removed / added from the host's undo history.
|
||||
@param audioModification The audio modification that was activated or deactivated
|
||||
@param deactivate A bool indicating whether \p audioModification was deactivated or activated.
|
||||
*/
|
||||
virtual void didDeactivateAudioModificationForUndoHistory (ARAAudioModification* audioModification,
|
||||
bool deactivate);
|
||||
|
||||
/** Called after a playback region is added to the audio modification.
|
||||
@param audioModification The audio modification that \p playbackRegion was added to.
|
||||
@param playbackRegion The playback region that was added to \p audioModification.
|
||||
*/
|
||||
virtual void didAddPlaybackRegionToAudioModification (ARAAudioModification* audioModification,
|
||||
ARAPlaybackRegion* playbackRegion);
|
||||
|
||||
/** Called before a playback region is removed from the audio modification.
|
||||
@param audioModification The audio modification that \p playbackRegion will be removed from.
|
||||
@param playbackRegion The playback region that will be removed from \p audioModification.
|
||||
*/
|
||||
virtual void willRemovePlaybackRegionFromAudioModification (ARAAudioModification* audioModification,
|
||||
ARAPlaybackRegion* playbackRegion);
|
||||
|
||||
/** Called before the audio modification is destroyed.
|
||||
@param audioModification The audio modification that will be destroyed.
|
||||
*/
|
||||
virtual void willDestroyAudioModification (ARAAudioModification* audioModification);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Base class representing an ARA audio modification.
|
||||
|
||||
@tags{ARA}
|
||||
*/
|
||||
class JUCE_API ARAAudioModification : public ARA::PlugIn::AudioModification,
|
||||
public ARAListenableModelClass<ARAAudioModificationListener>,
|
||||
public ARAObject
|
||||
{
|
||||
public:
|
||||
using PropertiesPtr = ARA::PlugIn::PropertiesPtr<ARA::ARAAudioModificationProperties>;
|
||||
using Listener = ARAAudioModificationListener;
|
||||
|
||||
using ARA::PlugIn::AudioModification::AudioModification;
|
||||
|
||||
/** Returns the result of ARA::PlugIn::AudioModification::getAudioSource() with the pointer cast
|
||||
to ARAAudioSource*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreateAudioSource(), then you
|
||||
can use the template parameter to cast the pointers to your subclass of ARAAudioSource.
|
||||
*/
|
||||
template <typename AudioSource_t = ARAAudioSource>
|
||||
AudioSource_t* getAudioSource() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::AudioModification::getAudioSource<AudioSource_t>();
|
||||
}
|
||||
|
||||
/** Returns the result of ARA::PlugIn::AudioModification::getPlaybackRegions() with the
|
||||
pointers within cast to ARAPlaybackRegion*.
|
||||
|
||||
If you have overridden ARADocumentControllerSpecialisation::doCreatePlaybackRegion(), then
|
||||
you can use the template parameter to cast the pointers to your subclass of ARAPlaybackRegion.
|
||||
*/
|
||||
template <typename PlaybackRegion_t = ARAPlaybackRegion>
|
||||
const std::vector<PlaybackRegion_t*>& getPlaybackRegions() const noexcept
|
||||
{
|
||||
return ARA::PlugIn::AudioModification::getPlaybackRegions<PlaybackRegion_t>();
|
||||
}
|
||||
|
||||
size_t getNumChildren() const noexcept override;
|
||||
|
||||
ARAObject* getChild (size_t index) override;
|
||||
|
||||
ARAObject* getParent() override { return getAudioSource(); }
|
||||
|
||||
void visit (ARAObjectVisitor& visitor) override { visitor.visitAudioModification (*this); }
|
||||
|
||||
/** Notify the ARA host and any listeners of a content update initiated by the plug-in.
|
||||
This must be called by the plug-in model management code on the message thread whenever updating
|
||||
the internal content representation, such as after the user editing the pitch of a note.
|
||||
Listeners will be notified immediately. If \p notifyARAHost is true, a notification to the host
|
||||
will be enqueued and sent out the next time it polls for updates.
|
||||
\p notifyARAHost must be false if the updated content is being restored from an archive.
|
||||
|
||||
@param scopeFlags The scope of the content update.
|
||||
@param notifyARAHost If true, the ARA host will be notified of the content change.
|
||||
*/
|
||||
void notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost);
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Vendored
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ([[maybe_unused]] AudioBuffer<double>& buffer,
|
||||
[[maybe_unused]] AudioProcessor::Realtime realtime,
|
||||
[[maybe_unused]] const AudioPlayHead::PositionInfo& positionInfo) noexcept
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
void ARARenderer::prepareToPlay ([[maybe_unused]] double sampleRate,
|
||||
[[maybe_unused]] int maximumSamplesPerBlock,
|
||||
[[maybe_unused]] int numChannels,
|
||||
[[maybe_unused]] AudioProcessor::ProcessingPrecision precision,
|
||||
[[maybe_unused]] AlwaysNonRealtime alwaysNonRealtime) {}
|
||||
|
||||
//==============================================================================
|
||||
#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
|
||||
|
||||
bool ARAPlaybackRenderer::processBlock ([[maybe_unused]] AudioBuffer<float>& buffer,
|
||||
[[maybe_unused]] AudioProcessor::Realtime realtime,
|
||||
[[maybe_unused]] const AudioPlayHead::PositionInfo& positionInfo) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool ARAEditorRenderer::processBlock ([[maybe_unused]] AudioBuffer<float>& buffer,
|
||||
[[maybe_unused]] AudioProcessor::Realtime isNonRealtime,
|
||||
[[maybe_unused]] const AudioPlayHead::PositionInfo& positionInfo) noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
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);
|
||||
}
|
||||
|
||||
void ARAEditorView::Listener::onNewSelection ([[maybe_unused]] const ARAViewSelection& viewSelection) {}
|
||||
void ARAEditorView::Listener::onHideRegionSequences ([[maybe_unused]] const std::vector<ARARegionSequence*>& regionSequences) {}
|
||||
|
||||
} // namespace juce
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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);
|
||||
|
||||
/** 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::PositionInfo& 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::PositionInfo& 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::PositionInfo& positionInfo) noexcept override;
|
||||
|
||||
using ARARenderer::processBlock;
|
||||
|
||||
// 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::PositionInfo& positionInfo) noexcept override;
|
||||
|
||||
using ARARenderer::processBlock;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ARAEditorRenderer)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Base class for 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>
|
||||
const std::vector<RegionSequence_t*>& 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 (const std::vector<ARA::PlugIn::RegionSequence*>& 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;
|
||||
|
||||
/** Called when the editor view's selection changes.
|
||||
@param viewSelection The current selection state
|
||||
*/
|
||||
virtual void onNewSelection (const ARAViewSelection& 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 (const std::vector<ARARegionSequence*>& regionSequences);
|
||||
};
|
||||
|
||||
/** \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)
|
||||
};
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 || (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU))) && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX)
|
||||
namespace juce
|
||||
{
|
||||
#if ARA_ENABLE_INTERNAL_ASSERTS
|
||||
JUCE_API void JUCE_CALLTYPE handleARAAssertion (const char* file, const int line, const char* diagnosis) noexcept
|
||||
{
|
||||
#if (JUCE_DEBUG && ! JUCE_DISABLE_ASSERTIONS)
|
||||
DBG (diagnosis);
|
||||
#endif
|
||||
|
||||
logAssertion (file, line);
|
||||
|
||||
#if (JUCE_DEBUG && ! JUCE_DISABLE_ASSERTIONS)
|
||||
if (juce_isRunningUnderDebugger())
|
||||
JUCE_BREAK_IN_DEBUGGER;
|
||||
JUCE_ANALYZER_NORETURN
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#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"
|
||||
|
||||
ARA_SETUP_DEBUG_MESSAGE_PREFIX (JucePlugin_Name);
|
||||
#endif
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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",
|
||||
"-Wfloat-equal")
|
||||
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
|
||||
Vendored
+154
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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::PositionInfo& 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)
|
||||
{
|
||||
return processBlockForARA (buffer,
|
||||
realtime,
|
||||
playhead != nullptr ? playhead->getPosition().orFallback (AudioPlayHead::PositionInfo{})
|
||||
: AudioPlayHead::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
|
||||
Vendored
+204
@@ -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::PositionInfo& 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
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 AAXPluginId
|
||||
{
|
||||
public:
|
||||
static std::optional<AAXPluginId> create (std::array<char, 4> letters)
|
||||
{
|
||||
std::array<size_t, 4> indices{};
|
||||
|
||||
for (size_t i = 0; i < letters.size(); ++i)
|
||||
{
|
||||
if (const auto index = findIndexOfChar (letters[i]))
|
||||
indices[i] = *index;
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return AAXPluginId { std::move (indices) };
|
||||
}
|
||||
|
||||
std::optional<AAXPluginId> withIncrementedLetter (size_t index, size_t increment) const
|
||||
{
|
||||
if (indices.size() <= index)
|
||||
return std::nullopt;
|
||||
|
||||
auto copy = *this;
|
||||
copy.indices[index] += increment;
|
||||
|
||||
if ((size_t) std::size (validChars) <= copy.indices[index])
|
||||
return std::nullopt;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
int32 getPluginId() const
|
||||
{
|
||||
int32 result = 0;
|
||||
|
||||
for (size_t i = 0; i < indices.size(); ++i)
|
||||
result |= static_cast<int32> (validChars[indices[i]]) << (8 * (indices.size() - 1 - i));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::optional<size_t> findIndexOfChar (char c)
|
||||
{
|
||||
const auto ptr = std::find (std::begin (validChars), std::end (validChars), c);
|
||||
return ptr != std::end (validChars) ? std::make_optional (std::distance (std::begin (validChars), ptr))
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
static inline constexpr char validChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
explicit AAXPluginId (std::array<size_t, 4> indicesIn)
|
||||
: indices (std::move (indicesIn))
|
||||
{}
|
||||
|
||||
std::array<size_t, 4> indices;
|
||||
};
|
||||
|
||||
static const AudioChannelSet channelSets[] { AudioChannelSet::disabled(),
|
||||
AudioChannelSet::mono(),
|
||||
AudioChannelSet::stereo(),
|
||||
AudioChannelSet::createLCR(),
|
||||
AudioChannelSet::createLCRS(),
|
||||
AudioChannelSet::quadraphonic(),
|
||||
AudioChannelSet::create5point0(),
|
||||
AudioChannelSet::create5point1(),
|
||||
AudioChannelSet::create6point0(),
|
||||
AudioChannelSet::create6point1(),
|
||||
AudioChannelSet::create7point0(),
|
||||
AudioChannelSet::create7point1(),
|
||||
AudioChannelSet::create7point0SDDS(),
|
||||
AudioChannelSet::create7point1SDDS(),
|
||||
AudioChannelSet::create7point0point2(),
|
||||
AudioChannelSet::create7point1point2(),
|
||||
AudioChannelSet::ambisonic (1),
|
||||
AudioChannelSet::ambisonic (2),
|
||||
AudioChannelSet::ambisonic (3),
|
||||
AudioChannelSet::create5point0point2(),
|
||||
AudioChannelSet::create5point1point2(),
|
||||
AudioChannelSet::create5point0point4(),
|
||||
AudioChannelSet::create5point1point4(),
|
||||
AudioChannelSet::create7point0point4(),
|
||||
AudioChannelSet::create7point1point4(),
|
||||
AudioChannelSet::create7point0point6(),
|
||||
AudioChannelSet::create7point1point6(),
|
||||
AudioChannelSet::create9point0point4(),
|
||||
AudioChannelSet::create9point1point4(),
|
||||
AudioChannelSet::create9point0point6(),
|
||||
AudioChannelSet::create9point1point6(),
|
||||
AudioChannelSet::ambisonic (4),
|
||||
AudioChannelSet::ambisonic (5),
|
||||
AudioChannelSet::ambisonic (6),
|
||||
AudioChannelSet::ambisonic (7) };
|
||||
|
||||
int32 AAXClientExtensions::getPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout,
|
||||
const AudioChannelSet& mainOutputLayout,
|
||||
bool idForAudioSuite) const
|
||||
{
|
||||
auto pluginId = [&]
|
||||
{
|
||||
auto opt = idForAudioSuite ? AAXPluginId::create ({ 'j', 'y', 'a', 'a' })
|
||||
: AAXPluginId::create ({ 'j', 'c', 'a', 'a' });
|
||||
jassert (opt.has_value());
|
||||
return *opt;
|
||||
}();
|
||||
|
||||
for (const auto& [channelSet, indexToModify] : { std::tuple (&mainInputLayout, (size_t) 2),
|
||||
std::tuple (&mainOutputLayout, (size_t) 3) })
|
||||
{
|
||||
const auto increment = (size_t) std::distance (std::begin (channelSets),
|
||||
std::find (std::begin (channelSets),
|
||||
std::end (channelSets),
|
||||
*channelSet));
|
||||
|
||||
if (auto modifiedPluginIdOpt = pluginId.withIncrementedLetter (indexToModify, increment);
|
||||
increment < (size_t) std::size (channelSets) && modifiedPluginIdOpt.has_value())
|
||||
{
|
||||
pluginId = *modifiedPluginIdOpt;
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
return pluginId.getPluginId();
|
||||
}
|
||||
|
||||
String AAXClientExtensions::getPageFileName() const
|
||||
{
|
||||
#ifdef JucePlugin_AAXPageTableFile
|
||||
JUCE_COMPILER_WARNING ("JucePlugin_AAXPageTableFile is deprecated, instead implement AAXClientExtensions::getPageFileName()")
|
||||
return JucePlugin_AAXPageTableFile;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
static std::array<char, 4> toCharArray (int32 identifier)
|
||||
{
|
||||
std::array<char, 4> result;
|
||||
|
||||
for (size_t i = 0; i < result.size(); ++i)
|
||||
result[i] = static_cast<char> ((identifier >> (i * 8)) & 0xff);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool isValidAAXPluginId (int32 pluginId)
|
||||
{
|
||||
const auto chars = toCharArray (pluginId);
|
||||
|
||||
return std::all_of (std::begin (chars),
|
||||
std::end (chars),
|
||||
[] (const auto& c)
|
||||
{
|
||||
return AAXPluginId::findIndexOfChar (c).has_value();
|
||||
});
|
||||
}
|
||||
|
||||
static int32 getPluginIDForMainBusConfigJuce705 (const AudioChannelSet& mainInputLayout,
|
||||
const AudioChannelSet& mainOutputLayout,
|
||||
bool idForAudioSuite)
|
||||
{
|
||||
int uniqueFormatId = 0;
|
||||
|
||||
for (int dir = 0; dir < 2; ++dir)
|
||||
{
|
||||
const bool isInput = (dir == 0);
|
||||
auto& set = (isInput ? mainInputLayout : mainOutputLayout);
|
||||
int aaxFormatIndex = 0;
|
||||
|
||||
const AudioChannelSet sets[]
|
||||
{
|
||||
AudioChannelSet::disabled(),
|
||||
AudioChannelSet::mono(),
|
||||
AudioChannelSet::stereo(),
|
||||
AudioChannelSet::createLCR(),
|
||||
AudioChannelSet::createLCRS(),
|
||||
AudioChannelSet::quadraphonic(),
|
||||
AudioChannelSet::create5point0(),
|
||||
AudioChannelSet::create5point1(),
|
||||
AudioChannelSet::create6point0(),
|
||||
AudioChannelSet::create6point1(),
|
||||
AudioChannelSet::create7point0(),
|
||||
AudioChannelSet::create7point1(),
|
||||
AudioChannelSet::create7point0SDDS(),
|
||||
AudioChannelSet::create7point1SDDS(),
|
||||
AudioChannelSet::create7point0point2(),
|
||||
AudioChannelSet::create7point1point2(),
|
||||
AudioChannelSet::ambisonic (1),
|
||||
AudioChannelSet::ambisonic (2),
|
||||
AudioChannelSet::ambisonic (3),
|
||||
AudioChannelSet::create5point0point2(),
|
||||
AudioChannelSet::create5point1point2(),
|
||||
AudioChannelSet::create5point0point4(),
|
||||
AudioChannelSet::create5point1point4(),
|
||||
AudioChannelSet::create7point0point4(),
|
||||
AudioChannelSet::create7point1point4(),
|
||||
AudioChannelSet::create7point0point6(),
|
||||
AudioChannelSet::create7point1point6(),
|
||||
AudioChannelSet::create9point0point4(),
|
||||
AudioChannelSet::create9point1point4(),
|
||||
AudioChannelSet::create9point0point6(),
|
||||
AudioChannelSet::create9point1point6(),
|
||||
AudioChannelSet::ambisonic (4),
|
||||
AudioChannelSet::ambisonic (5),
|
||||
AudioChannelSet::ambisonic (6),
|
||||
AudioChannelSet::ambisonic (7)
|
||||
};
|
||||
|
||||
const auto index = (int) std::distance (std::begin (sets), std::find (std::begin (sets), std::end (sets), set));
|
||||
|
||||
if (index != (int) std::size (sets))
|
||||
aaxFormatIndex = index;
|
||||
else
|
||||
jassertfalse;
|
||||
|
||||
uniqueFormatId = (uniqueFormatId << 8) | aaxFormatIndex;
|
||||
}
|
||||
|
||||
return (idForAudioSuite ? 0x6a796161 /* 'jyaa' */ : 0x6a636161 /* 'jcaa' */) + uniqueFormatId;
|
||||
}
|
||||
|
||||
class AAXClientExtensionsTests final : public UnitTest
|
||||
{
|
||||
public:
|
||||
AAXClientExtensionsTests()
|
||||
: UnitTest ("AAXClientExtensionsTests", UnitTestCategories::audioProcessors)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
AAXClientExtensions extensions;
|
||||
|
||||
beginTest ("Previously valid PluginIds should be unchanged");
|
||||
{
|
||||
for (const auto& input : channelSets)
|
||||
for (const auto& output : channelSets)
|
||||
for (const auto idForAudioSuite : { false, true })
|
||||
if (const auto oldId = getPluginIDForMainBusConfigJuce705 (input, output, idForAudioSuite); isValidAAXPluginId (oldId))
|
||||
expect (extensions.getPluginIDForMainBusConfig (input, output, idForAudioSuite) == oldId);
|
||||
}
|
||||
|
||||
beginTest ("Valid, unique PluginIds should be generated for all configurations");
|
||||
{
|
||||
std::set<int32> pluginIds;
|
||||
|
||||
for (const auto& input : channelSets)
|
||||
for (const auto& output : channelSets)
|
||||
for (const auto idForAudioSuite : { false, true })
|
||||
pluginIds.insert (extensions.getPluginIDForMainBusConfig (input, output, idForAudioSuite));
|
||||
|
||||
for (auto identifier : pluginIds)
|
||||
expect (isValidAAXPluginId (identifier));
|
||||
|
||||
expect (pluginIds.size() == square (std::size (channelSets)) * 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static AAXClientExtensionsTests aaxClientExtensionsTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/**
|
||||
An interface to allow an AudioProcessor to implement extended AAX-specific functionality.
|
||||
|
||||
To use this class, create an object that inherits from it, implement the methods, then return
|
||||
a pointer to the object in your AudioProcessor `getAAXClientExtensions()` method.
|
||||
|
||||
@see AudioProcessor, VST2ClientExtensions, VST3ClientExtensions
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct AAXClientExtensions
|
||||
{
|
||||
virtual ~AAXClientExtensions() = default;
|
||||
|
||||
/** AAX plug-ins need to report a unique "plug-in id" for every audio layout
|
||||
configuration that your AudioProcessor supports on the main bus. Override this
|
||||
function if you want your AudioProcessor to use a custom "plug-in id" (for example
|
||||
to stay backward compatible with older versions of JUCE).
|
||||
|
||||
The default implementation will compute a unique integer from the input and output
|
||||
layout and add this value to the 4 character code 'jcaa' (for native AAX) or 'jyaa'
|
||||
(for AudioSuite plug-ins).
|
||||
*/
|
||||
virtual int32 getPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout,
|
||||
const AudioChannelSet& mainOutputLayout,
|
||||
bool idForAudioSuite) const;
|
||||
|
||||
/** Returns an optional filename (including extension) for a page file to be used.
|
||||
|
||||
A page file allows an AAX plugin to specify how its parameters are displayed on
|
||||
various control surfaces. For more information read the Page Table Guide in the
|
||||
AAX SDK documentation.
|
||||
|
||||
By default this file will be searched for in `*.aaxplugin/Contents/Resources`.
|
||||
|
||||
@see getPageFileSearchPath
|
||||
*/
|
||||
virtual String getPageFileName() const;
|
||||
|
||||
/** Optionally returns a search path for finding a page table file.
|
||||
|
||||
This can be useful for specifying a location outside the plugin bundle so users can
|
||||
make changes to a page table file without breaking any code signatures.
|
||||
|
||||
If this function returns a default-constructed File, then a default location will be used.
|
||||
The AAX SDK states this location will be `*.aaxplugin/Contents/Resources`.
|
||||
|
||||
@note The returned path should be an absolute path to a directory.
|
||||
|
||||
@see getPageFileName
|
||||
*/
|
||||
virtual File getPageFileSearchPath() const { return {}; }
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
AudioParameterBool::AudioParameterBool (const ParameterID& idToUse,
|
||||
const String& nameToUse,
|
||||
bool def,
|
||||
const AudioParameterBoolAttributes& attributes)
|
||||
: RangedAudioParameter (idToUse, nameToUse, attributes.getAudioProcessorParameterWithIDAttributes()),
|
||||
value (def ? 1.0f : 0.0f),
|
||||
valueDefault (def),
|
||||
stringFromBoolFunction (attributes.getStringFromValueFunction() != nullptr
|
||||
? attributes.getStringFromValueFunction()
|
||||
: [] (bool v, int) { return v ? TRANS ("On") : TRANS ("Off"); }),
|
||||
boolFromStringFunction (attributes.getValueFromStringFunction() != nullptr
|
||||
? attributes.getValueFromStringFunction()
|
||||
: [] (const String& text)
|
||||
{
|
||||
static const StringArray onStrings { TRANS ("on"), TRANS ("yes"), TRANS ("true") };
|
||||
static const StringArray offStrings { TRANS ("off"), TRANS ("no"), TRANS ("false") };
|
||||
|
||||
String lowercaseText (text.toLowerCase());
|
||||
|
||||
for (auto& testText : onStrings)
|
||||
if (lowercaseText == testText)
|
||||
return true;
|
||||
|
||||
for (auto& testText : offStrings)
|
||||
if (lowercaseText == testText)
|
||||
return false;
|
||||
|
||||
return text.getIntValue() != 0;
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
AudioParameterBool::~AudioParameterBool()
|
||||
{
|
||||
#if __cpp_lib_atomic_is_always_lock_free
|
||||
static_assert (std::atomic<float>::is_always_lock_free,
|
||||
"AudioParameterBool requires a lock-free std::atomic<float>");
|
||||
#endif
|
||||
}
|
||||
|
||||
float AudioParameterBool::getValue() const { return value; }
|
||||
void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); }
|
||||
float AudioParameterBool::getDefaultValue() const { return valueDefault; }
|
||||
int AudioParameterBool::getNumSteps() const { return 2; }
|
||||
bool AudioParameterBool::isDiscrete() const { return true; }
|
||||
bool AudioParameterBool::isBoolean() const { return true; }
|
||||
void AudioParameterBool::valueChanged (bool) {}
|
||||
|
||||
float AudioParameterBool::getValueForText (const String& text) const
|
||||
{
|
||||
return boolFromStringFunction (text) ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
String AudioParameterBool::getText (float v, int maximumLength) const
|
||||
{
|
||||
return stringFromBoolFunction (v >= 0.5f, maximumLength);
|
||||
}
|
||||
|
||||
AudioParameterBool& AudioParameterBool::operator= (bool newValue)
|
||||
{
|
||||
if (get() != newValue)
|
||||
setValueNotifyingHost (newValue ? 1.0f : 0.0f);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/** Properties of an AudioParameterBool.
|
||||
|
||||
@see AudioParameterBool(), RangedAudioParameterAttributes()
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class AudioParameterBoolAttributes : public RangedAudioParameterAttributes<AudioParameterBoolAttributes, bool> {};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Provides a class of AudioProcessorParameter that can be used as a boolean value.
|
||||
|
||||
@see AudioParameterFloat, AudioParameterInt, AudioParameterChoice
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioParameterBool : public RangedAudioParameter
|
||||
{
|
||||
public:
|
||||
/** Creates a AudioParameterBool with the specified parameters.
|
||||
|
||||
Note that the attributes argument is optional and only needs to be
|
||||
supplied if you want to change options from their default values.
|
||||
|
||||
Example usage:
|
||||
@code
|
||||
auto attributes = AudioParameterBoolAttributes().withStringFromValueFunction ([] (auto x, auto) { return x ? "On" : "Off"; })
|
||||
.withLabel ("enabled");
|
||||
auto param = std::make_unique<AudioParameterBool> ("paramID", "Parameter Name", false, attributes);
|
||||
@endcode
|
||||
|
||||
@param parameterID The parameter ID to use
|
||||
@param parameterName The parameter name to use
|
||||
@param defaultValue The default value
|
||||
@param attributes Optional characteristics
|
||||
*/
|
||||
AudioParameterBool (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
bool defaultValue,
|
||||
const AudioParameterBoolAttributes& attributes = {});
|
||||
|
||||
/** Creates a AudioParameterBool with the specified parameters.
|
||||
|
||||
@param parameterID The parameter ID to use
|
||||
@param parameterName The parameter name to use
|
||||
@param defaultValue The default value
|
||||
@param parameterLabel An optional label for the parameter's value
|
||||
@param stringFromBool An optional lambda function that converts a bool
|
||||
value to a string with a maximum length. This may
|
||||
be used by hosts to display the parameter's value.
|
||||
@param boolFromString An optional lambda function that parses a string and
|
||||
converts it into a bool value. Some hosts use this
|
||||
to allow users to type in parameter values.
|
||||
*/
|
||||
[[deprecated ("Prefer the signature taking an Attributes argument")]]
|
||||
AudioParameterBool (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
bool defaultValue,
|
||||
const String& parameterLabel,
|
||||
std::function<String (bool value, int maximumStringLength)> stringFromBool = nullptr,
|
||||
std::function<bool (const String& text)> boolFromString = nullptr)
|
||||
: AudioParameterBool (parameterID,
|
||||
parameterName,
|
||||
defaultValue,
|
||||
AudioParameterBoolAttributes().withLabel (parameterLabel)
|
||||
.withStringFromValueFunction (std::move (stringFromBool))
|
||||
.withValueFromStringFunction (std::move (boolFromString)))
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~AudioParameterBool() override;
|
||||
|
||||
/** Returns the parameter's current boolean value. */
|
||||
bool get() const noexcept { return value >= 0.5f; }
|
||||
|
||||
/** Returns the parameter's current boolean value. */
|
||||
operator bool() const noexcept { return get(); }
|
||||
|
||||
/** Changes the parameter's current value to a new boolean. */
|
||||
AudioParameterBool& operator= (bool newValue);
|
||||
|
||||
/** Returns the range of values that the parameter can take. */
|
||||
const NormalisableRange<float>& getNormalisableRange() const override { return range; }
|
||||
|
||||
protected:
|
||||
/** Override this method if you are interested in receiving callbacks
|
||||
when the parameter value changes.
|
||||
*/
|
||||
virtual void valueChanged (bool newValue);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
float getValue() const override;
|
||||
void setValue (float newValue) override;
|
||||
float getDefaultValue() const override;
|
||||
int getNumSteps() const override;
|
||||
bool isDiscrete() const override;
|
||||
bool isBoolean() const override;
|
||||
String getText (float, int) const override;
|
||||
float getValueForText (const String&) const override;
|
||||
|
||||
const NormalisableRange<float> range { 0.0f, 1.0f, 1.0f };
|
||||
std::atomic<float> value;
|
||||
const float valueDefault;
|
||||
std::function<String (bool, int)> stringFromBoolFunction;
|
||||
std::function<bool (const String&)> boolFromStringFunction;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterBool)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
AudioParameterChoice::AudioParameterChoice (const ParameterID& idToUse,
|
||||
const String& nameToUse,
|
||||
const StringArray& c,
|
||||
int def,
|
||||
const AudioParameterChoiceAttributes& attributes)
|
||||
: RangedAudioParameter (idToUse, nameToUse, attributes.getAudioProcessorParameterWithIDAttributes()),
|
||||
choices (c),
|
||||
range ([this]
|
||||
{
|
||||
NormalisableRange<float> rangeWithInterval { 0.0f, (float) choices.size() - 1.0f,
|
||||
[] (float, float end, float v) { return jlimit (0.0f, end, v * end); },
|
||||
[] (float, float end, float v) { return jlimit (0.0f, 1.0f, v / end); },
|
||||
[] (float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); } };
|
||||
rangeWithInterval.interval = 1.0f;
|
||||
return rangeWithInterval;
|
||||
}()),
|
||||
value ((float) def),
|
||||
defaultValue (convertTo0to1 ((float) def)),
|
||||
stringFromIndexFunction (attributes.getStringFromValueFunction() != nullptr
|
||||
? attributes.getStringFromValueFunction()
|
||||
: [this] (int index, int) { return choices [index]; }),
|
||||
indexFromStringFunction (attributes.getValueFromStringFunction() != nullptr
|
||||
? attributes.getValueFromStringFunction()
|
||||
: [this] (const String& text) { return choices.indexOf (text); })
|
||||
{
|
||||
jassert (choices.size() > 1); // you must supply an actual set of items to choose from!
|
||||
}
|
||||
|
||||
AudioParameterChoice::~AudioParameterChoice()
|
||||
{
|
||||
#if __cpp_lib_atomic_is_always_lock_free
|
||||
static_assert (std::atomic<float>::is_always_lock_free,
|
||||
"AudioParameterChoice requires a lock-free std::atomic<float>");
|
||||
#endif
|
||||
}
|
||||
|
||||
float AudioParameterChoice::getValue() const { return convertTo0to1 (value); }
|
||||
void AudioParameterChoice::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (getIndex()); }
|
||||
float AudioParameterChoice::getDefaultValue() const { return defaultValue; }
|
||||
int AudioParameterChoice::getNumSteps() const { return choices.size(); }
|
||||
bool AudioParameterChoice::isDiscrete() const { return true; }
|
||||
float AudioParameterChoice::getValueForText (const String& text) const { return convertTo0to1 ((float) indexFromStringFunction (text)); }
|
||||
String AudioParameterChoice::getText (float v, int length) const { return stringFromIndexFunction ((int) convertFrom0to1 (v), length); }
|
||||
void AudioParameterChoice::valueChanged (int) {}
|
||||
|
||||
AudioParameterChoice& AudioParameterChoice::operator= (int newValue)
|
||||
{
|
||||
if (getIndex() != newValue)
|
||||
setValueNotifyingHost (convertTo0to1 ((float) newValue));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
struct AudioParameterChoiceTests final : public UnitTest
|
||||
{
|
||||
AudioParameterChoiceTests()
|
||||
: UnitTest ("AudioParameterChoice", UnitTestCategories::audioProcessorParameters)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("Three options switches at the correct points");
|
||||
{
|
||||
AudioParameterChoice choice ({}, {}, { "a", "b", "c" }, {});
|
||||
|
||||
choice.setValueNotifyingHost (0.0f);
|
||||
expectEquals (choice.getIndex(), 0);
|
||||
|
||||
choice.setValueNotifyingHost (0.2f);
|
||||
expectEquals (choice.getIndex(), 0);
|
||||
|
||||
choice.setValueNotifyingHost (0.3f);
|
||||
expectEquals (choice.getIndex(), 1);
|
||||
|
||||
choice.setValueNotifyingHost (0.7f);
|
||||
expectEquals (choice.getIndex(), 1);
|
||||
|
||||
choice.setValueNotifyingHost (0.8f);
|
||||
expectEquals (choice.getIndex(), 2);
|
||||
|
||||
choice.setValueNotifyingHost (1.0f);
|
||||
expectEquals (choice.getIndex(), 2);
|
||||
}
|
||||
|
||||
beginTest ("Out-of-bounds input");
|
||||
{
|
||||
AudioParameterChoice choiceParam ({}, {}, { "a", "b", "c" }, {});
|
||||
|
||||
choiceParam.setValueNotifyingHost (-0.5f);
|
||||
expectEquals (choiceParam.getIndex(), 0);
|
||||
|
||||
choiceParam.setValueNotifyingHost (1.5f);
|
||||
expectEquals (choiceParam.getIndex(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static AudioParameterChoiceTests audioParameterChoiceTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/** Properties of an AudioParameterChoice.
|
||||
|
||||
@see AudioParameterChoice(), RangedAudioParameterAttributes()
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class AudioParameterChoiceAttributes : public RangedAudioParameterAttributes<AudioParameterChoiceAttributes, int> {};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Provides a class of AudioProcessorParameter that can be used to select
|
||||
an indexed, named choice from a list.
|
||||
|
||||
@see AudioParameterFloat, AudioParameterInt, AudioParameterBool
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioParameterChoice : public RangedAudioParameter
|
||||
{
|
||||
public:
|
||||
/** Creates a AudioParameterChoice with the specified parameters.
|
||||
|
||||
Note that the attributes argument is optional and only needs to be
|
||||
supplied if you want to change options from their default values.
|
||||
|
||||
Example usage:
|
||||
@code
|
||||
auto attributes = AudioParameterChoiceAttributes().withLabel ("selected");
|
||||
auto param = std::make_unique<AudioParameterChoice> ("paramID", "Parameter Name", StringArray { "a", "b", "c" }, 0, attributes);
|
||||
@endcode
|
||||
|
||||
@param parameterID The parameter ID to use
|
||||
@param parameterName The parameter name to use
|
||||
@param choices The set of choices to use
|
||||
@param defaultItemIndex The index of the default choice
|
||||
@param attributes Optional characteristics
|
||||
*/
|
||||
AudioParameterChoice (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
const StringArray& choices,
|
||||
int defaultItemIndex,
|
||||
const AudioParameterChoiceAttributes& attributes = {});
|
||||
|
||||
/** Creates a AudioParameterChoice with the specified parameters.
|
||||
|
||||
@param parameterID The parameter ID to use
|
||||
@param parameterName The parameter name to use
|
||||
@param choicesToUse The set of choices to use
|
||||
@param defaultItemIndex The index of the default choice
|
||||
@param parameterLabel An optional label for the parameter's value
|
||||
@param stringFromIndex An optional lambda function that converts a choice
|
||||
index to a string with a maximum length. This may
|
||||
be used by hosts to display the parameter's value.
|
||||
@param indexFromString An optional lambda function that parses a string and
|
||||
converts it into a choice index. Some hosts use this
|
||||
to allow users to type in parameter values.
|
||||
*/
|
||||
[[deprecated ("Prefer the signature taking an Attributes argument")]]
|
||||
AudioParameterChoice (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
const StringArray& choicesToUse,
|
||||
int defaultItemIndex,
|
||||
const String& parameterLabel,
|
||||
std::function<String (int index, int maximumStringLength)> stringFromIndex = nullptr,
|
||||
std::function<int (const String& text)> indexFromString = nullptr)
|
||||
: AudioParameterChoice (parameterID,
|
||||
parameterName,
|
||||
choicesToUse,
|
||||
defaultItemIndex,
|
||||
AudioParameterChoiceAttributes().withLabel (parameterLabel)
|
||||
.withStringFromValueFunction (std::move (stringFromIndex))
|
||||
.withValueFromStringFunction (std::move (indexFromString)))
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~AudioParameterChoice() override;
|
||||
|
||||
/** Returns the current index of the selected item. */
|
||||
int getIndex() const noexcept { return roundToInt (value.load()); }
|
||||
|
||||
/** Returns the current index of the selected item. */
|
||||
operator int() const noexcept { return getIndex(); }
|
||||
|
||||
/** Returns the name of the currently selected item. */
|
||||
String getCurrentChoiceName() const noexcept { return choices[getIndex()]; }
|
||||
|
||||
/** Returns the name of the currently selected item. */
|
||||
operator String() const noexcept { return getCurrentChoiceName(); }
|
||||
|
||||
/** Changes the selected item to a new index. */
|
||||
AudioParameterChoice& operator= (int newValue);
|
||||
|
||||
/** Returns the range of values that the parameter can take. */
|
||||
const NormalisableRange<float>& getNormalisableRange() const override { return range; }
|
||||
|
||||
/** Provides access to the list of choices that this parameter is working with. */
|
||||
const StringArray choices;
|
||||
|
||||
protected:
|
||||
/** Override this method if you are interested in receiving callbacks
|
||||
when the parameter value changes.
|
||||
*/
|
||||
virtual void valueChanged (int newValue);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
float getValue() const override;
|
||||
void setValue (float newValue) override;
|
||||
float getDefaultValue() const override;
|
||||
int getNumSteps() const override;
|
||||
bool isDiscrete() const override;
|
||||
String getText (float, int) const override;
|
||||
float getValueForText (const String&) const override;
|
||||
|
||||
const NormalisableRange<float> range;
|
||||
std::atomic<float> value;
|
||||
const float defaultValue;
|
||||
std::function<String (int, int)> stringFromIndexFunction;
|
||||
std::function<int (const String&)> indexFromStringFunction;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterChoice)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
AudioParameterFloat::AudioParameterFloat (const ParameterID& idToUse,
|
||||
const String& nameToUse,
|
||||
NormalisableRange<float> r,
|
||||
float def,
|
||||
const AudioParameterFloatAttributes& attributes)
|
||||
: RangedAudioParameter (idToUse, nameToUse, attributes.getAudioProcessorParameterWithIDAttributes()),
|
||||
range (r),
|
||||
value (def),
|
||||
valueDefault (def),
|
||||
stringFromValueFunction (attributes.getStringFromValueFunction()),
|
||||
valueFromStringFunction (attributes.getValueFromStringFunction())
|
||||
{
|
||||
if (stringFromValueFunction == nullptr)
|
||||
{
|
||||
auto numDecimalPlacesToDisplay = [this]
|
||||
{
|
||||
int numDecimalPlaces = 7;
|
||||
|
||||
if (! approximatelyEqual (range.interval, 0.0f))
|
||||
{
|
||||
if (approximatelyEqual (std::abs (range.interval - std::floor (range.interval)), 0.0f))
|
||||
return 0;
|
||||
|
||||
auto v = std::abs (roundToInt (range.interval * pow (10, numDecimalPlaces)));
|
||||
|
||||
while ((v % 10) == 0 && numDecimalPlaces > 0)
|
||||
{
|
||||
--numDecimalPlaces;
|
||||
v /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
return numDecimalPlaces;
|
||||
}();
|
||||
|
||||
stringFromValueFunction = [numDecimalPlacesToDisplay] (float v, int length)
|
||||
{
|
||||
String asText (v, numDecimalPlacesToDisplay);
|
||||
return length > 0 ? asText.substring (0, length) : asText;
|
||||
};
|
||||
}
|
||||
|
||||
if (valueFromStringFunction == nullptr)
|
||||
valueFromStringFunction = [] (const String& text) { return text.getFloatValue(); };
|
||||
}
|
||||
|
||||
AudioParameterFloat::AudioParameterFloat (const ParameterID& pid, const String& nm, float minValue, float maxValue, float def)
|
||||
: AudioParameterFloat (pid, nm, { minValue, maxValue, 0.01f }, def)
|
||||
{
|
||||
}
|
||||
|
||||
AudioParameterFloat::~AudioParameterFloat()
|
||||
{
|
||||
#if __cpp_lib_atomic_is_always_lock_free
|
||||
static_assert (std::atomic<float>::is_always_lock_free,
|
||||
"AudioParameterFloat requires a lock-free std::atomic<float>");
|
||||
#endif
|
||||
}
|
||||
|
||||
float AudioParameterFloat::getValue() const { return convertTo0to1 (value); }
|
||||
void AudioParameterFloat::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); }
|
||||
float AudioParameterFloat::getDefaultValue() const { return convertTo0to1 (valueDefault); }
|
||||
int AudioParameterFloat::getNumSteps() const { return AudioProcessorParameterWithID::getNumSteps(); }
|
||||
String AudioParameterFloat::getText (float v, int length) const { return stringFromValueFunction (convertFrom0to1 (v), length); }
|
||||
float AudioParameterFloat::getValueForText (const String& text) const { return convertTo0to1 (valueFromStringFunction (text)); }
|
||||
void AudioParameterFloat::valueChanged (float) {}
|
||||
|
||||
AudioParameterFloat& AudioParameterFloat::operator= (float newValue)
|
||||
{
|
||||
if (! approximatelyEqual ((float) value, newValue))
|
||||
setValueNotifyingHost (convertTo0to1 (newValue));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/** Properties of an AudioParameterFloat.
|
||||
|
||||
@see AudioParameterFloat(), RangedAudioParameterAttributes()
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class AudioParameterFloatAttributes : public RangedAudioParameterAttributes<AudioParameterFloatAttributes, float> {};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A subclass of AudioProcessorParameter that provides an easy way to create a
|
||||
parameter which maps onto a given NormalisableRange.
|
||||
|
||||
@see AudioParameterInt, AudioParameterBool, AudioParameterChoice
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioParameterFloat : public RangedAudioParameter
|
||||
{
|
||||
public:
|
||||
/** Creates a AudioParameterFloat with the specified parameters.
|
||||
|
||||
Note that the attributes argument is optional and only needs to be
|
||||
supplied if you want to change options from their default values.
|
||||
|
||||
Example usage:
|
||||
@code
|
||||
auto attributes = AudioParameterFloatAttributes().withStringFromValueFunction ([] (auto x, auto) { return String (x * 100); })
|
||||
.withLabel ("%");
|
||||
auto param = std::make_unique<AudioParameterFloat> ("paramID", "Parameter Name", NormalisableRange<float>(), 0.5f, attributes);
|
||||
@endcode
|
||||
|
||||
@param parameterID The parameter ID to use
|
||||
@param parameterName The parameter name to use
|
||||
@param normalisableRange The NormalisableRange to use
|
||||
@param defaultValue The non-normalised default value
|
||||
@param attributes Optional characteristics
|
||||
*/
|
||||
AudioParameterFloat (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
NormalisableRange<float> normalisableRange,
|
||||
float defaultValue,
|
||||
const AudioParameterFloatAttributes& attributes = {});
|
||||
|
||||
/** Creates a AudioParameterFloat with the specified parameters.
|
||||
|
||||
@param parameterID The parameter ID to use
|
||||
@param parameterName The parameter name to use
|
||||
@param normalisableRange The NormalisableRange to use
|
||||
@param defaultValue The non-normalised default value
|
||||
@param parameterLabel An optional label for the parameter's value
|
||||
@param parameterCategory An optional parameter category
|
||||
@param stringFromValue An optional lambda function that converts a non-normalised
|
||||
value to a string with a maximum length. This may
|
||||
be used by hosts to display the parameter's value.
|
||||
@param valueFromString An optional lambda function that parses a string and
|
||||
converts it into a non-normalised value. Some hosts use
|
||||
this to allow users to type in parameter values.
|
||||
*/
|
||||
[[deprecated ("Prefer the signature taking an Attributes argument")]]
|
||||
AudioParameterFloat (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
NormalisableRange<float> normalisableRange,
|
||||
float defaultValue,
|
||||
const String& parameterLabel,
|
||||
Category parameterCategory = AudioProcessorParameter::genericParameter,
|
||||
std::function<String (float value, int maximumStringLength)> stringFromValue = nullptr,
|
||||
std::function<float (const String& text)> valueFromString = nullptr)
|
||||
: AudioParameterFloat (parameterID,
|
||||
parameterName,
|
||||
std::move (normalisableRange),
|
||||
defaultValue,
|
||||
AudioParameterFloatAttributes().withLabel (parameterLabel)
|
||||
.withCategory (parameterCategory)
|
||||
.withStringFromValueFunction (std::move (stringFromValue))
|
||||
.withValueFromStringFunction (std::move (valueFromString)))
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a AudioParameterFloat with an ID, name, and range.
|
||||
On creation, its value is set to the default value.
|
||||
For control over skew factors, you can use the other
|
||||
constructor and provide a NormalisableRange.
|
||||
*/
|
||||
AudioParameterFloat (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
float minValue,
|
||||
float maxValue,
|
||||
float defaultValue);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioParameterFloat() override;
|
||||
|
||||
/** Returns the parameter's current value. */
|
||||
float get() const noexcept { return value; }
|
||||
|
||||
/** Returns the parameter's current value. */
|
||||
operator float() const noexcept { return value; }
|
||||
|
||||
/** Changes the parameter's current value. */
|
||||
AudioParameterFloat& operator= (float newValue);
|
||||
|
||||
/** Returns the range of values that the parameter can take. */
|
||||
const NormalisableRange<float>& getNormalisableRange() const override { return range; }
|
||||
|
||||
/** Provides access to the parameter's range. */
|
||||
NormalisableRange<float> range;
|
||||
|
||||
protected:
|
||||
/** Override this method if you are interested in receiving callbacks
|
||||
when the parameter value changes.
|
||||
*/
|
||||
virtual void valueChanged (float newValue);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
float getValue() const override;
|
||||
void setValue (float newValue) override;
|
||||
float getDefaultValue() const override;
|
||||
int getNumSteps() const override;
|
||||
String getText (float, int) const override;
|
||||
float getValueForText (const String&) const override;
|
||||
|
||||
std::atomic<float> value;
|
||||
const float valueDefault;
|
||||
std::function<String (float, int)> stringFromValueFunction;
|
||||
std::function<float (const String&)> valueFromStringFunction;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterFloat)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
AudioParameterInt::AudioParameterInt (const ParameterID& idToUse, const String& nameToUse,
|
||||
int minValue, int maxValue, int def,
|
||||
const AudioParameterIntAttributes& attributes)
|
||||
: RangedAudioParameter (idToUse, nameToUse, attributes.getAudioProcessorParameterWithIDAttributes()),
|
||||
range ([minValue, maxValue]
|
||||
{
|
||||
NormalisableRange<float> rangeWithInterval { (float) minValue, (float) maxValue,
|
||||
[] (float start, float end, float v) { return jlimit (start, end, v * (end - start) + start); },
|
||||
[] (float start, float end, float v) { return jlimit (0.0f, 1.0f, (v - start) / (end - start)); },
|
||||
[] (float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); } };
|
||||
rangeWithInterval.interval = 1.0f;
|
||||
return rangeWithInterval;
|
||||
}()),
|
||||
value ((float) def),
|
||||
defaultValue (convertTo0to1 ((float) def)),
|
||||
stringFromIntFunction (attributes.getStringFromValueFunction() != nullptr
|
||||
? attributes.getStringFromValueFunction()
|
||||
: [] (int v, int) { return String (v); }),
|
||||
intFromStringFunction (attributes.getValueFromStringFunction() != nullptr
|
||||
? attributes.getValueFromStringFunction()
|
||||
: [] (const String& text) { return text.getIntValue(); })
|
||||
{
|
||||
jassert (minValue < maxValue); // must have a non-zero range of values!
|
||||
}
|
||||
|
||||
AudioParameterInt::~AudioParameterInt()
|
||||
{
|
||||
#if __cpp_lib_atomic_is_always_lock_free
|
||||
static_assert (std::atomic<float>::is_always_lock_free,
|
||||
"AudioParameterInt requires a lock-free std::atomic<float>");
|
||||
#endif
|
||||
}
|
||||
|
||||
float AudioParameterInt::getValue() const { return convertTo0to1 (value); }
|
||||
void AudioParameterInt::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); }
|
||||
float AudioParameterInt::getDefaultValue() const { return defaultValue; }
|
||||
int AudioParameterInt::getNumSteps() const { return ((int) getNormalisableRange().getRange().getLength()) + 1; }
|
||||
float AudioParameterInt::getValueForText (const String& text) const { return convertTo0to1 ((float) intFromStringFunction (text)); }
|
||||
String AudioParameterInt::getText (float v, int length) const { return stringFromIntFunction ((int) convertFrom0to1 (v), length); }
|
||||
void AudioParameterInt::valueChanged (int) {}
|
||||
|
||||
AudioParameterInt& AudioParameterInt::operator= (int newValue)
|
||||
{
|
||||
if (get() != newValue)
|
||||
setValueNotifyingHost (convertTo0to1 ((float) newValue));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
struct AudioParameterIntTests final : public UnitTest
|
||||
{
|
||||
AudioParameterIntTests()
|
||||
: UnitTest ("AudioParameterInt", UnitTestCategories::audioProcessorParameters)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("Three options switches at the correct points");
|
||||
{
|
||||
AudioParameterInt intParam ({}, {}, 1, 3, 1);
|
||||
|
||||
intParam.setValueNotifyingHost (0.0f);
|
||||
expectEquals (intParam.get(), 1);
|
||||
|
||||
intParam.setValueNotifyingHost (0.2f);
|
||||
expectEquals (intParam.get(), 1);
|
||||
|
||||
intParam.setValueNotifyingHost (0.3f);
|
||||
expectEquals (intParam.get(), 2);
|
||||
|
||||
intParam.setValueNotifyingHost (0.7f);
|
||||
expectEquals (intParam.get(), 2);
|
||||
|
||||
intParam.setValueNotifyingHost (0.8f);
|
||||
expectEquals (intParam.get(), 3);
|
||||
|
||||
intParam.setValueNotifyingHost (1.0f);
|
||||
expectEquals (intParam.get(), 3);
|
||||
}
|
||||
|
||||
beginTest ("Out-of-bounds input");
|
||||
{
|
||||
AudioParameterInt intParam ({}, {}, -1, 2, 0);
|
||||
|
||||
intParam.setValueNotifyingHost (-0.5f);
|
||||
expectEquals (intParam.get(), -1);
|
||||
|
||||
intParam.setValueNotifyingHost (1.5f);
|
||||
expectEquals (intParam.get(), 2);
|
||||
|
||||
intParam = -5;
|
||||
expectEquals (intParam.get(), -1);
|
||||
|
||||
intParam = 5;
|
||||
expectEquals (intParam.get(), 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static AudioParameterIntTests audioParameterIntTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/** Properties of an AudioParameterInt.
|
||||
|
||||
@see AudioParameterInt(), RangedAudioParameterAttributes()
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class AudioParameterIntAttributes : public RangedAudioParameterAttributes<AudioParameterIntAttributes, int> {};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Provides a class of AudioProcessorParameter that can be used as an
|
||||
integer value with a given range.
|
||||
|
||||
@see AudioParameterFloat, AudioParameterBool, AudioParameterChoice
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioParameterInt : public RangedAudioParameter
|
||||
{
|
||||
public:
|
||||
/** Creates a AudioParameterInt with the specified parameters.
|
||||
|
||||
Note that the attributes argument is optional and only needs to be
|
||||
supplied if you want to change options from their default values.
|
||||
|
||||
Example usage:
|
||||
@code
|
||||
auto attributes = AudioParameterIntAttributes().withStringFromValueFunction ([] (auto x, auto) { return String (x); })
|
||||
.withLabel ("things");
|
||||
auto param = std::make_unique<AudioParameterInt> ("paramID", "Parameter Name", 0, 100, 50, attributes);
|
||||
@endcode
|
||||
|
||||
@param parameterID The parameter ID to use
|
||||
@param parameterName The parameter name to use
|
||||
@param minValue The minimum parameter value
|
||||
@param maxValue The maximum parameter value
|
||||
@param defaultValue The default value
|
||||
@param attributes Optional characteristics
|
||||
*/
|
||||
AudioParameterInt (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
int defaultValue,
|
||||
const AudioParameterIntAttributes& attributes = {});
|
||||
|
||||
/** Creates a AudioParameterInt with the specified parameters.
|
||||
|
||||
@param parameterID The parameter ID to use
|
||||
@param parameterName The parameter name to use
|
||||
@param minValue The minimum parameter value
|
||||
@param maxValue The maximum parameter value
|
||||
@param defaultValueIn The default value
|
||||
@param parameterLabel An optional label for the parameter's value
|
||||
@param stringFromInt An optional lambda function that converts a int
|
||||
value to a string with a maximum length. This may
|
||||
be used by hosts to display the parameter's value.
|
||||
@param intFromString An optional lambda function that parses a string
|
||||
and converts it into an int. Some hosts use this
|
||||
to allow users to type in parameter values.
|
||||
*/
|
||||
[[deprecated ("Prefer the signature taking an Attributes argument")]]
|
||||
AudioParameterInt (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
int defaultValueIn,
|
||||
const String& parameterLabel,
|
||||
std::function<String (int value, int maximumStringLength)> stringFromInt = nullptr,
|
||||
std::function<int (const String& text)> intFromString = nullptr)
|
||||
: AudioParameterInt (parameterID,
|
||||
parameterName,
|
||||
minValue,
|
||||
maxValue,
|
||||
defaultValueIn,
|
||||
AudioParameterIntAttributes().withLabel (parameterLabel)
|
||||
.withStringFromValueFunction (std::move (stringFromInt))
|
||||
.withValueFromStringFunction (std::move (intFromString)))
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~AudioParameterInt() override;
|
||||
|
||||
/** Returns the parameter's current value as an integer. */
|
||||
int get() const noexcept { return roundToInt (value.load()); }
|
||||
|
||||
/** Returns the parameter's current value as an integer. */
|
||||
operator int() const noexcept { return get(); }
|
||||
|
||||
/** Changes the parameter's current value to a new integer.
|
||||
The value passed in will be snapped to the permitted range before being used.
|
||||
*/
|
||||
AudioParameterInt& operator= (int newValue);
|
||||
|
||||
/** Returns the parameter's range. */
|
||||
Range<int> getRange() const noexcept { return { (int) getNormalisableRange().start, (int) getNormalisableRange().end }; }
|
||||
|
||||
/** Returns the range of values that the parameter can take. */
|
||||
const NormalisableRange<float>& getNormalisableRange() const override { return range; }
|
||||
|
||||
protected:
|
||||
/** Override this method if you are interested in receiving callbacks
|
||||
when the parameter value changes.
|
||||
*/
|
||||
virtual void valueChanged (int newValue);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
float getValue() const override;
|
||||
void setValue (float newValue) override;
|
||||
float getDefaultValue() const override;
|
||||
int getNumSteps() const override;
|
||||
String getText (float, int) const override;
|
||||
float getValueForText (const String&) const override;
|
||||
|
||||
const NormalisableRange<float> range;
|
||||
std::atomic<float> value;
|
||||
const float defaultValue;
|
||||
std::function<String (int, int)> stringFromIntFunction;
|
||||
std::function<int (const String&)> intFromStringFunction;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterInt)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
AudioProcessorParameterWithID::AudioProcessorParameterWithID (const ParameterID& idToUse,
|
||||
const String& nameToUse,
|
||||
const AudioProcessorParameterWithIDAttributes& attributes)
|
||||
: HostedAudioProcessorParameter (idToUse.getVersionHint()),
|
||||
paramID (idToUse.getParamID()),
|
||||
name (nameToUse),
|
||||
label (attributes.getLabel()),
|
||||
category (attributes.getCategory()),
|
||||
meta (attributes.getMeta()),
|
||||
automatable (attributes.getAutomatable()),
|
||||
inverted (attributes.getInverted())
|
||||
{
|
||||
}
|
||||
|
||||
String AudioProcessorParameterWithID::getName (int maximumStringLength) const { return name.substring (0, maximumStringLength); }
|
||||
String AudioProcessorParameterWithID::getLabel() const { return label; }
|
||||
AudioProcessorParameter::Category AudioProcessorParameterWithID::getCategory() const { return category; }
|
||||
|
||||
} // namespace juce
|
||||
Vendored
+191
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/**
|
||||
Combines a parameter ID and a version hint.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class ParameterID
|
||||
{
|
||||
public:
|
||||
ParameterID() = default;
|
||||
|
||||
/** Constructs an instance.
|
||||
|
||||
Note that this constructor implicitly converts from Strings and string-like types.
|
||||
|
||||
@param identifier A string that uniquely identifies a single parameter
|
||||
@param versionHint Influences parameter ordering in Audio Unit plugins.
|
||||
Used to provide backwards compatibility of Audio Unit plugins in
|
||||
Logic and GarageBand.
|
||||
@see AudioProcessorParameter (int)
|
||||
*/
|
||||
template <typename StringLike, typename = DisableIfSameOrDerived<ParameterID, StringLike>>
|
||||
ParameterID (StringLike&& identifier, int versionHint = 0)
|
||||
: paramID (std::forward<StringLike> (identifier)), version (versionHint) {}
|
||||
|
||||
/** @see AudioProcessorParameterWithID::paramID */
|
||||
auto getParamID() const { return paramID; }
|
||||
|
||||
/** @see AudioProcessorParameter (int) */
|
||||
auto getVersionHint() const { return version; }
|
||||
|
||||
private:
|
||||
String paramID;
|
||||
int version = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
An instance of this class may be passed to the constructor of an AudioProcessorParameterWithID
|
||||
to set optional characteristics of that parameter.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class AudioProcessorParameterWithIDAttributes
|
||||
{
|
||||
using This = AudioProcessorParameterWithIDAttributes;
|
||||
|
||||
public:
|
||||
using Category = AudioProcessorParameter::Category;
|
||||
|
||||
/** An optional label for the parameter's value */
|
||||
[[nodiscard]] auto withLabel (String x) const { return withMember (*this, &This::label, std::move (x)); }
|
||||
|
||||
/** The semantics of this parameter */
|
||||
[[nodiscard]] auto withCategory (Category x) const { return withMember (*this, &This::category, std::move (x)); }
|
||||
|
||||
/** @see AudioProcessorParameter::isMetaParameter() */
|
||||
[[nodiscard]] auto withMeta (bool x) const { return withMember (*this, &This::meta, std::move (x)); }
|
||||
|
||||
/** @see AudioProcessorParameter::isAutomatable() */
|
||||
[[nodiscard]] auto withAutomatable (bool x) const { return withMember (*this, &This::automatable, std::move (x)); }
|
||||
|
||||
/** @see AudioProcessorParameter::isOrientationInverted() */
|
||||
[[nodiscard]] auto withInverted (bool x) const { return withMember (*this, &This::inverted, std::move (x)); }
|
||||
|
||||
/** An optional label for the parameter's value */
|
||||
[[nodiscard]] auto getLabel() const { return label; }
|
||||
|
||||
/** The semantics of this parameter */
|
||||
[[nodiscard]] auto getCategory() const { return category; }
|
||||
|
||||
/** @see AudioProcessorParameter::isMetaParameter() */
|
||||
[[nodiscard]] auto getMeta() const { return meta; }
|
||||
|
||||
/** @see AudioProcessorParameter::isAutomatable() */
|
||||
[[nodiscard]] auto getAutomatable() const { return automatable; }
|
||||
|
||||
/** @see AudioProcessorParameter::isOrientationInverted() */
|
||||
[[nodiscard]] auto getInverted() const { return inverted; }
|
||||
|
||||
private:
|
||||
String label;
|
||||
Category category = AudioProcessorParameter::genericParameter;
|
||||
bool meta = false, automatable = true, inverted = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This abstract base class is used by some AudioProcessorParameter helper classes.
|
||||
|
||||
@see AudioParameterFloat, AudioParameterInt, AudioParameterBool, AudioParameterChoice
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioProcessorParameterWithID : public HostedAudioProcessorParameter
|
||||
{
|
||||
public:
|
||||
/** The creation of this object requires providing a name and ID which will be constant for its lifetime.
|
||||
|
||||
Given that AudioProcessorParameterWithID is abstract, you'll probably call this constructor
|
||||
from a derived class constructor, e.g.
|
||||
@code
|
||||
MyParameterType (String paramID, String name, String label, bool automatable)
|
||||
: AudioProcessorParameterWithID (paramID, name, AudioProcessorParameterWithIDAttributes().withLabel (label)
|
||||
.withAutomatable (automatable))
|
||||
{
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param parameterID Specifies the identifier, and optionally the parameter's version hint.
|
||||
@param parameterName The user-facing parameter name.
|
||||
@param attributes Other parameter properties.
|
||||
*/
|
||||
AudioProcessorParameterWithID (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
const AudioProcessorParameterWithIDAttributes& attributes = {});
|
||||
|
||||
/** The creation of this object requires providing a name and ID which will be
|
||||
constant for its lifetime.
|
||||
|
||||
@param parameterID Used to uniquely identify the parameter
|
||||
@param parameterName The user-facing name of the parameter
|
||||
@param parameterLabel An optional label for the parameter's value
|
||||
@param parameterCategory The semantics of this parameter
|
||||
*/
|
||||
[[deprecated ("Prefer the signature taking an Attributes argument")]]
|
||||
AudioProcessorParameterWithID (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
const String& parameterLabel,
|
||||
Category parameterCategory = AudioProcessorParameter::genericParameter)
|
||||
: AudioProcessorParameterWithID (parameterID,
|
||||
parameterName,
|
||||
AudioProcessorParameterWithIDAttributes().withLabel (parameterLabel)
|
||||
.withCategory (parameterCategory))
|
||||
{
|
||||
}
|
||||
|
||||
/** Provides access to the parameter's ID string. */
|
||||
const String paramID;
|
||||
|
||||
/** Provides access to the parameter's name. */
|
||||
const String name;
|
||||
|
||||
/** Provides access to the parameter's label. */
|
||||
const String label;
|
||||
|
||||
/** Provides access to the parameter's category. */
|
||||
const Category category;
|
||||
|
||||
String getName (int) const override;
|
||||
String getLabel() const override;
|
||||
Category getCategory() const override;
|
||||
|
||||
String getParameterID() const override { return paramID; }
|
||||
bool isMetaParameter() const override { return meta; }
|
||||
bool isAutomatable() const override { return automatable; }
|
||||
bool isOrientationInverted() const override { return inverted; }
|
||||
|
||||
private:
|
||||
bool meta = false, automatable = true, inverted = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameterWithID)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Vendored
+988
@@ -0,0 +1,988 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
|
||||
AudioProcessorValueTreeState::Parameter::Parameter (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
NormalisableRange<float> valueRange,
|
||||
float defaultParameterValue,
|
||||
const AudioProcessorValueTreeStateParameterAttributes& attributes)
|
||||
: AudioParameterFloat (parameterID,
|
||||
parameterName,
|
||||
valueRange,
|
||||
defaultParameterValue,
|
||||
attributes.getAudioParameterFloatAttributes()),
|
||||
unsnappedDefault (valueRange.convertTo0to1 (defaultParameterValue)),
|
||||
discrete (attributes.getDiscrete()),
|
||||
boolean (attributes.getBoolean())
|
||||
{
|
||||
}
|
||||
|
||||
float AudioProcessorValueTreeState::Parameter::getDefaultValue() const { return unsnappedDefault; }
|
||||
int AudioProcessorValueTreeState::Parameter::getNumSteps() const { return RangedAudioParameter::getNumSteps(); }
|
||||
|
||||
bool AudioProcessorValueTreeState::Parameter::isDiscrete() const { return discrete; }
|
||||
bool AudioProcessorValueTreeState::Parameter::isBoolean() const { return boolean; }
|
||||
|
||||
void AudioProcessorValueTreeState::Parameter::valueChanged (float newValue)
|
||||
{
|
||||
if (approximatelyEqual ((float) lastValue, newValue))
|
||||
return;
|
||||
|
||||
lastValue = newValue;
|
||||
NullCheckedInvocation::invoke (onValueChanged);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class AudioProcessorValueTreeState::ParameterAdapter final : private AudioProcessorParameter::Listener
|
||||
{
|
||||
private:
|
||||
using Listener = AudioProcessorValueTreeState::Listener;
|
||||
|
||||
public:
|
||||
explicit ParameterAdapter (RangedAudioParameter& parameterIn)
|
||||
: parameter (parameterIn),
|
||||
// For legacy reasons, the unnormalised value should *not* be snapped on construction
|
||||
unnormalisedValue (getRange().convertFrom0to1 (parameter.getDefaultValue()))
|
||||
{
|
||||
parameter.addListener (this);
|
||||
|
||||
if (auto* ptr = dynamic_cast<Parameter*> (¶meter))
|
||||
ptr->onValueChanged = [this] { parameterValueChanged ({}, {}); };
|
||||
}
|
||||
|
||||
~ParameterAdapter() override { parameter.removeListener (this); }
|
||||
|
||||
void addListener (Listener* l) { listeners.add (l); }
|
||||
void removeListener (Listener* l) { listeners.remove (l); }
|
||||
|
||||
RangedAudioParameter& getParameter() { return parameter; }
|
||||
const RangedAudioParameter& getParameter() const { return parameter; }
|
||||
|
||||
const NormalisableRange<float>& getRange() const { return parameter.getNormalisableRange(); }
|
||||
|
||||
float getDenormalisedDefaultValue() const { return denormalise (parameter.getDefaultValue()); }
|
||||
|
||||
void setDenormalisedValue (float value)
|
||||
{
|
||||
if (! approximatelyEqual (value, (float) unnormalisedValue))
|
||||
setNormalisedValue (normalise (value));
|
||||
}
|
||||
|
||||
float getDenormalisedValueForText (const String& text) const
|
||||
{
|
||||
return denormalise (parameter.getValueForText (text));
|
||||
}
|
||||
|
||||
String getTextForDenormalisedValue (float value) const
|
||||
{
|
||||
return parameter.getText (normalise (value), 0);
|
||||
}
|
||||
|
||||
float getDenormalisedValue() const { return unnormalisedValue; }
|
||||
std::atomic<float>& getRawDenormalisedValue() { return unnormalisedValue; }
|
||||
|
||||
bool flushToTree (const Identifier& key, UndoManager* um)
|
||||
{
|
||||
auto needsUpdateTestValue = true;
|
||||
|
||||
if (! needsUpdate.compare_exchange_strong (needsUpdateTestValue, false))
|
||||
return false;
|
||||
|
||||
if (auto* valueProperty = tree.getPropertyPointer (key))
|
||||
{
|
||||
if (! approximatelyEqual ((float) *valueProperty, unnormalisedValue.load()))
|
||||
{
|
||||
ScopedValueSetter<bool> svs (ignoreParameterChangedCallbacks, true);
|
||||
tree.setProperty (key, unnormalisedValue.load(), um);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tree.setProperty (key, unnormalisedValue.load(), nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ValueTree tree;
|
||||
|
||||
private:
|
||||
void parameterGestureChanged (int, bool) override {}
|
||||
|
||||
void parameterValueChanged (int, float) override
|
||||
{
|
||||
const auto newValue = denormalise (parameter.getValue());
|
||||
|
||||
if (! listenersNeedCalling && approximatelyEqual ((float) unnormalisedValue, newValue))
|
||||
return;
|
||||
|
||||
unnormalisedValue = newValue;
|
||||
listeners.call ([this] (Listener& l) { l.parameterChanged (parameter.paramID, unnormalisedValue); });
|
||||
listenersNeedCalling = false;
|
||||
needsUpdate = true;
|
||||
}
|
||||
|
||||
float denormalise (float normalised) const
|
||||
{
|
||||
return getParameter().convertFrom0to1 (normalised);
|
||||
}
|
||||
|
||||
float normalise (float denormalised) const
|
||||
{
|
||||
return getParameter().convertTo0to1 (denormalised);
|
||||
}
|
||||
|
||||
void setNormalisedValue (float value)
|
||||
{
|
||||
if (ignoreParameterChangedCallbacks)
|
||||
return;
|
||||
|
||||
parameter.setValueNotifyingHost (value);
|
||||
}
|
||||
|
||||
class LockedListeners
|
||||
{
|
||||
public:
|
||||
template <typename Fn>
|
||||
void call (Fn&& fn)
|
||||
{
|
||||
const CriticalSection::ScopedLockType lock (mutex);
|
||||
listeners.call (std::forward<Fn> (fn));
|
||||
}
|
||||
|
||||
void add (Listener* l)
|
||||
{
|
||||
const CriticalSection::ScopedLockType lock (mutex);
|
||||
listeners.add (l);
|
||||
}
|
||||
|
||||
void remove (Listener* l)
|
||||
{
|
||||
const CriticalSection::ScopedLockType lock (mutex);
|
||||
listeners.remove (l);
|
||||
}
|
||||
|
||||
private:
|
||||
CriticalSection mutex;
|
||||
ListenerList<Listener> listeners;
|
||||
};
|
||||
|
||||
RangedAudioParameter& parameter;
|
||||
LockedListeners listeners;
|
||||
std::atomic<float> unnormalisedValue { 0.0f };
|
||||
std::atomic<bool> needsUpdate { true }, listenersNeedCalling { true };
|
||||
bool ignoreParameterChangedCallbacks { false };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& processorToConnectTo,
|
||||
UndoManager* undoManagerToUse,
|
||||
const Identifier& valueTreeType,
|
||||
ParameterLayout parameterLayout)
|
||||
: AudioProcessorValueTreeState (processorToConnectTo, undoManagerToUse)
|
||||
{
|
||||
struct PushBackVisitor final : ParameterLayout::Visitor
|
||||
{
|
||||
explicit PushBackVisitor (AudioProcessorValueTreeState& stateIn)
|
||||
: state (&stateIn) {}
|
||||
|
||||
void visit (std::unique_ptr<RangedAudioParameter> param) const override
|
||||
{
|
||||
if (param == nullptr)
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
state->addParameterAdapter (*param);
|
||||
state->processor.addParameter (param.release());
|
||||
}
|
||||
|
||||
void visit (std::unique_ptr<AudioProcessorParameterGroup> group) const override
|
||||
{
|
||||
if (group == nullptr)
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto param : group->getParameters (true))
|
||||
{
|
||||
if (const auto rangedParam = dynamic_cast<RangedAudioParameter*> (param))
|
||||
{
|
||||
state->addParameterAdapter (*rangedParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If you hit this assertion then you are attempting to add a parameter that is
|
||||
// not derived from RangedAudioParameter to the AudioProcessorValueTreeState.
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
state->processor.addParameterGroup (std::move (group));
|
||||
}
|
||||
|
||||
AudioProcessorValueTreeState* state;
|
||||
};
|
||||
|
||||
for (auto& item : parameterLayout.parameters)
|
||||
item->accept (PushBackVisitor (*this));
|
||||
|
||||
state = ValueTree (valueTreeType);
|
||||
}
|
||||
|
||||
AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& p, UndoManager* um)
|
||||
: processor (p), undoManager (um)
|
||||
{
|
||||
startTimerHz (10);
|
||||
state.addListener (this);
|
||||
}
|
||||
|
||||
AudioProcessorValueTreeState::~AudioProcessorValueTreeState()
|
||||
{
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (const String& paramID,
|
||||
const String& paramName,
|
||||
const String& labelText,
|
||||
NormalisableRange<float> range,
|
||||
float defaultVal,
|
||||
std::function<String (float)> valueToTextFunction,
|
||||
std::function<float (const String&)> textToValueFunction,
|
||||
bool isMetaParameter,
|
||||
bool isAutomatableParameter,
|
||||
bool isDiscreteParameter,
|
||||
AudioProcessorParameter::Category category,
|
||||
bool isBooleanParameter)
|
||||
{
|
||||
auto attributes = AudioProcessorValueTreeStateParameterAttributes()
|
||||
.withLabel (labelText)
|
||||
.withStringFromValueFunction ([fn = std::move (valueToTextFunction)] (float v, int) { return fn (v); })
|
||||
.withValueFromStringFunction (std::move (textToValueFunction))
|
||||
.withMeta (isMetaParameter)
|
||||
.withAutomatable (isAutomatableParameter)
|
||||
.withDiscrete (isDiscreteParameter)
|
||||
.withCategory (category)
|
||||
.withBoolean (isBooleanParameter);
|
||||
|
||||
return createAndAddParameter (std::make_unique<Parameter> (paramID,
|
||||
paramName,
|
||||
range,
|
||||
defaultVal,
|
||||
std::move (attributes)));
|
||||
}
|
||||
|
||||
RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (std::unique_ptr<RangedAudioParameter> param)
|
||||
{
|
||||
if (param == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// All parameters must be created before giving this manager a ValueTree state!
|
||||
jassert (! state.isValid());
|
||||
|
||||
if (getParameter (param->paramID) != nullptr)
|
||||
return nullptr;
|
||||
|
||||
addParameterAdapter (*param);
|
||||
|
||||
processor.addParameter (param.get());
|
||||
|
||||
return param.release();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AudioProcessorValueTreeState::addParameterAdapter (RangedAudioParameter& param)
|
||||
{
|
||||
adapterTable.emplace (param.paramID, std::make_unique<ParameterAdapter> (param));
|
||||
}
|
||||
|
||||
AudioProcessorValueTreeState::ParameterAdapter* AudioProcessorValueTreeState::getParameterAdapter (StringRef paramID) const
|
||||
{
|
||||
auto it = adapterTable.find (paramID);
|
||||
return it == adapterTable.end() ? nullptr : it->second.get();
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::addParameterListener (StringRef paramID, Listener* listener)
|
||||
{
|
||||
if (auto* p = getParameterAdapter (paramID))
|
||||
p->addListener (listener);
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::removeParameterListener (StringRef paramID, Listener* listener)
|
||||
{
|
||||
if (auto* p = getParameterAdapter (paramID))
|
||||
p->removeListener (listener);
|
||||
}
|
||||
|
||||
Value AudioProcessorValueTreeState::getParameterAsValue (StringRef paramID) const
|
||||
{
|
||||
if (auto* adapter = getParameterAdapter (paramID))
|
||||
if (adapter->tree.isValid())
|
||||
return adapter->tree.getPropertyAsValue (valuePropertyID, undoManager);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
NormalisableRange<float> AudioProcessorValueTreeState::getParameterRange (StringRef paramID) const noexcept
|
||||
{
|
||||
if (auto* p = getParameterAdapter (paramID))
|
||||
return p->getRange();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
RangedAudioParameter* AudioProcessorValueTreeState::getParameter (StringRef paramID) const noexcept
|
||||
{
|
||||
if (auto adapter = getParameterAdapter (paramID))
|
||||
return &adapter->getParameter();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::atomic<float>* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept
|
||||
{
|
||||
if (auto* p = getParameterAdapter (paramID))
|
||||
return &p->getRawDenormalisedValue();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ValueTree AudioProcessorValueTreeState::copyState()
|
||||
{
|
||||
ScopedLock lock (valueTreeChanging);
|
||||
flushParameterValuesToValueTree();
|
||||
return state.createCopy();
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::replaceState (const ValueTree& newState)
|
||||
{
|
||||
ScopedLock lock (valueTreeChanging);
|
||||
|
||||
state = newState;
|
||||
|
||||
if (undoManager != nullptr)
|
||||
undoManager->clearUndoHistory();
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::setNewState (ValueTree vt)
|
||||
{
|
||||
jassert (vt.getParent() == state);
|
||||
|
||||
if (auto* p = getParameterAdapter (vt.getProperty (idPropertyID).toString()))
|
||||
{
|
||||
p->tree = vt;
|
||||
p->setDenormalisedValue (p->tree.getProperty (valuePropertyID, p->getDenormalisedDefaultValue()));
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::updateParameterConnectionsToChildTrees()
|
||||
{
|
||||
ScopedLock lock (valueTreeChanging);
|
||||
|
||||
for (auto& p : adapterTable)
|
||||
p.second->tree = ValueTree();
|
||||
|
||||
for (const auto& child : state)
|
||||
setNewState (child);
|
||||
|
||||
for (auto& p : adapterTable)
|
||||
{
|
||||
auto& adapter = *p.second;
|
||||
|
||||
if (! adapter.tree.isValid())
|
||||
{
|
||||
adapter.tree = ValueTree (valueType);
|
||||
adapter.tree.setProperty (idPropertyID, adapter.getParameter().paramID, nullptr);
|
||||
state.appendChild (adapter.tree, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
flushParameterValuesToValueTree();
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::valueTreePropertyChanged (ValueTree& tree, const Identifier&)
|
||||
{
|
||||
if (tree.hasType (valueType) && tree.getParent() == state)
|
||||
setNewState (tree);
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::valueTreeChildAdded (ValueTree& parent, ValueTree& tree)
|
||||
{
|
||||
if (parent == state && tree.hasType (valueType))
|
||||
setNewState (tree);
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::valueTreeRedirected (ValueTree& v)
|
||||
{
|
||||
if (v == state)
|
||||
updateParameterConnectionsToChildTrees();
|
||||
}
|
||||
|
||||
bool AudioProcessorValueTreeState::flushParameterValuesToValueTree()
|
||||
{
|
||||
ScopedLock lock (valueTreeChanging);
|
||||
|
||||
bool anyUpdated = false;
|
||||
|
||||
for (auto& p : adapterTable)
|
||||
anyUpdated |= p.second->flushToTree (valuePropertyID, undoManager);
|
||||
|
||||
return anyUpdated;
|
||||
}
|
||||
|
||||
void AudioProcessorValueTreeState::timerCallback()
|
||||
{
|
||||
auto anythingUpdated = flushParameterValuesToValueTree();
|
||||
|
||||
startTimer (anythingUpdated ? 1000 / 50
|
||||
: jlimit (50, 500, getTimerInterval() + 20));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename Attachment, typename Control>
|
||||
std::unique_ptr<Attachment> makeAttachment (const AudioProcessorValueTreeState& stateToUse,
|
||||
const String& parameterID,
|
||||
Control& control)
|
||||
{
|
||||
if (auto* parameter = stateToUse.getParameter (parameterID))
|
||||
return std::make_unique<Attachment> (*parameter, control, stateToUse.undoManager);
|
||||
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AudioProcessorValueTreeState::SliderAttachment::SliderAttachment (AudioProcessorValueTreeState& stateToUse,
|
||||
const String& parameterID,
|
||||
Slider& slider)
|
||||
: attachment (makeAttachment<SliderParameterAttachment> (stateToUse, parameterID, slider))
|
||||
{
|
||||
}
|
||||
|
||||
AudioProcessorValueTreeState::ComboBoxAttachment::ComboBoxAttachment (AudioProcessorValueTreeState& stateToUse,
|
||||
const String& parameterID,
|
||||
ComboBox& combo)
|
||||
: attachment (makeAttachment<ComboBoxParameterAttachment> (stateToUse, parameterID, combo))
|
||||
{
|
||||
}
|
||||
|
||||
AudioProcessorValueTreeState::ButtonAttachment::ButtonAttachment (AudioProcessorValueTreeState& stateToUse,
|
||||
const String& parameterID,
|
||||
Button& button)
|
||||
: attachment (makeAttachment<ButtonParameterAttachment> (stateToUse, parameterID, button))
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
struct ParameterAdapterTests final : public UnitTest
|
||||
{
|
||||
ParameterAdapterTests()
|
||||
: UnitTest ("Parameter Adapter", UnitTestCategories::audioProcessorParameters)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("The default value is returned correctly");
|
||||
{
|
||||
const auto test = [&] (NormalisableRange<float> range, float value)
|
||||
{
|
||||
AudioParameterFloat param ({}, {}, range, value);
|
||||
|
||||
AudioProcessorValueTreeState::ParameterAdapter adapter (param);
|
||||
|
||||
expectEquals (adapter.getDenormalisedDefaultValue(), value);
|
||||
};
|
||||
|
||||
test ({ -100, 100 }, 0);
|
||||
test ({ -2.5, 12.5 }, 10);
|
||||
}
|
||||
|
||||
beginTest ("Denormalised parameter values can be retrieved");
|
||||
{
|
||||
const auto test = [&] (NormalisableRange<float> range, float value)
|
||||
{
|
||||
AudioParameterFloat param ({}, {}, range, {});
|
||||
AudioProcessorValueTreeState::ParameterAdapter adapter (param);
|
||||
|
||||
adapter.setDenormalisedValue (value);
|
||||
|
||||
expectEquals (adapter.getDenormalisedValue(), value);
|
||||
expectEquals (adapter.getRawDenormalisedValue().load(), value);
|
||||
};
|
||||
|
||||
test ({ -20, -10 }, -15);
|
||||
test ({ 0, 7.5 }, 2.5);
|
||||
}
|
||||
|
||||
beginTest ("Floats can be converted to text");
|
||||
{
|
||||
const auto test = [&] (NormalisableRange<float> range, float value, String expected)
|
||||
{
|
||||
AudioParameterFloat param ({}, {}, range, {});
|
||||
AudioProcessorValueTreeState::ParameterAdapter adapter (param);
|
||||
|
||||
expectEquals (adapter.getTextForDenormalisedValue (value), expected);
|
||||
};
|
||||
|
||||
test ({ -100, 100 }, 0, "0.0000000");
|
||||
test ({ -2.5, 12.5 }, 10, "10.0000000");
|
||||
test ({ -20, -10 }, -15, "-15.0000000");
|
||||
test ({ 0, 7.5 }, 2.5, "2.5000000");
|
||||
}
|
||||
|
||||
beginTest ("Text can be converted to floats");
|
||||
{
|
||||
const auto test = [&] (NormalisableRange<float> range, String text, float expected)
|
||||
{
|
||||
AudioParameterFloat param ({}, {}, range, {});
|
||||
AudioProcessorValueTreeState::ParameterAdapter adapter (param);
|
||||
|
||||
expectEquals (adapter.getDenormalisedValueForText (text), expected);
|
||||
};
|
||||
|
||||
test ({ -100, 100 }, "0.0", 0);
|
||||
test ({ -2.5, 12.5 }, "10.0", 10);
|
||||
test ({ -20, -10 }, "-15.0", -15);
|
||||
test ({ 0, 7.5 }, "2.5", 2.5);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static ParameterAdapterTests parameterAdapterTests;
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename ValueType>
|
||||
inline bool operator== (const NormalisableRange<ValueType>& a,
|
||||
const NormalisableRange<ValueType>& b)
|
||||
{
|
||||
return std::tie (a.start, a.end, a.interval, a.skew, a.symmetricSkew)
|
||||
== std::tie (b.start, b.end, b.interval, b.skew, b.symmetricSkew);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline bool operator!= (const NormalisableRange<ValueType>& a,
|
||||
const NormalisableRange<ValueType>& b)
|
||||
{
|
||||
return ! (a == b);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class AudioProcessorValueTreeStateTests final : public UnitTest
|
||||
{
|
||||
private:
|
||||
using Parameter = AudioProcessorValueTreeState::Parameter;
|
||||
using ParameterGroup = AudioProcessorParameterGroup;
|
||||
using ParameterLayout = AudioProcessorValueTreeState::ParameterLayout;
|
||||
using Attributes = AudioProcessorValueTreeStateParameterAttributes;
|
||||
|
||||
class TestAudioProcessor final : public AudioProcessor
|
||||
{
|
||||
public:
|
||||
TestAudioProcessor() = default;
|
||||
|
||||
explicit TestAudioProcessor (ParameterLayout layout)
|
||||
: state (*this, nullptr, "state", std::move (layout)) {}
|
||||
|
||||
const String getName() const override { return {}; }
|
||||
void prepareToPlay (double, int) override {}
|
||||
void releaseResources() override {}
|
||||
void processBlock (AudioBuffer<float>&, MidiBuffer&) override {}
|
||||
using AudioProcessor::processBlock;
|
||||
double getTailLengthSeconds() const override { return {}; }
|
||||
bool acceptsMidi() const override { return {}; }
|
||||
bool producesMidi() const override { return {}; }
|
||||
AudioProcessorEditor* createEditor() override { return {}; }
|
||||
bool hasEditor() const override { return {}; }
|
||||
int getNumPrograms() override { return 1; }
|
||||
int getCurrentProgram() override { return {}; }
|
||||
void setCurrentProgram (int) override {}
|
||||
const String getProgramName (int) override { return {}; }
|
||||
void changeProgramName (int, const String&) override {}
|
||||
void getStateInformation (MemoryBlock&) override {}
|
||||
void setStateInformation (const void*, int) override {}
|
||||
|
||||
AudioProcessorValueTreeState state { *this, nullptr };
|
||||
};
|
||||
|
||||
struct Listener final : public AudioProcessorValueTreeState::Listener
|
||||
{
|
||||
void parameterChanged (const String& idIn, float valueIn) override
|
||||
{
|
||||
id = idIn;
|
||||
value = valueIn;
|
||||
}
|
||||
|
||||
String id;
|
||||
float value{};
|
||||
};
|
||||
|
||||
public:
|
||||
AudioProcessorValueTreeStateTests()
|
||||
: UnitTest ("Audio Processor Value Tree State", UnitTestCategories::audioProcessorParameters)
|
||||
{}
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6262)
|
||||
void runTest() override
|
||||
{
|
||||
ScopedJuceInitialiser_GUI scopedJuceInitialiser_gui;
|
||||
|
||||
beginTest ("After calling createAndAddParameter, the number of parameters increases by one");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
|
||||
proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
String(),
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f));
|
||||
|
||||
expectEquals (proc.getParameters().size(), 1);
|
||||
}
|
||||
|
||||
beginTest ("After creating a normal named parameter, we can later retrieve that parameter");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f));
|
||||
|
||||
expect (proc.state.getParameter (key) == param);
|
||||
}
|
||||
|
||||
beginTest ("After construction, the value tree has the expected format");
|
||||
{
|
||||
TestAudioProcessor proc ({
|
||||
std::make_unique<AudioProcessorParameterGroup> ("A", "", "",
|
||||
std::make_unique<AudioParameterBool> ("a", "", false),
|
||||
std::make_unique<AudioParameterFloat> ("b", "", NormalisableRange<float>{}, 0.0f)),
|
||||
std::make_unique<AudioProcessorParameterGroup> ("B", "", "",
|
||||
std::make_unique<AudioParameterInt> ("c", "", 0, 1, 0),
|
||||
std::make_unique<AudioParameterChoice> ("d", "", StringArray { "foo", "bar" }, 0)) });
|
||||
|
||||
const auto valueTree = proc.state.copyState();
|
||||
|
||||
expectEquals (valueTree.getNumChildren(), 4);
|
||||
|
||||
for (auto child : valueTree)
|
||||
{
|
||||
expect (child.hasType ("PARAM"));
|
||||
expect (child.hasProperty ("id"));
|
||||
expect (child.hasProperty ("value"));
|
||||
}
|
||||
}
|
||||
|
||||
beginTest ("Meta parameters can be created");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f,
|
||||
Attributes().withMeta (true)));
|
||||
|
||||
expect (param->isMetaParameter());
|
||||
}
|
||||
|
||||
beginTest ("Automatable parameters can be created");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f,
|
||||
Attributes().withAutomatable (true)));
|
||||
|
||||
expect (param->isAutomatable());
|
||||
}
|
||||
|
||||
beginTest ("Discrete parameters can be created");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f,
|
||||
Attributes().withDiscrete (true)));
|
||||
|
||||
expect (param->isDiscrete());
|
||||
}
|
||||
|
||||
beginTest ("Custom category parameters can be created");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f,
|
||||
Attributes().withCategory (AudioProcessorParameter::Category::inputMeter)));
|
||||
|
||||
expect (param->category == AudioProcessorParameter::Category::inputMeter);
|
||||
}
|
||||
|
||||
beginTest ("Boolean parameters can be created");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f,
|
||||
Attributes().withBoolean (true)));
|
||||
|
||||
expect (param->isBoolean());
|
||||
}
|
||||
|
||||
beginTest ("After creating a custom named parameter, we can later retrieve that parameter");
|
||||
{
|
||||
const auto key = "id";
|
||||
auto param = std::make_unique<AudioParameterBool> (key, "", false);
|
||||
const auto paramPtr = param.get();
|
||||
|
||||
TestAudioProcessor proc (std::move (param));
|
||||
|
||||
expect (proc.state.getParameter (key) == paramPtr);
|
||||
}
|
||||
|
||||
beginTest ("After adding a normal parameter that already exists, the AudioProcessor parameters are unchanged");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f));
|
||||
|
||||
proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f));
|
||||
|
||||
expectEquals (proc.getParameters().size(), 1);
|
||||
expect (proc.getParameters().getFirst() == param);
|
||||
}
|
||||
|
||||
beginTest ("After setting a parameter value, that value is reflected in the state");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f));
|
||||
|
||||
const auto value = 0.5f;
|
||||
param->setValueNotifyingHost (value);
|
||||
|
||||
expectEquals (proc.state.getRawParameterValue (key)->load(), value);
|
||||
}
|
||||
|
||||
beginTest ("After adding an APVTS::Parameter, its value is the default value");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
const auto key = "id";
|
||||
const auto value = 5.0f;
|
||||
|
||||
proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float> (0.0f, 100.0f, 10.0f),
|
||||
value));
|
||||
|
||||
expectEquals (proc.state.getRawParameterValue (key)->load(), value);
|
||||
}
|
||||
|
||||
beginTest ("Listeners receive notifications when parameters change");
|
||||
{
|
||||
Listener listener;
|
||||
TestAudioProcessor proc;
|
||||
const auto key = "id";
|
||||
const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f));
|
||||
proc.state.addParameterListener (key, &listener);
|
||||
|
||||
const auto value = 0.5f;
|
||||
param->setValueNotifyingHost (value);
|
||||
|
||||
expectEquals (listener.id, String { key });
|
||||
expectEquals (listener.value, value);
|
||||
}
|
||||
|
||||
beginTest ("Bool parameters have a range of 0-1");
|
||||
{
|
||||
const auto key = "id";
|
||||
|
||||
TestAudioProcessor proc (std::make_unique<AudioParameterBool> (key, "", false));
|
||||
|
||||
expect (proc.state.getParameterRange (key) == NormalisableRange<float> (0.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
beginTest ("Float parameters retain their specified range");
|
||||
{
|
||||
const auto key = "id";
|
||||
const auto range = NormalisableRange<float> { -100, 100, 0.7f, 0.2f, true };
|
||||
|
||||
TestAudioProcessor proc (std::make_unique<AudioParameterFloat> (key, "", range, 0.0f));
|
||||
|
||||
expect (proc.state.getParameterRange (key) == range);
|
||||
}
|
||||
|
||||
beginTest ("Int parameters retain their specified range");
|
||||
{
|
||||
const auto key = "id";
|
||||
const auto min = -27;
|
||||
const auto max = 53;
|
||||
|
||||
TestAudioProcessor proc (std::make_unique<AudioParameterInt> (key, "", min, max, 0));
|
||||
|
||||
expect (proc.state.getParameterRange (key) == NormalisableRange<float> (float (min), float (max), 1.0f));
|
||||
}
|
||||
|
||||
beginTest ("Choice parameters retain their specified range");
|
||||
{
|
||||
const auto key = "id";
|
||||
const auto choices = StringArray { "", "", "" };
|
||||
|
||||
TestAudioProcessor proc (std::make_unique<AudioParameterChoice> (key, "", choices, 0));
|
||||
|
||||
expect (proc.state.getParameterRange (key) == NormalisableRange<float> (0.0f, (float) (choices.size() - 1), 1.0f));
|
||||
expect (proc.state.getParameter (key)->getNumSteps() == choices.size());
|
||||
}
|
||||
|
||||
beginTest ("When the parameter value is changed, normal parameter values are updated");
|
||||
{
|
||||
TestAudioProcessor proc;
|
||||
const auto key = "id";
|
||||
const auto initialValue = 0.2f;
|
||||
auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
initialValue));
|
||||
proc.state.state = ValueTree { "state" };
|
||||
|
||||
auto value = proc.state.getParameterAsValue (key);
|
||||
expectEquals (float (value.getValue()), initialValue);
|
||||
|
||||
const auto newValue = 0.75f;
|
||||
value = newValue;
|
||||
|
||||
expectEquals (param->getValue(), newValue);
|
||||
expectEquals (proc.state.getRawParameterValue (key)->load(), newValue);
|
||||
}
|
||||
|
||||
beginTest ("When the parameter value is changed, custom parameter values are updated");
|
||||
{
|
||||
const auto key = "id";
|
||||
const auto choices = StringArray ("foo", "bar", "baz");
|
||||
auto param = std::make_unique<AudioParameterChoice> (key, "", choices, 0);
|
||||
const auto paramPtr = param.get();
|
||||
TestAudioProcessor proc (std::move (param));
|
||||
|
||||
const auto newValue = 2.0f;
|
||||
auto value = proc.state.getParameterAsValue (key);
|
||||
value = newValue;
|
||||
|
||||
expectEquals (paramPtr->getCurrentChoiceName(), choices[int (newValue)]);
|
||||
expectEquals (proc.state.getRawParameterValue (key)->load(), newValue);
|
||||
}
|
||||
|
||||
beginTest ("When the parameter value is changed, listeners are notified");
|
||||
{
|
||||
Listener listener;
|
||||
TestAudioProcessor proc;
|
||||
const auto key = "id";
|
||||
proc.state.createAndAddParameter (std::make_unique<Parameter> (
|
||||
key,
|
||||
String(),
|
||||
NormalisableRange<float>(),
|
||||
0.0f));
|
||||
proc.state.addParameterListener (key, &listener);
|
||||
proc.state.state = ValueTree { "state" };
|
||||
|
||||
const auto newValue = 0.75f;
|
||||
proc.state.getParameterAsValue (key) = newValue;
|
||||
|
||||
expectEquals (listener.value, newValue);
|
||||
expectEquals (listener.id, String { key });
|
||||
}
|
||||
|
||||
beginTest ("When the parameter value is changed, listeners are notified");
|
||||
{
|
||||
const auto key = "id";
|
||||
const auto choices = StringArray { "foo", "bar", "baz" };
|
||||
Listener listener;
|
||||
TestAudioProcessor proc (std::make_unique<AudioParameterChoice> (key, "", choices, 0));
|
||||
proc.state.addParameterListener (key, &listener);
|
||||
|
||||
const auto newValue = 2.0f;
|
||||
proc.state.getParameterAsValue (key) = newValue;
|
||||
|
||||
expectEquals (listener.value, newValue);
|
||||
expectEquals (listener.id, String (key));
|
||||
}
|
||||
}
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
};
|
||||
|
||||
static AudioProcessorValueTreeStateTests audioProcessorValueTreeStateTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
Vendored
+660
@@ -0,0 +1,660 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/** Advanced properties of an AudioProcessorValueTreeState::Parameter.
|
||||
|
||||
The members here have the same meaning as the similarly-named member functions of
|
||||
AudioParameterFloatAttributes.
|
||||
|
||||
@see AudioParameterFloatAttributes, RangedAudioParameterAttributes
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class AudioProcessorValueTreeStateParameterAttributes
|
||||
{
|
||||
using This = AudioProcessorValueTreeStateParameterAttributes;
|
||||
using StringFromValue = AudioParameterFloatAttributes::StringFromValue;
|
||||
using ValueFromString = AudioParameterFloatAttributes::ValueFromString;
|
||||
using Category = AudioParameterFloatAttributes::Category;
|
||||
|
||||
public:
|
||||
/** @see RangedAudioParameterAttributes::withStringFromValueFunction() */
|
||||
[[nodiscard]] auto withStringFromValueFunction (StringFromValue x) const { return withMember (*this, &This::attributes, attributes.withStringFromValueFunction (std::move (x))); }
|
||||
/** @see RangedAudioParameterAttributes::withValueFromStringFunction() */
|
||||
[[nodiscard]] auto withValueFromStringFunction (ValueFromString x) const { return withMember (*this, &This::attributes, attributes.withValueFromStringFunction (std::move (x))); }
|
||||
/** @see RangedAudioParameterAttributes::withLabel() */
|
||||
[[nodiscard]] auto withLabel (String x) const { return withMember (*this, &This::attributes, attributes.withLabel (std::move (x))); }
|
||||
/** @see RangedAudioParameterAttributes::withCategory() */
|
||||
[[nodiscard]] auto withCategory (Category x) const { return withMember (*this, &This::attributes, attributes.withCategory (std::move (x))); }
|
||||
/** @see RangedAudioParameterAttributes::withMeta() */
|
||||
[[nodiscard]] auto withMeta (bool x) const { return withMember (*this, &This::attributes, attributes.withMeta (std::move (x))); }
|
||||
/** @see RangedAudioParameterAttributes::withAutomatable() */
|
||||
[[nodiscard]] auto withAutomatable (bool x) const { return withMember (*this, &This::attributes, attributes.withAutomatable (std::move (x))); }
|
||||
/** @see RangedAudioParameterAttributes::withInverted() */
|
||||
[[nodiscard]] auto withInverted (bool x) const { return withMember (*this, &This::attributes, attributes.withInverted (std::move (x))); }
|
||||
|
||||
/** Pass 'true' if this parameter has discrete steps, or 'false' if the parameter is continuous.
|
||||
|
||||
Using an AudioParameterChoice or AudioParameterInt might be a better choice than setting this flag.
|
||||
*/
|
||||
[[nodiscard]] auto withDiscrete (bool x) const { return withMember (*this, &This::discrete, std::move (x)); }
|
||||
|
||||
/** Pass 'true' if this parameter only has two valid states.
|
||||
|
||||
Using an AudioParameterBool might be a better choice than setting this flag.
|
||||
*/
|
||||
[[nodiscard]] auto withBoolean (bool x) const { return withMember (*this, &This::boolean, std::move (x)); }
|
||||
|
||||
/** @returns all attributes that might also apply to an AudioParameterFloat */
|
||||
[[nodiscard]] const auto& getAudioParameterFloatAttributes() const { return attributes; }
|
||||
/** @returns 'true' if this parameter has discrete steps, or 'false' if the parameter is continuous. */
|
||||
[[nodiscard]] const auto& getDiscrete() const { return discrete; }
|
||||
/** @returns 'true' if this parameter only has two valid states. */
|
||||
[[nodiscard]] const auto& getBoolean() const { return boolean; }
|
||||
|
||||
private:
|
||||
AudioParameterFloatAttributes attributes;
|
||||
bool discrete = false, boolean = false;
|
||||
};
|
||||
|
||||
/**
|
||||
This class contains a ValueTree that is used to manage an AudioProcessor's entire state.
|
||||
|
||||
It has its own internal class of parameter object that is linked to values
|
||||
within its ValueTree, and which are each identified by a string ID.
|
||||
|
||||
You can get access to the underlying ValueTree object via the state member variable,
|
||||
so you can add extra properties to it as necessary.
|
||||
|
||||
It also provides some utility child classes for connecting parameters directly to
|
||||
GUI controls like sliders.
|
||||
|
||||
The favoured constructor of this class takes a collection of RangedAudioParameters or
|
||||
AudioProcessorParameterGroups of RangedAudioParameters and adds them to the attached
|
||||
AudioProcessor directly.
|
||||
|
||||
The deprecated way of using this class is as follows:
|
||||
|
||||
1) Create an AudioProcessorValueTreeState, and give it some parameters using createAndAddParameter().
|
||||
2) Initialise the state member variable with a type name.
|
||||
|
||||
The deprecated constructor will be removed from the API in a future version of JUCE!
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioProcessorValueTreeState : private Timer,
|
||||
private ValueTree::Listener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** A class to contain a set of RangedAudioParameters and AudioProcessorParameterGroups
|
||||
containing RangedAudioParameters.
|
||||
|
||||
This class is used in the AudioProcessorValueTreeState constructor to allow
|
||||
arbitrarily grouped RangedAudioParameters to be passed to an AudioProcessor.
|
||||
*/
|
||||
class JUCE_API ParameterLayout final
|
||||
{
|
||||
private:
|
||||
//==============================================================================
|
||||
template <typename It>
|
||||
using ValidIfIterator = decltype (std::next (std::declval<It>()));
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
template <typename... Items>
|
||||
ParameterLayout (std::unique_ptr<Items>... items) { add (std::move (items)...); }
|
||||
|
||||
template <typename It, typename = ValidIfIterator<It>>
|
||||
ParameterLayout (It begin, It end) { add (begin, end); }
|
||||
|
||||
template <typename... Items>
|
||||
void add (std::unique_ptr<Items>... items)
|
||||
{
|
||||
parameters.reserve (parameters.size() + sizeof... (items));
|
||||
(parameters.push_back (makeParameterStorage (std::move (items))), ...);
|
||||
}
|
||||
|
||||
template <typename It, typename = ValidIfIterator<It>>
|
||||
void add (It begin, It end)
|
||||
{
|
||||
parameters.reserve (parameters.size() + std::size_t (std::distance (begin, end)));
|
||||
std::transform (std::make_move_iterator (begin),
|
||||
std::make_move_iterator (end),
|
||||
std::back_inserter (parameters),
|
||||
[] (auto item) { return makeParameterStorage (std::move (item)); });
|
||||
}
|
||||
|
||||
ParameterLayout (const ParameterLayout& other) = delete;
|
||||
ParameterLayout (ParameterLayout&& other) noexcept { swap (other); }
|
||||
|
||||
ParameterLayout& operator= (const ParameterLayout& other) = delete;
|
||||
ParameterLayout& operator= (ParameterLayout&& other) noexcept { swap (other); return *this; }
|
||||
|
||||
void swap (ParameterLayout& other) noexcept { std::swap (other.parameters, parameters); }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct Visitor
|
||||
{
|
||||
virtual ~Visitor() = default;
|
||||
|
||||
// If you have a compiler error telling you that there is no matching
|
||||
// member function to call for 'visit', then you are probably attempting
|
||||
// to add a parameter that is not derived from RangedAudioParameter to
|
||||
// the AudioProcessorValueTreeState.
|
||||
virtual void visit (std::unique_ptr<RangedAudioParameter>) const = 0;
|
||||
virtual void visit (std::unique_ptr<AudioProcessorParameterGroup>) const = 0;
|
||||
};
|
||||
|
||||
struct ParameterStorageBase
|
||||
{
|
||||
virtual ~ParameterStorageBase() = default;
|
||||
virtual void accept (const Visitor& visitor) = 0;
|
||||
};
|
||||
|
||||
template <typename Contents>
|
||||
struct ParameterStorage : ParameterStorageBase
|
||||
{
|
||||
explicit ParameterStorage (std::unique_ptr<Contents> input) : contents (std::move (input)) {}
|
||||
|
||||
void accept (const Visitor& visitor) override { visitor.visit (std::move (contents)); }
|
||||
|
||||
std::unique_ptr<Contents> contents;
|
||||
};
|
||||
|
||||
template <typename Contents>
|
||||
static std::unique_ptr<ParameterStorage<Contents>> makeParameterStorage (std::unique_ptr<Contents> contents)
|
||||
{
|
||||
return std::make_unique<ParameterStorage<Contents>> (std::move (contents));
|
||||
}
|
||||
|
||||
void add() {}
|
||||
|
||||
friend class AudioProcessorValueTreeState;
|
||||
|
||||
std::vector<std::unique_ptr<ParameterStorageBase>> parameters;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a state object for a given processor, and sets up all the parameters
|
||||
that will control that processor.
|
||||
|
||||
You should *not* assign a new ValueTree to the state, or call
|
||||
createAndAddParameter, after using this constructor.
|
||||
|
||||
Note that each AudioProcessorValueTreeState should be attached to only one
|
||||
processor, and must have the same lifetime as the processor, as they will
|
||||
have dependencies on each other.
|
||||
|
||||
The ParameterLayout parameter has a set of constructors that allow you to
|
||||
add multiple RangedAudioParameters and AudioProcessorParameterGroups containing
|
||||
RangedAudioParameters to the AudioProcessorValueTreeState inside this constructor.
|
||||
|
||||
@code
|
||||
YourAudioProcessor()
|
||||
: apvts (*this, &undoManager, "PARAMETERS",
|
||||
{ std::make_unique<AudioParameterFloat> ("a", "Parameter A", NormalisableRange<float> (-100.0f, 100.0f), 0),
|
||||
std::make_unique<AudioParameterInt> ("b", "Parameter B", 0, 5, 2) })
|
||||
@endcode
|
||||
|
||||
To add parameters programmatically you can call `add` repeatedly on a
|
||||
ParameterLayout instance:
|
||||
|
||||
@code
|
||||
AudioProcessorValueTreeState::ParameterLayout createParameterLayout()
|
||||
{
|
||||
AudioProcessorValueTreeState::ParameterLayout layout;
|
||||
|
||||
for (int i = 1; i < 9; ++i)
|
||||
layout.add (std::make_unique<AudioParameterInt> (String (i), String (i), 0, i, 0));
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
YourAudioProcessor()
|
||||
: apvts (*this, &undoManager, "PARAMETERS", createParameterLayout())
|
||||
{
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param processorToConnectTo The Processor that will be managed by this object
|
||||
@param undoManagerToUse An optional UndoManager to use; pass nullptr if no UndoManager is required
|
||||
@param valueTreeType The identifier used to initialise the internal ValueTree
|
||||
@param parameterLayout An object that holds all parameters and parameter groups that the
|
||||
AudioProcessor should use.
|
||||
*/
|
||||
AudioProcessorValueTreeState (AudioProcessor& processorToConnectTo,
|
||||
UndoManager* undoManagerToUse,
|
||||
const Identifier& valueTreeType,
|
||||
ParameterLayout parameterLayout);
|
||||
|
||||
/** This constructor is discouraged and will be deprecated in a future version of JUCE!
|
||||
Use the other constructor instead.
|
||||
|
||||
Creates a state object for a given processor.
|
||||
|
||||
The UndoManager is optional and can be a nullptr. After creating your state object,
|
||||
you should add parameters with the createAndAddParameter() method. Note that each
|
||||
AudioProcessorValueTreeState should be attached to only one processor, and must have
|
||||
the same lifetime as the processor, as they will have dependencies on each other.
|
||||
*/
|
||||
AudioProcessorValueTreeState (AudioProcessor& processorToConnectTo, UndoManager* undoManagerToUse);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioProcessorValueTreeState() override;
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
/** Previous calls to
|
||||
|
||||
@code
|
||||
createAndAddParameter (paramID1, paramName1, ...);
|
||||
@endcode
|
||||
|
||||
can be replaced with
|
||||
|
||||
@code
|
||||
using Parameter = AudioProcessorValueTreeState::Parameter;
|
||||
createAndAddParameter (std::make_unique<Parameter> (paramID1, paramName1, ...));
|
||||
@endcode
|
||||
|
||||
However, a much better approach is to use the AudioProcessorValueTreeState
|
||||
constructor directly
|
||||
|
||||
@code
|
||||
using Parameter = AudioProcessorValueTreeState::Parameter;
|
||||
YourAudioProcessor()
|
||||
: apvts (*this, &undoManager, "PARAMETERS", { std::make_unique<Parameter> (paramID1, paramName1, ...),
|
||||
std::make_unique<Parameter> (paramID2, paramName2, ...),
|
||||
... })
|
||||
@endcode
|
||||
|
||||
@see AudioProcessorValueTreeState::AudioProcessorValueTreeState
|
||||
|
||||
This function creates and returns a new parameter object for controlling a
|
||||
parameter with the given ID.
|
||||
|
||||
Calling this will create and add a special type of AudioProcessorParameter to the
|
||||
AudioProcessor to which this state is attached.
|
||||
*/
|
||||
[[deprecated ("This function is deprecated and will be removed in a future version of JUCE! "
|
||||
"See the method docs for a code example of the replacement methods.")]]
|
||||
RangedAudioParameter* createAndAddParameter (const String& parameterID,
|
||||
const String& parameterName,
|
||||
const String& labelText,
|
||||
NormalisableRange<float> valueRange,
|
||||
float defaultValue,
|
||||
std::function<String (float)> valueToTextFunction,
|
||||
std::function<float (const String&)> textToValueFunction,
|
||||
bool isMetaParameter = false,
|
||||
bool isAutomatableParameter = true,
|
||||
bool isDiscrete = false,
|
||||
AudioProcessorParameter::Category parameterCategory = AudioProcessorParameter::genericParameter,
|
||||
bool isBoolean = false);
|
||||
#endif
|
||||
|
||||
/** This function adds a parameter to the attached AudioProcessor and that parameter will
|
||||
be managed by this AudioProcessorValueTreeState object.
|
||||
*/
|
||||
RangedAudioParameter* createAndAddParameter (std::unique_ptr<RangedAudioParameter> parameter);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a parameter by its ID string. */
|
||||
RangedAudioParameter* getParameter (StringRef parameterID) const noexcept;
|
||||
|
||||
/** Returns a pointer to a floating point representation of a particular parameter which a realtime
|
||||
process can read to find out its current value.
|
||||
|
||||
Note that calling this method from within AudioProcessorValueTreeState::Listener::parameterChanged()
|
||||
is not guaranteed to return an up-to-date value for the parameter.
|
||||
*/
|
||||
std::atomic<float>* getRawParameterValue (StringRef parameterID) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** A listener class that can be attached to an AudioProcessorValueTreeState.
|
||||
Use AudioProcessorValueTreeState::addParameterListener() to register a callback.
|
||||
*/
|
||||
struct JUCE_API Listener
|
||||
{
|
||||
virtual ~Listener() = default;
|
||||
|
||||
/** This callback method is called by the AudioProcessorValueTreeState when a parameter changes.
|
||||
|
||||
Within this call, retrieving the value of the parameter that has changed via the getRawParameterValue()
|
||||
or getParameter() methods is not guaranteed to return the up-to-date value. If you need this you should
|
||||
instead use the newValue parameter.
|
||||
*/
|
||||
virtual void parameterChanged (const String& parameterID, float newValue) = 0;
|
||||
};
|
||||
|
||||
/** Attaches a callback to one of the parameters, which will be called when the parameter changes. */
|
||||
void addParameterListener (StringRef parameterID, Listener* listener);
|
||||
|
||||
/** Removes a callback that was previously added with addParameterCallback(). */
|
||||
void removeParameterListener (StringRef parameterID, Listener* listener);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a Value object that can be used to control a particular parameter. */
|
||||
Value getParameterAsValue (StringRef parameterID) const;
|
||||
|
||||
/** Returns the range that was set when the given parameter was created. */
|
||||
NormalisableRange<float> getParameterRange (StringRef parameterID) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a copy of the state value tree.
|
||||
|
||||
The AudioProcessorValueTreeState's ValueTree is updated internally on the
|
||||
message thread, but there may be cases when you may want to access the state
|
||||
from a different thread (getStateInformation is a good example). This method
|
||||
flushes all pending audio parameter value updates and returns a copy of the
|
||||
state in a thread safe way.
|
||||
|
||||
Note: This method uses locks to synchronise thread access, so whilst it is
|
||||
thread-safe, it is not realtime-safe. Do not call this method from within
|
||||
your audio processing code!
|
||||
*/
|
||||
ValueTree copyState();
|
||||
|
||||
/** Replaces the state value tree.
|
||||
|
||||
The AudioProcessorValueTreeState's ValueTree is updated internally on the
|
||||
message thread, but there may be cases when you may want to modify the state
|
||||
from a different thread (setStateInformation is a good example). This method
|
||||
allows you to replace the state in a thread safe way.
|
||||
|
||||
Note: This method uses locks to synchronise thread access, so whilst it is
|
||||
thread-safe, it is not realtime-safe. Do not call this method from within
|
||||
your audio processing code!
|
||||
*/
|
||||
void replaceState (const ValueTree& newState);
|
||||
|
||||
//==============================================================================
|
||||
/** A reference to the processor with which this state is associated. */
|
||||
AudioProcessor& processor;
|
||||
|
||||
/** The state of the whole processor.
|
||||
|
||||
This must be initialised after all calls to createAndAddParameter().
|
||||
You can replace this with your own ValueTree object, and can add properties and
|
||||
children to the tree. This class will automatically add children for each of the
|
||||
parameter objects that are created by createAndAddParameter().
|
||||
*/
|
||||
ValueTree state;
|
||||
|
||||
/** Provides access to the undo manager that this object is using. */
|
||||
UndoManager* const undoManager;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class ParameterAdapter;
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** A parameter class that maintains backwards compatibility with deprecated
|
||||
AudioProcessorValueTreeState functionality.
|
||||
|
||||
Previous calls to
|
||||
|
||||
@code
|
||||
createAndAddParameter (paramID1, paramName1, ...);
|
||||
@endcode
|
||||
|
||||
can be replaced with
|
||||
|
||||
@code
|
||||
using Parameter = AudioProcessorValueTreeState::Parameter;
|
||||
createAndAddParameter (std::make_unique<Parameter> (paramID1, paramName1, ...));
|
||||
@endcode
|
||||
|
||||
However, a much better approach is to use the AudioProcessorValueTreeState
|
||||
constructor directly
|
||||
|
||||
@code
|
||||
using Parameter = AudioProcessorValueTreeState::Parameter;
|
||||
YourAudioProcessor()
|
||||
: apvts (*this, &undoManager, "PARAMETERS", { std::make_unique<Parameter> (paramID1, paramName1, ...),
|
||||
std::make_unique<Parameter> (paramID2, paramName2, ...),
|
||||
... })
|
||||
@endcode
|
||||
*/
|
||||
class Parameter final : public AudioParameterFloat
|
||||
{
|
||||
public:
|
||||
/** Constructs a parameter instance.
|
||||
|
||||
Example usage:
|
||||
@code
|
||||
using Parameter = AudioProcessorValueTreeState::Parameter;
|
||||
using Attributes = AudioProcessorValueTreeStateParameterAttributes;
|
||||
|
||||
auto parameter = std::make_unique<Parameter> (ParameterID { "uniqueID", 1 },
|
||||
"Name",
|
||||
NormalisableRange<float> { 0.0f, 100.0f },
|
||||
50.0f,
|
||||
Attributes().withStringFromValueFunction (myStringFromValueFunction)
|
||||
.withValueFromStringFunction (myValueFromStringFunction)
|
||||
.withLabel ("%"));
|
||||
@endcode
|
||||
|
||||
@param parameterID The globally-unique identifier of this parameter
|
||||
@param parameterName The user-facing name of this parameter
|
||||
@param valueRange The valid range of values for this parameter
|
||||
@param defaultValue The initial parameter value
|
||||
@param attributes Further advanced settings to customise the behaviour of this parameter
|
||||
*/
|
||||
Parameter (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
NormalisableRange<float> valueRange,
|
||||
float defaultValue,
|
||||
const AudioProcessorValueTreeStateParameterAttributes& attributes = {});
|
||||
|
||||
[[deprecated ("Prefer the signature taking an Attributes argument")]]
|
||||
Parameter (const ParameterID& parameterID,
|
||||
const String& parameterName,
|
||||
const String& labelText,
|
||||
NormalisableRange<float> valueRange,
|
||||
float defaultParameterValue,
|
||||
std::function<String (float)> valueToTextFunction,
|
||||
std::function<float (const String&)> textToValueFunction,
|
||||
bool isMetaParameter = false,
|
||||
bool isAutomatableParameter = true,
|
||||
bool isDiscrete = false,
|
||||
AudioProcessorParameter::Category parameterCategory = AudioProcessorParameter::genericParameter,
|
||||
bool isBoolean = false)
|
||||
: Parameter (parameterID,
|
||||
parameterName,
|
||||
valueRange,
|
||||
defaultParameterValue,
|
||||
AudioProcessorValueTreeStateParameterAttributes().withLabel (labelText)
|
||||
.withStringFromValueFunction (adaptSignature (std::move (valueToTextFunction)))
|
||||
.withValueFromStringFunction (std::move (textToValueFunction))
|
||||
.withMeta (isMetaParameter)
|
||||
.withAutomatable (isAutomatableParameter)
|
||||
.withDiscrete (isDiscrete)
|
||||
.withCategory (parameterCategory)
|
||||
.withBoolean (isBoolean))
|
||||
{
|
||||
}
|
||||
|
||||
float getDefaultValue() const override;
|
||||
int getNumSteps() const override;
|
||||
|
||||
bool isDiscrete() const override;
|
||||
bool isBoolean() const override;
|
||||
|
||||
private:
|
||||
static std::function<String (float, int)> adaptSignature (std::function<String (float)> func)
|
||||
{
|
||||
if (func == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return [f = std::move (func)] (float v, int) { return f (v); };
|
||||
}
|
||||
|
||||
void valueChanged (float) override;
|
||||
|
||||
std::function<void()> onValueChanged;
|
||||
|
||||
const float unsnappedDefault;
|
||||
const bool discrete, boolean;
|
||||
std::atomic<float> lastValue { -1.0f };
|
||||
|
||||
friend class AudioProcessorValueTreeState::ParameterAdapter;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** An object of this class maintains a connection between a Slider and a parameter
|
||||
in an AudioProcessorValueTreeState.
|
||||
|
||||
During the lifetime of this SliderAttachment object, it keeps the two things in
|
||||
sync, making it easy to connect a slider to a parameter. When this object is
|
||||
deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState
|
||||
and Slider aren't deleted before this object!
|
||||
*/
|
||||
class JUCE_API SliderAttachment
|
||||
{
|
||||
public:
|
||||
SliderAttachment (AudioProcessorValueTreeState& stateToUse,
|
||||
const String& parameterID,
|
||||
Slider& slider);
|
||||
|
||||
private:
|
||||
std::unique_ptr<SliderParameterAttachment> attachment;
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderAttachment)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** An object of this class maintains a connection between a ComboBox and a parameter
|
||||
in an AudioProcessorValueTreeState.
|
||||
|
||||
Combobox items will be spaced linearly across the range of the parameter. For
|
||||
example if the range is specified by NormalisableRange<float> (-0.5f, 0.5f, 0.5f)
|
||||
and you add three items then the first will be mapped to a value of -0.5, the
|
||||
second to 0, and the third to 0.5.
|
||||
|
||||
During the lifetime of this ComboBoxAttachment object, it keeps the two things in
|
||||
sync, making it easy to connect a combo box to a parameter. When this object is
|
||||
deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState
|
||||
and ComboBox aren't deleted before this object!
|
||||
*/
|
||||
class JUCE_API ComboBoxAttachment
|
||||
{
|
||||
public:
|
||||
ComboBoxAttachment (AudioProcessorValueTreeState& stateToUse,
|
||||
const String& parameterID,
|
||||
ComboBox& combo);
|
||||
|
||||
private:
|
||||
std::unique_ptr<ComboBoxParameterAttachment> attachment;
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComboBoxAttachment)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** An object of this class maintains a connection between a Button and a parameter
|
||||
in an AudioProcessorValueTreeState.
|
||||
|
||||
During the lifetime of this ButtonAttachment object, it keeps the two things in
|
||||
sync, making it easy to connect a button to a parameter. When this object is
|
||||
deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState
|
||||
and Button aren't deleted before this object!
|
||||
*/
|
||||
class JUCE_API ButtonAttachment
|
||||
{
|
||||
public:
|
||||
ButtonAttachment (AudioProcessorValueTreeState& stateToUse,
|
||||
const String& parameterID,
|
||||
Button& button);
|
||||
|
||||
private:
|
||||
std::unique_ptr<ButtonParameterAttachment> attachment;
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonAttachment)
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
/** Code that looks like this:
|
||||
|
||||
@code
|
||||
auto paramA = apvts.createParameter ("a", "Parameter A", {}, { -100, 100 }, ...);
|
||||
auto paramB = apvts.createParameter ("b", "Parameter B", {}, { 0, 5 }, ...);
|
||||
addParameterGroup (std::make_unique<AudioProcessorParameterGroup> ("g1", "Group 1", " | ", std::move (paramA), std::move (paramB)));
|
||||
apvts.state = ValueTree (Identifier ("PARAMETERS"));
|
||||
@endcode
|
||||
|
||||
can instead create the APVTS like this, avoiding the two-step initialization process and leveraging one of JUCE's
|
||||
pre-built parameter types (or your own custom type derived from RangedAudioParameter):
|
||||
|
||||
@code
|
||||
using Parameter = AudioProcessorValueTreeState::Parameter;
|
||||
YourAudioProcessor()
|
||||
: apvts (*this, &undoManager, "PARAMETERS",
|
||||
{ std::make_unique<AudioProcessorParameterGroup> ("g1", "Group 1", " | ",
|
||||
std::make_unique<Parameter> ("a", "Parameter A", "", NormalisableRange<float> (-100, 100), ...),
|
||||
std::make_unique<Parameter> ("b", "Parameter B", "", NormalisableRange<float> (0, 5), ...)) })
|
||||
@endcode
|
||||
*/
|
||||
[[deprecated ("This method was introduced to allow you to use AudioProcessorValueTreeState parameters in "
|
||||
"an AudioProcessorParameterGroup, but there is now a much nicer way to achieve this. See the "
|
||||
"method docs for a code example.")]]
|
||||
std::unique_ptr<RangedAudioParameter> createParameter (const String&, const String&, const String&, NormalisableRange<float>,
|
||||
float, std::function<String (float)>, std::function<float (const String&)>,
|
||||
bool, bool, bool, AudioProcessorParameter::Category, bool);
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
friend struct ParameterAdapterTests;
|
||||
#endif
|
||||
|
||||
void addParameterAdapter (RangedAudioParameter&);
|
||||
ParameterAdapter* getParameterAdapter (StringRef) const;
|
||||
|
||||
bool flushParameterValuesToValueTree();
|
||||
void setNewState (ValueTree);
|
||||
void timerCallback() override;
|
||||
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override;
|
||||
void valueTreeChildAdded (ValueTree&, ValueTree&) override;
|
||||
void valueTreeRedirected (ValueTree&) override;
|
||||
void updateParameterConnectionsToChildTrees();
|
||||
|
||||
const Identifier valueType { "PARAM" }, valuePropertyID { "value" }, idPropertyID { "id" };
|
||||
|
||||
struct StringRefLessThan final
|
||||
{
|
||||
bool operator() (StringRef a, StringRef b) const noexcept { return a.text.compare (b.text) < 0; }
|
||||
};
|
||||
|
||||
std::map<StringRef, std::unique_ptr<ParameterAdapter>, StringRefLessThan> adapterTable;
|
||||
|
||||
CriticalSection valueTreeChanging;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorValueTreeState)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
// Forward declarations to avoid leaking implementation details.
|
||||
namespace Steinberg::Vst
|
||||
{
|
||||
class IComponent;
|
||||
} // namespace Steinberg::Vst
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if TARGET_OS_IPHONE
|
||||
struct OpaqueAudioComponentInstance;
|
||||
typedef struct OpaqueAudioComponentInstance* AudioComponentInstance;
|
||||
#else
|
||||
struct ComponentInstanceRecord;
|
||||
typedef struct ComponentInstanceRecord* AudioComponentInstance;
|
||||
#endif
|
||||
|
||||
typedef AudioComponentInstance AudioUnit;
|
||||
|
||||
//==============================================================================
|
||||
/* If you are including the VST headers inside a namespace this forward
|
||||
declaration may cause a collision with the contents of `aeffect.h`.
|
||||
|
||||
If that is the case you can avoid the collision by placing a `struct AEffect;`
|
||||
forward declaration inside the namespace and before the inclusion of the VST
|
||||
headers, e.g. @code
|
||||
|
||||
namespace Vst2
|
||||
{
|
||||
struct AEffect;
|
||||
#include <pluginterfaces/vst2.x/aeffect.h>
|
||||
#include <pluginterfaces/vst2.x/aeffectx.h>
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
struct AEffect;
|
||||
|
||||
//==============================================================================
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/** Create a derived implementation of this class and pass it to
|
||||
AudioPluginInstance::getExtensions() to retrieve format-specific
|
||||
information about a plugin instance.
|
||||
|
||||
Note that the references passed to the visit member functions are only
|
||||
guaranteed to live for the duration of the function call, so don't
|
||||
store pointers to these objects! If you need to store and reuse
|
||||
format-specific information, it is recommended to copy the result
|
||||
of the function calls that you care about. For example, you should
|
||||
store the result of VST::getAEffectPtr() rather than storing a pointer
|
||||
to the VST instance.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct ExtensionsVisitor
|
||||
{
|
||||
/** Indicates that there is no platform specific information available. */
|
||||
struct Unknown {};
|
||||
|
||||
/** Can be used to retrieve information about a VST3 that is wrapped by an AudioProcessor. */
|
||||
struct VST3Client
|
||||
{
|
||||
virtual ~VST3Client() = default;
|
||||
virtual Steinberg::Vst::IComponent* getIComponentPtr() const noexcept = 0;
|
||||
|
||||
virtual MemoryBlock getPreset() const = 0;
|
||||
virtual bool setPreset (const MemoryBlock&) const = 0;
|
||||
};
|
||||
|
||||
/** Can be used to retrieve information about an AudioUnit that is wrapped by an AudioProcessor. */
|
||||
struct AudioUnitClient
|
||||
{
|
||||
virtual ~AudioUnitClient() = default;
|
||||
virtual AudioUnit getAudioUnitHandle() const noexcept = 0;
|
||||
};
|
||||
|
||||
/** Can be used to retrieve information about a VST that is wrapped by an AudioProcessor. */
|
||||
struct VSTClient
|
||||
{
|
||||
virtual ~VSTClient() = default;
|
||||
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;
|
||||
};
|
||||
|
||||
ExtensionsVisitor() = default;
|
||||
|
||||
ExtensionsVisitor (const ExtensionsVisitor&) = default;
|
||||
ExtensionsVisitor (ExtensionsVisitor&&) = default;
|
||||
|
||||
ExtensionsVisitor& operator= (const ExtensionsVisitor&) = default;
|
||||
ExtensionsVisitor& operator= (ExtensionsVisitor&&) = default;
|
||||
|
||||
virtual ~ExtensionsVisitor() = default;
|
||||
|
||||
/** Will be called if there is no platform specific information available. */
|
||||
virtual void visitUnknown (const Unknown&) {}
|
||||
|
||||
/** Called with VST3-specific information. */
|
||||
virtual void visitVST3Client (const VST3Client&) {}
|
||||
|
||||
/** Called with VST-specific information. */
|
||||
virtual void visitVSTClient (const VSTClient&) {}
|
||||
|
||||
/** Called with AU-specific information. */
|
||||
virtual void visitAudioUnitClient (const AudioUnitClient&) {}
|
||||
|
||||
/** Called with ARA-specific information. */
|
||||
virtual void visitARAClient (const ARAClient&) {}
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ! DOXYGEN
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
template <size_t requiredFlagBitsPerItem>
|
||||
class FlagCache
|
||||
{
|
||||
using FlagType = uint32_t;
|
||||
|
||||
public:
|
||||
FlagCache() = default;
|
||||
|
||||
explicit FlagCache (size_t items)
|
||||
: flags (divCeil (items, groupsPerWord))
|
||||
{
|
||||
std::fill (flags.begin(), flags.end(), 0);
|
||||
}
|
||||
|
||||
void set (size_t index, FlagType bits)
|
||||
{
|
||||
const auto flagIndex = index / groupsPerWord;
|
||||
jassert (flagIndex < flags.size());
|
||||
const auto groupIndex = index - (flagIndex * groupsPerWord);
|
||||
flags[flagIndex].fetch_or (moveToGroupPosition (bits, groupIndex), std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
/* Calls the supplied callback for any entries with non-zero flags, and
|
||||
sets all flags to zero.
|
||||
*/
|
||||
template <typename Callback>
|
||||
void ifSet (Callback&& callback)
|
||||
{
|
||||
for (size_t flagIndex = 0; flagIndex < flags.size(); ++flagIndex)
|
||||
{
|
||||
const auto prevFlags = flags[flagIndex].exchange (0, std::memory_order_acq_rel);
|
||||
|
||||
for (size_t group = 0; group < groupsPerWord; ++group)
|
||||
{
|
||||
const auto masked = moveFromGroupPosition (prevFlags, group);
|
||||
|
||||
if (masked != 0)
|
||||
callback ((flagIndex * groupsPerWord) + group, masked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::fill (flags.begin(), flags.end(), 0);
|
||||
}
|
||||
|
||||
private:
|
||||
/* Given the flags for a single item, and a group index, shifts the flags
|
||||
so that they are positioned at the appropriate location for that group
|
||||
index.
|
||||
|
||||
e.g. If the flag type is a uint32_t, and there are 2 flags per item,
|
||||
then each uint32_t will hold flags for 16 items. The flags for item 0
|
||||
are the least significant two bits; the flags for item 15 are the most
|
||||
significant two bits.
|
||||
*/
|
||||
static constexpr FlagType moveToGroupPosition (FlagType ungrouped, size_t groupIndex)
|
||||
{
|
||||
return (ungrouped & groupMask) << (groupIndex * bitsPerFlagGroup);
|
||||
}
|
||||
|
||||
/* Given a set of grouped flags for multiple items, and a group index,
|
||||
extracts the flags set for an item at that group index.
|
||||
|
||||
e.g. If the flag type is a uint32_t, and there are 2 flags per item,
|
||||
then each uint32_t will hold flags for 16 items. Asking for groupIndex
|
||||
0 will return the least significant two bits; asking for groupIndex 15
|
||||
will return the most significant two bits.
|
||||
*/
|
||||
static constexpr FlagType moveFromGroupPosition (FlagType grouped, size_t groupIndex)
|
||||
{
|
||||
return (grouped >> (groupIndex * bitsPerFlagGroup)) & groupMask;
|
||||
}
|
||||
|
||||
static constexpr size_t findNextPowerOfTwoImpl (size_t n, size_t shift)
|
||||
{
|
||||
return shift == 32 ? n : findNextPowerOfTwoImpl (n | (n >> shift), shift * 2);
|
||||
}
|
||||
|
||||
static constexpr size_t findNextPowerOfTwo (size_t value)
|
||||
{
|
||||
return findNextPowerOfTwoImpl (value - 1, 1) + 1;
|
||||
}
|
||||
|
||||
static constexpr size_t divCeil (size_t a, size_t b)
|
||||
{
|
||||
return (a / b) + ((a % b) != 0);
|
||||
}
|
||||
|
||||
static constexpr size_t bitsPerFlagGroup = findNextPowerOfTwo (requiredFlagBitsPerItem);
|
||||
static constexpr size_t groupsPerWord = (8 * sizeof (FlagType)) / bitsPerFlagGroup;
|
||||
static constexpr FlagType groupMask = ((FlagType) 1 << requiredFlagBitsPerItem) - 1;
|
||||
|
||||
std::vector<std::atomic<FlagType>> flags;
|
||||
};
|
||||
|
||||
template <size_t requiredFlagBitsPerItem>
|
||||
class FlaggedFloatCache
|
||||
{
|
||||
public:
|
||||
FlaggedFloatCache() = default;
|
||||
|
||||
explicit FlaggedFloatCache (size_t sizeIn)
|
||||
: values (sizeIn),
|
||||
flags (sizeIn)
|
||||
{
|
||||
std::fill (values.begin(), values.end(), 0.0f);
|
||||
}
|
||||
|
||||
size_t size() const noexcept { return values.size(); }
|
||||
|
||||
float exchangeValue (size_t index, float value)
|
||||
{
|
||||
jassert (index < size());
|
||||
return values[index].exchange (value, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void setBits (size_t index, uint32_t bits) { flags.set (index, bits); }
|
||||
|
||||
void setValueAndBits (size_t index, float value, uint32_t bits)
|
||||
{
|
||||
exchangeValue (index, value);
|
||||
setBits (index, bits);
|
||||
}
|
||||
|
||||
float get (size_t index) const noexcept
|
||||
{
|
||||
jassert (index < size());
|
||||
return values[index].load (std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/* Calls the supplied callback for any entries which have been modified
|
||||
since the last call to this function.
|
||||
*/
|
||||
template <typename Callback>
|
||||
void ifSet (Callback&& callback)
|
||||
{
|
||||
flags.ifSet ([this, &callback] (size_t groupIndex, uint32_t bits)
|
||||
{
|
||||
callback (groupIndex, values[groupIndex].load (std::memory_order_relaxed), bits);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::atomic<float>> values;
|
||||
FlagCache<requiredFlagBitsPerItem> flags;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#endif
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
ParameterAttachment::ParameterAttachment (RangedAudioParameter& param,
|
||||
std::function<void (float)> parameterChangedCallback,
|
||||
UndoManager* um)
|
||||
: parameter (param),
|
||||
undoManager (um),
|
||||
setValue (std::move (parameterChangedCallback))
|
||||
{
|
||||
parameter.addListener (this);
|
||||
}
|
||||
|
||||
ParameterAttachment::~ParameterAttachment()
|
||||
{
|
||||
parameter.removeListener (this);
|
||||
cancelPendingUpdate();
|
||||
}
|
||||
|
||||
void ParameterAttachment::sendInitialUpdate()
|
||||
{
|
||||
parameterValueChanged ({}, parameter.getValue());
|
||||
}
|
||||
|
||||
void ParameterAttachment::setValueAsCompleteGesture (float newDenormalisedValue)
|
||||
{
|
||||
callIfParameterValueChanged (newDenormalisedValue, [this] (float f)
|
||||
{
|
||||
beginGesture();
|
||||
parameter.setValueNotifyingHost (f);
|
||||
endGesture();
|
||||
});
|
||||
}
|
||||
|
||||
void ParameterAttachment::beginGesture()
|
||||
{
|
||||
if (undoManager != nullptr)
|
||||
undoManager->beginNewTransaction();
|
||||
|
||||
parameter.beginChangeGesture();
|
||||
}
|
||||
|
||||
void ParameterAttachment::setValueAsPartOfGesture (float newDenormalisedValue)
|
||||
{
|
||||
callIfParameterValueChanged (newDenormalisedValue, [this] (float f)
|
||||
{
|
||||
parameter.setValueNotifyingHost (f);
|
||||
});
|
||||
}
|
||||
|
||||
void ParameterAttachment::endGesture()
|
||||
{
|
||||
parameter.endChangeGesture();
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void ParameterAttachment::callIfParameterValueChanged (float newDenormalisedValue,
|
||||
Callback&& callback)
|
||||
{
|
||||
const auto newValue = normalise (newDenormalisedValue);
|
||||
|
||||
if (! approximatelyEqual (parameter.getValue(), newValue))
|
||||
callback (newValue);
|
||||
}
|
||||
|
||||
void ParameterAttachment::parameterValueChanged (int, float newValue)
|
||||
{
|
||||
lastValue = newValue;
|
||||
|
||||
if (MessageManager::getInstance()->isThisTheMessageThread())
|
||||
{
|
||||
cancelPendingUpdate();
|
||||
handleAsyncUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterAttachment::handleAsyncUpdate()
|
||||
{
|
||||
NullCheckedInvocation::invoke (setValue, parameter.convertFrom0to1 (lastValue));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SliderParameterAttachment::SliderParameterAttachment (RangedAudioParameter& param,
|
||||
Slider& s,
|
||||
UndoManager* um)
|
||||
: slider (s),
|
||||
attachment (param, [this] (float f) { setValue (f); }, um)
|
||||
{
|
||||
slider.valueFromTextFunction = [¶m] (const String& text) { return (double) param.convertFrom0to1 (param.getValueForText (text)); };
|
||||
slider.textFromValueFunction = [¶m] (double value) { return param.getText (param.convertTo0to1 ((float) value), 0); };
|
||||
slider.setDoubleClickReturnValue (true, param.convertFrom0to1 (param.getDefaultValue()));
|
||||
|
||||
auto range = param.getNormalisableRange();
|
||||
|
||||
auto convertFrom0To1Function = [range] (double currentRangeStart,
|
||||
double currentRangeEnd,
|
||||
double normalisedValue) mutable
|
||||
{
|
||||
range.start = (float) currentRangeStart;
|
||||
range.end = (float) currentRangeEnd;
|
||||
return (double) range.convertFrom0to1 ((float) normalisedValue);
|
||||
};
|
||||
|
||||
auto convertTo0To1Function = [range] (double currentRangeStart,
|
||||
double currentRangeEnd,
|
||||
double mappedValue) mutable
|
||||
{
|
||||
range.start = (float) currentRangeStart;
|
||||
range.end = (float) currentRangeEnd;
|
||||
return (double) range.convertTo0to1 ((float) mappedValue);
|
||||
};
|
||||
|
||||
auto snapToLegalValueFunction = [range] (double currentRangeStart,
|
||||
double currentRangeEnd,
|
||||
double mappedValue) mutable
|
||||
{
|
||||
range.start = (float) currentRangeStart;
|
||||
range.end = (float) currentRangeEnd;
|
||||
return (double) range.snapToLegalValue ((float) mappedValue);
|
||||
};
|
||||
|
||||
NormalisableRange<double> newRange { (double) range.start,
|
||||
(double) range.end,
|
||||
std::move (convertFrom0To1Function),
|
||||
std::move (convertTo0To1Function),
|
||||
std::move (snapToLegalValueFunction) };
|
||||
newRange.interval = range.interval;
|
||||
newRange.skew = range.skew;
|
||||
newRange.symmetricSkew = range.symmetricSkew;
|
||||
|
||||
slider.setNormalisableRange (newRange);
|
||||
|
||||
sendInitialUpdate();
|
||||
slider.valueChanged();
|
||||
slider.addListener (this);
|
||||
}
|
||||
|
||||
SliderParameterAttachment::~SliderParameterAttachment()
|
||||
{
|
||||
slider.removeListener (this);
|
||||
}
|
||||
|
||||
void SliderParameterAttachment::sendInitialUpdate() { attachment.sendInitialUpdate(); }
|
||||
|
||||
void SliderParameterAttachment::setValue (float newValue)
|
||||
{
|
||||
const ScopedValueSetter<bool> svs (ignoreCallbacks, true);
|
||||
slider.setValue (newValue, sendNotificationSync);
|
||||
}
|
||||
|
||||
void SliderParameterAttachment::sliderValueChanged (Slider*)
|
||||
{
|
||||
if (! ignoreCallbacks)
|
||||
attachment.setValueAsPartOfGesture ((float) slider.getValue());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ComboBoxParameterAttachment::ComboBoxParameterAttachment (RangedAudioParameter& param,
|
||||
ComboBox& c,
|
||||
UndoManager* um)
|
||||
: comboBox (c),
|
||||
storedParameter (param),
|
||||
attachment (param, [this] (float f) { setValue (f); }, um)
|
||||
{
|
||||
sendInitialUpdate();
|
||||
comboBox.addListener (this);
|
||||
}
|
||||
|
||||
ComboBoxParameterAttachment::~ComboBoxParameterAttachment()
|
||||
{
|
||||
comboBox.removeListener (this);
|
||||
}
|
||||
|
||||
void ComboBoxParameterAttachment::sendInitialUpdate()
|
||||
{
|
||||
attachment.sendInitialUpdate();
|
||||
}
|
||||
|
||||
void ComboBoxParameterAttachment::setValue (float newValue)
|
||||
{
|
||||
const auto normValue = storedParameter.convertTo0to1 (newValue);
|
||||
const auto index = roundToInt (normValue * (float) (comboBox.getNumItems() - 1));
|
||||
|
||||
if (index == comboBox.getSelectedItemIndex())
|
||||
return;
|
||||
|
||||
const ScopedValueSetter<bool> svs (ignoreCallbacks, true);
|
||||
comboBox.setSelectedItemIndex (index, sendNotificationSync);
|
||||
}
|
||||
|
||||
void ComboBoxParameterAttachment::comboBoxChanged (ComboBox*)
|
||||
{
|
||||
if (ignoreCallbacks)
|
||||
return;
|
||||
|
||||
const auto numItems = comboBox.getNumItems();
|
||||
const auto selected = (float) comboBox.getSelectedItemIndex();
|
||||
const auto newValue = numItems > 1 ? selected / (float) (numItems - 1)
|
||||
: 0.0f;
|
||||
|
||||
attachment.setValueAsCompleteGesture (storedParameter.convertFrom0to1 (newValue));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ButtonParameterAttachment::ButtonParameterAttachment (RangedAudioParameter& param,
|
||||
Button& b,
|
||||
UndoManager* um)
|
||||
: button (b),
|
||||
attachment (param, [this] (float f) { setValue (f); }, um)
|
||||
{
|
||||
sendInitialUpdate();
|
||||
button.addListener (this);
|
||||
}
|
||||
|
||||
ButtonParameterAttachment::~ButtonParameterAttachment()
|
||||
{
|
||||
button.removeListener (this);
|
||||
}
|
||||
|
||||
void ButtonParameterAttachment::sendInitialUpdate()
|
||||
{
|
||||
attachment.sendInitialUpdate();
|
||||
}
|
||||
|
||||
void ButtonParameterAttachment::setValue (float newValue)
|
||||
{
|
||||
const ScopedValueSetter<bool> svs (ignoreCallbacks, true);
|
||||
button.setToggleState (newValue >= 0.5f, sendNotificationSync);
|
||||
}
|
||||
|
||||
void ButtonParameterAttachment::buttonClicked (Button*)
|
||||
{
|
||||
if (ignoreCallbacks)
|
||||
return;
|
||||
|
||||
attachment.setValueAsCompleteGesture (button.getToggleState() ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/** Used to implement 'attachments' or 'controllers' that link a plug-in
|
||||
parameter to a UI element.
|
||||
|
||||
To implement a new attachment type, create a new class which includes an
|
||||
instance of this class as a data member. Your class should pass a function
|
||||
to the constructor of the ParameterAttachment, which will then be called on
|
||||
the message thread when the parameter changes. You can use this function to
|
||||
update the state of the UI control. Your class should also register as a
|
||||
listener of the UI control and respond to respond to changes in the UI element
|
||||
by calling either setValueAsCompleteGesture or beginGesture,
|
||||
setValueAsPartOfGesture and endGesture.
|
||||
|
||||
Make sure to call `sendInitialUpdate` at the end of your new attachment's
|
||||
constructor, so that the UI immediately reflects the state of the parameter.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class ParameterAttachment : private AudioProcessorParameter::Listener,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
/** Listens to a parameter and calls the the provided function in response to
|
||||
parameter changes. If an undoManager is supplied `beginNewTransaction` will
|
||||
be called on it whenever the UI requests a parameter change via this attachment.
|
||||
|
||||
@param parameter The parameter to which this attachment will listen
|
||||
@param parameterChangedCallback The function that will be called on the message thread in response
|
||||
to parameter changes
|
||||
@param undoManager The UndoManager that will be used to begin transactions when the UI
|
||||
requests a parameter change.
|
||||
*/
|
||||
ParameterAttachment (RangedAudioParameter& parameter,
|
||||
std::function<void (float)> parameterChangedCallback,
|
||||
UndoManager* undoManager = nullptr);
|
||||
|
||||
/** Destructor. */
|
||||
~ParameterAttachment() override;
|
||||
|
||||
/** Calls the parameterChangedCallback function that was registered in
|
||||
the constructor, making the UI reflect the current parameter state.
|
||||
|
||||
This function should be called after doing any necessary setup on
|
||||
the UI control that is being managed (e.g. adding ComboBox entries,
|
||||
making buttons toggle-able).
|
||||
*/
|
||||
void sendInitialUpdate();
|
||||
|
||||
/** Triggers a full gesture message on the managed parameter.
|
||||
|
||||
Call this in the listener callback of the UI control in response
|
||||
to a one-off change in the UI like a button-press.
|
||||
*/
|
||||
void setValueAsCompleteGesture (float newDenormalisedValue);
|
||||
|
||||
/** Begins a gesture on the managed parameter.
|
||||
|
||||
Call this when the UI is about to begin a continuous interaction,
|
||||
like when the mouse button is pressed on a slider.
|
||||
*/
|
||||
void beginGesture();
|
||||
|
||||
/** Updates the parameter value during a gesture.
|
||||
|
||||
Call this during a continuous interaction, like a slider value
|
||||
changed callback.
|
||||
*/
|
||||
void setValueAsPartOfGesture (float newDenormalisedValue);
|
||||
|
||||
/** Ends a gesture on the managed parameter.
|
||||
|
||||
Call this when the UI has finished a continuous interaction,
|
||||
like when the mouse button is released on a slider.
|
||||
*/
|
||||
void endGesture();
|
||||
|
||||
private:
|
||||
float normalise (float f) const { return parameter.convertTo0to1 (f); }
|
||||
|
||||
template <typename Callback>
|
||||
void callIfParameterValueChanged (float newDenormalisedValue, Callback&& callback);
|
||||
|
||||
void parameterValueChanged (int, float) override;
|
||||
void parameterGestureChanged (int, bool) override {}
|
||||
void handleAsyncUpdate() override;
|
||||
|
||||
RangedAudioParameter& parameter;
|
||||
std::atomic<float> lastValue { 0.0f };
|
||||
UndoManager* undoManager = nullptr;
|
||||
std::function<void (float)> setValue;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterAttachment)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** An object of this class maintains a connection between a Slider and a
|
||||
plug-in parameter.
|
||||
|
||||
During the lifetime of this object it keeps the two things in sync, making
|
||||
it easy to connect a slider to a parameter. When this object is deleted, the
|
||||
connection is broken. Make sure that your parameter and Slider are not
|
||||
deleted before this object!
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class SliderParameterAttachment : private Slider::Listener
|
||||
{
|
||||
public:
|
||||
/** Creates a connection between a plug-in parameter and a Slider.
|
||||
|
||||
@param parameter The parameter to use
|
||||
@param slider The Slider to use
|
||||
@param undoManager An optional UndoManager
|
||||
*/
|
||||
SliderParameterAttachment (RangedAudioParameter& parameter, Slider& slider,
|
||||
UndoManager* undoManager = nullptr);
|
||||
|
||||
/** Destructor. */
|
||||
~SliderParameterAttachment() override;
|
||||
|
||||
/** Call this after setting up your slider in the case where you need to do
|
||||
extra setup after constructing this attachment.
|
||||
*/
|
||||
void sendInitialUpdate();
|
||||
|
||||
private:
|
||||
void setValue (float newValue);
|
||||
void sliderValueChanged (Slider*) override;
|
||||
|
||||
void sliderDragStarted (Slider*) override { attachment.beginGesture(); }
|
||||
void sliderDragEnded (Slider*) override { attachment.endGesture(); }
|
||||
|
||||
Slider& slider;
|
||||
ParameterAttachment attachment;
|
||||
bool ignoreCallbacks = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** An object of this class maintains a connection between a ComboBox and a
|
||||
plug-in parameter.
|
||||
|
||||
ComboBox items will be spaced linearly across the range of the parameter. For
|
||||
example if the range is specified by NormalisableRange<float> (-0.5f, 0.5f, 0.5f)
|
||||
and you add three items then the first will be mapped to a value of -0.5, the
|
||||
second to 0, and the third to 0.5.
|
||||
|
||||
During the lifetime of this object it keeps the two things in sync, making it
|
||||
easy to connect a combo box to a parameter. When this object is deleted, the
|
||||
connection is broken. Make sure that your parameter and ComboBox are not deleted
|
||||
before this object!
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class ComboBoxParameterAttachment : private ComboBox::Listener
|
||||
{
|
||||
public:
|
||||
/** Creates a connection between a plug-in parameter and a ComboBox.
|
||||
|
||||
@param parameter The parameter to use
|
||||
@param combo The ComboBox to use
|
||||
@param undoManager An optional UndoManager
|
||||
*/
|
||||
ComboBoxParameterAttachment (RangedAudioParameter& parameter, ComboBox& combo,
|
||||
UndoManager* undoManager = nullptr);
|
||||
|
||||
/** Destructor. */
|
||||
~ComboBoxParameterAttachment() override;
|
||||
|
||||
/** Call this after setting up your combo box in the case where you need to do
|
||||
extra setup after constructing this attachment.
|
||||
*/
|
||||
void sendInitialUpdate();
|
||||
|
||||
private:
|
||||
void setValue (float newValue);
|
||||
void comboBoxChanged (ComboBox*) override;
|
||||
|
||||
ComboBox& comboBox;
|
||||
RangedAudioParameter& storedParameter;
|
||||
ParameterAttachment attachment;
|
||||
bool ignoreCallbacks = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** An object of this class maintains a connection between a Button and a
|
||||
plug-in parameter.
|
||||
|
||||
During the lifetime of this object it keeps the two things in sync, making it
|
||||
easy to connect a button to a parameter. When this object is deleted, the
|
||||
connection is broken. Make sure that your parameter and Button are not deleted
|
||||
before this object!
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class ButtonParameterAttachment : private Button::Listener
|
||||
{
|
||||
public:
|
||||
/** Creates a connection between a plug-in parameter and a Button.
|
||||
|
||||
@param parameter The parameter to use
|
||||
@param button The Button to use
|
||||
@param undoManager An optional UndoManager
|
||||
*/
|
||||
ButtonParameterAttachment (RangedAudioParameter& parameter, Button& button,
|
||||
UndoManager* undoManager = nullptr);
|
||||
|
||||
/** Destructor. */
|
||||
~ButtonParameterAttachment() override;
|
||||
|
||||
/** Call this after setting up your button in the case where you need to do
|
||||
extra setup after constructing this attachment.
|
||||
*/
|
||||
void sendInitialUpdate();
|
||||
|
||||
private:
|
||||
void setValue (float newValue);
|
||||
void buttonClicked (Button*) override;
|
||||
|
||||
Button& button;
|
||||
ParameterAttachment attachment;
|
||||
bool ignoreCallbacks = false;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP)
|
||||
bool JUCE_CALLTYPE juce_isInterAppAudioConnected();
|
||||
void JUCE_CALLTYPE juce_switchToHostApplication();
|
||||
juce::Image JUCE_CALLTYPE juce_getIAAHostIcon (int);
|
||||
#endif
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
Image JUCE_API getIconFromApplication (const String&, const int);
|
||||
|
||||
AudioProcessor::WrapperType PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_Undefined;
|
||||
std::function<bool (AudioProcessor&)> PluginHostType::jucePlugInIsRunningInAudioSuiteFn = nullptr;
|
||||
String PluginHostType::hostIdReportedByWrapper;
|
||||
|
||||
bool PluginHostType::isInterAppAudioConnected() const
|
||||
{
|
||||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP)
|
||||
if (getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone)
|
||||
return juce_isInterAppAudioConnected();
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PluginHostType::switchToHostApplication() const
|
||||
{
|
||||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP)
|
||||
if (getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone)
|
||||
juce_switchToHostApplication();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PluginHostType::isInAAXAudioSuite ([[maybe_unused]] AudioProcessor& processor)
|
||||
{
|
||||
#if JucePlugin_Build_AAX
|
||||
if (PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_AAX
|
||||
&& jucePlugInIsRunningInAudioSuiteFn != nullptr)
|
||||
{
|
||||
return jucePlugInIsRunningInAudioSuiteFn (processor);
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Image PluginHostType::getHostIcon ([[maybe_unused]] int size) const
|
||||
{
|
||||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP)
|
||||
if (isInterAppAudioConnected())
|
||||
return juce_getIAAHostIcon (size);
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC
|
||||
String bundlePath (getHostPath().upToLastOccurrenceOf (".app", true, true));
|
||||
return getIconFromApplication (bundlePath, size);
|
||||
#endif
|
||||
|
||||
return Image();
|
||||
}
|
||||
|
||||
const char* PluginHostType::getHostDescription() const noexcept
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AbletonLive6: return "Ableton Live 6";
|
||||
case AbletonLive7: return "Ableton Live 7";
|
||||
case AbletonLive8: return "Ableton Live 8";
|
||||
case AbletonLive9: return "Ableton Live 9";
|
||||
case AbletonLive10: return "Ableton Live 10";
|
||||
case AbletonLive11: return "Ableton Live 11";
|
||||
case AbletonLiveGeneric: return "Ableton Live";
|
||||
case AdobeAudition: return "Adobe Audition";
|
||||
case AdobePremierePro: return "Adobe Premiere";
|
||||
case AppleGarageBand: return "Apple GarageBand";
|
||||
case AppleInfoHelper: return "com.apple.audio.InfoHelper";
|
||||
case AppleLogic: return "Apple Logic";
|
||||
case AppleMainStage: return "Apple MainStage";
|
||||
case Ardour: return "Ardour";
|
||||
case AULab: return "AU Lab";
|
||||
case AUVal: return "auval";
|
||||
case AvidProTools: return "ProTools";
|
||||
case BitwigStudio: return "Bitwig Studio";
|
||||
case CakewalkSonar8: return "Cakewalk Sonar 8";
|
||||
case CakewalkSonarGeneric: return "Cakewalk Sonar";
|
||||
case CakewalkByBandlab: return "Cakewalk by Bandlab";
|
||||
case DaVinciResolve: return "DaVinci Resolve";
|
||||
case DigitalPerformer: return "DigitalPerformer";
|
||||
case FinalCut: return "Final Cut";
|
||||
case FruityLoops: return "FruityLoops";
|
||||
case JUCEPluginHost: return "JUCE AudioPluginHost";
|
||||
case MagixSamplitude: return "Magix Samplitude";
|
||||
case MagixSequoia: return "Magix Sequoia";
|
||||
case pluginval: return "pluginval";
|
||||
case MergingPyramix: return "Pyramix";
|
||||
case MuseReceptorGeneric: return "Muse Receptor";
|
||||
case Maschine: return "NI Maschine";
|
||||
case Reaper: return "Reaper";
|
||||
case Reason: return "Reason";
|
||||
case Renoise: return "Renoise";
|
||||
case SADiE: return "SADiE";
|
||||
case SteinbergCubase4: return "Steinberg Cubase 4";
|
||||
case SteinbergCubase5: return "Steinberg Cubase 5";
|
||||
case SteinbergCubase5Bridged: return "Steinberg Cubase 5 Bridged";
|
||||
case SteinbergCubase6: return "Steinberg Cubase 6";
|
||||
case SteinbergCubase7: return "Steinberg Cubase 7";
|
||||
case SteinbergCubase8: return "Steinberg Cubase 8";
|
||||
case SteinbergCubase8_5: return "Steinberg Cubase 8.5";
|
||||
case SteinbergCubase9: return "Steinberg Cubase 9";
|
||||
case SteinbergCubase9_5: return "Steinberg Cubase 9.5";
|
||||
case SteinbergCubase10: return "Steinberg Cubase 10";
|
||||
case SteinbergCubase10_5: return "Steinberg Cubase 10.5";
|
||||
case SteinbergCubaseGeneric: return "Steinberg Cubase";
|
||||
case SteinbergNuendo3: return "Steinberg Nuendo 3";
|
||||
case SteinbergNuendo4: return "Steinberg Nuendo 4";
|
||||
case SteinbergNuendo5: return "Steinberg Nuendo 5";
|
||||
case SteinbergNuendoGeneric: return "Steinberg Nuendo";
|
||||
case SteinbergWavelab5: return "Steinberg Wavelab 5";
|
||||
case SteinbergWavelab6: return "Steinberg Wavelab 6";
|
||||
case SteinbergWavelab7: return "Steinberg Wavelab 7";
|
||||
case SteinbergWavelab8: return "Steinberg Wavelab 8";
|
||||
case SteinbergWavelabGeneric: return "Steinberg Wavelab";
|
||||
case SteinbergTestHost: return "Steinberg TestHost";
|
||||
case StudioOne: return "Studio One";
|
||||
case Tracktion3: return "Tracktion 3";
|
||||
case TracktionGeneric: return "Tracktion";
|
||||
case TracktionWaveform: return "Tracktion Waveform";
|
||||
case VBVSTScanner: return "VBVSTScanner";
|
||||
case ViennaEnsemblePro: return "Vienna Ensemble Pro";
|
||||
case WaveBurner: return "WaveBurner";
|
||||
case UnknownHost:
|
||||
default: break;
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
PluginHostType::HostType PluginHostType::getHostType()
|
||||
{
|
||||
auto hostPath = getHostPath();
|
||||
auto hostFilename = File (hostPath).getFileName();
|
||||
|
||||
#if JUCE_MAC
|
||||
if (hostPath.containsIgnoreCase ("Final Cut Pro.app")) return FinalCut;
|
||||
if (hostPath.containsIgnoreCase ("Final Cut Pro Trial.app")) return FinalCut;
|
||||
if (hostPath.containsIgnoreCase ("Live 6")) return AbletonLive6;
|
||||
if (hostPath.containsIgnoreCase ("Live 7")) return AbletonLive7;
|
||||
if (hostPath.containsIgnoreCase ("Live 8")) return AbletonLive8;
|
||||
if (hostPath.containsIgnoreCase ("Live 9")) return AbletonLive9;
|
||||
if (hostPath.containsIgnoreCase ("Live 10")) return AbletonLive10;
|
||||
if (hostPath.containsIgnoreCase ("Live 11")) return AbletonLive11;
|
||||
if (hostFilename.containsIgnoreCase ("Live")) return AbletonLiveGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition;
|
||||
if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro;
|
||||
if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand;
|
||||
if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic;
|
||||
if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage;
|
||||
if (hostFilename.containsIgnoreCase ("AU Lab")) return AULab;
|
||||
if (hostFilename.containsIgnoreCase ("Pro Tools")) return AvidProTools;
|
||||
if (hostFilename.containsIgnoreCase ("Nuendo 3")) return SteinbergNuendo3;
|
||||
if (hostFilename.containsIgnoreCase ("Nuendo 4")) return SteinbergNuendo4;
|
||||
if (hostFilename.containsIgnoreCase ("Nuendo 5")) return SteinbergNuendo5;
|
||||
if (hostFilename.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase 4")) return SteinbergCubase4;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase 5")) return SteinbergCubase5;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase 6")) return SteinbergCubase6;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase 7")) return SteinbergCubase7;
|
||||
if (hostPath.containsIgnoreCase ("Cubase 8.app")) return SteinbergCubase8;
|
||||
if (hostPath.containsIgnoreCase ("Cubase 8.5.app")) return SteinbergCubase8_5;
|
||||
if (hostPath.containsIgnoreCase ("Cubase 9.app")) return SteinbergCubase9;
|
||||
if (hostPath.containsIgnoreCase ("Cubase 9.5.app")) return SteinbergCubase9_5;
|
||||
if (hostPath.containsIgnoreCase ("Cubase 10.app")) return SteinbergCubase10;
|
||||
if (hostPath.containsIgnoreCase ("Cubase 10.5.app")) return SteinbergCubase10_5;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric;
|
||||
if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7;
|
||||
if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8;
|
||||
if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("WaveBurner")) return WaveBurner;
|
||||
if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer;
|
||||
if (hostFilename.containsIgnoreCase ("reaper")) return Reaper;
|
||||
if (hostFilename.containsIgnoreCase ("Reason")) return Reason;
|
||||
if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne;
|
||||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform;
|
||||
if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3;
|
||||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise;
|
||||
if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve;
|
||||
if (hostFilename.startsWith ("Bitwig")) return BitwigStudio;
|
||||
if (hostFilename.containsIgnoreCase ("OsxFL")) return FruityLoops;
|
||||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval;
|
||||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost;
|
||||
if (hostFilename.containsIgnoreCase ("Maschine")) return Maschine;
|
||||
if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro;
|
||||
if (hostFilename.containsIgnoreCase ("auvaltool")) return AUVal;
|
||||
if (hostFilename.containsIgnoreCase ("com.apple.audio.infohelper")) return AppleInfoHelper;
|
||||
|
||||
if (hostIdReportedByWrapper == "com.apple.logic.pro") return AppleLogic;
|
||||
if (hostIdReportedByWrapper == "com.apple.garageband") return AppleGarageBand;
|
||||
if (hostIdReportedByWrapper == "com.apple.mainstage") return AppleMainStage;
|
||||
|
||||
const auto procName = nsStringToJuce ([[NSRunningApplication currentApplication] localizedName]);
|
||||
|
||||
const auto matchesInOrder = [&] (const StringArray& strings)
|
||||
{
|
||||
return procName.matchesWildcard ("AUHostingService*(" + strings.joinIntoString ("*") + ")", false);
|
||||
};
|
||||
|
||||
// Depending on localization settings, spaces are not always plain ascii spaces
|
||||
if (matchesInOrder ({ "Logic", "Pro" })) return AppleLogic;
|
||||
if (matchesInOrder ({ "GarageBand" })) return AppleGarageBand;
|
||||
if (matchesInOrder ({ "MainStage" })) return AppleMainStage;
|
||||
if (matchesInOrder ({ "Final", "Cut", "Pro" })) return FinalCut;
|
||||
|
||||
#elif JUCE_WINDOWS
|
||||
if (hostFilename.containsIgnoreCase ("Live 6")) return AbletonLive6;
|
||||
if (hostFilename.containsIgnoreCase ("Live 7")) return AbletonLive7;
|
||||
if (hostFilename.containsIgnoreCase ("Live 8")) return AbletonLive8;
|
||||
if (hostFilename.containsIgnoreCase ("Live 9")) return AbletonLive9;
|
||||
if (hostFilename.containsIgnoreCase ("Live 10")) return AbletonLive10;
|
||||
if (hostFilename.containsIgnoreCase ("Live 11")) return AbletonLive11;
|
||||
if (hostFilename.containsIgnoreCase ("Live ")) return AbletonLiveGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition;
|
||||
if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro;
|
||||
if (hostFilename.containsIgnoreCase ("ProTools")) return AvidProTools;
|
||||
if (hostPath.containsIgnoreCase ("SONAR 8")) return CakewalkSonar8;
|
||||
if (hostFilename.containsIgnoreCase ("SONAR")) return CakewalkSonarGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("Cakewalk.exe")) return CakewalkByBandlab;
|
||||
if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand;
|
||||
if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic;
|
||||
if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage;
|
||||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform;
|
||||
if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3;
|
||||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("reaper")) return Reaper;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase4")) return SteinbergCubase4;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase5")) return SteinbergCubase5;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase6")) return SteinbergCubase6;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase7")) return SteinbergCubase7;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase8.exe")) return SteinbergCubase8;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase8.5.exe")) return SteinbergCubase8_5;
|
||||
// Later version of Cubase scan plug-ins with a separate executable "vst2xscanner"
|
||||
if (hostFilename.containsIgnoreCase ("Cubase9.5.exe")
|
||||
|| hostPath.containsIgnoreCase ("Cubase 9.5")) return SteinbergCubase9_5;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase9.exe")
|
||||
|| hostPath.containsIgnoreCase ("Cubase 9")) return SteinbergCubase9;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase10.5.exe")
|
||||
|| hostPath.containsIgnoreCase ("Cubase 10.5")) return SteinbergCubase10_5;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase10.exe")
|
||||
|| hostPath.containsIgnoreCase ("Cubase 10")) return SteinbergCubase10;
|
||||
if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("VSTBridgeApp")) return SteinbergCubase5Bridged;
|
||||
if (hostPath.containsIgnoreCase ("Wavelab 5")) return SteinbergWavelab5;
|
||||
if (hostPath.containsIgnoreCase ("Wavelab 6")) return SteinbergWavelab6;
|
||||
if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7;
|
||||
if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8;
|
||||
if (hostPath.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost;
|
||||
if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric;
|
||||
if (hostFilename.containsIgnoreCase ("Maschine")) return Maschine;
|
||||
if (hostFilename.startsWith ("FL")) return FruityLoops;
|
||||
if (hostFilename.contains ("ilbridge.")) return FruityLoops;
|
||||
if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne;
|
||||
if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer;
|
||||
if (hostFilename.containsIgnoreCase ("VST_Scanner")) return VBVSTScanner;
|
||||
if (hostPath.containsIgnoreCase ("Merging Technologies")) return MergingPyramix;
|
||||
if (hostFilename.startsWithIgnoreCase ("Sam")) return MagixSamplitude;
|
||||
if (hostFilename.startsWithIgnoreCase ("Sequoia")) return MagixSequoia;
|
||||
if (hostFilename.containsIgnoreCase ("Reason")) return Reason;
|
||||
if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise;
|
||||
if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve;
|
||||
if (hostPath.containsIgnoreCase ("Bitwig Studio")) return BitwigStudio;
|
||||
if (hostFilename.containsIgnoreCase ("Sadie")) return SADiE;
|
||||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval;
|
||||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost;
|
||||
if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro;
|
||||
|
||||
#elif JUCE_LINUX || JUCE_BSD
|
||||
if (hostFilename.containsIgnoreCase ("Ardour")) return Ardour;
|
||||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform;
|
||||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric;
|
||||
if (hostFilename.startsWith ("Bitwig")) return BitwigStudio;
|
||||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval;
|
||||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost;
|
||||
|
||||
#elif JUCE_IOS
|
||||
#elif JUCE_ANDROID
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
return UnknownHost;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A useful utility class to determine the host or DAW in which your plugin is
|
||||
loaded.
|
||||
|
||||
Declare a PluginHostType object in your class to use it.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class PluginHostType
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
PluginHostType() : type (getHostType()) {}
|
||||
PluginHostType (const PluginHostType& other) = default;
|
||||
PluginHostType& operator= (const PluginHostType& other) = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Represents the host type and also its version for some hosts. */
|
||||
enum HostType
|
||||
{
|
||||
UnknownHost, /**< Represents an unknown host. */
|
||||
AbletonLive6, /**< Represents Ableton Live 6. */
|
||||
AbletonLive7, /**< Represents Ableton Live 7. */
|
||||
AbletonLive8, /**< Represents Ableton Live 8. */
|
||||
AbletonLive9, /**< Represents Ableton Live 9. */
|
||||
AbletonLive10, /**< Represents Ableton Live 10. */
|
||||
AbletonLive11, /**< Represents Ableton Live 11. */
|
||||
AbletonLiveGeneric, /**< Represents Ableton Live. */
|
||||
AdobeAudition, /**< Represents Adobe Audition. */
|
||||
AdobePremierePro, /**< Represents Adobe Premiere Pro. */
|
||||
AppleGarageBand, /**< Represents Apple GarageBand. */
|
||||
AppleInfoHelper, /**< Represents Apple com.apple.audio.InfoHelper. */
|
||||
AppleLogic, /**< Represents Apple Logic Pro. */
|
||||
AppleMainStage, /**< Represents Apple Main Stage. */
|
||||
Ardour, /**< Represents Ardour. */
|
||||
AULab, /**< Represents AU Lab. */
|
||||
AUVal, /**< Represents Apple AU validator. */
|
||||
AvidProTools, /**< Represents Avid Pro Tools. */
|
||||
BitwigStudio, /**< Represents Bitwig Studio. */
|
||||
CakewalkSonar8, /**< Represents Cakewalk Sonar 8. */
|
||||
CakewalkSonarGeneric, /**< Represents Cakewalk Sonar. */
|
||||
CakewalkByBandlab, /**< Represents Cakewalk by Bandlab. */
|
||||
DaVinciResolve, /**< Represents DaVinci Resolve. */
|
||||
DigitalPerformer, /**< Represents Digital Performer. */
|
||||
FinalCut, /**< Represents Apple Final Cut Pro. */
|
||||
FruityLoops, /**< Represents Fruity Loops. */
|
||||
JUCEPluginHost, /**< Represents the JUCE AudioPluginHost */
|
||||
MagixSamplitude, /**< Represents Magix Samplitude. */
|
||||
MagixSequoia, /**< Represents Magix Sequoia. */
|
||||
MergingPyramix, /**< Represents Merging Pyramix. */
|
||||
MuseReceptorGeneric, /**< Represents Muse Receptor. */
|
||||
Maschine, /**< Represents Native Instruments Maschine. */
|
||||
pluginval, /**< Represents pluginval. */
|
||||
Reaper, /**< Represents Cockos Reaper. */
|
||||
Reason, /**< Represents Reason. */
|
||||
Renoise, /**< Represents Renoise. */
|
||||
SADiE, /**< Represents SADiE. */
|
||||
SteinbergCubase4, /**< Represents Steinberg Cubase 4. */
|
||||
SteinbergCubase5, /**< Represents Steinberg Cubase 5. */
|
||||
SteinbergCubase5Bridged, /**< Represents Steinberg Cubase 5 Bridged. */
|
||||
SteinbergCubase6, /**< Represents Steinberg Cubase 6. */
|
||||
SteinbergCubase7, /**< Represents Steinberg Cubase 7. */
|
||||
SteinbergCubase8, /**< Represents Steinberg Cubase 8. */
|
||||
SteinbergCubase8_5, /**< Represents Steinberg Cubase 8.5. */
|
||||
SteinbergCubase9, /**< Represents Steinberg Cubase 9. */
|
||||
SteinbergCubase9_5, /**< Represents Steinberg Cubase 9.5. */
|
||||
SteinbergCubase10, /**< Represents Steinberg Cubase 10. */
|
||||
SteinbergCubase10_5, /**< Represents Steinberg Cubase 10.5. */
|
||||
SteinbergCubaseGeneric, /**< Represents Steinberg Cubase. */
|
||||
SteinbergNuendo3, /**< Represents Steinberg Nuendo 3. */
|
||||
SteinbergNuendo4, /**< Represents Steinberg Nuendo 4. */
|
||||
SteinbergNuendo5, /**< Represents Steinberg Nuendo 5. */
|
||||
SteinbergNuendoGeneric, /**< Represents Steinberg Nuendo. */
|
||||
SteinbergWavelab5, /**< Represents Steinberg Wavelab 5. */
|
||||
SteinbergWavelab6, /**< Represents Steinberg Wavelab 6. */
|
||||
SteinbergWavelab7, /**< Represents Steinberg Wavelab 7. */
|
||||
SteinbergWavelab8, /**< Represents Steinberg Wavelab 8. */
|
||||
SteinbergWavelabGeneric, /**< Represents Steinberg Wavelab. */
|
||||
SteinbergTestHost, /**< Represents Steinberg's VST3 Test Host. */
|
||||
StudioOne, /**< Represents PreSonus Studio One. */
|
||||
Tracktion3, /**< Represents Tracktion 3. */
|
||||
TracktionGeneric, /**< Represents Tracktion. */
|
||||
TracktionWaveform, /**< Represents Tracktion Waveform. */
|
||||
VBVSTScanner, /**< Represents VB Audio VST Scanner. */
|
||||
ViennaEnsemblePro, /**< Represents Vienna Ensemble Pro. */
|
||||
WaveBurner /**< Represents Apple WaveBurner. */
|
||||
};
|
||||
|
||||
HostType type;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the host is any version of Ableton Live. */
|
||||
bool isAbletonLive() const noexcept { return type == AbletonLive6 || type == AbletonLive7 || type == AbletonLive8
|
||||
|| type == AbletonLive9 || type == AbletonLive10 || type == AbletonLive11
|
||||
|| type == AbletonLiveGeneric; }
|
||||
/** Returns true if the host is Adobe Audition. */
|
||||
bool isAdobeAudition() const noexcept { return type == AdobeAudition; }
|
||||
/** Returns true if the host is com.apple.audio.InfoHelper. */
|
||||
bool isAppleInfoHelper() const noexcept { return type == AppleInfoHelper; }
|
||||
/** Returns true if the host is Ardour. */
|
||||
bool isArdour() const noexcept { return type == Ardour; }
|
||||
/** Returns true if the host is AU Lab. */
|
||||
bool isAULab() const noexcept { return type == AULab; }
|
||||
/** Returns true if the host is auval. */
|
||||
bool isAUVal() const noexcept { return type == AUVal; }
|
||||
/** Returns true if the host is Bitwig Studio. */
|
||||
bool isBitwigStudio() const noexcept { return type == BitwigStudio; }
|
||||
/** Returns true if the host is any version of Steinberg Cubase. */
|
||||
bool isCubase() const noexcept { return type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase5Bridged || type == SteinbergCubase6
|
||||
|| type == SteinbergCubase7 || type == SteinbergCubase8 || type == SteinbergCubase8_5 || type == SteinbergCubase9
|
||||
|| type == SteinbergCubase9_5 || type == SteinbergCubase10 || type == SteinbergCubase10_5 || type == SteinbergCubaseGeneric; }
|
||||
/** Returns true if the host is Steinberg Cubase 7 or later. */
|
||||
bool isCubase7orLater() const noexcept { return isCubase() && ! (type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase6); }
|
||||
/** Returns true if the host is Steinberg Cubase 5 Bridged. */
|
||||
bool isCubaseBridged() const noexcept { return type == SteinbergCubase5Bridged; }
|
||||
/** Returns true if the host is DaVinci Resolve. */
|
||||
bool isDaVinciResolve() const noexcept { return type == DaVinciResolve; }
|
||||
/** Returns true if the host is Digital Performer. */
|
||||
bool isDigitalPerformer() const noexcept { return type == DigitalPerformer; }
|
||||
/** Returns true if the host is Apple Final Cut Pro. */
|
||||
bool isFinalCut() const noexcept { return type == FinalCut; }
|
||||
/** Returns true if the host is Fruity Loops. */
|
||||
bool isFruityLoops() const noexcept { return type == FruityLoops; }
|
||||
/** Returns true if the host is Apple GarageBand. */
|
||||
bool isGarageBand() const noexcept { return type == AppleGarageBand; }
|
||||
/** Returns true if the host is the JUCE AudioPluginHost */
|
||||
bool isJUCEPluginHost() const noexcept { return type == JUCEPluginHost; }
|
||||
/** Returns true if the host is Apple Logic Pro. */
|
||||
bool isLogic() const noexcept { return type == AppleLogic; }
|
||||
/** Returns true if the host is Apple MainStage. */
|
||||
bool isMainStage() const noexcept { return type == AppleMainStage; }
|
||||
/** Returns true if the host is any version of Steinberg Nuendo. */
|
||||
bool isNuendo() const noexcept { return type == SteinbergNuendo3 || type == SteinbergNuendo4 || type == SteinbergNuendo5 || type == SteinbergNuendoGeneric; }
|
||||
/** Returns true if the host is pluginval. */
|
||||
bool isPluginval() const noexcept { return type == pluginval; }
|
||||
/** Returns true if the host is Adobe Premiere Pro. */
|
||||
bool isPremiere() const noexcept { return type == AdobePremierePro; }
|
||||
/** Returns true if the host is Avid Pro Tools. */
|
||||
bool isProTools() const noexcept { return type == AvidProTools; }
|
||||
/** Returns true if the host is Merging Pyramix. */
|
||||
bool isPyramix() const noexcept { return type == MergingPyramix; }
|
||||
/** Returns true if the host is Muse Receptor. */
|
||||
bool isReceptor() const noexcept { return type == MuseReceptorGeneric; }
|
||||
/** Returns true if the host is Cockos Reaper. */
|
||||
bool isReaper() const noexcept { return type == Reaper; }
|
||||
/** Returns true if the host is Reason. */
|
||||
bool isReason() const noexcept { return type == Reason; }
|
||||
/** Returns true if the host is Renoise. */
|
||||
bool isRenoise() const noexcept { return type == Renoise; }
|
||||
/** Returns true if the host is SADiE. */
|
||||
bool isSADiE() const noexcept { return type == SADiE; }
|
||||
/** Returns true if the host is Magix Samplitude. */
|
||||
bool isSamplitude() const noexcept { return type == MagixSamplitude; }
|
||||
/** Returns true if the host is Magix Sequoia. */
|
||||
bool isSequoia() const noexcept { return type == MagixSequoia; }
|
||||
/** Returns true if the host is any version of Cakewalk Sonar. */
|
||||
bool isSonar() const noexcept { return type == CakewalkSonar8 || type == CakewalkSonarGeneric || type == CakewalkByBandlab; }
|
||||
/** Returns true if the host is Steinberg's VST3 Test Host. */
|
||||
bool isSteinbergTestHost() const noexcept { return type == SteinbergTestHost; }
|
||||
/** Returns true if the host is any product from Steinberg. */
|
||||
bool isSteinberg() const noexcept { return isCubase() || isNuendo() || isWavelab() || isSteinbergTestHost(); }
|
||||
/** Returns true if the host is PreSonus Studio One. */
|
||||
bool isStudioOne() const noexcept { return type == StudioOne; }
|
||||
/** Returns true if the host is any version of Tracktion. */
|
||||
bool isTracktion() const noexcept { return type == Tracktion3 || type == TracktionGeneric || isTracktionWaveform(); }
|
||||
/** Returns true if the host is Tracktion Waveform. */
|
||||
bool isTracktionWaveform() const noexcept { return type == TracktionWaveform; }
|
||||
/** Returns true if the host is VB Audio VST Scanner. */
|
||||
bool isVBVSTScanner() const noexcept { return type == VBVSTScanner; }
|
||||
/** Returns true if the host is Vienna Ensemble Pro. */
|
||||
bool isViennaEnsemblePro() const noexcept { return type == ViennaEnsemblePro; }
|
||||
/** Returns true if the host is Apple WaveBurner. */
|
||||
bool isWaveBurner() const noexcept { return type == WaveBurner; }
|
||||
/** Returns true if the host is any version of Steinberg WaveLab. */
|
||||
bool isWavelab() const noexcept { return isWavelabLegacy() || type == SteinbergWavelab7 || type == SteinbergWavelab8 || type == SteinbergWavelabGeneric; }
|
||||
/** Returns true if the host is Steinberg WaveLab 6 or below. */
|
||||
bool isWavelabLegacy() const noexcept { return type == SteinbergWavelab5 || type == SteinbergWavelab6; }
|
||||
/** Returns true if the host is Native Instruments Maschine. */
|
||||
bool isMaschine() const noexcept { return type == Maschine; }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a human-readable description of the host. */
|
||||
const char* getHostDescription() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the plugin is connected with Inter-App Audio on iOS. */
|
||||
bool isInterAppAudioConnected() const;
|
||||
/** Switches to the host application when Inter-App Audio is used on iOS. */
|
||||
void switchToHostApplication() const;
|
||||
/** Gets the host app's icon when Inter-App Audio is used on iOS. */
|
||||
Image getHostIcon (int size) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the complete absolute path of the host application executable. */
|
||||
static String getHostPath()
|
||||
{
|
||||
return File::getSpecialLocation (File::hostApplicationPath).getFullPathName();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Returns the plug-in format via which the plug-in file was loaded. This value is
|
||||
identical to AudioProcessor::wrapperType of the main audio processor of this
|
||||
plug-in. This function is useful for code that does not have access to the
|
||||
plug-in's main audio processor.
|
||||
|
||||
@see AudioProcessor::wrapperType
|
||||
*/
|
||||
static AudioProcessor::WrapperType getPluginLoadedAs() noexcept { return jucePlugInClientCurrentWrapperType; }
|
||||
|
||||
/** Returns true if the AudioProcessor instance is an AAX plug-in running in AudioSuite. */
|
||||
static bool isInAAXAudioSuite (AudioProcessor&);
|
||||
|
||||
//==============================================================================
|
||||
|
||||
#ifndef DOXYGEN
|
||||
// @internal
|
||||
static AudioProcessor::WrapperType jucePlugInClientCurrentWrapperType;
|
||||
static std::function<bool (AudioProcessor&)> jucePlugInIsRunningInAudioSuiteFn;
|
||||
static String hostIdReportedByWrapper;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static HostType getHostType();
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
int RangedAudioParameter::getNumSteps() const
|
||||
{
|
||||
const auto& range = getNormalisableRange();
|
||||
|
||||
if (range.interval > 0)
|
||||
return (static_cast<int> ((range.end - range.start) / range.interval) + 1);
|
||||
|
||||
return AudioProcessor::getDefaultNumParameterSteps();
|
||||
}
|
||||
|
||||
float RangedAudioParameter::convertTo0to1 (float v) const noexcept
|
||||
{
|
||||
const auto& range = getNormalisableRange();
|
||||
return range.convertTo0to1 (range.snapToLegalValue (v));
|
||||
}
|
||||
|
||||
float RangedAudioParameter::convertFrom0to1 (float v) const noexcept
|
||||
{
|
||||
const auto& range = getNormalisableRange();
|
||||
return range.snapToLegalValue (range.convertFrom0to1 (jlimit (0.0f, 1.0f, v)));
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/**
|
||||
@internal
|
||||
|
||||
Holds common attributes of audio parameters.
|
||||
|
||||
CRTP is used here because we want the Attributes types for each parameter
|
||||
(Float, Bool, Choice, Int) to be distinct and extensible in the future.
|
||||
i.e. the identifiers AudioParameterFloatAttributes and RangedAudioParameterAttributes<float>
|
||||
should not be interchangable because we might need to add float-specific attributes in
|
||||
the future. Users should not refer directly to RangedAudioParameterAttributes.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
template <typename Derived, typename Value>
|
||||
class RangedAudioParameterAttributes
|
||||
{
|
||||
using This = RangedAudioParameterAttributes;
|
||||
|
||||
public:
|
||||
using Category = AudioProcessorParameter::Category;
|
||||
|
||||
using StringFromValue = std::function<String (Value, int)>;
|
||||
using ValueFromString = std::function<Value (const String&)>;
|
||||
|
||||
/** An optional lambda function that converts a non-normalised value to a string with a maximum length. This may be used by hosts to display the parameter's value. */
|
||||
[[nodiscard]] auto withStringFromValueFunction (StringFromValue x) const { return withMember (asDerived(), &Derived::stringFromValue, std::move (x)); }
|
||||
|
||||
/** An optional lambda function that parses a string and converts it into a non-normalised value. Some hosts use this to allow users to type in parameter values. */
|
||||
[[nodiscard]] auto withValueFromStringFunction (ValueFromString x) const { return withMember (asDerived(), &Derived::valueFromString, std::move (x)); }
|
||||
|
||||
/** See AudioProcessorParameterWithIDAttributes::withLabel() */
|
||||
[[nodiscard]] auto withLabel (String x) const { return withMember (asDerived(), &Derived::attributes, attributes.withLabel (std::move (x))); }
|
||||
|
||||
/** See AudioProcessorParameterWithIDAttributes::withCategory() */
|
||||
[[nodiscard]] auto withCategory (Category x) const { return withMember (asDerived(), &Derived::attributes, attributes.withCategory (std::move (x))); }
|
||||
|
||||
/** See AudioProcessorParameter::isMetaParameter() */
|
||||
[[nodiscard]] auto withMeta (bool x) const { return withMember (asDerived(), &Derived::attributes, attributes.withMeta (std::move (x))); }
|
||||
|
||||
/** See AudioProcessorParameter::isAutomatable() */
|
||||
[[nodiscard]] auto withAutomatable (bool x) const { return withMember (asDerived(), &Derived::attributes, attributes.withAutomatable (std::move (x))); }
|
||||
|
||||
/** See AudioProcessorParameter::isOrientationInverted() */
|
||||
[[nodiscard]] auto withInverted (bool x) const { return withMember (asDerived(), &Derived::attributes, attributes.withInverted (std::move (x))); }
|
||||
|
||||
/** An optional lambda function that converts a non-normalised value to a string with a maximum length. This may be used by hosts to display the parameter's value. */
|
||||
[[nodiscard]] const auto& getStringFromValueFunction() const { return stringFromValue; }
|
||||
|
||||
/** An optional lambda function that parses a string and converts it into a non-normalised value. Some hosts use this to allow users to type in parameter values. */
|
||||
[[nodiscard]] const auto& getValueFromStringFunction() const { return valueFromString; }
|
||||
|
||||
/** Gets attributes that would also apply to an AudioProcessorParameterWithID */
|
||||
[[nodiscard]] const auto& getAudioProcessorParameterWithIDAttributes() const { return attributes; }
|
||||
|
||||
private:
|
||||
auto& asDerived() const { return *static_cast<const Derived*> (this); }
|
||||
|
||||
AudioProcessorParameterWithIDAttributes attributes;
|
||||
StringFromValue stringFromValue;
|
||||
ValueFromString valueFromString;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This abstract base class is used by some AudioProcessorParameter helper classes.
|
||||
|
||||
@see AudioParameterFloat, AudioParameterInt, AudioParameterBool, AudioParameterChoice
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API RangedAudioParameter : public AudioProcessorParameterWithID
|
||||
{
|
||||
public:
|
||||
using AudioProcessorParameterWithID::AudioProcessorParameterWithID;
|
||||
|
||||
/** Returns the range of values that the parameter can take. */
|
||||
virtual const NormalisableRange<float>& getNormalisableRange() const = 0;
|
||||
|
||||
/** Returns the number of steps for this parameter based on the normalisable range's interval.
|
||||
If you are using lambda functions to define the normalisable range's snapping behaviour
|
||||
then you should override this function so that it returns the number of snapping points.
|
||||
*/
|
||||
int getNumSteps() const override;
|
||||
|
||||
/** Normalises and snaps a value based on the normalisable range. */
|
||||
float convertTo0to1 (float v) const noexcept;
|
||||
|
||||
/** Denormalises and snaps a value based on the normalisable range. */
|
||||
float convertFrom0to1 (float v) const noexcept;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
pointer_sized_int VST2ClientExtensions::handleVstPluginCanDo ([[maybe_unused]] int32 index,
|
||||
[[maybe_unused]] pointer_sized_int value,
|
||||
[[maybe_unused]] void* ptr,
|
||||
[[maybe_unused]] float opt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VST2ClientExtensions::handleVstHostCallbackAvailable ([[maybe_unused]] std::function<VstHostCallbackType>&& callback) {}
|
||||
|
||||
} // namespace juce
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/**
|
||||
An interface to allow an AudioProcessor to implement extended VST2-specific functionality.
|
||||
|
||||
To use this class, create an object that inherits from it, implement the methods, then return
|
||||
a pointer to the object in your AudioProcessor::getVST2ClientExtensions() method.
|
||||
|
||||
@see AudioProcessor, AAXClientExtensions, VST3ClientExtensions
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct VST2ClientExtensions
|
||||
{
|
||||
virtual ~VST2ClientExtensions() = default;
|
||||
|
||||
/** This is called by the VST plug-in wrapper when it receives unhandled
|
||||
plug-in "can do" calls from the host.
|
||||
*/
|
||||
virtual pointer_sized_int handleVstPluginCanDo (int32 index,
|
||||
pointer_sized_int value,
|
||||
void* ptr,
|
||||
float opt);
|
||||
|
||||
/** This is called by the VST plug-in wrapper when it receives unhandled
|
||||
vendor specific calls from the host.
|
||||
*/
|
||||
virtual pointer_sized_int handleVstManufacturerSpecific (int32 index,
|
||||
pointer_sized_int value,
|
||||
void* ptr,
|
||||
float opt) = 0;
|
||||
|
||||
/** The host callback function type. */
|
||||
using VstHostCallbackType = pointer_sized_int (int32 opcode,
|
||||
int32 index,
|
||||
pointer_sized_int value,
|
||||
void* ptr,
|
||||
float opt);
|
||||
|
||||
/** This is called once by the VST plug-in wrapper after its constructor.
|
||||
You can use the supplied function to query the VST host.
|
||||
*/
|
||||
virtual void handleVstHostCallbackAvailable (std::function<VstHostCallbackType>&& callback);
|
||||
};
|
||||
|
||||
using VSTCallbackHandler [[deprecated ("replace with VST2ClientExtensions")]] = VST2ClientExtensions;
|
||||
|
||||
} // namespace juce
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
// Forward declaration to avoid leaking implementation details.
|
||||
namespace Steinberg
|
||||
{
|
||||
class FUnknown;
|
||||
using TUID = char[16];
|
||||
} // namespace Steinberg
|
||||
|
||||
#endif
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/**
|
||||
An interface to allow an AudioProcessor to implement extended VST3-specific functionality.
|
||||
|
||||
To use this class, create an object that inherits from it, implement the methods, then return
|
||||
a pointer to the object in your AudioProcessor::getVST3ClientExtensions() method.
|
||||
|
||||
@see AudioProcessor, AAXClientExtensions, VST2ClientExtensions
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct VST3ClientExtensions
|
||||
{
|
||||
virtual ~VST3ClientExtensions() = default;
|
||||
|
||||
/** This function may be used by implementations of queryInterface()
|
||||
in the VST3's implementation of IEditController to return
|
||||
additional supported interfaces.
|
||||
*/
|
||||
virtual int32_t queryIEditController (const Steinberg::TUID, void** obj)
|
||||
{
|
||||
*obj = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** This function may be used by implementations of queryInterface()
|
||||
in the VST3's implementation of IAudioProcessor to return
|
||||
additional supported interfaces.
|
||||
*/
|
||||
virtual int32_t queryIAudioProcessor (const Steinberg::TUID, void** obj)
|
||||
{
|
||||
*obj = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** This may be called by the VST3 wrapper when the host sets an
|
||||
IComponentHandler for the plugin to use.
|
||||
|
||||
You should not make any assumptions about how and when this will be
|
||||
called - this function may not be called at all!
|
||||
*/
|
||||
virtual void setIComponentHandler (Steinberg::FUnknown*) {}
|
||||
|
||||
/** This may be called shortly after the AudioProcessor is constructed
|
||||
with the current IHostApplication.
|
||||
|
||||
You should not make any assumptions about how and when this will be
|
||||
called - this function may not be called at all!
|
||||
*/
|
||||
virtual void setIHostApplication (Steinberg::FUnknown*) {}
|
||||
|
||||
/** This function will be called to check whether the first input bus
|
||||
should be designated as "kMain" or "kAux". Return true if the
|
||||
first bus should be kMain, or false if the bus should be kAux.
|
||||
|
||||
All other input buses will always be designated kAux.
|
||||
*/
|
||||
virtual bool getPluginHasMainInput() const { return true; }
|
||||
|
||||
/** This function should return the UIDs of any compatible VST2 plug-ins.
|
||||
|
||||
Each item in the vector should be a 32-character string consisting only
|
||||
of the characters 0-9 and A-F.
|
||||
|
||||
This information will be used to implement the IPluginCompatibility
|
||||
interface. Hosts can use this interface to determine whether this VST3
|
||||
is capable of replacing a given VST2.
|
||||
*/
|
||||
virtual std::vector<String> getCompatibleClasses() const { return {}; }
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Reference in New Issue
Block a user