Skip to content

Instantly share code, notes, and snippets.

@qwtel
Last active August 29, 2015 14:04
Show Gist options
  • Save qwtel/957f7d339886417e7f4a to your computer and use it in GitHub Desktop.
Save qwtel/957f7d339886417e7f4a to your computer and use it in GitHub Desktop.
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;
});
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