iOS的AVAudioUnit提供的音效包括:混响、延迟、均衡器、失真、变速、变调等。按照类型划分为Audio Effect和Time Effect,其中Audio Effect包括混响、延迟、均衡器和失真,而Time Effect主要是变速、变调。
一、音效应用层框架
音效的应用层框架以AVAudioUnit作为核心抽象类,如下图所示:
二、音效HAL层
1、音效与HAL层关系图
音效的HAL硬件抽象层属于CoreAudio框架,而AUHAL即AudioUnit的HAL层,用于连接I/O Kit与Mixer Unit的桥梁。如下图所示:
2、音效HAL层核心类
音效硬件抽象层的相关头文件如下:
-
AUComponent.h
: 定义AudioUnit类型. AudioComponent.h
: 定义音频组件的接口.AudioOutputUnit.h
: 定义输出单元开关的接口.AudioUnit.h
: 涵盖AudioUnit框架类.AudioUnitParameters.h
: 预定义AudioUnit的参数常量.AudioUnitProperties.h
: 预定义AudioUnit的属性类型.
三、Audio Effect
1、均衡器
AVAudioUnitEQ均衡器提供EQ滤波器参数,用于设置频率、增益、滤波器类型,具体如下:
- bandwidth:均衡器频宽,范围[0.05, 5.0]
- bypass:频带的触发状态,true代表激活
- filterType:滤波器类型,包括lowPass、highPass、bandPass等
- frequency:频率,有效值为20Hz~采样率/2
- gain:默认为0 dB,范围[-96 dB, 24 dB]
2、失真
AVAudioUnitDistortion失真可以设置预失真、干湿比。干湿比指的是干声音和湿声音的比例,干声音代表直达声,湿声音代表反射声。具体如下:
- pregain:失真前的增益,默认-6 dB,范围[-80 dB, 20 dB]
- wetDryMix:干湿比,默认50%,范围[0%, 100%]
3、延迟
AVAudioUnitDelay延迟可以实现回声效果,可设置参数包括延迟时间、衰减系数等,具体如下:
- delayTime:延迟时间,默认为1s,范围[0, 2]
- feedback:衰减系数,默认为50%,范围[-100%, 100%]
- lowPassCutoff:低通截断,默认为15000Hz,范围为10Hz~采样率/2
- wetDryMix:干湿比,默认100%,范围[0, 100],0代表全为干声音
4、混响
AVAudioUnitReverb混响可以增强音质,混响支持preset预设环境,具体如下:
- smallRoom:小房间
- mediumRoom:中房间
- largeRoom:大房间
- mediaHall:中走廊
- largeHall:大走廊
- plate:平面
- mediaChamber:中会议厅
- largeChamber:大会议厅
- cathedral:大教堂
四、Time Effect
iOS音频底层提供音质较好的变速变调、变速不变调。而Android往往要依赖第三方库SoundTouch或Sonic实现变速不变调,否则在实现变速功能时声调也发生变化。
1、变调
AVAudioUnitTimePitch变调提供设置混叠、音调、速率参数。具体如下(一度等于1200cents):
- overlap:混叠,默认值8.0,范围[3.0, 32.0]
- pitch:音调,默认值0,单位cents,范围[-2400, 2400]
- rate:速率,默认值1.0,范围[1/32, 32.0]
2、变速
AVAudioUnitRarispeed变速,用于设置播放速率,默认值1.0,范围[0.25, 4.0]。
音调计算公式:
速率计算公式:
五、AVAudioEngine
AVAudioEngine用于管理音频节点,实现各种音效混合输出播放,处理链架构如下:
我们来看看使用AVAudioEngine实现均衡器音效播放,示例代码如下 :
let audioFile = AVAudioFile ()
let audioEngine = AVAudioEngine()
let playerNode = AVAudioPlayerNode()
let effectNode = AVAudioUnitEQ()
// Attach player node
audioEngine.attach(playerNode)
// Attach effect node
audioEngine.attach(effectNode)
// Connect player node to effect node
audioEngine.connect(playerNode,
to: effectNode,
format: audioFile.processingFormat)
// Connect effect node to output node
audioEngine.connect(effectNode,
to: audioEngine.outputNode,
format: audioFile.processingFormat)
启动AVAudioEngine:
do {
try audioEngine.start()
playerNode.play()
} catch {
// handle error
}
停止AVAudioEngine:
playerNode.stop()
audioEngine.stop()