Suppose there is a certain sampe.mp3. I want to extract raw data using javascript and draw a graph of this sound. How to do it?
- oneItself did not work with it, however, as I understood, you want to make an equalizer. On this occasion, there is an answer to the English version and even two - Temka, too,
|
2 answers
<html> <head> <meta charset="utf-8"> <title>Визуализатор</title> <style> #canvas{ position: absolute; top: 50px; left: 0px; background: #333; } #progress{ position: absolute; top: 50px; left: 0px; background: rgba(255, 155, 0, 0.5); width: 0px; height: 256px; } </style> </head> <body bgcolor=#444> <audio id=audio src="http://auto-gurov.vv.si/1/sound.mp3" controls></audio> <canvas id=canvas width=512 height=256></canvas> <div id=progress></div> <script> var audio = document.getElementById("audio"); var ctx = canvas.getContext("2d"); var color_L = "#7cf", color_R = "#f7c"; // Цвета осциллограмм левого и правого стереоканалов var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); audio.onplay = function(){b = setInterval(function(){progress.style.width = Math.floor(audio.currentTime / audio.duration * canvas.width) + "px"}, 100)}; audio.onended = function(){ this.currentTime = 0; clearInterval(b); progress.style.width = "0px"; } var source = audioCtx.createBufferSource(); var request = new XMLHttpRequest(); request.open('GET', audio.src, true); request.responseType = 'arraybuffer'; request.onload = function(){ var audioData = request.response; audioCtx.decodeAudioData(audioData, function(buffer){ source.buffer = buffer; data_L = buffer.getChannelData(0); data_R = buffer.getChannelData(1); // Если аудиофайл моно - поменяйте в этой сроке единицу на ноль. // При несоответствии количества стереоканалов - ошибка в консоли и код не работает. for(var i = 0; i < data_L.length; i++){ var x = Math.floor(i / data_L.length * canvas.width); var L = data_L[i] * canvas.height / 4; var R = data_R[i] * canvas.height / 4; if(Math.floor(i / 16) == i / 16){ // Число 16 для больших аудиофайлов лучше побольше. Нужно подбирать. ctx.fillStyle = color_L; ctx.fillRect(x, canvas.height * 0.25 + L, 1, -L); ctx.fillStyle = color_R; ctx.fillRect(x, canvas.height * 0.75 + R, 1, -R); } } }, function(e){"Error with decoding audio data" + e.err}); } request.send(); canvas.onmousedown = progress.onmousedown = function(e){ progress.style.width = e.pageX + "px"; audio.currentTime = e.pageX / canvas.width * audio.duration; } canvas.ondblclick = function(){audio.play()}; ctx.fillStyle = color_L; ctx.fillRect(0, canvas.height * 0.25, canvas.width, 1); ctx.fillStyle = color_R; ctx.fillRect(0, canvas.height * 0.75, canvas.width, 1); </script> </body> </html> For some reason, the graph on this site is not drawn, only the custom playback progress, but the code is working. Therefore, I attach a picture of how the graph should look like:
|
Another implementation of the oscillogram drawing, and this time without the canvas, and by programmatically creating a graphic image of a standard format right in RAM (for example, BMP format) and transferring it to the img element as src :
<html> <head> <meta charset="utf-8"> <title>Визуализатор</title> </head> <body bgcolor=#444> <img id=oscillogram width=512 height=256><br><br> <script> var osc = document.getElementById("oscillogram"); var w = osc.width,h = osc.height; var w3 = w * 3, w3h = w3 * h; var RGB = [[114, 196, 243],[243, 114, 196]]; // цвета для осциллограмы var view = new DataView(new ArrayBuffer(54 + w3h)); view.setUint8(0, 66, true); view.setUint8(1, 77, true); view.setUint32(2, w3h + 54, true); view.setUint32(6, 0, true); view.setUint32(10, 54, true); view.setUint32(14, 40, true); view.setUint32(18, w, true); view.setUint32(22, h, true); view.setUint16(26, 1, true); view.setUint16(28, 24, true); view.setUint32(30, 0, true); view.setUint32(34, w3h, true); for(i = 38; i < 54; i += 4)view.setUint32(i, 0, true); var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); var source = audioCtx.createBufferSource(); var request = new XMLHttpRequest(); request.open('GET', "sound.mp3", true); // тут путь к подключаемому аудиофайлу request.responseType = 'arraybuffer'; request.onload = function(){ audioCtx.decodeAudioData(request.response, function(buffer){ source.buffer = buffer; for(c = 0; c < 2; c++){ var data = buffer.getChannelData(c); for(i = 0; i < data.length; i += Math.floor(data.length/10000)){ var lp = data[i] * h / 4; for(j = 0; j < Math.abs(lp); j++){ for(t = 0; t < 3; t++)view.setUint8(54 + Math.floor(h * (0.75 - c / 2) + (lp >= 0 ? j : -j)) * w3 + Math.floor(i / data.length * w) * 3 + t,RGB[c][2 - t], true); } } } osc.src = URL.createObjectURL(new Blob([view], {type: "image/bmp"})); }, function(e){console.log("Ошибка чтения аудиоданных " + e.err)}); } request.send(); </script> </body> </html> There are nuances - for correct display, img id = oscillogram must be set to a multiple of four, while the code works only with stereo audio files. Audio data of only small audio files is quickly decoded, one song requires about a minute of waiting.
|
