// ---------------------------------------------------------------------------- // Buzz, a Javascript HTML5 Audio library // v1.1.0 - released 2013-08-15 13:18 // Licensed under the MIT license. // http://buzz.jaysalvat.com/ // ---------------------------------------------------------------------------- // Copyright (C) 2010-2013 Jay Salvat // http://jaysalvat.com/ // ---------------------------------------------------------------------------- (function(name, context, factory) { if (typeof module !== "undefined" && module.exports) { module.exports = factory(); } else if (typeof context.define === "function" && context.define.amd) { define(name, [], factory); } else { context[name] = factory(); } })("buzz", this, function() { var buzz = { defaults: { autoplay: false, duration: 5e3, formats: [], loop: false, placeholder: "--", preload: "metadata", volume: 80, document: document }, types: { mp3: "audio/mpeg", ogg: "audio/ogg", wav: "audio/wav", aac: "audio/aac", m4a: "audio/x-m4a" }, sounds: [], el: document.createElement("audio"), sound: function(src, options) { options = options || {}; var doc = options.document || buzz.defaults.document; var pid = 0, events = [], eventsOnce = {}, supported = buzz.isSupported(); this.load = function() { if (!supported) { return this; } this.sound.load(); return this; }; this.play = function() { if (!supported) { return this; } this.sound.play(); return this; }; this.togglePlay = function() { if (!supported) { return this; } if (this.sound.paused) { this.sound.play(); } else { this.sound.pause(); } return this; }; this.pause = function() { if (!supported) { return this; } this.sound.pause(); return this; }; this.isPaused = function() { if (!supported) { return null; } return this.sound.paused; }; this.stop = function() { if (!supported) { return this; } this.setTime(0); this.sound.pause(); return this; }; this.isEnded = function() { if (!supported) { return null; } return this.sound.ended; }; this.loop = function() { if (!supported) { return this; } this.sound.loop = "loop"; this.bind("ended.buzzloop", function() { this.currentTime = 0; this.play(); }); return this; }; this.unloop = function() { if (!supported) { return this; } this.sound.removeAttribute("loop"); this.unbind("ended.buzzloop"); return this; }; this.mute = function() { if (!supported) { return this; } this.sound.muted = true; return this; }; this.unmute = function() { if (!supported) { return this; } this.sound.muted = false; return this; }; this.toggleMute = function() { if (!supported) { return this; } this.sound.muted = !this.sound.muted; return this; }; this.isMuted = function() { if (!supported) { return null; } return this.sound.muted; }; this.setVolume = function(volume) { if (!supported) { return this; } if (volume < 0) { volume = 0; } if (volume > 100) { volume = 100; } this.volume = volume; this.sound.volume = volume / 100; return this; }; this.getVolume = function() { if (!supported) { return this; } return this.volume; }; this.increaseVolume = function(value) { return this.setVolume(this.volume + (value || 1)); }; this.decreaseVolume = function(value) { return this.setVolume(this.volume - (value || 1)); }; this.setTime = function(time) { if (!supported) { return this; } var set = true; this.whenReady(function() { if (set === true) { set = false; this.sound.currentTime = time; } }); return this; }; this.getTime = function() { if (!supported) { return null; } var time = Math.round(this.sound.currentTime * 100) / 100; return isNaN(time) ? buzz.defaults.placeholder : time; }; this.setPercent = function(percent) { if (!supported) { return this; } return this.setTime(buzz.fromPercent(percent, this.sound.duration)); }; this.getPercent = function() { if (!supported) { return null; } var percent = Math.round(buzz.toPercent(this.sound.currentTime, this.sound.duration)); return isNaN(percent) ? buzz.defaults.placeholder : percent; }; this.setSpeed = function(duration) { if (!supported) { return this; } this.sound.playbackRate = duration; return this; }; this.getSpeed = function() { if (!supported) { return null; } return this.sound.playbackRate; }; this.getDuration = function() { if (!supported) { return null; } var duration = Math.round(this.sound.duration * 100) / 100; return isNaN(duration) ? buzz.defaults.placeholder : duration; }; this.getPlayed = function() { if (!supported) { return null; } return timerangeToArray(this.sound.played); }; this.getBuffered = function() { if (!supported) { return null; } return timerangeToArray(this.sound.buffered); }; this.getSeekable = function() { if (!supported) { return null; } return timerangeToArray(this.sound.seekable); }; this.getErrorCode = function() { if (supported && this.sound.error) { return this.sound.error.code; } return 0; }; this.getErrorMessage = function() { if (!supported) { return null; } switch (this.getErrorCode()) { case 1: return "MEDIA_ERR_ABORTED"; case 2: return "MEDIA_ERR_NETWORK"; case 3: return "MEDIA_ERR_DECODE"; case 4: return "MEDIA_ERR_SRC_NOT_SUPPORTED"; default: return null; } }; this.getStateCode = function() { if (!supported) { return null; } return this.sound.readyState; }; this.getStateMessage = function() { if (!supported) { return null; } switch (this.getStateCode()) { case 0: return "HAVE_NOTHING"; case 1: return "HAVE_METADATA"; case 2: return "HAVE_CURRENT_DATA"; case 3: return "HAVE_FUTURE_DATA"; case 4: return "HAVE_ENOUGH_DATA"; default: return null; } }; this.getNetworkStateCode = function() { if (!supported) { return null; } return this.sound.networkState; }; this.getNetworkStateMessage = function() { if (!supported) { return null; } switch (this.getNetworkStateCode()) { case 0: return "NETWORK_EMPTY"; case 1: return "NETWORK_IDLE"; case 2: return "NETWORK_LOADING"; case 3: return "NETWORK_NO_SOURCE"; default: return null; } }; this.set = function(key, value) { if (!supported) { return this; } this.sound[key] = value; return this; }; this.get = function(key) { if (!supported) { return null; } return key ? this.sound[key] : this.sound; }; this.bind = function(types, func) { if (!supported) { return this; } types = types.split(" "); var self = this, efunc = function(e) { func.call(self, e); }; for (var t = 0; t < types.length; t++) { var type = types[t], idx = type; type = idx.split(".")[0]; events.push({ idx: idx, func: efunc }); this.sound.addEventListener(type, efunc, true); } return this; }; this.unbind = function(types) { if (!supported) { return this; } types = types.split(" "); for (var t = 0; t < types.length; t++) { var idx = types[t], type = idx.split(".")[0]; for (var i = 0; i < events.length; i++) { var namespace = events[i].idx.split("."); if (events[i].idx == idx || namespace[1] && namespace[1] == idx.replace(".", "")) { this.sound.removeEventListener(type, events[i].func, true); events.splice(i, 1); } } } return this; }; this.bindOnce = function(type, func) { if (!supported) { return this; } var self = this; eventsOnce[pid++] = false; this.bind(type + "." + pid, function() { if (!eventsOnce[pid]) { eventsOnce[pid] = true; func.call(self); } self.unbind(type + "." + pid); }); return this; }; this.trigger = function(types) { if (!supported) { return this; } types = types.split(" "); for (var t = 0; t < types.length; t++) { var idx = types[t]; for (var i = 0; i < events.length; i++) { var eventType = events[i].idx.split("."); if (events[i].idx == idx || eventType[0] && eventType[0] == idx.replace(".", "")) { var evt = doc.createEvent("HTMLEvents"); evt.initEvent(eventType[0], false, true); this.sound.dispatchEvent(evt); } } } return this; }; this.fadeTo = function(to, duration, callback) { if (!supported) { return this; } if (duration instanceof Function) { callback = duration; duration = buzz.defaults.duration; } else { duration = duration || buzz.defaults.duration; } var from = this.volume, delay = duration / Math.abs(from - to), self = this; this.play(); function doFade() { setTimeout(function() { if (from < to && self.volume < to) { self.setVolume(self.volume += 1); doFade(); } else if (from > to && self.volume > to) { self.setVolume(self.volume -= 1); doFade(); } else if (callback instanceof Function) { callback.apply(self); } }, delay); } this.whenReady(function() { doFade(); }); return this; }; this.fadeIn = function(duration, callback) { if (!supported) { return this; } return this.setVolume(0).fadeTo(100, duration, callback); }; this.fadeOut = function(duration, callback) { if (!supported) { return this; } return this.fadeTo(0, duration, callback); }; this.fadeWith = function(sound, duration) { if (!supported) { return this; } this.fadeOut(duration, function() { this.stop(); }); sound.play().fadeIn(duration); return this; }; this.whenReady = function(func) { if (!supported) { return null; } var self = this; if (this.sound.readyState === 0) { this.bind("canplay.buzzwhenready", function() { func.call(self); }); } else { func.call(self); } }; function timerangeToArray(timeRange) { var array = [], length = timeRange.length - 1; for (var i = 0; i <= length; i++) { array.push({ start: timeRange.start(i), end: timeRange.end(i) }); } return array; } function getExt(filename) { return filename.split(".").pop(); } function addSource(sound, src) { var source = doc.createElement("source"); source.src = src; if (buzz.types[getExt(src)]) { source.type = buzz.types[getExt(src)]; } sound.appendChild(source); } if (supported && src) { for (var i in buzz.defaults) { if (buzz.defaults.hasOwnProperty(i)) { options[i] = options[i] || buzz.defaults[i]; } } this.sound = doc.createElement("audio"); if (src instanceof Array) { for (var j in src) { if (src.hasOwnProperty(j)) { addSource(this.sound, src[j]); } } } else if (options.formats.length) { for (var k in options.formats) { if (options.formats.hasOwnProperty(k)) { addSource(this.sound, src + "." + options.formats[k]); } } } else { addSource(this.sound, src); } if (options.loop) { this.loop(); } if (options.autoplay) { this.sound.autoplay = "autoplay"; } if (options.preload === true) { this.sound.preload = "auto"; } else if (options.preload === false) { this.sound.preload = "none"; } else { this.sound.preload = options.preload; } this.setVolume(options.volume); buzz.sounds.push(this); } }, group: function(sounds) { sounds = argsToArray(sounds, arguments); this.getSounds = function() { return sounds; }; this.add = function(soundArray) { soundArray = argsToArray(soundArray, arguments); for (var a = 0; a < soundArray.length; a++) { sounds.push(soundArray[a]); } }; this.remove = function(soundArray) { soundArray = argsToArray(soundArray, arguments); for (var a = 0; a < soundArray.length; a++) { for (var i = 0; i < sounds.length; i++) { if (sounds[i] == soundArray[a]) { sounds.splice(i, 1); break; } } } }; this.load = function() { fn("load"); return this; }; this.play = function() { fn("play"); return this; }; this.togglePlay = function() { fn("togglePlay"); return this; }; this.pause = function(time) { fn("pause", time); return this; }; this.stop = function() { fn("stop"); return this; }; this.mute = function() { fn("mute"); return this; }; this.unmute = function() { fn("unmute"); return this; }; this.toggleMute = function() { fn("toggleMute"); return this; }; this.setVolume = function(volume) { fn("setVolume", volume); return this; }; this.increaseVolume = function(value) { fn("increaseVolume", value); return this; }; this.decreaseVolume = function(value) { fn("decreaseVolume", value); return this; }; this.loop = function() { fn("loop"); return this; }; this.unloop = function() { fn("unloop"); return this; }; this.setTime = function(time) { fn("setTime", time); return this; }; this.set = function(key, value) { fn("set", key, value); return this; }; this.bind = function(type, func) { fn("bind", type, func); return this; }; this.unbind = function(type) { fn("unbind", type); return this; }; this.bindOnce = function(type, func) { fn("bindOnce", type, func); return this; }; this.trigger = function(type) { fn("trigger", type); return this; }; this.fade = function(from, to, duration, callback) { fn("fade", from, to, duration, callback); return this; }; this.fadeIn = function(duration, callback) { fn("fadeIn", duration, callback); return this; }; this.fadeOut = function(duration, callback) { fn("fadeOut", duration, callback); return this; }; function fn() { var args = argsToArray(null, arguments), func = args.shift(); for (var i = 0; i < sounds.length; i++) { sounds[i][func].apply(sounds[i], args); } } function argsToArray(array, args) { return array instanceof Array ? array : Array.prototype.slice.call(args); } }, all: function() { return new buzz.group(buzz.sounds); }, isSupported: function() { return !!buzz.el.canPlayType; }, isOGGSupported: function() { return !!buzz.el.canPlayType && buzz.el.canPlayType('audio/ogg; codecs="vorbis"'); }, isWAVSupported: function() { return !!buzz.el.canPlayType && buzz.el.canPlayType('audio/wav; codecs="1"'); }, isMP3Supported: function() { return !!buzz.el.canPlayType && buzz.el.canPlayType("audio/mpeg;"); }, isAACSupported: function() { return !!buzz.el.canPlayType && (buzz.el.canPlayType("audio/x-m4a;") || buzz.el.canPlayType("audio/aac;")); }, toTimer: function(time, withHours) { var h, m, s; h = Math.floor(time / 3600); h = isNaN(h) ? "--" : h >= 10 ? h : "0" + h; m = withHours ? Math.floor(time / 60 % 60) : Math.floor(time / 60); m = isNaN(m) ? "--" : m >= 10 ? m : "0" + m; s = Math.floor(time % 60); s = isNaN(s) ? "--" : s >= 10 ? s : "0" + s; return withHours ? h + ":" + m + ":" + s : m + ":" + s; }, fromTimer: function(time) { var splits = time.toString().split(":"); if (splits && splits.length == 3) { time = parseInt(splits[0], 10) * 3600 + parseInt(splits[1], 10) * 60 + parseInt(splits[2], 10); } if (splits && splits.length == 2) { time = parseInt(splits[0], 10) * 60 + parseInt(splits[1], 10); } return time; }, toPercent: function(value, total, decimal) { var r = Math.pow(10, decimal || 0); return Math.round(value * 100 / total * r) / r; }, fromPercent: function(percent, total, decimal) { var r = Math.pow(10, decimal || 0); return Math.round(total / 100 * percent * r) / r; } }; return buzz; });