LMMS
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))
27
28#include "juce_ARAHosting.h"
29#include <ARA_Library/Debug/ARADebug.h>
30
31#include <ARA_Library/Dispatch/ARAHostDispatch.cpp>
32
33namespace juce
34{
35struct ARAEditGuardState
36{
37public:
38 /* Returns true if this controller wasn't previously present. */
39 bool add (ARA::Host::DocumentController& dc)
40 {
41 const std::lock_guard<std::mutex> lock (mutex);
42 return ++counts[&dc] == 1;
43 }
44
45 /* Returns true if this controller is no longer present. */
46 bool remove (ARA::Host::DocumentController& dc)
47 {
48 const std::lock_guard<std::mutex> lock (mutex);
49 return --counts[&dc] == 0;
50 }
51
52private:
53 std::map<ARA::Host::DocumentController*, int> counts;
54 std::mutex mutex;
55};
56
57static ARAEditGuardState editGuardState;
58
59ARAEditGuard::ARAEditGuard (ARA::Host::DocumentController& dcIn) : dc (dcIn)
60{
61 if (editGuardState.add (dc))
62 dc.beginEditing();
63}
64
65ARAEditGuard::~ARAEditGuard()
66{
67 if (editGuardState.remove (dc))
68 dc.endEditing();
69}
70
71//==============================================================================
72namespace ARAHostModel
73{
74
75//==============================================================================
76AudioSource::AudioSource (ARA::ARAAudioSourceHostRef hostRef,
77 ARA::Host::DocumentController& dc,
78 const ARA::ARAAudioSourceProperties& props)
79 : ManagedARAHandle (dc, [&]
80 {
81 const ARAEditGuard guard (dc);
82 return dc.createAudioSource (hostRef, &props);
83 }())
84{
85}
86
87void AudioSource::update (const ARA::ARAAudioSourceProperties& props)
88{
89 const ARAEditGuard guard (getDocumentController());
90 getDocumentController().updateAudioSourceProperties (getPluginRef(), &props);
91}
92
93void AudioSource::enableAudioSourceSamplesAccess (bool x)
94{
95 const ARAEditGuard guard (getDocumentController());
96 getDocumentController().enableAudioSourceSamplesAccess (getPluginRef(), x);
97}
98
99void AudioSource::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
100{
101 dc.destroyAudioSource (ptr);
102}
103
104//==============================================================================
105AudioModification::AudioModification (ARA::ARAAudioModificationHostRef hostRef,
106 ARA::Host::DocumentController& dc,
107 AudioSource& s,
108 const ARA::ARAAudioModificationProperties& props)
109 : ManagedARAHandle (dc, [&]
110 {
111 const ARAEditGuard guard (dc);
112 return dc.createAudioModification (s.getPluginRef(), hostRef, &props);
113 }()),
114 source (s)
115{
116}
117
118void AudioModification::update (const ARA::ARAAudioModificationProperties& props)
119{
120 const ARAEditGuard guard (getDocumentController());
121 getDocumentController().updateAudioModificationProperties (getPluginRef(), &props);
122}
123
124void AudioModification::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
125{
126 dc.destroyAudioModification (ptr);
127}
128
129//==============================================================================
130class PlaybackRegion::Impl : public ManagedARAHandle<Impl, ARA::ARAPlaybackRegionRef>,
131 public DeletionListener
132{
133public:
134 Impl (ARA::ARAPlaybackRegionHostRef hostRef,
135 ARA::Host::DocumentController& dc,
136 AudioModification& m,
137 const ARA::ARAPlaybackRegionProperties& props);
138
139 ~Impl() override
140 {
141 for (const auto& l : listeners)
142 l->removeListener (*this);
143 }
144
145 /* Updates the state of the corresponding %ARA model object.
146
147 Places the DocumentController in editable state.
148
149 You can use getEmptyProperties() to acquire a properties struct where the `structSize`
150 field has already been correctly set.
151 */
152 void update (const ARA::ARAPlaybackRegionProperties& props);
153
154 auto& getAudioModification() const { return modification; }
155
156 static void destroy (ARA::Host::DocumentController&, Ptr);
157
158 void addListener (DeletionListener& l) { listeners.insert (&l); }
159 void removeListener (DeletionListener& l) noexcept override { listeners.erase (&l); }
160
161private:
162 AudioModification* modification = nullptr;
163 std::unordered_set<DeletionListener*> listeners;
164};
165
166PlaybackRegion::Impl::Impl (ARA::ARAPlaybackRegionHostRef hostRef,
167 ARA::Host::DocumentController& dc,
168 AudioModification& m,
169 const ARA::ARAPlaybackRegionProperties& props)
170 : ManagedARAHandle (dc, [&]
171 {
172 const ARAEditGuard guard (dc);
173 return dc.createPlaybackRegion (m.getPluginRef(), hostRef, &props);
174 }()),
175 modification (&m)
176{
177}
178
179PlaybackRegion::~PlaybackRegion() = default;
180
181void PlaybackRegion::Impl::update (const ARA::ARAPlaybackRegionProperties& props)
182{
183 const ARAEditGuard guard (getDocumentController());
184 getDocumentController().updatePlaybackRegionProperties (getPluginRef(), &props);
185}
186
187void PlaybackRegion::Impl::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
188{
189 dc.destroyPlaybackRegion (ptr);
190}
191
192PlaybackRegion::PlaybackRegion (ARA::ARAPlaybackRegionHostRef hostRef,
193 ARA::Host::DocumentController& dc,
194 AudioModification& m,
195 const ARA::ARAPlaybackRegionProperties& props)
196 : impl (std::make_unique<Impl> (hostRef, dc, m, props))
197{
198}
199
200void PlaybackRegion::update (const ARA::ARAPlaybackRegionProperties& props) { impl->update (props); }
201
202void PlaybackRegion::addListener (DeletionListener& x) { impl->addListener (x); }
203
204auto& PlaybackRegion::getAudioModification() const { return impl->getAudioModification(); }
205
206ARA::ARAPlaybackRegionRef PlaybackRegion::getPluginRef() const noexcept { return impl->getPluginRef(); }
207
208DeletionListener& PlaybackRegion::getDeletionListener() const noexcept { return *impl.get(); }
209
210//==============================================================================
211MusicalContext::MusicalContext (ARA::ARAMusicalContextHostRef hostRef,
212 ARA::Host::DocumentController& dc,
213 const ARA::ARAMusicalContextProperties& props)
214 : ManagedARAHandle (dc, [&]
215 {
216 const ARAEditGuard guard (dc);
217 return dc.createMusicalContext (hostRef, &props);
218 }())
219{
220}
221
222void MusicalContext::update (const ARA::ARAMusicalContextProperties& props)
223{
224 const ARAEditGuard guard (getDocumentController());
225 return getDocumentController().updateMusicalContextProperties (getPluginRef(), &props);
226}
227
228void MusicalContext::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
229{
230 dc.destroyMusicalContext (ptr);
231}
232
233//==============================================================================
234RegionSequence::RegionSequence (ARA::ARARegionSequenceHostRef hostRef,
235 ARA::Host::DocumentController& dc,
236 const ARA::ARARegionSequenceProperties& props)
237 : ManagedARAHandle (dc, [&]
238 {
239 const ARAEditGuard guard (dc);
240 return dc.createRegionSequence (hostRef, &props);
241 }())
242{
243}
244
245void RegionSequence::update (const ARA::ARARegionSequenceProperties& props)
246{
247 const ARAEditGuard guard (getDocumentController());
248 return getDocumentController().updateRegionSequenceProperties (getPluginRef(), &props);
249}
250
251void RegionSequence::destroy (ARA::Host::DocumentController& dc, Ptr ptr)
252{
253 dc.destroyRegionSequence (ptr);
254}
255
256//==============================================================================
257PlaybackRendererInterface PlugInExtensionInstance::getPlaybackRendererInterface() const
258{
259 if (instance != nullptr)
260 return PlaybackRendererInterface (instance->playbackRendererRef, instance->playbackRendererInterface);
261
262 return {};
263}
264
265EditorRendererInterface PlugInExtensionInstance::getEditorRendererInterface() const
266{
267 if (instance != nullptr)
268 return EditorRendererInterface (instance->editorRendererRef, instance->editorRendererInterface);
269
270 return {};
271}
272
273} // namespace ARAHostModel
274
275//==============================================================================
276class ARAHostDocumentController::Impl
277{
278public:
279 Impl (ARAFactoryWrapper araFactoryIn,
280 std::unique_ptr<ARA::Host::DocumentControllerHostInstance>&& dcHostInstanceIn,
281 const ARA::ARADocumentControllerInstance* documentControllerInstance)
282 : araFactory (std::move (araFactoryIn)),
283 dcHostInstance (std::move (dcHostInstanceIn)),
284 documentController (documentControllerInstance)
285 {
286 }
287
288 ~Impl()
289 {
290 documentController.destroyDocumentController();
291 }
292
293 static std::unique_ptr<Impl>
294 createImpl (ARAFactoryWrapper araFactory,
295 const String& documentName,
296 std::unique_ptr<ARA::Host::AudioAccessControllerInterface>&& audioAccessController,
297 std::unique_ptr<ARA::Host::ArchivingControllerInterface>&& archivingController,
298 std::unique_ptr<ARA::Host::ContentAccessControllerInterface>&& contentAccessController,
299 std::unique_ptr<ARA::Host::ModelUpdateControllerInterface>&& modelUpdateController,
300 std::unique_ptr<ARA::Host::PlaybackControllerInterface>&& playbackController)
301 {
302 std::unique_ptr<ARA::Host::DocumentControllerHostInstance> dcHostInstance =
303 std::make_unique<ARA::Host::DocumentControllerHostInstance> (audioAccessController.release(),
304 archivingController.release(),
305 contentAccessController.release(),
306 modelUpdateController.release(),
307 playbackController.release());
308
309 const auto documentProperties = makeARASizedStruct (&ARA::ARADocumentProperties::name, documentName.toRawUTF8());
310
311 if (auto* dci = araFactory.get()->createDocumentControllerWithDocument (dcHostInstance.get(), &documentProperties))
312 return std::make_unique<Impl> (std::move (araFactory), std::move (dcHostInstance), dci);
313
314 return {};
315 }
316
317 ARAHostModel::PlugInExtensionInstance bindDocumentToPluginInstance (AudioPluginInstance& instance,
318 ARA::ARAPlugInInstanceRoleFlags knownRoles,
319 ARA::ARAPlugInInstanceRoleFlags assignedRoles)
320 {
321
322 const auto makeVisitor = [] (auto vst3Fn, auto auFn)
323 {
324 using Vst3Fn = decltype (vst3Fn);
325 using AuFn = decltype (auFn);
326
327 struct Visitor : ExtensionsVisitor, Vst3Fn, AuFn
328 {
329 explicit Visitor (Vst3Fn vst3Fn, AuFn auFn) : Vst3Fn (std::move (vst3Fn)), AuFn (std::move (auFn)) {}
330 void visitVST3Client (const VST3Client& x) override { Vst3Fn::operator() (x); }
331 void visitAudioUnitClient (const AudioUnitClient& x) override { AuFn::operator() (x); }
332 };
333
334 return Visitor { std::move (vst3Fn), std::move (auFn) };
335 };
336
337 const ARA::ARAPlugInExtensionInstance* pei = nullptr;
338 auto visitor = makeVisitor ([this, &pei, knownRoles, assignedRoles] (const ExtensionsVisitor::VST3Client& vst3Client)
339 {
340 auto* iComponentPtr = vst3Client.getIComponentPtr();
341 VSTComSmartPtr<ARA::IPlugInEntryPoint2> araEntryPoint;
342
343 if (araEntryPoint.loadFrom (iComponentPtr))
344 pei = araEntryPoint->bindToDocumentControllerWithRoles (documentController.getRef(), knownRoles, assignedRoles);
345 },
346 #if JUCE_PLUGINHOST_AU && JUCE_MAC
347 [this, &pei, knownRoles, assignedRoles] (const ExtensionsVisitor::AudioUnitClient& auClient)
348 {
349 auto audioUnit = auClient.getAudioUnitHandle();
350 auto propertySize = (UInt32) sizeof (ARA::ARAAudioUnitPlugInExtensionBinding);
351 const auto expectedPropertySize = propertySize;
352 ARA::ARAAudioUnitPlugInExtensionBinding audioUnitBinding { ARA::kARAAudioUnitMagic,
353 documentController.getRef(),
354 nullptr,
355 knownRoles,
356 assignedRoles };
357
358 auto status = AudioUnitGetProperty (audioUnit,
359 ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles,
360 kAudioUnitScope_Global,
361 0,
362 &audioUnitBinding,
363 &propertySize);
364
365 if (status == noErr
366 && propertySize == expectedPropertySize
367 && audioUnitBinding.inOutMagicNumber == ARA::kARAAudioUnitMagic
368 && audioUnitBinding.inDocumentControllerRef == documentController.getRef()
369 && audioUnitBinding.outPlugInExtension != nullptr)
370 {
371 pei = audioUnitBinding.outPlugInExtension;
372 }
373 else
375 }
376 #else
377 [] (const auto&) {}
378 #endif
379 );
380
381 instance.getExtensions (visitor);
382 return ARAHostModel::PlugInExtensionInstance { pei };
383 }
384
385 auto& getDocumentController() { return documentController; }
386
387private:
388 ARAFactoryWrapper araFactory;
389 std::unique_ptr<ARA::Host::DocumentControllerHostInstance> dcHostInstance;
390 ARA::Host::DocumentController documentController;
391};
392
393ARAHostDocumentController::ARAHostDocumentController (std::unique_ptr<Impl>&& implIn)
394 : impl { std::move (implIn) }
395{}
396
397std::unique_ptr<ARAHostDocumentController> ARAHostDocumentController::create (ARAFactoryWrapper factory,
398 const String& documentName,
399 std::unique_ptr<ARA::Host::AudioAccessControllerInterface> audioAccessController,
400 std::unique_ptr<ARA::Host::ArchivingControllerInterface> archivingController,
401 std::unique_ptr<ARA::Host::ContentAccessControllerInterface> contentAccessController,
402 std::unique_ptr<ARA::Host::ModelUpdateControllerInterface> modelUpdateController,
403 std::unique_ptr<ARA::Host::PlaybackControllerInterface> playbackController)
404{
405 if (auto impl = Impl::createImpl (std::move (factory),
406 documentName,
407 std::move (audioAccessController),
408 std::move (archivingController),
409 std::move (contentAccessController),
410 std::move (modelUpdateController),
411 std::move (playbackController)))
412 {
413 return rawToUniquePtr (new ARAHostDocumentController (std::move (impl)));
414 }
415
416 return {};
417}
418
419ARAHostDocumentController::~ARAHostDocumentController() = default;
420
421ARA::Host::DocumentController& ARAHostDocumentController::getDocumentController() const
422{
423 return impl->getDocumentController();
424}
425
426ARAHostModel::PlugInExtensionInstance ARAHostDocumentController::bindDocumentToPluginInstance (AudioPluginInstance& instance,
427 ARA::ARAPlugInInstanceRoleFlags knownRoles,
428 ARA::ARAPlugInInstanceRoleFlags assignedRoles)
429{
430 return impl->bindDocumentToPluginInstance (instance, knownRoles, assignedRoles);
431}
432
433void createARAFactoryAsync (AudioPluginInstance& instance, std::function<void (ARAFactoryWrapper)> cb)
434{
435 if (! instance.getPluginDescription().hasARAExtension)
436 cb (ARAFactoryWrapper{});
437
438 struct Extensions : public ExtensionsVisitor
439 {
440 Extensions (std::function<void (ARAFactoryWrapper)> callbackIn)
441 : callback (std::move (callbackIn))
442 {}
443
444 void visitARAClient (const ARAClient& araClient) override
445 {
446 araClient.createARAFactoryAsync (std::move (callback));
447 }
448
449 std::function<void (ARAFactoryWrapper)> callback;
450 };
451
452 Extensions extensions { std::move(cb) };
453 instance.getExtensions (extensions);
454}
455
456} // namespace juce
457
458#endif
pthread_mutex_t mutex
Definition Controller.C:6
#define noexcept
Definition DistrhoDefines.h:72
Definition String.h:48
const char * toRawUTF8() const
Definition String.cpp:1925
int * l
Definition inflate.c:1579
unsigned * m
Definition inflate.c:1559
unsigned s
Definition inflate.c:1555
unsigned x[BMAX+1]
Definition inflate.c:1586
#define jassertfalse
void move(void *from, void *to)
Definition juce_FixedSizeFunction.h:53
Definition carla_juce.cpp:31
constexpr Obj makeARASizedStruct(Member Obj::*member, Ts &&... ts)
Definition juce_ARACommon.h:79
std::unique_ptr< T > rawToUniquePtr(T *ptr)
Definition juce_Memory.h:195
void add(SampleFrame *dst, const SampleFrame *src, int frames)
Add samples from src to dst.
Definition MixHelpers.cpp:135
Definition juce_Uuid.h:141
RECT const char void(* callback)(const char *droppath))) SWELL_API_DEFINE(BOOL
Definition swell-functions.h:1004
#define void
Definition unzip.h:396
#define const
Definition zconf.h:137