Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/93.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何将AUGraph的输出写入文件?_Ios_Core Audio - Fatal编程技术网

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

Ios 如何将AUGraph的输出写入文件?,ios,core-audio,Ios,Core Audio,我正在尝试编写(应该是什么)一个简单的应用程序,它在一个曲线图中有一系列音频单元,然后将输出写入一个文件。我使用AUGraphAddRenderNotify添加了一个回调。这是我的回调函数: OSStatus MyAURenderCallback(void *inRefCon, AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp

我正在尝试编写(应该是什么)一个简单的应用程序,它在一个曲线图中有一系列音频单元,然后将输出写入一个文件。我使用AUGraphAddRenderNotify添加了一个回调。这是我的回调函数:

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);
    }
}
这类工作。该文件是可播放的,我可以听到我录制的内容,但有大量的静电,使它几乎听不见

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


谢谢你的帮助。

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

以下是Apple提供的一些示例代码(该项目是PlaySequence,但不是特定于MIDI的),可能会有所帮助:

{
    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);
    }
}
{
CAStreamBasicDescription clientFormat=CAStreamBasicDescription();
ca\u require\u noerr(结果=AudioUnitGetProperty(输出单位,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_输出,0,
&客户端格式和大小),失败);
size=sizeof(clientFormat);
ca_require_noerr(结果=ExtAudioFileSetProperty(outfile、kExtAudioFileProperty_ClientDataFormat、大小和clientFormat),失败);
{
音乐时间;
AUOutputBL outputBuffer(clientFormat,numFrames);
音频时间戳;
memset(&tStamp,0,sizeof(AudioTimeStamp));
tStamp.mFlags=kAudioTimeStampSampleTimeValid;
int i=0;
int numTimesFor10Secs=(int)(10./(numFrames/srate));
做{
outputBuffer.Prepare();
AudioUnitRenderActionFlags actionFlags=0;
ca_require_noerr(结果=AudioUnitRender(outputUnit,&actionFlags,&tStamp,0,numFrames,outputBuffer.ABL()),失败);
tStamp.mSampleTime+=numFrames;
ca_require_noerr(结果=ExtAudioFileWrite(outfile,numFrames,outputBuffer.ABL()),失败);
ca_require_noerr(结果=MusicLayerGetTime(播放器和当前时间),失败);
如果(应打印和(++i%numTimesFor10Secs==0))
printf(“当前时间:%6.2f拍\n”,当前时间);
}while(currentTime
刚才我对音频单元有了顿悟,这帮助我解决了自己的问题。我对音频单元连接和渲染回调的工作方式有一个误解。我以为它们是完全不同的东西,但事实证明,连接只是渲染回调的简写

执行从音频单元A的输出到音频单元B的输入的kAudioUnitProperty_MakeConnection与对单元B的输入执行kAudioUnitProperty_SetRenderCallback以及对音频单元A的输出调用AudioUnitRender的回调函数相同

在设置渲染回调后,我通过建立连接进行了测试,渲染回调不再被调用

因此,我能够通过以下方式解决我的问题:

AURenderCallbackStruct callbackStruct = {0};
callbackStruct.inputProc = MyAURenderCallback;
callbackStruct.inputProcRefCon = mixerUnit;

AudioUnitSetProperty(ioUnit,
                     kAudioUnitProperty_SetRenderCallback,
                     kAudioUnitScope_Input,
                     0,
                     &callbackStruct,
                     sizeof(callbackStruct));
我的回调函数做了如下操作:

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回调时遇到问题。稍后我将对此进行更深入的研究,但目前我找到了一个似乎有效的解决方案。

您的AUGraph和ExtAudioFile(客户端数据格式)的格式匹配吗?还有,你需要实时记录吗?我想他们是匹配的。我使用相同的AudioStreamBasicDescription配置所有音频单元并创建文件。但我不知道如何真正检查。你知道怎么做吗?我想我会调查的。我想我不需要实时录制,但还有其他方法吗?如果我不将数据实时保存到某个位置,则数据将丢失。我相信您不需要调用
AUGraphStart
而是要在图表的开头重复调用
AudioUnitRender
。我认为实时操作的问题在于,
ExtAudioFile
的内部环形缓冲区填满并丢失数据。哦,这就是你所说的非实时。我想我确实需要它是实时的,因为我正在从麦克风录音,同时也将音频传送到扬声器。上面的代码真的有效吗?我认为它会抛出一个错误,因为您将refCon设置为“self”,然后在回调中将其转换为AUMixer。您是正确的。我稍微简化了项目中的代码。我传入了self,然后通过一个属性访问了mixerUnit。我更新了我的帖子以传入mixerUnit,它是输出单元之前的单元,我想在将其输出传递到输出单元之前将其写入文件。Ok-我想知道。您可能对我的将图形输出保存到文件的解决方案感兴趣—将renderCallback放回remoteIO实例,然后在“post_Render”阶段获取渲染数据。我不知道这是否是一个“好”的方式,但它的工作。还可以将实时保存为ACC压缩格式(耶!):您的答案肯定有效,但实际上是以破坏
AUGraph
API为代价的。请看一看,作为回答,我使用
AUGraphAddRenderNotify()
提供了一个有效的解决方案。