2014-09-12 04:55:10 +00:00
|
|
|
define(["Tone/core/Tone", "Tone/signal/Multiply"], function(Tone){
|
2014-09-08 15:49:21 +00:00
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
/**
|
2014-09-11 17:38:41 +00:00
|
|
|
* @class Signal-rate modulo operator. Specify the modulus and the
|
2014-09-08 15:49:21 +00:00
|
|
|
* number of bits of the incoming signal. Because the operator is composed of many components,
|
|
|
|
* fewer bits will improve performance.
|
|
|
|
*
|
|
|
|
* @constructor
|
|
|
|
* @extends {Tone}
|
2014-10-23 01:52:42 +00:00
|
|
|
* @param {number} modulus the modulus to apply
|
2014-09-14 19:33:02 +00:00
|
|
|
* @param {number} [bits=8] optionally set the maximum bits the incoming signal can have.
|
|
|
|
* defaults to 8 meaning that incoming values must be in the range
|
2014-10-23 01:52:42 +00:00
|
|
|
* [-255,255].
|
2014-09-08 15:49:21 +00:00
|
|
|
*/
|
|
|
|
Tone.Modulo = function(modulus, bits){
|
|
|
|
|
|
|
|
Tone.call(this);
|
|
|
|
|
2014-09-12 04:55:10 +00:00
|
|
|
bits = this.defaultArg(bits, 8);
|
2014-09-08 15:49:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* the array of Modulus Subroutine objects
|
|
|
|
* @type {Array.<ModulusSubroutine>}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this._modChain = [];
|
|
|
|
|
|
|
|
//create all of the subroutines
|
|
|
|
for (var i = bits - 1; i >= 0; i--){
|
|
|
|
var mod = new ModuloSubroutine(modulus, Math.pow(2, i));
|
|
|
|
this._modChain.push(mod);
|
|
|
|
}
|
|
|
|
this.chain.apply(this, this._modChain);
|
2014-09-12 04:55:10 +00:00
|
|
|
this.input.connect(this._modChain[0]);
|
|
|
|
this._modChain[this._modChain.length - 1].connect(this.output);
|
2014-09-08 15:49:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Tone.extend(Tone.Modulo);
|
|
|
|
|
|
|
|
Tone.Modulo.prototype.dispose = function(){
|
|
|
|
Tone.prototype.dispose.call(this);
|
|
|
|
for (var i = 0; i < this._modChain.length; i++) {
|
|
|
|
this._modChain[i].dispose();
|
|
|
|
this._modChain[i] = null;
|
|
|
|
}
|
|
|
|
this._modChain = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @class applies a modolus at a single bit depth.
|
|
|
|
* uses this operation: http://stackoverflow.com/a/14842954
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @internal helper class for modulo
|
|
|
|
* @constructor
|
|
|
|
* @extends {Tone}
|
|
|
|
*/
|
|
|
|
var ModuloSubroutine = function(modulus, multiple){
|
|
|
|
|
|
|
|
var val = modulus * multiple;
|
|
|
|
|
2014-09-12 05:03:48 +00:00
|
|
|
/**
|
|
|
|
* the input node
|
|
|
|
*/
|
|
|
|
this.input = this.context.createGain();
|
|
|
|
|
2014-09-08 15:49:21 +00:00
|
|
|
/**
|
2014-09-12 04:55:10 +00:00
|
|
|
* divide the incoming signal so it's on a 0 to 1 scale
|
|
|
|
* @type {Tone.Multiply}
|
2014-09-08 15:49:21 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2014-09-12 04:55:10 +00:00
|
|
|
this._div = new Tone.Multiply(1 / val);
|
2014-09-08 15:49:21 +00:00
|
|
|
|
2014-11-04 00:22:17 +00:00
|
|
|
/**
|
|
|
|
* the curve that the waveshaper uses
|
|
|
|
* @type {Float32Array}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this._curve = new Float32Array(1024);
|
|
|
|
|
2014-09-08 15:49:21 +00:00
|
|
|
/**
|
2014-09-12 04:55:10 +00:00
|
|
|
* apply the equation logic
|
|
|
|
* @type {WaveShaperNode}
|
2014-09-08 15:49:21 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2014-09-12 04:55:10 +00:00
|
|
|
this._operator = this.context.createWaveShaper();
|
2014-09-08 15:49:21 +00:00
|
|
|
|
2014-09-12 04:55:10 +00:00
|
|
|
//connect it up
|
2014-09-12 05:03:48 +00:00
|
|
|
this.chain(this.input, this._div, this._operator);
|
2014-09-12 04:55:10 +00:00
|
|
|
this._makeCurve(val);
|
2014-09-08 15:49:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Tone.extend(ModuloSubroutine);
|
|
|
|
|
2014-09-12 04:55:10 +00:00
|
|
|
/**
|
|
|
|
* make the operator curve
|
|
|
|
* @param {number} val
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
ModuloSubroutine.prototype._makeCurve = function(val){
|
2014-11-04 00:22:17 +00:00
|
|
|
var arrayLength = this._curve.length;
|
|
|
|
for (var i = 0; i < arrayLength; i++) {
|
2014-09-12 04:55:10 +00:00
|
|
|
if (i === arrayLength - 1){
|
2014-11-04 00:22:17 +00:00
|
|
|
this._curve[i] = -val;
|
2014-09-12 04:55:10 +00:00
|
|
|
} else if (i === 0){
|
2014-11-04 00:22:17 +00:00
|
|
|
this._curve[i] = val;
|
2014-09-12 04:55:10 +00:00
|
|
|
} else {
|
2014-11-04 00:22:17 +00:00
|
|
|
this._curve[i] = 0;
|
2014-09-12 04:55:10 +00:00
|
|
|
}
|
|
|
|
}
|
2014-11-04 00:22:17 +00:00
|
|
|
this._operator.curve = this._curve;
|
2014-09-12 04:55:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @override the default connection to connect the operator and the input to the next node
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
ModuloSubroutine.prototype.connect = function(node){
|
|
|
|
this._operator.connect(node);
|
|
|
|
this.input.connect(node);
|
|
|
|
};
|
|
|
|
|
2014-09-08 15:49:21 +00:00
|
|
|
/**
|
|
|
|
* internal class clean up
|
|
|
|
*/
|
|
|
|
ModuloSubroutine.prototype.dispose = function(){
|
2014-09-12 04:55:10 +00:00
|
|
|
Tone.prototype.dispose.call(this);
|
|
|
|
this._div.dispose();
|
|
|
|
this._div = null;
|
2014-11-04 00:22:17 +00:00
|
|
|
this._operator.disconnect();
|
2014-09-12 04:55:10 +00:00
|
|
|
this._operator = null;
|
2014-11-04 00:22:17 +00:00
|
|
|
this._curve = null;
|
2014-09-08 15:49:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return Tone.Modulo;
|
|
|
|
});
|