最近在使用React Native应用程序时,我发现需要下拉并编写一些本机代码以进行音频处理。 我有一个简单的目标:将两个音轨彼此叠加。
由于对iOS开发的了解大致为零,所以我不知道从哪里开始。 在发现AVAudioEngine之前,我尝试了很多事情-但这就是我一直在寻找的东西。 这个优雅的界面使很多时间将过时且复杂的示例代码转换成几行感觉像魔术的行。
我将在Swift中使用示例,因为哇 ,我比Objective C更喜欢它。#opinions
什么是AVAudioEngine?
从苹果文档:
一组连接的音频节点对象,用于生成和处理音频信号以及执行音频输入和输出。
您需要知道的是什么? 🖐🎤
但这确实是对正在发生的事情的很好描述。 我们创建一个AVAudioEngine
,并将一堆从AVAudioNode
继承的节点连接到它。 这些节点可能正在从文件或音频数据的缓冲区中读取。 它们也可以是效果或混音器节点。 有很多的可能性。
那CoreAudio和AUGraph呢?
好问题。 在iOS上完成的许多规范音频工作都是通过旧的健壮的CoreAudio框架完成的。 但是,随着AVAudioEngine
的扩展和改进以及CoreAudio在2018年即将弃用,如果您今天正在编写新的音频代码,那么AVAudioEngine
似乎是您的最佳选择。
示例:播放多首曲目
首先,我将提供一段代码,然后再分解示例。
请注意,这确实不是很多用于进行音频混合的代码-一项艰巨的任务。 (部分原因是因为我已经放弃了任何错误处理,但是仍然如此)。
现在对该要点进行文字说明。
从初始化的AVAudioEngine
开始,我们将AVAudioEngine
连接到引擎,并将其输出设置为audioEngine的输出。 默认情况下,这将从设备播放声音,但是,当然,它也可以连接到其他节点。 连接混音器后,我们为每个文件创建一个AVAudioPlayerNode
并将这些输出连接到混音器。 然后使用文件url创建AVAudioFile
对象, AVAudioFile
对象可以安排通过AVAudioPlayerNode
播放(这不是对文件URL的非常健壮的处理)。
请注意,这也处理了编解码器和采样率的繁琐工作,而无需我们担心。 如果您手动上调或下采样音频以进行混音,那么您将知道这可以避免进行繁重的工作。
一些小的“陷阱”:
- 在尝试安排要播放的文件之前 ,启动引擎很重要。
- 请在后台线程中完成您的工作。 🙂
- 如果您想第二次播放文件,则需要重新安排它。 如果您要循环播放音频,则可以将文件加载到缓冲区(通过
scheduleBuffer
具有选项)中或在complementHandler中处理它 - 如果您确实决定计划缓冲区,则如果决定将大文件加载到内存中而直接计划文件时看不到,则可能会遇到延迟。
同步音频文件播放
我想提到的是,在寻找如何确保音频文件以完美同步开始时,我遇到了该线程的最后一个答案。 对于我来说,执行以下操作似乎效果很好:
如果startFramePosition == nil {
audioPlayer.play(at:nil)
startFramePosition =(audioPlayer.lastRenderTime?.sampleTime)!
startTime = AVAudioTime.init(sampleTime:startFramePosition !, atRate:Double(self.mixer.rate))
}其他{
audioPlayer.play(at:startTime!)
}
该答案还有另一个建议:
如果您真的想确保自己具有完美的同步效果,则可以使用44.1kHz / 16bit的CD翻录的song.wav。
制作一个副本并将其加载到音频编辑器中,将相位反转并立即保存。
现在,当您在完全相同的startTime(当然还有相同的音量/声像设置)下安排两个版本时,您会听到— SILENCE…
如果您曾经使用音频,那是有道理的,但还是很不错的。 我喜欢使用音频的一件事是音频的强大数学特性!