Swift中的AudioUnitRender和ExtAudioFileWrite错误-50:尝试将MIDI转换为音频文件

时间:2016-09-03 18:21:10

标签: ios audio core-audio audiobuffer mikmidi

我正在尝试将MIDI文件转换为Swift中的音频文件(.m4a)。

现在我正在使用MIKMIDI作为排序和播放MIDI文件的工具,但它不包括将播放保存到文件中的功能。 MIKMID的创建者概述了执行此操作的过程here。为了捕获并将输出保存到音频文件,我跟着this example尝试用Swift中的GeneralIO节点替换MIKMIDI Graph的RemoteIO节点。当我尝试使用AudioUnitRender和ExtAudioFileWrite将输出保存到文件时,它们都返回错误-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文件?

UPDATE :我已经通过将mNumberChannels和channel更改为= 1来解决ExtAudioFileWrite错误-50。现在我得到一个带噪声的一秒音频文件。 AudioUnitRender仍会返回错误-50。

1 个答案:

答案 0 :(得分:1)

您的代码存在一些问题:

  1. 您的AudioBufferList不同意客户格式,请尝试

    let bufferList = AudioBufferList.allocate(maximumBuffers: Int(clientFormat.mChannelsPerFrame)) 
    
  2. 您正在从AUGraph替换错误的节点,并将剩余的节点连接到自身,导致AudioUnitRender上出现无限循环。

  3. 但主要问题是您没有实施author suggested的解决方案。您希望可以使用示例时间戳调用AudioUnitRender,比实时更快,但作者说不,您必须手动将采样时间转换为主机时间,并在需要时实现midi播放器的更好部分。

    所以你可以这样做(听起来很难),或file a feature request,或者可以通过向图形的远程IO音频单元添加渲染通知来监听音乐来实时录制文件{{1}并在AudioUnitAddRenderNotify阶段写下样本。