AUv3 extension based on AVAudioUnitSampler not registered

I created a multi-timbral instrument application based on multiple AVAudioUnitSampler instances (one per Midi channel), wrapped in a custom AVSampler class.

I want to expose it also as an AUv3. I followed some articles and samples and put the view controller and other classes in a Framework target, created an AudioUnit extension target (with a dummy/empty class file as I've no implementation to provide).

In the extension's Info.plist (NSExtensionAttributes) I added AudioComponentBundle (points to the AUFramework) and AudioComponents item with factoryFunction (points to $(PRODUCT_MODULE_NAME).MultiSamplerViewController), aumu type. Also added NSExtensionPrincipalClass pointing to AUFramework.MultiSamplerViewController.

In the shared MultiSamplerViewController I implemented

  • (AUAudioUnit *)createAudioUnitWithComponentDescription:(AudioComponentDescription)desc error:(NSError **)error {

    return [[[multiSampler engine] outputNode] AUAudioUnit];

}

It also contains an - (id)initWithCoder:(NSCoder*)decoder method, that instantiates the wrapping MultiSampler and starts an enclosed MidiManager.

The host application target runs fine, however the AU extension plugin isn't listed in GarageBand (even after runnig the host application once). The target platform is iPad.

I added code to load the appex plugin bundle, however it doesn't seem enough to register the plugin. Also I cannot use the AUAudioUnit registerSubclass as I've no concrete AU implementation class (I could pass [[[multiSampler engine] outputNode] AUAudioUnit] ?)

I'm in the same configuration as an application built on AudioKit framework (that originally wrapped AVAudioUnitSampler - and now uses a custom implementation).

I may have to implement AUaudioUnit callbacks. To pass mainMixerNode buffers to AUaudioUnit render callback I could store (in memory, so would grow over time... not ideal) these through installTapOnBus, and then access these from render callback.

AVSampler : AUAudioUnit

-(void) createAudioEngine

  ...   [mixerNode installTapOnBus:0           bufferSize:4096             format:[[AVAudioFormat alloc]initWithStreamDescription:&audioFormat]              block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {                 [self.timeToBuffer addObject:buffer forKey:when]; }]; ...

 (AUInternalRenderBlock)internalRenderBlock {

  return ^AUAudioUnitStatus(AudioUnitRenderActionFlags    *actionFlags,

                              const AudioTimeStamp     *timestamp,

                              AVAudioFrameCount     frameCount,

                              NSInteger     outputBusNumber,

                              AudioBufferList     *outputBufferListPtr,

                              const AURenderEvent     *realtimeEventListHead,

                              AURenderPullInputBlock     pullInputBlock ) {

        

        int outputNumBuffers = outputBufferListPtr->mNumberBuffers;

float *ptrLeft  = (float*)outputBufferListPtr->mBuffers[0].mData;

        float *ptrRight = NULL;

        if (outputNumBuffers == 2) {

            ptrRight = (float*)outputBufferListPtr->mBuffers[1].mData;

        }

AVAudioPCMBuffer *mixerNodeBuffer = [self.timeToBuffer objectForKey:timestamp]; mixerNodeBuffer.audioBufferList.pointee.mBuffers int n = frameCount; if(mixerNodeBuffer.frameLength == frameCount) for (int i=0;i<n;i++) {     ptrLeft[i] = mixerNodeBuffer.floatChannelData[0].pointee[n];     ptrRight[i] = mixerNodeBuffer.floatChannelData[1].pointee[n]; }

  } }

AUv3 extension based on AVAudioUnitSampler not registered
 
 
Q