Cocoa 音频单元:将生成的音频放入渲染回调

Cocoa 音频单元:将生成的音频放入渲染回调,cocoa,audio,core-audio,audiounit,Cocoa,Audio,Core Audio,Audiounit,我一直试图通过在音频单元的输入端附加一个aundercallbackstruct来操纵kAudioUnitType_生成器音频单元生成的样本,但没有成功。我通过以下简单的图表在OS X上实现了这一点: (input callback) -> multichannel mixer -> (intput callback) -> default output 但我在以下(更简单的)从发电机组开始的图表中失败了: speech synthesis -> (intput cal

我一直试图通过在音频单元的输入端附加一个aundercallbackstruct来操纵kAudioUnitType_生成器音频单元生成的样本,但没有成功。我通过以下简单的图表在OS X上实现了这一点:

(input callback) -> multichannel mixer -> (intput callback) -> default output
但我在以下(更简单的)从发电机组开始的图表中失败了:

speech synthesis -> (intput callback) -> default output           | fails in render callback with kAudioUnitErr_Uninitialized
audiofile player -> (intput callback) -> default output           | fails when scheduling file region with kAudioUnitErr_Uninitialized
我尝试了我能想到的一切,从设置ASBD格式到采样率,但我总是遇到这些错误。有人知道如何建立一个图表,我们可以从这些漂亮的发电机组中操作样本吗

下面是尝试使用语音合成时失败的渲染回调函数和图形实例化方法。当然,除了设置文件播放之外,音频文件播放器在这方面几乎相同。如果我移除回调并在其位置添加一个AUGraphConnectNodeInput,这两种设置都可以工作

static OSStatus RenderCallback(void *inRefCon,
                                    AudioUnitRenderActionFlags *ioActionFlags,
                                    const AudioTimeStamp *inTimeStamp,
                                    UInt32 inBusNumber,
                                    UInt32 inNumberFrames,
                                    AudioBufferList *ioData) {

    AppDelegate *app = (AppDelegate *)inRefCon;
    AudioUnit inputUnit = app->_speechUnit;
    OSStatus status = noErr;

    status = AudioUnitRender(inputUnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);
    // *** ERROR *** kAudioUnitErr_Uninitialized, code: -10867

    // ... insert processing code here...

    return status;
}

- (int)createSynthGraph {
    AUGRAPH_CHECK( NewAUGraph( &_graph ) );

    AUNode speechNode, outputNode;

    // speech synthesizer
    AudioComponentDescription speechCD = {0};
    speechCD.componentType = kAudioUnitType_Generator;
    speechCD.componentSubType = kAudioUnitSubType_SpeechSynthesis;
    speechCD.componentManufacturer = kAudioUnitManufacturer_Apple;

    // output device (speakers)
    AudioComponentDescription outputCD = {0};
    outputCD.componentType = kAudioUnitType_Output;
    outputCD.componentSubType = kAudioUnitSubType_DefaultOutput;
    outputCD.componentManufacturer = kAudioUnitManufacturer_Apple;

    AUGRAPH_CHECK( AUGraphAddNode( _graph, &outputCD, &outputNode ) );
    AUGRAPH_CHECK( AUGraphAddNode( _graph, &speechCD, &speechNode ) );

    AUGRAPH_CHECK( AUGraphOpen( _graph ) );
    AUGRAPH_CHECK( AUGraphNodeInfo( _graph, outputNode, NULL, &_outputUnit ) );
    AUGRAPH_CHECK( AUGraphNodeInfo( _graph, speechNode, NULL, &_speechUnit ) );

    // setup stream formats:
    AudioStreamBasicDescription streamFormat = [self streamFormat];
    AU_CHECK( AudioUnitSetProperty( _speechUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, sizeof(streamFormat) ) );

    // setup callback:
    AURenderCallbackStruct callback;
    callback.inputProc = RenderCallback;
    callback.inputProcRefCon = self;
    AUGRAPH_CHECK( AUGraphSetNodeInputCallback ( _graph, outputNode, 0, &callback ) );

    // init and start
    AUGRAPH_CHECK( AUGraphInitialize( _graph ) );
    AUGRAPH_CHECK( AUGraphStart( _graph ) );
    return 0;
}

必须使用
AUGraphConnectNodeInput
将这些节点连接在一起。除非音频单元已连接,
AUGraph
将不会初始化其中的音频单元。图形中未连接到其他单元的单元将不会初始化


您也可以尝试在启动图表之前手动初始化它们。

kAudioUnitErr\u音频单元未初始化时出现未初始化错误。在设置问题属性之前,只需初始化图形。这将初始化图形中所有打开的音频单元。从AUGraph.h中的AUGraph初始化讨论:

对每个打开的节点/音频单元调用AudioUnitInitialize() (准备渲染)和子图中涉及的 互动


问题:为什么要挂接渲染回调,而不是使用
AUGraphConnectNodeInput
将这些节点连接在一起?在渲染回调中,您似乎没有做任何比仅仅通过语音单元的渲染更有趣的事情。在它工作之前,您不能做任何事情。:)我在上面的回调中添加了一条评论,以表明我的意图。哦,我明白了。。。马上回答…谢谢你的建议。然而,这似乎不是真的,因为正如我在上面所写的,我能够正确地运行一个图形,该图形具有一个混音器作为它的第一个音频单元(当然,前提是有一个额外的输入回调来为它提供样本)。此代码使用了两次AUGraphSetNodeInputCallback,但没有使用AUGraphConnectNodeInput@iluvcapra,您建议使用什么方法手动初始化单元/节点?不要初始化图形,而是直接使用
AudioUnitInitialize()
初始化单元。我认为你在这里做的事情根本不需要图形。我已经让它在没有图形的情况下工作,但我想把它作为一个选项来探索,因为图形为你提供了额外的运行时修改功能,比如交换连接等。