Created
December 15, 2012 02:19
-
-
Save ryngonzalez/4290730 to your computer and use it in GitHub Desktop.
A small library for HTML5 Audio that executes a given function at particular time during playback.
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
/** | |
* Copyright 2012 - Ryan Gonzalez - @ryngonzalez - [email protected] | |
* | |
* Director.js | |
* | |
* Takes an audio element and an | |
* object of functions and corresponding | |
* times to execute them during | |
* audio playback. | |
* | |
* @version 0.0.1 | |
*/ | |
;(function(exports){ | |
"use strict"; | |
/** | |
* Set variables for easy access. | |
*/ | |
var document = exports.document; | |
/** | |
* Create a director object. | |
*/ | |
exports.director = function(selector, opts) { | |
return new Director(director.select(selector), opts); | |
}; | |
/** | |
* Director version. SUPER ALPHA. | |
*/ | |
exports.director.version = '0.0.1' | |
/** | |
* Default element selection utilized by `director(selector)`. | |
* Must be an audio element. | |
* | |
* Override to implement your own selection, for example | |
* with jQuery one might write: | |
* | |
* director.select = function(selector) { | |
* return jQuery(selector).get(0); | |
* }; | |
* | |
* @param {Object|String} selector | |
* @return {Element} | |
* @api public | |
*/ | |
director.select = function(selector){ | |
if ('string' != typeof selector) return selector; | |
var element = document.getElementById(selector) || | |
document.querySelectorAll(selector)[0]; | |
if(element.tagName != "AUDIO") return selector; | |
return element; | |
}; | |
/** | |
* Creates a new EventEmitter with an empty object of callbacks. | |
*/ | |
function EventEmitter() { | |
this.callbacks = {}; | |
} | |
/** | |
* Attach `fn` to a given `event` to be executed later. | |
* | |
* @params {String} event | |
* @params {Function} fn | |
*/ | |
EventEmitter.prototype.on = function(event, fn) { | |
(this.callbacks[event] = this.callbacks[event] || []).push(fn); | |
return this; | |
}; | |
/** | |
* For a given event, execute all of its callbacks, with optional arguments. | |
* | |
* @params {String} event | |
* @params {Mixed} args | |
*/ | |
EventEmitter.prototype.emit = function(event) { | |
var args = Array.prototype.slice.call(arguments, 1), | |
callbacks = this.callbacks[event]; | |
if (callbacks) { | |
for (var i = 0; i < callbacks.length ; ++i) { | |
callbacks[i].apply(this, args); | |
} | |
} | |
return this; | |
}; | |
EventEmitter.extend = function(object){ | |
var props = ['on', 'emit']; | |
for(var i = 0; i < props.length; i ++){ | |
destObject.prototype[props[i]] = EventEmitter.prototype[props[i]]; | |
} | |
}; | |
/** | |
* Initilizes a new `Director` from a given `el`. | |
* | |
* @params {String} el | |
* @api public | |
*/ | |
// exports.youtube = { | |
// event: "timeupdate", | |
// play: function(media) { | |
// media.playVideo(); | |
// EventEmitter.extend(media); | |
// setTimeout(function(){ | |
// media.emit("timeupdate"); | |
// }, 10); | |
// }, | |
// currentTime: function(media) { return media.getCurrentTime(); } | |
// } | |
var audio = { | |
event: "timeupdate", | |
play: function(media) { return media.play(); }, | |
pause: function(media) { return media.pause(); }, | |
paused: function(media) { return media.paused; }, | |
currentTime: function(media) { return media.currentTime; }, | |
} | |
exports.Director = function Director(el, opts) { | |
if(!(this instanceof Director)) return new Director(el); | |
EventEmitter.call(this); | |
this.el = director.select(el); | |
this.module = audio; | |
this._actions = []; | |
this._duration = 0; | |
} | |
/** | |
* Inherit from `EventEmitter.prototype`. | |
*/ | |
Director.prototype = new EventEmitter; | |
Director.prototype.constructor = Director; | |
/** | |
* Perform this `fn` at `time` of the audio selected. | |
* | |
* @params {Object} options | |
* @params {Number} time | |
* @params {Function} fn | |
* @params {Number} duration | |
* @api public | |
*/ | |
Director.prototype.at = function (options) { | |
this._actions.push(options); | |
return this; | |
} | |
/** | |
* Sorts the array based on timestamps. | |
* | |
* @api public | |
*/ | |
Director.prototype.sort = function () { | |
this._actions.sort(function(a,b){ | |
return a.time - b.time; | |
}); | |
return this; | |
} | |
/** | |
* Duration collects the total duration of the actions attached to the audio. | |
* | |
* @api private | |
*/ | |
Director.prototype.duration = function () { | |
if (this._actions.length) { | |
var duration = 0; | |
for (var i = this._actions.length - 1; i >= 0; i--) { | |
duration += this._actions[i].duration; | |
}; | |
return this._duration = duration; | |
} | |
return 0; | |
} | |
/** | |
* Defer the given `fn` until the animation | |
* is complete. `fn` may be one of the following: | |
* | |
* - a function to invoke | |
* - an instanceof `Director` to call `.end()` | |
* - nothing, to return a clone of this `Director` instance for chaining | |
* | |
* @param {Function|Director} fn | |
* @return {Director} for chaining | |
* @api public | |
*/ | |
Director.prototype.then = function(fn){ | |
// invoke .end() | |
if ('function' == typeof fn) { | |
this.on('end', fn); | |
} | |
return this; | |
}; | |
/** | |
* Plays the song, then performs the actions attached. | |
* | |
* @api public | |
*/ | |
Director.prototype.play = function (fn) { | |
var module = this.module, | |
media = this.el, | |
self = this; | |
// self.duration(); | |
console.log(media.paused); | |
console.log(module); | |
module.paused(media) ? module.play(media) : module.pause(media) | |
var action = this._actions.shift(); | |
this.on(action.time, action.fn); | |
if (module.currentTime(media) === 0) { | |
media.addEventListener(module.event, function() { | |
if (module.currentTime(media) > action.time) { | |
self.emit(action.time); | |
setTimeout(function(){ | |
self.emit('end'); | |
if (self._actions.length) { | |
action = self._actions.shift(); | |
} else { action = {}; } | |
self.on(action.time, action.fn); | |
}, action.duration); | |
} | |
}); | |
} | |
return this; | |
} | |
})(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment