 隆Buen dia amigos!Quiero compartir experiencia con audio. Por "audio" me refiero a HTMLAudioElement y Web Audio API.qu茅 hacemos?Crearemos algo as铆 como un jugador para una pista (sobre un jugador de pleno derecho, en uno de los siguientes art铆culos).Condiciones:
隆Buen dia amigos!Quiero compartir experiencia con audio. Por "audio" me refiero a HTMLAudioElement y Web Audio API.qu茅 hacemos?Crearemos algo as铆 como un jugador para una pista (sobre un jugador de pleno derecho, en uno de los siguientes art铆culos).Condiciones:- La capacidad de descargar un archivo desde cualquier lugar del disco duro, ya sea con el clic de un bot贸n o arrastrando y soltando.
- Indicadores circulares de progreso gr谩fico y de texto.
- Indicador de texto del volumen del sonido.
- Visualizaci贸n de datos de audio.
- Controla al jugador usando el teclado.
La red est谩 llena de materiales sobre HTMLAudioElement y WAAPI , por lo que me centrar茅 en el componente pr谩ctico. Adem谩s del audio, trabajaremos con arrastrar y soltar y lienzo .Sin m谩s introducci贸n ...S铆, casi lo olvido: tom茅 el trabajo de uno de los ciudadanos de Habrovsk como la base del "visualizador". No puedo encontrarlo buscando. Agradecer铆a la referencia.As铆 es como se ve nuestro marcado:<p>click or drag</p>
<div dropzone>
    <img src="https://thebestcode.ru/media/audioProgress&Visualizer/plus.png" alt="#">
    <input type="file" accept="audio/*">
</div>
<canvas></canvas>
Tenemos una informaci贸n sobre herramientas (p谩rrafo), un bot贸n (imagen + "entrada" con el atributo accept en el contenedor con el atributo dropzone )y un lienzo.Como puede ver, nada inusual.Nada sobrenatural en estilos tampoco.CSS:@font-face {
  font-family: "Nova Mono", monospace;
  src: url("https://thebestcode.ru/media/audioProgress&Visualizer/font.ttf");
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  height: 100vh;
  background: radial-gradient(circle, #666, #222);
  display: flex;
  justify-content: center;
  align-items: center;
}
p {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -70px);
  color: #ddd;
  text-align: center;
  text-transform: uppercase;
  font-family: "Nova Mono", monospace;
  font-size: 0.8em;
  font-weight: bold;
  letter-spacing: 2px;
  user-select: none;
}
span {
  display: block;
  font-size: 1.6em;
}
div {
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
  border: 1px dashed #ddd;
  border-radius: 10%;
  cursor: pointer;
}
img {
  width: 70px;
  height: 70px;
  filter: invert();
}
input {
  display: none;
}
canvas {
  display: none;
}
 Pasamos a JS.Declaramos las principales variables:let dropZone = document.querySelector("div"),
    input = document.querySelector("input"),
    file,
    text,
    progress,
    volume,
    audio,
    
    frequencyArray;
Trabajamos con arrastrar y soltar:
dropZone.ondrop = e => {
    
    e.preventDefault();
    
    if (e.dataTransfer.items[0].kind == "file") {
        
        file = e.dataTransfer.items[0].getAsFile();
    } else return;
    
    playTrack(file);
};
dropZone.ondragover = e => {
    
    e.preventDefault();
};
dropZone.onclick = () => {
    
    input.click();
    
    input.onchange = () => {
        
        file = input.files[0];
        
        playTrack(file);
    };
};
Seguimos.Declarar variables para el lienzo:let C = document.querySelector("canvas"),
    $ = C.getContext("2d"),
    W = (C.width = innerWidth),
    H = (C.height = innerHeight),
    centerX = W / 2,
    centerY = H / 2,
    radius,
    
    piece,
    
    bars = 200,
    x,
    y,
    xEnd,
    yEnd,
    
    barWidth = 2,
    
    barHeight,
    
    lineColor;
Procedemos a la funci贸n principal (todo nuestro c贸digo adicional estar谩 en esta funci贸n):function playTrack(file) {
    
}
Eliminamos la zona (ya no la necesitamos), cambiamos el texto del p谩rrafo, inicializamos las variables de sonido y progreso:dropZone.style.display = "none";
text = document.querySelector("p");
text.style.transform = "translate(-50%,-50%)";
text.innerHTML = `progress: <span class="progress"></span> <br> volume: <span class="volume"></span>`;
volume = document.querySelector(".volume");
progress = document.querySelector(".progress");
Conjurando con sonido:audio = new Audio();
context = new AudioContext();
analyser = context.createAnalyser();
audio.src = URL.createObjectURL(file);
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);
frequencyArray = new Uint8Array(analyser.frequencyBinCount);
audio.play();
audio.loop = true;
Agregue la capacidad de controlar el reproductor (no tenemos botones, por lo que puede controlar el reproductor solo con el teclado):document.addEventListener("keydown", e => {
    
    
    
    
    
    try {
        
        e.preventDefault()
        
        if (e.keyCode == 32) {
            
            audio.paused ? audio.play() : audio.pause();
        
        } else if (e.keyCode == 13) {
            
            audio.load();
        
        } else if (e.keyCode == 39) {
            
            audio.currentTime += 10;
        
        } else if (e.keyCode == 37) {
            
            audio.currentTime -= 10;
        
        } else if (e.keyCode == 40) {
            
            audio.volume -= 0.1;
        
        } else if (e.keyCode == 38) {
            
            audio.volume += 0.1;
        }
    
    } catch {
        return;
    }
});
console.log(
    " Use Keyboard: \n Space to Play/Pause \n Enter to Stop \n Arrows to Change \n Time and Volume"
);
La siguiente parte es animaci贸n. Llamamos a la funci贸n correspondiente:startAnimation();
La funci贸n en s铆 es la siguiente:function startAnimation() {
    
    C.style.display = "block";
    
    piece = audio.currentTime / audio.duration;
    
    
    radius = 105;
    
    
    $.clearRect(0, 0, W, H);
    
    
    $.beginPath();
    $.arc(centerX, centerY, radius, 0, Math.PI * (2 * piece));
    $.lineWidth = 30;
    $.stroke();
    
    
    volume.innerText = Math.trunc(audio.volume * 100) + "%";
    
    
    progress.innerText = Math.trunc(piece * 100) + "%";
    
    analyser.getByteFrequencyData(frequencyArray);
    
    for (let i = 0; i < bars; i++) {
        
        radius = 120;
        
        rads = Math.PI * 2 / bars;
        
        barHeight = frequencyArray[i] * 0.6;
        
        
        x = centerX + Math.cos(rads * i) * radius;
        y = centerY + Math.sin(rads * i) * radius;
        xEnd = centerX + Math.cos(rads * i) * (radius + barHeight);
        yEnd = centerY + Math.sin(rads * i) * (radius + barHeight);
        
        
        drawBar(x, y, xEnd, yEnd, barWidth, frequencyArray[i]);
    }
    
    requestAnimationFrame(startAnimation);
}
Y finalmente - renderizar columnas:
function drawBar(x1, y1, x2, y2, width, frequency) {
    
    lineColor = "rgb(" + frequency + ", " + frequency + ", " + 205 + ")";
    
    
    $.strokeStyle = lineColor;
    $.lineWidth = width;
    $.beginPath();
    $.moveTo(x1, y1);
    $.lineTo(x2, y2);
    $.stroke();
}
El resultado se puede ver aqu铆 .Gracias por su atenci贸n.