mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-17 00:58:09 +00:00
246 lines
No EOL
7.8 KiB
JavaScript
246 lines
No EOL
7.8 KiB
JavaScript
define(["Tone/core/Tone", "Tone/source/BufferSource", "Tone/core/Buffers",
|
|
"Tone/source/Source", "Tone/component/Volume"],
|
|
function (Tone) {
|
|
|
|
/**
|
|
* @class Tone.MultiPlayer is well suited for one-shots, multi-sampled instruments
|
|
* or any time you need to play a bunch of audio buffers.
|
|
* @param {Object|Array|Tone.Buffers} buffers The buffers which are available
|
|
* to the MultiPlayer
|
|
* @param {Function} onload The callback to invoke when all of the buffers are loaded.
|
|
* @extends {Tone}
|
|
* @example
|
|
* var multiPlayer = new MultiPlayer({
|
|
* "kick" : "path/to/kick.mp3",
|
|
* "snare" : "path/to/snare.mp3",
|
|
* }, function(){
|
|
* multiPlayer.start("kick");
|
|
* });
|
|
* @example
|
|
* //can also store the values in an array
|
|
* var multiPlayer = new MultiPlayer(["path/to/kick.mp3", "path/to/snare.mp3"],
|
|
* function(){
|
|
* //if an array is passed in, the samples are referenced to by index
|
|
* multiPlayer.start(1);
|
|
* });
|
|
*/
|
|
Tone.MultiPlayer = function(urls){
|
|
|
|
//remove the urls from the options
|
|
if (arguments.length === 1 && !Tone.isUndef(arguments[0]) && !arguments[0].hasOwnProperty("urls")){
|
|
urls = { "urls" : urls };
|
|
}
|
|
var options = Tone.defaults(arguments, ["urls", "onload"], Tone.MultiPlayer);
|
|
Tone.Source.call(this, options);
|
|
|
|
if (options.urls instanceof Tone.Buffers){
|
|
/**
|
|
* All the buffers belonging to the player.
|
|
* @type {Tone.Buffers}
|
|
*/
|
|
this.buffers = options.urls;
|
|
} else {
|
|
this.buffers = new Tone.Buffers(options.urls, options.onload);
|
|
}
|
|
|
|
/**
|
|
* Keeps track of the currently playing sources.
|
|
* @type {Object}
|
|
* @private
|
|
*/
|
|
this._activeSources = {};
|
|
|
|
/**
|
|
* The fade in envelope which is applied
|
|
* to the beginning of the BufferSource
|
|
* @type {Time}
|
|
*/
|
|
this.fadeIn = options.fadeIn;
|
|
|
|
/**
|
|
* The fade out envelope which is applied
|
|
* to the end of the BufferSource
|
|
* @type {Time}
|
|
*/
|
|
this.fadeOut = options.fadeOut;
|
|
};
|
|
|
|
Tone.extend(Tone.MultiPlayer, Tone.Source);
|
|
|
|
/**
|
|
* The defaults
|
|
* @type {Object}
|
|
*/
|
|
Tone.MultiPlayer.defaults = {
|
|
"onload" : Tone.noOp,
|
|
"fadeIn" : 0,
|
|
"fadeOut" : 0
|
|
};
|
|
|
|
/**
|
|
* Make the source from the buffername
|
|
* @param {String} bufferName
|
|
* @return {Tone.BufferSource}
|
|
* @private
|
|
*/
|
|
Tone.MultiPlayer.prototype._makeSource = function(bufferName){
|
|
var buffer;
|
|
if (Tone.isString(bufferName) || Tone.isNumber(bufferName)){
|
|
buffer = this.buffers.get(bufferName).get();
|
|
} else if (bufferName instanceof Tone.Buffer){
|
|
buffer = bufferName.get();
|
|
} else if (bufferName instanceof AudioBuffer){
|
|
buffer = bufferName;
|
|
}
|
|
var source = new Tone.BufferSource(buffer).connect(this.output);
|
|
if (!this._activeSources.hasOwnProperty(bufferName)){
|
|
this._activeSources[bufferName] = [];
|
|
}
|
|
this._activeSources[bufferName].push(source);
|
|
return source;
|
|
};
|
|
|
|
/**
|
|
* Start a buffer by name. The `start` method allows a number of options
|
|
* to be passed in such as offset, interval, and gain. This is good for multi-sampled
|
|
* instruments and sound sprites where samples are repitched played back at different velocities.
|
|
* @param {String} bufferName The name of the buffer to start.
|
|
* @param {Time} time When to start the buffer.
|
|
* @param {Time} [offset=0] The offset into the buffer to play from.
|
|
* @param {Time=} duration How long to play the buffer for.
|
|
* @param {Interval} [pitch=0] The interval to repitch the buffer.
|
|
* @param {Gain} [gain=1] The gain to play the sample at.
|
|
* @return {Tone.MultiPlayer} this
|
|
*/
|
|
Tone.MultiPlayer.prototype.start = function(bufferName, time, offset, duration, pitch, gain){
|
|
time = this.toSeconds(time);
|
|
var source = this._makeSource(bufferName);
|
|
source.start(time, offset, duration, Tone.defaultArg(gain, 1), this.fadeIn);
|
|
if (duration){
|
|
source.stop(time + this.toSeconds(duration), this.fadeOut);
|
|
}
|
|
pitch = Tone.defaultArg(pitch, 0);
|
|
source.playbackRate.value = Tone.intervalToFrequencyRatio(pitch);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Start a looping buffer by name. Similar to `start`, but the buffer
|
|
* is looped instead of played straight through. Can still be stopped with `stop`.
|
|
* @param {String} bufferName The name of the buffer to start.
|
|
* @param {Time} time When to start the buffer.
|
|
* @param {Time} [offset=0] The offset into the buffer to play from.
|
|
* @param {Time=} loopStart The start of the loop.
|
|
* @param {Time=} loopEnd The end of the loop.
|
|
* @param {Interval} [pitch=0] The interval to repitch the buffer.
|
|
* @param {Gain} [gain=1] The gain to play the sample at.
|
|
* @return {Tone.MultiPlayer} this
|
|
*/
|
|
Tone.MultiPlayer.prototype.startLoop = function(bufferName, time, offset, loopStart, loopEnd, pitch, gain){
|
|
time = this.toSeconds(time);
|
|
var source = this._makeSource(bufferName);
|
|
source.loop = true;
|
|
source.loopStart = this.toSeconds(Tone.defaultArg(loopStart, 0));
|
|
source.loopEnd = this.toSeconds(Tone.defaultArg(loopEnd, 0));
|
|
source.start(time, offset, undefined, Tone.defaultArg(gain, 1), this.fadeIn);
|
|
pitch = Tone.defaultArg(pitch, 0);
|
|
source.playbackRate.value = Tone.intervalToFrequencyRatio(pitch);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Stop the first played instance of the buffer name.
|
|
* @param {String} bufferName The buffer to stop.
|
|
* @param {Time=} time When to stop the buffer
|
|
* @return {Tone.MultiPlayer} this
|
|
*/
|
|
Tone.MultiPlayer.prototype.stop = function(bufferName, time){
|
|
if (this._activeSources[bufferName] && this._activeSources[bufferName].length){
|
|
time = this.toSeconds(time);
|
|
this._activeSources[bufferName].shift().stop(time, this.fadeOut);
|
|
} else {
|
|
throw new Error("Tone.MultiPlayer: cannot stop a buffer that hasn't been started or is already stopped");
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Stop all currently playing buffers at the given time.
|
|
* @param {Time=} time When to stop the buffers.
|
|
* @return {Tone.MultiPlayer} this
|
|
*/
|
|
Tone.MultiPlayer.prototype.stopAll = function(time){
|
|
time = this.toSeconds(time);
|
|
for (var bufferName in this._activeSources){
|
|
var sources = this._activeSources[bufferName];
|
|
for (var i = 0; i < sources.length; i++){
|
|
sources[i].stop(time);
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Add another buffer to the available buffers.
|
|
* @param {String} name The name to that the buffer is refered
|
|
* to in start/stop methods.
|
|
* @param {String|Tone.Buffer} url The url of the buffer to load
|
|
* or the buffer.
|
|
* @param {Function} callback The function to invoke after the buffer is loaded.
|
|
*/
|
|
Tone.MultiPlayer.prototype.add = function(name, url, callback){
|
|
this.buffers.add(name, url, callback);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Returns the playback state of the source. "started"
|
|
* if there are any buffers playing. "stopped" otherwise.
|
|
* @type {Tone.State}
|
|
* @readOnly
|
|
* @memberOf Tone.MultiPlayer#
|
|
* @name state
|
|
*/
|
|
Object.defineProperty(Tone.MultiPlayer.prototype, "state", {
|
|
get : function(){
|
|
return this._activeSources.length > 0 ? Tone.State.Started : Tone.State.Stopped;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Mute the output.
|
|
* @memberOf Tone.MultiPlayer#
|
|
* @type {boolean}
|
|
* @name mute
|
|
* @example
|
|
* //mute the output
|
|
* source.mute = true;
|
|
*/
|
|
Object.defineProperty(Tone.MultiPlayer.prototype, "mute", {
|
|
get : function(){
|
|
return this._volume.mute;
|
|
},
|
|
set : function(mute){
|
|
this._volume.mute = mute;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Clean up.
|
|
* @return {Tone.MultiPlayer} this
|
|
*/
|
|
Tone.MultiPlayer.prototype.dispose = function(){
|
|
Tone.Source.prototype.dispose.call(this);
|
|
for (var bufferName in this._activeSources){
|
|
this._activeSources[bufferName].forEach(function(source){
|
|
source.dispose();
|
|
});
|
|
}
|
|
this.buffers.dispose();
|
|
this.buffers = null;
|
|
this._activeSources = null;
|
|
return this;
|
|
};
|
|
|
|
return Tone.MultiPlayer;
|
|
}); |