Android在应用层提供丰富的多媒体接口,本文主要介绍音效处理:均衡器风格、预设混响、重低音调节、音量增强、可视化动态频谱,这些音效都使用audioSessionId进行绑定。让用户可选择/设置自己喜欢的风格,身临其境地感受不同歌曲的跳动旋律。方便开发者进行二次开发,打造出酷炫的音乐播放器。
第一篇文章
探讨:MediaPlayer、MediaCodec、AudioTrack、MediaMuxer、MediaExtractor。
第二篇文章
探讨:MediaRecorder、AudioRecord、MediaMetadataRetriever、MediaProjection、AudioManager。
第三篇文章
探讨:CameraX,即对Camera的封装,提供预览、拍照、录像功能。
目录
我们先看下均衡器的各种风格以及其它音效,如下图所示:
一、均衡器风格
均衡器Equalizer,Android源码地址:
Equalizer
。根据官方介绍,均衡器用于调节音乐源或输出混音的频率增益,频率范围从低到高包括:超低频、低频、中频、高频、超高频。我们可以通过mEqualizer?.bandLevelRange[0]获取频率带宽最小值,通过mEqualizer?.bandLevelRange[1]获取频率带宽最大值,然后获取band个数mEqualizer?.numberOfBands,最终根据最小值、最大值和band个数计算出所有频率带宽。具体实现如下:
val equalizerList = ArrayList<Pair<*, *>>()
mEqualizer = Equalizer(0, mPlayer!!.audioSessionId)
mEqualizer!!.enabled = enableEqualizer
minEQLevel = mEqualizer!!.bandLevelRange[0]
val maxEQLevel = mEqualizer!!.bandLevelRange[1]
bands = mEqualizer!!.numberOfBands
for (i in 0 until bands) {
val centerFreq = (mEqualizer!!.getCenterFreq(i.toShort()) / 1000).toString() + " Hz"
val pair = Pair.create(centerFreq, mEqualizer!!.getBandLevel(i.toShort()) - minEQLevel)
equalizerList.add(pair)
}
关于均衡器风格,我们可以使用mEqualizer?.getPresetName(i)来遍历获取,包括古典、舞蹈、民俗、重金属、嘻哈、爵士、流行、摇滚等,如下列表所示:
Normal
Classical
Dance
Flat
Folk
Heavy Metal
Hip Hop
Jazz
Pop
Rock
二、预设混响
预设混响PresetReverb,源码地址:
PresetReverb
。根据官方介绍,一个房间内产生的声音可以往多个方向传播,当声波经历越来越多的反射到达后,聆听者听到的是随时间衰减的连续混响。它可以在音乐应用程序用来模拟各种环境中播放音乐,或者在游戏中让听众沉浸在游戏环境里。
混响模型有Schroeder模型和Moorer模型。其中Schroeder模型由4个梳状滤波器和2个全通滤波器组成,梳状滤波器提供较长延时,全通滤波器提供较短延时。而Moorer模型在Schroeder基础上提出改进:引入低通滤波器,用于高频衰减;增加前级反馈,用于早反射。
混响参数包括:房间大小、高频衰减系数、延时大小、干湿比、立体声宽度等。
预设混响包括小房间、中等房间、大房间、中等大厅、宽敞大厅等,如下列表所示:
SmallRoom
MediumRoom
LargeRoom
MediaHall
LargeHall
Plate
三、重低音调节
重低音BassBoost,源码地址:
BassBoost
。重低音又称为低音增强,重低音是一种放大或增强低频声音的音频效果,它类似于简单的均衡器,只是限于低频范围内的频带放大。调用mBass?.setStrength(progress.toShort())来调节放大等级。
四、音量增强
音量增强LoudnessEnhancer,一种用于增强声音响度的音乐效果,通过设置目标增益值来决定声音信号放大系数。把LoudnessEnhancer关联到特定的AudioTrack或者MediaPlayer,然后指定从AudioTrack或MediaPlayer获取的audio session id。声音信号的目标增益值默认单位是mB,其中100mB=1dB,当增益值为0mB时,默认不进行信号放大。Android官方提供的源码地址:
LoudnessEnhancer
。
五、可视化频谱
可视化频谱Visualizer,用于播放音乐时产生可视化数据,让用户享受跳动的旋律。由PCM数据从时域到频域变换,即FFT变换得到频谱。源码地址:
Visualizer
。
1、申请权限
为了保护用户声音数据的隐私安全,需要申请录音操作权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
另外,在输出混音(audio session id为0)时,需要申请修改录音的权限:
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
如果没有录音权限,直接初始化会报错,因为底层初始化时会检测录音权限,抛出RuntimeException。底层源码如下:
public Visualizer(int audioSession)
throws UnsupportedOperationException, RuntimeException {
int[] id = new int[1];
synchronized (mStateLock) {
mState = STATE_UNINITIALIZED;
// native initialization
int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id,
ActivityThread.currentOpPackageName());
if (result != SUCCESS && result != ALREADY_EXISTS) {
Log.e(TAG, "Error code "+result+" when initializing Visualizer.");
switch (result) {
case ERROR_INVALID_OPERATION:
throw (new UnsupportedOperationException("Effect library not loaded"));
default:
throw (new RuntimeException("Cannot initialize Visualizer engine, error: "
+result));
}
}
mId = id[0];
if (native_getEnabled()) {
mState = STATE_ENABLED;
} else {
mState = STATE_INITIALIZED;
}
}
}
2、初始化
在初始化时,需要设置captureSize每次采样的数据量,通过Visualizer.getCaptureSizeRange()[1]来获取。另外,获取采样率Visualizer.getMaxCaptureRate() / 2,注册数据监听接口回调,然后调用visualizer.setEnabled(true)来开启音频数据的采集处理。具体接口如下:
open fun setDataCaptureListener(
listener: Visualizer.OnDataCaptureListener!,
rate: Int,
waveform: Boolean,
fft: Boolean
): Int
3、数据的获取与显示
音频内容的展示有两种捕获类型:
方波数据:连续8位(无符号)单声道采样,调用getWaveform(byte[] waveform)方法。
频率数据:8位幅度的FFT傅立叶变换,调用getFFT(byte[] fft)方法。
4、释放资源
在音乐播放结束时,需要调用释放可视化频谱的相关资源。先关闭可视化频谱器,注销监听接口,最后调用release来释放资源。需要注意的是,我们在release之前,先注销监听接口,不然有些机型(比如vivo的一些特定机型)会报错。
int captureRate = Visualizer.getMaxCaptureRate() / 2;
visualizer.setEnabled(false);
visualizer.setDataCaptureListener(null, captureRate, false, false);
visualizer.release();
至此,关于音效处理的均衡器、混响、重低音、音量增强、可视化频谱介绍完毕。