使用 AVAudioPlayer 播放带有起音/延音(循环)/衰减的声音的最佳方式
Posted
技术标签:
【中文标题】使用 AVAudioPlayer 播放带有起音/延音(循环)/衰减的声音的最佳方式【英文标题】:Best way to play a sound with an attack / sustain (loop) / decay with AVAudioPlayer 【发布时间】:2011-05-09 03:46:37 【问题描述】:我在寻找播放没有过渡中断的起音(声音开始)/延音(循环声音)/衰减(声音结束)序列的资源时遇到问题。是否有任何好的库来处理这个问题,或者我应该使用 AVAudioPlayer 自己动手? AudioQueue 是一个更好的地方吗?我曾经使用 SoundEngine.cpp,但它已经很久没有使用了。 CAF 仍然是最好的格式吗?
谢谢!
【问题讨论】:
我也有同样的问题。好几个月没问了,找到解决办法了吗? 【参考方案1】:根据您的描述,听起来好像您正在尝试编写软件合成器。您可以将AVAudioPlayer
用于此类操作的唯一方法是将音符的整个持续时间组合为单个 WAV 文件,然后使用AVAudioPlayer
播放整个内容。
要创建任意持续时间的音符声音,即响应用户操作(如点击按钮)开始播放,然后继续播放直到第二次用户操作(如点击“停止”按钮或松开手指)第一个按钮)开始将循环区域的音量降低到零的过程(“释放”部分),您需要使用AudioQueue
(AVAudioPlayer
可用于播放完全在内存中构建的音频,但整个必须在播放开始之前构建播放,这意味着您无法更改正在播放的内容以响应用户操作 [除了停止播放])。
这里是another question/answer,它简单地展示了如何使用AudioQueue
。 AudioQueue
在需要加载更多数据来播放时调用回调方法 - 您必须实现循环和信封包装原始 WAV 文件数据的所有代码。
【讨论】:
我不知道操作,但就我而言,它是用于游戏的背景音乐。我需要起音,因为音乐有前奏,然后在前奏之后它应该继续循环延音。为了避免更大的内存占用,我想使用 AVAudioPlayer 流式传输音乐(大约需要 10 MB,而我的游戏已经需要太多内存)。我目前的问题是,当我使用 AVAudioPlayer 播放声音时,它有很大的延迟(比如 200 毫秒),即使我之前已经调用过 prepareToPlay,这也会在起音和延音之间留下不希望的间隙。 @fbafelipe:AudioQueue
几乎可以肯定是您想要的方式。它比 AVAudioPlayer 使用起来更复杂(尤其是因为主要教程包括 C++),但也更强大和灵活。我一直想好好学习 AQ,因为它是我非常熟悉的 waveOut...win32 API 的 ios 版本。一旦你学会了如何在内存中创建音频并使用像 AudioQueue 这样的低级 API 播放它,它就会打开一个充满编程可能性的世界。它还倾向于暴露出更高级别的 API 在幕后实际上做了多少。
但是 AudioQueue 可以流式传输音频吗?我目前正在使用 OpenAL 来制作音效和背景音乐,我想保留 OpenAL 来制作效果,但流式传输音乐以节省内存。
AQ 可以流式传输音频,但我认为 OpenAL 也可以。我认为您可以使用 OpenAL 做您需要的事情,但我不确定 - 我对它不是很熟悉。
我可以使用 OpenAL 进行流式传输,但我需要自己读取缓冲区并提供 OpenAL。使用 AVAudioPlayer,我只需打开文件,它就会为我流式传输。好吧,我想我将不得不使用 OpenAL 实现流式传输。感谢您的帮助。【参考方案2】:
创建自己的包络生成器非常简单。困难的部分是更新您的程序以使用较低级别的音频服务,以便直接改变信号。
为此,您需要:
音频文件的样本 设置 AudioQueue(这是一种方法,但我会采用它,因为它在 OP 中提到,它是用户提供的样本缓冲区的相对高级 API) 向队列提供信号 确定您的程序是最好的实时还是预渲染实时
允许实时变化 管理您的循环点 管理您的渲染位置 能够根据您正在读取的样本位置范围确定要应用的幅度或
预渲染
可能需要更多内存 需要更少的 CPU 将信封应用到您的样本缓冲区副本 管理您的渲染位置我还假设您只需要缓慢/简单的过渡。如果你想要一些疯狂/快速的 LFO,没有混叠,你将有更多的工作要做。除非您的更改过于突然,否则这种方法不应产生可听见的混叠:
编写简单的包络发生器 (EG) 很容易;如果您需要朝那个方向推进,请查看 Apple 的 SinSynth 以获得非常基本的 EG。
【讨论】:
以上是关于使用 AVAudioPlayer 播放带有起音/延音(循环)/衰减的声音的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章
如何使用远程推送通知触发 AVAudioPlayer 播放?
如何使用 swift 显示带有进度条的 AVAudioPlayer?