零、涉及到的技术,Api,名词等
大家可以自行在
MDN
上搜索查阅
AudioContext
AudioBufferSourceNode
AnalyserNode
ArrayBuffer
TypeArray – Uint8Array等XMLHttpRequest
Canvas
requestAnimationFrame
一、技术分析 – 基本思路
- 1.播放音频
- 2.在音频播放的时候拿到实时数据
- 3.在Canvas上按一定规则画出
二、下载一个音频
首先手写一段xml请求方法
我习惯使用promise来封装请求,方便进行异步编程,更好的利用async
和await
来进行异步同步等操作
// 加载音频文件
function loadSound(url) {
return new Promise((resolve) => {
const request = new XMLHttpRequest(); //建立一个请求
request.open('GET', url, true); //配置好请求类型,文件路径等
request.responseType = 'arraybuffer'; //配置数据返回类型
// 一旦获取完成,对音频进行进一步操作,比如解码
request.onload = () => {
resolve(request.response);
}
request.send();
});
}
复制代码
写一个init的异步函数。并在里面加载音频
// 弄个函数,方便异步编程
async function init() {
const arrayBuffer = await loadSound("https://yun.duiba.com.cn/aurora/assets/3457521d415e67cd2311a0df0ac4152439e75de7.mp3");
audioBufferSourceNode.buffer = audioBuffer;
}
init();
复制代码
三、播放一个音频
在全局变量中创建AudioContext
对象和音频播放节点,可以用于播放音频
// 兼容
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
// 创建音频播放节点
const audioBufferSourceNode = audioContext.createBufferSource();
audioBufferSourceNode.connect(audioContext.destination); // 连接到AudioContext对象
复制代码
在init函数中使用AudioContext
将ArrayBuffer
转为AudioBuffer
用于音频播放
并绑定给AudioBufferSourceNode
/**
* ArrayBuffer 转 AudioBuffer
* @param arrayBuffer
* @returns {Promise}
*/
function bufferToAudio(arrayBuffer) {
return new Promise((resolve, reject) => {
audioContext.decodeAudioData(
arrayBuffer,
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
}
// 弄个函数,方便异步编程
async function init() {
const arrayBuffer = await loadSound("https://yun.duiba.com.cn/aurora/assets/3457521d415e67cd2311a0df0ac4152439e75de7.mp3");
// 把arrayBuffer转换成audioBuffer
const audioBuffer = await bufferToAudio(arrayBuffer);
// 绑定音频对象
audioBufferSourceNode.buffer = audioBuffer;
}
复制代码
写一个播放按钮
<button onclick="play()">播放</button>
<script>
function play() {
if (audioBufferSourceNode.isStart) {
audioBufferSourceNode.isStart = false;
audioBufferSourceNode.stop(); // 暂停音频
} else {
audioBufferSourceNode.isStart = true;
audioBufferSourceNode.start(0); // 从0开始播放音频
}
}
</script>
复制代码
打开网页,点击按钮发现又美妙的歌声传出
要学神仙~ 驾鹤飞天~
点石成金~ 妙不可言~
四、音频分析器
在全局变量中创建音频音频分析器,并和音频对象连接
// 创建音频分析器,连接音频分析器
const analyser = audioContext.createAnalyser();
audioBufferSourceNode.connect(analyser);
analyser.fftSize = 2048; // 表示单次数据的长度,只能是2的n次方
// 设置好fftSize之后可以拿到frequencyBinCount
const bufferLength = analyser.frequencyBinCount;
// 使用frequencyBinCount来创建一个Uint8Array,用于装数据
const dataArray = new Uint8Array(bufferLength);
复制代码
通过analyser.getByteTimeDomainData
可以将当前数据填充在dataArray中
analyser.getByteTimeDomainData(dataArray);
复制代码
五、拿到实时数据在Canvas上按规则画出
创建一个Canvas
<canvas id="myCanvas" width="450" height="450"></canvas>
复制代码
写一个draw函数在里面写绘画逻辑
这个网上抄来的,随便找一段好看的就行
绑定在requestAnimationFrame上每帧调用
在init
之后直接调用draw
// canvas
const canvas = document.getElementById("myCanvas");
const canvasCtx = canvas.getContext("2d");
function draw() {
requestAnimationFrame(draw); // 循环调用
analyser.getByteTimeDomainData(dataArray); // 将当前数据填充在dataArray中
canvasCtx.fillStyle = 'rgb(200, 200, 200)';
canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
canvasCtx.lineWidth = 2;
canvasCtx.strokeStyle = 'rgb(0, 0, 0)';
canvasCtx.beginPath();
const sliceWidth = canvas.width * 1.0 / bufferLength;
let x = 0;
for (let i = 0; i < bufferLength; i++) {
const v = dataArray[i] / 128.0;
const y = v * canvas.height / 2;
if (i === 0) {
canvasCtx.moveTo(x, y);
} else {
canvasCtx.lineTo(x, y);
}
x += sliceWidth;
}
canvasCtx.lineTo(canvas.width, canvas.height / 2);
canvasCtx.stroke();
}
init();
draw();
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END