前天尝试了一波那个什么 MediaSourceExtension,结果发现那套API目前限制蛮大的,而且对我来说没什么帮助(audio/x-wav 完全不正常支持,audio/mpeg 也只能在 Chrome 上使用)于是只能放弃折腾了 QAQ
昨天突然想起之前写 nanoPlayer 的时候,使用了一个叫 Audio Context 的接口,nanoPlayer 用了这个 API 里的 createAnalyser 方法,来获得音频的频率数据,进而实现了一个频谱可视化功能。之前就注意到了这个接口中有个自定义 AudioBufferSource 的方法,可以指定若干 Float32Array 并交给浏览器播放,应该是蛮有意思的。
这里就实现一个可制定频率的正弦波音频吧,如果这个实现起来没有什么难度的话,就准备试试浏览器端解码 WAV 音频。
首先是 HTML,我们要准备一个文本框来获得指定的频率,两个按钮分别控制播放的开始与停止:
然后初始化若干变量:
let ctx = new AudioContext(); let frames = ctx.sampleRate; let start = document.querySelector('button[start]'); let stop = document.querySelector('button[stop]'); let last = null;
其中 ctx.sampleRate 是 AudioContext 的采样率,这里直接将一秒钟的采样数作为帧数,产生一段持续时间为一秒的 AudioSourceBuffer 就足够了,还有 last 是用来保存上一次的 AudioSource,可以随时调用 stop 方法来终止播放。
然后就是为 start 按钮增加一个点击事件:根据文本框里的数值产生一段指定频率的音频采样:
start.onclick = (e) => { if (last) last.stop(); let freq = document.querySelector('#freq').value; // 初始化一个单声道,采样率和 AudioCotnext 一致,持续时间为 1 sec 的 AudioBuffer let audioBuffer = ctx.createBuffer(1, ctx.sampleRate, ctx.sampleRate); // 获得其中第一个声道的数据源,类型是 Float32Array let nowBuffering = audioBuffer.getChannelData(0); // 填充数据,取值范围是 [-1, 1],直接用正弦函数就行了 for (let i = 0; i < frames; ++i) { nowBuffering[i] = Math.sin((Math.PI * 2 * freq) * (i / ctx.sampleRate)); } // 初始化一个 AudioBufferSource,并将上面的 AudioBuffer 与之绑定,并输出到 AudioContext let source = ctx.createBufferSource(); source.loop = true; source.buffer = audioBuffer; source.connect(ctx.destination); // 开始回放 source.start(); // 保存以备后续使用 last = source; }
当然还需要对停止按钮绑定一个事件,来停止回放:
stop.onclick = (e) => { if (last) last.stop(); last = null; };
以上就是所有代码啦,效果的话,我在这里直接放个demo就行: