0

我有一个应用程序,其中有一组大约 50 个声音,长度范围从大约 300 毫秒到大约 4 秒。需要在精确的时间播放各种声音组合(一次最多可以触发 10 个)。有些声音需要以短至 100 毫秒的间隔重复。

我已经将其实现为 AVAudioPlayers 的二维数组,所有这些都在应用程序启动时加载了声音。每个声音有几个播放器,以适应快速重复的声音。特定声音的播放器在严格轮换中重复使用。当安排了新的声音时,该声音的最旧播放器将停止并且其当前时间设置为 0,因此声音将从头开始重复,下次使用 player.play(atTime:) 进行安排。有一个线程可以在播放新声音之前大约 300 毫秒安排新的声音集。

这一切都很好,直到某个点因设备而异。最终,随着声音播放得更快,和/或安排了更多同时的声音,一些声音将拒绝播放。

我正在考虑使用混合器节点切换到 AVAudioEngine 和 AVAudioPlayerNodes。有谁知道这种方法是否可以处理更多的同时声音?我的猜测是,这两种方法都转化为一组相当相似的 CoreAudio 函数,但我实际上并没有编写代码来测试这个假设——在我这样做之前,我希望其他人可能在我之前探索过这个问题。我之前对CoreAudio很深入,我希望能够使用这些方便的高级功能来代替!

另外,有没有人知道当声音开始时触发关闭的方法?记录的功能允许回调关闭,但我能够在声音开始时触发事件的唯一方法是为 DispatchQueue 创建一个高质量的服务队列。不幸的是,根据系统负载,排队事件的执行时间可能与预定时间相差最多约 50 毫秒,这并不像我希望的那样精确。

4

1 回答 1

2

将 AVAudioEngine 与 AVAudioPlayersNodes 一起使用可以提供更好的性能,尽管代价是一些代码复杂性。通过更好的缓冲控制,我能够轻松地将播放速率提高五倍。

切换到这种方法的主要缺点是 Apple 的文档不够出色。在 Apple 的文档中添加一些内容会使这项任务变得容易得多:

混音器节点被记录为能够转换采样率和通道数,因此我尝试配置 audioEngine.mainMixerNode 以将单声道缓冲区转换为输出节点的设置。将主混音器节点的输出设置为输出节点的格式似乎是可以接受的,但在运行时抛出了不透明的错误,抱怨通道数不匹配。

看起来主混合器节点实际上并不是一个功能齐全的混合器节点。为了让它工作,我必须插入另一个执行通道转换的混音器节点,并将其连接到主混音器节点。如果 Apple 的文档中确实提到了这一点,它会为我节省大量的实验。

此外,仅调度缓冲区不会导致任何播放。在发生任何事情之前,您需要在播放器节点上调用 play()。Apple 的文档在这里令人困惑——它说不带参数调用 play() 会导致立即播放,这不是我想要的。需要一些实验来确定 play() 只是告诉播放器节点唤醒,并且预定的缓冲区实际上将在预定的时间播放,而不是立即播放。

如果 Apple 提供的不仅仅是自动生成的类文档,那将会非常有帮助。一些人工生成的文档会为我节省大量令人沮丧的实验。

当我使用 Core Audio 时,Chris Adamson 写得很好的“Learning Core Audio”非常有帮助——很遗憾,新的 AVAudioEngine 功能几乎没有被记录。

于 2020-05-02T17:42:04.770 回答