Swift 中的 AudioUnitRender 和 ExtAudioFileWrite 错误 -50:尝试将 MIDI 转换为音频文件
AudioUnitRender and ExtAudioFileWrite error -50 in Swift: Trying to convert MIDI to Audio File
我正在尝试将 MIDI 文件转换为 Swift 中的音频文件 (.m4a)。
现在我正在使用 MIKMIDI as a tool to sequence and playback MIDI files, however it does not include the ability to save the playback into a file. MIKMID's creator outlines the process to do this here. In an attempt to capture and save the output to an audio file, I've followed this example 尝试将 MIKMIDI Graph 的 RemoteIO 节点替换为 Swift 中的 GeneralIO 节点。当我尝试使用 AudioUnitRender 和 ExtAudioFileWrite 将输出保存到文件时,它们都 return error -50 (kAudio_ParamError).
var channels = 2
var buffFrames = 512
var bufferList = AudioBufferList.allocate(maximumBuffers: 1)
for i in 0...bufferList.count-1{
var buffer = AudioBuffer()
buffer.mNumberChannels = 2
buffer.mDataByteSize = UInt32(buffFrames*sizeofValue(AudioUnitSampleType))
buffer.mData = calloc(buffFrames, sizeofValue(AudioUnitSampleType))
bufferList[i] = buffer
result = AudioUnitRender(generalIOAudioUnit, &flags, &inTimeStamp, busNum, UInt32(buffFrames), bufferList.unsafeMutablePointer)
inTimeStamp.mSampleTime += 1
result = ExtAudioFileWrite(extAudioFile, UInt32(buffFrames), bufferList.unsafeMutablePointer)
}
是什么导致错误 -50,我该如何解决它以将 MIDI(离线)渲染为 .m4a 文件?
更新:我通过将 mNumberChannels 和通道更改为 = 1 解决了 ExtAudioFileWrite 错误 -50。现在我得到了一个带有噪音的一秒音频文件。 AudioUnitRender 仍然 returns 错误 -50.
您的代码有几个问题:
你的AudioBufferList
不符合客户端格式,试试
let bufferList = AudioBufferList.allocate(maximumBuffers: Int(clientFormat.mChannelsPerFrame))
您正在替换 AUGraph
中的错误节点,并将剩余的节点连接到自身,导致 AudioUnitRender
上的无限循环。
但主要问题是您没有实施 author suggested 的解决方案。你希望你可以用样本时间戳调用 AudioUnitRender
,比实时更快,但作者说不,如果你想要的话,你必须手动将样本时间转换为主机时间并实现 midi 播放器的更好部分。
所以你可以做到这一点(听起来很难),或者 file a feature request,或者在你听音乐的时候实时记录到文件中,方法是使用 AudioUnitAddRenderNotify
并在 kAudioUnitRenderAction_PostRender
阶段编写样本。
我正在尝试将 MIDI 文件转换为 Swift 中的音频文件 (.m4a)。
现在我正在使用 MIKMIDI as a tool to sequence and playback MIDI files, however it does not include the ability to save the playback into a file. MIKMID's creator outlines the process to do this here. In an attempt to capture and save the output to an audio file, I've followed this example 尝试将 MIKMIDI Graph 的 RemoteIO 节点替换为 Swift 中的 GeneralIO 节点。当我尝试使用 AudioUnitRender 和 ExtAudioFileWrite 将输出保存到文件时,它们都 return error -50 (kAudio_ParamError).
var channels = 2
var buffFrames = 512
var bufferList = AudioBufferList.allocate(maximumBuffers: 1)
for i in 0...bufferList.count-1{
var buffer = AudioBuffer()
buffer.mNumberChannels = 2
buffer.mDataByteSize = UInt32(buffFrames*sizeofValue(AudioUnitSampleType))
buffer.mData = calloc(buffFrames, sizeofValue(AudioUnitSampleType))
bufferList[i] = buffer
result = AudioUnitRender(generalIOAudioUnit, &flags, &inTimeStamp, busNum, UInt32(buffFrames), bufferList.unsafeMutablePointer)
inTimeStamp.mSampleTime += 1
result = ExtAudioFileWrite(extAudioFile, UInt32(buffFrames), bufferList.unsafeMutablePointer)
}
是什么导致错误 -50,我该如何解决它以将 MIDI(离线)渲染为 .m4a 文件?
更新:我通过将 mNumberChannels 和通道更改为 = 1 解决了 ExtAudioFileWrite 错误 -50。现在我得到了一个带有噪音的一秒音频文件。 AudioUnitRender 仍然 returns 错误 -50.
您的代码有几个问题:
你的
AudioBufferList
不符合客户端格式,试试let bufferList = AudioBufferList.allocate(maximumBuffers: Int(clientFormat.mChannelsPerFrame))
您正在替换
AUGraph
中的错误节点,并将剩余的节点连接到自身,导致AudioUnitRender
上的无限循环。
但主要问题是您没有实施 author suggested 的解决方案。你希望你可以用样本时间戳调用 AudioUnitRender
,比实时更快,但作者说不,如果你想要的话,你必须手动将样本时间转换为主机时间并实现 midi 播放器的更好部分。
所以你可以做到这一点(听起来很难),或者 file a feature request,或者在你听音乐的时候实时记录到文件中,方法是使用 AudioUnitAddRenderNotify
并在 kAudioUnitRenderAction_PostRender
阶段编写样本。