migrating to the latest JUCE version

This commit is contained in:
2022-11-04 23:11:33 +01:00
committed by Nikolai Rodionov
parent 4257a0f8ba
commit faf8f18333
2796 changed files with 888518 additions and 784244 deletions

View File

@ -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

View File

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

View File

@ -0,0 +1,520 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
namespace juce
{
class ARAPlaybackRenderer;
class ARAEditorRenderer;
class ARAEditorView;
class ARAInputStream;
class ARAOutputStream;
/** This class contains the customisation points for the JUCE provided ARA document controller
implementation.
Every ARA enabled plugin must provide its own document controller implementation. To do this,
inherit from this class, and override its protected methods as needed. Then you need to
implement a global function somewhere in your module called createARAFactory(). This function
must return an ARAFactory* that will instantiate document controller objects using your
specialisation. There are helper functions inside ARADocumentControllerSpecialisation, so the
implementation of createARAFactory() can always be a simple one-liner. For example
@code
class MyDocumentController : public ARADocumentControllerSpecialisation
{
//...
};
const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory()
{
return juce::ARADocumentControllerSpecialisation::createARAFactory<MyDocumentController>();
}
@endcode
Most member functions have a default implementation so you can build up your required feature
set gradually. The protected functions of this class fall in three distinct groups:
- interactive editing and playback,
- analysis features provided by the plugin and utilised by the host, and
- maintaining the ARA model graph.
On top of the pure virtual functions, you will probably want to override
doCreatePlaybackRenderer() at the very least if you want your plugin to play any sound. This
function belongs to the first group.
If your plugin has analysis capabilities and wants to allow the host to access these, functions
in the second group should be overridden.
The default implementation of the ARA model object classes - i.e. ARADocument, ARAMusicalContext,
ARARegionSequence, ARAAudioSource, ARAAudioModification, ARAPlaybackRegion - should be sufficient
for maintaining a representation of the ARA model graph, hence overriding the model object
creation functions e.g. doCreateMusicalContext() is considered an advanced use case. Hence you
should be able to get a lot done without overriding functions in the third group.
In order to react to the various ARA state changes you can override any of the ARA model object
Listener functions that ARADocumentControllerSpecialisation inherits from. Such listener
functions can be attached to one particular model objects instance, but the listener functions
inside ARADocumentControllerSpecialisation will respond to the events of all instances of the
model objects.
@tags{ARA}
*/
class ARADocumentControllerSpecialisation : public ARADocument::Listener,
public ARAMusicalContext::Listener,
public ARARegionSequence::Listener,
public ARAAudioSource::Listener,
public ARAAudioModification::Listener,
public ARAPlaybackRegion::Listener
{
public:
//==============================================================================
/** Constructor. Used internally by the ARAFactory implementation.
*/
ARADocumentControllerSpecialisation (const ARA::PlugIn::PlugInEntry* entry,
const ARA::ARADocumentControllerHostInstance* instance);
/** Destructor. */
virtual ~ARADocumentControllerSpecialisation();
/** Returns the underlying DocumentController object that references this specialisation.
*/
ARA::PlugIn::DocumentController* getDocumentController() noexcept;
/** Helper function for implementing the global createARAFactory() function.
For example
@code
class MyDocumentController : public ARADocumentControllerSpecialisation
{
//...
};
const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory()
{
return juce::ARADocumentControllerSpecialisation::createARAFactory<MyDocumentController>();
}
@endcode
*/
template <typename SpecialisationType>
static const ARA::ARAFactory* createARAFactory()
{
static_assert (std::is_base_of<ARADocumentControllerSpecialisation, SpecialisationType>::value,
"DocumentController specialization types must inherit from ARADocumentControllerSpecialisation");
return ARA::PlugIn::PlugInEntry::getPlugInEntry<FactoryConfig<SpecialisationType>>()->getFactory();
}
/** Returns a pointer to the ARADocumentControllerSpecialisation instance that is referenced
by the provided DocumentController. You can use this function to access your specialisation
from anywhere where you have access to ARA::PlugIn::DocumentController*.
*/
template <typename Specialisation = ARADocumentControllerSpecialisation>
static Specialisation* getSpecialisedDocumentController (ARA::PlugIn::DocumentController* dc)
{
return static_cast<Specialisation*> (getSpecialisedDocumentControllerImpl (dc));
}
/** Returns a pointer to the ARA document root maintained by this document controller. */
template <typename DocumentType = ARADocument>
DocumentType* getDocument()
{
return static_cast<DocumentType*> (getDocumentImpl());
}
protected:
//==============================================================================
/** Read an ARADocument archive from a juce::InputStream.
@param input Data stream containing previously persisted data to be used when restoring the ARADocument
@param filter A filter to be applied to the stream
Return true if the operation is successful.
@see ARADocumentControllerInterface::restoreObjectsFromArchive
*/
virtual bool doRestoreObjectsFromStream (ARAInputStream& input, const ARARestoreObjectsFilter* filter) = 0;
/** Write an ARADocument archive to a juce::OutputStream.
@param output Data stream that should be used to write the persistent ARADocument data
@param filter A filter to be applied to the stream
Returns true if the operation is successful.
@see ARADocumentControllerInterface::storeObjectsToArchive
*/
virtual bool doStoreObjectsToStream (ARAOutputStream& output, const ARAStoreObjectsFilter* filter) = 0;
//==============================================================================
/** Override to return a custom subclass instance of ARAPlaybackRenderer. */
virtual ARAPlaybackRenderer* doCreatePlaybackRenderer();
/** Override to return a custom subclass instance of ARAEditorRenderer. */
virtual ARAEditorRenderer* doCreateEditorRenderer();
/** Override to return a custom subclass instance of ARAEditorView. */
virtual ARAEditorView* doCreateEditorView();
//==============================================================================
// ARAAudioSource content access
/** Override to implement isAudioSourceContentAvailable() for all your supported content types -
the default implementation always returns false, preventing any calls to doGetAudioSourceContentGrade()
and doCreateAudioSourceContentReader().
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doIsAudioSourceContentAvailable.
*/
virtual bool doIsAudioSourceContentAvailable (const ARA::PlugIn::AudioSource* audioSource,
ARA::ARAContentType type);
/** Override to implement getAudioSourceContentGrade() for all your supported content types.
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doGetAudioSourceContentGrade.
*/
virtual ARA::ARAContentGrade doGetAudioSourceContentGrade (const ARA::PlugIn::AudioSource* audioSource,
ARA::ARAContentType type);
/** Override to implement createAudioSourceContentReader() for all your supported content types,
returning a custom subclass instance of ContentReader providing data of the requested type.
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doCreateAudioSourceContentReader.
*/
virtual ARA::PlugIn::ContentReader* doCreateAudioSourceContentReader (ARA::PlugIn::AudioSource* audioSource,
ARA::ARAContentType type,
const ARA::ARAContentTimeRange* range);
//==============================================================================
// ARAAudioModification content access
/** Override to implement isAudioModificationContentAvailable() for all your supported content types -
the default implementation always returns false.
For read-only data directly inherited from the underlying audio source you can just delegate the
call to the audio source, but user-editable modification data must be specifically handled here.
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doIsAudioModificationContentAvailable.
*/
virtual bool doIsAudioModificationContentAvailable (const ARA::PlugIn::AudioModification* audioModification,
ARA::ARAContentType type);
/** Override to implement getAudioModificationContentGrade() for all your supported content types.
For read-only data directly inherited from the underlying audio source you can just delegate the
call to the audio source, but user-editable modification data must be specifically handled here.
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doGetAudioModificationContentGrade.
*/
virtual ARA::ARAContentGrade doGetAudioModificationContentGrade (const ARA::PlugIn::AudioModification* audioModification,
ARA::ARAContentType type);
/** Override to implement createAudioModificationContentReader() for all your supported content types,
returning a custom subclass instance of ContentReader providing data of the requested \p type.
For read-only data directly inherited from the underlying audio source you can just delegate the
call to the audio source, but user-editable modification data must be specifically handled here.
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doCreateAudioModificationContentReader.
*/
virtual ARA::PlugIn::ContentReader* doCreateAudioModificationContentReader (ARA::PlugIn::AudioModification* audioModification,
ARA::ARAContentType type,
const ARA::ARAContentTimeRange* range);
//==============================================================================
// ARAPlaybackRegion content access
/** Override to implement isPlaybackRegionContentAvailable() for all your supported content types -
the default implementation always returns false.
Typically, this call can directly delegate to the underlying audio modification, since most
plug-ins will apply their modification data to the playback region with a transformation that
does not affect content availability.
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doIsPlaybackRegionContentAvailable.
*/
virtual bool doIsPlaybackRegionContentAvailable (const ARA::PlugIn::PlaybackRegion* playbackRegion,
ARA::ARAContentType type);
/** Override to implement getPlaybackRegionContentGrade() for all your supported content types.
Typically, this call can directly delegate to the underlying audio modification, since most
plug-ins will apply their modification data to the playback region with a transformation that
does not affect content grade.
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doGetPlaybackRegionContentGrade.
*/
virtual ARA::ARAContentGrade doGetPlaybackRegionContentGrade (const ARA::PlugIn::PlaybackRegion* playbackRegion,
ARA::ARAContentType type);
/** Override to implement createPlaybackRegionContentReader() for all your supported content types,
returning a custom subclass instance of ContentReader providing data of the requested type.
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doCreatePlaybackRegionContentReader.
*/
virtual ARA::PlugIn::ContentReader* doCreatePlaybackRegionContentReader (ARA::PlugIn::PlaybackRegion* playbackRegion,
ARA::ARAContentType type,
const ARA::ARAContentTimeRange* range);
//==============================================================================
// ARAAudioSource analysis
/** Override to implement isAudioSourceContentAnalysisIncomplete().
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doIsAudioSourceContentAnalysisIncomplete.
*/
virtual bool doIsAudioSourceContentAnalysisIncomplete (const ARA::PlugIn::AudioSource* audioSource,
ARA::ARAContentType type);
/** Override to implement requestAudioSourceContentAnalysis().
This function's called from
ARA::PlugIn::DocumentControllerDelegate::doRequestAudioSourceContentAnalysis.
*/
virtual void doRequestAudioSourceContentAnalysis (ARA::PlugIn::AudioSource* audioSource,
std::vector<ARA::ARAContentType> const& contentTypes);
//==============================================================================
// Analysis Algorithm selection
/** Override to implement getProcessingAlgorithmsCount().
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmsCount.
*/
virtual ARA::ARAInt32 doGetProcessingAlgorithmsCount ();
/** Override to implement getProcessingAlgorithmProperties().
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmProperties.
*/
virtual const ARA::ARAProcessingAlgorithmProperties*
doGetProcessingAlgorithmProperties (ARA::ARAInt32 algorithmIndex);
/** Override to implement getProcessingAlgorithmForAudioSource().
This function's result is returned from
ARA::PlugIn::DocumentControllerDelegate::doGetProcessingAlgorithmForAudioSource.
*/
virtual ARA::ARAInt32 doGetProcessingAlgorithmForAudioSource (const ARA::PlugIn::AudioSource* audioSource);
/** Override to implement requestProcessingAlgorithmForAudioSource().
This function's called from
ARA::PlugIn::DocumentControllerDelegate::doRequestProcessingAlgorithmForAudioSource.
*/
virtual void doRequestProcessingAlgorithmForAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::ARAInt32 algorithmIndex);
//==============================================================================
/** Override to return a custom subclass instance of ARADocument. */
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

View File

@ -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

View File

@ -0,0 +1,199 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
size_t ARADocument::getNumChildren() const noexcept
{
return getMusicalContexts().size() + getRegionSequences().size() + getAudioSources().size();
}
ARAObject* ARADocument::getChild (size_t index)
{
auto& musicalContexts = getMusicalContexts();
if (index < musicalContexts.size())
return musicalContexts[index];
const auto numMusicalContexts = musicalContexts.size();
auto& regionSequences = getRegionSequences();
if (index < numMusicalContexts + regionSequences.size())
return regionSequences[index - numMusicalContexts];
const auto numMusicalContextsAndRegionSequences = numMusicalContexts + regionSequences.size();
auto& audioSources = getAudioSources();
if (index < numMusicalContextsAndRegionSequences + audioSources.size())
return getAudioSources()[index - numMusicalContextsAndRegionSequences];
return nullptr;
}
//==============================================================================
size_t ARARegionSequence::getNumChildren() const noexcept
{
return 0;
}
ARAObject* ARARegionSequence::getChild (size_t)
{
return nullptr;
}
Range<double> ARARegionSequence::getTimeRange (ARAPlaybackRegion::IncludeHeadAndTail includeHeadAndTail) const
{
if (getPlaybackRegions().empty())
return {};
auto startTime = std::numeric_limits<double>::max();
auto endTime = std::numeric_limits<double>::lowest();
for (const auto& playbackRegion : getPlaybackRegions())
{
const auto regionTimeRange = playbackRegion->getTimeRange (includeHeadAndTail);
startTime = jmin (startTime, regionTimeRange.getStart());
endTime = jmax (endTime, regionTimeRange.getEnd());
}
return { startTime, endTime };
}
double ARARegionSequence::getCommonSampleRate() const
{
const auto getSampleRate = [] (auto* playbackRegion)
{
return playbackRegion->getAudioModification()->getAudioSource()->getSampleRate();
};
const auto range = getPlaybackRegions();
const auto sampleRate = range.size() > 0 ? getSampleRate (range.front()) : 0.0;
if (std::any_of (range.begin(), range.end(), [&] (auto& x) { return getSampleRate (x) != sampleRate; }))
return 0.0;
return sampleRate;
}
//==============================================================================
size_t ARAAudioSource::getNumChildren() const noexcept
{
return getAudioModifications().size();
}
ARAObject* ARAAudioSource::getChild (size_t index)
{
return getAudioModifications()[index];
}
void ARAAudioSource::notifyAnalysisProgressStarted()
{
getDocumentController<ARADocumentController>()->internalNotifyAudioSourceAnalysisProgressStarted (this);
}
void ARAAudioSource::notifyAnalysisProgressUpdated (float progress)
{
getDocumentController<ARADocumentController>()->internalNotifyAudioSourceAnalysisProgressUpdated (this, progress);
}
void ARAAudioSource::notifyAnalysisProgressCompleted()
{
getDocumentController<ARADocumentController>()->internalNotifyAudioSourceAnalysisProgressCompleted (this);
}
void ARAAudioSource::notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost)
{
getDocumentController<ARADocumentController>()->internalNotifyAudioSourceContentChanged (this,
scopeFlags,
notifyARAHost);
}
//==============================================================================
size_t ARAAudioModification::getNumChildren() const noexcept
{
return getPlaybackRegions().size();
}
ARAObject* ARAAudioModification::getChild (size_t index)
{
return getPlaybackRegions()[index];
}
void ARAAudioModification::notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost)
{
getDocumentController<ARADocumentController>()->internalNotifyAudioModificationContentChanged (this,
scopeFlags,
notifyARAHost);
}
//==============================================================================
ARAObject* ARAPlaybackRegion::getParent() { return getAudioModification(); }
Range<double> ARAPlaybackRegion::getTimeRange (IncludeHeadAndTail includeHeadAndTail) const
{
auto startTime = getStartInPlaybackTime();
auto endTime = getEndInPlaybackTime();
if (includeHeadAndTail == IncludeHeadAndTail::yes)
{
ARA::ARATimeDuration headTime {}, tailTime {};
getDocumentController()->getPlaybackRegionHeadAndTailTime (toRef (this), &headTime, &tailTime);
startTime -= headTime;
endTime += tailTime;
}
return { startTime, endTime };
}
Range<int64> ARAPlaybackRegion::getSampleRange (double sampleRate, IncludeHeadAndTail includeHeadAndTail) const
{
const auto timeRange = getTimeRange (includeHeadAndTail);
return { ARA::samplePositionAtTime (timeRange.getStart(), sampleRate),
ARA::samplePositionAtTime (timeRange.getEnd(), sampleRate) };
}
double ARAPlaybackRegion::getHeadTime() const
{
ARA::ARATimeDuration headTime {}, tailTime {};
getDocumentController()->getPlaybackRegionHeadAndTailTime (toRef (this), &headTime, &tailTime);
return headTime;
}
double ARAPlaybackRegion::getTailTime() const
{
ARA::ARATimeDuration headTime {}, tailTime {};
getDocumentController()->getPlaybackRegionHeadAndTailTime (toRef (this), &headTime, &tailTime);
return tailTime;
}
void ARAPlaybackRegion::notifyContentChanged (ARAContentUpdateScopes scopeFlags, bool notifyARAHost)
{
getDocumentController<ARADocumentController>()->internalNotifyPlaybackRegionContentChanged (this,
scopeFlags,
notifyARAHost);
}
} // namespace juce

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,92 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "juce_ARAPlugInInstanceRoles.h"
namespace juce
{
bool ARARenderer::processBlock (AudioBuffer<double>& buffer,
AudioProcessor::Realtime realtime,
const AudioPlayHead::PositionInfo& positionInfo) noexcept
{
ignoreUnused (buffer, realtime, positionInfo);
// If you hit this assertion then either the caller called the double
// precision version of processBlock on a processor which does not support it
// (i.e. supportsDoublePrecisionProcessing() returns false), or the implementation
// of the ARARenderer forgot to override the double precision version of this method
jassertfalse;
return false;
}
//==============================================================================
#if ARA_VALIDATE_API_CALLS
void ARAPlaybackRenderer::addPlaybackRegion (ARA::ARAPlaybackRegionRef playbackRegionRef) noexcept
{
if (araExtension)
ARA_VALIDATE_API_STATE (! araExtension->isPrepared);
ARA::PlugIn::PlaybackRenderer::addPlaybackRegion (playbackRegionRef);
}
void ARAPlaybackRenderer::removePlaybackRegion (ARA::ARAPlaybackRegionRef playbackRegionRef) noexcept
{
if (araExtension)
ARA_VALIDATE_API_STATE (! araExtension->isPrepared);
ARA::PlugIn::PlaybackRenderer::removePlaybackRegion (playbackRegionRef);
}
#endif
//==============================================================================
void ARAEditorView::doNotifySelection (const ARA::PlugIn::ViewSelection* viewSelection) noexcept
{
listeners.call ([&] (Listener& l)
{
l.onNewSelection (*viewSelection);
});
}
void ARAEditorView::doNotifyHideRegionSequences (std::vector<ARA::PlugIn::RegionSequence*> const& regionSequences) noexcept
{
listeners.call ([&] (Listener& l)
{
l.onHideRegionSequences (ARA::vector_cast<ARARegionSequence*> (regionSequences));
});
}
void ARAEditorView::addListener (Listener* l)
{
listeners.add (l);
}
void ARAEditorView::removeListener (Listener* l)
{
listeners.remove (l);
}
} // namespace juce

View File

@ -0,0 +1,275 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
namespace juce
{
//==============================================================================
/** Base class for a renderer fulfilling either the ARAPlaybackRenderer or the ARAEditorRenderer role.
Instances of either subclass are constructed by the DocumentController.
@tags{ARA}
*/
class JUCE_API ARARenderer
{
public:
enum class AlwaysNonRealtime { no, yes };
virtual ~ARARenderer() = default;
/** Initialises the renderer for playback.
@param sampleRate The sample rate that will be used for the data that is sent
to the renderer
@param maximumSamplesPerBlock The maximum number of samples that will be in the blocks
sent to process() method
@param numChannels The number of channels that the process() method will be
expected to handle
@param precision This should be the same as the result of getProcessingPrecision()
for the enclosing AudioProcessor
@param alwaysNonRealtime yes if this renderer is never used in realtime (e.g. if
providing data for views only)
*/
virtual void prepareToPlay (double sampleRate,
int maximumSamplesPerBlock,
int numChannels,
AudioProcessor::ProcessingPrecision precision,
AlwaysNonRealtime alwaysNonRealtime = AlwaysNonRealtime::no)
{
ignoreUnused (sampleRate, maximumSamplesPerBlock, numChannels, precision, alwaysNonRealtime);
}
/** Frees render resources allocated in prepareToPlay(). */
virtual void releaseResources() {}
/** Resets the internal state variables of the renderer. */
virtual void reset() {}
/** Renders the output into the given buffer. Returns true if rendering executed without error,
false otherwise.
@param buffer The output buffer for the rendering. ARAPlaybackRenderers will
replace the sample data, while ARAEditorRenderer will add to it.
@param realtime Indicates whether the call is executed under real time constraints.
The value of this parameter may change from one call to the next,
and if the value is yes, the rendering may fail if the required
samples cannot be obtained in time.
@param positionInfo Current song position, playback state and playback loop location.
There should be no need to access the bpm, timeSig and ppqPosition
members in any ARA renderer since ARA provides that information with
random access in its model graph.
Returns false if non-ARA fallback rendering is required and true otherwise.
*/
virtual bool processBlock (AudioBuffer<float>& buffer,
AudioProcessor::Realtime realtime,
const AudioPlayHead::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
{
ignoreUnused (buffer, realtime, positionInfo);
return false;
}
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
{
ignoreUnused (buffer, isNonRealtime, positionInfo);
return true;
}
using ARARenderer::processBlock;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ARAEditorRenderer)
};
//==============================================================================
/** Base class for a renderer fulfilling the ARAEditorView role as described in the ARA SDK.
Instances of this class are constructed by the DocumentController. If you are subclassing
ARAEditorView, make sure to call the base class implementation of overridden functions.
@tags{ARA}
*/
class JUCE_API ARAEditorView : public ARA::PlugIn::EditorView
{
public:
using ARA::PlugIn::EditorView::EditorView;
// Shadowing templated getters to default to JUCE versions of the returned classes
template <typename RegionSequence_t = ARARegionSequence>
std::vector<RegionSequence_t*> const& getHiddenRegionSequences() const noexcept
{
return ARA::PlugIn::EditorView::getHiddenRegionSequences<RegionSequence_t>();
}
// Base class implementation must be called if overridden
void doNotifySelection (const ARA::PlugIn::ViewSelection* currentSelection) noexcept override;
// Base class implementation must be called if overridden
void doNotifyHideRegionSequences (std::vector<ARA::PlugIn::RegionSequence*> const& regionSequences) noexcept override;
/** A base class for listeners that want to know about changes to an ARAEditorView object.
Use ARAEditorView::addListener() to register your listener with an ARAEditorView.
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() = default;
ARA_DISABLE_UNREFERENCED_PARAMETER_WARNING_BEGIN
/** Called when the editor view's selection changes.
@param viewSelection The current selection state
*/
virtual void onNewSelection (const ARA::PlugIn::ViewSelection& viewSelection)
{
ignoreUnused (viewSelection);
}
/** Called when region sequences are flagged as hidden in the host UI.
@param regionSequences A vector containing all hidden region sequences.
*/
virtual void onHideRegionSequences (std::vector<ARARegionSequence*> const& regionSequences)
{
ignoreUnused (regionSequences);
}
ARA_DISABLE_UNREFERENCED_PARAMETER_WARNING_END
};
/** \copydoc ARAListenableModelClass::addListener */
void addListener (Listener* l);
/** \copydoc ARAListenableModelClass::removeListener */
void removeListener (Listener* l);
private:
ListenerList<Listener> listeners;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ARAEditorView)
};
}

View File

@ -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

View File

@ -0,0 +1,85 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#if JucePlugin_Enable_ARA
// Include ARA SDK headers
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wgnu-zero-variadic-macro-arguments",
"-Wunused-parameter")
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6387)
#include <ARA_Library/PlugIn/ARAPlug.h>
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
JUCE_END_IGNORE_WARNINGS_MSVC
namespace juce
{
using ARAViewSelection = ARA::PlugIn::ViewSelection;
using ARAContentUpdateScopes = ARA::ContentUpdateScopes;
using ARARestoreObjectsFilter = ARA::PlugIn::RestoreObjectsFilter;
using ARAStoreObjectsFilter = ARA::PlugIn::StoreObjectsFilter;
/** Converts an ARA::ARAUtf8String to a JUCE String. */
inline String convertARAString (ARA::ARAUtf8String str)
{
return String (CharPointer_UTF8 (str));
}
/** Converts a potentially NULL ARA::ARAUtf8String to a JUCE String.
Returns the JUCE equivalent of the provided string if it's not nullptr, and the fallback string
otherwise.
*/
inline String convertOptionalARAString (ARA::ARAUtf8String str, const String& fallbackString = String())
{
return (str != nullptr) ? convertARAString (str) : fallbackString;
}
/** Converts an ARA::ARAColor* to a JUCE Colour. */
inline Colour convertARAColour (const ARA::ARAColor* colour)
{
return Colour::fromFloatRGBA (colour->r, colour->g, colour->b, 1.0f);
}
/** Converts a potentially NULL ARA::ARAColor* to a JUCE Colour.
Returns the JUCE equivalent of the provided colour if it's not nullptr, and the fallback colour
otherwise.
*/
inline Colour convertOptionalARAColour (const ARA::ARAColor* colour, const Colour& fallbackColour = Colour())
{
return (colour != nullptr) ? convertARAColour (colour) : fallbackColour;
}
} // namespace juce
#include "juce_ARAModelObjects.h"
#include "juce_ARADocumentController.h"
#include "juce_AudioProcessor_ARAExtensions.h"
#include "juce_ARAPlugInInstanceRoles.h"
#endif

View File

@ -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

View File

@ -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

View File

@ -1,105 +1,95 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 String& idToUse, const String& nameToUse,
bool def, const String& labelToUse,
std::function<String (bool, int)> stringFromBool,
std::function<bool (const String&)> boolFromString)
: RangedAudioParameter (idToUse, nameToUse, labelToUse),
value (def ? 1.0f : 0.0f),
defaultValue (value),
stringFromBoolFunction (stringFromBool),
boolFromStringFunction (boolFromString)
{
if (stringFromBoolFunction == nullptr)
stringFromBoolFunction = [] (bool v, int) { return v ? TRANS("On") : TRANS("Off"); };
if (boolFromStringFunction == nullptr)
{
StringArray onStrings;
onStrings.add (TRANS("on"));
onStrings.add (TRANS("yes"));
onStrings.add (TRANS("true"));
StringArray offStrings;
offStrings.add (TRANS("off"));
offStrings.add (TRANS("no"));
offStrings.add (TRANS("false"));
boolFromStringFunction = [onStrings, offStrings] (const String& text)
{
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 defaultValue; }
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
/*
==============================================================================
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

View File

@ -1,98 +1,138 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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
{
/**
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.
@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.
*/
AudioParameterBool (const String& parameterID, const String& parameterName, bool defaultValue,
const String& parameterLabel = String(),
std::function<String (bool value, int maximumStringLength)> stringFromBool = nullptr,
std::function<bool (const String& text)> boolFromString = nullptr);
/** 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 defaultValue;
std::function<String (bool, int)> stringFromBoolFunction;
std::function<bool (const String&)> boolFromStringFunction;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterBool)
};
} // namespace juce
/*
==============================================================================
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()
*/
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

View File

@ -1,136 +1,136 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 String& idToUse, const String& nameToUse,
const StringArray& c, int def, const String& labelToUse,
std::function<String (int, int)> stringFromIndex,
std::function<int (const String&)> indexFromString)
: RangedAudioParameter (idToUse, nameToUse, labelToUse), 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 (stringFromIndex),
indexFromStringFunction (indexFromString)
{
jassert (choices.size() > 1); // you must supply an actual set of items to choose from!
if (stringFromIndexFunction == nullptr)
stringFromIndexFunction = [this] (int index, int) { return choices [index]; };
if (indexFromStringFunction == nullptr)
indexFromStringFunction = [this] (const String& text) { return choices.indexOf (text); };
}
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 : 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
/*
==============================================================================
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 : 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

View File

@ -1,110 +1,151 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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
{
/**
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.
@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 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.
*/
AudioParameterChoice (const String& parameterID, const String& parameterName,
const StringArray& choices,
int defaultItemIndex,
const String& parameterLabel = String(),
std::function<String (int index, int maximumStringLength)> stringFromIndex = nullptr,
std::function<int (const String& text)> indexFromString = nullptr);
/** 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
/*
==============================================================================
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()
*/
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

View File

@ -1,102 +1,104 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 String& idToUse, const String& nameToUse,
NormalisableRange<float> r, float def,
const String& labelToUse, Category categoryToUse,
std::function<String (float, int)> stringFromValue,
std::function<float (const String&)> valueFromString)
: RangedAudioParameter (idToUse, nameToUse, labelToUse, categoryToUse),
range (r), value (def), defaultValue (def),
stringFromValueFunction (stringFromValue),
valueFromStringFunction (valueFromString)
{
if (stringFromValueFunction == nullptr)
{
auto numDecimalPlacesToDisplay = [this]
{
int numDecimalPlaces = 7;
if (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 (String pid, 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 (defaultValue); }
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 (value != newValue)
setValueNotifyingHost (convertTo0to1 (newValue));
return *this;
}
} // namespace juce
/*
==============================================================================
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 (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 (value != newValue)
setValueNotifyingHost (convertTo0to1 (newValue));
return *this;
}
} // namespace juce

View File

@ -1,116 +1,158 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 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.
@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.
*/
AudioParameterFloat (const String& parameterID,
const String& parameterName,
NormalisableRange<float> normalisableRange,
float defaultValue,
const String& parameterLabel = String(),
Category parameterCategory = AudioProcessorParameter::genericParameter,
std::function<String (float value, int maximumStringLength)> stringFromValue = nullptr,
std::function<float (const String& text)> valueFromString = nullptr);
/** 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 (String parameterID,
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 defaultValue;
std::function<String (float, int)> stringFromValueFunction;
std::function<float (const String&)> valueFromStringFunction;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterFloat)
};
} // namespace juce
/*
==============================================================================
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()
*/
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

View File

@ -1,141 +1,137 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 String& idToUse, const String& nameToUse,
int minValue, int maxValue, int def,
const String& labelToUse,
std::function<String (int, int)> stringFromInt,
std::function<int (const String&)> intFromString)
: RangedAudioParameter (idToUse, nameToUse, labelToUse),
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 (stringFromInt),
intFromStringFunction (intFromString)
{
jassert (minValue < maxValue); // must have a non-zero range of values!
if (stringFromIntFunction == nullptr)
stringFromIntFunction = [] (int v, int) { return String (v); };
if (intFromStringFunction == nullptr)
intFromStringFunction = [] (const String& text) { return text.getIntValue(); };
}
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 : 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
/*
==============================================================================
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 : 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

View File

@ -1,106 +1,152 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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
{
/**
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.
@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 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.
*/
AudioParameterInt (const String& parameterID, const String& parameterName,
int minValue, int maxValue,
int defaultValue,
const String& parameterLabel = String(),
std::function<String (int value, int maximumStringLength)> stringFromInt = nullptr,
std::function<int (const String& text)> intFromString = nullptr);
/** 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
/*
==============================================================================
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()
*/
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

View File

@ -1,40 +1,47 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 String& idToUse,
const String& nameToUse,
const String& labelToUse,
AudioProcessorParameter::Category categoryToUse)
: paramID (idToUse), name (nameToUse), label (labelToUse), category (categoryToUse) {}
AudioProcessorParameterWithID::~AudioProcessorParameterWithID() {}
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
/*
==============================================================================
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

View File

@ -1,70 +1,187 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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
{
/**
This abstract base class is used by some AudioProcessorParameter helper classes.
@see AudioParameterFloat, AudioParameterInt, AudioParameterBool, AudioParameterChoice
@tags{Audio}
*/
class JUCE_API AudioProcessorParameterWithID : public AudioProcessorParameter
{
public:
/** The creation of this object requires providing a name and ID which will be
constant for its lifetime.
*/
AudioProcessorParameterWithID (const String& parameterID,
const String& parameterName,
const String& parameterLabel = {},
Category parameterCategory = AudioProcessorParameter::genericParameter);
/** Destructor. */
~AudioProcessorParameterWithID() override;
/** 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;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameterWithID)
};
} // namespace juce
/*
==============================================================================
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.
*/
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.
*/
class AudioProcessorParameterWithIDAttributes
{
using This = AudioProcessorParameterWithIDAttributes;
public:
using Category = AudioProcessorParameter::Category;
/** An optional label for the parameter's value */
JUCE_NODISCARD auto withLabel (String x) const { return withMember (*this, &This::label, std::move (x)); }
/** The semantics of this parameter */
JUCE_NODISCARD auto withCategory (Category x) const { return withMember (*this, &This::category, std::move (x)); }
/** @see AudioProcessorParameter::isMetaParameter() */
JUCE_NODISCARD auto withMeta (bool x) const { return withMember (*this, &This::meta, std::move (x)); }
/** @see AudioProcessorParameter::isAutomatable() */
JUCE_NODISCARD auto withAutomatable (bool x) const { return withMember (*this, &This::automatable, std::move (x)); }
/** @see AudioProcessorParameter::isOrientationInverted() */
JUCE_NODISCARD auto withInverted (bool x) const { return withMember (*this, &This::inverted, std::move (x)); }
/** An optional label for the parameter's value */
JUCE_NODISCARD auto getLabel() const { return label; }
/** The semantics of this parameter */
JUCE_NODISCARD auto getCategory() const { return category; }
/** @see AudioProcessorParameter::isMetaParameter() */
JUCE_NODISCARD auto getMeta() const { return meta; }
/** @see AudioProcessorParameter::isAutomatable() */
JUCE_NODISCARD auto getAutomatable() const { return automatable; }
/** @see AudioProcessorParameter::isOrientationInverted() */
JUCE_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

View File

@ -1,88 +1,149 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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
{
//==============================================================================
/** 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 void* 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 void* 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 void* getAEffectPtr() const noexcept = 0;
};
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&) {}
};
} // namespace juce
/*
==============================================================================
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
{
namespace Vst
{
class IComponent;
}
} // namespace Steinberg
#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

View File

@ -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(); }
void setValue (size_t index, float value)
{
jassert (index < size());
values[index].store (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)
{
setValue (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

View File

@ -0,0 +1,66 @@
/*
==============================================================================
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
{
static void removeScaleFactorListenerFromAllPeers (ComponentPeer::ScaleFactorListener& listener)
{
for (int i = 0; i < ComponentPeer::getNumPeers(); ++i)
ComponentPeer::getPeer (i)->removeScaleFactorListener (&listener);
}
NativeScaleFactorNotifier::NativeScaleFactorNotifier (Component* comp, std::function<void (float)> onScaleChanged)
: ComponentMovementWatcher (comp),
scaleChanged (std::move (onScaleChanged))
{
componentPeerChanged();
}
NativeScaleFactorNotifier::~NativeScaleFactorNotifier()
{
removeScaleFactorListenerFromAllPeers (*this);
}
void NativeScaleFactorNotifier::nativeScaleFactorChanged (double newScaleFactor)
{
NullCheckedInvocation::invoke (scaleChanged, (float) newScaleFactor);
}
void NativeScaleFactorNotifier::componentPeerChanged()
{
removeScaleFactorListenerFromAllPeers (*this);
if (auto* x = getComponent())
peer = x->getPeer();
if (auto* x = peer)
{
x->addScaleFactorListener (this);
nativeScaleFactorChanged (x->getPlatformScaleFactor());
}
}
} // namespace juce

View File

@ -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.
==============================================================================
*/
namespace juce
{
/**
Calls a function every time the native scale factor of a component's peer changes.
This is used in the VST and VST3 wrappers to ensure that the editor's scale is kept in sync with
the scale of its containing component.
*/
class NativeScaleFactorNotifier : private ComponentMovementWatcher,
private ComponentPeer::ScaleFactorListener
{
public:
/** Constructs an instance.
While the instance is alive, it will listen for changes to the scale factor of the
comp's peer, and will call onScaleChanged whenever this scale factor changes.
@param comp The component to observe
@param onScaleChanged A function that will be called when the backing scale factor changes
*/
NativeScaleFactorNotifier (Component* comp, std::function<void (float)> onScaleChanged);
~NativeScaleFactorNotifier() override;
private:
void nativeScaleFactorChanged (double newScaleFactor) override;
void componentPeerChanged() override;
using ComponentMovementWatcher::componentVisibilityChanged;
void componentVisibilityChanged() override {}
using ComponentMovementWatcher::componentMovedOrResized;
void componentMovedOrResized (bool, bool) override {}
ComponentPeer* peer = nullptr;
std::function<void (float)> scaleChanged;
JUCE_DECLARE_NON_COPYABLE (NativeScaleFactorNotifier)
JUCE_DECLARE_NON_MOVEABLE (NativeScaleFactorNotifier)
};
} // namespace juce

View File

@ -1,271 +1,269 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 (parameter.getValue() != newValue)
callback (newValue);
}
void ParameterAttachment::parameterValueChanged (int, float newValue)
{
lastValue = newValue;
if (MessageManager::getInstance()->isThisTheMessageThread())
{
cancelPendingUpdate();
handleAsyncUpdate();
}
else
{
triggerAsyncUpdate();
}
}
void ParameterAttachment::handleAsyncUpdate()
{
if (setValue != nullptr)
setValue (parameter.convertFrom0to1 (lastValue));
}
//==============================================================================
SliderParameterAttachment::SliderParameterAttachment (RangedAudioParameter& param,
Slider& s,
UndoManager* um)
: slider (s),
attachment (param, [this] (float f) { setValue (f); }, um)
{
slider.valueFromTextFunction = [&param] (const String& text) { return (double) param.convertFrom0to1 (param.getValueForText (text)); };
slider.textFromValueFunction = [&param] (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 || ModifierKeys::currentModifiers.isRightButtonDown())
return;
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
/*
==============================================================================
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 (parameter.getValue() != newValue)
callback (newValue);
}
void ParameterAttachment::parameterValueChanged (int, float newValue)
{
lastValue = newValue;
if (MessageManager::getInstance()->isThisTheMessageThread())
{
cancelPendingUpdate();
handleAsyncUpdate();
}
else
{
triggerAsyncUpdate();
}
}
void ParameterAttachment::handleAsyncUpdate()
{
if (setValue != nullptr)
setValue (parameter.convertFrom0to1 (lastValue));
}
//==============================================================================
SliderParameterAttachment::SliderParameterAttachment (RangedAudioParameter& param,
Slider& s,
UndoManager* um)
: slider (s),
attachment (param, [this] (float f) { setValue (f); }, um)
{
slider.valueFromTextFunction = [&param] (const String& text) { return (double) param.convertFrom0to1 (param.getValueForText (text)); };
slider.textFromValueFunction = [&param] (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

View File

@ -1,251 +1,251 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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
/*
==============================================================================
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

View File

@ -1,315 +1,315 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 (AudioProcessor& processor)
{
#if JucePlugin_Build_AAX
if (PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_AAX
&& jucePlugInIsRunningInAudioSuiteFn != nullptr)
{
return jucePlugInIsRunningInAudioSuiteFn (processor);
}
#endif
ignoreUnused (processor);
return false;
}
Image PluginHostType::getHostIcon (int size) const
{
ignoreUnused (size);
#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 AppleLogic: return "Apple Logic";
case AppleMainStage: return "Apple MainStage";
case Ardour: return "Ardour";
case AULab: return "AU Lab";
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 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 ("Vienna Ensemble Pro")) return ViennaEnsemblePro;
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.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
/*
==============================================================================
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 (AudioProcessor& processor)
{
#if JucePlugin_Build_AAX
if (PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_AAX
&& jucePlugInIsRunningInAudioSuiteFn != nullptr)
{
return jucePlugInIsRunningInAudioSuiteFn (processor);
}
#endif
ignoreUnused (processor);
return false;
}
Image PluginHostType::getHostIcon (int size) const
{
ignoreUnused (size);
#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 AppleLogic: return "Apple Logic";
case AppleMainStage: return "Apple MainStage";
case Ardour: return "Ardour";
case AULab: return "AU Lab";
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 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 ("Vienna Ensemble Pro")) return ViennaEnsemblePro;
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.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

View File

@ -1,247 +1,247 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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. */
AppleLogic, /**< Represents Apple Logic Pro. */
AppleMainStage, /**< Represents Apple Main Stage. */
Ardour, /**< Represents Ardour. */
AULab, /**< Represents AU Lab. */
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. */
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 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 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 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
/*
==============================================================================
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. */
AppleLogic, /**< Represents Apple Logic Pro. */
AppleMainStage, /**< Represents Apple Main Stage. */
Ardour, /**< Represents Ardour. */
AULab, /**< Represents AU Lab. */
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. */
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 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 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 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

View File

@ -1,59 +1,51 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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
{
RangedAudioParameter::RangedAudioParameter (const String& parameterID,
const String& parameterName,
const String& parameterLabel,
Category parameterCategory)
: AudioProcessorParameterWithID (parameterID, parameterName, parameterLabel, parameterCategory)
{
}
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
/*
==============================================================================
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

View File

@ -1,63 +1,118 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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
{
/**
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:
/** The creation of this object requires providing a name and ID which will be
constant for its lifetime.
*/
RangedAudioParameter (const String& parameterID,
const String& parameterName,
const String& parameterLabel = {},
Category parameterCategory = AudioProcessorParameter::genericParameter);
/** 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
/*
==============================================================================
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.
*/
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. */
JUCE_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. */
JUCE_NODISCARD auto withValueFromStringFunction (ValueFromString x) const { return withMember (asDerived(), &Derived::valueFromString, std::move (x)); }
/** See AudioProcessorParameterWithIDAttributes::withLabel() */
JUCE_NODISCARD auto withLabel (String x) const { return withMember (asDerived(), &Derived::attributes, attributes.withLabel (std::move (x))); }
/** See AudioProcessorParameterWithIDAttributes::withCategory() */
JUCE_NODISCARD auto withCategory (Category x) const { return withMember (asDerived(), &Derived::attributes, attributes.withCategory (std::move (x))); }
/** See AudioProcessorParameter::isMetaParameter() */
JUCE_NODISCARD auto withMeta (bool x) const { return withMember (asDerived(), &Derived::attributes, attributes.withMeta (std::move (x))); }
/** See AudioProcessorParameter::isAutomatable() */
JUCE_NODISCARD auto withAutomatable (bool x) const { return withMember (asDerived(), &Derived::attributes, attributes.withAutomatable (std::move (x))); }
/** See AudioProcessorParameter::isOrientationInverted() */
JUCE_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. */
JUCE_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. */
JUCE_NODISCARD const auto& getValueFromStringFunction() const { return valueFromString; }
/** Gets attributes that would also apply to an AudioProcessorParameterWithID */
JUCE_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

View File

@ -1,95 +1,99 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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.
==============================================================================
*/
// Forward declaration to avoid leaking implementation details.
namespace Steinberg
{
class FUnknown;
using TUID = char[16];
}
namespace juce
{
/** An interface to allow an AudioProcessor to implement extended VST3-specific
functionality.
To use this class, ensure that your AudioProcessor publicly inherits
from VST3ClientExtensions.
@see VSTCallbackHandler
@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; }
};
} // namespace juce
/*
==============================================================================
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, ensure that your AudioProcessor publicly inherits
from VST3ClientExtensions.
@see VSTCallbackHandler
@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; }
};
} // namespace juce

View File

@ -1,80 +1,80 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - 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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-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 send and receive VST specific calls from
the host.
To use this class, ensure that your AudioProcessor publicly inherits
from VSTCallbackHandler.
@see VST3ClientExtensions
@tags{Audio}
*/
struct VSTCallbackHandler
{
virtual ~VSTCallbackHandler() = 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)
{
ignoreUnused (index, value, ptr, opt);
return 0;
}
/** 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;
// Note: VS2013 prevents a "using" declaration here
/** The host callback function type. */
typedef pointer_sized_int (VstHostCallbackType) (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)
{
ignoreUnused (callback);
}
};
} // namespace juce
/*
==============================================================================
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 send and receive VST specific calls from
the host.
To use this class, ensure that your AudioProcessor publicly inherits
from VSTCallbackHandler.
@see VST3ClientExtensions
@tags{Audio}
*/
struct VSTCallbackHandler
{
virtual ~VSTCallbackHandler() = 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)
{
ignoreUnused (index, value, ptr, opt);
return 0;
}
/** 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;
// Note: VS2013 prevents a "using" declaration here
/** The host callback function type. */
typedef pointer_sized_int (VstHostCallbackType) (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)
{
ignoreUnused (callback);
}
};
} // namespace juce