首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将AUGraph的输出写入文件?

如何将AUGraph的输出写入文件?
EN

Stack Overflow用户
提问于 2012-01-21 15:35:56
回答 3查看 5.4K关注 0票数 5

我正在尝试编写(应该是)一个简单的应用程序,它在AUGraph中有一堆顺序的音频单元,然后将输出写入一个文件。我使用AUGraphAddRenderNotify添加了一个回调。下面是我的回调函数:

代码语言:javascript
复制
OSStatus MyAURenderCallback(void *inRefCon,
                        AudioUnitRenderActionFlags *actionFlags,
                        const AudioTimeStamp *inTimeStamp,
                        UInt32 inBusNumber,
                        UInt32 inNumberFrames,
                        AudioBufferList *ioData) {
    if (*actionFlags & kAudioUnitRenderAction_PostRender) {
        ExtAudioFileRef outputFile = (ExtAudioFileRef)inRefCon;
        ExtAudioFileWriteAsync(outputFile, inNumberFrames, ioData);
    }
}

这是一种可行的方法。该文件是可播放的,我可以听到我录制的内容,但有可怕的静电,使它几乎听不见。

有人知道这是怎么回事吗?或者,是否有人知道更好的方法来将AUGraph输出记录到文件中?

谢谢你的帮助。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-01-26 10:58:15

我刚刚对音频单元有了一个顿悟,这帮助我解决了自己的问题。我对音频单元连接和渲染回调的工作方式有误解。我以为它们是完全不同的东西,但事实证明,连接只是渲染回调的缩写。

从音频单元A的输出到音频单元B的输入执行kAudioUnitProperty_MakeConnection与在单元B的输入上执行kAudioUnitProperty_SetRenderCallback并使回调函数在音频单元A的输出上调用AudioUnitRender相同。

在设置渲染回调之后,我通过执行make connection来测试这一点,渲染回调不再被调用。

因此,我能够通过执行以下操作解决我的问题:

代码语言:javascript
复制
AURenderCallbackStruct callbackStruct = {0};
callbackStruct.inputProc = MyAURenderCallback;
callbackStruct.inputProcRefCon = mixerUnit;

AudioUnitSetProperty(ioUnit,
                     kAudioUnitProperty_SetRenderCallback,
                     kAudioUnitScope_Input,
                     0,
                     &callbackStruct,
                     sizeof(callbackStruct));

我的回调函数做了这样的事情:

代码语言:javascript
复制
OSStatus MyAURenderCallback(void *inRefCon,
                        AudioUnitRenderActionFlags *actionFlags,
                        const AudioTimeStamp *inTimeStamp,
                        UInt32 inBusNumber,
                        UInt32 inNumberFrames,
                        AudioBufferList *ioData) {

    AudioUnit mixerUnit = (AudioUnit)inRefCon;

    AudioUnitRender(mixerUnit,
                    actionFlags,
                    inTimeStamp,
                    0,
                    inNumberFrames,
                    ioData);

    ExtAudioFileWriteAsync(outputFile, 
                           inNumberFrames, 
                           ioData);

    return noErr;
}

这对我来说可能是显而易见的,但既然不是这样,我打赌还有其他人也以同样的方式感到困惑,所以希望这对他们也有帮助。

我仍然不确定为什么我在使用AUGraphAddRenderNotify回调时会遇到问题。我稍后会更深入地研究这个问题,但现在我找到了一个似乎可行的解决方案。

票数 6
EN

Stack Overflow用户

发布于 2012-01-23 21:44:39

下面是来自苹果的一些示例代码(该项目是PlaySequence,但它不是特定于MIDI的),它们可能会有所帮助:

代码语言:javascript
复制
{
    CAStreamBasicDescription clientFormat = CAStreamBasicDescription();
    ca_require_noerr (result = AudioUnitGetProperty(outputUnit,
                                                    kAudioUnitProperty_StreamFormat,
                                                    kAudioUnitScope_Output, 0,
                                                    &clientFormat, &size), fail);
    size = sizeof(clientFormat);
    ca_require_noerr (result = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat), fail);

    {
        MusicTimeStamp currentTime;
        AUOutputBL outputBuffer (clientFormat, numFrames);
        AudioTimeStamp tStamp;
        memset (&tStamp, 0, sizeof(AudioTimeStamp));
        tStamp.mFlags = kAudioTimeStampSampleTimeValid;
        int i = 0;
        int numTimesFor10Secs = (int)(10. / (numFrames / srate));
        do {
            outputBuffer.Prepare();
            AudioUnitRenderActionFlags actionFlags = 0;
            ca_require_noerr (result = AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, outputBuffer.ABL()), fail);

            tStamp.mSampleTime += numFrames;

            ca_require_noerr (result = ExtAudioFileWrite(outfile, numFrames, outputBuffer.ABL()), fail);    

            ca_require_noerr (result = MusicPlayerGetTime (player, &currentTime), fail);
            if (shouldPrint && (++i % numTimesFor10Secs == 0))
                printf ("current time: %6.2f beats\n", currentTime);
        } while (currentTime < sequenceLength);
    }
}
票数 1
EN

Stack Overflow用户

发布于 2012-01-22 03:32:48

也许你可以试试这个。将音频单元回调中的数据复制到长缓冲区。播放缓冲区以对其进行测试,然后在验证整个缓冲区正常后将整个缓冲区写入文件。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8951458

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档