UNPKG

lettuce

Version:

Lettuce JS, Mini Mobile Framework for Romantic with DSL.

494 lines (460 loc) 15.8 kB
/* * MelonJS Game Engine * Copyright (C) 2011 - 2013, Olivier BIOT * http://www.melonjs.org * * Audio Mngt Objects * * */ (function () { /** * There is no constructor function for me.audio. * @namespace me.audio * @memberOf me */ me.audio = (function () { /* * PRIVATE STUFF */ // hold public stuff in our singleton var api = {}; // audio channel list var audioTracks = {}; // current music var current_track_id = null; // a retry counter var retry_counter = 0; /** * event listener callback on load error * @ignore */ function soundLoadError(sound_name, onerror_cb) { // check the retry counter if (retry_counter++ > 3) { // something went wrong var errmsg = "melonJS: failed loading " + sound_name; if (me.sys.stopOnAudioError === false) { // disable audio me.audio.disable(); // call error callback if defined if (onerror_cb) { onerror_cb(); } // warning console.log(errmsg + ", disabling audio"); } else { // throw an exception and stop everything ! throw new api.Error(errmsg); } // else try loading again ! } else { audioTracks[sound_name].load(); } } /* * PUBLIC STUFF */ /** * Base class for Audio exception handling. * @name Error * @class * @memberOf me.audio * @constructor * @param {String} msg Error message. */ api.Error = me.Error.extend({ init : function (msg) { this._super(me.Error, "init", [ msg ]); this.name = "me.audio.Error"; } }); /** * initialize the audio engine<br> * the melonJS loader will try to load audio files corresponding to the * browser supported audio format<br> * if no compatible audio codecs are found, audio will be disabled * @name init * @memberOf me.audio * @public * @function * @param {String} * audioFormat audio format provided ("mp3, ogg, m4a, wav") * @return {Boolean} Indicates whether audio initialization was successful * @example * // initialize the "sound engine", giving "mp3" and "ogg" as desired audio format * // i.e. on Safari, the loader will load all audio.mp3 files, * // on Opera the loader will however load audio.ogg files * if (!me.audio.init("mp3,ogg")) { * alert("Sorry but your browser does not support html 5 audio !"); * return; * } */ api.init = function (audioFormat) { if (!me.initialized) { throw new api.Error("me.audio.init() called before engine initialization."); } // if no param is given to init we use mp3 by default audioFormat = typeof audioFormat === "string" ? audioFormat : "mp3"; // convert it into an array this.audioFormats = audioFormat.split(","); return !Howler.noAudio; }; /** * enable audio output <br> * only useful if audio supported and previously disabled through * * @see me.audio#disable * @name enable * @memberOf me.audio * @public * @function */ api.enable = function () { this.unmuteAll(); }; /** * disable audio output * * @name disable * @memberOf me.audio * @public * @function */ api.disable = function () { this.muteAll(); }; /** * Load an audio file.<br> * <br> * sound item must contain the following fields :<br> * - name : name of the sound<br> * - src : source path<br> * @ignore */ api.load = function (sound, onload_cb, onerror_cb) { var urls = []; if (typeof(this.audioFormats) === "undefined" || this.audioFormats.length === 0) { throw new api.Error("target audio extension(s) should be set through me.audio.init() before calling the preloader."); } for (var i = 0; i < this.audioFormats.length; i++) { urls.push(sound.src + sound.name + "." + this.audioFormats[i] + me.loader.nocache); } audioTracks[sound.name] = new Howl({ src : urls, volume : Howler.volume(), onloaderror : function () { audioTracks[sound.name] = this; soundLoadError.call(me.audio, sound.name, onerror_cb); }, onload : function () { audioTracks[sound.name] = this; retry_counter = 0; if (onload_cb) { onload_cb(); } } }); return 1; }; /** * play the specified sound * @name play * @memberOf me.audio * @public * @function * @param {String} sound_name audio clip name * @param {Boolean} [loop=false] loop audio * @param {Function} [onend] Function to call when sound instance ends playing. * @param {Number} [volume=default] Float specifying volume (0.0 - 1.0 values accepted). * @return {Number} the sound instance ID. * @example * // play the "cling" audio clip * me.audio.play("cling"); * // play & repeat the "engine" audio clip * me.audio.play("engine", true); * // play the "gameover_sfx" audio clip and call myFunc when finished * me.audio.play("gameover_sfx", false, myFunc); * // play the "gameover_sfx" audio clip with a lower volume level * me.audio.play("gameover_sfx", false, null, 0.5); */ api.play = function (sound_name, loop, onend, volume) { var sound = audioTracks[sound_name.toLowerCase()]; if (sound && typeof sound !== "undefined") { var instance_id = sound.play(); if (typeof loop === "boolean") { // arg[0] can take different types in howler 2.0 sound.loop(loop, instance_id); } sound.volume(typeof(volume) === "number" ? volume.clamp(0.0, 1.0) : Howler.volume(), instance_id); if (typeof(onend) === "function") { if (loop === true) { sound.on("end", onend, instance_id); } else { sound.once("end", onend, instance_id); } } return instance_id; } }; /** * Fade a currently playing sound between two volumee. * @name fade * @memberOf me.audio * @public * @function * @param {String} sound_name audio clip name * @param {Number} from Volume to fade from (0.0 to 1.0). * @param {Number} to Volume to fade to (0.0 to 1.0). * @param {Number} duration Time in milliseconds to fade. * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will fade. */ api.fade = function (sound_name, from, to, duration, instance_id) { var sound = audioTracks[sound_name.toLowerCase()]; if (sound && typeof sound !== "undefined") { sound.fade(from, to, duration, instance_id); } }; /** * stop the specified sound on all channels * @name stop * @memberOf me.audio * @public * @function * @param {String} sound_name audio clip name * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will stop. * @example * me.audio.stop("cling"); */ api.stop = function (sound_name, instance_id) { var sound = audioTracks[sound_name.toLowerCase()]; if (sound && typeof sound !== "undefined") { sound.stop(instance_id); // remove the defined onend callback (if any defined) sound.off("end", instance_id); } }; /** * pause the specified sound on all channels<br> * this function does not reset the currentTime property * @name pause * @memberOf me.audio * @public * @function * @param {String} sound_name audio clip name * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will pause. * @example * me.audio.pause("cling"); */ api.pause = function (sound_name, instance_id) { var sound = audioTracks[sound_name.toLowerCase()]; if (sound && typeof sound !== "undefined") { sound.pause(instance_id); } }; /** * play the specified audio track<br> * this function automatically set the loop property to true<br> * and keep track of the current sound being played. * @name playTrack * @memberOf me.audio * @public * @function * @param {String} sound_name audio track name * @param {Number} [volume=default] Float specifying volume (0.0 - 1.0 values accepted). * @return {Number} the sound instance ID. * @example * me.audio.playTrack("awesome_music"); */ api.playTrack = function (sound_name, volume) { current_track_id = sound_name.toLowerCase(); return me.audio.play( current_track_id, true, null, volume ); }; /** * stop the current audio track * * @see me.audio#playTrack * @name stopTrack * @memberOf me.audio * @public * @function * @example * // play a awesome music * me.audio.playTrack("awesome_music"); * // stop the current music * me.audio.stopTrack(); */ api.stopTrack = function () { if (current_track_id !== null) { audioTracks[current_track_id].stop(); current_track_id = null; } }; /** * pause the current audio track * * @name pauseTrack * @memberOf me.audio * @public * @function * @example * me.audio.pauseTrack(); */ api.pauseTrack = function () { if (current_track_id !== null) { audioTracks[current_track_id].pause(); } }; /** * resume the previously paused audio track * * @name resumeTrack * @memberOf me.audio * @public * @function * @example * // play an awesome music * me.audio.playTrack("awesome_music"); * // pause the audio track * me.audio.pauseTrack(); * // resume the music * me.audio.resumeTrack(); */ api.resumeTrack = function () { if (current_track_id !== null) { audioTracks[current_track_id].play(); } }; /** * returns the current track Id * @name getCurrentTrack * @memberOf me.audio * @public * @function * @return {String} audio track name */ api.getCurrentTrack = function () { return current_track_id; }; /** * set the default global volume * @name setVolume * @memberOf me.audio * @public * @function * @param {Number} volume Float specifying volume (0.0 - 1.0 values accepted). */ api.setVolume = function (volume) { Howler.volume(volume); }; /** * get the default global volume * @name getVolume * @memberOf me.audio * @public * @function * @returns {Number} current volume value in Float [0.0 - 1.0] . */ api.getVolume = function () { return Howler.volume(); }; /** * mute the specified sound * @name mute * @memberOf me.audio * @public * @function * @param {String} sound_name audio clip name * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will mute. */ api.mute = function (sound_name, instance_id, mute) { // if not defined : true mute = (typeof(mute) === "undefined" ? true : !!mute); var sound = audioTracks[sound_name.toLowerCase()]; if (sound && typeof(sound) !== "undefined") { sound.mute(mute, instance_id); } }; /** * unmute the specified sound * @name unmute * @memberOf me.audio * @public * @function * @param {String} sound_name audio clip name * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will unmute. */ api.unmute = function (sound_name, instance_id) { api.mute(sound_name, instance_id, false); }; /** * mute all audio * @name muteAll * @memberOf me.audio * @public * @function */ api.muteAll = function () { Howler.mute(true); }; /** * unmute all audio * @name unmuteAll * @memberOf me.audio * @public * @function */ api.unmuteAll = function () { Howler.mute(false); }; /** * unload specified audio track to free memory * * @name unload * @memberOf me.audio * @public * @function * @param {String} sound_name audio track name * @return {Boolean} true if unloaded * @example * me.audio.unload("awesome_music"); */ api.unload = function (sound_name) { sound_name = sound_name.toLowerCase(); if (!(sound_name in audioTracks)) { return false; } // destroy the Howl object audioTracks[sound_name].unload(); delete audioTracks[sound_name]; return true; }; /** * unload all audio to free memory * * @name unloadAll * @memberOf me.audio * @public * @function * @example * me.audio.unloadAll(); */ api.unloadAll = function () { for (var sound_name in audioTracks) { if (audioTracks.hasOwnProperty(sound_name)) { api.unload(sound_name); } } }; // return our object return api; })(); })();