Macos 如何使用audioConverterFillComplexBuffer及其回调?

Macos 如何使用audioConverterFillComplexBuffer及其回调?,macos,core-audio,Macos,Core Audio,我需要一个关于如何使用audioConverterFillComplexBuffer及其回调的逐步演练。不,别让我看苹果的文档。我照他们说的做,转换总是失败。不,不要告诉我去寻找audioConverterFillComplexBuffer及其回调在使用中的示例-我已经复制了十几个这样的示例,包括逐行和修改,转换总是失败。不,输入数据没有任何问题。不,这不是endian的问题。不,问题不是我的OS X版本 问题是我不明白audioConverterFillComplexBuffer是如何工作的,

我需要一个关于如何使用audioConverterFillComplexBuffer及其回调的逐步演练。不,别让我看苹果的文档。我照他们说的做,转换总是失败。不,不要告诉我去寻找audioConverterFillComplexBuffer及其回调在使用中的示例-我已经复制了十几个这样的示例,包括逐行和修改,转换总是失败。不,输入数据没有任何问题。不,这不是endian的问题。不,问题不是我的OS X版本

问题是我不明白audioConverterFillComplexBuffer是如何工作的,所以我不知道我做错了什么。没有任何东西能帮助我理解,因为似乎地球上也没有人真正理解audioConverterFillComplexBuffer是如何工作的。从实际使用它的人(我在他们的代码中间谍货物崇拜编程)到学习核心音频和/或苹果本身的作者(http://stackoverflow.com/questions/13604612/core-audio-how-can-one-packet-one-byte-when-clearly-one-packet-4-bytes)

这不仅是我的问题,也是任何想在Mac平台上编程高性能音频的人的问题。显然是错误的陈腐文档和不起作用的示例毫无乐趣


再说一次,我需要一步一步地演练如何使用audioConverterFillComplexBuffer及其回调,整个Mac开发者社区也是如此

这是一个非常古老的问题,但我认为仍然相关。我花了几天的时间来解决这个问题,最终实现了成功的转化。我当然不是专家,但我将概述我对其工作原理的理解。请注意,我正在使用Swift,这也是我正在学习的

以下是主要函数参数:

inAudioConverter:AudioConverterRef
:这一个非常简单,只需传入以前创建的AudioConverterRef

inInputDataProc:AudioConverter ComplexInputDataProc
:非常复杂的回调。我们将回到这个话题

inInputDataProcUserData,UnsafemtableRawPointer?
:这是对可能需要提供给回调函数的任何数据的引用。重要的是,即使在swift中,回调也不能继承上下文。例如,您可能需要访问AudioFileID或跟踪到目前为止读取的数据包数量

ioOutputDataPacketSize:UnsafeMutablePointer
:这个有点误导。名称意味着它是数据包大小,但阅读文档意味着我们了解到它是输出格式预期的数据包总数。您可以将其计算为
outPacketCount=frameCount/outStreamDescription.mFramesPerPacket

outOutputData:UnsafeMutablePointer
:这是一个音频缓冲区列表,您需要用足够的空间初始化该列表以保存预期的输出数据。大小可以计算为
byteSize=outPacketCount*outMaxPacketSize

outPacketDescription:UnsafeMutablePointer?
:这是可选的。如果需要数据包描述,请传入一块大小为
outPacketCount*sizof(AudioStreamPacketDescription)
的内存


当转换器运行时,它将重复调用回调函数以请求更多数据进行转换。回调的主要任务只是从源数据中读取请求的数字数据包。然后转换器将数据包转换为输出格式并填充输出缓冲区。以下是回调的参数:

音频转换器:音频转换器ref
:再次打开音频转换器。你可能不需要用这个

ioNumberDataPackets:UnsafeMutablePointer
:要读取的数据包数。读取后,必须将其设置为实际读取的数据包数(如果到达末尾,可能会小于请求的数据包数)

ioData:UnsafeMutablePointer
:已配置的音频缓冲区列表,实际数据除外。您需要以足够的容量初始化ioData.mBuffers.mData,以容纳预期数量的数据包,即
ioNumberDataPackets*inMaxPacketSize
。将ioData.mBuffers.mDataByteSize的值设置为匹配

outDataPacketDescription:UnsafeMutablePointer?
:根据使用的格式,转换器可能需要跟踪数据包描述。您需要用足够的容量初始化它,以容纳预期数量的数据包描述

inUserData:UnsafeMutableRawPointer?
:提供给转换器的用户数据


因此,要开始,您需要:

  • 有足够的关于输入和输出数据的信息,即帧数和最大数据包大小
  • 初始化具有足够容量的AudioBufferList以保存输出数据
  • 调用音频转换器FillComplexBuffer
  • 在每次运行回调时,您需要:

  • 初始化
    ioData
    ,使其具有足够的容量来存储源数据的
    ioNumberDataPackets
  • 初始化
    outDataPacketDescription
    ,使其具有足够的容量来存储音频流packetdescription的
    ioNumberDataPackets
  • 用源数据包填充缓冲区
  • 写下数据包描述
  • ioNumberDataPackets
    设置为实际读取的数据包数
  • 如果成功,返回
    noErr
  • 以下是我从AudioFileID读取数据的示例:

    var转换器:AudioConverterRef?
    //用户数据保存AudioFileID、输入最大数据包大小和读取的数据包计数
    var uData=(fRef,maxPacketSize,UnsafeMutablePointer.allocate(容量:1))
    err=音频转换器新建(&inStreamDesc,&outStreamDesc,&converter)
    err=AudioConverterFillComplexBuffer(转换器!,{u0,ioNumberDataPackets