前端音频可视化入门

零、涉及到的技术,Api,名词等

大家可以自行在
MDN
上搜索查阅

AudioContext
AudioBufferSourceNode
AnalyserNode
ArrayBuffer
TypeArray – Uint8Array等

XMLHttpRequest

Canvas
requestAnimationFrame

一、技术分析 – 基本思路

  • 1.播放音频
  • 2.在音频播放的时候拿到实时数据
  • 3.在Canvas上按一定规则画出

二、下载一个音频

首先手写一段xml请求方法
我习惯使用promise来封装请求,方便进行异步编程,更好的利用asyncawait来进行异步同步等操作

// 加载音频文件
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函数中使用AudioContextArrayBuffer转为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
喜欢就支持一下吧
点赞0 分享