0

I've been learning (trying to :-D) Web Audio API.Here in the follwing code i want to play a list of songs in songs[] array.
But i'm getting errors...Please help.Thank you in advance. Code:-

var sources = new Array();
var actx;
var songs = ['src1.mp3'];

function start() {
  console.log("WELCOME!!");
  try{
      actx = new AudioContext();
  }catch(e){
    console.log('WebAudio api is not supported!!');

  }
  var buffer_list =getBuffers(actx,songs);
  //console.log("hello");
  //console.log(buffer_list[1]);
  for (var x = 0;x<(buffer_list.length);x++){
    var i = actx.createBufferSource();
    sources[x] = i  ;
  }
  for (var x = 0;x<(buffer_list.length);x++){
    sources[x].buffer = buffer_list[x];

  }
  for(var x = 0;x<(buffer_list.length);x++){
    sources[x].connect(actx.destination);
  }
}

function getBuffers(actx,songs){
  var buffer_list = new Array();
  for (var x = 0;x<songs.length;x++){
    console.log(songs[x]);
      var request = new XMLHttpRequest();
      request.open('GET',songs[x],true);
      request.responseType = 'arraybuffer';
      //onload function for downloading,After sending request.
      request.onload = function(){
        var audioData = request.response;
        //console.log(audioData);
        if(audioData){
          actx.decodeAudioData(audioData,function(buffer){
            //console.log(buffer);
            console.log(x);
            buffer_list[x] = buffer;
          },
          function(e){
            console.log(e.err);
          });
      }else {
        console.error("problem!!");
      }
  }
  request.send();
}
console.log(buffer_list);
return buffer_list;

}

function play() {
  start();
  sources[0].start(0);
  //sources[1].start(0);
}
function stop(){
  sources[0].stop(0);
  //sources[1].stop(0);
}

When im debugging in web Console, i can see that the array buffer_list[] have the audio buffer in position 1 not in 0. I cheked then the value of x. Its coming 1 not 0.
But why? i've started x from 0 not 1?Please help.. And for testing purpose i've started with a single song in songs[]..

  • `XMLHttpRequest` `load` event returns results asynchronously. `for` loop does not wait the completion of the asynchronous task before proceeding to the next element in the iterable; e.g., see [FileReader does not render the image from multiple files](https://stackoverflow.com/questions/48265094/filereader-does-not-render-the-image-from-multiple-files/) – guest271314 Jan 19 '18 at 18:45
  • So @guest2734 what should I do? To get this thing right..... – Saptarshi Sahoo Jan 19 '18 at 18:47
  • 1
    You can use a closure https://stackoverflow.com/questions/13343340/calling-an-asynchronous-function-within-a-for-loop-in-javascript or `async/await` and `Promise` since the code currently expects a value other than a `Promise` object at `var buffer_list =getBuffers(actx,songs);`. Note, `decodeAudioData()` also returns results asynchronously – guest271314 Jan 19 '18 at 18:48

1 Answers1

1

You can use async/await an Promise to await the completion of multiple asynchronous tasks

var sources = new Array();
var actx;
var songs = ["https://upload.wikimedia.org/wikipedia/commons/6/6e/Micronesia_National_Anthem.ogg"];

async function start() {
  console.log("WELCOME!!");
  try {
    actx = new AudioContext();
  } catch (e) {
    console.log('WebAudio api is not supported!!');

  }
  var buffer_list = await getBuffers(actx, songs);
  //console.log("hello");
  //console.log(buffer_list[1]);
  for (var x = 0; x < (buffer_list.length); x++) {
    var i = actx.createBufferSource();
    sources[x] = i;
  }
  for (var x = 0; x < (buffer_list.length); x++) {
    sources[x].buffer = buffer_list[x];

  }
  for (var x = 0; x < (buffer_list.length); x++) {
    sources[x].connect(actx.destination);
  }
}

async function getBuffers(actx, songs) {
  var buffer_list = new Array();
  for (var x = 0; x < songs.length; x++) {
    await new Promise(function(resolve) {
    console.log(songs[x]);
    var request = new XMLHttpRequest();
    request.open('GET', songs[x], true);
    request.responseType = 'arraybuffer';
    //onload function for downloading,After sending request.
    request.onload = function() {
      var audioData = request.response;
      //console.log(audioData);
      if (audioData) {
        actx.decodeAudioData(audioData, function(buffer) {
            //console.log(buffer);
            console.log(x);
            buffer_list[x] = buffer;
            resolve()
          },
          function(e) {
            console.log(e.err);
          });
      } else {
        console.error("problem!!");
      }
    }
    request.send();
    })
  }
  console.log(buffer_list);
  return buffer_list;

}

async function play() {
  await start();
  sources[0].start(0);
  //sources[1].start(0);
}

async function stop() {
  sources[0].stop(0);
  //sources[1].stop(0);
}

play();
guest271314
  • 1
  • 15
  • 104
  • 177
  • Hello sir. Thank you for your help. I've modified the source [here](https://github.com/SAHOO98/Web-Audio-api/blob/master/wa.js) it is. When im debuging in web console. im seeing 'buffers.lenght' is coming _0_. But since **buffers** is global. i can access it from console so when im 'buffers.lenght' in console its showing _2_. I can understand that there is some **async** problem going on but cant figure out. If you can please help me. – Saptarshi Sahoo Jan 20 '18 at 15:01
  • 1
    @UzumakiSaptarshi As you described, `getBuffers()` performs asynchronous tasks. If you are expecting the result of an asynchronous task to be defined at the next line within synchronous code you can use `async/await`, as demonstrated at the code at Answer – guest271314 Jan 20 '18 at 15:52
  • Please check [it](https://github.com/SAHOO98/Web-Audio-api/blob/master/wa.js) again. I've modified it again. But still its coming _0_ not _2_. Please help. – Saptarshi Sahoo Jan 20 '18 at 16:11
  • You can include `console.log(buffer_list.length);` at line `14` at the code at stacksnippets – guest271314 Jan 20 '18 at 16:14
  • Pardon me i didnt get what are you imposing? – Saptarshi Sahoo Jan 20 '18 at 16:16
  • You can use the code at the stacksnippets at the Answer, include `console.log(buffer_list.length);` at line following `var buffer_list = await getBuffers(actx, songs);` – guest271314 Jan 20 '18 at 16:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/163549/discussion-between-uzumaki-saptarshi-and-guest271314). – Saptarshi Sahoo Jan 20 '18 at 16:19