Я объединил в основном эти оба примера вместе:
https://www.youtube.com/watch?v=hYNJGPnmwls (https://codepen.io/jakealbaugh/pen/jvQweW/)
и пример из веб-аудио API:
https://github.com/mdn/webaudio-examples/blob/master/audio-analyser/index.html
let audioBuffer;
let sourceNode;
let analyserNode;
let javascriptNode;
let audioData = null;
let audioPlaying = false;
let sampleSize = 1024; // number of samples to collect before analyzing data
let frequencyDataArray; // array to hold time domain data
// Global Variables for the Graphics
let canvasWidth = 512;
let canvasHeight = 256;
let ctx;
document.addEventListener("DOMContentLoaded", function () {
ctx = document.body.querySelector('canvas').getContext("2d");
// the AudioContext is the primary 'container' for all your audio node objects
try {
audioContext = new AudioContext();
} catch (e) {
alert('Web Audio API is not supported in this browser');
}
// When the Start button is clicked, finish setting up the audio nodes, play the sound,
// gather samples for the analysis, update the canvas
document.body.querySelector('#start_button').addEventListener('click', function (e) {
e.preventDefault();
// Set up the audio Analyser, the Source Buffer and javascriptNode
initCanvas();
setupAudioNodes();
javascriptNode.onaudioprocess = function () {
// get the Time Domain data for this sample
analyserNode.getByteFrequencyData(frequencyDataArray);
// draw the display if the audio is playing
console.log(frequencyDataArray)
draw();
};
loadSound();
});
document.body.querySelector("#stop_button").addEventListener('click', function(e) {
e.preventDefault();
sourceNode.stop(0);
audioPlaying = false;
});
function loadSound() {
fetch('http://localhost:3000/audio/8bars60bpmOnlyKick.wav').then(response => {
response.arrayBuffer().then(function (buffer) {
audioContext.decodeAudioData(buffer).then((audioBuffer) => {
console.log('audioBuffer', audioBuffer);
// {length: 1536000, duration: 32, sampleRate: 48000, numberOfChannels: 2}
audioData = audioBuffer;
playSound(audioBuffer);
});
});
})
}
function setupAudioNodes() {
sourceNode = audioContext.createBufferSource();
analyserNode = audioContext.createAnalyser();
analyserNode.fftSize = 4096;
javascriptNode = audioContext.createScriptProcessor(sampleSize, 1, 1);
// Create the array for the data values
frequencyDataArray = new Uint8Array(analyserNode.frequencyBinCount);
// Now connect the nodes together
sourceNode.connect(audioContext.destination);
sourceNode.connect(analyserNode);
analyserNode.connect(javascriptNode);
javascriptNode.connect(audioContext.destination);
}
function initCanvas() {
ctx.fillStyle = 'hsl(280, 100%, 10%)';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
};
// Play the audio once
function playSound(buffer) {
sourceNode.buffer = buffer;
sourceNode.start(0); // Play the sound now
sourceNode.loop = false;
audioPlaying = true;
}
function draw() {
const data = frequencyDataArray;
const dataLength = frequencyDataArray.length;
console.log("data", data);
const h = canvasHeight / dataLength;
// draw on the right edge
const x = canvasWidth - 1;
// copy the old image and move one left
let imgData = ctx.getImageData(1, 0, canvasWidth - 1, canvasHeight);
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.putImageData(imgData, 0, 0);
for (let i = 0; i < dataLength; i++) {
// console.log(data)
let rat = data[i] / 255;
let hue = Math.round((rat * 120) + 280 % 360);
let sat = '100%';
let lit = 10 + (70 * rat) + '%';
// console.log("rat %s, hue %s, lit %s", rat, hue, lit);
ctx.beginPath();
ctx.strokeStyle = `hsl(${hue}, ${sat}, ${lit})`;
ctx.moveTo(x, canvasHeight - (i * h));
ctx.lineTo(x, canvasHeight - (i * h + h));
ctx.stroke();
}
}
});
Я кратко объясню, что делает каждая часть:
создание аудио контекста
Когда DOM загружается, создается AudioContext
.
загрузка аудиофайла и преобразование его в AudioBuffer
Затем я загружаю звук с бэкэнд-сервера (код такой, как показано выше). Ответ затем преобразуется в буфер, который затем декодируется в AudioBuffer. Это в основном основное решение вопроса выше.
Process AudioBuffer
Чтобы показать немного больше контекста, как использовать загруженный аудиофайл, я включил остальную часть файла.
Для дальнейшей обработки AudioBuffer создается источник, и буферу назначается источник: sourceNode.buffer = buffer
.
javascriptNode
действует IMHO как поток, в котором вы можете получить доступ к выходу анализатора.