Audio Unit v3 Instrument with inputBusses problem

Hello,

I am having problems getting my AUv3 Instrument with an inputBus to work. As a standalone app (with the SimplePlayEngine of the sample code integrated) it seems to work fine, the plugin also passes the auval test without errors. But when I try to use the plugin in a host application (like garageband / logic / host of the sample code) I can't get any output, the internalRenderBlock is not even being called. I narrowed it down to the inputBusses property, so it seems that I am doing something wrong with setting up the input bus.


To reproduce, take the InstrumentDemo of the Apple sample code, and in the init method initialize an inputBusBuffer, create an inputBusArray with the bus of the inputBusBuffer. Set the inputBusArray as the return value for the inputBusses property and allocateRenderResources of the inputBusBuffer in the allocateRenderResourcesAndReturnError (and deallocateRenderResources in the deallocateRenderResources call). All of this is done analogous to the inputBus setup in the FilterDemo example.

I also explicitly set the channelCapabilities to Stereo In, Stereo Out.


Omitting the further processing in the internalRenderBlock, shouldn't this work to the point that internalRenderBlock is getting called? Ít is getting called in the App, and auval validation succeeds, but it is not being called in any host.


Am I missing something here?


Any help will be much appreciated!

Replies

Nobody? Would be glad for any input!

Here are the changes to the sample code of InstumentDemo.mm by Apple to reproduce:


1. add an inputBusArray to the @interface (and channelCapabilitiesArray)

@interface AUv3InstrumentDemo ()

@property AUAudioUnitBus *outputBus;
@property AUAudioUnitBusArray *outputBusArray;
@property AUAudioUnitBusArray *inputBusArray;
@property NSArray<NSNumber *> *channelCapabilitiesArray;
@property (nonatomic, readwrite) AUParameterTree *parameterTree;

@end


2. add a BufferedInputBus to the @implementation

@implementation AUv3InstrumentDemo {
    // C++ members need to be ivars; they would be copied on access if they were properties.
    InstrumentDSPKernel _kernel;
    BufferedOutputBus _outputBusBuffer;
    BufferedInputBus _inputBusBuffer;
}


3. initialize the BufferedInputBus in the init method, set the inputBusArray and the channelCapabilitiesArray

(instancetype)initWithComponentDescription:(AudioComponentDescription)componentDescription options:
     (AudioComponentInstantiationOptions)options error:(NSError **)outError {
     ...
     // Create the output bus.
    _inputBusBuffer.init(defaultFormat, 2);
    _outputBusBuffer.init(defaultFormat, 2);
    _outputBus = _outputBusBuffer.bus;

     // Create the input and output bus arrays.
    _outputBusArray = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self
                                                             busType:AUAudioUnitBusTypeOutput
                                                              busses: @[_outputBus]];

    _inputBusArray  = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self
                                                             busType:AUAudioUnitBusTypeInput 
                                                              busses: @[_inputBusBuffer.bus]];

     // create the channel capabilities
    NSArray *channelConfig = [NSArray arrayWithObjects:
                              [NSNumber numberWithInt:2],[NSNumber numberWithInt:2],nil];
    _channelCapabilitiesArray = channelConfig;
     ...
}


4. add the inputBusses (and channelCapabilities) getter to the class

...
#pragma mark - AUAudioUnit (Overrides)

- (NSArray<NSNumber *>*)channelCapabilities {return _channelCapabilitiesArray;}

- (AUAudioUnitBusArray *)inputBusses {
    return _inputBusArray;
}
...


5. run in a host and set a breakpoint in the internalRenderBlock callback (you can leave out the channelCapabilities part, makes no difference)


expected result: AudioUnit should go into the internalRenderBlock and hit the breakpoint


actual result: nothing happens, no render callback (everything else works fine)


note: AudioUnit validates correctly with auval and works as standalone app

nobody?

Do you need the inputBus routine of an effect plugin or do you need the inputBus routine for a synth ???


For an Effect (.mm):


#import <AVFoundation/AVFoundation.h>

#pragma mark AudioUnit (Presets)
static const UInt8 kNumberOfPresets = 3;
static const NSInteger kDefaultFactoryPreset = 0;

typedef struct FactoryPresetParameters {
    AUValue cutoffValue;
    AUValue resonanceValue;
} FactoryPresetParameters;
static const FactoryPresetParameters presetParameters[kNumberOfPresets] =
{
    /
    {
        400.0f,/
        -5.0f,/
    },
   
    /
    {
        6000.0f,/
        15.0f,/
    },
   
    /
    {
        1000.0f,/
        5.0f,/
    }
};

static AUAudioUnitPreset* NewAUPreset(NSInteger number, NSString *name)
{
    AUAudioUnitPreset *aPreset = [AUAudioUnitPreset new];
    aPreset.number = number;
    aPreset.name = name;
    return aPreset;
}

@property AUAudioUnitBus *inputBus;
@property AUAudioUnitBus *outputBus;
@property AUAudioUnitBusArray *inputBusArray;
@property AUAudioUnitBusArray *outputBusArray;
@property (nonatomic, readwrite) AUParameterTree *parameterTree;
@end

@implementation AudioUnit
{
    AUAudioUnitPreset   *_currentPreset;
    NSInteger           _currentFactoryPresetIndex;
    NSArray<AUAudioUnitPreset *> *_presets;
}
@synthesize parameterTree = _parameterTree;
@synthesize factoryPresets = _presets;
- (instancetype)initWithComponentDescription:(AudioComponentDescription)componentDescription options:(AudioComponentInstantiationOptions)options error:(NSError **)outError {
    self = [super initWithComponentDescription:componentDescription options:options error:outError];
   
    if (self == nil) {
        return nil;
    }
   
   
    /
    AVAudioFormat *defaultFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100. channels:2];
   
   
    /
    AUParameter *param1 = [AUParameterTree
                           createParameterWithIdentifier:@"param1"
                           name:@"Test Parameter 1"
                           address:myParam1
                           min:0
                           max:100
                           unit:kAudioUnitParameterUnit_Percent
                           unitName:nil
                           flags:kAudioUnitParameterFlag_IsReadable | kAudioUnitParameterFlag_IsWritable
                           valueStrings:NULL
                           dependentParameters:nil];
   
   
    /
    param1.value = 1.0;
   
    /
    _parameterTree = [AUParameterTree createTreeWithChildren:@[ param1 ]];
   
    /
    _currentFactoryPresetIndex = kDefaultFactoryPreset;
    _presets = @[NewAUPreset(0, @"First Preset"),
                 NewAUPreset(1, @"Second Preset"),
                 NewAUPreset(2, @"Third Preset")];
   
   
    /
    _inputBus = [[AUAudioUnitBus alloc] initWithFormat:defaultFormat error:nil];
    _outputBus = [[AUAudioUnitBus alloc] initWithFormat:defaultFormat error:nil];
   
    /
    _inputBusArray  = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self busType:AUAudioUnitBusTypeInput  busses: @[_inputBus]];
    _outputBusArray = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self busType:AUAudioUnitBusTypeOutput busses: @[_outputBus]];
   
    /
    /
    __block FilterDSPKernel *filterKernel = &_kernel;
   
    /
    _parameterTree.implementorValueObserver = ^(AUParameter *param, AUValue value) {
        filterKernel->setParameter(param.address, value);
    };
   
    /
    _parameterTree.implementorValueProvider = ^(AUParameter *param) {
        return filterKernel->getParameter(param.address);
    };
    */
   
    /
    _parameterTree.implementorStringFromValueCallback = ^(AUParameter *param, const AUValue *__nullable valuePtr) {
        AUValue value = valuePtr == nil ? param.value : *valuePtr;
       
        switch (param.address) {
            case myParam1:
                return [NSString stringWithFormat:@"%.f", value];
            default:
                return @"?";
        }
    };
   
    self.maximumFramesToRender = 512;
    /
    self.currentPreset = _presets.firstObject;
   
    return self;
}
-(void)dealloc {
    /
}
#pragma mark - AUAudioUnit Overrides
/
- (NSArray <AUAudioUnitPreset *> *)factoryPresets {
    NSArray *parray = @[@"Preset One"];
    return parray;
}
*/
- (NSTimeInterval)latency {
    return 0;
}
- (NSTimeInterval)tailTime{
    return 1.0;
}
- (BOOL)shouldBypassEffect {
    return true;
}
- (NSArray <NSNumber *> *)channelCapabilities{
    NSArray *carray = @[@-1,@-2];
    return carray;
}
- (AUAudioChannelCount)maximumChannelCount{
    return UINT_MAX;
}
- (AUAudioUnitBusArray *)inputBusses {
    return _inputBusArray;
}
- (AUAudioUnitBusArray *)outputBusses {
    return _outputBusArray;
}
- (BOOL)canProcessInPlace {
    return YES;
}
- (BOOL)allocateRenderResourcesAndReturnError:(NSError **)outError {
    if (![super allocateRenderResourcesAndReturnError:outError]) {
        return NO;
    }
   
    /
    /
   
    return YES;
}
- (void)deallocateRenderResources {
    [super deallocateRenderResources];
   
    /
}
#pragma mark - AudioUnit DSP
- (AUInternalRenderBlock)internalRenderBlock {
    /

    return ^AUAudioUnitStatus(AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp *timestamp, AVAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList *outputData, const AURenderEvent *realtimeEventListHead, AURenderPullInputBlock pullInputBlock) {
        /
       
        return noErr;
       
    };
}
#pragma mark- AUAudioUnit (Optional Properties)
- (AUAudioUnitPreset *)currentPreset
{
    if (_currentPreset.number >= 0) {
        return [_presets objectAtIndex:_currentFactoryPresetIndex];
    } else {
        return _currentPreset;
    }
}
- (void)setCurrentPreset:(AUAudioUnitPreset *)currentPreset
{
    if (nil == currentPreset) { return; }
   
    if (currentPreset.number >= 0) {
        /
        for (AUAudioUnitPreset *factoryPreset in _presets) {
            if (currentPreset.number == factoryPreset.number) {
               
                /
                AUParameter *cutoffParameter = [self.parameterTree valueForKey: @"cutoff"];
                AUParameter *resonanceParameter = [self.parameterTree valueForKey: @"resonance"];
               
                cutoffParameter.value = presetParameters[factoryPreset.number].cutoffValue;
                resonanceParameter.value = presetParameters[factoryPreset.number].resonanceValue;
                */
               
               
                /
                _currentPreset = currentPreset;
                _currentFactoryPresetIndex = factoryPreset.number;
                break;
            }
        }
    } else if (nil != currentPreset.name) {
        /
        _currentPreset = currentPreset;
    } else {
    }
}
@end


please delete the props you dont have ;-)

I'm trying to do the same thing to add an inputBus to an AU v3 instrument in order to get a Sidechain dropdown menu in Logic. I'm also having trouble, did anyone every figure out how to do this?

I was able to reproduce the same behavior as user "jfjs". As far as I can tell this is the same boilerplate as in the AU effects example posted by user "NB System".