简体   繁体   中英

how to play multiple audio with js audio api

I'm reading audio files from the server. And I have an array for raw audio files.

const allAudio = [];

Then I play them sequentially.

var volumeSeq=1;

    function playAudio(){
     if(volumeSeq==allAudio.length){ volumeSeq=1;}
      var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
      source = audioCtx.createBufferSource();
      audioCtx.decodeAudioData(allAudio[volumeSeq], function(buffer) {
      source.buffer = buffer;
      console.log(source.buffer);
      source.connect(audioCtx.destination);
      source.loop = false;});

      source.start(0);
      source.onended = function () {
        volumeSeq++;
        playAudio();
}

I catch the problem. But I don't know why. Problem is, that after the decoding i.element of the array, the element in it is being deleted. I mean when I decode the allAudio[1] then allAudio[1] is empty. So I cant create a loop for these audio tracks.

What should i do?

Why don't you decode all audio files at the begining, and then loop through them? Like this:

var allAudio = [];
var audioCtx = new AudioContext();
var volumeSeq = 0;
var decodedAudio = [];

function decodeAudio() {
    allAudio.forEach(function (file, index) {
        audioCtx.decodeAudioData(file, function(buffer) {
            decodedAudio[index] = buffer;
            if (decodedAudio.length >= allAudio.length) {
                play();
            }
        })
     })
}
function play() {
    if (volumeSeq >= allAudio.length){ volumeSeq=0;}
    var source = audioCtx.createBufferSource();
    source.buffer = decodedAudio[volumeSeq];
    source.connect(audioCtx.destination);
    source.start(0);
    source.onended = function () {
        volumeSeq++;
        play();
    }
}
decodeAudio();

Few more things:

  • You don't need to create AudioContext every time.
  • AudioBufferSourceNode.loop is false by default. You can skip source.loop = false;
  • Every new variable should start with const , let or var . You are missing it with source . BTW nowadays it is beter to use const and let , not var . I will show it in next "modern" example.
  • I don't know why you iterate allAudio starting from index 1. First index in array is 0.

If you don't care about old browsers like IE, you can make code cleaner by using Promises and async/await :

const audioCtx = new AudioContext();
async function start() {
   const decodedAudio = await Promise.all(allAudio.map((file) => audioCtx.decodeAudioData(file)));
   let volumeSeq = 0;
   function play() {
        if(volumeSeq >= allAudio.length) volumeSeq = 0;
        const source = audioCtx.createBufferSource();
        source.buffer = decodedAudio[volumeSeq];
        source.connect(audioCtx.destination);
        source.start(0);
        source.addEventListener('ended', () => {
           volumeSeq++;
           play();
        }, { once: true })
   }
   play();
}
start()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM