Browse Source

ARA Client: Add ARA interface extensions to AU and VST3 wrappers

pull/22/head
attila 3 years ago
parent
commit
5f4da905d7
8 changed files with 348 additions and 1 deletions
  1. +61
    -0
      modules/juce_audio_plugin_client/ARA/juce_ARA_Wrapper.cpp
  2. +48
    -0
      modules/juce_audio_plugin_client/ARA/juce_ARA_Wrapper.h
  3. +56
    -0
      modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  4. +146
    -0
      modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  5. +4
    -0
      modules/juce_audio_plugin_client/juce_audio_plugin_client.h
  6. +19
    -0
      modules/juce_audio_plugin_client/juce_audio_plugin_client_ARA.cpp
  7. +4
    -0
      modules/juce_audio_plugin_client/utility/juce_CreatePluginFilter.h
  8. +10
    -1
      modules/juce_audio_processors/juce_audio_processors.h

+ 61
- 0
modules/juce_audio_plugin_client/ARA/juce_ARA_Wrapper.cpp View 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
- 0
modules/juce_audio_plugin_client/ARA/juce_ARA_Wrapper.h View 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

+ 56
- 0
modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm View File

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


+ 146
- 0
modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp View File

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


+ 4
- 0
modules/juce_audio_plugin_client/juce_audio_plugin_client.h View File

@@ -121,3 +121,7 @@
#endif
#include "utility/juce_CreatePluginFilter.h"
#if JucePlugin_Enable_ARA
#include "ARA/juce_ARA_Wrapper.h"
#endif

+ 19
- 0
modules/juce_audio_plugin_client/juce_audio_plugin_client_ARA.cpp View File

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

+ 4
- 0
modules/juce_audio_plugin_client/utility/juce_CreatePluginFilter.h View File

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


+ 10
- 1
modules/juce_audio_processors/juce_audio_processors.h View File

@@ -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…
Cancel
Save