Tone.js/doc/Tone.js.html
2014-07-03 23:50:49 -04:00

5250 lines
126 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tone.js Source: Tone.js</title>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/sunlight.default.css">
<link type="text/css" rel="stylesheet" href="styles/site.spacelab.css">
</head>
<body>
<div class="container-fluid">
<div class="navbar navbar-fixed-top navbar-inverse">
<div class="navbar-inner">
<a class="brand" href="index.html">Tone.js</a>
<ul class="nav">
<li class="dropdown">
<a href="classes.list.html" class="dropdown-toggle" data-toggle="dropdown">Classes<b
class="caret"></b></a>
<ul class="dropdown-menu ">
<li>
<a href="Tone.html">Tone</a>
</li>
<li>
<a href="Tone.Abs.html">Abs</a>
</li>
<li>
<a href="Tone.Add.html">Add</a>
</li>
<li>
<a href="Tone.AutoPanner.html">AutoPanner</a>
</li>
<li>
<a href="Tone.BitCrusher.html">BitCrusher</a>
</li>
<li>
<a href="Tone.DryWet.html">DryWet</a>
</li>
<li>
<a href="Tone.Effect.html">Effect</a>
</li>
<li>
<a href="Tone.Envelope.html">Envelope</a>
</li>
<li>
<a href="Tone.Equal.html">Equal</a>
</li>
<li>
<a href="Tone.EqualZero.html">EqualZero</a>
</li>
<li>
<a href="Tone.FeedbackDelay.html">FeedbackDelay</a>
</li>
<li>
<a href="Tone.FeedbackEffect.html">FeedbackEffect</a>
</li>
<li>
<a href="Tone.Follower.html">Follower</a>
</li>
<li>
<a href="Tone.Gate.html">Gate</a>
</li>
<li>
<a href="Tone.GreaterThan.html">GreaterThan</a>
</li>
<li>
<a href="Tone.LessThan.html">LessThan</a>
</li>
<li>
<a href="Tone.LFO.html">LFO</a>
</li>
<li>
<a href="Tone.Merge.html">Merge</a>
</li>
<li>
<a href="Tone.Meter.html">Meter</a>
</li>
<li>
<a href="Tone.Microphone.html">Microphone</a>
</li>
<li>
<a href="Tone.Multiply.html">Multiply</a>
</li>
<li>
<a href="Tone.Negate.html">Negate</a>
</li>
<li>
<a href="Tone.Noise.html">Noise</a>
</li>
<li>
<a href="Tone.Oscillator.html">Oscillator</a>
</li>
<li>
<a href="Tone.Panner.html">Panner</a>
</li>
<li>
<a href="Tone.PingPongDelay.html">PingPongDelay</a>
</li>
<li>
<a href="Tone.Player.html">Player</a>
</li>
<li>
<a href="Tone.Recorder.html">Recorder</a>
</li>
<li>
<a href="Tone.Scale.html">Scale</a>
</li>
<li>
<a href="Tone.Signal.html">Signal</a>
</li>
<li>
<a href="Tone.Source.html">Source</a>
</li>
<li>
<a href="Tone.Split.html">Split</a>
</li>
<li>
<a href="Tone.Threshold.html">Threshold</a>
</li>
<li>
<a href="Tone.Transport.html">Transport</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<div id="main">
<h1 class="page-title">Source: Tone.js</h1>
<section>
<article>
<pre class="sunlight-highlight-javascript linenums">/**
* Tone.js
*
* @version 0.1.2
*
* @author Yotam Mann
*
* @license http://opensource.org/licenses/MIT MIT License 2014
*/
(function (root) {
// Tone.js can run with or without requirejs
//
// this anonymous function checks to see if the 'define'
// method exists, if it does not (and there is not already
// something called Tone) it will create a function called
// 'define'. 'define' will invoke the 'core' module and attach
// its return value to the root. for all other modules
// Tone will be passed in as the argument.
if (typeof define !== "function" &&
typeof root.Tone !== "function") {
//define 'define' to invoke the callbacks with Tone
root.define = function(name, deps, func){
//grab the one at the root
if (name === "Tone/core/Tone"){
root.Tone = func();
} else {
//for all others pass it in
func(root.Tone);
}
};
}
} (this));
define("Tone/core/Tone", [], function(){
//////////////////////////////////////////////////////////////////////////
// WEB AUDIO CONTEXT
///////////////////////////////////////////////////////////////////////////
//borrowed from underscore.js
function isUndef(val){
return val === void 0;
}
//ALIAS
if (isUndef(window.AudioContext)){
window.AudioContext = window.webkitAudioContext;
}
var audioContext;
if (!isUndef(window.AudioContext)){
audioContext = new AudioContext();
} else {
throw new Error("Web Audio is not supported in this browser");
}
//SHIMS////////////////////////////////////////////////////////////////////
if (typeof AudioContext.prototype.createGain !== "function"){
AudioContext.prototype.createGain = AudioContext.prototype.createGainNode;
}
if (typeof AudioContext.prototype.createDelay !== "function"){
AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode;
}
if (typeof AudioBufferSourceNode.prototype.start !== "function"){
AudioBufferSourceNode.prototype.start = AudioBufferSourceNode.prototype.noteGrainOn;
}
if (typeof AudioBufferSourceNode.prototype.stop !== "function"){
AudioBufferSourceNode.prototype.stop = AudioBufferSourceNode.prototype.noteOff;
}
if (typeof OscillatorNode.prototype.start !== "function"){
OscillatorNode.prototype.start = OscillatorNode.prototype.noteOn;
}
if (typeof OscillatorNode.prototype.stop !== "function"){
OscillatorNode.prototype.stop = OscillatorNode.prototype.noteOff;
}
//extend the connect function to include Tones
AudioNode.prototype._nativeConnect = AudioNode.prototype.connect;
AudioNode.prototype.connect = function(B){
if (B.input){
this.connect(B.input);
} else {
try {
this._nativeConnect.apply(this, arguments);
} catch (e) {
throw new Error("trying to connect to a node with no inputs");
}
}
};
///////////////////////////////////////////////////////////////////////////
// TONE
///////////////////////////////////////////////////////////////////////////
/**
* Tone is the baseclass of all ToneNodes
*
* From Tone, children inherit timing and math which is used throughout Tone.js
*
* @constructor
* @alias Tone
*/
var Tone = function(){
/**
* default input of the ToneNode
*
* @type {GainNode}
*/
this.input = this.context.createGain();
/**
* default output of the ToneNode
*
* @type {GainNode}
*/
this.output = this.context.createGain();
};
///////////////////////////////////////////////////////////////////////////
// CLASS VARS
///////////////////////////////////////////////////////////////////////////
/**
* A static pointer to the audio context
* @type {AudioContext}
*/
Tone.context = audioContext;
/**
* A static pointer to the audio context
* @type {AudioContext}
* @static
*/
Tone.prototype.context = Tone.context;
/**
* the default buffer size
* @type {number}
* @static
* @const
*/
Tone.prototype.bufferSize = 2048;
///////////////////////////////////////////////////////////////////////////
// CONNECTIONS
///////////////////////////////////////////////////////////////////////////
/**
* connect the output of a ToneNode to an AudioParam, AudioNode, or ToneNode
* @param {Tone | AudioParam | AudioNode} unit
*/
Tone.prototype.connect = function(unit){
this.output.connect(unit);
};
/**
* disconnect the output
*/
Tone.prototype.disconnect = function(){
this.output.disconnect();
};
/**
* connect together all of the arguments in series
* @param {...AudioParam|Tone}
*/
Tone.prototype.chain = function(){
if (arguments.length > 1){
var currentUnit = arguments[0];
for (var i = 1; i &lt; arguments.length; i++){
var toUnit = arguments[i];
currentUnit.connect(toUnit);
currentUnit = toUnit;
}
}
};
///////////////////////////////////////////////////////////////////////////
// UTILITIES / HELPERS / MATHS
///////////////////////////////////////////////////////////////////////////
/**
* if a the given is undefined, use the fallback
*
* @param {*} given
* @param {*} fallback
* @return {*}
*/
Tone.prototype.defaultArg = function(given, fallback){
return isUndef(given) ? fallback : given;
};
/**
* equal power gain scale
* good for cross-fading
*
* @param {number} percent (0-1)
* @return {number} output gain (0-1)
*/
Tone.prototype.equalPowerScale = function(percent){
var piFactor = 0.5 * Math.PI;
return Math.sin(percent * piFactor);
};
/**
* @param {number} gain (0-1)
* @return {number} gain (decibel scale but betwee 0-1)
*/
Tone.prototype.logScale = function(gain) {
return Math.max(this.normalize(this.gainToDb(gain), -100, 0), 0);
};
/**
* @param {number} gain (0-1)
* @return {number} gain (decibel scale but betwee 0-1)
*/
Tone.prototype.expScale = function(gain) {
return this.dbToGain(this.interpolate(gain, -100, 0));
};
/**
* convert db scale to gain scale (0-1)
* @param {number} db
* @return {number}
*/
Tone.prototype.dbToGain = function(db) {
return Math.pow(2, db / 6);
};
/**
* convert gain scale to decibels
* @param {number} gain (0-1)
* @return {number}
*/
Tone.prototype.gainToDb = function(gain) {
return 20 * (Math.log(gain) / Math.LN10);
};
/**
* interpolate the input value (0-1) to be between outputMin and outputMax
* @param {number} input
* @param {number} outputMin
* @param {number} outputMax
* @return {number}
*/
Tone.prototype.interpolate = function(input, outputMin, outputMax){
return input*(outputMax - outputMin) + outputMin;
};
/**
* normalize the input to 0-1 from between inputMin to inputMax
* @param {number} input
* @param {number} inputMin
* @param {number} inputMax
* @return {number}
*/
Tone.prototype.normalize = function(input, inputMin, inputMax){
//make sure that min &lt; max
if (inputMin > inputMax){
var tmp = inputMax;
inputMax = inputMin;
inputMin = tmp;
} else if (inputMin == inputMax){
return 0;
}
return (input - inputMin) / (inputMax - inputMin);
};
/**
* a dispose method
*
* @abstract
*/
Tone.prototype.dispose = function(){};
///////////////////////////////////////////////////////////////////////////
// TIMING
///////////////////////////////////////////////////////////////////////////
/**
* @return {number} the currentTime from the AudioContext
*/
Tone.prototype.now = function(){
return this.context.currentTime;
};
/**
* convert a sample count to seconds
* @param {number} samples
* @return {number}
*/
Tone.prototype.samplesToSeconds = function(samples){
return samples / this.context.sampleRate;
};
/**
* convert a time into samples
*
* @param {Tone.time} time
* @return {number}
*/
Tone.prototype.toSamples = function(time){
var seconds = this.toSeconds(time);
return Math.round(seconds * this.context.sampleRate);
};
/**
* convert Tone.Time to seconds
*
* this is a simplified version which only handles numbers and
* 'now' relative numbers. If the Transport is included this
* method is overridden to include many other features including
* notationTime, Frequency, and transportTime
*
* @param {Tone.Time} time
* @param {number=} now if passed in, this number will be
* used for all 'now' relative timings
* @return {number} seconds in the same timescale as the AudioContext
*/
Tone.prototype.toSeconds = function(time, now){
now = this.defaultArg(now, this.now());
if (typeof time === "number"){
return time; //assuming that it's seconds
} else if (typeof time === "string"){
var plusTime = 0;
if(time.charAt(0) === "+") {
time = time.slice(1);
}
return parseFloat(time) + now;
} else {
return now;
}
};
/**
* convert a frequency into seconds
* accepts both numbers and strings
* i.e. 10hz or 10 both equal .1
*
* @param {number|string} freq
* @return {number}
*/
Tone.prototype.frequencyToSeconds = function(freq){
return 1 / parseFloat(freq);
};
/**
* convert a number in seconds to a frequency
* @param {number} seconds
* @return {number}
*/
Tone.prototype.secondsToFrequency = function(seconds){
return 1/seconds;
};
///////////////////////////////////////////////////////////////////////////
// MUSIC NOTES
///////////////////////////////////////////////////////////////////////////
var noteToIndex = { "a" : 0, "a#" : 1, "bb" : 1, "b" : 2, "c" : 3, "c#" : 4,
"db" : 4, "d" : 5, "d#" : 6, "eb" : 6, "e" : 7, "f" : 8, "f#" : 9,
"gb" : 9, "g" : 10, "g#" : 11, "ab" : 11
};
var noteIndexToNote = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"];
/**
* convert a note name to frequency (i.e. A4 to 440)
* @param {string} note
* @return {number}
*/
Tone.prototype.noteToFrequency = function(note){
//break apart the note by frequency and octave
var parts = note.split(/(\d+)/);
if (parts.length === 3){
var index = noteToIndex[parts[0].toLowerCase()];
var octave = parts[1];
var noteNumber = index + parseInt(octave, 10) * 12;
return Math.pow(2, (noteNumber - 48) / 12) * 440;
} else {
return 0;
}
};
/**
* convert a note name (i.e. A4, C#5, etc to a frequency)
* @param {number} freq
* @return {string}
*/
Tone.prototype.frequencyToNote = function(freq){
var log = Math.log(freq / 440) / Math.LN2;
var noteNumber = Math.round(12 * log) + 48;
var octave = Math.floor(noteNumber/12);
var noteName = noteIndexToNote[noteNumber % 12];
return noteName + octave.toString();
};
///////////////////////////////////////////////////////////////////////////
// STATIC METHODS
///////////////////////////////////////////////////////////////////////////
/**
* have a child inherit all of Tone's (or a parent's) prototype
* to inherit the parent's properties, make sure to call
* Parent.call(this) in the child's constructor
*
* based on closure library's inherit function
*
* @param {function} child
* @param {function=} parent (optional) parent to inherit from
* if no parent is supplied, the child
* will inherit from Tone
*/
Tone.extend = function(child, parent){
if (isUndef(parent)){
parent = Tone;
}
function tempConstructor(){}
tempConstructor.prototype = parent.prototype;
child.prototype = new tempConstructor();
/** @override */
child.prototype.constructor = child;
};
return Tone;
});
define('Tone/core/Master',["Tone/core/Tone"], function(Tone){
/**
* Master Output
*
* a single master output
* adds toMaster to Tone
*
* @constructor
* @extends {Tone}
*/
var Master = function(){
//extend audio unit
Tone.call(this);
/**
* put a hard limiter on the output so we don't blow any eardrums
*
* @type {DynamicsCompressorNode}
*/
this.limiter = this.context.createDynamicsCompressor();
this.limiter.threshold.value = 0;
this.limiter.ratio.value = 20;
//connect it up
this.chain(this.input, this.limiter, this.output, this.context.destination);
};
Tone.extend(Master);
/**
* mute the output
* @param {boolean} muted
*/
Master.prototype.mute = function(muted){
muted = this.defaultArg(muted, true);
if (muted){
this.output.gain.value = 0;
} else {
this.output.gain.value = 1;
}
};
/**
* @param {number} value
* @param {Tone.Time=} fadeTime (optional) time it takes to reach the value
*/
Master.prototype.setVolume = function(value, fadeTime){
var now = this.now();
if (fadeTime){
var currentVolume = this.output.gain.value;
this.output.gain.cancelScheduledValues(now);
this.output.gain.setValueAtTime(currentVolume, now);
this.output.gain.linearRampToValueAtTime(value, now + this.toSeconds(time));
} else {
this.output.gain.setValueAtTime(value, now);
}
};
///////////////////////////////////////////////////////////////////////////
// AUGMENT TONE's PROTOTYPE
///////////////////////////////////////////////////////////////////////////
/**
* connect 'this' to the master output
*/
Tone.prototype.toMaster = function(){
this.connect(Tone.Master);
};
/**
* Also augment AudioNode's prototype to include toMaster
* as a convenience
*/
AudioNode.prototype.toMaster = function(){
this.connect(Tone.Master);
};
/**
* a silent connection to the DesinationNode
* which will ensure that anything connected to it
* will not be garbage collected
*
* @private
*/
var _silentNode = Tone.context.createGain();
_silentNode.gain.value = 0;
_silentNode.connect(Tone.context.destination);
/**
* makes a connection to ensure that the node will not be garbage collected
* until 'dispose' is explicitly called
*
* use carefully. circumvents JS and WebAudio's normal Garbage Collection behavior
*/
Tone.prototype.noGC = function(){
this.output.connect(_silentNode);
};
AudioNode.prototype.noGC = function(){
this.connect(_silentNode);
};
//a single master output
Tone.Master = new Master();
return Tone.Master;
});
define('Tone/signal/Signal',["Tone/core/Tone", "Tone/core/Master"], function(Tone){
/**
* all signals share a common constant signal generator
*
* @static
* @private
* @type {OscillatorNode}
*/
var generator = Tone.context.createOscillator();
/**
* @static
* @private
* @type {WaveShaperNode}
*/
var constant = Tone.context.createWaveShaper();
//generate the waveshaper table which outputs 1 for any input value
(function(){
var len = 8;
var curve = new Float32Array(len);
for (var i = 0; i &lt; len; i++){
//all inputs produce the output value
curve[i] = 1;
}
constant.curve = curve;
})();
generator.connect(constant);
generator.start(0);
generator.noGC();
/**
* constant audio-rate signal
*
* Tone.Signal is a core component which allows for synchronization of many components.
* A single signal can drive multiple parameters by applying Scaling.
*
* For example: to synchronize two Tone.Oscillators in octaves of each other,
* Signal --> OscillatorA.frequency
* ^--> Tone.Multiply(2) --> OscillatorB.frequency
*
*
* Tone.Signal can be scheduled with all of the functions available to AudioParams
*
*
* @constructor
* @extends {Tone}
* @param {number=} value (optional) initial value
*/
Tone.Signal = function(value){
Tone.call(this);
/**
* scales the constant output to the desired output
* @type {GainNode}
*/
this.scalar = this.context.createGain();
/**
* the ratio of the this value to the control signal value
*
* @private
* @type {number}
*/
this._syncRatio = 1;
//connect the constant 1 output to the node output
this.chain(constant, this.scalar, this.output);
//signal passes through
this.input.connect(this.output);
//set the default value
this.setValue(this.defaultArg(value, 0));
};
Tone.extend(Tone.Signal);
/**
* @return {number} the current value of the signal
*/
Tone.Signal.prototype.getValue = function(){
return this.scalar.gain.value;
};
/**
* set the value of the signal right away
* will be overwritten if there are previously scheduled automation curves
*
* @param {number} value
*/
Tone.Signal.prototype.setValue = function(value){
if (this._syncRatio === 0){
value = 0;
} else {
value *= this._syncRatio;
}
this.scalar.gain.value = value;
};
/**
* Schedules a parameter value change at the given time.
*
* @param {number} value
* @param {Tone.Time} time
*/
Tone.Signal.prototype.setValueAtTime = function(value, time){
value *= this._syncRatio;
this.scalar.gain.setValueAtTime(value, this.toSeconds(time));
};
/**
* creates a schedule point with the current value at the current time
*
* @param {number=} now (optionally) pass the now value in
* @returns {number} the current value
*/
Tone.Signal.prototype.setCurrentValueNow = function(now){
now = this.defaultArg(now, this.now());
var currentVal = this.getValue();
this.cancelScheduledValues(now);
this.scalar.gain.setValueAtTime(currentVal, now);
return currentVal;
};
/**
* Schedules a linear continuous change in parameter value from the
* previous scheduled parameter value to the given value.
*
* @param {number} value
* @param {Tone.Time} endTime
*/
Tone.Signal.prototype.linearRampToValueAtTime = function(value, endTime){
value *= this._syncRatio;
this.scalar.gain.linearRampToValueAtTime(value, this.toSeconds(endTime));
};
/**
* Schedules an exponential continuous change in parameter value from
* the previous scheduled parameter value to the given value.
*
* NOTE: Chrome will throw an error if you try to exponentially ramp to a
* value 0 or less.
*
* @param {number} value
* @param {Tone.Time} endTime
*/
Tone.Signal.prototype.exponentialRampToValueAtTime = function(value, endTime){
value *= this._syncRatio;
this.scalar.gain.exponentialRampToValueAtTime(value, this.toSeconds(endTime));
};
/**
* Schedules an exponential continuous change in parameter value from
* the current time and current value to the given value.
*
* @param {number} value
* @param {Tone.Time} endTime
*/
Tone.Signal.prototype.exponentialRampToValueNow = function(value, endTime){
var now = this.now();
this.setCurrentValueNow(now);
value *= this._syncRatio;
//make sure that the endTime doesn't start with +
if (endTime.toString().charAt(0) === "+"){
endTime = endTime.substr(1);
}
this.scalar.gain.exponentialRampToValueAtTime(value, now + this.toSeconds(endTime));
};
/**
* Schedules an linear continuous change in parameter value from
* the current time and current value to the given value at the given time.
*
* @param {number} value
* @param {Tone.Time} endTime
*/
Tone.Signal.prototype.linearRampToValueNow = function(value, endTime){
var now = this.now();
this.setCurrentValueNow(now);
value *= this._syncRatio;
//make sure that the endTime doesn't start with +
if (endTime.toString().charAt(0) === "+"){
endTime = endTime.substr(1);
}
this.scalar.gain.linearRampToValueAtTime(value, now + this.toSeconds(endTime));
};
/**
* Start exponentially approaching the target value at the given time with
* a rate having the given time constant.
*
* @param {number} value
* @param {Tone.Time} startTime
* @param {number} timeConstant
*/
Tone.Signal.prototype.setTargetAtTime = function(value, startTime, timeConstant){
value *= this._syncRatio;
this.output.gain.setTargetAtTime(value, this.toSeconds(startTime), timeConstant);
};
/**
* Sets an array of arbitrary parameter values starting at the given time
* for the given duration.
*
* @param {Array&lt;number>} values
* @param {Tone.Time} startTime
* @param {Tone.Time} duration
*/
Tone.Signal.prototype.setValueCurveAtTime = function(values, startTime, duration){
for (var i = 0; i &lt; values.length; i++){
values[i] *= this._syncRatio;
}
this.scalar.gain.setValueCurveAtTime(values, this.toSeconds(startTime), this.toSeconds(duration));
};
/**
* Cancels all scheduled parameter changes with times greater than or
* equal to startTime.
*
* @param {Tone.Time} startTime
*/
Tone.Signal.prototype.cancelScheduledValues = function(startTime){
this.scalar.gain.cancelScheduledValues(this.toSeconds(startTime));
};
/**
* Sync this to another signal and it will always maintain the
* ratio between the two signals until it is unsynced
*
* Signals can only be synced to one other signal. while syncing,
* if a signal's value is changed, the new ratio between the signals
* is maintained as the syncing signal is changed.
*
* @param {Tone.Signal} signal to sync to
* @param {number=} ratio optionally pass in the ratio between
* the two signals, otherwise it will be computed
*/
Tone.Signal.prototype.sync = function(signal, ratio){
if (ratio){
this._syncRatio = ratio;
} else {
//get the sync ratio
if (signal.getValue() !== 0){
this._syncRatio = this.getValue() / signal.getValue();
} else {
this._syncRatio = 0;
}
}
//make a new scalar which is not connected to the constant signal
this.scalar.disconnect();
this.scalar = this.context.createGain();
this.chain(signal, this.scalar, this.output);
//set it ot the sync ratio
this.scalar.gain.value = this._syncRatio;
};
/**
* unbind the signal control
*
* will leave the signal value as it was without the influence of the control signal
*/
Tone.Signal.prototype.unsync = function(){
//make a new scalar so that it's disconnected from the control signal
//get the current gain
var currentGain = this.getValue();
this.scalar.disconnect();
this.scalar = this.context.createGain();
this.scalar.gain.value = currentGain / this._syncRatio;
this._syncRatio = 1;
//reconnect things up
this.chain(constant, this.scalar, this.output);
};
/**
* internal dispose method to tear down the node
*/
Tone.Signal.prototype.dispose = function(){
//disconnect everything
this.output.disconnect();
this.scalar.disconnect();
this.output = null;
this.scalar = null;
};
/**
* Signals can connect to other Signals
*
* @override
* @param {AudioParam|AudioNode|Tone.Signal|Tone} node
*/
Tone.Signal.prototype.connect = function(node){
//zero it out so that the signal can have full control
if (node instanceof Tone.Signal){
node.setValue(0);
} else if (node instanceof AudioParam){
node.value = 0;
}
this.output.connect(node);
};
return Tone.Signal;
});
define('Tone/signal/Add',["Tone/core/Tone", "Tone/signal/Signal"], function(Tone){
/**
* Adds a value to an incoming signal
*
* @constructor
* @extends {Tone}
* @param {number} value
*/
Tone.Add = function(value){
/**
* @private
* @type {Tone}
*/
this._value = new Tone.Signal(value);
/**
* @type {GainNode}
*/
this.input = this.output = this.context.createGain();
//connections
this._value.connect(this.output);
};
Tone.extend(Tone.Add);
/**
* set the constant
*
* @param {number} value
*/
Tone.Add.prototype.setValue = function(value){
this._value.setValue(value);
};
/**
* dispose method
*/
Tone.Add.prototype.dispose = function(){
this._value.dispose();
this.output.disconnect();
this._value = null;
this.output = null;
};
return Tone.Add;
});
define('Tone/signal/Multiply',["Tone/core/Tone"], function(Tone){
/**
* Multiply the incoming signal by some factor
*
* @constructor
* @extends {Tone}
* @param {number=} value constant value to multiple
*/
Tone.Multiply = function(value){
/**
* the input node is the same as the output node
* it is also the GainNode which handles the scaling of incoming signal
*
* @type {GainNode}
*/
this.input = this.output = this.context.createGain();
//apply the inital scale factor
this.input.gain.value = this.defaultArg(value, 1);
};
Tone.extend(Tone.Multiply);
/**
* set the constant multiple
*
* @param {number} value
*/
Tone.Multiply.prototype.setValue = function(value){
this.input.gain.value = value;
};
/**
* clean up
*/
Tone.Multiply.prototype.dispose = function(){
this.input.disconnect();
this.input = null;
};
return Tone.Multiply;
});
define('Tone/signal/Scale',["Tone/core/Tone", "Tone/signal/Add", "Tone/signal/Multiply"], function(Tone){
/**
* performs a linear scaling on an input signal
*
* scales from the input range of inputMin to inputMax
* to the output range of outputMin to outputMax
*
* if only two arguments are provided, the inputMin and inputMax are set to -1 and 1
*
* @constructor
* @extends {Tone}
* @param {number} inputMin
* @param {number} inputMax
* @param {number=} outputMin
* @param {number=} outputMax
*/
Tone.Scale = function(inputMin, inputMax, outputMin, outputMax){
Tone.call(this);
//if there are only two args
if (arguments.length == 2){
outputMin = inputMin;
outputMax = inputMax;
inputMin = -1;
inputMax = 1;
}
/** @private
@type {number} */
this._inputMin = inputMin;
/** @private
@type {number} */
this._inputMax = inputMax;
/** @private
@type {number} */
this._outputMin = outputMin;
/** @private
@type {number} */
this._outputMax = outputMax;
/** @private
@type {Tone.Add} */
this._plusInput = new Tone.Add(0);
/** @private
@type {Tone.Multiply} */
this._scale = new Tone.Multiply(1);
/** @private
@type {Tone.Add} */
this._plusOutput = new Tone.Add(0);
//connections
this.chain(this.input, this._plusInput, this._scale, this._plusOutput, this.output);
//set the scaling values
this._setScalingParameters();
};
Tone.extend(Tone.Scale);
/**
* set the scaling parameters
*
* @private
*/
Tone.Scale.prototype._setScalingParameters = function(){
//components
this._plusInput.setValue(-this._inputMin);
this._scale.setValue((this._outputMax - this._outputMin)/(this._inputMax - this._inputMin));
this._plusOutput.setValue(this._outputMin);
};
/**
* set the input min value
* @param {number} val
*/
Tone.Scale.prototype.setInputMin = function(val){
this._inputMin = val;
this._setScalingParameters();
};
/**
* set the input max value
* @param {number} val
*/
Tone.Scale.prototype.setInputMax = function(val){
this._inputMax = val;
this._setScalingParameters();
};
/**
* set the output min value
* @param {number} val
*/
Tone.Scale.prototype.setOutputMin = function(val){
this._outputMin = val;
this._setScalingParameters();
};
/**
* set the output max value
* @param {number} val
*/
Tone.Scale.prototype.setOutputMax = function(val){
this._outputMax = val;
this._setScalingParameters();
};
/**
* clean up
*/
Tone.Scale.prototype.dispose = function(){
this.input.disconnect();
this.output.disconnect();
this._plusInput.dispose();
this._plusOutput.dispose();
this._scale.dispose();
this.input = null;
this.output = null;
this._plusInput = null;
this._plusOutput = null;
this._scale = null;
};
return Tone.Scale;
});
define('Tone/component/DryWet',["Tone/core/Tone", "Tone/signal/Signal", "Tone/signal/Scale"], function(Tone){
/**
* DRY/WET KNOB
*
* equal power fading control values:
* 0 = 100% dry - 0% wet
* 1 = 0% dry - 100% wet
*
* @constructor
* @param {number=} initialDry
*/
Tone.DryWet = function(initialDry){
Tone.call(this);
/**
* connect this input to the dry signal
* the dry signal is also the default input
*
* @type {GainNode}
*/
this.dry = this.input;
/**
* connect this input to the wet signal
*
* @type {GainNode}
*/
this.wet = this.context.createGain();
/**
* controls the amount of wet signal
* which is mixed into the dry signal
*
* @type {Tone.Signal}
*/
this.wetness = new Tone.Signal();
/**
* invert the incoming signal
* @private
* @type {Tone}
*/
this._invert = new Tone.Scale(0, 1, 1, 0);
//connections
this.dry.connect(this.output);
this.wet.connect(this.output);
//wet control
this.chain(this.wetness, this.wet.gain);
//dry control is the inverse of the wet
this.chain(this.wetness, this._invert, this.dry.gain);
this.dry.gain.value = 0;
this.wet.gain.value = 0;
this.setDry(this.defaultArg(initialDry, 0));
};
Tone.extend(Tone.DryWet);
/**
* Set the dry value
*
* @param {number} val
* @param {Tone.Time=} rampTime
*/
Tone.DryWet.prototype.setDry = function(val, rampTime){
this.setWet(1-val, rampTime);
};
/**
* Set the wet value
*
* @param {number} val
* @param {Tone.Time=} rampTime
*/
Tone.DryWet.prototype.setWet = function(val, rampTime){
if (rampTime){
this.wetness.linearRampToValueNow(val, rampTime);
} else {
this.wetness.setValue(val);
}
};
/**
* clean up
*/
Tone.DryWet.prototype.dispose = function(){
this.dry.disconnect();
this.wet.disconnect();
this.wetness.dispose();
this._invert.dispose();
this.output.disconnect();
this.dry = null;
this.wet = null;
this.wetness = null;
this._invert = null;
this.output = null;
};
return Tone.DryWet;
});
define('Tone/component/Envelope',["Tone/core/Tone", "Tone/signal/Signal"], function(Tone){
/**
* Envelope
* ADR envelope generator attaches to an AudioParam or AudioNode
*
* @constructor
* @extends {Tone}
* @param {Tone.Time=} attack
* @param {Tone.Time=} decay
* @param {number=} sustain a percentage (0-1) of the full amplitude
* @param {Tone.Time=} release
* @param {number=} minOutput the lowest point of the envelope
* @param {number=} maxOutput the highest point of the envelope
*/
Tone.Envelope = function(attack, decay, sustain, release, minOutput, maxOutput){
//extend Unit
Tone.call(this);
/** @type {number} */
this.attack = this.toSeconds(this.defaultArg(attack, 0.01));
/** @type {number} */
this.decay = this.toSeconds(this.defaultArg(decay, 0.1));
/** @type {number} */
this.release = this.toSeconds(this.defaultArg(release, 1));
/** @type {number} */
this.sustain = this.toSeconds(this.defaultArg(sustain, 0.5));
/** @type {number} */
this.min = this.defaultArg(minOutput, 0);
/** @type {number} */
this.max = this.defaultArg(maxOutput, 1);
/** @type {Tone.Signal} */
this.control = new Tone.Signal(this.min);
//connections
this.chain(this.control, this.output);
};
Tone.extend(Tone.Envelope);
/**
* attack->decay->sustain linear ramp
* @param {Tone.Time=} time
*/
Tone.Envelope.prototype.triggerAttack = function(time){
var sustainVal = (this.max - this.min) * this.sustain + this.min;
if (!time){
this.control.linearRampToValueNow(this.max, this.attack);
this.control.linearRampToValueAtTime(sustainVal, this.now() + this.attack + this.decay);
} else {
var startVal = this.min;
time = this.toSeconds(time);
this.control.cancelScheduledValues(time);
this.control.setValueAtTime(startVal, time);
this.control.linearRampToValueAtTime(this.max, time + this.attack);
this.control.linearRampToValueAtTime(sustainVal, time + this.attack + this.decay);
}
};
/**
* attack->decay->sustain exponential attack and linear decay
* @param {Tone.Time=} time
*/
Tone.Envelope.prototype.triggerExponentialAttack = function(time){
var sustainVal = (this.max - this.min) * this.sustain + this.min;
if (!time){
this.control.exponentialRampToValueNow(this.max, this.attack);
this.control.linearRampToValueAtTime(sustainVal, this.now() + this.attack + this.decay);
} else {
var startVal = this.min;
time = this.toSeconds(time);
this.control.cancelScheduledValues(time);
this.control.setValueAtTime(startVal, time);
this.control.exponentialRampToValueAtTime(this.max, time + this.attack);
this.control.linearRampToValueAtTime(sustainVal, time + this.attack + this.decay);
}
};
/**
* triggers the release of the envelope with a linear ramp
* @param {Tone.Time=} time
*/
Tone.Envelope.prototype.triggerRelease = function(time){
if (time){
//if there's a time, start at the sustain value
startVal = (this.max - this.min) * this.sustain + this.min;
time = this.toSeconds(time);
this.control.cancelScheduledValues(time);
this.control.setValueAtTime(startVal, time);
this.control.linearRampToValueAtTime(this.min, time + this.toSeconds(this.release));
} else {
this.control.linearRampToValueNow(this.min, this.toSeconds(this.release));
}
};
/**
* triggers the release of the envelope with an exponential ramp
*
* @param {Tone.Time=} time
*/
Tone.Envelope.prototype.triggerExponentialRelease = function(time){
if (time){
//if there's a time, start at the sustain value
startVal = (this.max - this.min) * this.sustain + this.min;
time = this.toSeconds(time);
this.control.cancelScheduledValues(time);
this.control.setValueAtTime(startVal, time);
this.control.exponentialRampToValueAtTime(this.min, time + this.toSeconds(this.release));
} else {
this.control.exponentialRampToValueNow(this.min, this.toSeconds(this.release));
}
};
/**
* pointer to the parent's connect method
* @private
*/
Tone.Envelope.prototype._connect = Tone.prototype.connect;
/**
* connect the envelope
*
* if the envelope is connected to a param, the params
* value will be set to 0 so that it doesn't interfere with the envelope
*
* @param {number} param
*/
Tone.Envelope.prototype.connect = function(param){
if (param instanceof AudioParam){
//set the initial value
param.value = 0;
}
this._connect(param);
};
/**
* disconnect and dispose
*/
Tone.Envelope.prototype.dispose = function(){
this.control.dispose();
this.control = null;
};
return Tone.Envelope;
});
define('Tone/signal/Threshold',["Tone/core/Tone"], function(Tone){
/**
* Threshold an incoming signal. the signal is assumed to be in the normal range (-1 to 1)
*
* Sets a threshold value such that signal above the value will equal 1,
* and below will equal 0.
*
* @constructor
* @param {number=} [thresh=0] threshold value above which the output will equal 1
* and below which the output will equal 0
* @extends {Tone}
*/
Tone.Threshold = function(thresh){
/**
* @type {WaveShaperNode}
* @private
*/
this._thresh = this.context.createWaveShaper();
/**
* make doubly sure that the input is thresholded by
* passing it through two waveshapers
*
* @type {WaveShaperNode}
* @private
*/
this._doubleThresh = this.context.createWaveShaper();
/**
* @type {WaveShaperNode}
*/
this.input = this._thresh;
this.output = this._doubleThresh;
this._thresh.connect(this._doubleThresh);
this._setThresh(this._thresh, this.defaultArg(thresh, 0));
this._setThresh(this._doubleThresh, 1);
};
Tone.extend(Tone.Threshold);
/**
* @param {number} thresh
* @private
*/
Tone.Threshold.prototype._setThresh = function(component, thresh){
var curveLength = 1024;
var curve = new Float32Array(curveLength);
for (var i = 0; i &lt; curveLength; i++){
var normalized = (i / (curveLength - 1)) * 2 - 1;
var val;
if (normalized &lt; thresh){
val = 0;
} else {
val = 1;
}
curve[i] = val;
}
component.curve = curve;
};
/**
* sets the threshold value
*
* @param {number} thresh number must be between -1 and 1
*/
Tone.Threshold.prototype.setThreshold = function(thresh){
this._setThresh(this._thresh, thresh);
};
/**
* dispose method
*/
Tone.Threshold.prototype.dispose = function(){
this._thresh.disconnect();
this._doubleThresh.disconnect();
this._thresh = null;
this._doubleThresh = null;
};
return Tone.Threshold;
});
define('Tone/signal/Negate',["Tone/core/Tone", "Tone/signal/Multiply"], function(Tone){
/**
* Negate the incoming signal. i.e. an input signal of 10 will output -10
*
* @constructor
* @extends {Tone}
*/
Tone.Negate = function(value){
/**
* negation is done by multiplying by -1
* @type {Tone.Multiply}
* @private
*/
this._multiply = new Tone.Multiply(-1);
/**
* the input and output
*/
this.input = this.output = this._multiply;
};
Tone.extend(Tone.Negate);
/**
* clean up
*/
Tone.Negate.prototype.dispose = function(){
this.input.disconnect();
this.input = null;
};
return Tone.Negate;
});
define('Tone/signal/EqualZero',["Tone/core/Tone", "Tone/signal/Threshold"], function(Tone){
/**
* Output 1 if the signal is equal to 0, otherwise outputs 0
*
* @constructor
* @extends {Tone}
*/
Tone.EqualZero = function(){
/**
* @type {WaveShaperNode}
* @private
*/
this._equals = this.context.createWaveShaper();
/**
* @type {WaveShaperNode}
* @private
*/
this._thresh = new Tone.Threshold(1);
/**
* @type {WaveShaperNode}
*/
this.input = this._equals;
this._equals.connect(this._thresh);
this.output = this._thresh;
this._setEquals();
};
Tone.extend(Tone.EqualZero);
/**
* @private
*/
Tone.EqualZero.prototype._setEquals = function(){
var curveLength = 1024;
var curve = new Float32Array(curveLength);
for (var i = 0; i &lt; curveLength; i++){
var normalized = (i / (curveLength)) * 2 - 1;
if (normalized === 0){
curve[i] = 1;
} else {
curve[i] = 0;
}
}
this._equals.curve = curve;
};
/**
* dispose method
*/
Tone.EqualZero.prototype.dispose = function(){
this._equals.disconnect();
this._thresh.dispose();
this._equals = null;
this._thresh = null;
};
return Tone.EqualZero;
});
define('Tone/signal/Abs',["Tone/core/Tone", "Tone/signal/Threshold", "Tone/signal/Negate", "Tone/signal/EqualZero"], function(Tone){
/**
* return the absolute value of an incoming signal
*
* @constructor
* @extends {Tone}
* @param {number} value
*/
Tone.Abs = function(value){
Tone.call(this);
/**
* @type {Tone.Threshold}
* @private
*/
this._thresh = new Tone.Threshold(0);
/**
* @type {Tone.Negate}
* @private
*/
this._negate = new Tone.Negate();
/**
* @type {Tone.EqualZero}
* @private
*/
this._not = new Tone.EqualZero();
/**
* @type {GainNode}
* @private
*/
this._positive = this.context.createGain();
/**
* @type {GainNode}
* @private
*/
this._negative = this.context.createGain();
this.input.connect(this._thresh);
//two routes, one positive, one negative
this.chain(this.input, this._positive, this.output);
this.chain(this.input, this._negate, this._negative, this.output);
//the switching logic
this._thresh.connect(this._positive.gain);
this._positive.gain.value = 0;
this.chain(this._thresh, this._not, this._negative.gain);
this._negative.gain.value = 0;
};
Tone.extend(Tone.Abs);
/**
* dispose method
*/
Tone.Abs.prototype.dispose = function(){
this._thresh.dispose();
this._negate.dispose();
this._not.dispose();
this._positive.disconnect();
this._negative.disconnect();
this.input.disconnect();
this.output.disconnect();
this._thresh = null;
this._negate = null;
this._not = null;
this._positive = null;
this._negative = null;
this.input = null;
this.output = null;
};
return Tone.Abs;
});
define('Tone/component/Follower',["Tone/core/Tone", "Tone/signal/Abs", "Tone/signal/Negate", "Tone/signal/Threshold"], function(Tone){
/**
* Follow the envelope of the incoming signal
* @constructor
* @extends {Tone}
* @param {Tone.Time=} [attackTime = 0.01]
* @param {Tone.Time=} [releaseTime = 0.1]
*/
Tone.Follower = function(attackTime, releaseTime){
Tone.call(this);
//default values
attackTime = this.defaultArg(attackTime, 0.01);
releaseTime = this.defaultArg(releaseTime, 0.1);
/**
* @type {Tone.Abs}
* @private
*/
this._abs = new Tone.Abs();
/**
* the lowpass filter
* @type {BiquadFilterNode}
* @private
*/
this._filter = this.context.createBiquadFilter();
this._filter.type = "lowpass";
this._filter.frequency.value = 0;
/**
* @type {WaveShaperNode}
* @private
*/
this._frequencyValues = this.context.createWaveShaper();
/**
* @type {Tone.Negate}
* @private
*/
this._negate = new Tone.Negate();
/**
* @type {GainNode}
* @private
*/
this._difference = this.context.createGain();
/**
* @type {GainNode}
* @private
*/
this._thresh = new Tone.Threshold(0);
//the smoothed signal
this.chain(this.input, this._abs, this._filter, this.output);
//subtract the smoothed signal from the input signal
this.input.connect(this._negate);
this.output.connect(this._difference);
this._negate.connect(this._difference);
//threshold the difference and use the thresh to set the frequency
this.chain(this._difference, this._thresh, this._frequencyValues, this._filter.frequency);
//set the attack and release values in the table
this._setAttackRelease(this.secondsToFrequency(attackTime), this.secondsToFrequency(releaseTime));
};
Tone.extend(Tone.Follower);
/**
* sets the attack and release times in the wave shaper
* @param {number} attack
* @param {number} release
* @private
*/
Tone.Follower.prototype._setAttackRelease = function(attack, release){
var curveLength = 1024;
var curve = new Float32Array(curveLength);
for (var i = 0; i &lt; curveLength; i++){
var normalized = (i / (curveLength - 1)) * 2 - 1;
var val;
if (normalized &lt; 0.5){
val = attack;
} else {
val = release;
}
curve[i] = val;
}
this._frequencyValues.curve = curve;
};
/**
* dispose
*/
Tone.Follower.prototype.dispose = function(){
this._filter.disconnect();
this.input.disconnect();
this._frequencyValues.disconnect();
this.output.disconnect();
this._abs.dispose();
this._negate.dispose();
this._difference.dispose();
this._thresh.dispose();
this._filter = null;
this.input = null;
this._frequencyValues = null;
this.output = null;
this._abs = null;
this._negate = null;
this._difference = null;
this._thresh = null;
};
return Tone.Follower;
});
define('Tone/core/Transport',["Tone/core/Tone", "Tone/core/Master", "Tone/signal/Signal"],
function(Tone){
/**
* oscillator-based transport allows for simple musical timing
* supports tempo curves and time changes
*
* @constructor
* @extends {Tone}
*/
Tone.Transport = function(){
/**
* watches the main oscillator for timing ticks
*
* @private
* @type {ScriptProcessorNode}
*/
this._jsNode = this.context.createScriptProcessor(this.bufferSize, 1, 1);
this._jsNode.onaudioprocess = this._processBuffer.bind(this);
/**
* @type {boolean}
*/
this.loop = false;
/**
* @type {TransportState}
*/
this.state = TransportState.STOPPED;
//so it doesn't get garbage collected
this._jsNode.noGC();
};
Tone.extend(Tone.Transport);
/**
* @private
* @type {number}
*/
var timelineTicks = 0;
/**
* @private
* @type {number}
*/
var transportTicks = 0;
/**
* @private
* @type {number}
*/
var tatum = 12;
/**
* @private
* @type {Boolean}
*/
var upTick = false;
/**
* @private
* @type {number}
*/
var transportTimeSignature = 4;
/**
* @private
* @type {number}
*/
var loopStart = 0;
/**
* @private
* @type {number}
*/
var loopEnd = tatum * 4;
/**
* @private
* @type {Array}
*/
var intervals = [];
/**
* @private
* @type {Array}
*/
var timeouts = [];
/**
* @private
* @type {Array}
*/
var transportTimeline = [];
/**
* @private
* @type {number}
*/
var timelineProgress = 0;
/**
* The main oscillator for the system
* @private
* @type {OscillatorNode}
*/
var oscillator = null;
/**
* controls the oscillator frequency
* starts at 120bpm
*
* @private
* @type {Tone.Signal}
*/
var controlSignal = new Tone.Signal(24);
/**
* All of the synced components
* @private
* @type {Array&lt;Tone>}
*/
var SyncedSources = [];
/**
* @enum
*/
var TransportState = {
STARTED : "started",
PAUSED : "paused",
STOPPED : "stopped"
};
///////////////////////////////////////////////////////////////////////////////
// JS NODE PROCESSING
///////////////////////////////////////////////////////////////////////////////
/**
* called when a buffer is ready
*
* @param {AudioProcessingEvent} event
*/
Tone.Transport.prototype._processBuffer = function(event){
var now = this.defaultArg(event.playbackTime, this.now());
var bufferSize = this._jsNode.bufferSize;
var incomingBuffer = event.inputBuffer.getChannelData(0);
for (var i = 0; i &lt; bufferSize; i++){
var sample = incomingBuffer[i];
if (sample > 0 && !upTick){
upTick = true;
this._processTick(now + this.samplesToSeconds(i));
} else if (sample &lt; 0 && upTick){
upTick = false;
}
}
};
//@param {number} tickTime
Tone.Transport.prototype._processTick = function(tickTime){
if (oscillator !== null){
processIntervals(tickTime);
processTimeouts(tickTime);
processTimeline(tickTime);
transportTicks += 1;
timelineTicks += 1;
if (this.loop){
if (timelineTicks === loopEnd){
this._setTicks(loopStart);
}
}
}
};
//jump to a specific tick in the timeline
Tone.Transport.prototype._setTicks = function(ticks){
timelineTicks = ticks;
for (var i = 0; i &lt; transportTimeline.length; i++){
var timeout = transportTimeline[i];
if (timeout.callbackTick() >= ticks){
timelineProgress = i;
break;
}
}
};
///////////////////////////////////////////////////////////////////////////////
// EVENT PROCESSING
///////////////////////////////////////////////////////////////////////////////
/**
* process the intervals
* @param {number} time
*/
var processIntervals = function(time){
for (var i = 0, len = intervals.length; i&lt;len; i++){
var interval = intervals[i];
if (interval.testInterval(transportTicks)){
interval.doCallback(time);
}
}
};
/**
* process the timeouts
* @param {number} time
*/
var processTimeouts = function(time){
var removeTimeouts = 0;
for (var i = 0, len = timeouts.length; i&lt;len; i++){
var timeout = timeouts[i];
var callbackTick = timeout.callbackTick();
if (callbackTick &lt;= transportTicks){
timeout.doCallback(time);
removeTimeouts++;
} else if (callbackTick > transportTicks){
break;
}
}
//remove the timeouts off the front of the array after they've been called
timeouts.splice(0, removeTimeouts);
};
/**
* process the transportTimeline events
* @param {number} time
*/
var processTimeline = function(time){
for (var i = timelineProgress, len = transportTimeline.length; i&lt;len; i++){
var evnt = transportTimeline[i];
var callbackTick = evnt.callbackTick();
if (callbackTick === timelineTicks){
evnt.doCallback(time);
timelineProgress = i;
} else if (callbackTick > timelineTicks){
break;
}
}
};
/**
* clear the timeouts and intervals
*/
function clearTimelineEvents(){
intervals = [];
}
///////////////////////////////////////////////////////////////////////////////
// INTERVAL
///////////////////////////////////////////////////////////////////////////////
/**
* intervals are recurring events
*
* @param {function} callback
* @param {Tone.Time} interval
* @param {Object} ctx the context the function is invoked in
* @return {number} the id of the interval
*/
Tone.Transport.prototype.setInterval = function(callback, interval, ctx){
var tickTime = this.toTicks(interval);
var timeout = new TimelineEvent(callback, ctx, tickTime, transportTicks);
intervals.push(timeout);
return timeout.id;
};
/**
* clear an interval from the processing array
* @param {number} rmInterval the interval to remove
* @return {boolean} true if the event was removed
*/
Tone.Transport.prototype.clearInterval = function(rmInterval){
for (var i = 0; i &lt; intervals.length; i++){
var interval = intervals[i];
if (interval.id === rmInterval){
intervals.splice(i, 1);
return true;
}
}
return false;
};
/**
* removes all of the intervals that are currently set
*/
Tone.Transport.prototype.clearIntervals = function(){
intervals = [];
};
///////////////////////////////////////////////////////////////////////////////
// TIMEOUT
///////////////////////////////////////////////////////////////////////////////
/**
* set a timeout to occur after time from now
*
* @param {function} callback
* @param {Tone.Time} time
* @param {Object} ctx the context to invoke the callback in
* @return {number} the id of the timeout for clearing timeouts
*/
Tone.Transport.prototype.setTimeout = function(callback, time, ctx){
var ticks = this.toTicks(time);
var timeout = new TimelineEvent(callback, ctx, ticks + transportTicks, 0);
//put it in the right spot
for (var i = 0, len = timeouts.length; i&lt;len; i++){
var testEvnt = timeouts[i];
if (testEvnt.callbackTick() > timeout.callbackTick()){
timeouts.splice(i, 0, timeout);
return timeout.id;
}
}
//otherwise push it on the end
timeouts.push(timeout);
return timeout.id;
};
/**
* clear the timeout based on it's ID
* @param {number} timeoutID
* @return {boolean} true if the timeout was removed
*/
Tone.Transport.prototype.clearTimeout = function(timeoutID){
for (var i = 0; i &lt; timeouts.length; i++){
var testTimeout = timeouts[i];
if (testTimeout.id === timeoutID){
timeouts.splice(i, 1);
return true;
}
}
return false;
};
/**
* removes all of the timeouts that are currently set
*
* @todo (optionally) remove events after a certain time
*/
Tone.Transport.prototype.clearTimeouts = function(){
timeouts = [];
};
///////////////////////////////////////////////////////////////////////////////
// TIMELINE
///////////////////////////////////////////////////////////////////////////////
/**
* Timeline events are synced to the transportTimeline of the Transport
* Unlike Timeout, Timeline events will restart after the
* Transport has been stopped and restarted.
*
*
* @param {function} callback
* @param {Tome.Time} timeout
* @param {Object} ctx the context in which the funtion is called
* @return {number} the id for clearing the transportTimeline event
*/
Tone.Transport.prototype.setTimeline = function(callback, timeout, ctx){
var ticks = this.toTicks(timeout);
var timelineEvnt = new TimelineEvent(callback, ctx, ticks, 0);
//put it in the right spot
for (var i = timelineProgress, len = transportTimeline.length; i&lt;len; i++){
var testEvnt = transportTimeline[i];
if (testEvnt.callbackTick() > timelineEvnt.callbackTick()){
transportTimeline.splice(i, 0, timelineEvnt);
return timelineEvnt.id;
}
}
//otherwise push it on the end
transportTimeline.push(timelineEvnt);
return timelineEvnt.id;
};
/**
* clear the transportTimeline event from the
* @param {number} timelineID
* @return {boolean} true if it was removed
*/
Tone.Transport.prototype.clearTimeline = function(timelineID){
for (var i = 0; i &lt; transportTimeline.length; i++){
var testTimeline = transportTimeline[i];
if (testTimeline.id === timelineID){
transportTimeline.splice(i, 1);
return true;
}
}
return false;
};
/**
* remove all events from the timeline
*/
Tone.Transport.prototype.clearTimelines = function(){
timelineProgress = 0;
transportTimeline = [];
};
///////////////////////////////////////////////////////////////////////////////
// TIME CONVERSIONS
///////////////////////////////////////////////////////////////////////////////
/**
* turns the time into
* @param {Tone.Time} time
* @return {number}
*/
Tone.Transport.prototype.toTicks = function(time){
//get the seconds
var seconds = this.toSeconds(time);
var quarter = this.notationToSeconds("4n");
var quarters = seconds / quarter;
var tickNum = quarters * tatum;
//quantize to tick value
return Math.round(tickNum);
};
/**
* get the transport time
* @return {string} in transportTime format (measures:beats:sixteenths)
*/
Tone.Transport.prototype.getTransportTime = function(){
var quarters = timelineTicks / tatum;
var measures = Math.floor(quarters / transportTimeSignature);
var sixteenths = Math.floor((quarters % 1) * 4);
quarters = Math.floor(quarters) % transportTimeSignature;
var progress = [measures, quarters, sixteenths];
return progress.join(":");
};
/**
* set the transport time, jump to the position right away
*
* @param {Tone.Time} progress
*/
Tone.Transport.prototype.setTransportTime = function(progress){
var ticks = this.toTicks(progress);
this._setTicks(ticks);
};
///////////////////////////////////////////////////////////////////////////////
// START/STOP/PAUSE
///////////////////////////////////////////////////////////////////////////////
/**
* start the transport and all sources synced to the transport
*
* @param {Tone.Time} time
*/
Tone.Transport.prototype.start = function(time){
if (this.state === TransportState.STOPPED || this.state === TransportState.PAUSED){
this.state = TransportState.STARTED;
//reset the oscillator
oscillator = this.context.createOscillator();
oscillator.type = "square";
oscillator.connect(this._jsNode);
//connect it up
controlSignal.connect(oscillator.frequency);
oscillator.frequency.value = 0;
upTick = false;
var startTime = this.toSeconds(time);
oscillator.start(startTime);
//call start on each of the synced sources
for (var i = 0; i &lt; SyncedSources.length; i++){
var source = SyncedSources[i].source;
var delay = SyncedSources[i].delay;
source.start(startTime + delay);
}
}
};
/**
* stop the transport and all sources synced to the transport
*
* @param {Tone.Time} time
*/
Tone.Transport.prototype.stop = function(time){
if (this.state === TransportState.STARTED || this.state === TransportState.PAUSED){
this.state = TransportState.STOPPED;
var stopTime = this.toSeconds(time);
oscillator.stop(stopTime);
oscillator = null;
this._setTicks(0);
this.clearTimeouts();
this.clearIntervals();
//call start on each of the synced sources
for (var i = 0; i &lt; SyncedSources.length; i++){
var source = SyncedSources[i].source;
source.stop(stopTime);
}
}
};
/**
* pause the transport and all sources synced to the transport
*
* @param {Tone.Time} time
*/
Tone.Transport.prototype.pause = function(time){
if (this.state === TransportState.STARTED){
this.state = TransportState.PAUSED;
var stopTime = this.toSeconds(time);
oscillator.stop(stopTime);
oscillator = null;
clearTimelineEvents();
//call pause on each of the synced sources
for (var i = 0; i &lt; SyncedSources.length; i++){
var source = SyncedSources[i].source;
source.pause(stopTime);
}
}
};
///////////////////////////////////////////////////////////////////////////////
// SETTERS/GETTERS
///////////////////////////////////////////////////////////////////////////////
/**
* set the BPM
* optionally ramp to the bpm over some time
* @param {number} bpm
* @param {Tone.Time=} rampTime
*/
Tone.Transport.prototype.setBpm = function(bpm, rampTime){
//convert the bpm to frequency
var tatumFreq = this.secondsToFrequency(this.notationToSeconds(tatum.toString() + "n", bpm, transportTimeSignature));
// var tatumFreq = this.toFrequency(tatum.toString() + "n", bpm, transportTimeSignature);
var freqVal = 4 * tatumFreq;
if (!rampTime){
controlSignal.cancelScheduledValues(0);
controlSignal.setValue(freqVal);
} else {
controlSignal.exponentialRampToValueNow(freqVal, rampTime);
}
};
/**
* return the current BPM
*
* @return {number}
*/
Tone.Transport.prototype.getBpm = function(){
//convert the current frequency of the oscillator to bpm
var freq = controlSignal.getValue();
return 60 * (freq / tatum);
};
/**
* set the time signature
*
* @example
* this.setTimeSignature(4); //for 4/4
*
* @param {number} numerator
* @param {number=} denominator defaults to 4
*/
Tone.Transport.prototype.setTimeSignature = function(numerator, denominator){
denominator = this.defaultArg(denominator, 4);
transportTimeSignature = numerator / (denominator / 4);
};
/**
* return the time signature as just the numerator
* over 4 is assumed.
* for example 4/4 would return 4 and 6/8 would return 3
*
* @return {number}
*/
Tone.Transport.prototype.getTimeSignature = function(){
return transportTimeSignature;
};
/**
* set the loop start position
*
* @param {Tone.Time} startPosition
*/
Tone.Transport.prototype.setLoopStart = function(startPosition){
loopStart = this.toTicks(startPosition);
};
/**
* set the loop start position
*
* @param {Tone.Time} endPosition
*/
Tone.Transport.prototype.setLoopEnd = function(endPosition){
loopEnd = this.toTicks(endPosition);
};
/**
* shorthand loop setting
* @param {Tone.Time} startPosition
* @param {Tone.Time} endPosition
*/
Tone.Transport.prototype.setLoopPoint = function(startPosition, endPosition){
this.setLoopStart(startPosition);
this.setLoopEnd(endPosition);
};
///////////////////////////////////////////////////////////////////////////////
// SYNCING
///////////////////////////////////////////////////////////////////////////////
/**
* Sync a source to the transport so that
* @param {Tone.Source} source the source to sync to the transport
* @param {Tone.Time} delay (optionally) start the source with a delay from the transport
*/
Tone.Transport.prototype.sync = function(source, startDelay){
SyncedSources.push({
source : source,
delay : this.toSeconds(this.defaultArg(startDelay, 0))
});
};
/**
* attaches the signal to the tempo control signal so that
* any changes in the tempo will change the signal in the same
* ratio
*
* @param {Tone.Signal} signal
*/
Tone.Transport.prototype.syncSignal = function(signal){
};
/**
* remove the source from the list of Synced Sources
*
* @param {Tone.Source} source [description]
*/
Tone.Transport.prototype.unsync = function(source){
for (var i = 0; i &lt; SyncedSources.length; i++){
if (SyncedSources[i].source === source){
SyncedSources.splice(i, 1);
}
}
};
///////////////////////////////////////////////////////////////////////////////
// TIMELINE EVENT
///////////////////////////////////////////////////////////////////////////////
/**
* @static
* @type {number}
*/
var TimelineEventIDCounter = 0;
/**
* A Timeline event
*
* @constructor
* @param {function(number)} callback
* @param {Object} context
* @param {number} tickTime
* @param {number} startTicks
*/
var TimelineEvent = function(callback, context, tickTime, startTicks){
this.startTicks = startTicks;
this.tickTime = tickTime;
this.callback = callback;
this.context = context;
this.id = TimelineEventIDCounter++;
};
/**
* invoke the callback in the correct context
* passes in the playback time
*
* @param {number} playbackTime
*/
TimelineEvent.prototype.doCallback = function(playbackTime){
this.callback.call(this.context, playbackTime);
};
/**
* get the tick which the callback is supposed to occur on
*
* @return {number}
*/
TimelineEvent.prototype.callbackTick = function(){
return this.startTicks + this.tickTime;
};
/**
* test if the tick occurs on the interval
*
* @param {number} tick
* @return {boolean}
*/
TimelineEvent.prototype.testInterval = function(tick){
return (tick - this.startTicks) % this.tickTime === 0;
};
///////////////////////////////////////////////////////////////////////////////
// AUGMENT TONE'S PROTOTYPE TO INCLUDE TRANSPORT TIMING
///////////////////////////////////////////////////////////////////////////////
/**
* tests if a string is musical notation
* i.e.:
* 4n = quarter note
* 2m = two measures
* 8t = eighth-note triplet
*
* @return {boolean}
* @method isNotation
* @lends Tone.prototype.isNotation
*/
Tone.prototype.isNotation = (function(){
var notationFormat = new RegExp(/[0-9]+[mnt]$/i);
return function(note){
return notationFormat.test(note);
};
})();
/**
* tests if a string is transportTime
* i.e. :
* 1:2:0 = 1 measure + two quarter notes + 0 sixteenth notes
*
* @return {boolean}
*
* @method isTransportTime
* @lends Tone.prototype.isTransportTime
*/
Tone.prototype.isTransportTime = (function(){
var transportTimeFormat = new RegExp(/^\d+(\.\d+)?:\d+(\.\d+)?(:\d+(\.\d+)?)?$/);
return function(transportTime){
return transportTimeFormat.test(transportTime);
};
})();
/**
* true if the input is in the format number+hz
* i.e.: 10hz
*
* @param {number} freq
* @return {boolean}
*
* @method isFrequency
* @lends Tone.prototype.isFrequency
*/
Tone.prototype.isFrequency = (function(){
var freqFormat = new RegExp(/[0-9]+hz$/i);
return function(freq){
return freqFormat.test(freq);
};
})();
/**
*
* convert notation format strings to seconds
* @param {string} notation
* @param {number=} bpm
* @param {number=} timeSignature
* @return {number}
*
*/
Tone.prototype.notationToSeconds = function(notation, bpm, timeSignature){
bpm = this.defaultArg(bpm, Tone.Transport.getBpm());
timeSignature = this.defaultArg(timeSignature, transportTimeSignature);
var beatTime = (60 / bpm);
var subdivision = parseInt(notation, 10);
var beats = 0;
if (subdivision === 0){
beats = 0;
}
var lastLetter = notation.slice(-1);
if (lastLetter === "t"){
beats = (4 / subdivision) * 2/3;
} else if (lastLetter === "n"){
beats = 4 / subdivision;
} else if (lastLetter === "m"){
beats = subdivision * timeSignature;
} else {
beats = 0;
}
return beatTime * beats;
};
/**
* convert transportTime into seconds
*
* ie: 4:2:3 == 4 measures + 2 quarters + 3 sixteenths
*
* @param {string} transportTime
* @param {number=} bpm
* @param {number=} timeSignature
* @return {number} seconds
*
* @lends Tone.prototype.transportTimeToSeconds
*/
Tone.prototype.transportTimeToSeconds = function(transportTime, bpm, timeSignature){
bpm = this.defaultArg(bpm, Tone.Transport.getBpm());
timeSignature = this.defaultArg(timeSignature, transportTimeSignature);
var measures = 0;
var quarters = 0;
var sixteenths = 0;
var split = transportTime.split(":");
if (split.length === 2){
measures = parseFloat(split[0]);
quarters = parseFloat(split[1]);
} else if (split.length === 1){
quarters = parseFloat(split[0]);
} else if (split.length === 3){
measures = parseFloat(split[0]);
quarters = parseFloat(split[1]);
sixteenths = parseFloat(split[2]);
}
var beats = (measures * timeSignature + quarters + sixteenths / 4);
return beats * this.notationToSeconds("4n");
};
/**
* Convert seconds to the closest transportTime in the form
* measures:quarters:sixteenths
*
* @method toTransportTime
*
* @param {Tone.Time} seconds
* @param {number=} bpm
* @param {number=} timeSignature
* @return {string}
*
* @lends Tone.prototype.toTransportTime
*/
Tone.prototype.toTransportTime = function(time, bpm, timeSignature){
var seconds = this.toSeconds(time, bpm, timeSignature);
bpm = this.defaultArg(bpm, Tone.Transport.getBpm());
timeSignature = this.defaultArg(timeSignature, transportTimeSignature);
var quarterTime = this.notationToSeconds("4n");
var quarters = seconds / quarterTime;
var measures = Math.floor(quarters / timeSignature);
var sixteenths = Math.floor((quarters % 1) * 4);
quarters = Math.floor(quarters) % timeSignature;
var progress = [measures, quarters, sixteenths];
return progress.join(":");
};
/**
* convert a time to a frequency
*
* @param {Tone.Time} time
* @return {number} the time in hertz
*/
Tone.prototype.toFrequency = function(time, now){
if (this.isFrequency(time)){
return parseFloat(time);
} else if (this.isNotation(time) || this.isTransportTime(time)) {
return this.secondsToFrequency(this.toSeconds(time, now));
} else {
return time;
}
};
/**
* convert Tone.Time into seconds.
*
* unlike the method which it overrides, this takes into account
* transporttime and musical notation
*
* @override
* @param {Tone.Time} time
* @param {number=} now if passed in, this number will be
* used for all 'now' relative timings
* @return {number}
*/
Tone.prototype.toSeconds = function(time, now){
now = this.defaultArg(now, this.now());
if (typeof time === "number"){
return time; //assuming that it's seconds
} else if (typeof time === "string"){
var plusTime = 0;
if(time.charAt(0) === "+") {
plusTime = now;
time = time.slice(1);
}
if (this.isNotation(time)){
time = this.notationToSeconds(time);
} else if (this.isTransportTime(time)){
time = this.transportTimeToSeconds(time);
} else if (this.isFrequency(time)){
time = this.frequencyToSeconds(time);
} else {
time = parseFloat(time);
}
return time + plusTime;
} else {
return now;
}
};
//a single transport object
Tone.Transport = new Tone.Transport();
return Tone.Transport;
});
define('Tone/source/Source',["Tone/core/Tone", "Tone/core/Transport"], function(Tone){
/**
* base class for sources
*
* sources have start/stop/pause
*
* they also have the ability to be synced to the
* start/stop/pause of Tone.Transport
*
* @constructor
* @extends {Tone}
*/
Tone.Source = function(){
/**
* unlike most ToneNodes, Sources only have an output and no input
*
* @type {GainNode}
*/
this.output = this.context.createGain();
/**
* @type {Tone.Source.State}
*/
this.state = Tone.Source.State.STOPPED;
};
Tone.extend(Tone.Source);
/**
* @abstract
* @param {Tone.Time} time
*/
Tone.Source.prototype.start = function(){};
/**
* @abstract
* @param {Tone.Time} time
*/
Tone.Source.prototype.stop = function(){};
/**
* @abstract
* @param {Tone.Time} time
*/
Tone.Source.prototype.pause = function(time){
//if there is no pause, just stop it
this.stop(time);
};
/**
* sync the source to the Transport
*
* @param {Tone.Time=} delay optional delay time before starting the source
*/
Tone.Source.prototype.sync = function(delay){
Tone.Transport.sync(this, delay);
};
/**
* unsync the source to the Transport
*/
Tone.Source.prototype.unsync = function(){
Tone.Transport.unsync(this);
};
/**
* @param {number} value
* @param {Tone.Time=} fadeTime (optional) time it takes to reach the value
*/
Tone.Source.prototype.setVolume = function(value, fadeTime){
var now = this.now();
if (fadeTime){
var currentVolume = this.output.gain.value;
this.output.gain.cancelScheduledValues(now);
this.output.gain.setValueAtTime(currentVolume, now);
this.output.gain.linearRampToValueAtTime(value, now + this.toSeconds(time));
} else {
this.output.gain.setValueAtTime(value, now);
}
};
/**
* @enum {string}
*/
Tone.Source.State = {
STARTED : "started",
PAUSED : "paused",
STOPPED : "stopped",
SYNCED : "synced"
};
return Tone.Source;
});
define('Tone/source/Oscillator',["Tone/core/Tone", "Tone/core/Transport", "Tone/signal/Signal", "Tone/source/Source"],
function(Tone){
/**
* Oscillator
*
* Oscilator with start, pause, stop and sync to Transport
*
* @constructor
* @extends {Tone.Source}
* @param {number|string=} freq starting frequency
* @param {string=} type type of oscillator (sine|square|triangle|sawtooth)
*/
Tone.Oscillator = function(freq, type){
Tone.Source.call(this);
/**
* the main oscillator
* @type {OscillatorNode}
*/
this.oscillator = this.context.createOscillator();
/**
* the frequency control signal
* @type {Tone.Signal}
*/
this.frequency = new Tone.Signal(this.defaultArg(this.toFrequency(freq), 440));
/**
* @type {function()}
*/
this.onended = function(){};
//connections
this.oscillator.connect(this.output);
//setup
this.oscillator.type = this.defaultArg(type, "sine");
};
Tone.extend(Tone.Oscillator, Tone.Source);
/**
* start the oscillator
*
* @param {Tone.Time} time
*/
Tone.Oscillator.prototype.start = function(time){
if (this.state === Tone.Source.State.STOPPED){
this.state = Tone.Source.State.STARTED;
//get previous values
var type = this.oscillator.type;
var detune = this.oscillator.detune.value;
//new oscillator with previous values
this.oscillator = this.context.createOscillator();
this.oscillator.type = type;
this.oscillator.detune.value = detune;
//connect the control signal to the oscillator frequency
this.oscillator.connect(this.output);
this.frequency.connect(this.oscillator.frequency);
this.oscillator.frequency.value = 0;
//start the oscillator
this.oscillator.start(this.toSeconds(time));
this.oscillator.onended = this._onended.bind(this);
}
};
/**
* stop the oscillator
* @param {Tone.Time=} time (optional) timing parameter
*/
Tone.Oscillator.prototype.stop = function(time){
if (this.state === Tone.Source.State.STARTED){
if (!time){
this.state = Tone.Source.State.STOPPED;
}
this.oscillator.stop(this.toSeconds(time));
}
};
/**
* Sync the oscillator to the transport
*
* the current ratio between the oscillator and the Transport BPM
* is fixed and any change to the Transport BPM will change this
* oscillator in that same ratio
*
* Transport start/pause/stop will also start/pause/stop the oscillator
*
* @param {Tone.Time=} delay optional delay time before starting the source
*/
Tone.Oscillator.prototype.sync = function(delay){
Tone.Transport.sync(this, delay);
// Tone.Transport.syncSignal(this.frequency);
};
/**
* unsync the oscillator from the Transport
*/
Tone.Oscillator.prototype.unsync = function(){
Tone.Transport.unsync(this);
// this.frequency.unsync();
};
/**
* exponentially ramp the frequency of the oscillator over the rampTime
*
* @param {Tone.Time} val
* @param {Tone.Time=} rampTime when the oscillator will arrive at the frequency
*/
Tone.Oscillator.prototype.setFrequency = function(val, rampTime){
if (rampTime){
this.frequency.exponentialRampToValueAtTime(this.toFrequency(val), this.toSeconds(rampTime));
} else {
this.frequency.setValue(this.toFrequency(val));
}
};
/**
* set the oscillator type
*
* @param {string} type (sine|square|triangle|sawtooth)
*/
Tone.Oscillator.prototype.setType = function(type){
this.oscillator.type = type;
};
/**
* internal on end call
* @private
*/
Tone.Oscillator.prototype._onended = function(){
this.state = Tone.Source.State.STOPPED;
this.onended();
};
/**
* dispose and disconnect
*/
Tone.Oscillator.prototype.dispose = function(){
if (this.oscillator !== null){
this.oscillator.disconnect();
this.oscillator = null;
}
this.frequency.dispose();
this.frequency = null;
this.output.disconnect();
this.output = null;
};
return Tone.Oscillator;
});
define('Tone/component/LFO',["Tone/core/Tone", "Tone/source/Oscillator", "Tone/signal/Scale"], function(Tone){
/**
* Low Frequency Oscillator
*
* LFO produces an output signal which can be attached to an AudioParam
* for constant control over that parameter
* the LFO can also be synced to the transport
*
* @constructor
* @extends {Tone}
* @param {number} rate
* @param {number=} outputMin
* @param {number=} outputMax
*/
Tone.LFO = function(rate, outputMin, outputMax){
/** @type {GainNode} */
this.input = this.context.createGain();
/** @type {Tone.Oscillator} */
this.oscillator = new Tone.Oscillator(this.defaultArg(rate, 1), "sine");
/**
@type {Tone.Scale}
@private
*/
this._scaler = new Tone.Scale(this.defaultArg(outputMin, 0), this.defaultArg(outputMax, 1));
/** alias for the output */
this.output = this._scaler;
//connect it up
this.chain(this.oscillator, this.output);
};
Tone.extend(Tone.LFO);
/**
* start the LFO
* @param {Tone.Time} time
*/
Tone.LFO.prototype.start = function(time){
this.oscillator.start(time);
};
/**
* stop the LFO
* @param {Tone.Time} time
*/
Tone.LFO.prototype.stop = function(time){
this.oscillator.stop(time);
};
/**
* Sync the start/stop/pause to the transport
* and the frequency to the bpm of the transport
*/
Tone.LFO.prototype.sync = function(){
this.oscillator.sync();
// Tone.Transport.syncSignal(this.oscillator.frequency);
};
/**
* unsync the LFO from transport control
*/
Tone.LFO.prototype.unsync = function(){
this.oscillator.unsync();
// this.oscillator.frequency.unsync();
};
/**
* set the frequency
* @param {number} rate
*/
Tone.LFO.prototype.setFrequency = function(rate){
this.oscillator.setFrequency(rate);
};
/**
* set the minimum output of the LFO
* @param {number} min
*/
Tone.LFO.prototype.setMin = function(min){
this._scaler.setOutputMin(min);
};
/**
* set the maximum output of the LFO
* @param {number} min
*/
Tone.LFO.prototype.setMax = function(max){
this._scaler.setOuputMax(max);
};
/**
* set the waveform of the LFO
* @param {string} type
*/
Tone.LFO.prototype.setType = function(type){
this.oscillator.setType(type);
};
/**
* pointer to the parent's connect method
* @private
*/
Tone.LFO.prototype._connect = Tone.prototype.connect;
/**
* override the connect method so that it 0's out the value
* if attached to an AudioParam
*
* @borrows Tone.Signal.connect as Tone.LFO.connect
*/
Tone.LFO.prototype.connect = Tone.Signal.prototype.connect;
/**
* disconnect and dispose
*/
Tone.LFO.prototype.dispose = function(){
this.oscillator.dispose();
this.output.disconnect();
this._scaler.dispose();
this.oscillator = null;
this.output = null;
this._scaler = null;
};
return Tone.LFO;
});
define('Tone/component/Meter',["Tone/core/Tone", "Tone/core/Master"], function(Tone){
/**
* get the rms of the input signal with some averaging
* can also just get the value of the signal
* or the value in dB
*
* inspired by https://github.com/cwilso/volume-meter/blob/master/volume-meter.js
* The MIT License (MIT) Copyright (c) 2014 Chris Wilson
*
* @constructor
* @extends {Tone}
* @param {number=} channels (optional) number of channels being metered
* @param {number=} smoothing (optional) amount of smoothing applied to the volume
* @param {number=} clipMemory (optional) number in ms that a "clip" should be remembered
*/
Tone.Meter = function(channels, smoothing, clipMemory){
//extends Unit
Tone.call(this);
/** @type {number} */
this.channels = this.defaultArg(channels, 1);
/** @type {number} */
this.smoothing = this.defaultArg(smoothing, 0.8);
/** @type {number} */
this.clipMemory = this.defaultArg(clipMemory, 500);
/**
* the rms for each of the channels
* @private
* @type {Array&lt;number>}
*/
this._volume = new Array(this.channels);
/**
* the raw values for each of the channels
* @private
* @type {Array&lt;number>}
*/
this._values = new Array(this.channels);
//zero out the volume array
for (var i = 0; i &lt; this.channels; i++){
this._volume[i] = 0;
this._values[i] = 0;
}
/**
* last time the values clipped
* @private
* @type {number}
*/
this._lastClip = 0;
/**
* @private
* @type {ScriptProcessorNode}
*/
this._jsNode = this.context.createScriptProcessor(this.bufferSize, this.channels, 1);
this._jsNode.onaudioprocess = this._onprocess.bind(this);
//so it doesn't get garbage collected
this._jsNode.noGC();
//signal just passes
this.input.connect(this.output);
this.input.connect(this._jsNode);
};
Tone.extend(Tone.Meter);
/**
* called on each processing frame
* @private
* @param {AudioProcessingEvent} event
*/
Tone.Meter.prototype._onprocess = function(event){
var bufferSize = this._jsNode.bufferSize;
var smoothing = this.smoothing;
for (var channel = 0; channel &lt; this.channels; channel++){
var input = event.inputBuffer.getChannelData(channel);
var sum = 0;
var total = 0;
var x;
var clipped = false;
for (var i = 0; i &lt; bufferSize; i++){
x = input[i];
if (!clipped && x > 0.95){
clipped = true;
this._lastClip = Date.now();
}
total += x;
sum += x * x;
}
var average = total / bufferSize;
var rms = Math.sqrt(sum / bufferSize);
this._volume[channel] = Math.max(rms, this._volume[channel] * smoothing);
this._values[channel] = average;
}
};
/**
* get the rms of the signal
*
* @param {number=} channel which channel
* @return {number} the value
*/
Tone.Meter.prototype.getLevel = function(channel){
channel = this.defaultArg(channel, 0);
var vol = this._volume[channel];
if (vol &lt; 0.00001){
return 0;
} else {
return vol;
}
};
/**
* get the value of the signal
* @param {number=} channel
* @return {number}
*/
Tone.Meter.prototype.getValue = function(channel){
channel = this.defaultArg(channel, 0);
return this._values[channel];
};
/**
* get the volume of the signal in dB
* @param {number=} channel
* @return {number}
*/
Tone.Meter.prototype.getDb = function(channel){
return this.gainToDb(this.getLevel(channel));
};
// @returns {boolean} if the audio has clipped in the last 500ms
Tone.Meter.prototype.isClipped = function(){
return Date.now() - this._lastClip &lt; this.clipMemory;
};
/**
* @override
*/
Tone.Meter.prototype.dispose = function(){
this._jsNode.disconnect();
this._jsNode.onaudioprocess = null;
this._volume = null;
this._values = null;
this.input.disconnect();
this.output.disconnect();
};
return Tone.Meter;
});
define('Tone/signal/Merge',["Tone/core/Tone"], function(Tone){
/**
* merge a left and a right channel into a single stereo channel
*
* instead of connecting to the input, connect to either the left, or right input
*
* default input for connect is left input
*
* @constructor
* @extends {Tone}
*/
Tone.Merge = function(){
Tone.call(this);
/**
* the left input channel
* also an alias for the input
* @type {GainNode}
*/
this.left = this.input;
/**
* the right input channel
* @type {GainNode}
*/
this.right = this.context.createGain();
/**
* the merger node for the two channels
* @type {ChannelMergerNode}
*/
this.merger = this.context.createChannelMerger(2);
//connections
this.left.connect(this.merger, 0, 0);
this.right.connect(this.merger, 0, 1);
this.merger.connect(this.output);
};
Tone.extend(Tone.Merge);
/**
* clean up
*/
Tone.Merge.prototype.dispose = function(){
this.input.disconnect();
this.right.disconnect();
this.merger.disconnect();
this.input = null;
this.right = null;
this.merger = null;
};
return Tone.Merge;
});
define('Tone/signal/Split',["Tone/core/Tone"], function(Tone){
/**
* split the incoming signal into left and right channels
*
* the left channel is the default output
*
* @constructor
* @extends {Tone}
*/
Tone.Split = function(){
Tone.call(this);
/**
* @type {ChannelSplitterNode}
*/
this.splitter = this.context.createChannelSplitter(2);
/**
* left channel output
* @type {GainNode}
*/
this.left = this.output;
/**
* the right channel output
* @type {GainNode}
*/
this.right = this.context.createGain();
//connections
this.input.connect(this.splitter);
this.splitter.connect(this.left, 0, 0);
this.splitter.connect(this.right, 1, 0);
};
Tone.extend(Tone.Split);
/**
* dispose method
*/
Tone.Split.prototype.dispose = function(){
this.splitter.disconnect();
this.input.disconnect();
this.output.disconnect();
this.splitter = null;
this.input = null;
this.output = null;
};
return Tone.Split;
});
define('Tone/component/Panner',["Tone/core/Tone", "Tone/component/DryWet", "Tone/signal/Merge", "Tone/signal/Split"],
function(Tone){
/**
* Panner.
*
* Equal Power Gain L/R Panner. Not 3D
*
* a panner uses a dry/wet knob internally
*
* 0 = 100% Left
* 1 = 100% Right
*
* @constructor
* @extends {Tone}
* @param {number=} initialPan the initail panner value (defaults to 0.5 = center)
*/
Tone.Panner = function(initialPan){
Tone.call(this);
/**
* the dry/wet knob
* @type {Tone.DryWet}
* @private
*/
this._dryWet = new Tone.DryWet();
/**
* @type {Tone.Merge}
* @private
*/
this._merger = new Tone.Merge();
/**
* @type {Tone.Split}
* @private
*/
this._splitter = new Tone.Split();
/**
* the pan control
* @type {Tone.Signal}
*/
this.pan = this._dryWet.wetness;
//CONNECTIONS:
this.input.connect(this._splitter.left);
this.input.connect(this._splitter.right);
//left channel is dry, right channel is wet
this._splitter.left.connect(this._dryWet.dry);
this._splitter.right.connect(this._dryWet.wet);
//merge it back together
this._dryWet.dry.connect(this._merger.left);
this._dryWet.wet.connect(this._merger.right);
this._merger.connect(this.output);
//initial value
this.setPan(this.defaultArg(initialPan, 0.5));
};
Tone.extend(Tone.Panner);
/**
* set the l/r pan.
*
* 0 = 100% left.
* 1 = 100% right.
*
* @param {number} pan 0-1
* @param {Tone.Time=} rampTime (optionally) ramp to the pan position
*/
Tone.Panner.prototype.setPan = function(pan, rampTime){
this._dryWet.setWet(pan, rampTime);
};
/**
* clean up
*/
Tone.Panner.prototype.dispose = function(){
this._dryWet.dispose();
this._splitter.dispose();
this._merger.dispose();
this.input.disconnect();
this.output.disconnect();
this._dryWet = null;
this._splitter = null;
this._merger = null;
this.input = null;
this.output = null;
};
return Tone.Panner;
});
define('Tone/component/Recorder',["Tone/core/Tone", "Tone/core/Master"], function(Tone){
/**
* Record an input into an array or AudioBuffer
*
* it is limited in that the recording length needs to be known beforehand
*
* @constructor
* @extends {Tone}
* @param {number} channels
*/
Tone.Recorder = function(channels){
Tone.call(this);
/**
* the number of channels in the recording
* @type {number}
*/
this.channels = this.defaultArg(channels, 1);
/**
* @private
* @type {ScriptProcessorNode}
*/
this._jsNode = this.context.createScriptProcessor(this.bufferSize, this.channels, 1);
this._jsNode.onaudioprocess = this._audioprocess.bind(this);
/**
* Float32Array for each channel
* @private
* @type {Array&lt;Float32Array>}
*/
this._recordBuffers = new Array(this.channels);
/**
* @type {number}
* @private
*/
this._recordStartSample = 0;
/**
* @type {number}
* @private
*/
this._recordEndSample = 0;
/**
* @type {number}
* @private
*/
this._recordDuration = 0;
/**
* @type {RecordState}
*/
this.state = RecordState.STOPPED;
/**
* @private
* @type {number}
*/
this._recordBufferOffset = 0;
/**
* callback invoked when the recording is over
* @private
* @type {function(Float32Array)}
*/
this._callback = function(){};
//connect it up
this.input.connect(this._jsNode);
//pass thru audio
this.input.connect(this.output);
//so it doesn't get garbage collected
this._jsNode.noGC();
//clear it to start
this.clear();
};
Tone.extend(Tone.Recorder);
/**
* internal method called on audio process
*
* @private
* @param {AudioProcessorEvent} event
*/
Tone.Recorder.prototype._audioprocess = function(event){
if (this.state === RecordState.STOPPED){
return;
} else if (this.state === RecordState.RECORDING){
//check if it's time yet
var now = this.defaultArg(event.playbackTime, this.now());
var processPeriodStart = this.toSamples(now);
var bufferSize = this._jsNode.bufferSize;
var processPeriodEnd = processPeriodStart + bufferSize;
var bufferOffset, len;
if (processPeriodStart > this._recordEndSample){
this.state = RecordState.STOPPED;
this._callback(this._recordBuffers);
} else if (processPeriodStart > this._recordStartSample) {
bufferOffset = 0;
len = Math.min(this._recordEndSample - processPeriodStart, bufferSize);
this._recordChannels(event.inputBuffer, bufferOffset, len, bufferSize);
} else if (processPeriodEnd > this._recordStartSample) {
len = processPeriodEnd - this._recordStartSample;
bufferOffset = bufferSize - len;
this._recordChannels(event.inputBuffer, bufferOffset, len, bufferSize);
}
}
};
/**
* record an input channel
* @param {AudioBuffer} inputBuffer
* @param {number} from
* @param {number} to
* @private
*/
Tone.Recorder.prototype._recordChannels = function(inputBuffer, from, to, bufferSize){
var offset = this._recordBufferOffset;
var buffers = this._recordBuffers;
for (var channelNum = 0; channelNum &lt; inputBuffer.numberOfChannels; channelNum++){
var channel = inputBuffer.getChannelData(channelNum);
if ((from === 0) && (to === bufferSize)){
//set the whole thing
this._recordBuffers[channelNum].set(channel, offset);
} else {
for (var i = from; i &lt; from + to; i++){
var zeroed = i - from;
buffers[channelNum][zeroed + offset] = channel[i];
}
}
}
this._recordBufferOffset += to;
};
/**
* Record for a certain period of time
*
* will clear the internal buffer before starting
*
* @param {Tone.Time} duration
* @param {Tone.Time} wait the wait time before recording
* @param {function(Float32Array)} callback the callback to be invoked when the buffer is done recording
*/
Tone.Recorder.prototype.record = function(duration, startTime, callback){
if (this.state === RecordState.STOPPED){
this.clear();
this._recordBufferOffset = 0;
startTime = this.defaultArg(startTime, 0);
this._recordDuration = this.toSamples(duration);
this._recordStartSample = this.toSamples("+"+startTime);
this._recordEndSample = this._recordStartSample + this._recordDuration;
for (var i = 0; i &lt; this.channels; i++){
this._recordBuffers[i] = new Float32Array(this._recordDuration);
}
this.state = RecordState.RECORDING;
this._callback = this.defaultArg(callback, function(){});
}
};
/**
* clears the recording buffer
*/
Tone.Recorder.prototype.clear = function(){
for (var i = 0; i &lt; this.channels; i++){
this._recordBuffers[i] = null;
}
this._recordBufferOffset = 0;
};
/**
* true if there is nothing in the buffers
* @return {boolean}
*/
Tone.Recorder.prototype.isEmpty = function(){
return this._recordBuffers[0] === null;
};
/**
* @return {Array&lt;Float32Array>}
*/
Tone.Recorder.prototype.getFloat32Array = function(){
if (this.isEmpty()){
return null;
} else {
return this._recordBuffers;
}
};
/**
* @return {AudioBuffer}
*/
Tone.Recorder.prototype.getAudioBuffer = function(){
if (this.isEmpty()){
return null;
} else {
var audioBuffer = this.context.createBuffer(this.channels, this._recordBuffers[0].length, this.context.sampleRate);
for (var channelNum = 0; channelNum &lt; audioBuffer.numberOfChannels; channelNum++){
var channel = audioBuffer.getChannelData(channelNum);
channel.set(this._recordBuffers[channelNum]);
}
return audioBuffer;
}
};
/**
* clean up
*/
Tone.Recorder.prototype.dispose = function(){
this.output.disconnect();
this.input.disconnect();
this._jsNode.disconnect();
this._jsNode.onaudioprocess = undefined;
this.output = null;
this.input = null;
this._jsNode = null;
this._recordBuffers = null;
};
/**
* @enum {string}
*/
var RecordState = {
STOPPED : "stopped",
SCHEDULED : "scheduled",
RECORDING : "recording"
};
return Tone.Recorder;
});
define('Tone/core/Bus',["Tone/core/Tone"], function(Tone){
/**
* buses are another way of routing audio
*
* augments Tone.prototype to include send and recieve
*/
/**
* All of the routes
*
* @type {Object}
*/
var Buses = {};
/**
* send signal to a channel name
*
* @param {string} channelName
* @param {number} amount
* @return {GainNode}
*/
Tone.prototype.send = function(channelName, amount){
if (!Buses.hasOwnProperty(channelName)){
Buses[channelName] = this.context.createGain();
}
var sendKnob = this.context.createGain();
sendKnob.gain.value = this.defaultArg(amount, 1);
this.chain(this.output, sendKnob, Buses[channelName]);
return sendKnob;
};
/**
* recieve the input from the desired channelName to the input gain of 'this' node.
*
* @param {string} channelName
*/
Tone.prototype.receive = function(channelName){
if (!Buses.hasOwnProperty(channelName)){
Buses[channelName] = this.context.createGain();
}
Buses[channelName].connect(this.input);
};
Tone.Buses = Buses;
return Buses;
});
define('Tone/effect/Effect',["Tone/core/Tone", "Tone/component/DryWet"], function(Tone){
/**
* Effect is the base class for effects. connect the effect between
* the effectSend and effectReturn GainNodes. then control the amount of
* effect which goes to the output using the dry/wet control.
*
* @constructor
* @extends {Tone}
* @param {number=} initalDry the starting dry value
* defaults to 0.5 (50% dry / 50% wet)
*/
Tone.Effect = function(initialDry){
Tone.call(this);
/**
* the drywet knob to control the amount of effect
*
* @type {Tone.DryWet}
*/
this.dryWet = new Tone.DryWet();
/**
* connect the effectSend to the input of hte effect
*
* @type {GainNode}
*/
this.effectSend = this.context.createGain();
/**
* connect the output of the effect to the effectReturn
*
* @type {GainNode}
*/
this.effectReturn = this.context.createGain();
//connections
this.input.connect(this.dryWet.dry);
this.input.connect(this.effectSend);
this.effectReturn.connect(this.dryWet.wet);
this.dryWet.connect(this.output);
//setup
this.setDry(this.defaultArg(initialDry, 0.5));
};
Tone.extend(Tone.Effect);
/**
* setDry adjusts the dry / wet balance
* dryness is 0 (100% wet) to 1 (100% dry)
*
* @param {number} dryness
* @param {Tone.Time=} rampTime
*/
Tone.Effect.prototype.setDry = function(dryness, rampTime){
this.dryWet.setDry(dryness, rampTime);
};
/**
* setWet also adjusts the dry / wet balance
* wetVal is 0 (100% dry) to 1 (100% wet)
*
* @param {number} wetness
* @param {Tone.Time=} rampTime
*/
Tone.Effect.prototype.setWet = function(wetVal, rampTime){
this.dryWet.setWet(wetVal, rampTime);
};
/**
* bypass the effect
*/
Tone.Effect.prototype.bypass = function(){
this.setDry(1);
};
/**
* chains the effect in between the effectSend and effectReturn
* @param {Tone} effect
*/
Tone.Effect.prototype.connectEffect = function(effect){
this.chain(this.effectSend, effect, this.effectReturn);
};
/**
* tear down
*/
Tone.Effect.prototype.dispose = function(){
this.dryWet.dispose();
this.input.disconnect();
this.output.disconnect();
this.effectSend.disconnect();
this.effectReturn.disconnect();
this.dryWet = null;
this.input = null;
this.output = null;
this.effectSend = null;
this.effectReturn = null;
};
return Tone.Effect;
});
define('Tone/effect/AutoPanner',["Tone/core/Tone", "Tone/effect/Effect", "Tone/component/LFO", "Tone/component/Panner"], function(Tone){
/**
* AutoPanner is a Tone.Panner with an LFO connected to the pan amount
*
* @constructor
* @extends {Tone.Effect}
* @param { number= } rate (optional) rate in HZ of the left-right pan
* @param { number= } amount (optional) of the pan (0 - 1)
*/
Tone.AutoPanner = function(rate, amount){
Tone.Effect.call(this);
/**
* the lfo which drives the panning
* @type {Tone.LFO}
*/
this.lfo = new Tone.LFO(rate, 0, 1);
/**
* the panner node which does the panning
* @type {Tone.Panner}
*/
this.panner = new Tone.Panner();
//connections
this.connectEffect(this.panner);
this.lfo.connect(this.panner.pan);
//default dry value
this.setDry(this.defaultArg(amount, 1));
};
//extend Effect
Tone.extend(Tone.AutoPanner, Tone.Effect);
/**
* Start the panner
*
* @param {Tone.Time=} Time the panner begins.
*/
Tone.AutoPanner.prototype.start = function(time){
this.lfo.start(time);
};
/**
* Stop the panner
*
* @param {Tone.Time=} time the panner stops.
*/
Tone.AutoPanner.prototype.stop = function(time){
this.lfo.stop(time);
};
/**
* Set the type of oscillator attached to the AutoPanner.
*
* @param {string} type of oscillator the panner is attached to (sine|sawtooth|triangle|square)
*/
Tone.AutoPanner.prototype.setType = function(type){
this.lfo.setType(type);
};
/**
* Set frequency of the oscillator attached to the AutoPanner.
*
* @param {number|string} rate in HZ of the oscillator's frequency.
*/
Tone.AutoPanner.prototype.setFrequency = function(rate){
this.lfo.setFrequency(rate);
};
/**
* pointer to the parent's dipose method
*/
Tone.AutoPanner.prototype._effectDispose = Tone.Effect.prototype.dispose;
/**
* clean up
*/
Tone.AutoPanner.prototype.dispose = function(){
this._effectDispose();
this.lfo.dispose();
this.panner.dispose();
this.lfo = null;
this.panner = null;
};
return Tone.AutoPanner;
});
define('Tone/effect/BitCrusher',["Tone/core/Tone"], function(Tone){
/**
* downsample incoming signal
* inspiration from https://github.com/jaz303/bitcrusher/blob/master/index.js
*
* @constructor
* @extends {Tone}
* @param {number=} bits
* @param {number=} frequency
*/
Tone.BitCrusher = function(bits, frequency){
Tone.call(this);
/**
* @private
* @type {number}
*/
this._bits = this.defaultArg(bits, 8);
/**
* @private
* @type {number}
*/
this._frequency = this.defaultArg(frequency, 0.5);
/**
* @private
* @type {number}
*/
this._step = 2 * Math.pow(0.5, this._bits);
/**
* @private
* @type {number}
*/
this._invStep = 1/this._step;
/**
* @private
* @type {number}
*/
this._phasor = 0;
/**
* @private
* @type {number}
*/
this._last = 0;
/**
* @private
* @type {ScriptProcessorNode}
*/
this._crusher = this.context.createScriptProcessor(this.bufferSize, 1, 1);
this._crusher.onaudioprocess = this._audioprocess.bind(this);
//connect it up
this.chain(this.input, this._crusher, this.output);
};
Tone.extend(Tone.BitCrusher);
/**
* @private
* @param {AudioProcessingEvent} event
*/
Tone.BitCrusher.prototype._audioprocess = function(event){
//cache the values used in the loop
var phasor = this._phasor;
var freq = this._frequency;
var invStep = this._invStep;
var last = this._last;
var step = this._step;
var input = event.inputBuffer.getChannelData(0);
var output = event.outputBuffer.getChannelData(0);
for (var i = 0, len = output.length; i &lt; len; i++) {
phasor += freq;
if (phasor >= 1) {
phasor -= 1;
last = step * ((input[i] * invStep) | 0 + 0.5);
}
output[i] = last;
}
//set the values for the next loop
this._phasor = phasor;
this._last = last;
};
/**
* set the bit rate
*
* @param {number} bits
*/
Tone.BitCrusher.prototype.setBits = function(bits){
this._bits = bits;
this._step = 2 * Math.pow(0.5, this._bits);
this._invStep = 1/this._step;
};
/**
* set the frequency
* @param {number} freq
*/
Tone.BitCrusher.prototype.setFrequency = function(freq){
this._frequency = freq;
};
/**
* clean up
*/
Tone.BitCrusher.prototype.dispose = function(){
this.input.disconnect();
this.output.disconnect();
this._crusher.disconnect();
this.input = null;
this.output = null;
this._crusher = null;
};
return Tone.BitCrusher;
});
define('Tone/effect/FeedbackEffect',["Tone/core/Tone", "Tone/effect/Effect", "Tone/signal/Signal"], function(Tone){
/**
* Feedback Effect (a sound loop between an audio source and its own output)
*
* @constructor
* @extends {Tone.Effect}
* @param {number=} initialFeedback the initial feedback value (defaults to 0.25)
*/
Tone.FeedbackEffect = function(initialFeedback){
Tone.Effect.call(this);
/**
* controls the amount of feedback
* @type {Tone.Signal}
*/
this.feedback = new Tone.Signal(this.defaultArg(initialFeedback, 0.25));
/**
* the gain which controls the feedback
* @type {GainNode}
* @private
*/
this._feedbackGain = this.context.createGain();
//the feedback loop
this.chain(this.effectReturn, this._feedbackGain, this.effectSend);
this.feedback.connect(this._feedbackGain.gain);
};
Tone.extend(Tone.FeedbackEffect, Tone.Effect);
/**
* set the feedback amount
*
* @param {number} value the amount of feedback
* @param {Tone.Time=} rampTime (optionally) set the ramp time it takes
* to reach the new feedback value
*/
Tone.FeedbackEffect.prototype.setFeedback = function(value, rampTime){
if (rampTime){
this.feedback.linearRampToValueNow(value, rampTime);
} else {
this.feedback.setValue(value);
}
};
/**
* the parents dispose method
* @private
* @borrows Tone.Effect.dispose as Tone.FeedbackEffect._effectDispose
*/
Tone.FeedbackEffect.prototype._effectDispose = Tone.Effect.prototype.dispose;
/**
* clean up
*/
Tone.FeedbackEffect.prototype.dispose = function(){
this._effectDispose();
this.feedback.dispose();
this._feedbackGain.disconnect();
this.feedback = null;
this._feedbackGain = null;
};
return Tone.FeedbackEffect;
});
define('Tone/effect/FeedbackDelay',["Tone/core/Tone", "Tone/effect/FeedbackEffect", "Tone/signal/Signal"], function(Tone){
/**
* A feedback delay
*
* @constructor
* @extends {Tone.FeedbackEffect}
* @param {Tone.Time=} delayTime
*/
Tone.FeedbackDelay = function(delayTime){
Tone.FeedbackEffect.call(this);
/**
* Tone.Signal to control the delay amount
* @type {Tone.Signal}
*/
this.delay = new Tone.Signal();
/**
* the delay node
* @type {DelayNode}
* @private
*/
this._delayNode = this.context.createDelay(4);
// connect it up
this.connectEffect(this._delayNode);
this.delay.connect(this._delayNode.delayTime);
//set the initial delay
this.setDelayTime(this.defaultArg(delayTime, 0.25));
};
Tone.extend(Tone.FeedbackDelay, Tone.FeedbackEffect);
/**
* Sets the delay time
*
* @param {Tone.Time} delayTime
* @param {Tone.Time=} rampTime time it takes to reach the desired delayTime
*/
Tone.FeedbackDelay.prototype.setDelayTime = function(delayTime, rampTime){
if (rampTime){
this.delay.linearRampToValueNow(this.toSeconds(delayTime), rampTime);
} else {
this.delay.setValue(this.toSeconds(delayTime));
}
};
/**
* pointer to the feedback effects dispose method
* @borrows Tone.FeedbackDelay._feedbackEffectDispose as Tone.FeedbackEffect.dispose;
*/
Tone.FeedbackDelay.prototype._feedbackEffectDispose = Tone.FeedbackEffect.prototype.dispose;
/**
* clean up
*/
Tone.FeedbackDelay.prototype.dispose = function(){
this._feedbackEffectDispose();
this.delay.dispose();
this._delayNode.disconnect();
this._delayNode = null;
this.delay = null;
};
return Tone.FeedbackDelay;
});
define('Tone/effect/PingPongDelay',["Tone/core/Tone", "Tone/effect/FeedbackDelay", "Tone/signal/Split", "Tone/signal/Merge"], function(Tone){
/**
* PingPongDelay is a dual delay effect where the echo is heard first in one channel and next in the opposite channel
*
* @constructor
* @extends {Tone.Effect}
* @param {Tone.Time=} delayTime is the interval between consecutive echos
*/
Tone.PingPongDelay = function(delayTime){
Tone.call(this);
/**
* merge the delayed signal
*/
this._merger = new Tone.Merge();
/**
* each channel (left/right) gets a feedback delay
* @type {Tone.FeedbackDelay}
*/
this.leftDelay = new Tone.FeedbackDelay(delayTime);
/**
* @type {Tone.FeedbackDelay}
*/
this.rightDelay = new Tone.FeedbackDelay(delayTime);
//connect it up
this.input.connect(this.leftDelay);
this.input.connect(this.rightDelay);
//disconnect the feedback lines to connect them to the other delay
// http://jvzaudio.files.wordpress.com/2011/04/delay-f43.gif
this.leftDelay._feedbackGain.disconnect();
this.rightDelay._feedbackGain.disconnect();
this.leftDelay._feedbackGain.connect(this.rightDelay.effectSend);
this.rightDelay._feedbackGain.connect(this.leftDelay.effectSend);
this.leftDelay.connect(this._merger.left);
this.rightDelay.connect(this._merger.right);
this._merger.connect(this.output);
//initial vals;
this.setDelayTime(this.defaultArg(delayTime, 0.25));
};
Tone.extend(Tone.PingPongDelay);
/**
* setDelayTime
*
* @param {Tone.Time} delayTime
*/
Tone.PingPongDelay.prototype.setDelayTime = function(delayTime){
this.leftDelay.setDelayTime(delayTime);
this.rightDelay.setDelayTime(delayTime * 2);
};
/**
* setFeedback
*
* @param {number} feedback (0 - 1)
*/
Tone.PingPongDelay.prototype.setFeedback = function(feedback){
this.leftDelay.setFeedback(feedback);
this.rightDelay.setFeedback(feedback);
};
/**
* setWet
*
* @param {number} wet (0 - 1)
*/
Tone.PingPongDelay.prototype.setWet = function(wet){
this.leftDelay.setWet(wet);
this.rightDelay.setWet(wet);
};
/**
* setDry
*
* @param {number} dry (0 - 1)
*/
Tone.PingPongDelay.prototype.setDry = function(dry){
this.leftDelay.setDry(dry);
this.rightDelay.setDry(dry);
};
return Tone.PingPongDelay;
});
define('Tone/signal/Equal',["Tone/core/Tone", "Tone/signal/EqualZero", "Tone/signal/Add"], function(Tone){
/**
* Output 1 if the signal is equal to the value, otherwise outputs 0
*
* @constructor
* @extends {Tone}
* @param {number} value the number to compare the incoming signal to
*/
Tone.Equal = function(value){
/**
* subtract the value from the incoming signal
*
* @type {Tone.Add}
* @private
*/
this._adder = new Tone.Add(-value);
/**
* @type {Tone.EqualZero}
* @private
*/
this._equals = new Tone.EqualZero();
/**
* @type {Tone.Add}
*/
this.input = this._adder;
/**
* @type {Tone.EqualZero}
*/
this.output = this._equals;
this._adder.connect(this._equals);
};
Tone.extend(Tone.Equal);
/**
* @param {number} value set the comparison value
*/
Tone.Equal.prototype.setValue = function(value){
this._adder.setValue(-value);
};
/**
* dispose method
*/
Tone.Equal.prototype.dispose = function(){
this._equals.disconnect();
this._adder.dispose();
this._equals = null;
this._adder = null;
};
return Tone.Equal;
});
define('Tone/signal/Gate',["Tone/core/Tone", "Tone/signal/Signal", "Tone/signal/Threshold"], function(Tone){
/**
* When the gate is set to 0, the input signal does not pass through to the output.
* If the gate is set to 1, the input signal passes through
*
* the switch will initially be closed.
*
* @constructor
* @extends {Tone}
*/
Tone.Gate = function(){
Tone.call(this);
/**
* the control signal for the switch
* when this value is 0, the input signal will not pass through,
* when it is high (1), the input signal will pass through.
*
* @type {Tone.Signal}
*/
this.gate = new Tone.Signal(0);
/**
* thresh the control signal
* @type {Tone.Threshold}
* @private
*/
this._thresh = new Tone.Threshold(0.5);
this.input.connect(this.output);
this.chain(this.gate, this._thresh, this.output.gain);
this.output.gain.value = 0;
};
Tone.extend(Tone.Gate);
/**
* open the switch at a specific time
*
* @param {Tone.Time} time the time when the switch will be open
*/
Tone.Gate.prototype.open = function(time){
this.gate.setValueAtTime(1, this.toSeconds(time));
};
/**
* close the switch at a specific time
*
* @param {Tone.Time} time the time when the switch will be open
*/
Tone.Gate.prototype.close = function(time){
this.gate.setValueAtTime(0, this.toSeconds(time));
};
/**
* clean up
*/
Tone.Gate.prototype.dispose = function(){
this.gate.dispose();
this._thresh.dispose();
this.input.disconnect();
this.output.disconnect();
this.signal = null;
this._thresh = null;
this.input = null;
this.output = null;
};
return Tone.Gate;
});
define('Tone/signal/GreaterThan',["Tone/core/Tone", "Tone/signal/Threshold"], function(Tone){
/**
* Output 1 if the signal is greater than the value, otherwise outputs 0
*
* @constructor
* @extends {Tone}
* @param {number=} [value=0] the value to compare to the incoming signal
*/
Tone.GreaterThan = function(value){
/**
* @type {WaveShaperNode}
* @private
*/
this._gt = this.context.createWaveShaper();
/**
* @type {WaveShaperNode}
* @private
*/
this._thresh = new Tone.Threshold(0.001);
/**
* subtract the value from the incoming signal
*
* @type {Tone.Add}
* @private
*/
this._adder = new Tone.Add(this.defaultArg(-value, 0));
/**
* alias for the adder
* @type {Tone.Add}
*/
this.input = this._adder;
/**
* alias for the thresh
* @type {Tone.Threshold}
*/
this.output = this._thresh;
//connect
this.chain(this._adder, this._gt, this._thresh);
//setup waveshaper
this._setGreaterThanZero();
};
Tone.extend(Tone.GreaterThan);
/**
* @private
*/
Tone.GreaterThan.prototype._setGreaterThanZero = function(){
var curveLength = 1024;
var curve = new Float32Array(curveLength);
for (var i = 0; i &lt; curveLength; i++){
var normalized = (i / (curveLength)) * 2 - 1;
if (normalized > 0){
curve[i] = 1;
} else {
curve[i] = 0;
}
}
this._gt.curve = curve;
};
/**
* set the value to compare to
*
* @param {number} value
*/
Tone.GreaterThan.prototype.setValue = function(value){
this._adder.setValue(-value);
};
/**
* dispose method
*/
Tone.GreaterThan.prototype.dispose = function(){
this._gt.disconnect();
this._adder.disconnect();
this._thresh.dispose();
this._gt = null;
this._adder = null;
this._thresh = null;
};
return Tone.GreaterThan;
});
define('Tone/signal/LessThan',["Tone/core/Tone", "Tone/signal/GreaterThan"], function(Tone){
/**
* Output 1 if the signal is less than the value, otherwise outputs 0
*
* @constructor
* @extends {Tone}
* @param {number} value the value to compare the incoming signal to
*/
Tone.LessThan = function(value){
/**
*
* @type {Tone.GreaterThan}
* @private
*/
this._gt = new Tone.GreaterThan(-value);
/**
* @type {Tone.GreaterThan}
*/
this.input = this.output = this._gt;
};
Tone.extend(Tone.LessThan);
/**
* @param {number} value
*/
Tone.LessThan.prototype.setValue = function(value){
this._gt.setValue(-value);
};
/**
* dispose method
*/
Tone.LessThan.prototype.dispose = function(){
this._gt.dispose();
this._gt = null;
};
return Tone.GreaterThan;
});
///////////////////////////////////////////////////////////////////////////////
//
// WEB RTC MICROPHONE
//
///////////////////////////////////////////////////////////////////////////////
define('Tone/source/Microphone',["Tone/core/Tone", "Tone/source/Source"], function(Tone){
/**
* WebRTC Microphone
*
* CHROME ONLY (for now) because of the
* use of the MediaStreamAudioSourceNode
*
* @constructor
* @extends {Tone.Source}
* @param {number=} inputNum
*/
Tone.Microphone = function(inputNum){
Tone.Source.call(this);
/**
* @type {MediaStreamAudioSourceNode}
* @private
*/
this._mediaStream = null;
/**
* @type {LocalMediaStream}
* @private
*/
this._stream = null;
/**
* @type {Object}
* @private
*/
this.constraints = {"audio" : {
echoCancellation : false
}};
//get the option
var self = this;
MediaStreamTrack.getSources(function (media_sources) {
if (inputNum &lt; media_sources.length){
self.constraints.audio = {
optional : [{ sourceId: media_sources[inputNum].id}]
};
}
});
};
Tone.extend(Tone.Microphone, Tone.Source);
/**
* start the stream.
*/
Tone.Microphone.prototype.start = function(){
if (this.state === Tone.Source.State.STOPPED){
this.state = Tone.Source.State.STARTED;
navigator.getUserMedia(this.constraints,
this._onStream.bind(this), this._onStreamError.bind(this));
}
};
/**
* stop the stream.
*/
Tone.Microphone.prototype.stop = function(){
if (this._stream && this.state === Tone.Source.State.STARTED){
this.state = Tone.Source.State.STOPPED;
this._stream.stop();
}
};
/**
* called when the stream is successfully setup
* @param {LocalMediaStream} stream
* @private
*/
Tone.Microphone.prototype._onStream = function(stream) {
this._stream = stream;
// Wrap a MediaStreamSourceNode around the live input stream.
this._mediaStream = this.context.createMediaStreamSource(stream);
this._mediaStream.connect(this.output);
};
/**
* called on error
* @param {Error} e
* @private
*/
Tone.Microphone.prototype._onStreamError = function(e) {
console.error(e);
};
/**
* clean up
*/
Tone.Microphone.prototype.dispose = function(e) {
this.input.disconnect();
this.output.disconnect();
this._stream.disconnect();
this._mediaStream.disconnect();
this.input = null;
this.output = null;
this._stream = null;
this._mediaStream = null;
};
//polyfill
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
return Tone.Microphone;
});
define('Tone/source/Noise',["Tone/core/Tone", "Tone/source/Source"], function(Tone){
var sampleRate = Tone.context.sampleRate;
//two seconds per buffer
var bufferLength = sampleRate * 4;
/**
* Noise generator.
*
* uses looped noise buffers to save on performance.
*
* @constructor
* @extends {Tone.Source}
* @param {string} type the noise type (white|pink|brown)
*/
Tone.Noise = function(type){
Tone.Source.call(this);
/**
* @private
* @type {AudioBufferSourceNode}
*/
this._source = null;
/**
* the buffer
* @private
* @type {AudioBuffer}
*/
this._buffer = null;
/**
* set a callback function to invoke when the sample is over
*
* @type {function}
*/
this.onended = function(){};
this.setType(this.defaultArg(type, "white"));
};
Tone.extend(Tone.Noise, Tone.Source);
/**
* set the noise type
*
* @param {string} type the noise type (white|pink|brown)
* @param {Tone.Time} time (optional) time that the set will occur
*/
Tone.Noise.prototype.setType = function(type, time){
switch (type){
case "white" :
this._buffer = _whiteNoise;
break;
case "pink" :
this._buffer = _pinkNoise;
break;
case "brown" :
this._buffer = _brownNoise;
break;
default :
this._buffer = _whiteNoise;
}
//if it's playing, stop and restart it
if (this.state === Tone.Source.State.STARTED){
time = this.toSeconds(time);
//remove the listener
this._source.onended = undefined;
this._stop(time);
this._start(time);
}
};
/**
* internal start method
*
* @param {Tone.Time} time
* @private
*/
Tone.Noise.prototype._start = function(time){
this._source = this.context.createBufferSource();
this._source.buffer = this._buffer;
this._source.loop = true;
this._source.start(this.toSeconds(time));
this.chain(this._source, this.output);
this._source.onended = this._onended.bind(this);
};
/**
* start the noise at a specific time
*
* @param {Tone.Time} time
*/
Tone.Noise.prototype.start = function(time){
if (this.state === Tone.Source.State.STOPPED){
this.state = Tone.Source.State.STARTED;
//make the source
this._start(time);
}
};
/**
* internal stop method
*
* @param {Tone.Time} time
* @private
*/
Tone.Noise.prototype._stop = function(time){
this._source.stop(this.toSeconds(time));
};
/**
* stop the noise at a specific time
*
* @param {Tone.Time} time
*/
Tone.Noise.prototype.stop = function(time){
if (this.state === Tone.Source.State.STARTED) {
if (this._buffer && this._source){
if (!time){
this.state = Tone.Source.State.STOPPED;
}
this._stop(time);
}
}
};
/**
* internal call when the buffer is done playing
*
* @private
*/
Tone.Noise.prototype._onended = function(){
this.state = Tone.Source.State.STOPPED;
this.onended();
};
/**
* dispose all the components
*/
Tone.Noise.prototype.dispose = function(){
if (this._source !== null){
this._source.disconnect();
this._source = null;
}
this._buffer = null;
this.output.disconnect();
this.output = null;
};
///////////////////////////////////////////////////////////////////////////
// THE BUFFERS
// borred heavily from http://noisehack.com/generate-noise-web-audio-api/
///////////////////////////////////////////////////////////////////////////
/**
* static brown noise buffer
*
* @static
* @private
* @type {AudioBuffer}
*/
var _pinkNoise = (function() {
var buffer = Tone.context.createBuffer(2, bufferLength, sampleRate);
for (var channelNum = 0; channelNum &lt; buffer.numberOfChannels; channelNum++){
var channel = buffer.getChannelData(channelNum);
var b0, b1, b2, b3, b4, b5, b6;
b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0;
for (var i = 0; i &lt; bufferLength; i++) {
var white = Math.random() * 2 - 1;
b0 = 0.99886 * b0 + white * 0.0555179;
b1 = 0.99332 * b1 + white * 0.0750759;
b2 = 0.96900 * b2 + white * 0.1538520;
b3 = 0.86650 * b3 + white * 0.3104856;
b4 = 0.55000 * b4 + white * 0.5329522;
b5 = -0.7616 * b5 - white * 0.0168980;
channel[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
channel[i] *= 0.11; // (roughly) compensate for gain
b6 = white * 0.115926;
}
}
return buffer;
}());
/**
* static brown noise buffer
*
* @static
* @private
* @type {AudioBuffer}
*/
var _brownNoise = (function() {
var buffer = Tone.context.createBuffer(2, bufferLength, sampleRate);
for (var channelNum = 0; channelNum &lt; buffer.numberOfChannels; channelNum++){
var channel = buffer.getChannelData(channelNum);
var lastOut = 0.0;
for (var i = 0; i &lt; bufferLength; i++) {
var white = Math.random() * 2 - 1;
channel[i] = (lastOut + (0.02 * white)) / 1.02;
lastOut = channel[i];
channel[i] *= 3.5; // (roughly) compensate for gain
}
}
return buffer;
})();
/**
* static white noise buffer
*
* @static
* @private
* @type {AudioBuffer}
*/
var _whiteNoise = (function(){
var buffer = Tone.context.createBuffer(2, bufferLength, sampleRate);
for (var channelNum = 0; channelNum &lt; buffer.numberOfChannels; channelNum++){
var channel = buffer.getChannelData(channelNum);
for (var i = 0; i &lt; bufferLength; i++){
channel[i] = Math.random() * 2 - 1;
}
}
return buffer;
}());
return Tone.Noise;
});
define('Tone/source/Player',["Tone/core/Tone", "Tone/source/Source"], function(Tone){
/**
* Audio Player
*
* Audio file player with start, loop, stop.
*
* @constructor
* @extends {Tone.Source}
* @param {string=} url if a url is passed in, it will be loaded
* and invoke the callback if it also passed
* in.
* @param {function(Tone.Player)=} onload callback to be invoked
* once the url is loaded
*/
Tone.Player = function(url, onload){
Tone.Source.call(this);
/**
* @private
* @type {AudioBufferSourceNode}
*/
this._source = null;
/**
* the buffer
* @private
* @type {AudioBuffer}
*/
this._buffer = null;
/**
* the duration of the buffer once it's been loaded
* @type {number}
*/
this.duration = 0;
/**
* if the buffer should loop once it's over
* @type {boolean}
*/
this.loop = false;
/**
* if 'loop' is true, the loop will start at this position
*
* @type {number}
*/
this.loopStart = 0;
/**
* if 'loop' is true, the loop will end at this position
*
* @type {number}
*/
this.loopEnd = 0;
/**
* the playback rate
* @private
* @type {number}
*/
this._playbackRate = 1;
/**
* enabling retrigger will allow a player to be restarted
* before the the previous 'start' is done playing
*
* @type {boolean}
*/
this.retrigger = false;
/**
* set a callback function to invoke when the sample is over
*
* @type {function}
*/
this.onended = function(){};
//if there is a url, load it.
if (url){
this.load(url, onload);
}
};
Tone.extend(Tone.Player, Tone.Source);
/**
* makes an xhr reqest for the selected url
* Load the audio file as an audio buffer.
* Decodes the audio asynchronously and invokes
* the callback once the audio buffer loads.
*
* @param {string} url the url of the buffer to load.
* filetype support depends on the
* browser.
* @param {function(Tone.Player)=} callback
*/
Tone.Player.prototype.load = function(url, callback){
if (!this._buffer){
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "arraybuffer";
// decode asynchronously
var self = this;
request.onload = function() {
self.context.decodeAudioData(request.response, function(buff) {
self.setBuffer(buff);
if (callback){
callback(self);
}
});
};
//send the request
request.send();
} else {
if (callback){
callback(this);
}
}
};
/**
* set the buffer
*
* @param {AudioBuffer} buffer the buffer which the player will play.
* note: if you switch the buffer after
* the player is already started, it will not
* take effect until the next time the player
* is started.
*/
Tone.Player.prototype.setBuffer = function(buffer){
this._buffer = buffer;
this.duration = buffer.duration;
};
/**
* play the buffer between the desired positions
*
* @param {Tone.Time=} startTime
* @param {Tone.Time=} offset
* @param {Tone.Time=} duration
*/
Tone.Player.prototype.start = function(startTime, offset, duration){
if (this.state === Tone.Source.State.STOPPED || this.retrigger){
if (this._buffer){
this.state = Tone.Source.State.STARTED;
//default args
offset = this.defaultArg(offset, 0);
duration = this.defaultArg(duration, this._buffer.duration - offset);
//make the source
this._source = this.context.createBufferSource();
this._source.buffer = this._buffer;
//set the looping properties
this._source.loop = this.loop;
this._source.loopStart = this.loopStart;
this._source.loopEnd = this.loopEnd;
//and other properties
this._source.playbackRate.value = this._playbackRate;
this._source.onended = this._onended.bind(this);
this.chain(this._source, this.output);
//start it
this._source.start(this.toSeconds(startTime), this.toSeconds(offset), this.toSeconds(duration));
}
}
};
/**
* Stop playback.
*
* @param {Tone.Time} time
*/
Tone.Player.prototype.stop = function(time){
if (this.state === Tone.Source.State.STARTED) {
if (this._buffer && this._source){
if (!time){
this.state = Tone.Source.State.STOPPED;
}
this._source.stop(this.toSeconds(time));
}
}
};
/**
* set the rate at which the file plays
*
* @param {number} rate
* @param {Tone.Time=} rampTime (optional) the amount of time it takes to
* reach the rate
*/
Tone.Player.prototype.setPlaybackRate = function(rate, rampTime){
this._playbackRate = rate;
if (this._source) {
if (rampTime){
this._source.playbackRate.exponentialRampToValueAtTime(rate, this.toSeconds(rampTime));
} else {
this._source.playbackRate.value = rampTime;
}
}
};
/**
* internal call when the buffer is done playing
*
* @private
*/
Tone.Player.prototype._onended = function(){
this.state = Tone.Source.State.STOPPED;
this.onended();
};
/**
* dispose and disconnect
*/
Tone.Player.prototype.dispose = function(){
if (this._source !== null){
this._source.disconnect();
this._source = null;
}
this._buffer = null;
this.output.disconnect();
this.output = null;
};
return Tone.Player;
});
</pre>
</article>
</section>
</div>
<div class="clearfix"></div>
<footer>
<span class="copyright">
Tone No Tone Copyright © 2014.
</span>
<br />
<span class="jsdoc-message">
Documentation generated on Thu Jul 03 2014 23:49:50 GMT-0400 (EDT).
</span>
</footer>
</div>
<br clear="both">
</div>
</div>
<script src="scripts/sunlight.js"></script>
<script src="scripts/sunlight.javascript.js"></script>
<script src="scripts/sunlight-plugin.doclinks.js"></script>
<script src="scripts/sunlight-plugin.linenumbers.js"></script>
<script src="scripts/sunlight-plugin.menu.js"></script>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/jquery.scrollTo.js"></script>
<script src="scripts/jquery.localScroll.js"></script>
<script src="scripts/bootstrap-dropdown.js"></script>
<script src="scripts/toc.js"></script>
<script> Sunlight.highlightAll({lineNumbers:true, showMenu: true, enableDoclinks :true}); </script>
<script>
$( function () {
$( "#toc" ).toc( {
selectors : "h1,h2,h3,h4",
showAndHide : false,
scrollTo : 60
} );
$( "#toc>ul" ).addClass( "nav nav-pills nav-stacked" );
$( "#main span[id^='toc']" ).addClass( "toc-shim" );
} );
</script>
<script>
$( function () {
$('#main').localScroll({
offset: { top: 56 } //offset by the height of your header (give or take a few px, see what works for you)
});
$( "dt h4.name" ).each( function () {
var $this = $( this );
var icon = $( "<i/>" ).addClass( "icon-plus-sign" ).addClass( "pull-right" ).addClass( "icon-white" );
var dt = $this.parents( "dt" );
var children = dt.next( "dd" );
$this.append( icon ).css( {cursor : "pointer"} );
$this.addClass( "member-collapsed" ).addClass( "member" );
children.hide();
$this.toggle( function () {
icon.addClass( "icon-minus-sign" ).removeClass( "icon-plus-sign" ).removeClass( "icon-white" );
$this.addClass( "member-open" ).removeClass( "member-collapsed" );
children.slideDown();
}, function () {
icon.addClass( "icon-plus-sign" ).removeClass( "icon-minus-sign" ).addClass( "icon-white" );
$this.addClass( "member-collapsed" ).removeClass( "member-open" );
children.slideUp();
} );
} );
} );
</script>
</body>
</html>