这篇文章主要介绍“前端音频可视化Web Audio如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“前端音频可视化Web Audio如何实现”文章能帮助大家解决问题。
首先画肯定是用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 - 绘制音频图谱
实现第二种类型,获取实时频率,用到的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如何实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://juejin.cn/post/7205381513339322427