JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_ARAHosting.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26#if (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU) && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX))
27
28#include "juce_ARAHosting.h"
29
30#include <ARA_Library/Dispatch/ARAHostDispatch.cpp>
31
32namespace juce
33{
35{
36public:
37 /* Returns true if this controller wasn't previously present. */
38 bool add (ARA::Host::DocumentController& dc)
39 {
41 return ++counts[&dc] == 1;
42 }
43
44 /* Returns true if this controller is no longer present. */
45 bool remove (ARA::Host::DocumentController& dc)
46 {
48 return --counts[&dc] == 0;
49 }
50
51private:
53 std::mutex mutex;
54};
55
57
58ARAEditGuard::ARAEditGuard (ARA::Host::DocumentController& dcIn) : dc (dcIn)
59{
60 if (editGuardState.add (dc))
61 dc.beginEditing();
62}
63
64ARAEditGuard::~ARAEditGuard()
65{
66 if (editGuardState.remove (dc))
67 dc.endEditing();
68}
69
70//==============================================================================
71namespace ARAHostModel
72{
73
74//==============================================================================
75AudioSource::AudioSource (ARA::ARAAudioSourceHostRef hostRef,
76 ARA::Host::DocumentController& dc,
77 const ARA::ARAAudioSourceProperties& props)
78 : ManagedARAHandle (dc, [&]
79 {
80 const ARAEditGuard guard (dc);
81 return dc.createAudioSource (hostRef, &props);
82 }())
83{
84}
85
86void AudioSource::update (const ARA::ARAAudioSourceProperties& props)
87{
88 const ARAEditGuard guard (getDocumentController());
89 getDocumentController().updateAudioSourceProperties (getPluginRef(), &props);
90}
91
92void AudioSource::enableAudioSourceSamplesAccess (bool x)
93{
94 const ARAEditGuard guard (getDocumentController());
95 getDocumentController().enableAudioSourceSamplesAccess (getPluginRef(), x);
96}
97
98void AudioSource::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
99{
100 dc.destroyAudioSource (ptr);
101}
102
103//==============================================================================
104AudioModification::AudioModification (ARA::ARAAudioModificationHostRef hostRef,
105 ARA::Host::DocumentController& dc,
106 AudioSource& s,
107 const ARA::ARAAudioModificationProperties& props)
108 : ManagedARAHandle (dc, [&]
109 {
110 const ARAEditGuard guard (dc);
111 return dc.createAudioModification (s.getPluginRef(), hostRef, &props);
112 }()),
113 source (s)
114{
115}
116
117void AudioModification::update (const ARA::ARAAudioModificationProperties& props)
118{
119 const ARAEditGuard guard (getDocumentController());
120 getDocumentController().updateAudioModificationProperties (getPluginRef(), &props);
121}
122
123void AudioModification::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
124{
125 dc.destroyAudioModification (ptr);
126}
127
128//==============================================================================
129class PlaybackRegion::Impl : public ManagedARAHandle<Impl, ARA::ARAPlaybackRegionRef>,
130 public DeletionListener
131{
132public:
133 Impl (ARA::ARAPlaybackRegionHostRef hostRef,
134 ARA::Host::DocumentController& dc,
135 AudioModification& m,
136 const ARA::ARAPlaybackRegionProperties& props);
137
138 ~Impl() override
139 {
140 for (const auto& l : listeners)
141 l->removeListener (*this);
142 }
143
144 /* Updates the state of the corresponding %ARA model object.
145
146 Places the DocumentController in editable state.
147
148 You can use getEmptyProperties() to acquire a properties struct where the `structSize`
149 field has already been correctly set.
150 */
151 void update (const ARA::ARAPlaybackRegionProperties& props);
152
153 auto& getAudioModification() const { return modification; }
154
155 static void destroy (ARA::Host::DocumentController&, Ptr);
156
157 void addListener (DeletionListener& l) { listeners.insert (&l); }
158 void removeListener (DeletionListener& l) noexcept override { listeners.erase (&l); }
159
160private:
161 AudioModification* modification = nullptr;
163};
164
165PlaybackRegion::Impl::Impl (ARA::ARAPlaybackRegionHostRef hostRef,
166 ARA::Host::DocumentController& dc,
167 AudioModification& m,
168 const ARA::ARAPlaybackRegionProperties& props)
169 : ManagedARAHandle (dc, [&]
170 {
171 const ARAEditGuard guard (dc);
172 return dc.createPlaybackRegion (m.getPluginRef(), hostRef, &props);
173 }()),
174 modification (&m)
175{
176}
177
178PlaybackRegion::~PlaybackRegion() = default;
179
180void PlaybackRegion::Impl::update (const ARA::ARAPlaybackRegionProperties& props)
181{
182 const ARAEditGuard guard (getDocumentController());
183 getDocumentController().updatePlaybackRegionProperties (getPluginRef(), &props);
184}
185
186void PlaybackRegion::Impl::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
187{
188 dc.destroyPlaybackRegion (ptr);
189}
190
191PlaybackRegion::PlaybackRegion (ARA::ARAPlaybackRegionHostRef hostRef,
192 ARA::Host::DocumentController& dc,
193 AudioModification& m,
194 const ARA::ARAPlaybackRegionProperties& props)
195 : impl (std::make_unique<Impl> (hostRef, dc, m, props))
196{
197}
198
199void PlaybackRegion::update (const ARA::ARAPlaybackRegionProperties& props) { impl->update (props); }
200
201void PlaybackRegion::addListener (DeletionListener& x) { impl->addListener (x); }
202
203auto& PlaybackRegion::getAudioModification() const { return impl->getAudioModification(); }
204
205ARA::ARAPlaybackRegionRef PlaybackRegion::getPluginRef() const noexcept { return impl->getPluginRef(); }
206
207DeletionListener& PlaybackRegion::getDeletionListener() const noexcept { return *impl.get(); }
208
209//==============================================================================
210MusicalContext::MusicalContext (ARA::ARAMusicalContextHostRef hostRef,
211 ARA::Host::DocumentController& dc,
212 const ARA::ARAMusicalContextProperties& props)
213 : ManagedARAHandle (dc, [&]
214 {
215 const ARAEditGuard guard (dc);
216 return dc.createMusicalContext (hostRef, &props);
217 }())
218{
219}
220
221void MusicalContext::update (const ARA::ARAMusicalContextProperties& props)
222{
223 const ARAEditGuard guard (getDocumentController());
224 return getDocumentController().updateMusicalContextProperties (getPluginRef(), &props);
225}
226
227void MusicalContext::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
228{
229 dc.destroyMusicalContext (ptr);
230}
231
232//==============================================================================
233RegionSequence::RegionSequence (ARA::ARARegionSequenceHostRef hostRef,
234 ARA::Host::DocumentController& dc,
235 const ARA::ARARegionSequenceProperties& props)
236 : ManagedARAHandle (dc, [&]
237 {
238 const ARAEditGuard guard (dc);
239 return dc.createRegionSequence (hostRef, &props);
240 }())
241{
242}
243
244void RegionSequence::update (const ARA::ARARegionSequenceProperties& props)
245{
246 const ARAEditGuard guard (getDocumentController());
247 return getDocumentController().updateRegionSequenceProperties (getPluginRef(), &props);
248}
249
250void RegionSequence::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
251{
252 dc.destroyRegionSequence (ptr);
253}
254
255//==============================================================================
256PlaybackRendererInterface PlugInExtensionInstance::getPlaybackRendererInterface() const
257{
258 if (instance != nullptr)
259 return PlaybackRendererInterface (instance->playbackRendererRef, instance->playbackRendererInterface);
260
261 return {};
262}
263
264EditorRendererInterface PlugInExtensionInstance::getEditorRendererInterface() const
265{
266 if (instance != nullptr)
267 return EditorRendererInterface (instance->editorRendererRef, instance->editorRendererInterface);
268
269 return {};
270}
271
272} // namespace ARAHostModel
273
274//==============================================================================
275class ARAHostDocumentController::Impl
276{
277public:
278 Impl (ARAFactoryWrapper araFactoryIn,
280 const ARA::ARADocumentControllerInstance* documentControllerInstance,
286 : araFactory (std::move (araFactoryIn)),
287 audioAccessController (std::move (audioAccessControllerIn)),
288 archivingController (std::move (archivingControllerIn)),
289 contentAccessController (std::move (contentAccessControllerIn)),
290 modelUpdateController (std::move (modelUpdateControllerIn)),
291 playbackController (std::move (playbackControllerIn)),
292 dcHostInstance (std::move (dcHostInstanceIn)),
293 documentController (documentControllerInstance)
294 {
295 }
296
297 ~Impl()
298 {
299 documentController.destroyDocumentController();
300 }
301
303 createImpl (ARAFactoryWrapper araFactory,
304 const String& documentName,
310 {
312 std::make_unique<ARA::Host::DocumentControllerHostInstance> (audioAccessController.get(),
313 archivingController.get(),
314 contentAccessController.get(),
315 modelUpdateController.get(),
316 playbackController.get());
317
318 const auto documentProperties = makeARASizedStruct (&ARA::ARADocumentProperties::name, documentName.toRawUTF8());
319
320 if (auto* dci = araFactory.get()->createDocumentControllerWithDocument (dcHostInstance.get(), &documentProperties))
321 return std::make_unique<Impl> (std::move (araFactory),
322 std::move (dcHostInstance),
323 dci,
324 std::move (audioAccessController),
325 std::move (archivingController),
326 std::move (contentAccessController),
327 std::move (modelUpdateController),
328 std::move (playbackController));
329
330 return {};
331 }
332
333 ARAHostModel::PlugInExtensionInstance bindDocumentToPluginInstance (AudioPluginInstance& instance,
334 ARA::ARAPlugInInstanceRoleFlags knownRoles,
335 ARA::ARAPlugInInstanceRoleFlags assignedRoles)
336 {
337
338 const auto makeVisitor = [] (auto vst3Fn, auto auFn)
339 {
340 using Vst3Fn = decltype (vst3Fn);
341 using AuFn = decltype (auFn);
342
343 struct Visitor final : public ExtensionsVisitor, Vst3Fn, AuFn
344 {
345 explicit Visitor (Vst3Fn vst3Fn, AuFn auFn) : Vst3Fn (std::move (vst3Fn)), AuFn (std::move (auFn)) {}
346 void visitVST3Client (const VST3Client& x) override { Vst3Fn::operator() (x); }
347 void visitAudioUnitClient (const AudioUnitClient& x) override { AuFn::operator() (x); }
348 };
349
350 return Visitor { std::move (vst3Fn), std::move (auFn) };
351 };
352
353 const ARA::ARAPlugInExtensionInstance* pei = nullptr;
354 auto visitor = makeVisitor ([this, &pei, knownRoles, assignedRoles] (const ExtensionsVisitor::VST3Client& vst3Client)
355 {
356 auto* iComponentPtr = vst3Client.getIComponentPtr();
357 VSTComSmartPtr<ARA::IPlugInEntryPoint2> araEntryPoint;
358
359 if (araEntryPoint.loadFrom (iComponentPtr))
360 pei = araEntryPoint->bindToDocumentControllerWithRoles (documentController.getRef(), knownRoles, assignedRoles);
361 },
362 #if JUCE_PLUGINHOST_AU && JUCE_MAC
363 [this, &pei, knownRoles, assignedRoles] (const ExtensionsVisitor::AudioUnitClient& auClient)
364 {
365 auto audioUnit = auClient.getAudioUnitHandle();
366 auto propertySize = (UInt32) sizeof (ARA::ARAAudioUnitPlugInExtensionBinding);
367 const auto expectedPropertySize = propertySize;
368 ARA::ARAAudioUnitPlugInExtensionBinding audioUnitBinding { ARA::kARAAudioUnitMagic,
369 documentController.getRef(),
370 nullptr,
371 knownRoles,
372 assignedRoles };
373
374 auto status = AudioUnitGetProperty (audioUnit,
375 ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles,
376 kAudioUnitScope_Global,
377 0,
378 &audioUnitBinding,
379 &propertySize);
380
381 if (status == noErr
382 && propertySize == expectedPropertySize
383 && audioUnitBinding.inOutMagicNumber == ARA::kARAAudioUnitMagic
384 && audioUnitBinding.inDocumentControllerRef == documentController.getRef()
385 && audioUnitBinding.outPlugInExtension != nullptr)
386 {
387 pei = audioUnitBinding.outPlugInExtension;
388 }
389 else
391 }
392 #else
393 [] (const auto&) {}
394 #endif
395 );
396
397 instance.getExtensions (visitor);
398 return ARAHostModel::PlugInExtensionInstance { pei };
399 }
400
401 auto& getDocumentController() { return documentController; }
402
403private:
404 ARAFactoryWrapper araFactory;
405
411
413 ARA::Host::DocumentController documentController;
414};
415
416ARAHostDocumentController::ARAHostDocumentController (std::unique_ptr<Impl>&& implIn)
417 : impl { std::move (implIn) }
418{}
419
420std::unique_ptr<ARAHostDocumentController> ARAHostDocumentController::create (ARAFactoryWrapper factory,
421 const String& documentName,
427{
428 if (auto impl = Impl::createImpl (std::move (factory),
429 documentName,
430 std::move (audioAccessController),
431 std::move (archivingController),
432 std::move (contentAccessController),
433 std::move (modelUpdateController),
434 std::move (playbackController)))
435 {
436 return rawToUniquePtr (new ARAHostDocumentController (std::move (impl)));
437 }
438
439 return {};
440}
441
442ARAHostDocumentController::~ARAHostDocumentController() = default;
443
444ARA::Host::DocumentController& ARAHostDocumentController::getDocumentController() const
445{
446 return impl->getDocumentController();
447}
448
449ARAHostModel::PlugInExtensionInstance ARAHostDocumentController::bindDocumentToPluginInstance (AudioPluginInstance& instance,
450 ARA::ARAPlugInInstanceRoleFlags knownRoles,
451 ARA::ARAPlugInInstanceRoleFlags assignedRoles)
452{
453 return impl->bindDocumentToPluginInstance (instance, knownRoles, assignedRoles);
454}
455
456void createARAFactoryAsync (AudioPluginInstance& instance, std::function<void (ARAFactoryWrapper)> cb)
457{
458 if (! instance.getPluginDescription().hasARAExtension)
459 cb (ARAFactoryWrapper{});
460
461 struct Extensions final : public ExtensionsVisitor
462 {
463 Extensions (std::function<void (ARAFactoryWrapper)> callbackIn)
464 : callback (std::move (callbackIn))
465 {}
466
467 void visitARAClient (const ARAClient& araClient) override
468 {
469 araClient.createARAFactoryAsync (std::move (callback));
470 }
471
472 std::function<void (ARAFactoryWrapper)> callback;
473 };
474
475 Extensions extensions { std::move (cb) };
476 instance.getExtensions (extensions);
477}
478
479} // namespace juce
480
481#endif
T destroy(T... args)
T get(T... args)
#define jassertfalse
This will always cause an assertion failure.
T lock(T... args)
T make_unique(T... args)
T move(T... args)
JUCE Namespace.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
void createARAFactoryAsync(AudioPluginInstance &instance, std::function< void(ARAFactoryWrapper)> cb)
Calls the provided callback with an ARAFactoryWrapper object obtained from the provided AudioPluginIn...
std::unique_ptr< T > rawToUniquePtr(T *ptr)
Converts an owning raw pointer into a unique_ptr, deriving the type of the unique_ptr automatically.
remove