在这篇文章中,我会介绍一个小型iOS程序,它可以生成一个持续的固定频率的音调,该频率由一个滑动条来调节。这个程序将会展示如何简单地通过喇叭输出自己生成的声音。
介绍
我之前写了一篇关于播放mp3或AAC格式的音频流的文章。这些文章介绍了关于采用AudioQuerer API来播放音频。AudioQueue的接口能够提取音频数据(即使是压缩格式),之后通过外放设备播放。AudioQueue API的解码能力是它的关键之处,而且采用它是唯一的方式来发挥iOS设备硬件解码的能力。
然而,如果你打算生成自定义的音频(而且它已经压缩为线性脉冲编码调制形式)的话,你不一定非要使用AudioQueue。但是现实是你将加入更多的控制而且需要做更多如果你准备利用最底层的音频API:AudioUnit,当然这里你仍然可以利用AudioQueue来播放音频。
程序实例:音调生成器
这个实例程序相当简单:一个滑块来控制频率并且一个按钮来控制播放。
这个音调是持续发声的同时你可以通过滑块调整频率让它发出哨子似的的声音来需求乐趣。
You can download the
ToneGenerator
and the complete sample project used in this post here ToneGenerator.zip (25kb)
Audio Units
AudioUnits 是iOS中最底层的声音生成器同时也是Mac中最底层的硬件抽象层。它们会生成原始音频样例并且将音频值放到输出缓冲区中。这就是它们全部的功能。
AudioUnit在它的渲染函数中生成音频样例。音频渲染函数在一个专用音频线程中来调用。
为了使代码关注AudioUnits的基础应用,我将展示如何创建单独的AudioUnit而且仅仅使用它来输出声音。虽然传统的方法是将AudioUnits作为AUGraph的一部分来使用,AUGraph串联一系列不同的单元来丰富声音数据,添加混响效果等等。也许在将来我可以在这里讲述更多但是现在,我们的目标就是使事情变得简单。
生成自定义的音频样例
生成音频样例意味着我们必须以特定的时间间隔计算出音频波形的值(采样点)。
在示例程序中,我们将使用32位float型数据来表示每一个采样值。这只是为了方便,这样的格式并不是iOS中最好的格式,该格式是8.24有符号定点采样(每个采样点32bits,24bits代表小数部分)。但是在这个示例程序中,方便性比不成熟的效率更重要。
采样值可以在-1到+1之间,但是程序会将采样值限制在一个更小的范围之内。
我们利用一个基本的正弦波来生成音调。每一个采样点的值通过下面的等式来决定:
f(n) = a sin ( θ(n) )
n代表当前采样的序号,a是幅度,当前的波形的相位θ(n)是:
θ(n) = 2π? n / r
f代表音调频率,r是音频的采样率
在AudioUnit的渲染函数中实现这一些,得到的函数如下所示: