使用html5 audio api音频可视化: Hello by OMFG

来源:互联网 发布:软件的缺陷等级 编辑:程序博客网 时间:2024/06/02 14:42

使用html5 audio api音频可视化


在网易云上听Hello - OMFG,无意间点开了MV,看上去很动感,但是简单到就像一个前端动画。于是自己想照着做一个WEB。最终效果和源码已传至github。

动画分析

首先中间的OMFG四个字母是不动的。

两侧跳跃的图形,应该跟音频相关,这个可以和音频文件的波形、频率对应。

跳跃图形下方还有一小部分倒影,这个可以在作出上方图形后,再以其为参照来制作。

忽明忽暗的背景黑圈也是和音频相关的。

研究过程

可视化第一步:获取音频数据

先看了些文章,学会了把音频文件的数据读取出来,也就是使用audio api获取音频内容。

var AudioContext = AudioContext || webkitAudioContext;var context = new AudioContext;//加载媒体var audio = new Audio("hello.mp4");//创建节点var source = context.createMediaElementSource(audio);var analyser = context.createAnalyser();//连接:source → analyser → destinationsource.connect(analyser);analyser.connect(context.destination);

这里先创建一个audio容器,载入音频文件hello.mp4。可以这样理解,source获取hello.mp4的内容节点,analyser是为可视化做准备的频谱分析器,destination是电脑上的声卡。连接后,音频节点先通过分析器,然后传到声卡。

analyser.fftSize = 4096;var length = analyser.fftSize;//创建数据var dataArray = new Uint8Array(length);

fftSize (Fast Fourier Transform) 是快速傅里叶变换,一般情况下是固定值2048。具体作用是什么我也不太清除,但是经过研究,这个值可以决定音频频谱的密集程度。值大了,频谱就松散,值小就密集。

dataArray数组将用来放音频高低音不同区域的数据信息,当音频播放时,每一个时间节点,都有不同的音频数据,使用analyser.getByteFrequencyData(dataArray)将数据放入数组,用来进行频谱的可视化绘制。

可视化:音频数据的canvas绘制

大家应该都见过,频谱就是类似下面这个图片的样子(波形和频谱是不同的概念)。

频谱图

我们已经在dataArray数组中获取到了音频数据,数据的内容是大小不同的数值,分布在数组小标从0dataArray.length的各数组项内。

MDN上面给出的例子,就是直接把数据以方块的形式绘制出来,比如dataArray[0]的值为128,那么就在画布横坐标0的地方画上128个方块。

明白了这个对应关系,画图就变得简单了。

我先使用线条绘制图形,然后填充,得到了频谱的主体。

在主体的基础上,再用类似的方法绘制一层线条,不填充,并加入随机变量、高度向上平移一些,得到高出主体的线条。

倒影刚开始我想用主体反转变形的方法,发现对图片的反转模糊很简单,图形太复杂。于是我又仿照主体图形的代码,写了一个反转的,高度收缩的倒影。

最后将所有的图形加上渐变填充,就变的色彩鲜明了。

背景变化的黑白光圈是一个中心辐射型的黑白填充,使用随机变量来确定辐射的半径。

到此,完成了所有canvas的动画部分,这些内容全部放到一个需要requestAnimationFrame()重复执行的块内。

文字部分:CSS动画很方便

绘制完动画后,同样使用canvas绘制开场的文字动画,发现太复杂:文字的滚动,擦除已经很麻烦了,还需要设计颜色样式。决定放弃canvas动画,转用CSS3动画,使用绝对定位,写几个相对坐标改变的动画就搞定了。

文字的倒影是一个绿色填充圆角DIV,加上阴影。

优化

所有工作完成后,发现不同分辨率下显示有问题,我的分辨率是1366*768,到更高的分辨率下就无法全屏显示了。

刚开始我想重新计算图形,使用自适应屏幕大小的方法。发现太复杂,要计算的东西很多。想了想,决定使用对bodytransform:scale(x,y)来拉伸整个页面:先计算当前分辨率与1366 768的比例,然后拉伸成不同比例。这样挺简单的。

总结

之前做过html5小游戏,加上这个音频可视化,两次使用canvas的感觉都是再跟数学打交道,全是坐标计算方面的工作。计算准确数值,画图什么的还是很简单的,都是基本绘制语句。看来以后还需要多学习数学呵~

效果、源码

DEMO

源码 on github

插曲

我一直都是在一个js副件内写代码的,最终定稿后,一个利索的操作把副件删除了,干净的html和js,等待上传github。传完打开,index.html提示找不到副件.js,瞬间意识到删错了东西,打开js一看,里面就几行代码。当时心里是崩溃的。学了一下午文件恢复,winhex始终找不到文件的位置。最终在chrome的缓存中取出了js的16进制原始文档。

写代码时遇到的一些问题

波形图 getByteTimeDomainData和频谱图 getByteFrequencyData 是两种形式的数据。我刚开始使用的是波形图,想做成频谱图的样子真是费了巨大的功夫,想了很多算法把波形图的数据转化成频谱图,无疾而终。

波形图,dataArray中最大值为256,最小值为0,初始值为128。频谱图初始值为0,只有比0大的值。

不同长度的数组dataArray console.log出来,内容有时相同,有时不同?

数组很大时,将analyser的实时数据装入数组,log操作很费时,导致log之后下一个短数组装入数据时,实时数据发生了变化。

canvas有多层画布时,是有先后顺序的,如果想要透明前面的层。除了要设定透明度外,必须给canvas加上一个z-index。

1 0
原创粉丝点击