audio可视化

如果没有播放点击play可视化
波形
频率
<div>
	<audio id="audio" controls autoplay>
		<source src="/imgs/demo.m4a" type="audio/mp4" />
	</audio>
</div>
<div style="display: flex;    flex-wrap: wrap; gap:20px">
	<div>
		<div>波形</div>
		<canvas id="canvas" width="200px" height='200px'></canvas>
	</div>
	<div>
		<div>频率</div>
		<canvas id="canvas1" width="200px" height='200px'></canvas>
	</div>
</div>

<script type="module">
	const audio = document.getElementById('audio');
	const canvas = document.getElementById("canvas");
	const canvasCtx = canvas.getContext("2d");
	const canvas1 = document.getElementById("canvas1");
	const canvas1Ctx = canvas1.getContext("2d");
	let play = false;

	audio.addEventListener('play', function () {
		play = true;
		const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
		const source = audioCtx.createMediaElementSource(audio);

		const analyser = audioCtx.createAnalyser();
		const gainNode = audioCtx.createGain();
		gainNode.gain.value = 0.4;
		// source -> analyser
		source.connect(analyser);

		// analyser -> gainNode
		analyser.connect(gainNode);

		// gainNode -> 扬声器
		gainNode.connect(audioCtx.destination);


		const bufferLength = analyser.frequencyBinCount;
		const domainArray = new Uint8Array(bufferLength);
		const frequencyArray = new Uint8Array(bufferLength);
		analyser.getByteTimeDomainData(domainArray);
		let time = 0;
		function draw() {
			window.requestAnimationFrame(draw);

			if (play) {
				// analyser.getByteTimeDomainData(domainArray);
				// console.log('data', domainArray);
				// console.log('frequency', frequencyArray);
				// time++

				analyser.getByteTimeDomainData(domainArray);

				canvasCtx.fillStyle = "rgb(220, 220, 220)";
				canvasCtx.fillRect(0, 0, canvas.width, canvas.height);

				canvasCtx.lineWidth = 2;
				canvasCtx.strokeStyle = "rgb(0, 0, 0)";

				canvasCtx.beginPath();
				let skip = 2 ** 4;
				var sliceWidth = canvas.width * 1.0 / bufferLength * skip;
				var x = 0;

				for (let i = 0; i < bufferLength; i++) {

					var v = domainArray[i] / 128.0;
					var 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();

				// 频率
				analyser.getByteFrequencyData(frequencyArray);

				canvas1Ctx.fillStyle = 'rgb(220, 220, 220)';
				canvas1Ctx.fillRect(0, 0, canvas1.width, canvas1.height);
				var barWidth = (canvas1.width / bufferLength * skip) * 2.5;
				var barHeight;
				var x = 0;

				for (let i = 0; i < bufferLength; i++) {
					barHeight = frequencyArray[i];

					canvas1Ctx.fillStyle = 'rgb(' + (barHeight + 100) + '50,50,50)';
					canvas1Ctx.fillRect(x, canvas1.height - barHeight / 2, barWidth, barHeight / 2);
					x += barWidth + 1;
				}
			}

		}

		draw()
	})
</script>