【问题标题】:Core Audio get data from AudioQueue (or AudioUnits) into memoryCore Audio 从 AudioQueue(或 AudioUnits)获取数据到内存
【发布时间】:2014-01-05 04:20:14
【问题描述】:

在核心音频方面,我完全是个菜鸟,所以请耐心等待。基本上我想做的是从机器的默认麦克风记录音频数据,记录直到用户决定停止,然后对整个记录进行一些分析。我一直在学习 Chis Adamson 和 Kevin Avila 的“Learning Core Audio”一书(这是一本很棒的书,在这里找到它:http://www.amazon.com/Learning-Core-Audio-Hands-On-Programming/dp/0321636848/ref=sr_1_1?ie=UTF8&qid=1388956621&sr=8-1&keywords=learning+core+audio)。我看到了 AudioQueue 是如何工作的,但我不确定如何获取来自缓冲区的数据并将其存储在全局数组中。

最大的问题是我不能先验分配一个数组,因为我们不知道用户想要记录多长时间。我猜想必须将一个全局数组传递给 AudioQueue 的回调,然后它会从最新的缓冲区中追加数据,但是我不确定如何执行此操作,或者这是否是这样做的正确位置.

如果使用 AudioUnits,我猜我需要创建两个音频单元,一个是远程 IO 单元来获取麦克风数据,另一个是通用输出音频单元,它将执行附加到单元中的数据(我猜在这里,真的不确定)AudioUnitRender() 函数。

如果您知道我需要在哪里做这些事情,或者知道任何可以帮助解释其工作原理的资源,那就太好了。

我最终想学习如何在 iOS 和 Mac OS 平台上执行此操作。目前我只是在 Mac OS 中工作。

【问题讨论】:

  • 是什么推动了您记录到内存中的要求?这将明确限制您可以进行的录制时间。
  • @sbooth 是的,我知道这一点。我现在并不关心它,主要原因是我想在所有收集的数据的上下文中对数据进行一些分析,而不仅仅是当前在缓冲区中的数据。

标签: ios macos core-audio audiounit audioqueueservices


【解决方案1】:

由于您知道采样率,您的应用可以在 UI 运行循环中(例如,周期性地,基于 NSTimer 或 CADisplayLink)预先分配足够数量的新缓冲区(例如,在链表中) ,然后您可以在音频队列回调期间将数据复制到其中。

还有一些异步文件写入函数可以在音频回调中安全调用。记录后,您可以将文件中的数据复制回一个现在已知大小的内存阵列(或仅映射文件)。

【讨论】:

  • 我曾想过先保存到文件,然后读取文件,但这似乎是不必要的步骤,我将尝试链接列表。
  • 不必要的:也许吧。但是你的录音时间越长,你的应用程序的内存占用就越大。在某些时候,保存录音并在内存中只保留一小部分会更有效。
【解决方案2】:

大家好,所以我找到了自己问题的答案,我只需要添加大约 10 行代码就可以让它工作。基本上我所做的是在用户数据结构中,或者苹果称之为客户端数据结构,我添加了一个变量来跟踪记录的样本总数,即采样率(这样我就可以访问内部的值回调)和一个指向音频数据的指针。在回调函数中,我为指针重新分配内存,然后将缓冲区的内容复制到新分配的内存中。

我将发布我的客户端记录器结构的代码和回调函数中的代码行。我想发布整个程序的代码,但其中大部分是从 Chis Adamson 和 Kevin Avila 的《Learning Core Audio》一书中借来的,我不想侵犯这本书所拥有的任何版权(有人可以告诉我在这里发布它是否合法?如果是,我会非常乐意发布整个程序。

客户端记录器结构代码:

//user info struct for recording audio queue callbacks
typedef struct MyRecorder{
    AudioFileID recordFile;
    SInt64 recordPacket;
    Boolean running;
    UInt32 totalRecordedSamples;
    Float32 * allData;
    Float64 sampleRate;
}MyRecorder;

这个结构体需要在程序的主循环中初始化。它看起来像这样:

MyRecorder recoder = {0};

我知道我拼错了“recorder”。

接下来,我在回调函数内部做了什么:

//now let's also write the data to a buffer that can be accessed in the rest of the program
//first calculate the number of samples in the buffer
Float32 nSamples = RECORD_SECONDS * recorder->sampleRate;
nSamples = (UInt32) nSamples;

//so first we need to reallocate memory that the recorder.allData pointer is pointing to
//pretty simple, just add the amount of samples we just recorded to the number that we already had
//to get the current total number of samples, and the size of each sample, which we get from
//sizeof(Float32).
recorder->allData = realloc(recorder->allData, sizeof(Float32) * (nSamples + recorder->totalRecordedSamples));


//now we need to copy what's in the current buffer into the memory that we just allocated
//however, rememeber that we don't want to overwrite what we already just recorded
//so using pointer arith, we need to offset the recorder->allData pointer in memcpy by
//the current value of totalRecordedSamples
memcpy((recorder->allData) + (recorder->totalRecordedSamples), inBuffer->mAudioData, sizeof(Float32) * nSamples);

//update the number of total recorded samples
recorder->totalRecordedSamples += nSamples;

当然,在我的程序结束时,我释放了 recoder.allData 指针中的内存。

另外,我在 C 方面的经验非常有限,所以如果我犯了一些错误,尤其是在内存管理方面,请告诉我。 C 中的一些 malloc、realloc、memcpy 等类型的函数让我大吃一惊。

编辑:我现在正在研究如何使用 AudioUnits 做同样的事情,完成后我会发布解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多