mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
ARA Client: Add ARA interface extensions to AU and VST3 wrappers
This commit is contained in:
parent
9ae96e98ca
commit
5f4da905d7
8 changed files with 348 additions and 1 deletions
61
modules/juce_audio_plugin_client/ARA/juce_ARA_Wrapper.cpp
Normal file
61
modules/juce_audio_plugin_client/ARA/juce_ARA_Wrapper.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE 7 technical preview.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
You may use this code under the terms of the GPL v3
|
||||
(see www.gnu.org/licenses).
|
||||
|
||||
For the technical preview this file cannot be licensed commercially.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
#include "../utility/juce_CheckSettingMacros.h"
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
|
||||
#include "../utility/juce_IncludeSystemHeaders.h"
|
||||
#include "../utility/juce_IncludeModuleHeaders.h"
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunused-parameter", "-Wgnu-zero-variadic-macro-arguments", "-Wmissing-prototypes")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4100)
|
||||
|
||||
#include <ARA_Library/PlugIn/ARAPlug.cpp>
|
||||
#include <ARA_Library/Dispatch/ARAPlugInDispatch.cpp>
|
||||
#include <ARA_Library/Utilities/ARAPitchInterpretation.cpp>
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if (JUCE_DEBUG && ! JUCE_DISABLE_ASSERTIONS) || JUCE_LOG_ASSERTIONS
|
||||
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
|
||||
|
||||
ARA_SETUP_DEBUG_MESSAGE_PREFIX(JucePlugin_Name);
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#endif
|
||||
48
modules/juce_audio_plugin_client/ARA/juce_ARA_Wrapper.h
Normal file
48
modules/juce_audio_plugin_client/ARA/juce_ARA_Wrapper.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE 7 technical preview.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
You may use this code under the terms of the GPL v3
|
||||
(see www.gnu.org/licenses).
|
||||
|
||||
For the technical preview this file cannot be licensed commercially.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
// Configure ARA debug support prior to including ARA SDK headers
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if (JUCE_DEBUG && ! JUCE_DISABLE_ASSERTIONS) || JUCE_LOG_ASSERTIONS
|
||||
|
||||
#define ARA_ENABLE_INTERNAL_ASSERTS 1
|
||||
|
||||
extern 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
|
||||
|
||||
#else
|
||||
|
||||
#define ARA_ENABLE_INTERNAL_ASSERTS 0
|
||||
|
||||
#endif // (JUCE_DEBUG && ! JUCE_DISABLE_ASSERTIONS) || JUCE_LOG_ASSERTIONS
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#endif
|
||||
|
|
@ -58,6 +58,14 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
|||
#include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp>
|
||||
#include <juce_audio_processors/format_types/juce_AU_Shared.h>
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
#include <juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h>
|
||||
#include <ARA_API/ARAAudioUnit.h>
|
||||
#if ARA_SUPPORT_VERSION_1
|
||||
#error "Unsupported ARA version - only ARA version 2 and onward are supported by the current JUCE ARA implementation"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
using namespace juce;
|
||||
|
||||
|
|
@ -425,6 +433,17 @@ public:
|
|||
outWritable = false;
|
||||
return noErr;
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
case ARA::kAudioUnitProperty_ARAFactory:
|
||||
outWritable = false;
|
||||
outDataSize = sizeof (ARA::ARAAudioUnitFactory);
|
||||
return noErr;
|
||||
case ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles:
|
||||
outWritable = false;
|
||||
outDataSize = sizeof (ARA::ARAAudioUnitPlugInExtensionBinding);
|
||||
return noErr;
|
||||
#endif
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
|
@ -466,6 +485,33 @@ public:
|
|||
jassertfalse;
|
||||
break;
|
||||
|
||||
//==============================================================================
|
||||
#if JucePlugin_Enable_ARA
|
||||
case ARA::kAudioUnitProperty_ARAFactory:
|
||||
{
|
||||
auto auFactory = static_cast<ARA::ARAAudioUnitFactory*> (outData);
|
||||
if (auFactory->inOutMagicNumber != ARA::kARAAudioUnitMagic)
|
||||
return kAudioUnitErr_InvalidProperty; // if the magic value isn't found, the property ID is re-used outside the ARA context with different, unsupported sematics
|
||||
|
||||
auFactory->outFactory = createARAFactory();
|
||||
return noErr;
|
||||
}
|
||||
|
||||
case ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles:
|
||||
{
|
||||
auto binding = static_cast<ARA::ARAAudioUnitPlugInExtensionBinding*> (outData);
|
||||
if (binding->inOutMagicNumber != ARA::kARAAudioUnitMagic)
|
||||
return kAudioUnitErr_InvalidProperty; // if the magic value isn't found, the property ID is re-used outside the ARA context with different, unsupported sematics
|
||||
|
||||
AudioProcessorARAExtension* araAudioProcessorExtension = dynamic_cast<AudioProcessorARAExtension*> (juceFilter.get());
|
||||
binding->outPlugInExtension = araAudioProcessorExtension->bindToARA (binding->inDocumentControllerRef, binding->knownRoles, binding->assignedRoles);
|
||||
if (binding->outPlugInExtension == nullptr)
|
||||
return kAudioUnitErr_CannotDoInCurrentContext; // bindToARA() returns null if binding is already established
|
||||
|
||||
return noErr;
|
||||
}
|
||||
#endif
|
||||
|
||||
case juceFilterObjectPropertyID:
|
||||
((void**) outData)[0] = (void*) static_cast<AudioProcessor*> (juceFilter.get());
|
||||
((void**) outData)[1] = (void*) this;
|
||||
|
|
@ -1030,6 +1076,9 @@ public:
|
|||
{
|
||||
const double rate = getSampleRate();
|
||||
jassert (rate > 0);
|
||||
#if JucePlugin_Enable_ARA
|
||||
jassert (juceFilter->getLatencySamples() == 0 || ! dynamic_cast<AudioProcessorARAExtension*> (juceFilter.get())->isBoundToARA());
|
||||
#endif
|
||||
return rate > 0 ? juceFilter->getLatencySamples() / rate : 0;
|
||||
}
|
||||
|
||||
|
|
@ -1698,7 +1747,14 @@ public:
|
|||
{
|
||||
if (AudioProcessor* filter = static_cast<AudioProcessor*> (pointers[0]))
|
||||
if (AudioProcessorEditor* editorComp = filter->createEditorIfNeeded())
|
||||
{
|
||||
#if JucePlugin_Enable_ARA
|
||||
jassert (dynamic_cast<AudioProcessorEditorARAExtension*> (editorComp) != nullptr);
|
||||
// for proper view embedding, ARA plug-ins must be resizable
|
||||
jassert (editorComp->isResizable());
|
||||
#endif
|
||||
return EditorCompHolder::createViewFor (filter, static_cast<JuceAU*> (pointers[1]), editorComp);
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,21 @@ JUCE_BEGIN_NO_SANITIZE ("vptr")
|
|||
#include <juce_core/native/juce_mac_CFHelpers.h>
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JucePlugin_Enable_ARA
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE("-Wpragma-pack")
|
||||
#include <ARA_API/ARAVST3.h>
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#if ARA_SUPPORT_VERSION_1
|
||||
#error "Unsupported ARA version - only ARA version 2 and onward are supported by the current implementation"
|
||||
#endif
|
||||
|
||||
DEF_CLASS_IID(ARA::IPlugInEntryPoint)
|
||||
DEF_CLASS_IID(ARA::IPlugInEntryPoint2)
|
||||
DEF_CLASS_IID(ARA::IMainFactory)
|
||||
#endif
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
|
|
@ -644,6 +659,9 @@ class JuceVST3EditController : public Vst::EditController,
|
|||
public Vst::IMidiMapping,
|
||||
public Vst::IUnitInfo,
|
||||
public Vst::ChannelContext::IInfoListener,
|
||||
#if JucePlugin_Enable_ARA
|
||||
public Presonus::IPlugInViewEmbedding,
|
||||
#endif
|
||||
public AudioProcessorListener,
|
||||
private ComponentRestarter::Listener
|
||||
{
|
||||
|
|
@ -925,6 +943,21 @@ public:
|
|||
return kResultOk;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JucePlugin_Enable_ARA
|
||||
Steinberg::TBool PLUGIN_API isViewEmbeddingSupported() override
|
||||
{
|
||||
if (auto* pluginInstance = getPluginInstance())
|
||||
return (Steinberg::TBool) dynamic_cast<AudioProcessorARAExtension*> (pluginInstance)->isEditorView();
|
||||
return (Steinberg::TBool) false;
|
||||
}
|
||||
|
||||
Steinberg::tresult PLUGIN_API setViewIsEmbedded (Steinberg::IPlugView* /*view*/, Steinberg::TBool /*embedded*/) override
|
||||
{
|
||||
return kResultOk;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
tresult PLUGIN_API setComponentState (IBStream* stream) override
|
||||
{
|
||||
|
|
@ -1266,6 +1299,10 @@ public:
|
|||
|
||||
auto latencySamples = pluginInstance->getLatencySamples();
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
jassert (latencySamples == 0 || ! dynamic_cast<AudioProcessorARAExtension*> (pluginInstance)->isBoundToARA());
|
||||
#endif
|
||||
|
||||
if (details.latencyChanged && latencySamples != lastLatencySamples)
|
||||
{
|
||||
flags |= Vst::kLatencyChanged;
|
||||
|
|
@ -1410,6 +1447,9 @@ private:
|
|||
UniqueBase<Vst::ChannelContext::IInfoListener>{},
|
||||
SharedBase<IPluginBase, Vst::IEditController>{},
|
||||
UniqueBase<IDependent>{},
|
||||
#if JucePlugin_Enable_ARA
|
||||
UniqueBase<Presonus::IPlugInViewEmbedding>{},
|
||||
#endif
|
||||
SharedBase<FUnknown, Vst::IEditController>{});
|
||||
|
||||
if (result.isOk())
|
||||
|
|
@ -1989,6 +2029,12 @@ private:
|
|||
{
|
||||
pluginEditor.reset (plugin.createEditorIfNeeded());
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
jassert (dynamic_cast<AudioProcessorEditorARAExtension*> (pluginEditor.get()) != nullptr);
|
||||
// for proper view embedding, ARA plug-ins must be resizable
|
||||
jassert (pluginEditor->isResizable());
|
||||
#endif
|
||||
|
||||
if (pluginEditor != nullptr)
|
||||
{
|
||||
editorHostContext = std::make_unique<EditorHostContext> (*owner.owner->audioProcessor,
|
||||
|
|
@ -2231,12 +2277,61 @@ private:
|
|||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3EditController)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if JucePlugin_Enable_ARA
|
||||
class JuceARAFactory : public ARA::IMainFactory
|
||||
{
|
||||
public:
|
||||
JuceARAFactory() = default;
|
||||
virtual ~JuceARAFactory() = default;
|
||||
|
||||
JUCE_DECLARE_VST3_COM_REF_METHODS
|
||||
|
||||
tresult PLUGIN_API queryInterface (const ::Steinberg::TUID targetIID, void** obj) override
|
||||
{
|
||||
const auto result = testForMultiple (*this,
|
||||
targetIID,
|
||||
UniqueBase<ARA::IMainFactory>{},
|
||||
UniqueBase<FUnknown>{});
|
||||
|
||||
if (result.isOk())
|
||||
return result.extract (obj);
|
||||
|
||||
if (doUIDsMatch (targetIID, JuceARAFactory::iid))
|
||||
{
|
||||
addRef();
|
||||
*obj = this;
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
*obj = nullptr;
|
||||
return kNoInterface;
|
||||
}
|
||||
|
||||
//---from ARA::IMainFactory-------
|
||||
const ARA::ARAFactory* PLUGIN_API getFactory() SMTG_OVERRIDE
|
||||
{
|
||||
return createARAFactory();
|
||||
}
|
||||
static const FUID iid;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
std::atomic<int> refCount { 1 };
|
||||
};
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class JuceVST3Component : public Vst::IComponent,
|
||||
public Vst::IAudioProcessor,
|
||||
public Vst::IUnitInfo,
|
||||
public Vst::IConnectionPoint,
|
||||
public Vst::IProcessContextRequirements,
|
||||
#if JucePlugin_Enable_ARA
|
||||
public ARA::IPlugInEntryPoint,
|
||||
public ARA::IPlugInEntryPoint2,
|
||||
#endif
|
||||
public AudioPlayHead
|
||||
{
|
||||
public:
|
||||
|
|
@ -3272,6 +3367,10 @@ private:
|
|||
UniqueBase<Vst::IUnitInfo>{},
|
||||
UniqueBase<Vst::IConnectionPoint>{},
|
||||
UniqueBase<Vst::IProcessContextRequirements>{},
|
||||
#if JucePlugin_Enable_ARA
|
||||
UniqueBase<ARA::IPlugInEntryPoint>{},
|
||||
UniqueBase<ARA::IPlugInEntryPoint2>{},
|
||||
#endif
|
||||
SharedBase<FUnknown, Vst::IComponent>{});
|
||||
|
||||
if (result.isOk())
|
||||
|
|
@ -3385,6 +3484,27 @@ private:
|
|||
bufferMapper.prepare (p, bufferSize);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JucePlugin_Enable_ARA
|
||||
const ARA::ARAFactory* PLUGIN_API getFactory() SMTG_OVERRIDE
|
||||
{
|
||||
return createARAFactory();
|
||||
}
|
||||
|
||||
const ARA::ARAPlugInExtensionInstance* PLUGIN_API bindToDocumentController (ARA::ARADocumentControllerRef /*controllerRef*/) SMTG_OVERRIDE
|
||||
{
|
||||
ARA_VALIDATE_API_STATE (false && "call is deprecated in ARA 2, host must not call this");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ARA::ARAPlugInExtensionInstance* PLUGIN_API bindToDocumentControllerWithRoles (ARA::ARADocumentControllerRef documentControllerRef,
|
||||
ARA::ARAPlugInInstanceRoleFlags knownRoles, ARA::ARAPlugInInstanceRoleFlags assignedRoles) SMTG_OVERRIDE
|
||||
{
|
||||
AudioProcessorARAExtension* araAudioProcessorExtension = dynamic_cast<AudioProcessorARAExtension*> (pluginInstance);
|
||||
return araAudioProcessorExtension->bindToARA (documentControllerRef, knownRoles, assignedRoles);
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
ScopedJuceInitialiser_GUI libraryInitialiser;
|
||||
|
||||
|
|
@ -3483,6 +3603,11 @@ DEF_CLASS_IID (JuceAudioProcessor)
|
|||
DEF_CLASS_IID (JuceVST3Component)
|
||||
#endif
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
DECLARE_CLASS_IID (JuceARAFactory, 0xABCDEF01, 0xA1B2C3D4, JucePlugin_ManufacturerCode, JucePlugin_PluginCode)
|
||||
DEF_CLASS_IID (JuceARAFactory)
|
||||
#endif
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
|
|
@ -3611,6 +3736,13 @@ static FUnknown* createControllerInstance (Vst::IHostApplication* host)
|
|||
return static_cast<Vst::IEditController*> (new JuceVST3EditController (host));
|
||||
}
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
static FUnknown* createARAFactoryInstance (Vst::IHostApplication* /*host*/)
|
||||
{
|
||||
return static_cast<ARA::IMainFactory*> (new JuceARAFactory());
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
struct JucePluginFactory;
|
||||
static JucePluginFactory* globalFactory = nullptr;
|
||||
|
|
@ -3883,6 +4015,20 @@ extern "C" SMTG_EXPORT_SYMBOL IPluginFactory* PLUGIN_API GetPluginFactory()
|
|||
kVstVersionString);
|
||||
|
||||
globalFactory->registerClass (controllerClass, createControllerInstance);
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
static const PClassInfo2 araFactoryClass (JuceARAFactory::iid,
|
||||
PClassInfo::kManyInstances,
|
||||
kARAMainFactoryClass,
|
||||
JucePlugin_Name,
|
||||
JucePlugin_Vst3ComponentFlags,
|
||||
JucePlugin_Vst3Category,
|
||||
JucePlugin_Manufacturer,
|
||||
JucePlugin_VersionString,
|
||||
kVstVersionString);
|
||||
|
||||
globalFactory->registerClass (araFactoryClass, createARAFactoryInstance);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -121,3 +121,7 @@
|
|||
#endif
|
||||
|
||||
#include "utility/juce_CreatePluginFilter.h"
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
#include "ARA/juce_ARA_Wrapper.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE 7 technical preview.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
You may use this code under the terms of the GPL v3
|
||||
(see www.gnu.org/licenses).
|
||||
|
||||
For the technical preview this file cannot be licensed commercially.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "ARA/juce_ARA_Wrapper.cpp"
|
||||
|
|
@ -30,6 +30,10 @@ inline AudioProcessor* JUCE_API JUCE_CALLTYPE createPluginFilterOfType (AudioPro
|
|||
// your createPluginFilter() method must return an object!
|
||||
jassert (pluginInstance != nullptr && pluginInstance->wrapperType == type);
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
jassert (dynamic_cast<juce::AudioProcessorARAExtension*> (pluginInstance) != nullptr);
|
||||
#endif
|
||||
|
||||
return pluginInstance;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,16 @@
|
|||
#include "utilities/juce_PluginHostType.h"
|
||||
#include "utilities/ARA/juce_ARA_utils.h"
|
||||
|
||||
// This is here to avoid missing-prototype warnings in user code.
|
||||
//==============================================================================
|
||||
// These declarations are here to avoid missing-prototype warnings in user code.
|
||||
|
||||
// If you're implementing a plugin, you should supply a body for
|
||||
// this function in your own code.
|
||||
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter();
|
||||
|
||||
// If you are implementing an ARA enabled plugin, you need to
|
||||
// implement this function somewhere in the codebase by returning
|
||||
// SubclassOfARADocumentControllerSpecialisation::createARAFactory<SubclassOfARADocumentControllerSpecialisation>();
|
||||
#if JucePlugin_Enable_ARA
|
||||
const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory();
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue