如何使用OpenAL从iOS的声音时间轴导出声音

时间:2011-04-02 18:43:14

标签: iphone objective-c ios openal

我不确定是否有可能达到我想要的效果,但基本上我有一个代表录音的NSDictionary。这是在什么时间点播放声音id的时间线。

我拥有它可以播放这个时间轴/录音,而且效果很好。

我想知道是否还有这个时间轴,并将其导出为单个声音,如果设备与iTunes同步,可以将其保存到计算机中。

所以基本上我问我是否可以采用声音的时间轴,播放它并将这些声音拼接成一个声音,然后可以导出。

我使用OpenAL作为我的声音框架,声音文件都是CAF。

感谢任何帮助或指导。

谢谢!

2 个答案:

答案 0 :(得分:1)

您将需要:

  • 很好地理解线性PCM音频格式(参见Wikipedia's Linear PCM page)。
  • 很好地理解音频采样率和一些基本数学,将您的时间转换为样本偏移。
  • 了解two's-complement二进制数(有符号/无符号,16位,32位等)如何存储在计算机中,以及处理器的endian-ness如何影响这一点。< / LI>
  • 耐心,对学习的兴趣,以及使这项工作充满活力的强烈愿望。

以下是该做什么:

  1. 在您的应用中启用文件共享(info.plist中为UIFileSharingEnabled=YES,并将文件写入/Documents目录)。

  2. 将使用过的声音渲染到包含线性PCM音频数据的内存缓冲区中(如果它们尚未存在,即如果它们已被压缩)。您可以使用音频队列的离线渲染功能执行此操作(请参阅Apple audio queue docs)。如果你将它们全部渲染到相同的PCM格式和采样率(例如16位带符号样本@ 44,100Hz,我会在所有示例中使用这种格式),它会使事情变得更容易很多,并使用相同的格式输出。我建议从Mono格式开始,然后在它工作后添加立体声。

  3. 选择未压缩的输出格式并将声音混合到一个流中:

    3.1。分配足够大的缓冲区,或打开要写入的文件流。

    3.2。写出任何标题(例如,如果使用WAV格式输出而不是原始PCM)并在第一个声音开始之前写入零(或样本范围的中间点,如果不使用带符号的样本格式)进行任何初始静音。例如,如果你想在第一个声音之前静音0.1秒,写入4410(0.1 * 44100)零样本,即写入4410短路(16位)全部为零。

    3.3。现在跟踪所有“正在播放”的声音并将它们混合在一起。从一个空的“当前正在播放的声音”列表开始,并跟踪您正在混音的样本的“当前时间”,对于您写出的每个样本,将“当前时间”增加1.0/sample_rate。当有时间开始另一个声音时,将其添加到“当前正在播放”列表中,样本偏移为0.现在要进行混音,您将遍历所有“当前正在播放”的声音并将其当前样本加在一起,然后增加每个样本的样本偏移量。将求和值写入输出缓冲区。例如,如果soundA从0.1秒开始(在静音之后)并且soundB从0.2秒开始,则对于样本8820,您将执行相当于output[8820] = soundA[4410] + soundB[0];的操作,对于样本8821,您将执行output[8821] = soundA[4411] + soundB[1];等等。作为声音结束(你到达其样本的末尾)只需将其从“当前播放”列表中删除,并继续直到音频数据结束。

    3.4。上述简单混合(样本总和)确实存在一些问题。例如,如果两个样本的值加起来大于32767,则不能将其存储在有符号的16位数中,这称为剪切。现在,只需将值钳位到32767,然后使其工作......稍后再回来并实现一个简单的限制器(参见最后的说明)。

  4. 现在您的音轨的混合版本采用未压缩的线性PCM格式,这可能已足够,因此请将其写入/Documents。如果您想以压缩格式编写它,您需要获取音频编码器的源并通过它运行线性PCM输出。

  5. 简单限制器:

    让我们选择限制样本范围的前10%,因此如果绝对值大于29490(int limitBegin = (int)(32767 * 0.9f);),我们将缩小该值。最大可能峰值为int maxSampleValue = 32767 * numPlayingSounds;,我们希望将值limitBegin以上的值扩展到32767处的峰值。因此,根据上述非常简单的混频器求和到sampleValue,然后:< / p>

    if(sampleValue > limitBegin)
    {
        float overLimit = (sampleValue - limitBegin) / (float)(maxSampleValue - limitBegin);
        sampleValue = limitBegin + (int)(overLimit * (32767 - limitBegin));
    }
    

    如果您正在注意,您会注意到当numPlayingSounds发生变化时(例如当新声音开始时),限制器变得更加(或更少)刺耳,这可能会导致音量突然变化(在有限的范围内)以适应额外的声音。您可以使用最大数量的播放声音,或设计一些巧妙的方法来在几毫秒内提升限制器。

    请记住,这是以sampleValue的绝对值运行(在签名格式中可能是负数),因此这里的代码只是为了演示这个想法。您需要正确编写它以处理样品范围两端(峰值和谷值)的限制。此外,在混音过程中你可以采取一些技巧来优化上述所有内容 - 你可能会在编写混音器时发现它们,小心并让它先工作,然后再根据需要重新进行重构/优化。

    还要记住要考虑正在使用的平台的字节序以及要写入的文件格式,因为您可能需要进行一些字节交换。

答案 1 :(得分:0)

如果您的文件以简单格式存储,那么一种不太难的方法就是手动将它们组合在一起。也就是说,使用caf格式创建一个新文件,并手动将所需的部分组合在一起。

如果声音未压缩(线性PCM),这将非常简单。但是,请在这里阅读caf文件格式的文件:

http://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/CAFSpec/CAF_spec/CAF_spec.html#//apple_ref/doc/uid/TP40001862-CH210-SW1