Last active
August 29, 2015 14:04
-
-
Save qwtel/957f7d339886417e7f4a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define([ | |
'promise' | |
], function (Promise) { | |
/** | |
* @param urlWithoutExtension {String} - the path to the sound file without a particular extension. | |
* @param audioContext {AudioContext} - the audio context of the sound file, used for decoding. | |
* @returns {Promise} - a promise containing the decoded audio data. | |
*/ | |
function getSoundBuffer(urlWithoutExtension, audioContext) { | |
return new Promise(function (resolve, reject) { | |
var formats = [ | |
{extension: 'mp3', mimeType: 'audio/mpeg;'}, | |
{extension: 'ogg', mimeType: 'audio/ogg; codecs="vorbis"'}, | |
{extension: 'wav', mimeType: 'audio/wav; codecs="1"'}, | |
{extension: 'aac', mimeType: 'audio/mp4; codecs="mp4a.40.2"'} | |
]; | |
/** | |
* Checks if the browser supports the following formats: mp3, ogg, wav, aac. | |
* @param urlWithoutExtension {String} - the path to the sound file without a particular extension. | |
* @returns {Array} - An array of urls for sound files who's encoding the browser supports. | |
*/ | |
function getSupportedUrls(urlWithoutExtension) { | |
var a = document.createElement('audio'); | |
function canPlayType(type) { | |
return !!(a.canPlayType && a.canPlayType(type).replace(/no/, '')); | |
} | |
var res = formats.filter(function (format) { | |
return canPlayType(format.mimeType) | |
}).map(function (format) { | |
return urlWithoutExtension + '.' + format.extension | |
}); | |
if (res.length === 0) { | |
console.warn("No available encoding supported by this browser"); | |
} | |
return res; | |
} | |
/** | |
* Makes a XMLHttpRequest to the server at the given url and expects a 'arraybuffer' response. | |
* @param url {String} - the full path to the resource | |
* @returns {Promise} - a promise containing the response | |
*/ | |
function getArrayBuffer(url) { | |
return new Promise(function (resolve, reject) { | |
// Do the usual XHR stuff | |
var req = new XMLHttpRequest(); | |
req.open('GET', url); | |
req.responseType = 'arraybuffer'; | |
req.onload = function () { | |
// This is called even on 404 etc | |
// so check the status | |
if (req.status == 200) { | |
// Resolve the promise with the response text | |
resolve(req.response); | |
} | |
else { | |
// Otherwise reject with the status text | |
// which will hopefully be a meaningful error | |
reject(Error(req.statusText)); | |
} | |
}; | |
// Handle network errors | |
req.onerror = function () { | |
reject(Error("Network Error")); | |
}; | |
// Make the request | |
req.send(); | |
}); | |
} | |
/** | |
* @param data {ArrayBuffer} - the raw audio data | |
* @returns {Promise} - a promise containing the decoded audio data | |
*/ | |
var decodeAudioData = function (data) { | |
return new Promise(function (resolve, reject) { | |
audioContext.decodeAudioData(data, function (soundBuffer) { | |
resolve(soundBuffer); | |
}, function () { | |
// This should never happen since we checked with canPlayType earlier | |
reject(Error("Error while decoding " + url)); | |
}); | |
}); | |
}; | |
var urls = getSupportedUrls(urlWithoutExtension); | |
/** | |
* Tries to load the first url in urls and then decoding the audio data. | |
* Will try the next url if it fails until an url is resolved or the list of urls is empty. | |
* @param urls {Array<String>} - a array of urls to audio resources. | |
*/ | |
function tryLoadUrls(urls) { | |
if (urls.length === 0) { | |
reject(Error("Can't load any available format of " + urlWithoutExtension)); | |
} else { | |
var url = urls.pop(); // head | |
getArrayBuffer(url) | |
.then(decodeAudioData) | |
.then(resolve) | |
.catch(function (error) { | |
console.warn(error); | |
tryLoadUrls(urls.splice(0)); // tail | |
}); | |
} | |
} | |
tryLoadUrls(urls.reverse()); | |
}); | |
} | |
return getSoundBuffer; | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var context = new AudioContext(); | |
getSoundBuffer('sounds/ring', context).then(function (soundBuffer) { | |
var source = context.createBufferSource(); // creates a sound source | |
source.buffer = soundBuffer; // tell the source which sound to play | |
source.connect(context.destination); // connect the source to the context's destination (the speakers) | |
if (!source.start) source.start = source.noteOn; | |
source.start(0); // play the source now | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment