记录--关于前端的音频可视化-Web Audio
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
背景
最近听音乐的时候,看到各种动效,突然好奇这些音频数据是如何获取并展示出来的,于是花了几天功夫去研究相关的内容,这里只是给大家一些代码实例,具体要看懂、看明白,还是建议大家大家结合相关API文档来阅读这篇文章。
实现思路
首先画肯定是用canvas去画,关于音频的相关数据(如频率、波形)如何去获取,需要去获取相关audio的DOM 或通过请求处理去拿到相关的音频数据,然后通过Web Audio API 提供相关的方法来实现。(当然还要考虑要音频请求跨域的问题,留在最后。)
一个简单而典型的 web audio 流程如下(取自MDN):
- 创建音频上下文
- 在音频上下文里创建源 — 例如
<audio>
, 振荡器,流 - 创建效果节点,例如混响、双二阶滤波器、平移、压缩
- 为音频选择一个目的地,例如你的系统扬声器
- 连接源到效果器,对目的地进行效果输出
实现
一、频率图
实现第一种类型,首先我们需要通过fetch或xhr来获取一个线上音频的数据,这里以fetch为例;
//创建一个音频上下文、考虑兼容性问题
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
//添加一个音频源节点
let source = audioCtx.createBufferSource();
//res.arrayBuffer是将数据转换为arrayBuffer格式
fetch(url).then((res) => res.arrayBuffer()).then((res) => {
//decodeAudioData是将arrayBuffer格式数据转换为audioBuffer
audioCtx.decodeAudioData(res).then((buffer) => {
// decodeAudioData解码完成后,返回一个AudioBuffer对象
// 绘制音频波形图
draw(buffer);
// 连接音频源
source.buffer = buffer;
source.connect(audioCtx.destination);
// 音频数据处理完毕
});
});
需要明白的是,source.connect(audioCtx.destination)是将音频源节点链接到输出设备,否则会没声音哦。那么现在有了数据、我们只需要通过canvas将数据画出来即可。
function draw(buffer) {
// buffer.numberOfChannels返回音频的通道数量,1即为单声道,2代表双声道。这里我们只取一条通道的数据
let data = [];
let originData = buffer.getChannelData(0);
// 存储所有的正数据
let positives = [];
// 存储所有的负数据
let negatives = [];
// 先每隔50条数据取1条
for (let i = 0; i < originData.length; i += 50) {
data.push(originData[i]);
}
// 再从data中每10条取一个最大值一个最小值
for (let j = 0, len = data.length / 10; j < len; j++) {
let temp = data.slice(j * 10, (j + 1) * 10);
positives.push(Math.max(...temp));
negatives.push(Math.min(...temp));
}
if (canvas.getContext) {
let ctx = canvas.getContext("2d");
canvas.width = positives.length;
let x = 0;
let y = 75;
let offset = 0;
var grd = ctx.createLinearGradient(0, 0, canvas.width, 0);
// 为渐变添加颜色,参数1表示渐变开始和结束之间的位置(用0至1的占比表示),参数2位颜色
grd.addColorStop(0, "yellow");
grd.addColorStop(0.5, "red");
grd.addColorStop(1, "blue");
ctx.fillStyle = grd;
ctx.beginPath();
ctx.moveTo(x, y);
// 横坐标上方绘制正数据,下方绘制负数据
// 先从左往右绘制正数据
// x + 0.5是为了解决canvas 1像素线条模糊的问题
for (let k = 0; k < positives.length; k++) {
ctx.lineTo(x + k + 0.5, y - 50 * positives[k]);
} // 再从右往左绘制负数据
for (let l = negatives.length - 1; l >= 0; l--) {
ctx.lineTo(x + l + 0.5, y + 50 * Math.abs(negatives[l]));
}
// 填充图形
ctx.fill();
}
}
[参考文章](Web Audio - 绘制音频图谱 - 掘金 (juejin.cn))
二、实时频率图
实现第二种类型,获取实时频率,用到的API与第一种有区别,但流程一直,都是通过一个音频源节点通过连接达到效果。只不过在连接的中间加入了一个分析器analyser,在将分析器连接到输出设备。
const audio =document.querySelector('audio')
//解决音频跨域问题
audio.crossOrigin ='anonymous'
const canvas =document.querySelector('canvas')
const ctx=canvas.getContext("2d")
function initCanvas(){
//初始化canvas
canvas.width=window.innerWidth*devicePixelRatio
canvas.height=(window.innerHeight/2)*devicePixelRatio
}
initCanvas()
//将数据提出来
let dataArray,analyser;
//播放事件
audio.onplay=function(){
//创建一个音频上下文实例
const audioCtx=new (window.AudioContext || window.webkitAudioContext)();
//添加一个音频源节点
const source=audioCtx.createMediaElementSource(audio);
//分析器节点
analyser=audioCtx.createAnalyser();
//fft分析器 越大 分析越细
analyser.fftSize=512
//创建一个无符号字节的数组
dataArray=new Uint8Array( analyser.frequencyBinCount);
//音频源节点 链接分析器
source.connect(analyser)
//分析器链接输出设备
analyser.connect(audioCtx.destination,)
}
那么接下来至于怎么把数据画出来,就凭大家的想法了。
requestAnimationFrame(draw)
//
const {width ,height}=canvas;
ctx.clearRect(0,0,width,height)
//分析器节点分析出的数据到数组中
ctx.fillStyle='#78C5F7'
ctx.lineWidth = 2;
ctx.beginPath();
//getByteFrequencyData,分析当前音频源的数据 装到dataArray数组中去
//获取实时数据
analyser.getByteFrequencyData(dataArray)
// console.log(dataArray);
const len =dataArray.length;
const barWidth=width/len;
let x=0;
for(let i=0;i<len;i++){
const data=dataArray[i];
const barHeight=data/255*height; // ctx.fillRect(x,y,barWidth,height) let v = dataArray[i] / 128.0;
let y = v * height/2; if(i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
} x += barWidth;
}
// ctx.lineTo(canvas.width, canvas.height/2);
ctx.stroke();
}
draw();
关于请求音频跨域问题解决方案
给获取的audio DOM添加一条属性即可
audio.crossOrigin ='anonymous'
或者直接在 aduio标签中 加入 crossorigin="anonymous"
总结
虽然现在已经有很多开源的对于音频相关的库,但如果真正的想要去了解,去学习音频相关的东西。必须要去深入学习相关的Web Audio API,当然这里只是用了其中两种的方法去实现Web Audio去实现可视化,算是一个基础入门,对于文中的createBufferSource,createMediaElementSource,createAnalyser,AudioContext,arrayBuffer,decodeAudioData等等相关的API都需要去了解,在可视化方面,还有多种多样的方式去绘制动画,如WebGL。对音频的处理也不只是在可视化方面。
本文转载于:
https://juejin.cn/post/7205381513339322427
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
记录--关于前端的音频可视化-Web Audio的更多相关文章
- 【HTML5】Web Audio API打造超炫的音乐可视化效果
HTML5真是太多炫酷的东西了,其中Web Audio API算一个,琢磨着弄了个音乐可视化的demo,先上效果图: 项目演示:别说话,点我! 源码已经挂到github上了,有兴趣的同学也可以去st ...
- Web Audio API之手把手教你用web api处理声音信号:可视化音乐demo
1.Web Audio API 介绍 Web Audio API 提供了在Web上控制音频的一个非常有效通用的系统 ,这些通用系统通俗的讲就是我们可以利用Web Audio API提供的各种方法操作各 ...
- HTML5 ——web audio API 音乐可视化(二)
上一篇 web audio API 音乐可视化(一)介绍了一些基本的API,以及如何简单的播放一个音频,本篇介绍一下怎么对获取到的音频进行分析,并将分析后的数据绘制成图像. 最终效果请戳这里; 完整版 ...
- HTML5 ——web audio API 音乐可视化(一)
使用Web Audio API可以对音频进行分析和操作,最终实现一个音频可视化程序. 最终效果请戳这里; 完整版代码请戳这里,如果还看得过眼,请给一个start⭐ 一.API AudioContext ...
- 基于canvas和Web Audio的音频播放器
wavesurfer.js是一款基于HTML5 canvas和Web Audio的音频播放器插件.通过wavesurfer.js你能够使用它来制作各种HTML5音频播放器,它能够在各种支持 Web A ...
- 关于HTML5音频——audio标签和Web Audio API各平台浏览器的支持情况
对比audio标签 和 Web Audio API 各平台浏览器的支持情况: audio element Web Audio API desktop browsers Chrome 14 Yes ...
- H5的Web Audio Api
概述 研究Web Audio Api的主要原因是:工作中需要在ios中实现声音的淡出效果,主要是通过setInterval来改audio标签的volume属性实现的,但是ios上面volume属性是只 ...
- Web Audio介绍
Web Audio还是一个比较新的JavaScript API,它和HTML5中的<audio>是不同的,简单来说,<audio>标签是为了能在网页中嵌入音频文件,和播放器一样 ...
- 使用Web Audio API绘制音波图
摘要:Web Audio API是对<audio> 标签功能上的补充,我们可以用它完成混音.音效.平移等各种复杂的音频处理,本文简单的使用其完成音波图的绘制. PS:本例子使用ES6编程, ...
- Web Audio初步介绍和实践
Web Audio还是一个比较新的JavaScript API,它和HTML5中的<audio>是不同的,简单来说,<audio>标签是为了能在网页中嵌入音频文件,和播放器一样 ...
随机推荐
- 听说有 Hugging Face 陪伴的春节,是这样的…
辞旧迎新春节到,家家户户好热闹.Hugging Face 中国团队成员祝各位社区成员们新春快乐,万事如意! 过去的一年我们持续看到 AI 技术的腾飞和发展,以及诸多机构为开源 AI 作出巨大的贡献.非 ...
- ABC 311
前四题过水 E 枚举正方形的上边界所在行.对于第 \(i\) 行一个没洞的位置 \((i,j)\),我们尝试求出以它为右上角的无洞正方形个数. 结论:设以 \((i,j-1)\) 为右上角的无洞正方形 ...
- 通过解析库探究函数式抽象代价 ( ini 解析示例补充)
上一篇 用 HexColor 作为示例,可能过于简单 这里再补充一个 ini 解析的示例 由于实在写不动用其他库解析 ini 了, 春节都要过完了,累了,写不动了, 所以随意找了一份解析ini的库, ...
- NC20811 蓝魔法师
题目链接 题目 题目描述 "你,你认错人了.我真的,真的不是食人魔."--蓝魔法师 给出一棵树,求有多少种删边方案,使得删后的图每个连通块大小小于等于k,两种方案不同当且仅当存在一 ...
- InnoDB中不同SQL语句设置的锁
锁定读(locking read).更新(UPDATE)或删除(DELETE)通常会在SQL语句处理过程中扫描的每个索引记录上设置记录锁.语句中是否存在排除行的WHERE条件并不重要.InnoDB不记 ...
- Windows SDK 之 mciSendString最后一个参数
这里在这里先附上mciSendString的函数原型: MCIERROR mciSendString( LPCTSTR lpszCommand, LPTSTR lpszReturnString, UI ...
- P4141 消失之物题解(写给每一位与我一样的新手玩家)
消失之物 传送门: P4141 消失之物 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路 暴力稳了 但是 hack tle了 这时候我们要想办法优化 这是一个回退背包问题 首先 ...
- django学习第十四天--Forms和ModelForm
Forms和ModelForm 进行数据校验,先看数据校验的过程 注册页面图解: 前端为了用户体验会做一些校验,不满足校验要求会报错 服务端也会对数据进行一些校验,不满足校验要求会报错 数据库也会对数 ...
- 【LeetCode回溯算法#01】图解组合问题
组合问题 力扣题目链接(opens new window) 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合. 示例: 输入: n = 4, k = 2 输出: [ [2 ...
- 【LeetCode二叉树#15】二叉搜索树中的众数(递归中序遍历)
二叉搜索树中的众数 力扣题目链接(opens new window) 给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素). 假定 BST 有如下定义: 结点左子树 ...