5

我正在尝试将 AudioUnit 类型添加kAudioUnitSubType_Reverb2到 anAUGraph并且-10868 (kAudioUnitErr_FormatNotSupported)AUGraphInitialize. 我的出发点是 Apple 的 iPhoneMixerEQGraphTest 示例应用程序,我基本上只是为混响添加了一个新的 AudioUnit,但无法让它工作。

这是代码 -

- (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);
}
4

1 回答 1

4

出于某种原因,一些 AU 节点默认采用浮点流格式,而另一些则采用整数。如果流格式不匹配,则会出现此错误。因此,您需要在均衡器节点和混响节点之间添加一个格式转换器:

    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);

确保将转换器节点输入的流格式设置为均衡器节点输出的格式:

    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);

对转换器的输出做同样的事情,用混响的输入格式设置它。那应该使您的图形初始化并运行,但是如果您设法使混响节点实际执行某些操作,请告诉我,因为它对我不起作用。

于 2012-06-21T07:08:59.633 回答