Audio API - 随音频跳动的Cube

2,056 阅读3分钟

关于Audio API简单介绍

阅读时间:约2 - 3分钟

一切源于一个简单的需求,音乐播放器,一开始就只是写个UI,调用媒体 API,然后加上了通过进度条映射到seek音频进度到功能,再往上加需求的时候,就是音频可视化了。

记得十多年前的电脑上,Windows Media Player、千千静听等音频软件都会有音频可视化的界面,都是各种各样随着音频的变化,绘制不同规律的图案。可是在浏览器中,做音频分析,对于我来说真的有点不可思议,直到我看到了AudioContext,它给音频处理打开了一扇门。

什么是AudioContext

AudioContext 是 Audio API 中的音频上下文,一切对于音频的操作,都发生在 AudioContext。用大家熟悉的东西来说的话 AudioContext 和 Canvas 的上下文是类似的概念。

Audio API 在 W3C 标准中还是草案状态(Web Audio API),但是不少PC现代主流浏览器已经实现了一部分的功能,所以我们还是可以先用Chrome来尝试一番。

创建AudioContext 并且连接音频

// 创建音频上下文,这是一种兼容的写法
let actx = new (window.AudioContext || webkitAudioContext)();
// 我们从网页的audio元素来连接音频
let audio = document.getElementById("didit");
let source = actx.createMediaElementSource(audio);

AudioContext 提供三种方式来提供音频内容

  • AudioContext.createBufferSource()

    通过AudioContext.createBuffer创建或AudioContext.decodeAudioData解码音轨来创建内容

  • AudioContext.createMediaElementSource()

    通过媒体元素来获取

  • AudioContext.createMediaStreamSource()

    通过流媒体获取(如麦克风)

利用Analyzer分析音频内容

// 创建analyzer
let analyzer = actx.createAnalyser();
// 创建用来获取音频数据的缓冲buffer
let bufferLength = analyzer.fftSize;
let dataArray = new Uint8Array(bufferLength);

// 连接analyzer和音频元
source.connect(analyzer)
analyzer.connect(actx.destination)

在使用Analyser的时候,我遇到了一个问题,analyzer没有办法获取到当前播放的内容。但是我注意到了在其他示例中,音频上下文和他的工具集之间建立了连接。

这就引出了Audio API的工作方式,他的工具集和音频上下文的目的地直接,是通过connect耦合的,在使用工具的时候,需要两方互相连接。

我们在这里使用analyzer.connect(actx.destination)连接音频上下文目的地的原因是,音频的播放信息在AudioContext连接音频元素的时候,就被AudioContext接管了,是它在传输现在播放音频的数据,所以需要如此连接。

一个简单的例子

function getNowText(some) {
  analyzer.getByteTimeDomainData(dataArray);

  let one = (findMax(dataArray) / 128);
  let delta = some - one;

  one = delta * 0.618 + one;

  c.rotate(0.5,0.5,0);
  c.scale(one , one , one );
  c.update();

  requestAnimationFrame(getNowText.bind(this,one))
}

使用一个我之前写的css3d库(HakeCSS3D)来进行简单的视觉效果,这里我们取音频最大值来作为控制变量,并实时更新。(请忽略我这个充满副作用的写法)

analyzer.getByteTimeDomainData(dataArray);是用来获取当前时间的音频分析信息,它返回的信息是128为基准值的整数。

实际效果参考:mcube.hustfe.com/ (请在PC现代浏览器下打开)

浏览器支持情况