Zero, the technology involved, Api, nouns, etc

You can search on MDN

AudioContext AudioBufferSourceNode AnalyserNode ArrayBuffer TypeArray – Uint8Array etc

XMLHttpRequest

Canvas

requestAnimationFrame

1. Technical analysis – Basic ideas

  • 1. Play audio
  • 2. Get real-time data while the audio plays
  • 3. Draw on the Canvas according to certain rules

2. Download an audio

I am used to use promise to encapsulate requests, which is convenient for asynchronous programming, and better use async and await to perform asynchronous synchronization and other operations

// Load the audio file
function loadSound(url) {
	return new Promise((resolve) = > {
		const request = new XMLHttpRequest(); // Create a request
		request.open('GET', url, true); // Configure the request type, file path, etc
		request.responseType = 'arraybuffer'; // Configure the data return type
		// Once the capture is complete, perform further operations on the audio, such as decoding
		request.onload = () = > {
			resolve(request.response);
		}
		request.send();
	});
}
Copy the code

Write an asynchronous init function. And load the audio inside

// Create a function to facilitate asynchronous programming
async function init() {
	const arrayBuffer = await loadSound("https://yun.duiba.com.cn/aurora/assets/3457521d415e67cd2311a0df0ac4152439e75de7.mp3");
	audioBufferSourceNode.buffer = audioBuffer;

}

init();
Copy the code

Play an audio

Create an AudioContext object and an audio player node in a global variable that can be used to play audio

/ / compatible
const audioContext = new (window.AudioContext || window.webkitAudioContext)();

// Create the audio player node
const audioBufferSourceNode = audioContext.createBufferSource();
audioBufferSourceNode.connect(audioContext.destination);    Connect to the AudioContext object
Copy the code

Use AudioContext in the init function to convert the ArrayBuffer to an AudioBuffer for audio playback and bind to the AudioBufferSourceNode

/** * Turn ArrayBuffer to AudioBuffer *@param arrayBuffer
 * @returns {Promise}* /
function bufferToAudio(arrayBuffer) {
	return new Promise((resolve, reject) = > {
		audioContext.decodeAudioData(
			arrayBuffer,
			(res) = > {
				resolve(res);
			},
			(err) = >{ reject(err); }); }); }// Create a function to facilitate asynchronous programming
async function init() {
	const arrayBuffer = await loadSound("https://yun.duiba.com.cn/aurora/assets/3457521d415e67cd2311a0df0ac4152439e75de7.mp3");

	// Convert arrayBuffer to audioBuffer
	const audioBuffer = await bufferToAudio(arrayBuffer);

	// Bind the audio object
	audioBufferSourceNode.buffer = audioBuffer;
}
Copy the code

Write a play button


<button onclick="play()">play</button>
<script>
    function play() {
        if (audioBufferSourceNode.isStart) {
            audioBufferSourceNode.isStart = false;
            audioBufferSourceNode.stop();   // Pause the audio
        } else {
            audioBufferSourceNode.isStart = true;
            audioBufferSourceNode.start(0); // Play the audio from 0}}</script>
Copy the code

Open the page, click the button to find a wonderful song out

To learn the gods ~ flying cranes ~ the Midas touch into gold ~ wonderful ~

Four, audio analyzer

Create an audio parser in a global variable and connect it to the audio object

// Create an audio analyzer and connect the audio analyzer
const analyser = audioContext.createAnalyser();
audioBufferSourceNode.connect(analyser);

analyser.fftSize = 2048;    // indicates the length of a single piece of data, which can only be 2 to the n
// Set fftSize to frequencyBinCount
const bufferLength = analyser.frequencyBinCount;
// Create a Uint8Array using frequencyBinCount for storing data
const dataArray = new Uint8Array(bufferLength);
Copy the code

Through the analyser. GetByteTimeDomainData current data can be filled in dataArray

analyser.getByteTimeDomainData(dataArray);
Copy the code

5. Get real-time data and draw on Canvas according to the rules

Create a Canvas

<canvas id="myCanvas" width="450" height="450"></canvas>
Copy the code

So I’m going to write a draw function and I’m going to write the drawing logic in there and I’m just going to copy it from the web, just find a nice one and bind it to the requestAnimationFrame and then call draw directly after init

// canvas
const canvas = document.getElementById("myCanvas");
const canvasCtx = canvas.getContext("2d");

function draw() {
	requestAnimationFrame(draw);    // Loop call
	analyser.getByteTimeDomainData(dataArray);  // Fill the current data in 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();
Copy the code