Problems porting to new ARA support

We’re just starting porting from the Celemony-provided JUCE_ARA to Juce 7.0.5, and we’re seeing some issues that I’m not sure how to address.

First off, it looks like instead of deriving from ARADocumentController, we need to derive our class from the new ARADocumentControllerSpecialisation, correct? I’ve done that, but now get a number of errors related to that change.

For one, the specialization seems to be missing some callbacks we implemented using the Celemony-provided code, so our overrides have nothing to override any more. Among these are:

updateMusicalContextContent
doDestroyMusicalContext

Others say that the non-virtual (why???) function marked as override hides a virtual function. These include:

doCreateMusicalContext
doCreateAudioSource
doCreateAudioModification
doCreatePlaybackRegion
as well as the listener callback:
willUpdatePlaybackRegionProperties

Others complain that the return type is not covariant with the return type of the function it overrides. These functions return ARA::Plugin:: objects but the specialization class apparently returns juce:: variants? These ones are:

doCreatePlaybackRenderer
doCreateEditorRenderer
doCreateEditorView

In addition, we get an error in ARAPlug.h, on this code:

**template** <**typename** DocumentController_t = DocumentController>
DocumentController_t* getDocumentController () **const** **noexcept** { **return** **static_cast**<DocumentController_t*> (**this**->_audioModification->getAudioSource ()->getDocumentController ()); }

It says that our derived class is not related to DocumentController any more. Not sure what to do here. We had to change to using the specialization class as the base class. So what are we supposed to do to fix this?

Here are examples of how we defined some of those functions. The problems seem mostly to stem from the use of ARA::Plugin objects, which are not how the new overrides are defined:

ARA::PlugIn::MusicalContext* doCreateMusicalContext (ARA::PlugIn::Document* document, ARA::ARAMusicalContextHostRef hostRef) noexcept override;

void doDestroyMusicalContext (ARA::PlugIn::MusicalContext* musicalContext) noexcept override;

ARA::PlugIn::AudioSource* doCreateAudioSource (ARA::PlugIn::Document* document, ARA::ARAAudioSourceHostRef hostRef) noexcept override;

ARA::PlugIn::PlaybackRenderer* doCreatePlaybackRenderer() noexcept override;

ARA::PlugIn::EditorRenderer* doCreateEditorRenderer() noexcept override;

ARA::PlugIn::EditorView* doCreateEditorView() 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;

Looks like I may be able to change, for example

ARA::PlugIn::MusicalContext* doCreateMusicalContext (ARA::PlugIn::Document* document, ARA::ARAMusicalContextHostRef hostRef) noexcept override;

to

juce::ARAMusicalContext* doCreateMusicalContext( juce::ARADocument* document …

That seems to let the header pass that error, at least. Is that kind of change sufficient?

That type of fix seems to handle them all except these two:

	void updateMusicalContextContent (ARA::ARAMusicalContextRef musicalContextRef, const ARA::ARAContentTimeRange* range, ARA::ContentUpdateScopes flags) noexcept override;

	void doDestroyMusicalContext (juce::ARAMusicalContext* musicalContext) noexcept override;

and this:

	void didEndEditing () noexcept override;

I don’t see any of those functions in the specialization.

Also missing is getHostArchivingController() in the specialization. We use that to call its notifyDocumentUnarchivingProgress() function to set the progress.

Looks like we’re getting it all worked out, slowly.

we need to derive our class from the new ARADocumentControllerSpecialisation, correct?

The ARADocumentControllerSpecialisation class along with the JUCE base classes for the various ARA model objects are meant to cover some typical use-cases, and make it easier to implement them in an incremental manner. It aims to do this by making certain assumptions about the nature of the implementation, and only exposing those functions through ARADocumentControllerSpecialisation that fit this approach.

These assumptions are:

  • Only functions of the ARA::PlugIn::DocumentControllerDelegate need to be overloaded, hence only these functions are added to the ...Specialisation class.
  • The model objects inherit from the JUCE base classes e.g. juce::ARAMusicalContext, and they aren’t just indices cast to pointers. Hence the default implementation of just deleting juce::ARAMusicalContext* is appropriate and doesn’t have to be overloaded. That’s why the doDestroy... functions are also not exposed.

This mirrors the two-tier ARA Library organisation of the ARA::PlugIn::DocumentController, where overriding anything outside the DocumentControllerDelegate functions is considered an advanced use-case.

This simplification allows us to provide a good default behaviour for everything not exposed, and we hoped this approach would ease the creation of new ARA plugins. Allowing users to override even lower-level functions outside the DocumentControllerDelegate class, would run the risk that our assumptions and default implementations break down.

This is indeed the primarily intended way of using the JUCE ARA integration.

However, you don’t have to use ARADocumentControllerSpecialisation, and when an even deeper level of customisation is necessary, you may have to inherit directly from ARA::PlugIn::DocumentController, and return your own ARAFactory class from the const ARA::ARAFactory* JUCE_CALLTYPE createARAFactory() standalone function. This is the only requirement for successfully compiling ARA plugins with JUCE.

I may be able to change, for example […] to `juce::ARAMusicalContext* doCreateMusicalContext…

Yes, that would be the intended usage of the ARADocumentControllerSpecialisation class.

missing some callbacks […] updateMusicalContextContent, doDestroyMusicalContext

The intended usage is to inherit from ARAMusicalContextListener and add it as a listener to your ARADocumentControllerSpecialisation. Then you can handle the doUpdateMusicalContextContent() and willDestroyMusicalContext() events.

You can inherit from ARADocumentListener and add it as a listener to handle didEndEditing().

You can get the HostArchivingController through ARADocumentControllerSpecialisation::getDocumentController()->getHostArchivingController().

Thanks for the thorough information! I moved on to another set of issues, but my colleague says he has worked out these issues. I’ll have him review this info and make any changes he feels are appropriate. Thanks again!