Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AUGraphInitialize an error code -10868 when adding kAudioUnitSubType_Reverb2 to AUGraph

I'm attempting to add an AudioUnit of type kAudioUnitSubType_Reverb2 to an AUGraph and am getting a -10868 (kAudioUnitErr_FormatNotSupported) supported error on AUGraphInitialize. My starting point was Apple's iPhoneMixerEQGraphTest sample app, I've basically just added a new AudioUnit for the reverb but cannot get it to work.

Here is the code -

- (void)initializeAUGraph
{
    printf("initializeAUGraph\n");

    AUNode outputNode;
    AUNode eqNode;
    AUNode mixerNode;
    AUNode reverbNode;

    printf("create client ASBD\n");

    // client format audio goes into the mixer
    mClientFormat.SetCanonical(2, true);                        
    mClientFormat.mSampleRate = kGraphSampleRate;
    mClientFormat.Print();

    printf("create output ASBD\n");

    // output format
    mOutputFormat.SetAUCanonical(2, false);                     
    mOutputFormat.mSampleRate = kGraphSampleRate;
    mOutputFormat.Print();

    OSStatus result = noErr;

    // load up the audio data
    [self performSelectorInBackground:@selector(loadFiles) withObject:nil];

    printf("new AUGraph\n");

    // create a new AUGraph
    result = NewAUGraph(&mGraph);
    if (result) { printf("NewAUGraph result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    // create three CAComponentDescription for the AUs we want in the graph

    // output unit
    CAComponentDescription output_desc(kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, kAudioUnitManufacturer_Apple);

    // iPodEQ unit
    CAComponentDescription eq_desc(kAudioUnitType_Effect, kAudioUnitSubType_AUiPodEQ, kAudioUnitManufacturer_Apple);

    // multichannel mixer unit
    CAComponentDescription mixer_desc(kAudioUnitType_Mixer, kAudioUnitSubType_MultiChannelMixer, kAudioUnitManufacturer_Apple);

    // reverb unit
    CAComponentDescription reverb_desc(kAudioUnitType_Effect, kAudioUnitSubType_Reverb2, kAudioUnitManufacturer_Apple);

    printf("add nodes\n");

    // create a node in the graph that is an AudioUnit, using the supplied AudioComponentDescription to find and open that unit
    result = AUGraphAddNode(mGraph, &output_desc, &outputNode);
    if (result) { printf("AUGraphNewNode 1 result %lu %4.4s\n", result, (char*)&result); return; }

    result = AUGraphAddNode(mGraph, &eq_desc, &eqNode);
    if (result) { printf("AUGraphNewNode 2 result %lu %4.4s\n", result, (char*)&result); return; }

    result = AUGraphAddNode(mGraph, &mixer_desc, &mixerNode);
    if (result) { printf("AUGraphNewNode 3 result %lu %4.4s\n", result, (char*)&result); return; }

    result = AUGraphAddNode(mGraph, &reverb_desc, &reverbNode);
    if (result) { printf("AUGraphNewNode 4 result %lu %4.4s\n", result, (char*)&result); return; }

    // connect a node's output to a node's input
    // mixer -> eq -> output
    result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, eqNode, 0);
    if (result) { printf("AUGraphConnectNodeInput result %lu %4.4s\n", result, (char*)&result); return; }

    result = AUGraphConnectNodeInput(mGraph, eqNode, 0, reverbNode, 0);
    if (result) { printf("AUGraphConnectNodeInput result %lu %4.4s\n", result, (char*)&result); return; }

    result = AUGraphConnectNodeInput(mGraph, reverbNode, 0, outputNode, 0);
    if (result) { printf("AUGraphConnectNodeInput reverb result %lu %4.4s\n", result, (char*)&result); return; }

    // open the graph AudioUnits are open but not initialized (no resource allocation occurs here)
    result = AUGraphOpen(mGraph);
    if (result) { printf("AUGraphOpen result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    // grab the audio unit instances from the nodes
    result = AUGraphNodeInfo(mGraph, mixerNode, NULL, &mMixer);
    if (result) { printf("AUGraphNodeInfo result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    result = AUGraphNodeInfo(mGraph, eqNode, NULL, &mEQ);
    if (result) { printf("AUGraphNodeInfo result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    result = AUGraphNodeInfo(mGraph, reverbNode, NULL, &mReverb);
    if (result) { printf("AUGraphNodeInfo reverb result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    // set bus count
    UInt32 numbuses = 2;

    printf("set input bus count %lu\n", numbuses);

    result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &numbuses, sizeof(numbuses));
    if (result) { printf("AudioUnitSetProperty result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    for (int i = 0; i < numbuses; ++i) {
        // setup render callback struct
        AURenderCallbackStruct rcbs;
        rcbs.inputProc = &renderInput;
        rcbs.inputProcRefCon = &mUserData;

        printf("set AUGraphSetNodeInputCallback\n");

        // set a callback for the specified node's specified input
        result = AUGraphSetNodeInputCallback(mGraph, mixerNode, i, &rcbs);
        if (result) { printf("AUGraphSetNodeInputCallback result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

        printf("set input bus %d, client kAudioUnitProperty_StreamFormat\n", i);

        // set the input stream format, this is the format of the audio for mixer input
        result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, i, &mClientFormat, sizeof(mClientFormat));
        if (result) { printf("AudioUnitSetProperty result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }
    }

    printf("get EQ kAudioUnitProperty_FactoryPresets\n");

    // get the eq's factory preset list -- this is a read-only CFArray array of AUPreset structures
    // host owns the retuned array and should release it when no longer needed
    UInt32 size = sizeof(mEQPresetsArray);
    result = AudioUnitGetProperty(mEQ, kAudioUnitProperty_FactoryPresets, kAudioUnitScope_Global, 0, &mEQPresetsArray, &size);
    if (result) { printf("AudioUnitGetProperty result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    /* this code can be used if you're interested in dumping out the preset list
    printf("iPodEQ Factory Preset List:\n");
    UInt8 count = CFArrayGetCount(mEQPresetsArray);
    for (int i = 0; i < count; ++i) {
        AUPreset *aPreset = (AUPreset*)CFArrayGetValueAtIndex(mEQPresetsArray, i);
        CFShow(aPreset->presetName);
    }*/

    printf("set output kAudioUnitProperty_StreamFormat\n");

    // set the output stream format of the mixer
    result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &mOutputFormat, sizeof(mOutputFormat));
    if (result) { printf("AudioUnitSetProperty result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    printf("set render notification\n");

    // add a render notification, this is a callback that the graph will call every time the graph renders
    // the callback will be called once before the graph’s render operation, and once after the render operation is complete
    result = AUGraphAddRenderNotify(mGraph, renderNotification, &mUserData);
    if (result) { printf("AUGraphAddRenderNotify result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }

    printf("AUGraphInitialize\n");

    // now that we've set everything up we can initialize the graph, this will also validate the connections
    result = AUGraphInitialize(mGraph);
    if (result) { printf("AUGraphInitialize result %ld %08X %4.4s\n", result, (unsigned int)result, (char*)&result); return; }
    // ---- result here is error code 10868

    CAShow(mGraph);
}
like image 904
Gary Thackrah Avatar asked Oct 08 '22 22:10

Gary Thackrah


1 Answers

For some reason, some AU nodes take a stream format in float by default, while others take it in integers. If the stream formats don't match, you get this error. So you need to add a Format Converter between your equalizer node and your reverb node:

    AudioComponentDescription convertUnitDescription;
convertUnitDescription.componentManufacturer  = kAudioUnitManufacturer_Apple;
convertUnitDescription.componentType          = kAudioUnitType_FormatConverter;
convertUnitDescription.componentSubType       = kAudioUnitSubType_AUConverter;
convertUnitDescription.componentFlags         = 0;
convertUnitDescription.componentFlagsMask     = 0;
result = AUGraphAddNode (graph, &convertUnitDescription, &convertNode);
NSCAssert (result == noErr, @"Unable to add the converted unit to the audio processing graph. Error code: %d '%.4s'", (int) result, (const char *)&result);

Make sure you set the stream format of the converter node input to the format of equalizer node output:

    AudioStreamBasicDescription eqStreamFormat;
UInt32 streamFormatSize = sizeof(eqStreamFormat);
result = AudioUnitGetProperty(eqUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &eqStreamFormat, &streamFormatSize);
NSAssert (result == noErr, @"Unable to get eq output format. Error code: %d '%.4s'", (int) result, (const char *)&result);

result = AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &eqStreamFormat, streamFormatSize);
NSAssert (result == noErr, @"Unable to set converter input format. Error code: %d '%.4s'", (int) result, (const char *)&result);

And do the same for the output of the converter, setting it with the reverb's input format. That should make your graph initialize and run, but let me know if you managed to make the reverb node actually do something, 'cause it doesn't work for me.

like image 83
Guy Moreillon Avatar answered Oct 12 '22 10:10

Guy Moreillon