Tengo una serie de archivos de audio importados y estoy tratando de reproducirlos secuencialmente con Web Audio API. Tengo un código que casi funciona, pero reproduce los sonidos en el orden incorrecto, aparentemente al azar.
¿Alguien puede decirme qué estoy haciendo mal o si hay una mejor manera de lograr mi objetivo?
import soundA from './assets/soundA.mp3' import soundB from './assets/soundB.mp3' import soundC from './assets/soundC.mp3' function playSoundsSequentially() { let mySounds = [soundA, soundB, soundC] const ctx = new window.AudioContext(); let time = 0; mySounds.forEach(sound => fetch(sound).then(response => response.arrayBuffer()) .then(buffer => ctx.decodeAudioData(buffer)) .then(buffer => { let track = ctx.createBufferSource(); track.buffer = buffer; track.connect(ctx.destination); track.start(ctx.currentTime + time); time += track.buffer.duration; })); }Actualización: mi solución basada en la visión de JMP sobre el uso de promesas. También abandoné el forEach por un bucle for simple porque me siento más cómodo con eso.
import soundA from './assets/soundA.mp3' import soundB from './assets/soundB.mp3' import soundC from './assets/soundC.mp3' function playSoundsSequentially() { let mySounds = [soundA, soundB, soundC] let promises = [] for(let i = 0; i < mySounds.length; ++i) { promises.push(fetch(mySounds[i]).then(response => response.arrayBuffer()) .then(buffer => ctx.decodeAudioData(buffer))); } Promise.all(promises).then(buffer => { for(let i = 0; i < buffer.length; ++i) { let track = ctx.createBufferSource(); track.buffer = buffer[i]; track.connect(ctx.destination); track.start(ctx.currentTime + time); time += track.buffer.duration; } }); }Tu pregunta es muy similar a esta pregunta:
¿Por qué AJAX está en el ciclo for ejecutándose en el orden incorrecto?
Su código ensambla las pistas en el orden en que se devuelven, no en el orden en que se enviaron,
Promise.all() se ocupa de una matriz de promesas ( MDN ), y también es una Promise en sí misma, que solo se cumple cuando todos los elementos de la matriz lo están, devolviendo una matriz en el orden original.
Probar
let mySounds = [soundA, soundB, soundC] const ctx = new window.AudioContext(); let time = 0; mySounds.forEach(sound => fetch(sound).then(response => response.arrayBuffer()) .then(buffer => ctx.decodeAudioData(buffer))); Promise.all(mySounds).then(buffer => { let track = ctx.createBufferSource(); track.buffer = buffer; track.connect(ctx.destination); track.start(ctx.currentTime + time); time += track.buffer.duration; });