我正在尝试编写(应该是什么)一个简单的应用程序,它在AUGraph中按顺序包含一堆音频单元,然后将输出写入文件。我使用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);
}
}
这种作品。该文件是可播放的,我可以听到我录制的内容,但是有大量静电使其几乎听不见。
有人知道这有什么问题吗?或者有没有人知道将AUGraph输出记录到文件的更好方法?
感谢您的帮助。
答案 0 :(得分:6)
我刚才有关于Audio Units的顿悟,这帮助我解决了自己的问题。我对音频单元连接和渲染回调的工作方式存在误解。我认为它们是完全不同的东西,但事实证明连接只是渲染回调的简写。
从音频单元A的输出到音频单元B的输入执行kAudioUnitProperty_MakeConnection与在单元B的输入上执行kAudioUnitProperty_SetRenderCallback并使回调函数在音频单元A的输出上调用AudioUnitRender相同。
我在设置渲染回调后通过make连接测试了这个,并且不再调用渲染回调。
因此,我能够通过以下方式解决我的问题:
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回调问题。我稍后会深入研究这个问题,但现在我找到了一个似乎有效的解决方案。
答案 1 :(得分:1)
以下是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, ¤tTime), fail);
if (shouldPrint && (++i % numTimesFor10Secs == 0))
printf ("current time: %6.2f beats\n", currentTime);
} while (currentTime < sequenceLength);
}
}
答案 2 :(得分:0)
也许试试这个。将数据从音频单元回调复制到长缓冲区。播放缓冲区进行测试,然后在验证整个缓冲区正常后将整个缓冲区写入文件。