Tone.js/Tone/source/Players.js
2017-06-19 15:18:50 -04:00

275 lines
6.3 KiB
JavaScript

define(["Tone/core/Tone", "Tone/source/Player", "Tone/component/Volume"], function(Tone){
"use strict";
/**
* @class Tone.Players combines multiple [Tone.Player](Player) objects.
*
* @constructor
* @extends {Tone}
* @param {Object} urls An object mapping a name to a url.
* @param {function=} onload The function to invoke when the buffer is loaded.
*/
Tone.Players = function(urls){
var args = Array.prototype.slice.call(arguments);
args.shift();
var options = Tone.defaults(args, ["onload"], Tone.Players);
Tone.call(this);
/**
* The output volume node
* @type {Tone.Volume}
* @private
*/
this._volume = this.output = new Tone.Volume(options.volume);
/**
* The volume of the output in decibels.
* @type {Decibels}
* @signal
* @example
* source.volume.value = -6;
*/
this.volume = this._volume.volume;
this._readOnly("volume");
//make the output explicitly stereo
this._volume.output.output.channelCount = 2;
this._volume.output.output.channelCountMode = "explicit";
//mute initially
this.mute = options.mute;
/**
* The container of all of the players
* @type {Object}
* @private
*/
this._players = {};
/**
* The loading count
* @type {Number}
* @private
*/
this._loadingCount = 0;
/**
* private holder of the fadeIn time
* @type {Time}
* @private
*/
this._fadeIn = options.fadeIn;
/**
* private holder of the fadeOut time
* @type {Time}
* @private
*/
this._fadeOut = options.fadeOut;
//add all of the players
for (var name in urls){
this._loadingCount++;
this.add(name, urls[name], this._bufferLoaded.bind(this, options.onload));
}
};
Tone.extend(Tone.Players);
/**
* The default values
* @type {Object}
*/
Tone.Players.defaults = {
"volume" : 0,
"mute" : false,
"onload" : Tone.noOp,
"fadeIn" : 0,
"fadeOut" : 0
};
/**
* A buffer was loaded. decrement the counter.
* @param {Function} callback
* @private
*/
Tone.Players.prototype._bufferLoaded = function(callback){
this._loadingCount--;
if (this._loadingCount === 0 && callback){
callback(this);
}
};
/**
* Mute the output.
* @memberOf Tone.Source#
* @type {boolean}
* @name mute
* @example
* //mute the output
* source.mute = true;
*/
Object.defineProperty(Tone.Players.prototype, "mute", {
get : function(){
return this._volume.mute;
},
set : function(mute){
this._volume.mute = mute;
}
});
/**
* The fadeIn time of the amplitude envelope.
* @memberOf Tone.Source#
* @type {Time}
* @name fadeIn
*/
Object.defineProperty(Tone.Players.prototype, "fadeIn", {
get : function(){
return this._fadeIn;
},
set : function(fadeIn){
this._fadeIn = fadeIn;
this._forEach(function(player){
player.fadeIn = fadeIn;
});
}
});
/**
* The fadeOut time of the amplitude envelope.
* @memberOf Tone.Source#
* @type {Time}
* @name fadeOut
*/
Object.defineProperty(Tone.Players.prototype, "fadeOut", {
get : function(){
return this._fadeOut;
},
set : function(fadeOut){
this._fadeOut = fadeOut;
this._forEach(function(player){
player.fadeOut = fadeOut;
});
}
});
/**
* The state of the players object. Returns "started" if any of the players are playing.
* @memberOf Tone.Players#
* @type {String}
* @name state
* @readOnly
*/
Object.defineProperty(Tone.Players.prototype, "state", {
get : function(){
var playing = false;
this._forEach(function(player){
playing = playing || player.state === Tone.State.Started;
});
return playing ? Tone.State.Started : Tone.State.Stopped;
}
});
/**
* True if the buffers object has a buffer by that name.
* @param {String|Number} name The key or index of the
* buffer.
* @return {Boolean}
*/
Tone.Players.prototype.has = function(name){
return this._players.hasOwnProperty(name);
};
/**
* Get a player by name.
* @param {String} name The players name as defined in
* the constructor object or `add` method.
* @return {Tone.Player}
*/
Tone.Players.prototype.get = function(name){
if (this.has(name)){
return this._players[name];
} else {
throw new Error("Tone.Players: no player named "+name);
}
};
/**
* Iterate over all of the players
* @param {Function} callback
* @return {Tone.Players} this
* @private
*/
Tone.Players.prototype._forEach = function(callback){
for (var playerName in this._players){
callback(this._players[playerName], playerName);
}
return this;
};
/**
* If all the buffers are loaded or not
* @memberOf Tone.Players#
* @type {Boolean}
* @name loaded
* @readOnly
*/
Object.defineProperty(Tone.Players.prototype, "loaded", {
get : function(){
var isLoaded = true;
this._forEach(function(player){
isLoaded = isLoaded && player.loaded;
});
return isLoaded;
}
});
/**
* Add a player by name and url to the Players
* @param {String} name A unique name to give the player
* @param {String|Tone.Buffer|Audiobuffer} url Either the url of the bufer,
* or a buffer which will be added
* with the given name.
* @param {Function=} callback The callback to invoke
* when the url is loaded.
*/
Tone.Players.prototype.add = function(name, url, callback){
this._players[name] = new Tone.Player(url, callback).connect(this.output);
this._players[name].fadeIn = this._fadeIn;
this._players[name].fadeOut = this._fadeOut;
return this;
};
/**
* Stop all of the players at the given time
* @param {Time} time The time to stop all of the players.
* @return {Tone.Players} this
*/
Tone.Players.prototype.stopAll = function(time){
this._forEach(function(player){
player.stop(time);
});
};
/**
* Dispose and disconnect.
* @return {Tone.Players} this
*/
Tone.Players.prototype.dispose = function(){
Tone.prototype.dispose.call(this);
this._volume.dispose();
this._volume = null;
this._writable("volume");
this.volume = null;
this.output = null;
this._forEach(function(player){
player.dispose();
});
this._players = null;
return this;
};
return Tone.Players;
});