Reputation: 13
I'm developping a simple web application which needs to load 16 audio files to process an hearing test. But my code is loading the files twice!
The application needs to be very light and fast, so it's a big problem.
For the same reason, i don't want to use jQuery libraries.
function loadSound(array) {
var i = 0;
array.forEach(function(soundUrl) {
var request = new XMLHttpRequest();
request.open('GET', soundUrl, true);
request.responseType = 'arraybuffer';
request.onloadend = function() {
var audioData = request.response;
contextAudio.decodeAudioData(audioData, function(buffer) {
sources[i] = contextAudio.createBufferSource();
sources[i].buffer = buffer;
sources[i].connect(contextAudio.destination);
i++
});
};
request.send(null);
});
}
The soundList array and loadSound calling:
var soundList = new Array(
'http://localhost/testauditif/sons/440L.wav',
'http://localhost/testauditif/sons/440R.wav',
'http://localhost/testauditif/sons/125L.wav',
'http://localhost/testauditif/sons/125R.wav',
'http://localhost/testauditif/sons/250L.wav',
'http://localhost/testauditif/sons/250R.wav',
'http://localhost/testauditif/sons/500L.wav',
'http://localhost/testauditif/sons/500R.wav',
'http://localhost/testauditif/sons/1000L.wav',
'http://localhost/testauditif/sons/1000R.wav',
'http://localhost/testauditif/sons/2000L.wav',
'http://localhost/testauditif/sons/2000R.wav',
'http://localhost/testauditif/sons/4000L.wav',
'http://localhost/testauditif/sons/4000R.wav',
'http://localhost/testauditif/sons/8000L.wav',
'http://localhost/testauditif/sons/8000R.wav'
);
loadSound(soundList);
The javascript console: XHRGEThttp://localhost/testauditif/sons/440L.wav [HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/440R.wav
[HTTP/1.1 200 OK 0ms]
0 script.js:88:12
XHRGEThttp://localhost/testauditif/sons/125L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/125R.wav
[HTTP/1.1 200 OK 0ms]
0 script.js:88:12
XHRGEThttp://localhost/testauditif/sons/250L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/250R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/500L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/500R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/1000L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/1000R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/2000L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/2000R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/4000L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/4000R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/8000L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/8000R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/440L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/440R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/125L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/125R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/250L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/250R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/500L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/500R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/1000L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/1000R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/2000L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/2000R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/4000L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/4000R.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/8000L.wav
[HTTP/1.1 200 OK 0ms]
XHRGEThttp://localhost/testauditif/sons/8000R.wav
[HTTP/1.1 200 OK 0ms]
Upvotes: 1
Views: 80
Reputation: 910
Closures!!!
Lets take a clos(ure)er look at what's happening with your code.
You start iterating over the array with each URL defined as soundUrl
in array.forEach(function(soundUrl) {})
. Please note that variable i
is retained as it is inside this anonymous function because it is defined in the loadSound
function.
You send your request using request.send(null);
. In the request.onloadend
function, the i
value is 0. All good so far.
Now comes the trouble. Without waiting for onloadend
to be called, you move to the next soundUrl
in your forEach loop. When the request.onloadend
is initialized, the i
value is still 0 unless onloadend
for previous request is already called. (This is highly unlikely assuming the audio files take a while to download to browser)
Somewhere in middle of your forEach loop, request.onloadend
get called for your first request incrementing the i
.
End result? You end up with a pile garbage for in sources
array where few files are downloaded, few are overwritten by next audio files with gaping holes in between.
PS: As the code stands, it doesn't work. Is that the real issue? May be. Without further information about what the array
contains and how many requests the code is sending to backend.
The solution I would suggest.
function loadSound(array) {
array.forEach(function(soundUrl, i) {
// No need to declare var i for iteration. Foreach provides the index.
var request = new XMLHttpRequest();
// Creating an instance of XMLHttpRequest inside loop to ensure
// request.onloadend does not get overriden in the next iteration.
request.open('GET', soundUrl, true);
request.responseType = 'arraybuffer';
request.onloadend = function() {
// Retain i inside the function using a local variable inside the callback function.
var idx = i;
var audioData = request.response;
contextAudio.decodeAudioData(audioData, function(buffer) {
// Not sure whether decodeAudioData in asyc. If so, you again need to retain idx inside the callback.
var src_idx = idx;
sources[src_idx] = contextAudio.createBufferSource();
sources[src_idx].buffer = buffer;
sources[src_idx].connect(contextAudio.destination);
});
};
request.send(null);
});
}
Upvotes: 1
Reputation: 444
Please try if this solves your problem
This version is not using var i
for setting things in sources. If you need i
later to know how many sources have been buffered. just make i
the length of sources
.
const request = new XMLHttpRequest();
var sources = null;
var i = null; // only if you want to keep i
function loadSound(array) {
console.log(array); // only here for testing
var sources = []; // define or re-define sources as empty array
array.forEach(function(soundUrl) {
request.open('GET', soundUrl, true);
request.responseType = 'arraybuffer';
request.onloadend = function() {
console.log(request); // only here for testing
var audioData = request.response;
contextAudio.decodeAudioData(audioData, function(buffer) {
let newsource = contextAudio.createBufferSource();
// let is ES6 style it can also work without let
newsource.buffer = buffer;
newsource.connect(contextAudio.destination);
sources.push(newsource);
// added your new source to your sources array
var i = sources.length;
// if you need var i elsewhere it now contains total number of sources
// if you don't need var i hereafter remove it from the code
console.log(sources); // only here for testing
});
};
request.send(null);
});
}
Upvotes: 0