听音乐时,您有时会看到那些视觉上令人愉悦的跳跃条,音量越大跳得越高。通常,左边的条对应较低的频率(低音),而右边的条对应较高的频率(高音):这些跳跃的条通常被称为视觉均衡器或可视化器,如果你想显示类似的可视化效果,您可以使用Android的原生Visualizer类,它是Android框架的一部分,可以附加到您的AudioTrack。有效,但有一个重要缺陷:需要申请麦克风权限,从官方文档来看,肯定是这样考虑的:Toprotectprivacyofcertainaudiodata(e.g.voicemail)theuseofthevisualizerrequiresthepermission.为了保护某些音频数据(例如语音邮件)的隐私,使用Visualizer需要权限。问题是用户不允许音乐应用程序请求使用他们的麦克风的权限(毫无疑问)。而我翻遍了Android官方提供的API或者其他三方库,也没有找到可以实现这种可视化效果的方案。所以我想自己造轮子。第一个问题是,我需要思考如何将正在播放的音乐转换成每个跳跃条对应的高度。可视化工具的工作原理首先,让我们从输入开始。在数字化音频时,我们通常会非常频繁地对信号幅度进行采样,这称为脉冲编码调制(PCM)。然后振幅被量化,我们将其表示在我们自己的数字标尺上。例如,如果编码是PCM-16,那么比率就是16位,我们可以表示一个2的16次方范围内的幅度,即65536个不同的幅度值。如果您在多个通道上采样(如在立体声中,分别记录左右通道),振幅会相互跟随,因此首先是通道0的振幅,然后是通道1的振幅,然后是通道0,依此类推。一旦我们有了这些量级值作为原始数据,我们就可以继续下一步了。为此,我们需要了解声音到底是什么:我们听到的声音是物体振动的结果。示例包括人的声带、吉他的金属弦和木琴的琴身。一般来说,如果不受特定声音振动的影响,空气分子会随机移动。来自《 Digital Sound and Music 》当音叉被敲击时,它会以非常特定的每秒440次(Hz)的频率振动,这种振动会通过空气传播到耳膜,在那里它以相同的频率产生共振,大脑将其解释为音符A.在PCM中,这可以表示为正弦波,每秒重复440次。这些波浪的高度不会改变音符,但它们代表振幅;通俗地说,当你听到它时,它在你耳朵里的声音有多大。但是在听音乐的时候,经常听到的不仅仅是音符A(虽然我希望如此),还有太多的乐器和声音,导致PCM图形对人眼来说没有意义。实际上它是大量不同频率和振幅的不同正弦波振动的组合。即使是非常简单的PCM信号(例如方波)在解构为不同的正弦波时也非常复杂:方波解构为近似正弦波和余弦波。幸运的是,我们有算法来进行这种解构,我们称之为傅里叶变换。正如上面的可视化工具所展示的,它实际上是从正弦波和余弦波的组合中解构出来的。余弦基本上是一个延迟的正弦波,但在这个算法中加入它们非常有用,否则我们将无法为点0创建一个值,因为每个正弦波都从0开始,乘法仍然会得到0。执行傅立叶变换的算法之一是快速傅立叶变换(FFT)。在我们的PCM声音数据上运行此FFT算法时,我们将获得每个正弦波的振幅列表。这些波是声音的频率。在列表的开头,我们可以找到低频(低音),最后是高频(高音)。这样,我们通过绘制这样的条形图来获得我们想要的可视化工具,条形图的高度由每个频率的大小决定。技术实现现在回到了Android。首先,我们需要音频的PCM数据。为此,我们可以为我们的ExoPlayer实例配置一个AudioProcessor,它将在转发之前接收每个音频字节。您还可以进行修改,例如更改振幅或过滤通道,但现在还不能。privatevalfftAudioProcessor=FFTAudioProcessor()valrenderersFactory=object:DefaultRenderersFactory(this){overridefunbuildAudioProcessors():Array
