diff --git a/app/js/lib/Tone.js b/app/js/lib/Tone.js
index 929af3b..a28a974 100644
--- a/app/js/lib/Tone.js
+++ b/app/js/lib/Tone.js
@@ -1,23722 +1,8 @@
-(function(root, factory){
-
- //UMD
- if ( typeof define === "function" && define.amd ) {
- define(function() {
- return factory();
- });
- } else if (typeof module === "object") {
- module.exports = factory();
- } else {
- root.Tone = factory();
- }
-
-}(this, function(){
-
- "use strict";
-
- var Tone;
- //constructs the main Tone object
- function Main(func){
- Tone = func();
- }
- //invokes each of the modules with the main Tone object as the argument
- function Module(func){
- func(Tone);
- } /**
+!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Tone=e():t.Tone=e()}("undefined"!=typeof self?self:this,function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=155)}([function(t,e,i){(function(n){var o,s;
+ /**
* Tone.js
* @author Yotam Mann
* @license http://opensource.org/licenses/MIT MIT License
- * @copyright 2014-2017 Yotam Mann
- */
- Main(function () {
-
- ///////////////////////////////////////////////////////////////////////////
- // TONE
- ///////////////////////////////////////////////////////////////////////////
- /**
- * @class Tone is the base class of all other classes.
- * @constructor
- */
- var Tone = function () {
- };
- /**
- * @memberOf Tone#
- * @returns {string} returns the name of the class as a string
- */
- Tone.prototype.toString = function () {
- for (var className in Tone) {
- var isLetter = className[0].match(/^[A-Z]$/);
- var sameConstructor = Tone[className] === this.constructor;
- if (Tone.isFunction(Tone[className]) && isLetter && sameConstructor) {
- return className;
- }
- }
- return 'Tone';
- };
- /**
- * @memberOf Tone#
- * disconnect and dispose
- * @returns {Tone} this
- */
- Tone.prototype.dispose = function () {
- return this;
- };
- ///////////////////////////////////////////////////////////////////////////
- // GET/SET
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Set the parameters at once. Either pass in an
- * object mapping parameters to values, or to set a
- * single parameter, by passing in a string and value.
- * The last argument is an optional ramp time which
- * will ramp any signal values to their destination value
- * over the duration of the rampTime.
- * @param {Object|string} params
- * @param {number=} value
- * @param {Time=} rampTime
- * @returns {Tone} this
- * @memberOf Tone#
- * @example
- * //set values using an object
- * filter.set({
- * "frequency" : 300,
- * "type" : highpass
- * });
- * @example
- * filter.set("type", "highpass");
- * @example
- * //ramp to the value 220 over 3 seconds.
- * oscillator.set({
- * "frequency" : 220
- * }, 3);
- */
- Tone.prototype.set = function (params, value, rampTime) {
- if (Tone.isObject(params)) {
- rampTime = value;
- } else if (Tone.isString(params)) {
- var tmpObj = {};
- tmpObj[params] = value;
- params = tmpObj;
- }
- paramLoop:
- for (var attr in params) {
- value = params[attr];
- var parent = this;
- if (attr.indexOf('.') !== -1) {
- var attrSplit = attr.split('.');
- for (var i = 0; i < attrSplit.length - 1; i++) {
- parent = parent[attrSplit[i]];
- if (parent instanceof Tone) {
- attrSplit.splice(0, i + 1);
- var innerParam = attrSplit.join('.');
- parent.set(innerParam, value);
- continue paramLoop;
- }
- }
- attr = attrSplit[attrSplit.length - 1];
- }
- var param = parent[attr];
- if (Tone.isUndef(param)) {
- continue;
- }
- if (Tone.Signal && param instanceof Tone.Signal || Tone.Param && param instanceof Tone.Param) {
- if (param.value !== value) {
- if (Tone.isUndef(rampTime)) {
- param.value = value;
- } else {
- param.rampTo(value, rampTime);
- }
- }
- } else if (param instanceof AudioParam) {
- if (param.value !== value) {
- param.value = value;
- }
- } else if (param instanceof Tone) {
- param.set(value);
- } else if (param !== value) {
- parent[attr] = value;
- }
- }
- return this;
- };
- /**
- * Get the object's attributes. Given no arguments get
- * will return all available object properties and their corresponding
- * values. Pass in a single attribute to retrieve or an array
- * of attributes. The attribute strings can also include a "."
- * to access deeper properties.
- * @memberOf Tone#
- * @example
- * osc.get();
- * //returns {"type" : "sine", "frequency" : 440, ...etc}
- * @example
- * osc.get("type");
- * //returns { "type" : "sine"}
- * @example
- * //use dot notation to access deep properties
- * synth.get(["envelope.attack", "envelope.release"]);
- * //returns {"envelope" : {"attack" : 0.2, "release" : 0.4}}
- * @param {Array=|string|undefined} params the parameters to get, otherwise will return
- * all available.
- * @returns {Object}
- */
- Tone.prototype.get = function (params) {
- if (Tone.isUndef(params)) {
- params = this._collectDefaults(this.constructor);
- } else if (Tone.isString(params)) {
- params = [params];
- }
- var ret = {};
- for (var i = 0; i < params.length; i++) {
- var attr = params[i];
- var parent = this;
- var subRet = ret;
- if (attr.indexOf('.') !== -1) {
- var attrSplit = attr.split('.');
- for (var j = 0; j < attrSplit.length - 1; j++) {
- var subAttr = attrSplit[j];
- subRet[subAttr] = subRet[subAttr] || {};
- subRet = subRet[subAttr];
- parent = parent[subAttr];
- }
- attr = attrSplit[attrSplit.length - 1];
- }
- var param = parent[attr];
- if (Tone.isObject(params[attr])) {
- subRet[attr] = param.get();
- } else if (Tone.Signal && param instanceof Tone.Signal) {
- subRet[attr] = param.value;
- } else if (Tone.Param && param instanceof Tone.Param) {
- subRet[attr] = param.value;
- } else if (param instanceof AudioParam) {
- subRet[attr] = param.value;
- } else if (param instanceof Tone) {
- subRet[attr] = param.get();
- } else if (!Tone.isFunction(param) && !Tone.isUndef(param)) {
- subRet[attr] = param;
- }
- }
- return ret;
- };
- /**
- * collect all of the default attributes in one
- * @private
- * @param {function} constr the constructor to find the defaults from
- * @return {Array} all of the attributes which belong to the class
- */
- Tone.prototype._collectDefaults = function (constr) {
- var ret = [];
- if (!Tone.isUndef(constr.defaults)) {
- ret = Object.keys(constr.defaults);
- }
- if (!Tone.isUndef(constr._super)) {
- var superDefs = this._collectDefaults(constr._super);
- //filter out repeats
- for (var i = 0; i < superDefs.length; i++) {
- if (ret.indexOf(superDefs[i]) === -1) {
- ret.push(superDefs[i]);
- }
- }
- }
- return ret;
- };
- ///////////////////////////////////////////////////////////////////////////
- // DEFAULTS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * @memberOf Tone
- * @param {Array} values The arguments array
- * @param {Array} keys The names of the arguments
- * @param {Function|Object} constr The class constructor
- * @return {Object} An object composed of the defaults between the class' defaults
- * and the passed in arguments.
- */
- Tone.defaults = function (values, keys, constr) {
- var options = {};
- if (values.length === 1 && Tone.isObject(values[0])) {
- options = values[0];
- } else {
- for (var i = 0; i < keys.length; i++) {
- options[keys[i]] = values[i];
- }
- }
- if (!Tone.isUndef(constr.defaults)) {
- return Tone.defaultArg(options, constr.defaults);
- } else if (Tone.isObject(constr)) {
- return Tone.defaultArg(options, constr);
- } else {
- return options;
- }
- };
- /**
- * If the `given` parameter is undefined, use the `fallback`.
- * If both `given` and `fallback` are object literals, it will
- * return a deep copy which includes all of the parameters from both
- * objects. If a parameter is undefined in given, it will return
- * the fallback property.
- *
- * WARNING: if object is self referential, it will go into an an
- * infinite recursive loop.
- * @memberOf Tone
- * @param {*} given
- * @param {*} fallback
- * @return {*}
- */
- Tone.defaultArg = function (given, fallback) {
- if (Tone.isObject(given) && Tone.isObject(fallback)) {
- var ret = {};
- //make a deep copy of the given object
- for (var givenProp in given) {
- ret[givenProp] = Tone.defaultArg(fallback[givenProp], given[givenProp]);
- }
- for (var fallbackProp in fallback) {
- ret[fallbackProp] = Tone.defaultArg(given[fallbackProp], fallback[fallbackProp]);
- }
- return ret;
- } else {
- return Tone.isUndef(given) ? fallback : given;
- }
- };
- ///////////////////////////////////////////////////////////////////////////
- // CONNECTIONS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * connect together all of the arguments in series
- * @param {...AudioParam|Tone|AudioNode} nodes
- * @returns {Tone}
- * @memberOf Tone
- * @static
- */
- Tone.connectSeries = function () {
- var currentUnit = arguments[0];
- for (var i = 1; i < arguments.length; i++) {
- var toUnit = arguments[i];
- currentUnit.connect(toUnit);
- currentUnit = toUnit;
- }
- return Tone;
- };
- ///////////////////////////////////////////////////////////////////////////
- // TYPE CHECKING
- ///////////////////////////////////////////////////////////////////////////
- /**
- * test if the arg is undefined
- * @param {*} arg the argument to test
- * @returns {boolean} true if the arg is undefined
- * @static
- * @memberOf Tone
- */
- Tone.isUndef = function (val) {
- return typeof val === 'undefined';
- };
- /**
- * test if the arg is a function
- * @param {*} arg the argument to test
- * @returns {boolean} true if the arg is a function
- * @static
- * @memberOf Tone
- */
- Tone.isFunction = function (val) {
- return typeof val === 'function';
- };
- /**
- * Test if the argument is a number.
- * @param {*} arg the argument to test
- * @returns {boolean} true if the arg is a number
- * @static
- * @memberOf Tone
- */
- Tone.isNumber = function (arg) {
- return typeof arg === 'number';
- };
- /**
- * Test if the given argument is an object literal (i.e. `{}`);
- * @param {*} arg the argument to test
- * @returns {boolean} true if the arg is an object literal.
- * @static
- * @memberOf Tone
- */
- Tone.isObject = function (arg) {
- return Object.prototype.toString.call(arg) === '[object Object]' && arg.constructor === Object;
- };
- /**
- * Test if the argument is a boolean.
- * @param {*} arg the argument to test
- * @returns {boolean} true if the arg is a boolean
- * @static
- * @memberOf Tone
- */
- Tone.isBoolean = function (arg) {
- return typeof arg === 'boolean';
- };
- /**
- * Test if the argument is an Array
- * @param {*} arg the argument to test
- * @returns {boolean} true if the arg is an array
- * @static
- * @memberOf Tone
- */
- Tone.isArray = function (arg) {
- return Array.isArray(arg);
- };
- /**
- * Test if the argument is a string.
- * @param {*} arg the argument to test
- * @returns {boolean} true if the arg is a string
- * @static
- * @memberOf Tone
- */
- Tone.isString = function (arg) {
- return typeof arg === 'string';
- };
- /**
- * Test if the argument is in the form of a note in scientific pitch notation.
- * e.g. "C4"
- * @param {*} arg the argument to test
- * @returns {boolean} true if the arg is a string
- * @static
- * @memberOf Tone
- */
- Tone.isNote = function (arg) {
- return Tone.isString(arg) && /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i.test(arg);
- };
- /**
- * An empty function.
- * @static
- */
- Tone.noOp = function () {
- };
- /**
- * Make the property not writable. Internal use only.
- * @private
- * @param {string} property the property to make not writable
- */
- Tone.prototype._readOnly = function (property) {
- if (Array.isArray(property)) {
- for (var i = 0; i < property.length; i++) {
- this._readOnly(property[i]);
- }
- } else {
- Object.defineProperty(this, property, {
- writable: false,
- enumerable: true
- });
- }
- };
- /**
- * Make an attribute writeable. Interal use only.
- * @private
- * @param {string} property the property to make writable
- */
- Tone.prototype._writable = function (property) {
- if (Array.isArray(property)) {
- for (var i = 0; i < property.length; i++) {
- this._writable(property[i]);
- }
- } else {
- Object.defineProperty(this, property, { writable: true });
- }
- };
- /**
- * Possible play states.
- * @enum {string}
- */
- Tone.State = {
- Started: 'started',
- Stopped: 'stopped',
- Paused: 'paused'
- };
- ///////////////////////////////////////////////////////////////////////////
- // CONVERSIONS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Equal power gain scale. Good for cross-fading.
- * @param {NormalRange} percent (0-1)
- * @return {Number} output gain (0-1)
- * @static
- * @memberOf Tone
- */
- Tone.equalPowerScale = function (percent) {
- var piFactor = 0.5 * Math.PI;
- return Math.sin(percent * piFactor);
- };
- /**
- * Convert decibels into gain.
- * @param {Decibels} db
- * @return {Number}
- * @static
- * @memberOf Tone
- */
- Tone.dbToGain = function (db) {
- return Math.pow(2, db / 6);
- };
- /**
- * Convert gain to decibels.
- * @param {Number} gain (0-1)
- * @return {Decibels}
- * @static
- * @memberOf Tone
- */
- Tone.gainToDb = function (gain) {
- return 20 * (Math.log(gain) / Math.LN10);
- };
- /**
- * Convert an interval (in semitones) to a frequency ratio.
- * @param {Interval} interval the number of semitones above the base note
- * @return {number} the frequency ratio
- * @static
- * @memberOf Tone
- * @example
- * tone.intervalToFrequencyRatio(0); // 1
- * tone.intervalToFrequencyRatio(12); // 2
- * tone.intervalToFrequencyRatio(-12); // 0.5
- */
- Tone.intervalToFrequencyRatio = function (interval) {
- return Math.pow(2, interval / 12);
- };
- ///////////////////////////////////////////////////////////////////////////
- // TIMING
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Return the current time of the AudioContext clock.
- * @return {Number} the currentTime from the AudioContext
- * @memberOf Tone#
- */
- Tone.prototype.now = function () {
- return Tone.context.now();
- };
- /**
- * Return the current time of the AudioContext clock.
- * @return {Number} the currentTime from the AudioContext
- * @static
- * @memberOf Tone
- */
- Tone.now = function () {
- return Tone.context.now();
- };
- /**
- * Adds warning in the console if the scheduled time has passed.
- * @type {Time}
- */
- Tone.isPast = function (time) {
- if (time < Tone.context.currentTime) {
- console.warn('Time \'' + time + '\' is in the past. Scheduled time must be \u2265 AudioContext.currentTime');
- }
- };
- ///////////////////////////////////////////////////////////////////////////
- // INHERITANCE
- ///////////////////////////////////////////////////////////////////////////
- /**
- * 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
- *
- * @memberOf Tone
- * @static
- * @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 (Tone.isUndef(parent)) {
- parent = Tone;
- }
- function TempConstructor() {
- }
- TempConstructor.prototype = parent.prototype;
- child.prototype = new TempConstructor();
- /** @override */
- child.prototype.constructor = child;
- child._super = parent;
- };
- ///////////////////////////////////////////////////////////////////////////
- // CONTEXT
- ///////////////////////////////////////////////////////////////////////////
- /**
- * The private audio context shared by all Tone Nodes.
- * @private
- * @type {Tone.Context}
- */
- var audioContext = null;
- /**
- * A static pointer to the audio context accessible as Tone.context.
- * @type {Tone.Context}
- * @name context
- * @memberOf Tone
- */
- Object.defineProperty(Tone, 'context', {
- get: function () {
- return audioContext;
- },
- set: function (context) {
- if (Tone.Context && context instanceof Tone.Context) {
- audioContext = context;
- } else {
- audioContext = new Tone.Context(context);
- }
- //initialize the new audio context
- Tone.Context.emit('init', audioContext);
- }
- });
- /**
- * The AudioContext
- * @type {Tone.Context}
- * @name context
- * @memberOf Tone#
- * @readOnly
- */
- Object.defineProperty(Tone.prototype, 'context', {
- get: function () {
- return Tone.context;
- }
- });
- /**
- * Tone automatically creates a context on init, but if you are working
- * with other libraries which also create an AudioContext, it can be
- * useful to set your own. If you are going to set your own context,
- * be sure to do it at the start of your code, before creating any objects.
- * @static
- * @param {AudioContext} ctx The new audio context to set
- */
- Tone.setContext = function (ctx) {
- Tone.context = ctx;
- };
- ///////////////////////////////////////////////////////////////////////////
- // ATTRIBUTES
- ///////////////////////////////////////////////////////////////////////////
- /**
- * The number of seconds of 1 processing block (128 samples)
- * @type {Number}
- * @name blockTime
- * @memberOf Tone
- * @static
- * @readOnly
- */
- Object.defineProperty(Tone.prototype, 'blockTime', {
- get: function () {
- return 128 / this.context.sampleRate;
- }
- });
- /**
- * The duration in seconds of one sample.
- * @type {Number}
- * @name sampleTime
- * @memberOf Tone
- * @static
- * @readOnly
- */
- Object.defineProperty(Tone.prototype, 'sampleTime', {
- get: function () {
- return 1 / this.context.sampleRate;
- }
- });
- /**
- * Whether or not all the technologies that Tone.js relies on are supported by the current browser.
- * @type {Boolean}
- * @name supported
- * @memberOf Tone
- * @readOnly
- * @static
- */
- Object.defineProperty(Tone, 'supported', {
- get: function () {
- var hasAudioContext = window.hasOwnProperty('AudioContext') || window.hasOwnProperty('webkitAudioContext');
- var hasPromises = window.hasOwnProperty('Promise');
- var hasWorkers = window.hasOwnProperty('Worker');
- return hasAudioContext && hasPromises && hasWorkers;
- }
- });
- /**
- * Boolean value if the audio context has been initialized.
- * @type {Boolean}
- * @memberOf Tone
- * @static
- * @name initialized
- */
- Object.defineProperty(Tone, 'initialized', {
- get: function () {
- return audioContext !== null;
- }
- });
- /**
- * Get the context when it becomes available
- * @param {Function} resolve Callback when the context is initialized
- * @return {Tone}
- */
- Tone.getContext = function (resolve) {
- if (Tone.initialized) {
- resolve(Tone.context);
- } else {
- var resCallback = function () {
- resolve(Tone.context);
- Tone.Context.off('init', resCallback);
- };
- Tone.Context.on('init', resCallback);
- }
- return Tone;
- };
- /**
- * The version number
- * @type {String}
- * @static
- */
- Tone.version = 'r11';
- // allow optional silencing of this log
- if (!window.TONE_SILENCE_VERSION_LOGGING) {
- console.log('%c * Tone.js ' + Tone.version + ' * ', 'background: #000; color: #fff');
- }
- return Tone;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Emitter gives classes which extend it
- * the ability to listen for and emit events.
- * Inspiration and reference from Jerome Etienne's [MicroEvent](https://github.com/jeromeetienne/microevent.js).
- * MIT (c) 2011 Jerome Etienne.
- *
- * @extends {Tone}
- */
- Tone.Emitter = function () {
- Tone.call(this);
- /**
- * Contains all of the events.
- * @private
- * @type {Object}
- */
- this._events = {};
- };
- Tone.extend(Tone.Emitter);
- /**
- * Bind a callback to a specific event.
- * @param {String} event The name of the event to listen for.
- * @param {Function} callback The callback to invoke when the
- * event is emitted
- * @return {Tone.Emitter} this
- */
- Tone.Emitter.prototype.on = function (event, callback) {
- //split the event
- var events = event.split(/\W+/);
- for (var i = 0; i < events.length; i++) {
- var eventName = events[i];
- if (!this._events.hasOwnProperty(eventName)) {
- this._events[eventName] = [];
- }
- this._events[eventName].push(callback);
- }
- return this;
- };
- /**
- * Remove the event listener.
- * @param {String} event The event to stop listening to.
- * @param {Function=} callback The callback which was bound to
- * the event with Tone.Emitter.on.
- * If no callback is given, all callbacks
- * events are removed.
- * @return {Tone.Emitter} this
- */
- Tone.Emitter.prototype.off = function (event, callback) {
- var events = event.split(/\W+/);
- for (var ev = 0; ev < events.length; ev++) {
- event = events[ev];
- if (this._events.hasOwnProperty(event)) {
- if (Tone.isUndef(callback)) {
- this._events[event] = [];
- } else {
- var eventList = this._events[event];
- for (var i = 0; i < eventList.length; i++) {
- if (eventList[i] === callback) {
- eventList.splice(i, 1);
- }
- }
- }
- }
- }
- return this;
- };
- /**
- * Invoke all of the callbacks bound to the event
- * with any arguments passed in.
- * @param {String} event The name of the event.
- * @param {*} args... The arguments to pass to the functions listening.
- * @return {Tone.Emitter} this
- */
- Tone.Emitter.prototype.emit = function (event) {
- if (this._events) {
- var args = Array.apply(null, arguments).slice(1);
- if (this._events.hasOwnProperty(event)) {
- var eventList = this._events[event];
- for (var i = 0, len = eventList.length; i < len; i++) {
- eventList[i].apply(this, args);
- }
- }
- }
- return this;
- };
- /**
- * Add Emitter functions (on/off/emit) to the object
- * @param {Object|Function} object The object or class to extend.
- * @returns {Tone.Emitter}
- */
- Tone.Emitter.mixin = function (object) {
- var functions = [
- 'on',
- 'off',
- 'emit'
- ];
- object._events = {};
- for (var i = 0; i < functions.length; i++) {
- var func = functions[i];
- var emitterFunc = Tone.Emitter.prototype[func];
- object[func] = emitterFunc;
- }
- return Tone.Emitter;
- };
- /**
- * Clean up
- * @return {Tone.Emitter} this
- */
- Tone.Emitter.prototype.dispose = function () {
- Tone.prototype.dispose.call(this);
- this._events = null;
- return this;
- };
- return Tone.Emitter;
- });
- Module(function (Tone) {
-
- /**
- * @class A Timeline class for scheduling and maintaining state
- * along a timeline. All events must have a "time" property.
- * Internally, events are stored in time order for fast
- * retrieval.
- * @extends {Tone}
- * @param {Positive} [memory=Infinity] The number of previous events that are retained.
- */
- Tone.Timeline = function () {
- var options = Tone.defaults(arguments, ['memory'], Tone.Timeline);
- Tone.call(this);
- /**
- * The array of scheduled timeline events
- * @type {Array}
- * @private
- */
- this._timeline = [];
- /**
- * An array of items to remove from the list.
- * @type {Array}
- * @private
- */
- this._toRemove = [];
- /**
- * An array of items to add from the list (once it's done iterating)
- * @type {Array}
- * @private
- */
- this._toAdd = [];
- /**
- * Flag if the timeline is mid iteration
- * @private
- * @type {Boolean}
- */
- this._iterating = false;
- /**
- * The memory of the timeline, i.e.
- * how many events in the past it will retain
- * @type {Positive}
- */
- this.memory = options.memory;
- };
- Tone.extend(Tone.Timeline);
- /**
- * the default parameters
- * @static
- * @const
- */
- Tone.Timeline.defaults = { 'memory': Infinity };
- /**
- * The number of items in the timeline.
- * @type {Number}
- * @memberOf Tone.Timeline#
- * @name length
- * @readOnly
- */
- Object.defineProperty(Tone.Timeline.prototype, 'length', {
- get: function () {
- return this._timeline.length;
- }
- });
- /**
- * Insert an event object onto the timeline. Events must have a "time" attribute.
- * @param {Object} event The event object to insert into the
- * timeline.
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.add = function (event) {
- //the event needs to have a time attribute
- if (Tone.isUndef(event.time)) {
- throw new Error('Tone.Timeline: events must have a time attribute');
- }
- if (this._iterating) {
- this._toAdd.push(event);
- } else {
- var index = this._search(event.time);
- this._timeline.splice(index + 1, 0, event);
- //if the length is more than the memory, remove the previous ones
- if (this.length > this.memory) {
- var diff = this.length - this.memory;
- this._timeline.splice(0, diff);
- }
- }
- return this;
- };
- /**
- * Remove an event from the timeline.
- * @param {Object} event The event object to remove from the list.
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.remove = function (event) {
- if (this._iterating) {
- this._toRemove.push(event);
- } else {
- var index = this._timeline.indexOf(event);
- if (index !== -1) {
- this._timeline.splice(index, 1);
- }
- }
- return this;
- };
- /**
- * Get the nearest event whose time is less than or equal to the given time.
- * @param {Number} time The time to query.
- * @param {String} comparator Which value in the object to compare
- * @returns {Object} The event object set after that time.
- */
- Tone.Timeline.prototype.get = function (time, comparator) {
- comparator = Tone.defaultArg(comparator, 'time');
- var index = this._search(time, comparator);
- if (index !== -1) {
- return this._timeline[index];
- } else {
- return null;
- }
- };
- /**
- * Return the first event in the timeline without removing it
- * @returns {Object} The first event object
- */
- Tone.Timeline.prototype.peek = function () {
- return this._timeline[0];
- };
- /**
- * Return the first event in the timeline and remove it
- * @returns {Object} The first event object
- */
- Tone.Timeline.prototype.shift = function () {
- return this._timeline.shift();
- };
- /**
- * Get the event which is scheduled after the given time.
- * @param {Number} time The time to query.
- * @param {String} comparator Which value in the object to compare
- * @returns {Object} The event object after the given time
- */
- Tone.Timeline.prototype.getAfter = function (time, comparator) {
- comparator = Tone.defaultArg(comparator, 'time');
- var index = this._search(time, comparator);
- if (index + 1 < this._timeline.length) {
- return this._timeline[index + 1];
- } else {
- return null;
- }
- };
- /**
- * Get the event before the event at the given time.
- * @param {Number} time The time to query.
- * @param {String} comparator Which value in the object to compare
- * @returns {Object} The event object before the given time
- */
- Tone.Timeline.prototype.getBefore = function (time, comparator) {
- comparator = Tone.defaultArg(comparator, 'time');
- var len = this._timeline.length;
- //if it's after the last item, return the last item
- if (len > 0 && this._timeline[len - 1][comparator] < time) {
- return this._timeline[len - 1];
- }
- var index = this._search(time, comparator);
- if (index - 1 >= 0) {
- return this._timeline[index - 1];
- } else {
- return null;
- }
- };
- /**
- * Cancel events after the given time
- * @param {Number} time The time to query.
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.cancel = function (after) {
- if (this._timeline.length > 1) {
- var index = this._search(after);
- if (index >= 0) {
- if (this._timeline[index].time === after) {
- //get the first item with that time
- for (var i = index; i >= 0; i--) {
- if (this._timeline[i].time === after) {
- index = i;
- } else {
- break;
- }
- }
- this._timeline = this._timeline.slice(0, index);
- } else {
- this._timeline = this._timeline.slice(0, index + 1);
- }
- } else {
- this._timeline = [];
- }
- } else if (this._timeline.length === 1) {
- //the first item's time
- if (this._timeline[0].time >= after) {
- this._timeline = [];
- }
- }
- return this;
- };
- /**
- * Cancel events before or equal to the given time.
- * @param {Number} time The time to cancel before.
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.cancelBefore = function (time) {
- var index = this._search(time);
- if (index >= 0) {
- this._timeline = this._timeline.slice(index + 1);
- }
- return this;
- };
- /**
- * Returns the previous event if there is one. null otherwise
- * @param {Object} event The event to find the previous one of
- * @return {Object} The event right before the given event
- */
- Tone.Timeline.prototype.previousEvent = function (event) {
- var index = this._timeline.indexOf(event);
- if (index > 0) {
- return this._timeline[index - 1];
- } else {
- return null;
- }
- };
- /**
- * Does a binary search on the timeline array and returns the
- * nearest event index whose time is after or equal to the given time.
- * If a time is searched before the first index in the timeline, -1 is returned.
- * If the time is after the end, the index of the last item is returned.
- * @param {Number} time
- * @param {String} comparator Which value in the object to compare
- * @return {Number} the index in the timeline array
- * @private
- */
- Tone.Timeline.prototype._search = function (time, comparator) {
- if (this._timeline.length === 0) {
- return -1;
- }
- comparator = Tone.defaultArg(comparator, 'time');
- var beginning = 0;
- var len = this._timeline.length;
- var end = len;
- if (len > 0 && this._timeline[len - 1][comparator] <= time) {
- return len - 1;
- }
- while (beginning < end) {
- // calculate the midpoint for roughly equal partition
- var midPoint = Math.floor(beginning + (end - beginning) / 2);
- var event = this._timeline[midPoint];
- var nextEvent = this._timeline[midPoint + 1];
- if (event[comparator] === time) {
- //choose the last one that has the same time
- for (var i = midPoint; i < this._timeline.length; i++) {
- var testEvent = this._timeline[i];
- if (testEvent[comparator] === time) {
- midPoint = i;
- }
- }
- return midPoint;
- } else if (event[comparator] < time && nextEvent[comparator] > time) {
- return midPoint;
- } else if (event[comparator] > time) {
- //search lower
- end = midPoint;
- } else {
- //search upper
- beginning = midPoint + 1;
- }
- }
- return -1;
- };
- /**
- * Internal iterator. Applies extra safety checks for
- * removing items from the array.
- * @param {Function} callback
- * @param {Number=} lowerBound
- * @param {Number=} upperBound
- * @private
- */
- Tone.Timeline.prototype._iterate = function (callback, lowerBound, upperBound) {
- this._iterating = true;
- lowerBound = Tone.defaultArg(lowerBound, 0);
- upperBound = Tone.defaultArg(upperBound, this._timeline.length - 1);
- for (var i = lowerBound; i <= upperBound; i++) {
- callback.call(this, this._timeline[i]);
- }
- this._iterating = false;
- this._toRemove.forEach(function (event) {
- this.remove(event);
- }.bind(this));
- this._toRemove = [];
- this._toAdd.forEach(function (event) {
- this.add(event);
- }.bind(this));
- this._toAdd = [];
- };
- /**
- * Iterate over everything in the array
- * @param {Function} callback The callback to invoke with every item
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.forEach = function (callback) {
- this._iterate(callback);
- return this;
- };
- /**
- * Iterate over everything in the array at or before the given time.
- * @param {Number} time The time to check if items are before
- * @param {Function} callback The callback to invoke with every item
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.forEachBefore = function (time, callback) {
- //iterate over the items in reverse so that removing an item doesn't break things
- var upperBound = this._search(time);
- if (upperBound !== -1) {
- this._iterate(callback, 0, upperBound);
- }
- return this;
- };
- /**
- * Iterate over everything in the array after the given time.
- * @param {Number} time The time to check if items are before
- * @param {Function} callback The callback to invoke with every item
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.forEachAfter = function (time, callback) {
- //iterate over the items in reverse so that removing an item doesn't break things
- var lowerBound = this._search(time);
- this._iterate(callback, lowerBound + 1);
- return this;
- };
- /**
- * Iterate over everything in the array at or after the given time. Similar to
- * forEachAfter, but includes the item(s) at the given time.
- * @param {Number} time The time to check if items are before
- * @param {Function} callback The callback to invoke with every item
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.forEachFrom = function (time, callback) {
- //iterate over the items in reverse so that removing an item doesn't break things
- var lowerBound = this._search(time);
- //work backwards until the event time is less than time
- while (lowerBound >= 0 && this._timeline[lowerBound].time >= time) {
- lowerBound--;
- }
- this._iterate(callback, lowerBound + 1);
- return this;
- };
- /**
- * Iterate over everything in the array at the given time
- * @param {Number} time The time to check if items are before
- * @param {Function} callback The callback to invoke with every item
- * @returns {Tone.Timeline} this
- */
- Tone.Timeline.prototype.forEachAtTime = function (time, callback) {
- //iterate over the items in reverse so that removing an item doesn't break things
- var upperBound = this._search(time);
- if (upperBound !== -1) {
- this._iterate(function (event) {
- if (event.time === time) {
- callback.call(this, event);
- }
- }, 0, upperBound);
- }
- return this;
- };
- /**
- * Clean up.
- * @return {Tone.Timeline} this
- */
- Tone.Timeline.prototype.dispose = function () {
- Tone.prototype.dispose.call(this);
- this._timeline = null;
- this._toRemove = null;
- this._toAdd = null;
- return this;
- };
- return Tone.Timeline;
- });
- Module(function (Tone) {
- /**
- * shim
- * @private
- */
- if (!window.hasOwnProperty('AudioContext') && window.hasOwnProperty('webkitAudioContext')) {
- window.AudioContext = window.webkitAudioContext;
- }
- /**
- * @class Wrapper around the native AudioContext.
- * @extends {Tone.Emitter}
- * @param {AudioContext=} context optionally pass in a context
- */
- Tone.Context = function () {
- Tone.Emitter.call(this);
- var options = Tone.defaults(arguments, ['context'], Tone.Context);
- if (!options.context) {
- options.context = new window.AudioContext();
- }
- this._context = options.context;
- // extend all of the methods
- for (var prop in this._context) {
- this._defineProperty(this._context, prop);
- }
- /**
- * The default latency hint
- * @type {String}
- * @private
- */
- this._latencyHint = options.latencyHint;
- /**
- * An object containing all of the constants AudioBufferSourceNodes
- * @type {Object}
- * @private
- */
- this._constants = {};
- ///////////////////////////////////////////////////////////////////////
- // WORKER
- ///////////////////////////////////////////////////////////////////////
- /**
- * The amount of time events are scheduled
- * into the future
- * @type {Number}
- * @private
- */
- this.lookAhead = options.lookAhead;
- /**
- * A reference to the actual computed update interval
- * @type {Number}
- * @private
- */
- this._computedUpdateInterval = 0;
- /**
- * A reliable callback method
- * @private
- * @type {Ticker}
- */
- this._ticker = new Ticker(this.emit.bind(this, 'tick'), options.clockSource, options.updateInterval);
- ///////////////////////////////////////////////////////////////////////
- // TIMEOUTS
- ///////////////////////////////////////////////////////////////////////
- /**
- * All of the setTimeout events.
- * @type {Tone.Timeline}
- * @private
- */
- this._timeouts = new Tone.Timeline();
- /**
- * The timeout id counter
- * @private
- * @type {Number}
- */
- this._timeoutIds = 0;
- this.on('tick', this._timeoutLoop.bind(this));
- };
- Tone.extend(Tone.Context, Tone.Emitter);
- Tone.Emitter.mixin(Tone.Context);
- /**
- * defaults
- * @static
- * @type {Object}
- */
- Tone.Context.defaults = {
- 'clockSource': 'worker',
- 'latencyHint': 'interactive',
- 'lookAhead': 0.1,
- 'updateInterval': 0.03
- };
- /**
- * Define a property on this Tone.Context.
- * This is used to extend the native AudioContext
- * @param {AudioContext} context
- * @param {String} prop
- * @private
- */
- Tone.Context.prototype._defineProperty = function (context, prop) {
- if (Tone.isUndef(this[prop])) {
- Object.defineProperty(this, prop, {
- get: function () {
- if (typeof context[prop] === 'function') {
- return context[prop].bind(context);
- } else {
- return context[prop];
- }
- },
- set: function (val) {
- context[prop] = val;
- }
- });
- }
- };
- /**
- * The current audio context time
- * @return {Number}
- */
- Tone.Context.prototype.now = function () {
- return this._context.currentTime + this.lookAhead;
- };
- /**
- * Generate a looped buffer at some constant value.
- * @param {Number} val
- * @return {BufferSourceNode}
- */
- Tone.Context.prototype.getConstant = function (val) {
- if (this._constants[val]) {
- return this._constants[val];
- } else {
- var buffer = this._context.createBuffer(1, 128, this._context.sampleRate);
- var arr = buffer.getChannelData(0);
- for (var i = 0; i < arr.length; i++) {
- arr[i] = val;
- }
- var constant = this._context.createBufferSource();
- constant.channelCount = 1;
- constant.channelCountMode = 'explicit';
- constant.buffer = buffer;
- constant.loop = true;
- constant.start(0);
- this._constants[val] = constant;
- return constant;
- }
- };
- /**
- * The private loop which keeps track of the context scheduled timeouts
- * Is invoked from the clock source
- * @private
- */
- Tone.Context.prototype._timeoutLoop = function () {
- var now = this.now();
- while (this._timeouts && this._timeouts.length && this._timeouts.peek().time <= now) {
- this._timeouts.shift().callback();
- }
- };
- /**
- * A setTimeout which is gaurenteed by the clock source.
- * Also runs in the offline context.
- * @param {Function} fn The callback to invoke
- * @param {Seconds} timeout The timeout in seconds
- * @returns {Number} ID to use when invoking Tone.Context.clearTimeout
- */
- Tone.Context.prototype.setTimeout = function (fn, timeout) {
- this._timeoutIds++;
- var now = this.now();
- this._timeouts.add({
- callback: fn,
- time: now + timeout,
- id: this._timeoutIds
- });
- return this._timeoutIds;
- };
- /**
- * Clears a previously scheduled timeout with Tone.context.setTimeout
- * @param {Number} id The ID returned from setTimeout
- * @return {Tone.Context} this
- */
- Tone.Context.prototype.clearTimeout = function (id) {
- this._timeouts.forEach(function (event) {
- if (event.id === id) {
- this.remove(event);
- }
- });
- return this;
- };
- /**
- * How often the Web Worker callback is invoked.
- * This number corresponds to how responsive the scheduling
- * can be. Context.updateInterval + Context.lookAhead gives you the
- * total latency between scheduling an event and hearing it.
- * @type {Number}
- * @memberOf Tone.Context#
- * @name updateInterval
- */
- Object.defineProperty(Tone.Context.prototype, 'updateInterval', {
- get: function () {
- return this._ticker.updateInterval;
- },
- set: function (interval) {
- this._ticker.updateInterval = interval;
- }
- });
- /**
- * What the source of the clock is, either "worker" (Web Worker [default]),
- * "timeout" (setTimeout), or "offline" (none).
- * @type {String}
- * @memberOf Tone.Context#
- * @name clockSource
- */
- Object.defineProperty(Tone.Context.prototype, 'clockSource', {
- get: function () {
- return this._ticker.type;
- },
- set: function (type) {
- this._ticker.type = type;
- }
- });
- /**
- * The type of playback, which affects tradeoffs between audio
- * output latency and responsiveness.
- *
- * In addition to setting the value in seconds, the latencyHint also
- * accepts the strings "interactive" (prioritizes low latency),
- * "playback" (prioritizes sustained playback), "balanced" (balances
- * latency and performance), and "fastest" (lowest latency, might glitch more often).
- * @type {String|Seconds}
- * @memberOf Tone.Context#
- * @name latencyHint
- * @example
- * //set the lookAhead to 0.3 seconds
- * Tone.context.latencyHint = 0.3;
- */
- Object.defineProperty(Tone.Context.prototype, 'latencyHint', {
- get: function () {
- return this._latencyHint;
- },
- set: function (hint) {
- var lookAhead = hint;
- this._latencyHint = hint;
- if (Tone.isString(hint)) {
- switch (hint) {
- case 'interactive':
- lookAhead = 0.1;
- this._context.latencyHint = hint;
- break;
- case 'playback':
- lookAhead = 0.8;
- this._context.latencyHint = hint;
- break;
- case 'balanced':
- lookAhead = 0.25;
- this._context.latencyHint = hint;
- break;
- case 'fastest':
- this._context.latencyHint = 'interactive';
- lookAhead = 0.01;
- break;
- }
- }
- this.lookAhead = lookAhead;
- this.updateInterval = lookAhead / 3;
- }
- });
- /**
- * Clean up
- * @returns {Tone.Context} this
- */
- Tone.Context.prototype.dispose = function () {
- Tone.Context.emit('close', this);
- Tone.Emitter.prototype.dispose.call(this);
- this._ticker.dispose();
- this._ticker = null;
- this._timeouts.dispose();
- this._timeouts = null;
- for (var con in this._constants) {
- this._constants[con].disconnect();
- }
- this._constants = null;
- this.close();
- return this;
- };
- /**
- * @class A class which provides a reliable callback using either
- * a Web Worker, or if that isn't supported, falls back to setTimeout.
- * @private
- */
- var Ticker = function (callback, type, updateInterval) {
- /**
- * Either "worker" or "timeout"
- * @type {String}
- * @private
- */
- this._type = type;
- /**
- * The update interval of the worker
- * @private
- * @type {Number}
- */
- this._updateInterval = updateInterval;
- /**
- * The callback to invoke at regular intervals
- * @type {Function}
- * @private
- */
- this._callback = Tone.defaultArg(callback, Tone.noOp);
- //create the clock source for the first time
- this._createClock();
- };
- /**
- * The possible ticker types
- * @private
- * @type {Object}
- */
- Ticker.Type = {
- Worker: 'worker',
- Timeout: 'timeout',
- Offline: 'offline'
- };
- /**
- * Generate a web worker
- * @return {WebWorker}
- * @private
- */
- Ticker.prototype._createWorker = function () {
- //URL Shim
- window.URL = window.URL || window.webkitURL;
- var blob = new Blob([//the initial timeout time
- 'var timeoutTime = ' + (this._updateInterval * 1000).toFixed(1) + ';' + //onmessage callback
- 'self.onmessage = function(msg){' + '\ttimeoutTime = parseInt(msg.data);' + '};' + //the tick function which posts a message
- //and schedules a new tick
- 'function tick(){' + '\tsetTimeout(tick, timeoutTime);' + '\tself.postMessage(\'tick\');' + '}' + //call tick initially
- 'tick();']);
- var blobUrl = URL.createObjectURL(blob);
- var worker = new Worker(blobUrl);
- worker.onmessage = this._callback.bind(this);
- this._worker = worker;
- };
- /**
- * Create a timeout loop
- * @private
- */
- Ticker.prototype._createTimeout = function () {
- this._timeout = setTimeout(function () {
- this._createTimeout();
- this._callback();
- }.bind(this), this._updateInterval * 1000);
- };
- /**
- * Create the clock source.
- * @private
- */
- Ticker.prototype._createClock = function () {
- if (this._type === Ticker.Type.Worker) {
- try {
- this._createWorker();
- } catch (e) {
- // workers not supported, fallback to timeout
- this._type = Ticker.Type.Timeout;
- this._createClock();
- }
- } else if (this._type === Ticker.Type.Timeout) {
- this._createTimeout();
- }
- };
- /**
- * @memberOf Ticker#
- * @type {Number}
- * @name updateInterval
- * @private
- */
- Object.defineProperty(Ticker.prototype, 'updateInterval', {
- get: function () {
- return this._updateInterval;
- },
- set: function (interval) {
- this._updateInterval = Math.max(interval, 128 / 44100);
- if (this._type === Ticker.Type.Worker) {
- this._worker.postMessage(Math.max(interval * 1000, 1));
- }
- }
- });
- /**
- * The type of the ticker, either a worker or a timeout
- * @memberOf Ticker#
- * @type {Number}
- * @name type
- * @private
- */
- Object.defineProperty(Ticker.prototype, 'type', {
- get: function () {
- return this._type;
- },
- set: function (type) {
- this._disposeClock();
- this._type = type;
- this._createClock();
- }
- });
- /**
- * Clean up the current clock source
- * @private
- */
- Ticker.prototype._disposeClock = function () {
- if (this._timeout) {
- clearTimeout(this._timeout);
- this._timeout = null;
- }
- if (this._worker) {
- this._worker.terminate();
- this._worker.onmessage = null;
- this._worker = null;
- }
- };
- /**
- * Clean up
- * @private
- */
- Ticker.prototype.dispose = function () {
- this._disposeClock();
- this._callback = null;
- };
- /**
- * Shim all connect/disconnect and some deprecated methods which are still in
- * some older implementations.
- * @private
- */
- Tone.getContext(function () {
- var nativeConnect = AudioNode.prototype.connect;
- var nativeDisconnect = AudioNode.prototype.disconnect;
- //replace the old connect method
- function toneConnect(B, outNum, inNum) {
- if (B.input) {
- inNum = Tone.defaultArg(inNum, 0);
- if (Tone.isArray(B.input)) {
- this.connect(B.input[inNum]);
- } else {
- this.connect(B.input, outNum, inNum);
- }
- } else {
- try {
- if (B instanceof AudioNode) {
- nativeConnect.call(this, B, outNum, inNum);
- } else {
- nativeConnect.call(this, B, outNum);
- }
- } catch (e) {
- throw new Error('error connecting to node: ' + B + '\n' + e);
- }
- }
- }
- //replace the old disconnect method
- function toneDisconnect(B, outNum, inNum) {
- if (B && B.input && Tone.isArray(B.input)) {
- inNum = Tone.defaultArg(inNum, 0);
- this.disconnect(B.input[inNum], outNum, 0);
- } else if (B && B.input) {
- this.disconnect(B.input, outNum, inNum);
- } else {
- try {
- nativeDisconnect.apply(this, arguments);
- } catch (e) {
- throw new Error('error disconnecting node: ' + B + '\n' + e);
- }
- }
- }
- if (AudioNode.prototype.connect !== toneConnect) {
- AudioNode.prototype.connect = toneConnect;
- AudioNode.prototype.disconnect = toneDisconnect;
- }
- });
- // set the audio context initially
- if (Tone.supported) {
- Tone.context = new Tone.Context();
- } else {
- console.warn('This browser does not support Tone.js');
- }
- return Tone.Context;
- });
- Module(function (Tone) {
- /**
- * @class Tone.AudioNode is the base class for classes which process audio.
- * AudioNodes have inputs and outputs.
- * @param {AudioContext=} context The audio context to use with the class
- * @extends {Tone}
- */
- Tone.AudioNode = function () {
- Tone.call(this);
- //use the default context if one is not passed in
- var options = Tone.defaults(arguments, ['context'], { 'context': Tone.context });
- /**
- * The AudioContext of this instance
- * @private
- * @type {AudioContext}
- */
- this._context = options.context;
- };
- Tone.extend(Tone.AudioNode);
- /**
- * Get the audio context belonging to this instance.
- * @type {Tone.Context}
- * @memberOf Tone.AudioNode#
- * @name context
- * @readOnly
- */
- Object.defineProperty(Tone.AudioNode.prototype, 'context', {
- get: function () {
- return this._context;
- }
- });
- /**
- * Create input and outputs for this object.
- * @param {Number} [input=0] The number of inputs
- * @param {Number} [outputs=0] The number of outputs
- * @return {Tone.AudioNode} this
- * @private
- */
- Tone.AudioNode.prototype.createInsOuts = function (inputs, outputs) {
- if (inputs === 1) {
- this.input = this.context.createGain();
- } else if (inputs > 1) {
- this.input = new Array(inputs);
- }
- if (outputs === 1) {
- this.output = this.context.createGain();
- } else if (outputs > 1) {
- this.output = new Array(outputs);
- }
- };
- /**
- * The number of inputs feeding into the AudioNode.
- * For source nodes, this will be 0.
- * @type {Number}
- * @name numberOfInputs
- * @readOnly
- */
- Object.defineProperty(Tone.AudioNode.prototype, 'numberOfInputs', {
- get: function () {
- if (this.input) {
- if (Tone.isArray(this.input)) {
- return this.input.length;
- } else {
- return 1;
- }
- } else {
- return 0;
- }
- }
- });
- /**
- * The number of outputs coming out of the AudioNode.
- * @type {Number}
- * @name numberOfOutputs
- * @readOnly
- */
- Object.defineProperty(Tone.AudioNode.prototype, 'numberOfOutputs', {
- get: function () {
- if (this.output) {
- if (Tone.isArray(this.output)) {
- return this.output.length;
- } else {
- return 1;
- }
- } else {
- return 0;
- }
- }
- });
- /**
- * connect the output of a ToneNode to an AudioParam, AudioNode, or ToneNode
- * @param {Tone | AudioParam | AudioNode} unit
- * @param {number} [outputNum=0] optionally which output to connect from
- * @param {number} [inputNum=0] optionally which input to connect to
- * @returns {Tone.AudioNode} this
- */
- Tone.AudioNode.prototype.connect = function (unit, outputNum, inputNum) {
- if (Tone.isArray(this.output)) {
- outputNum = Tone.defaultArg(outputNum, 0);
- this.output[outputNum].connect(unit, 0, inputNum);
- } else {
- this.output.connect(unit, outputNum, inputNum);
- }
- return this;
- };
- /**
- * disconnect the output
- * @param {Number|AudioNode} output Either the output index to disconnect
- * if the output is an array, or the
- * node to disconnect from.
- * @returns {Tone.AudioNode} this
- */
- Tone.AudioNode.prototype.disconnect = function (destination, outputNum, inputNum) {
- if (Tone.isArray(this.output)) {
- if (Tone.isNumber(destination)) {
- this.output[destination].disconnect();
- } else {
- outputNum = Tone.defaultArg(outputNum, 0);
- this.output[outputNum].disconnect(destination, 0, inputNum);
- }
- } else {
- this.output.disconnect.apply(this.output, arguments);
- }
- };
- /**
- * Connect the output of this node to the rest of the nodes in series.
- * @example
- * //connect a node to an effect, panVol and then to the master output
- * node.chain(effect, panVol, Tone.Master);
- * @param {...AudioParam|Tone|AudioNode} nodes
- * @returns {Tone.AudioNode} this
- * @private
- */
- Tone.AudioNode.prototype.chain = function () {
- var currentUnit = this;
- for (var i = 0; i < arguments.length; i++) {
- var toUnit = arguments[i];
- currentUnit.connect(toUnit);
- currentUnit = toUnit;
- }
- return this;
- };
- /**
- * connect the output of this node to the rest of the nodes in parallel.
- * @param {...AudioParam|Tone|AudioNode} nodes
- * @returns {Tone.AudioNode} this
- * @private
- */
- Tone.AudioNode.prototype.fan = function () {
- for (var i = 0; i < arguments.length; i++) {
- this.connect(arguments[i]);
- }
- return this;
- };
- if (window.AudioNode) {
- //give native nodes chain and fan methods
- AudioNode.prototype.chain = Tone.AudioNode.prototype.chain;
- AudioNode.prototype.fan = Tone.AudioNode.prototype.fan;
- }
- /**
- * Dispose and disconnect
- * @return {Tone.AudioNode} this
- */
- Tone.AudioNode.prototype.dispose = function () {
- if (!Tone.isUndef(this.input)) {
- if (this.input instanceof AudioNode) {
- this.input.disconnect();
- }
- this.input = null;
- }
- if (!Tone.isUndef(this.output)) {
- if (this.output instanceof AudioNode) {
- this.output.disconnect();
- }
- this.output = null;
- }
- this._context = null;
- return this;
- };
- return Tone.AudioNode;
- });
- Module(function (Tone) {
-
- /**
- * @class Base class for all Signals. Used Internally.
- *
- * @constructor
- * @extends {Tone}
- */
- Tone.SignalBase = function () {
- Tone.AudioNode.call(this);
- };
- Tone.extend(Tone.SignalBase, Tone.AudioNode);
- /**
- * When signals connect to other signals or AudioParams,
- * they take over the output value of that signal or AudioParam.
- * For all other nodes, the behavior is the same as a default connect.
- *
- * @override
- * @param {AudioParam|AudioNode|Tone.Signal|Tone} node
- * @param {number} [outputNumber=0] The output number to connect from.
- * @param {number} [inputNumber=0] The input number to connect to.
- * @returns {Tone.SignalBase} this
- */
- Tone.SignalBase.prototype.connect = function (node, outputNumber, inputNumber) {
- //zero it out so that the signal can have full control
- if (Tone.Signal && Tone.Signal === node.constructor || Tone.Param && Tone.Param === node.constructor || Tone.TimelineSignal && Tone.TimelineSignal === node.constructor) {
- //cancel changes
- node._param.cancelScheduledValues(0);
- //reset the value
- node._param.value = 0;
- //mark the value as overridden
- node.overridden = true;
- } else if (node instanceof AudioParam) {
- node.cancelScheduledValues(0);
- node.value = 0;
- }
- Tone.AudioNode.prototype.connect.call(this, node, outputNumber, inputNumber);
- return this;
- };
- return Tone.SignalBase;
- });
- Module(function (Tone) {
-
- /**
- * @class Wraps the native Web Audio API
- * [WaveShaperNode](http://webaudio.github.io/web-audio-api/#the-waveshapernode-interface).
- *
- * @extends {Tone.SignalBase}
- * @constructor
- * @param {function|Array|Number} mapping The function used to define the values.
- * The mapping function should take two arguments:
- * the first is the value at the current position
- * and the second is the array position.
- * If the argument is an array, that array will be
- * set as the wave shaping function. The input
- * signal is an AudioRange [-1, 1] value and the output
- * signal can take on any numerical values.
- *
- * @param {Number} [bufferLen=1024] The length of the WaveShaperNode buffer.
- * @example
- * var timesTwo = new Tone.WaveShaper(function(val){
- * return val * 2;
- * }, 2048);
- * @example
- * //a waveshaper can also be constructed with an array of values
- * var invert = new Tone.WaveShaper([1, -1]);
- */
- Tone.WaveShaper = function (mapping, bufferLen) {
- Tone.SignalBase.call(this);
- /**
- * the waveshaper
- * @type {WaveShaperNode}
- * @private
- */
- this._shaper = this.input = this.output = this.context.createWaveShaper();
- /**
- * the waveshapers curve
- * @type {Float32Array}
- * @private
- */
- this._curve = null;
- if (Array.isArray(mapping)) {
- this.curve = mapping;
- } else if (isFinite(mapping) || Tone.isUndef(mapping)) {
- this._curve = new Float32Array(Tone.defaultArg(mapping, 1024));
- } else if (Tone.isFunction(mapping)) {
- this._curve = new Float32Array(Tone.defaultArg(bufferLen, 1024));
- this.setMap(mapping);
- }
- };
- Tone.extend(Tone.WaveShaper, Tone.SignalBase);
- /**
- * Uses a mapping function to set the value of the curve.
- * @param {function} mapping The function used to define the values.
- * The mapping function take two arguments:
- * the first is the value at the current position
- * which goes from -1 to 1 over the number of elements
- * in the curve array. The second argument is the array position.
- * @returns {Tone.WaveShaper} this
- * @example
- * //map the input signal from [-1, 1] to [0, 10]
- * shaper.setMap(function(val, index){
- * return (val + 1) * 5;
- * })
- */
- Tone.WaveShaper.prototype.setMap = function (mapping) {
- for (var i = 0, len = this._curve.length; i < len; i++) {
- var normalized = i / (len - 1) * 2 - 1;
- this._curve[i] = mapping(normalized, i);
- }
- this._shaper.curve = this._curve;
- return this;
- };
- /**
- * The array to set as the waveshaper curve. For linear curves
- * array length does not make much difference, but for complex curves
- * longer arrays will provide smoother interpolation.
- * @memberOf Tone.WaveShaper#
- * @type {Array}
- * @name curve
- */
- Object.defineProperty(Tone.WaveShaper.prototype, 'curve', {
- get: function () {
- return this._shaper.curve;
- },
- set: function (mapping) {
- this._curve = new Float32Array(mapping);
- this._shaper.curve = this._curve;
- }
- });
- /**
- * Specifies what type of oversampling (if any) should be used when
- * applying the shaping curve. Can either be "none", "2x" or "4x".
- * @memberOf Tone.WaveShaper#
- * @type {string}
- * @name oversample
- */
- Object.defineProperty(Tone.WaveShaper.prototype, 'oversample', {
- get: function () {
- return this._shaper.oversample;
- },
- set: function (oversampling) {
- if ([
- 'none',
- '2x',
- '4x'
- ].indexOf(oversampling) !== -1) {
- this._shaper.oversample = oversampling;
- } else {
- throw new RangeError('Tone.WaveShaper: oversampling must be either \'none\', \'2x\', or \'4x\'');
- }
- }
- });
- /**
- * Clean up.
- * @returns {Tone.WaveShaper} this
- */
- Tone.WaveShaper.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._shaper.disconnect();
- this._shaper = null;
- this._curve = null;
- return this;
- };
- return Tone.WaveShaper;
- });
- Module(function (Tone) {
- /**
- * @class Tone.TimeBase is a flexible encoding of time
- * which can be evaluated to and from a string.
- * Parsing code modified from https://code.google.com/p/tapdigit/
- * Copyright 2011 2012 Ariya Hidayat, New BSD License
- * @extends {Tone}
- * @param {Time} val The time value as a number or string
- * @param {String=} units Unit values
- * @example
- * Tone.TimeBase(4, "n")
- * Tone.TimeBase(2, "t")
- * Tone.TimeBase("2t").add("1m")
- * Tone.TimeBase("2t + 1m");
- */
- Tone.TimeBase = function (val, units) {
- //allows it to be constructed with or without 'new'
- if (this instanceof Tone.TimeBase) {
- /**
- * Any expressions parsed from the Time
- * @type {Array}
- * @private
- */
- this._expr = this._noOp;
- if (val instanceof Tone.TimeBase) {
- this.copy(val);
- } else if (!Tone.isUndef(units) || Tone.isNumber(val)) {
- //default units
- units = Tone.defaultArg(units, this._defaultUnits);
- var method = this._primaryExpressions[units].method;
- this._expr = method.bind(this, val);
- } else if (Tone.isString(val)) {
- this.set(val);
- } else if (Tone.isUndef(val)) {
- //default expression
- this._expr = this._defaultExpr();
- }
- } else {
- return new Tone.TimeBase(val, units);
- }
- };
- Tone.extend(Tone.TimeBase);
- /**
- * Repalce the current time value with the value
- * given by the expression string.
- * @param {String} exprString
- * @return {Tone.TimeBase} this
- */
- Tone.TimeBase.prototype.set = function (exprString) {
- this._expr = this._parseExprString(exprString);
- return this;
- };
- /**
- * Return a clone of the TimeBase object.
- * @return {Tone.TimeBase} The new cloned Tone.TimeBase
- */
- Tone.TimeBase.prototype.clone = function () {
- var instance = new this.constructor();
- instance.copy(this);
- return instance;
- };
- /**
- * Copies the value of time to this Time
- * @param {Tone.TimeBase} time
- * @return {TimeBase}
- */
- Tone.TimeBase.prototype.copy = function (time) {
- var val = time._expr();
- return this.set(val);
- };
- ///////////////////////////////////////////////////////////////////////////
- // ABSTRACT SYNTAX TREE PARSER
- ///////////////////////////////////////////////////////////////////////////
- /**
- * All the primary expressions.
- * @private
- * @type {Object}
- */
- Tone.TimeBase.prototype._primaryExpressions = {
- 'n': {
- regexp: /^(\d+)n/i,
- method: function (value) {
- value = parseInt(value);
- if (value === 1) {
- return this._beatsToUnits(this._timeSignature());
- } else {
- return this._beatsToUnits(4 / value);
- }
- }
- },
- 't': {
- regexp: /^(\d+)t/i,
- method: function (value) {
- value = parseInt(value);
- return this._beatsToUnits(8 / (parseInt(value) * 3));
- }
- },
- 'm': {
- regexp: /^(\d+)m/i,
- method: function (value) {
- return this._beatsToUnits(parseInt(value) * this._timeSignature());
- }
- },
- 'i': {
- regexp: /^(\d+)i/i,
- method: function (value) {
- return this._ticksToUnits(parseInt(value));
- }
- },
- 'hz': {
- regexp: /^(\d+(?:\.\d+)?)hz/i,
- method: function (value) {
- return this._frequencyToUnits(parseFloat(value));
- }
- },
- 'tr': {
- regexp: /^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,
- method: function (m, q, s) {
- var total = 0;
- if (m && m !== '0') {
- total += this._beatsToUnits(this._timeSignature() * parseFloat(m));
- }
- if (q && q !== '0') {
- total += this._beatsToUnits(parseFloat(q));
- }
- if (s && s !== '0') {
- total += this._beatsToUnits(parseFloat(s) / 4);
- }
- return total;
- }
- },
- 's': {
- regexp: /^(\d+(?:\.\d+)?s)/,
- method: function (value) {
- return this._secondsToUnits(parseFloat(value));
- }
- },
- 'samples': {
- regexp: /^(\d+)samples/,
- method: function (value) {
- return parseInt(value) / this.context.sampleRate;
- }
- },
- 'default': {
- regexp: /^(\d+(?:\.\d+)?)/,
- method: function (value) {
- return this._primaryExpressions[this._defaultUnits].method.call(this, value);
- }
- }
- };
- /**
- * All the binary expressions that TimeBase can accept.
- * @private
- * @type {Object}
- */
- Tone.TimeBase.prototype._binaryExpressions = {
- '+': {
- regexp: /^\+/,
- precedence: 2,
- method: function (lh, rh) {
- return lh() + rh();
- }
- },
- '-': {
- regexp: /^\-/,
- precedence: 2,
- method: function (lh, rh) {
- return lh() - rh();
- }
- },
- '*': {
- regexp: /^\*/,
- precedence: 1,
- method: function (lh, rh) {
- return lh() * rh();
- }
- },
- '/': {
- regexp: /^\//,
- precedence: 1,
- method: function (lh, rh) {
- return lh() / rh();
- }
- }
- };
- /**
- * All the unary expressions.
- * @private
- * @type {Object}
- */
- Tone.TimeBase.prototype._unaryExpressions = {
- 'neg': {
- regexp: /^\-/,
- method: function (lh) {
- return -lh();
- }
- }
- };
- /**
- * Syntactic glue which holds expressions together
- * @private
- * @type {Object}
- */
- Tone.TimeBase.prototype._syntaxGlue = {
- '(': { regexp: /^\(/ },
- ')': { regexp: /^\)/ }
- };
- /**
- * tokenize the expression based on the Expressions object
- * @param {string} expr
- * @return {Object} returns two methods on the tokenized list, next and peek
- * @private
- */
- Tone.TimeBase.prototype._tokenize = function (expr) {
- var position = -1;
- var tokens = [];
- while (expr.length > 0) {
- expr = expr.trim();
- var token = getNextToken(expr, this);
- tokens.push(token);
- expr = expr.substr(token.value.length);
- }
- function getNextToken(expr, context) {
- var expressions = [
- '_binaryExpressions',
- '_unaryExpressions',
- '_primaryExpressions',
- '_syntaxGlue'
- ];
- for (var i = 0; i < expressions.length; i++) {
- var group = context[expressions[i]];
- for (var opName in group) {
- var op = group[opName];
- var reg = op.regexp;
- var match = expr.match(reg);
- if (match !== null) {
- return {
- method: op.method,
- precedence: op.precedence,
- regexp: op.regexp,
- value: match[0]
- };
- }
- }
- }
- throw new SyntaxError('Tone.TimeBase: Unexpected token ' + expr);
- }
- return {
- next: function () {
- return tokens[++position];
- },
- peek: function () {
- return tokens[position + 1];
- }
- };
- };
- /**
- * Given a token, find the value within the groupName
- * @param {Object} token
- * @param {String} groupName
- * @param {Number} precedence
- * @private
- */
- Tone.TimeBase.prototype._matchGroup = function (token, group, prec) {
- var ret = false;
- if (!Tone.isUndef(token)) {
- for (var opName in group) {
- var op = group[opName];
- if (op.regexp.test(token.value)) {
- if (!Tone.isUndef(prec)) {
- if (op.precedence === prec) {
- return op;
- }
- } else {
- return op;
- }
- }
- }
- }
- return ret;
- };
- /**
- * Match a binary expression given the token and the precedence
- * @param {Lexer} lexer
- * @param {Number} precedence
- * @private
- */
- Tone.TimeBase.prototype._parseBinary = function (lexer, precedence) {
- if (Tone.isUndef(precedence)) {
- precedence = 2;
- }
- var expr;
- if (precedence < 0) {
- expr = this._parseUnary(lexer);
- } else {
- expr = this._parseBinary(lexer, precedence - 1);
- }
- var token = lexer.peek();
- while (token && this._matchGroup(token, this._binaryExpressions, precedence)) {
- token = lexer.next();
- expr = token.method.bind(this, expr, this._parseBinary(lexer, precedence - 1));
- token = lexer.peek();
- }
- return expr;
- };
- /**
- * Match a unary expression.
- * @param {Lexer} lexer
- * @private
- */
- Tone.TimeBase.prototype._parseUnary = function (lexer) {
- var token, expr;
- token = lexer.peek();
- var op = this._matchGroup(token, this._unaryExpressions);
- if (op) {
- token = lexer.next();
- expr = this._parseUnary(lexer);
- return op.method.bind(this, expr);
- }
- return this._parsePrimary(lexer);
- };
- /**
- * Match a primary expression (a value).
- * @param {Lexer} lexer
- * @private
- */
- Tone.TimeBase.prototype._parsePrimary = function (lexer) {
- var token, expr;
- token = lexer.peek();
- if (Tone.isUndef(token)) {
- throw new SyntaxError('Tone.TimeBase: Unexpected end of expression');
- }
- if (this._matchGroup(token, this._primaryExpressions)) {
- token = lexer.next();
- var matching = token.value.match(token.regexp);
- return token.method.bind(this, matching[1], matching[2], matching[3]);
- }
- if (token && token.value === '(') {
- lexer.next();
- expr = this._parseBinary(lexer);
- token = lexer.next();
- if (!(token && token.value === ')')) {
- throw new SyntaxError('Expected )');
- }
- return expr;
- }
- throw new SyntaxError('Tone.TimeBase: Cannot process token ' + token.value);
- };
- /**
- * Recursively parse the string expression into a syntax tree.
- * @param {string} expr
- * @return {Function} the bound method to be evaluated later
- * @private
- */
- Tone.TimeBase.prototype._parseExprString = function (exprString) {
- if (!Tone.isString(exprString)) {
- exprString = exprString.toString();
- }
- var lexer = this._tokenize(exprString);
- var tree = this._parseBinary(lexer);
- return tree;
- };
- ///////////////////////////////////////////////////////////////////////////
- // DEFAULTS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * The initial expression value
- * @return {Number} The initial value 0
- * @private
- */
- Tone.TimeBase.prototype._noOp = function () {
- return 0;
- };
- /**
- * The default expression value if no arguments are given
- * @private
- */
- Tone.TimeBase.prototype._defaultExpr = function () {
- return this._noOp;
- };
- /**
- * The default units if none are given.
- * @private
- */
- Tone.TimeBase.prototype._defaultUnits = 's';
- ///////////////////////////////////////////////////////////////////////////
- // UNIT CONVERSIONS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Returns the value of a frequency in the current units
- * @param {Frequency} freq
- * @return {Number}
- * @private
- */
- Tone.TimeBase.prototype._frequencyToUnits = function (freq) {
- return 1 / freq;
- };
- /**
- * Return the value of the beats in the current units
- * @param {Number} beats
- * @return {Number}
- * @private
- */
- Tone.TimeBase.prototype._beatsToUnits = function (beats) {
- return 60 / Tone.Transport.bpm.value * beats;
- };
- /**
- * Returns the value of a second in the current units
- * @param {Seconds} seconds
- * @return {Number}
- * @private
- */
- Tone.TimeBase.prototype._secondsToUnits = function (seconds) {
- return seconds;
- };
- /**
- * Returns the value of a tick in the current time units
- * @param {Ticks} ticks
- * @return {Number}
- * @private
- */
- Tone.TimeBase.prototype._ticksToUnits = function (ticks) {
- return ticks * (this._beatsToUnits(1) / Tone.Transport.PPQ);
- };
- /**
- * Return the time signature.
- * @return {Number}
- * @private
- */
- Tone.TimeBase.prototype._timeSignature = function () {
- return Tone.Transport.timeSignature;
- };
- ///////////////////////////////////////////////////////////////////////////
- // EXPRESSIONS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Push an expression onto the expression list
- * @param {Time} val
- * @param {String} type
- * @param {String} units
- * @return {Tone.TimeBase}
- * @private
- */
- Tone.TimeBase.prototype._pushExpr = function (val, name, units) {
- //create the expression
- if (!(val instanceof Tone.TimeBase)) {
- val = new this.constructor(val, units);
- }
- this._expr = this._binaryExpressions[name].method.bind(this, this._expr, val._expr);
- return this;
- };
- /**
- * Add to the current value.
- * @param {Time} val The value to add
- * @param {String=} units Optional units to use with the value.
- * @return {Tone.TimeBase} this
- * @example
- * Tone.TimeBase("2m").add("1m"); //"3m"
- */
- Tone.TimeBase.prototype.add = function (val, units) {
- return this._pushExpr(val, '+', units);
- };
- /**
- * Subtract the value from the current time.
- * @param {Time} val The value to subtract
- * @param {String=} units Optional units to use with the value.
- * @return {Tone.TimeBase} this
- * @example
- * Tone.TimeBase("2m").sub("1m"); //"1m"
- */
- Tone.TimeBase.prototype.sub = function (val, units) {
- return this._pushExpr(val, '-', units);
- };
- /**
- * Multiply the current value by the given time.
- * @param {Time} val The value to multiply
- * @param {String=} units Optional units to use with the value.
- * @return {Tone.TimeBase} this
- * @example
- * Tone.TimeBase("2m").mult("2"); //"4m"
- */
- Tone.TimeBase.prototype.mult = function (val, units) {
- return this._pushExpr(val, '*', units);
- };
- /**
- * Divide the current value by the given time.
- * @param {Time} val The value to divide by
- * @param {String=} units Optional units to use with the value.
- * @return {Tone.TimeBase} this
- * @example
- * Tone.TimeBase("2m").div(2); //"1m"
- */
- Tone.TimeBase.prototype.div = function (val, units) {
- return this._pushExpr(val, '/', units);
- };
- /**
- * Evaluate the time value. Returns the time
- * in seconds.
- * @return {Seconds}
- */
- Tone.TimeBase.prototype.valueOf = function () {
- return this._expr();
- };
- /**
- * Clean up
- * @return {Tone.TimeBase} this
- */
- Tone.TimeBase.prototype.dispose = function () {
- this._expr = null;
- };
- return Tone.TimeBase;
- });
- Module(function (Tone) {
- /**
- * @class Tone.Time is a primitive type for encoding Time values.
- * Eventually all time values are evaluated to seconds
- * using the `eval` method. Tone.Time can be constructed
- * with or without the `new` keyword. Tone.Time can be passed
- * into the parameter of any method which takes time as an argument.
- * @constructor
- * @extends {Tone.TimeBase}
- * @param {String|Number} val The time value.
- * @param {String=} units The units of the value.
- * @example
- * var t = Tone.Time("4n");//encodes a quarter note
- * t.mult(4); // multiply that value by 4
- * t.toNotation(); //returns "1m"
- */
- Tone.Time = function (val, units) {
- if (this instanceof Tone.Time) {
- /**
- * If the current clock time should
- * be added to the output
- * @type {Boolean}
- * @private
- */
- this._plusNow = false;
- Tone.TimeBase.call(this, val, units);
- } else {
- return new Tone.Time(val, units);
- }
- };
- Tone.extend(Tone.Time, Tone.TimeBase);
- //clone the expressions so that
- //we can add more without modifying the original
- Tone.Time.prototype._unaryExpressions = Object.create(Tone.TimeBase.prototype._unaryExpressions);
- /*
- * Adds an additional unary expression
- * which quantizes values to the next subdivision
- * @type {Object}
- * @private
- */
- Tone.Time.prototype._unaryExpressions.quantize = {
- regexp: /^@/,
- method: function (rh) {
- return Tone.Transport.nextSubdivision(rh());
- }
- };
- /*
- * Adds an additional unary expression
- * which adds the current clock time.
- * @type {Object}
- * @private
- */
- Tone.Time.prototype._unaryExpressions.now = {
- regexp: /^\+/,
- method: function (lh) {
- this._plusNow = true;
- return lh();
- }
- };
- /**
- * Quantize the time by the given subdivision. Optionally add a
- * percentage which will move the time value towards the ideal
- * quantized value by that percentage.
- * @param {Number|Time} val The subdivision to quantize to
- * @param {NormalRange} [percent=1] Move the time value
- * towards the quantized value by
- * a percentage.
- * @return {Tone.Time} this
- * @example
- * Tone.Time(21).quantize(2) //returns 22
- * Tone.Time(0.6).quantize("4n", 0.5) //returns 0.55
- */
- Tone.Time.prototype.quantize = function (subdiv, percent) {
- percent = Tone.defaultArg(percent, 1);
- this._expr = function (expr, subdivision, percent) {
- expr = expr();
- subdivision = subdivision.toSeconds();
- var multiple = Math.round(expr / subdivision);
- var ideal = multiple * subdivision;
- var diff = ideal - expr;
- return expr + diff * percent;
- }.bind(this, this._expr, new this.constructor(subdiv), percent);
- return this;
- };
- /**
- * Adds the clock time to the time expression at the
- * moment of evaluation.
- * @return {Tone.Time} this
- */
- Tone.Time.prototype.addNow = function () {
- this._plusNow = true;
- return this;
- };
- /**
- * Override the default value return when no arguments are passed in.
- * The default value is 'now'
- * @override
- * @private
- */
- Tone.Time.prototype._defaultExpr = function () {
- this._plusNow = true;
- return this._noOp;
- };
- /**
- * Copies the value of time to this Time
- * @param {Tone.Time} time
- * @return {Time}
- */
- Tone.Time.prototype.copy = function (time) {
- Tone.TimeBase.prototype.copy.call(this, time);
- this._plusNow = time._plusNow;
- return this;
- };
- //CONVERSIONS//////////////////////////////////////////////////////////////
- /**
- * Convert a Time to Notation. Values will be thresholded to the nearest 128th note.
- * @return {Notation}
- * @example
- * //if the Transport is at 120bpm:
- * Tone.Time(2).toNotation();//returns "1m"
- */
- Tone.Time.prototype.toNotation = function () {
- var time = this.toSeconds();
- var testNotations = [
- '1m',
- '2n',
- '4n',
- '8n',
- '16n',
- '32n',
- '64n',
- '128n'
- ];
- var retNotation = this._toNotationHelper(time, testNotations);
- //try the same thing but with tripelets
- var testTripletNotations = [
- '1m',
- '2n',
- '2t',
- '4n',
- '4t',
- '8n',
- '8t',
- '16n',
- '16t',
- '32n',
- '32t',
- '64n',
- '64t',
- '128n'
- ];
- var retTripletNotation = this._toNotationHelper(time, testTripletNotations);
- //choose the simpler expression of the two
- if (retTripletNotation.split('+').length < retNotation.split('+').length) {
- return retTripletNotation;
- } else {
- return retNotation;
- }
- };
- /**
- * Helper method for Tone.toNotation
- * @param {Number} units
- * @param {Array} testNotations
- * @return {String}
- * @private
- */
- Tone.Time.prototype._toNotationHelper = function (units, testNotations) {
- //the threshold is the last value in the array
- var threshold = this._notationToUnits(testNotations[testNotations.length - 1]);
- var retNotation = '';
- for (var i = 0; i < testNotations.length; i++) {
- var notationTime = this._notationToUnits(testNotations[i]);
- //account for floating point errors (i.e. round up if the value is 0.999999)
- var multiple = units / notationTime;
- var floatingPointError = 0.000001;
- if (1 - multiple % 1 < floatingPointError) {
- multiple += floatingPointError;
- }
- multiple = Math.floor(multiple);
- if (multiple > 0) {
- if (multiple === 1) {
- retNotation += testNotations[i];
- } else {
- retNotation += multiple.toString() + '*' + testNotations[i];
- }
- units -= multiple * notationTime;
- if (units < threshold) {
- break;
- } else {
- retNotation += ' + ';
- }
- }
- }
- if (retNotation === '') {
- retNotation = '0';
- }
- return retNotation;
- };
- /**
- * Convert a notation value to the current units
- * @param {Notation} notation
- * @return {Number}
- * @private
- */
- Tone.Time.prototype._notationToUnits = function (notation) {
- var primaryExprs = this._primaryExpressions;
- var notationExprs = [
- primaryExprs.n,
- primaryExprs.t,
- primaryExprs.m
- ];
- for (var i = 0; i < notationExprs.length; i++) {
- var expr = notationExprs[i];
- var match = notation.match(expr.regexp);
- if (match) {
- return expr.method.call(this, match[1]);
- }
- }
- };
- /**
- * Return the time encoded as Bars:Beats:Sixteenths.
- * @return {BarsBeatsSixteenths}
- */
- Tone.Time.prototype.toBarsBeatsSixteenths = function () {
- var quarterTime = this._beatsToUnits(1);
- var quarters = this.toSeconds() / quarterTime;
- var measures = Math.floor(quarters / this._timeSignature());
- var sixteenths = quarters % 1 * 4;
- quarters = Math.floor(quarters) % this._timeSignature();
- sixteenths = sixteenths.toString();
- if (sixteenths.length > 3) {
- // the additional parseFloat removes insignificant trailing zeroes
- sixteenths = parseFloat(parseFloat(sixteenths).toFixed(3));
- }
- var progress = [
- measures,
- quarters,
- sixteenths
- ];
- return progress.join(':');
- };
- /**
- * Return the time in ticks.
- * @return {Ticks}
- */
- Tone.Time.prototype.toTicks = function () {
- var quarterTime = this._beatsToUnits(1);
- var quarters = this.valueOf() / quarterTime;
- return Math.floor(quarters * Tone.Transport.PPQ);
- };
- /**
- * Return the time in samples
- * @return {Samples}
- */
- Tone.Time.prototype.toSamples = function () {
- return this.toSeconds() * this.context.sampleRate;
- };
- /**
- * Return the time as a frequency value
- * @return {Frequency}
- * @example
- * Tone.Time(2).toFrequency(); //0.5
- */
- Tone.Time.prototype.toFrequency = function () {
- return 1 / this.toSeconds();
- };
- /**
- * Return the time in seconds.
- * @return {Seconds}
- */
- Tone.Time.prototype.toSeconds = function () {
- return this.valueOf();
- };
- /**
- * Return the time in milliseconds.
- * @return {Milliseconds}
- */
- Tone.Time.prototype.toMilliseconds = function () {
- return this.toSeconds() * 1000;
- };
- /**
- * Return the time in seconds.
- * @return {Seconds}
- */
- Tone.Time.prototype.valueOf = function () {
- var val = this._expr();
- return val + (this._plusNow ? this.now() : 0);
- };
- return Tone.Time;
- });
- Module(function (Tone) {
- /**
- * @class Tone.Frequency is a primitive type for encoding Frequency values.
- * Eventually all time values are evaluated to hertz
- * using the `eval` method.
- * @constructor
- * @extends {Tone.TimeBase}
- * @param {String|Number} val The time value.
- * @param {String=} units The units of the value.
- * @example
- * Tone.Frequency("C3") // 261
- * Tone.Frequency(38, "midi") //
- * Tone.Frequency("C3").transpose(4);
- */
- Tone.Frequency = function (val, units) {
- if (this instanceof Tone.Frequency) {
- Tone.TimeBase.call(this, val, units);
- } else {
- return new Tone.Frequency(val, units);
- }
- };
- Tone.extend(Tone.Frequency, Tone.TimeBase);
- ///////////////////////////////////////////////////////////////////////////
- // AUGMENT BASE EXPRESSIONS
- ///////////////////////////////////////////////////////////////////////////
- //clone the expressions so that
- //we can add more without modifying the original
- Tone.Frequency.prototype._primaryExpressions = Object.create(Tone.TimeBase.prototype._primaryExpressions);
- /*
- * midi type primary expression
- * @type {Object}
- * @private
- */
- Tone.Frequency.prototype._primaryExpressions.midi = {
- regexp: /^(\d+(?:\.\d+)?midi)/,
- method: function (value) {
- return this.midiToFrequency(value);
- }
- };
- /*
- * note type primary expression
- * @type {Object}
- * @private
- */
- Tone.Frequency.prototype._primaryExpressions.note = {
- regexp: /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i,
- method: function (pitch, octave) {
- var index = noteToScaleIndex[pitch.toLowerCase()];
- var noteNumber = index + (parseInt(octave) + 1) * 12;
- return this.midiToFrequency(noteNumber);
- }
- };
- /*
- * BeatsBarsSixteenths type primary expression
- * @type {Object}
- * @private
- */
- Tone.Frequency.prototype._primaryExpressions.tr = {
- regexp: /^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,
- method: function (m, q, s) {
- var total = 1;
- if (m && m !== '0') {
- total *= this._beatsToUnits(this._timeSignature() * parseFloat(m));
- }
- if (q && q !== '0') {
- total *= this._beatsToUnits(parseFloat(q));
- }
- if (s && s !== '0') {
- total *= this._beatsToUnits(parseFloat(s) / 4);
- }
- return total;
- }
- };
- ///////////////////////////////////////////////////////////////////////////
- // EXPRESSIONS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Transposes the frequency by the given number of semitones.
- * @param {Interval} interval
- * @return {Tone.Frequency} this
- * @example
- * Tone.Frequency("A4").transpose(3); //"C5"
- */
- Tone.Frequency.prototype.transpose = function (interval) {
- this._expr = function (expr, interval) {
- var val = expr();
- return val * Tone.intervalToFrequencyRatio(interval);
- }.bind(this, this._expr, interval);
- return this;
- };
- /**
- * Takes an array of semitone intervals and returns
- * an array of frequencies transposed by those intervals.
- * @param {Array} intervals
- * @return {Tone.Frequency} this
- * @example
- * Tone.Frequency("A4").harmonize([0, 3, 7]); //["A4", "C5", "E5"]
- */
- Tone.Frequency.prototype.harmonize = function (intervals) {
- this._expr = function (expr, intervals) {
- var val = expr();
- var ret = [];
- for (var i = 0; i < intervals.length; i++) {
- ret[i] = val * Tone.intervalToFrequencyRatio(intervals[i]);
- }
- return ret;
- }.bind(this, this._expr, intervals);
- return this;
- };
- ///////////////////////////////////////////////////////////////////////////
- // UNIT CONVERSIONS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Return the value of the frequency as a MIDI note
- * @return {MIDI}
- * @example
- * Tone.Frequency("C4").toMidi(); //60
- */
- Tone.Frequency.prototype.toMidi = function () {
- return this.frequencyToMidi(this.valueOf());
- };
- /**
- * Return the value of the frequency in Scientific Pitch Notation
- * @return {Note}
- * @example
- * Tone.Frequency(69, "midi").toNote(); //"A4"
- */
- Tone.Frequency.prototype.toNote = function () {
- var freq = this.valueOf();
- var log = Math.log(freq / Tone.Frequency.A4) / Math.LN2;
- var noteNumber = Math.round(12 * log) + 57;
- var octave = Math.floor(noteNumber / 12);
- if (octave < 0) {
- noteNumber += -12 * octave;
- }
- var noteName = scaleIndexToNote[noteNumber % 12];
- return noteName + octave.toString();
- };
- /**
- * Return the duration of one cycle in seconds.
- * @return {Seconds}
- */
- Tone.Frequency.prototype.toSeconds = function () {
- return 1 / this.valueOf();
- };
- /**
- * Return the value in Hertz
- * @return {Frequency}
- */
- Tone.Frequency.prototype.toFrequency = function () {
- return this.valueOf();
- };
- /**
- * Return the duration of one cycle in ticks
- * @return {Ticks}
- */
- Tone.Frequency.prototype.toTicks = function () {
- var quarterTime = this._beatsToUnits(1);
- var quarters = this.valueOf() / quarterTime;
- return Math.floor(quarters * Tone.Transport.PPQ);
- };
- ///////////////////////////////////////////////////////////////////////////
- // UNIT CONVERSIONS HELPERS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Returns the value of a frequency in the current units
- * @param {Frequency} freq
- * @return {Number}
- * @private
- */
- Tone.Frequency.prototype._frequencyToUnits = function (freq) {
- return freq;
- };
- /**
- * Returns the value of a tick in the current time units
- * @param {Ticks} ticks
- * @return {Number}
- * @private
- */
- Tone.Frequency.prototype._ticksToUnits = function (ticks) {
- return 1 / (ticks * 60 / (Tone.Transport.bpm.value * Tone.Transport.PPQ));
- };
- /**
- * Return the value of the beats in the current units
- * @param {Number} beats
- * @return {Number}
- * @private
- */
- Tone.Frequency.prototype._beatsToUnits = function (beats) {
- return 1 / Tone.TimeBase.prototype._beatsToUnits.call(this, beats);
- };
- /**
- * Returns the value of a second in the current units
- * @param {Seconds} seconds
- * @return {Number}
- * @private
- */
- Tone.Frequency.prototype._secondsToUnits = function (seconds) {
- return 1 / seconds;
- };
- /**
- * The default units if none are given.
- * @private
- */
- Tone.Frequency.prototype._defaultUnits = 'hz';
- ///////////////////////////////////////////////////////////////////////////
- // FREQUENCY CONVERSIONS
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Note to scale index
- * @type {Object}
- */
- var noteToScaleIndex = {
- 'cbb': -2,
- 'cb': -1,
- 'c': 0,
- 'c#': 1,
- 'cx': 2,
- 'dbb': 0,
- 'db': 1,
- 'd': 2,
- 'd#': 3,
- 'dx': 4,
- 'ebb': 2,
- 'eb': 3,
- 'e': 4,
- 'e#': 5,
- 'ex': 6,
- 'fbb': 3,
- 'fb': 4,
- 'f': 5,
- 'f#': 6,
- 'fx': 7,
- 'gbb': 5,
- 'gb': 6,
- 'g': 7,
- 'g#': 8,
- 'gx': 9,
- 'abb': 7,
- 'ab': 8,
- 'a': 9,
- 'a#': 10,
- 'ax': 11,
- 'bbb': 9,
- 'bb': 10,
- 'b': 11,
- 'b#': 12,
- 'bx': 13
- };
- /**
- * scale index to note (sharps)
- * @type {Array}
- */
- var scaleIndexToNote = [
- 'C',
- 'C#',
- 'D',
- 'D#',
- 'E',
- 'F',
- 'F#',
- 'G',
- 'G#',
- 'A',
- 'A#',
- 'B'
- ];
- /**
- * The [concert pitch](https://en.wikipedia.org/wiki/Concert_pitch)
- * A4's values in Hertz.
- * @type {Frequency}
- * @static
- */
- Tone.Frequency.A4 = 440;
- /**
- * Convert a MIDI note to frequency value.
- * @param {MIDI} midi The midi number to convert.
- * @return {Frequency} the corresponding frequency value
- * @example
- * tone.midiToFrequency(69); // returns 440
- */
- Tone.Frequency.prototype.midiToFrequency = function (midi) {
- return Tone.Frequency.A4 * Math.pow(2, (midi - 69) / 12);
- };
- /**
- * Convert a frequency value to a MIDI note.
- * @param {Frequency} frequency The value to frequency value to convert.
- * @returns {MIDI}
- * @example
- * tone.midiToFrequency(440); // returns 69
- */
- Tone.Frequency.prototype.frequencyToMidi = function (frequency) {
- return 69 + Math.round(12 * Math.log(frequency / Tone.Frequency.A4) / Math.LN2);
- };
- return Tone.Frequency;
- });
- Module(function (Tone) {
- /**
- * @class Tone.TransportTime is a the time along the Transport's
- * timeline. It is similar to Tone.Time, but instead of evaluating
- * against the AudioContext's clock, it is evaluated against
- * the Transport's position. See [TransportTime wiki](https://github.com/Tonejs/Tone.js/wiki/TransportTime).
- * @constructor
- * @param {Time} val The time value as a number or string
- * @param {String=} units Unit values
- * @extends {Tone.Time}
- */
- Tone.TransportTime = function (val, units) {
- if (this instanceof Tone.TransportTime) {
- Tone.Time.call(this, val, units);
- } else {
- return new Tone.TransportTime(val, units);
- }
- };
- Tone.extend(Tone.TransportTime, Tone.Time);
- //clone the expressions so that
- //we can add more without modifying the original
- Tone.TransportTime.prototype._unaryExpressions = Object.create(Tone.Time.prototype._unaryExpressions);
- /**
- * Adds an additional unary expression
- * which quantizes values to the next subdivision
- * @type {Object}
- * @private
- */
- Tone.TransportTime.prototype._unaryExpressions.quantize = {
- regexp: /^@/,
- method: function (rh) {
- var subdivision = this._secondsToTicks(rh());
- var multiple = Math.ceil(Tone.Transport.ticks / subdivision);
- return this._ticksToUnits(multiple * subdivision);
- }
- };
- /**
- * Convert seconds into ticks
- * @param {Seconds} seconds
- * @return {Ticks}
- * @private
- */
- Tone.TransportTime.prototype._secondsToTicks = function (seconds) {
- var quarterTime = this._beatsToUnits(1);
- var quarters = seconds / quarterTime;
- return Math.round(quarters * Tone.Transport.PPQ);
- };
- /**
- * Evaluate the time expression. Returns values in ticks
- * @return {Ticks}
- */
- Tone.TransportTime.prototype.valueOf = function () {
- var val = this._secondsToTicks(this._expr());
- return val + (this._plusNow ? Tone.Transport.ticks : 0);
- };
- /**
- * Return the time in ticks.
- * @return {Ticks}
- */
- Tone.TransportTime.prototype.toTicks = function () {
- return this.valueOf();
- };
- /**
- * Return the time in seconds.
- * @return {Seconds}
- */
- Tone.TransportTime.prototype.toSeconds = function () {
- var val = this._expr();
- return val + (this._plusNow ? Tone.Transport.seconds : 0);
- };
- /**
- * Return the time as a frequency value
- * @return {Frequency}
- */
- Tone.TransportTime.prototype.toFrequency = function () {
- return 1 / this.toSeconds();
- };
- return Tone.TransportTime;
- });
- Module(function (Tone) {
- ///////////////////////////////////////////////////////////////////////////
- // TYPES
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Units which a value can take on.
- * @enum {String}
- */
- Tone.Type = {
- /**
- * Default units
- * @typedef {Default}
- */
- Default: 'number',
- /**
- * Time can be described in a number of ways. Read more [Time](https://github.com/Tonejs/Tone.js/wiki/Time).
- *
- * * Numbers, which will be taken literally as the time (in seconds).
- * * Notation, ("4n", "8t") describes time in BPM and time signature relative values.
- * * TransportTime, ("4:3:2") will also provide tempo and time signature relative times
- * in the form BARS:QUARTERS:SIXTEENTHS.
- * * Frequency, ("8hz") is converted to the length of the cycle in seconds.
- * * Now-Relative, ("+1") prefix any of the above with "+" and it will be interpreted as
- * "the current time plus whatever expression follows".
- * * Expressions, ("3:0 + 2 - (1m / 7)") any of the above can also be combined
- * into a mathematical expression which will be evaluated to compute the desired time.
- * * No Argument, for methods which accept time, no argument will be interpreted as
- * "now" (i.e. the currentTime).
- *
- * @typedef {Time}
- */
- Time: 'time',
- /**
- * Frequency can be described similar to time, except ultimately the
- * values are converted to frequency instead of seconds. A number
- * is taken literally as the value in hertz. Additionally any of the
- * Time encodings can be used. Note names in the form
- * of NOTE OCTAVE (i.e. C4) are also accepted and converted to their
- * frequency value.
- * @typedef {Frequency}
- */
- Frequency: 'frequency',
- /**
- * TransportTime describes a position along the Transport's timeline. It is
- * similar to Time in that it uses all the same encodings, but TransportTime specifically
- * pertains to the Transport's timeline, which is startable, stoppable, loopable, and seekable.
- * [Read more](https://github.com/Tonejs/Tone.js/wiki/TransportTime)
- * @typedef {TransportTime}
- */
- TransportTime: 'transportTime',
- /**
- * Ticks are the basic subunit of the Transport. They are
- * the smallest unit of time that the Transport supports.
- * @typedef {Ticks}
- */
- Ticks: 'ticks',
- /**
- * Normal values are within the range [0, 1].
- * @typedef {NormalRange}
- */
- NormalRange: 'normalRange',
- /**
- * AudioRange values are between [-1, 1].
- * @typedef {AudioRange}
- */
- AudioRange: 'audioRange',
- /**
- * Decibels are a logarithmic unit of measurement which is useful for volume
- * because of the logarithmic way that we perceive loudness. 0 decibels
- * means no change in volume. -10db is approximately half as loud and 10db
- * is twice is loud.
- * @typedef {Decibels}
- */
- Decibels: 'db',
- /**
- * Half-step note increments, i.e. 12 is an octave above the root. and 1 is a half-step up.
- * @typedef {Interval}
- */
- Interval: 'interval',
- /**
- * Beats per minute.
- * @typedef {BPM}
- */
- BPM: 'bpm',
- /**
- * The value must be greater than or equal to 0.
- * @typedef {Positive}
- */
- Positive: 'positive',
- /**
- * Gain is the ratio between input and output of a signal.
- * A gain of 0 is the same as silencing the signal. A gain of
- * 1, causes no change to the incoming signal.
- * @typedef {Gain}
- */
- Gain: 'gain',
- /**
- * A cent is a hundredth of a semitone.
- * @typedef {Cents}
- */
- Cents: 'cents',
- /**
- * Angle between 0 and 360.
- * @typedef {Degrees}
- */
- Degrees: 'degrees',
- /**
- * A number representing a midi note.
- * @typedef {MIDI}
- */
- MIDI: 'midi',
- /**
- * A colon-separated representation of time in the form of
- * Bars:Beats:Sixteenths.
- * @typedef {BarsBeatsSixteenths}
- */
- BarsBeatsSixteenths: 'barsBeatsSixteenths',
- /**
- * Sampling is the reduction of a continuous signal to a discrete signal.
- * Audio is typically sampled 44100 times per second.
- * @typedef {Samples}
- */
- Samples: 'samples',
- /**
- * Hertz are a frequency representation defined as one cycle per second.
- * @typedef {Hertz}
- */
- Hertz: 'hertz',
- /**
- * A frequency represented by a letter name,
- * accidental and octave. This system is known as
- * [Scientific Pitch Notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation).
- * @typedef {Note}
- */
- Note: 'note',
- /**
- * One millisecond is a thousandth of a second.
- * @typedef {Milliseconds}
- */
- Milliseconds: 'milliseconds',
- /**
- * Seconds are the time unit of the AudioContext. In the end,
- * all values need to be evaluated to seconds.
- * @typedef {Seconds}
- */
- Seconds: 'seconds',
- /**
- * A string representing a duration relative to a measure.
- * * "4n" = quarter note
- * * "2m" = two measures
- * * "8t" = eighth-note triplet
- * @typedef {Notation}
- */
- Notation: 'notation'
- };
- ///////////////////////////////////////////////////////////////////////////
- // AUGMENT TONE's PROTOTYPE
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Convert Time into seconds.
- *
- * Unlike the method which it overrides, this takes into account
- * transporttime and musical notation.
- *
- * Time : 1.40
- * Notation: 4n or 1m or 2t
- * Now Relative: +3n
- * Math: 3n+16n or even complicated expressions ((3n*2)/6 + 1)
- *
- * @param {Time} time
- * @return {Seconds}
- */
- Tone.prototype.toSeconds = function (time) {
- if (Tone.isNumber(time)) {
- return time;
- } else if (Tone.isUndef(time)) {
- return this.now();
- } else if (Tone.isString(time)) {
- return new Tone.Time(time).toSeconds();
- } else if (time instanceof Tone.TimeBase) {
- return time.toSeconds();
- }
- };
- /**
- * Convert a frequency representation into a number.
- * @param {Frequency} freq
- * @return {Hertz} the frequency in hertz
- */
- Tone.prototype.toFrequency = function (freq) {
- if (Tone.isNumber(freq)) {
- return freq;
- } else if (Tone.isString(freq) || Tone.isUndef(freq)) {
- return new Tone.Frequency(freq).valueOf();
- } else if (freq instanceof Tone.TimeBase) {
- return freq.toFrequency();
- }
- };
- /**
- * Convert a time representation into ticks.
- * @param {Time} time
- * @return {Ticks} the time in ticks
- */
- Tone.prototype.toTicks = function (time) {
- if (Tone.isNumber(time) || Tone.isString(time)) {
- return new Tone.TransportTime(time).toTicks();
- } else if (Tone.isUndef(time)) {
- return Tone.Transport.ticks;
- } else if (time instanceof Tone.TimeBase) {
- return time.toTicks();
- }
- };
- return Tone;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Param wraps the native Web Audio's AudioParam to provide
- * additional unit conversion functionality. It also
- * serves as a base-class for classes which have a single,
- * automatable parameter.
- * @extends {Tone.AudioNode}
- * @param {AudioParam} param The parameter to wrap.
- * @param {Tone.Type} units The units of the audio param.
- * @param {Boolean} convert If the param should be converted.
- */
- Tone.Param = function () {
- var options = Tone.defaults(arguments, [
- 'param',
- 'units',
- 'convert'
- ], Tone.Param);
- Tone.AudioNode.call(this);
- /**
- * The native parameter to control
- * @type {AudioParam}
- * @private
- */
- this._param = this.input = options.param;
- /**
- * The units of the parameter
- * @type {Tone.Type}
- */
- this.units = options.units;
- /**
- * If the value should be converted or not
- * @type {Boolean}
- */
- this.convert = options.convert;
- /**
- * True if the signal value is being overridden by
- * a connected signal.
- * @readOnly
- * @type {boolean}
- * @private
- */
- this.overridden = false;
- /**
- * If there is an LFO, this is where it is held.
- * @type {Tone.LFO}
- * @private
- */
- this._lfo = null;
- if (Tone.isObject(options.lfo)) {
- this.value = options.lfo;
- } else if (!Tone.isUndef(options.value)) {
- this.value = options.value;
- }
- };
- Tone.extend(Tone.Param, Tone.AudioNode);
- /**
- * Defaults
- * @type {Object}
- * @const
- */
- Tone.Param.defaults = {
- 'units': Tone.Type.Default,
- 'convert': true,
- 'param': undefined
- };
- /**
- * The current value of the parameter.
- * @memberOf Tone.Param#
- * @type {Number}
- * @name value
- */
- Object.defineProperty(Tone.Param.prototype, 'value', {
- get: function () {
- return this._toUnits(this._param.value);
- },
- set: function (value) {
- if (Tone.isObject(value)) {
- //throw an error if the LFO needs to be included
- if (Tone.isUndef(Tone.LFO)) {
- throw new Error('Include \'Tone.LFO\' to use an LFO as a Param value.');
- }
- //remove the old one
- if (this._lfo) {
- this._lfo.dispose();
- }
- this._lfo = new Tone.LFO(value).start();
- this._lfo.connect(this.input);
- } else {
- var convertedVal = this._fromUnits(value);
- this._param.cancelScheduledValues(0);
- this._param.value = convertedVal;
- }
- }
- });
- /**
- * Convert the given value from the type specified by Tone.Param.units
- * into the destination value (such as Gain or Frequency).
- * @private
- * @param {*} val the value to convert
- * @return {number} the number which the value should be set to
- */
- Tone.Param.prototype._fromUnits = function (val) {
- if (this.convert || Tone.isUndef(this.convert)) {
- switch (this.units) {
- case Tone.Type.Time:
- return this.toSeconds(val);
- case Tone.Type.Frequency:
- return this.toFrequency(val);
- case Tone.Type.Decibels:
- return Tone.dbToGain(val);
- case Tone.Type.NormalRange:
- return Math.min(Math.max(val, 0), 1);
- case Tone.Type.AudioRange:
- return Math.min(Math.max(val, -1), 1);
- case Tone.Type.Positive:
- return Math.max(val, 0);
- default:
- return val;
- }
- } else {
- return val;
- }
- };
- /**
- * Convert the parameters value into the units specified by Tone.Param.units.
- * @private
- * @param {number} val the value to convert
- * @return {number}
- */
- Tone.Param.prototype._toUnits = function (val) {
- if (this.convert || Tone.isUndef(this.convert)) {
- switch (this.units) {
- case Tone.Type.Decibels:
- return Tone.gainToDb(val);
- default:
- return val;
- }
- } else {
- return val;
- }
- };
- /**
- * the minimum output value
- * @type {Number}
- * @private
- */
- Tone.Param.prototype._minOutput = 0.00001;
- /**
- * Schedules a parameter value change at the given time.
- * @param {*} value The value to set the signal.
- * @param {Time} time The time when the change should occur.
- * @returns {Tone.Param} this
- * @example
- * //set the frequency to "G4" in exactly 1 second from now.
- * freq.setValueAtTime("G4", "+1");
- */
- Tone.Param.prototype.setValueAtTime = function (value, time) {
- time = this.toSeconds(time);
- Tone.isPast(time);
- this._param.setValueAtTime(this._fromUnits(value), time);
- return this;
- };
- /**
- * Creates a schedule point with the current value at the current time.
- * This is useful for creating an automation anchor point in order to
- * schedule changes from the current value.
- *
- * @param {number=} now (Optionally) pass the now value in.
- * @returns {Tone.Param} this
- */
- Tone.Param.prototype.setRampPoint = function (now) {
- now = Tone.defaultArg(now, this.now());
- this.cancelAndHoldAtTime(this.context.currentTime);
- var currentVal = this._param.value;
- if (currentVal === 0) {
- currentVal = this._minOutput;
- }
- // cancel and hold at the given time
- this._param.setValueAtTime(currentVal, now);
- return this;
- };
- /**
- * Schedules a linear continuous change in parameter value from the
- * previous scheduled parameter value to the given value.
- *
- * @param {number} value
- * @param {Time} endTime
- * @returns {Tone.Param} this
- */
- Tone.Param.prototype.linearRampToValueAtTime = function (value, endTime) {
- value = this._fromUnits(value);
- endTime = this.toSeconds(endTime);
- Tone.isPast(endTime);
- this._param.linearRampToValueAtTime(value, endTime);
- return this;
- };
- /**
- * Schedules an exponential continuous change in parameter value from
- * the previous scheduled parameter value to the given value.
- *
- * @param {number} value
- * @param {Time} endTime
- * @returns {Tone.Param} this
- */
- Tone.Param.prototype.exponentialRampToValueAtTime = function (value, endTime) {
- value = this._fromUnits(value);
- value = Math.max(this._minOutput, value);
- endTime = this.toSeconds(endTime);
- Tone.isPast(endTime);
- this._param.exponentialRampToValueAtTime(value, endTime);
- return this;
- };
- /**
- * Schedules an exponential continuous change in parameter value from
- * the current time and current value to the given value over the
- * duration of the rampTime.
- *
- * @param {number} value The value to ramp to.
- * @param {Time} rampTime the time that it takes the
- * value to ramp from it's current value
- * @param {Time} [startTime=now] When the ramp should start.
- * @returns {Tone.Param} this
- * @example
- * //exponentially ramp to the value 2 over 4 seconds.
- * signal.exponentialRampTo(2, 4);
- */
- Tone.Param.prototype.exponentialRampTo = function (value, rampTime, startTime) {
- startTime = this.toSeconds(startTime);
- this.setRampPoint(startTime);
- this.exponentialRampToValueAtTime(value, startTime + this.toSeconds(rampTime));
- return this;
- };
- /**
- * Schedules an linear continuous change in parameter value from
- * the current time and current value to the given value over the
- * duration of the rampTime.
- *
- * @param {number} value The value to ramp to.
- * @param {Time} rampTime the time that it takes the
- * value to ramp from it's current value
- * @param {Time} [startTime=now] When the ramp should start.
- * @returns {Tone.Param} this
- * @example
- * //linearly ramp to the value 4 over 3 seconds.
- * signal.linearRampTo(4, 3);
- */
- Tone.Param.prototype.linearRampTo = function (value, rampTime, startTime) {
- startTime = this.toSeconds(startTime);
- this.setRampPoint(startTime);
- this.linearRampToValueAtTime(value, startTime + this.toSeconds(rampTime));
- return this;
- };
- /**
- * Convert between Time and time constant. The time
- * constant returned can be used in setTargetAtTime.
- * @param {Time} time The time to convert
- * @return {Number} The time constant to get an exponentially approaching
- * curve to over 99% of towards the target value.
- */
- Tone.Param.prototype.getTimeConstant = function (time) {
- return Math.log(this.toSeconds(time) + 1) / Math.log(200);
- };
- /**
- * Start exponentially approaching the target value at the given time. Since it
- * is an exponential approach it will continue approaching after the ramp duration. The
- * rampTime is the time that it takes to reach over 99% of the way towards the value.
- * @param {number} value The value to ramp to.
- * @param {Time} rampTime the time that it takes the
- * value to ramp from it's current value
- * @param {Time} [startTime=now] When the ramp should start.
- * @returns {Tone.Param} this
- * @example
- * //exponentially ramp to the value 2 over 4 seconds.
- * signal.exponentialRampTo(2, 4);
- */
- Tone.Param.prototype.targetRampTo = function (value, rampTime, startTime) {
- startTime = this.toSeconds(startTime);
- this.setRampPoint(startTime);
- this.setTargetAtTime(value, startTime, this.getTimeConstant(rampTime));
- return this;
- };
- /**
- * Start exponentially approaching the target value at the given time with
- * a rate having the given time constant.
- * @param {number} value
- * @param {Time} startTime
- * @param {number} timeConstant
- * @returns {Tone.Param} this
- */
- Tone.Param.prototype.setTargetAtTime = function (value, startTime, timeConstant) {
- value = this._fromUnits(value);
- // The value will never be able to approach without timeConstant > 0.
- // http://www.w3.org/TR/webaudio/#dfn-setTargetAtTime, where the equation
- // is described. 0 results in a division by 0.
- value = Math.max(this._minOutput, value);
- timeConstant = Math.max(this._minOutput, timeConstant);
- this._param.setTargetAtTime(value, this.toSeconds(startTime), timeConstant);
- return this;
- };
- /**
- * Sets an array of arbitrary parameter values starting at the given time
- * for the given duration.
- *
- * @param {Array} values
- * @param {Time} startTime
- * @param {Time} duration
- * @returns {Tone.Param} this
- */
- Tone.Param.prototype.setValueCurveAtTime = function (values, startTime, duration) {
- duration = this.toSeconds(duration);
- startTime = this.toSeconds(startTime);
- this.setValueAtTime(values[0], startTime);
- var segTime = duration / (values.length - 1);
- for (var i = 1; i < values.length; i++) {
- this._param.linearRampToValueAtTime(this._fromUnits(values[i]), startTime + i * segTime);
- }
- return this;
- };
- /**
- * Cancels all scheduled parameter changes with times greater than or
- * equal to startTime.
- *
- * @param {Time} startTime
- * @returns {Tone.Param} this
- */
- Tone.Param.prototype.cancelScheduledValues = function (startTime) {
- this._param.cancelScheduledValues(this.toSeconds(startTime));
- return this;
- };
- /**
- * This is similar to [cancelScheduledValues](#cancelScheduledValues) except
- * it holds the automated value at cancelTime until the next automated event.
- * @param {Time} cancelTime
- * @returns {Tone.Param} this
- */
- Tone.Param.prototype.cancelAndHoldAtTime = function (cancelTime) {
- cancelTime = this.toSeconds(cancelTime);
- if (this._param.cancelAndHoldAtTime) {
- this._param.cancelAndHoldAtTime(cancelTime);
- } else {
- //fallback for unsupported browsers
- //can't cancel and hold at any time in the future
- //just do it immediately for gapless automation curves
- var now = this.context.currentTime;
- this._param.cancelScheduledValues(now);
- var currentVal = this._param.value;
- if (currentVal === 0) {
- currentVal = this._minOutput;
- }
- this._param.setValueAtTime(currentVal, now + this.sampleTime);
- }
- return this;
- };
- /**
- * Ramps to the given value over the duration of the rampTime.
- * Automatically selects the best ramp type (exponential or linear)
- * depending on the `units` of the signal
- *
- * @param {number} value
- * @param {Time} rampTime The time that it takes the
- * value to ramp from it's current value
- * @param {Time} [startTime=now] When the ramp should start.
- * @returns {Tone.Param} this
- * @example
- * //ramp to the value either linearly or exponentially
- * //depending on the "units" value of the signal
- * signal.rampTo(0, 10);
- * @example
- * //schedule it to ramp starting at a specific time
- * signal.rampTo(0, 10, 5)
- */
- Tone.Param.prototype.rampTo = function (value, rampTime, startTime) {
- rampTime = Tone.defaultArg(rampTime, 0.1);
- if (this.units === Tone.Type.Frequency || this.units === Tone.Type.BPM || this.units === Tone.Type.Decibels) {
- this.exponentialRampTo(value, rampTime, startTime);
- } else {
- this.linearRampTo(value, rampTime, startTime);
- }
- return this;
- };
- /**
- * The LFO created by the signal instance. If none
- * was created, this is null.
- * @type {Tone.LFO}
- * @readOnly
- * @memberOf Tone.Param#
- * @name lfo
- */
- Object.defineProperty(Tone.Param.prototype, 'lfo', {
- get: function () {
- return this._lfo;
- }
- });
- /**
- * Clean up
- * @returns {Tone.Param} this
- */
- Tone.Param.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._param = null;
- if (this._lfo) {
- this._lfo.dispose();
- this._lfo = null;
- }
- return this;
- };
- return Tone.Param;
- });
- Module(function (Tone) {
-
- /**
- * createGain shim
- * @private
- */
- if (window.GainNode && !AudioContext.prototype.createGain) {
- AudioContext.prototype.createGain = AudioContext.prototype.createGainNode;
- }
- /**
- * @class A thin wrapper around the Native Web Audio GainNode.
- * The GainNode is a basic building block of the Web Audio
- * API and is useful for routing audio and adjusting gains.
- * @extends {Tone}
- * @param {Number=} gain The initial gain of the GainNode
- * @param {Tone.Type=} units The units of the gain parameter.
- */
- Tone.Gain = function () {
- var options = Tone.defaults(arguments, [
- 'gain',
- 'units'
- ], Tone.Gain);
- Tone.AudioNode.call(this);
- /**
- * The GainNode
- * @type {GainNode}
- * @private
- */
- this.input = this.output = this._gainNode = this.context.createGain();
- /**
- * The gain parameter of the gain node.
- * @type {Gain}
- * @signal
- */
- this.gain = new Tone.Param({
- 'param': this._gainNode.gain,
- 'units': options.units,
- 'value': options.gain,
- 'convert': options.convert
- });
- this._readOnly('gain');
- };
- Tone.extend(Tone.Gain, Tone.AudioNode);
- /**
- * The defaults
- * @const
- * @type {Object}
- */
- Tone.Gain.defaults = {
- 'gain': 1,
- 'convert': true
- };
- /**
- * Clean up.
- * @return {Tone.Gain} this
- */
- Tone.Gain.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._gainNode.disconnect();
- this._gainNode = null;
- this._writable('gain');
- this.gain.dispose();
- this.gain = null;
- };
- return Tone.Gain;
- });
- Module(function (Tone) {
-
- /**
- * @class A signal is an audio-rate value. Tone.Signal is a core component of the library.
- * Unlike a number, Signals can be scheduled with sample-level accuracy. Tone.Signal
- * has all of the methods available to native Web Audio
- * [AudioParam](http://webaudio.github.io/web-audio-api/#the-audioparam-interface)
- * as well as additional conveniences. Read more about working with signals
- * [here](https://github.com/Tonejs/Tone.js/wiki/Signals).
- *
- * @constructor
- * @extends {Tone.Param}
- * @param {Number|AudioParam} [value] Initial value of the signal. If an AudioParam
- * is passed in, that parameter will be wrapped
- * and controlled by the Signal.
- * @param {string} [units=Number] unit The units the signal is in.
- * @example
- * var signal = new Tone.Signal(10);
- */
- Tone.Signal = function () {
- var options = Tone.defaults(arguments, [
- 'value',
- 'units'
- ], Tone.Signal);
- var gainNode = Tone.context.createGain();
- options.param = gainNode.gain;
- Tone.Param.call(this, options);
- /**
- * The node where the constant signal value is scaled.
- * @type {GainNode}
- * @private
- */
- this.output = gainNode;
- /**
- * The node where the value is set.
- * @type {Tone.Param}
- * @private
- */
- this.input = this._param = this.output.gain;
- //connect the const output to the node output
- this.context.getConstant(1).connect(this.output);
- };
- Tone.extend(Tone.Signal, Tone.Param);
- /**
- * The default values
- * @type {Object}
- * @static
- * @const
- */
- Tone.Signal.defaults = {
- 'value': 0,
- 'units': Tone.Type.Default,
- 'convert': true
- };
- /**
- * When signals connect to other signals or AudioParams,
- * they take over the output value of that signal or AudioParam.
- * For all other nodes, the behavior is the same as a default connect.
- *
- * @override
- * @param {AudioParam|AudioNode|Tone.Signal|Tone} node
- * @param {number} [outputNumber=0] The output number to connect from.
- * @param {number} [inputNumber=0] The input number to connect to.
- * @returns {Tone.SignalBase} this
- * @method
- */
- Tone.Signal.prototype.connect = Tone.SignalBase.prototype.connect;
- /**
- * dispose and disconnect
- * @returns {Tone.Signal} this
- */
- Tone.Signal.prototype.dispose = function () {
- Tone.Param.prototype.dispose.call(this);
- return this;
- };
- return Tone.Signal;
- });
- Module(function (Tone) {
-
- /**
- * @class A signal which adds the method getValueAtTime.
- * Code and inspiration from https://github.com/jsantell/web-audio-automation-timeline
- * @extends {Tone.Signal}
- * @param {Number=} value The initial value of the signal
- * @param {String=} units The conversion units of the signal.
- */
- Tone.TimelineSignal = function () {
- var options = Tone.defaults(arguments, [
- 'value',
- 'units'
- ], Tone.Signal);
- Tone.Signal.call(this, options);
- /**
- * The scheduled events
- * @type {Tone.Timeline}
- * @private
- */
- this._events = new Tone.Timeline(100);
- /**
- * The initial scheduled value
- * @type {Number}
- * @private
- */
- this._initial = this._fromUnits(this._param.value);
- this.value = options.value;
- //delete the input node so that nothing can overwrite the signal value
- delete this.input;
- };
- Tone.extend(Tone.TimelineSignal, Tone.Signal);
- /**
- * The event types of a schedulable signal.
- * @enum {String}
- * @private
- */
- Tone.TimelineSignal.Type = {
- Linear: 'linear',
- Exponential: 'exponential',
- Target: 'target',
- Set: 'set'
- };
- /**
- * The current value of the signal.
- * @memberOf Tone.TimelineSignal#
- * @type {Number}
- * @name value
- */
- Object.defineProperty(Tone.TimelineSignal.prototype, 'value', {
- get: function () {
- var now = this.now();
- var val = this.getValueAtTime(now);
- return this._toUnits(val);
- },
- set: function (value) {
- if (this._events) {
- var convertedVal = this._fromUnits(value);
- this._initial = convertedVal;
- this.cancelScheduledValues();
- this._param.value = convertedVal;
- }
- }
- });
- ///////////////////////////////////////////////////////////////////////////
- // SCHEDULING
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Schedules a parameter value change at the given time.
- * @param {*} value The value to set the signal.
- * @param {Time} time The time when the change should occur.
- * @returns {Tone.TimelineSignal} this
- * @example
- * //set the frequency to "G4" in exactly 1 second from now.
- * freq.setValueAtTime("G4", "+1");
- */
- Tone.TimelineSignal.prototype.setValueAtTime = function (value, startTime) {
- value = this._fromUnits(value);
- startTime = this.toSeconds(startTime);
- this._events.add({
- 'type': Tone.TimelineSignal.Type.Set,
- 'value': value,
- 'time': startTime
- });
- //invoke the original event
- this._param.setValueAtTime(value, startTime);
- return this;
- };
- /**
- * Schedules a linear continuous change in parameter value from the
- * previous scheduled parameter value to the given value.
- *
- * @param {number} value
- * @param {Time} endTime
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.linearRampToValueAtTime = function (value, endTime) {
- value = this._fromUnits(value);
- endTime = this.toSeconds(endTime);
- this._events.add({
- 'type': Tone.TimelineSignal.Type.Linear,
- 'value': value,
- 'time': endTime
- });
- this._param.linearRampToValueAtTime(value, endTime);
- return this;
- };
- /**
- * Schedules an exponential continuous change in parameter value from
- * the previous scheduled parameter value to the given value.
- *
- * @param {number} value
- * @param {Time} endTime
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.exponentialRampToValueAtTime = function (value, endTime) {
- //get the previous event and make sure it's not starting from 0
- endTime = this.toSeconds(endTime);
- var beforeEvent = this._searchBefore(endTime);
- if (beforeEvent && beforeEvent.value === 0) {
- //reschedule that event
- this.setValueAtTime(this._minOutput, beforeEvent.time);
- }
- value = this._fromUnits(value);
- var setValue = Math.max(value, this._minOutput);
- this._events.add({
- 'type': Tone.TimelineSignal.Type.Exponential,
- 'value': setValue,
- 'time': endTime
- });
- //if the ramped to value is 0, make it go to the min output, and then set to 0.
- if (value < this._minOutput) {
- this._param.exponentialRampToValueAtTime(this._minOutput, endTime - this.sampleTime);
- this.setValueAtTime(0, endTime);
- } else {
- this._param.exponentialRampToValueAtTime(value, endTime);
- }
- return this;
- };
- /**
- * Start exponentially approaching the target value at the given time with
- * a rate having the given time constant.
- * @param {number} value
- * @param {Time} startTime
- * @param {number} timeConstant
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.setTargetAtTime = function (value, startTime, timeConstant) {
- value = this._fromUnits(value);
- value = Math.max(this._minOutput, value);
- timeConstant = Math.max(this._minOutput, timeConstant);
- startTime = this.toSeconds(startTime);
- this._events.add({
- 'type': Tone.TimelineSignal.Type.Target,
- 'value': value,
- 'time': startTime,
- 'constant': timeConstant
- });
- this._param.setTargetAtTime(value, startTime, timeConstant);
- return this;
- };
- /**
- * Set an array of arbitrary values starting at the given time for the given duration.
- * @param {Float32Array} values
- * @param {Time} startTime
- * @param {Time} duration
- * @param {NormalRange} [scaling=1] If the values in the curve should be scaled by some value
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.setValueCurveAtTime = function (values, startTime, duration, scaling) {
- scaling = Tone.defaultArg(scaling, 1);
- duration = this.toSeconds(duration);
- startTime = this.toSeconds(startTime);
- var segTime = duration / (values.length - 1);
- this.setValueAtTime(values[0] * scaling, startTime);
- for (var i = 1; i < values.length; i++) {
- this.linearRampToValueAtTime(values[i] * scaling, startTime + i * segTime);
- }
- return this;
- };
- /**
- * Cancels all scheduled parameter changes with times greater than or
- * equal to startTime.
- * @param {Time} startTime
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.cancelScheduledValues = function (after) {
- after = this.toSeconds(after);
- this._events.cancel(after);
- this._param.cancelScheduledValues(after);
- return this;
- };
- /**
- * Cancels all scheduled parameter changes with times greater than or
- * equal to cancelTime and sets the output of the signal to be the value
- * at cancelTime. Similar to (cancelScheduledValues)[#cancelscheduledvalues].
- * @param {Time} cancelTime
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.cancelAndHoldAtTime = function (cancelTime) {
- this.setRampPoint(this.toSeconds(cancelTime));
- return this;
- };
- /**
- * Sets the computed value at the given time. This provides
- * a point from which a linear or exponential curve
- * can be scheduled after. Will cancel events after
- * the given time and shorten the currently scheduled
- * linear or exponential ramp so that it ends at `time` .
- * This is to avoid discontinuities and clicks in envelopes.
- * @param {Time} time When to set the ramp point
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.setRampPoint = function (time) {
- time = this.toSeconds(time);
- //get the value at the given time
- var val = this._toUnits(this.getValueAtTime(time));
- //if there is an event at the given time
- //and that even is not a "set"
- var before = this._searchBefore(time);
- if (before && before.time === time) {
- //remove everything after
- this.cancelScheduledValues(time + this.sampleTime);
- } else {
- //reschedule the next event to end at the given time
- var after = this._searchAfter(time);
- if (after) {
- //cancel the next event(s)
- this.cancelScheduledValues(time);
- if (after.type === Tone.TimelineSignal.Type.Linear) {
- this.linearRampToValueAtTime(val, time);
- } else if (after.type === Tone.TimelineSignal.Type.Exponential) {
- this.exponentialRampToValueAtTime(val, time);
- }
- }
- }
- this.setValueAtTime(val, time);
- return this;
- };
- /**
- * Do a linear ramp to the given value between the start and finish times.
- * @param {Number} value The value to ramp to.
- * @param {Time} start The beginning anchor point to do the linear ramp
- * @param {Time} finish The ending anchor point by which the value of
- * the signal will equal the given value.
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.linearRampToValueBetween = function (value, start, finish) {
- this.setRampPoint(start);
- this.linearRampToValueAtTime(value, finish);
- return this;
- };
- /**
- * Do a exponential ramp to the given value between the start and finish times.
- * @param {Number} value The value to ramp to.
- * @param {Time} start The beginning anchor point to do the exponential ramp
- * @param {Time} finish The ending anchor point by which the value of
- * the signal will equal the given value.
- * @returns {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.exponentialRampToValueBetween = function (value, start, finish) {
- this.setRampPoint(start);
- this.exponentialRampToValueAtTime(value, finish);
- return this;
- };
- ///////////////////////////////////////////////////////////////////////////
- // GETTING SCHEDULED VALUES
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Returns the value before or equal to the given time
- * @param {Number} time The time to query
- * @return {Object} The event at or before the given time.
- * @private
- */
- Tone.TimelineSignal.prototype._searchBefore = function (time) {
- return this._events.get(time);
- };
- /**
- * The event after the given time
- * @param {Number} time The time to query.
- * @return {Object} The next event after the given time
- * @private
- */
- Tone.TimelineSignal.prototype._searchAfter = function (time) {
- return this._events.getAfter(time);
- };
- /**
- * Get the scheduled value at the given time. This will
- * return the unconverted (raw) value.
- * @param {Number} time The time in seconds.
- * @return {Number} The scheduled value at the given time.
- */
- Tone.TimelineSignal.prototype.getValueAtTime = function (time) {
- time = this.toSeconds(time);
- var after = this._searchAfter(time);
- var before = this._searchBefore(time);
- var value = this._initial;
- //if it was set by
- if (before === null) {
- value = this._initial;
- } else if (before.type === Tone.TimelineSignal.Type.Target) {
- var previous = this._events.getBefore(before.time);
- var previousVal;
- if (previous === null) {
- previousVal = this._initial;
- } else {
- previousVal = previous.value;
- }
- value = this._exponentialApproach(before.time, previousVal, before.value, before.constant, time);
- } else if (after === null) {
- value = before.value;
- } else if (after.type === Tone.TimelineSignal.Type.Linear) {
- value = this._linearInterpolate(before.time, before.value, after.time, after.value, time);
- } else if (after.type === Tone.TimelineSignal.Type.Exponential) {
- value = this._exponentialInterpolate(before.time, before.value, after.time, after.value, time);
- } else {
- value = before.value;
- }
- return value;
- };
- /**
- * When signals connect to other signals or AudioParams,
- * they take over the output value of that signal or AudioParam.
- * For all other nodes, the behavior is the same as a default connect.
- *
- * @override
- * @param {AudioParam|AudioNode|Tone.Signal|Tone} node
- * @param {number} [outputNumber=0] The output number to connect from.
- * @param {number} [inputNumber=0] The input number to connect to.
- * @returns {Tone.TimelineSignal} this
- * @method
- */
- Tone.TimelineSignal.prototype.connect = Tone.SignalBase.prototype.connect;
- ///////////////////////////////////////////////////////////////////////////
- // AUTOMATION CURVE CALCULATIONS
- // MIT License, copyright (c) 2014 Jordan Santell
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Calculates the the value along the curve produced by setTargetAtTime
- * @private
- */
- Tone.TimelineSignal.prototype._exponentialApproach = function (t0, v0, v1, timeConstant, t) {
- return v1 + (v0 - v1) * Math.exp(-(t - t0) / timeConstant);
- };
- /**
- * Calculates the the value along the curve produced by linearRampToValueAtTime
- * @private
- */
- Tone.TimelineSignal.prototype._linearInterpolate = function (t0, v0, t1, v1, t) {
- return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
- };
- /**
- * Calculates the the value along the curve produced by exponentialRampToValueAtTime
- * @private
- */
- Tone.TimelineSignal.prototype._exponentialInterpolate = function (t0, v0, t1, v1, t) {
- v0 = Math.max(this._minOutput, v0);
- return v0 * Math.pow(v1 / v0, (t - t0) / (t1 - t0));
- };
- /**
- * Clean up.
- * @return {Tone.TimelineSignal} this
- */
- Tone.TimelineSignal.prototype.dispose = function () {
- Tone.Signal.prototype.dispose.call(this);
- this._events.dispose();
- this._events = null;
- };
- return Tone.TimelineSignal;
- });
- Module(function (Tone) {
-
- /**
- * @class Pow applies an exponent to the incoming signal. The incoming signal
- * must be AudioRange.
- *
- * @extends {Tone.SignalBase}
- * @constructor
- * @param {Positive} exp The exponent to apply to the incoming signal, must be at least 2.
- * @example
- * var pow = new Tone.Pow(2);
- * var sig = new Tone.Signal(0.5).connect(pow);
- * //output of pow is 0.25.
- */
- Tone.Pow = function (exp) {
- Tone.SignalBase.call(this);
- /**
- * the exponent
- * @private
- * @type {number}
- */
- this._exp = Tone.defaultArg(exp, 1);
- /**
- * @type {WaveShaperNode}
- * @private
- */
- this._expScaler = this.input = this.output = new Tone.WaveShaper(this._expFunc(this._exp), 8192);
- };
- Tone.extend(Tone.Pow, Tone.SignalBase);
- /**
- * The value of the exponent.
- * @memberOf Tone.Pow#
- * @type {number}
- * @name value
- */
- Object.defineProperty(Tone.Pow.prototype, 'value', {
- get: function () {
- return this._exp;
- },
- set: function (exp) {
- this._exp = exp;
- this._expScaler.setMap(this._expFunc(this._exp));
- }
- });
- /**
- * the function which maps the waveshaper
- * @param {number} exp
- * @return {function}
- * @private
- */
- Tone.Pow.prototype._expFunc = function (exp) {
- return function (val) {
- return Math.pow(Math.abs(val), exp);
- };
- };
- /**
- * Clean up.
- * @returns {Tone.Pow} this
- */
- Tone.Pow.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._expScaler.dispose();
- this._expScaler = null;
- return this;
- };
- return Tone.Pow;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Envelope is an [ADSR](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope)
- * envelope generator. Tone.Envelope outputs a signal which
- * can be connected to an AudioParam or Tone.Signal.
- *
- *
- * @constructor
- * @extends {Tone.AudioNode}
- * @param {Time} [attack] The amount of time it takes for the envelope to go from
- * 0 to it's maximum value.
- * @param {Time} [decay] The period of time after the attack that it takes for the envelope
- * to fall to the sustain value.
- * @param {NormalRange} [sustain] The percent of the maximum value that the envelope rests at until
- * the release is triggered.
- * @param {Time} [release] The amount of time after the release is triggered it takes to reach 0.
- * @example
- * //an amplitude envelope
- * var gainNode = Tone.context.createGain();
- * var env = new Tone.Envelope({
- * "attack" : 0.1,
- * "decay" : 0.2,
- * "sustain" : 1,
- * "release" : 0.8,
- * });
- * env.connect(gainNode.gain);
- */
- Tone.Envelope = function () {
- //get all of the defaults
- var options = Tone.defaults(arguments, [
- 'attack',
- 'decay',
- 'sustain',
- 'release'
- ], Tone.Envelope);
- Tone.AudioNode.call(this);
- /**
- * When triggerAttack is called, the attack time is the amount of
- * time it takes for the envelope to reach it's maximum value.
- * @type {Time}
- */
- this.attack = options.attack;
- /**
- * After the attack portion of the envelope, the value will fall
- * over the duration of the decay time to it's sustain value.
- * @type {Time}
- */
- this.decay = options.decay;
- /**
- * The sustain value is the value
- * which the envelope rests at after triggerAttack is
- * called, but before triggerRelease is invoked.
- * @type {NormalRange}
- */
- this.sustain = options.sustain;
- /**
- * After triggerRelease is called, the envelope's
- * value will fall to it's miminum value over the
- * duration of the release time.
- * @type {Time}
- */
- this.release = options.release;
- /**
- * the next time the envelope is at standby
- * @type {number}
- * @private
- */
- this._attackCurve = 'linear';
- /**
- * the next time the envelope is at standby
- * @type {number}
- * @private
- */
- this._releaseCurve = 'exponential';
- /**
- * the signal
- * @type {Tone.TimelineSignal}
- * @private
- */
- this._sig = this.output = new Tone.TimelineSignal();
- this._sig.setValueAtTime(0, 0);
- //set the attackCurve initially
- this.attackCurve = options.attackCurve;
- this.releaseCurve = options.releaseCurve;
- };
- Tone.extend(Tone.Envelope, Tone.AudioNode);
- /**
- * the default parameters
- * @static
- * @const
- */
- Tone.Envelope.defaults = {
- 'attack': 0.01,
- 'decay': 0.1,
- 'sustain': 0.5,
- 'release': 1,
- 'attackCurve': 'linear',
- 'releaseCurve': 'exponential'
- };
- /**
- * Read the current value of the envelope. Useful for
- * syncronizing visual output to the envelope.
- * @memberOf Tone.Envelope#
- * @type {Number}
- * @name value
- * @readOnly
- */
- Object.defineProperty(Tone.Envelope.prototype, 'value', {
- get: function () {
- return this.getValueAtTime(this.now());
- }
- });
- /**
- * The shape of the attack.
- * Can be any of these strings:
- *
input[0]
- * and input[1]. If a value is passed into the constructor,
- * the it will be added to the input.
- *
- * @constructor
- * @extends {Tone.Signal}
- * @param {number=} value If no value is provided, Tone.Add will sum the first
- * and second inputs.
- * @example
- * var signal = new Tone.Signal(2);
- * var add = new Tone.Add(2);
- * signal.connect(add);
- * //the output of add equals 4
- * @example
- * //if constructed with no arguments
- * //it will add the first and second inputs
- * var add = new Tone.Add();
- * var sig0 = new Tone.Signal(3).connect(add, 0, 0);
- * var sig1 = new Tone.Signal(4).connect(add, 0, 1);
- * //the output of add equals 7.
- */
- Tone.Add = function (value) {
- Tone.Signal.call(this);
- this.createInsOuts(2, 0);
- /**
- * the summing node
- * @type {GainNode}
- * @private
- */
- this._sum = this.input[0] = this.input[1] = this.output = new Tone.Gain();
- /**
- * @private
- * @type {Tone.Signal}
- */
- this._param = this.input[1] = new Tone.Signal(value);
- this._param.connect(this._sum);
- };
- Tone.extend(Tone.Add, Tone.Signal);
- /**
- * Clean up.
- * @returns {Tone.Add} this
- */
- Tone.Add.prototype.dispose = function () {
- Tone.Signal.prototype.dispose.call(this);
- this._sum.dispose();
- this._sum = null;
- return this;
- };
- return Tone.Add;
- });
- Module(function (Tone) {
-
- /**
- * @class Multiply two incoming signals. Or, if a number is given in the constructor,
- * multiplies the incoming signal by that value.
- *
- * @constructor
- * @extends {Tone.Signal}
- * @param {number=} value Constant value to multiple. If no value is provided,
- * it will return the product of the first and second inputs
- * @example
- * var mult = new Tone.Multiply();
- * var sigA = new Tone.Signal(3);
- * var sigB = new Tone.Signal(4);
- * sigA.connect(mult, 0, 0);
- * sigB.connect(mult, 0, 1);
- * //output of mult is 12.
- * @example
- * var mult = new Tone.Multiply(10);
- * var sig = new Tone.Signal(2).connect(mult);
- * //the output of mult is 20.
- */
- Tone.Multiply = function (value) {
- Tone.Signal.call(this);
- this.createInsOuts(2, 0);
- /**
- * the input node is the same as the output node
- * it is also the GainNode which handles the scaling of incoming signal
- *
- * @type {GainNode}
- * @private
- */
- this._mult = this.input[0] = this.output = new Tone.Gain();
- /**
- * the scaling parameter
- * @type {AudioParam}
- * @private
- */
- this._param = this.input[1] = this.output.gain;
- this._param.value = Tone.defaultArg(value, 0);
- };
- Tone.extend(Tone.Multiply, Tone.Signal);
- /**
- * clean up
- * @returns {Tone.Multiply} this
- */
- Tone.Multiply.prototype.dispose = function () {
- Tone.Signal.prototype.dispose.call(this);
- this._mult.dispose();
- this._mult = null;
- this._param = null;
- return this;
- };
- return Tone.Multiply;
- });
- Module(function (Tone) {
-
- /**
- * @class Negate the incoming signal. i.e. an input signal of 10 will output -10
- *
- * @constructor
- * @extends {Tone.SignalBase}
- * @example
- * var neg = new Tone.Negate();
- * var sig = new Tone.Signal(-2).connect(neg);
- * //output of neg is positive 2.
- */
- Tone.Negate = function () {
- Tone.SignalBase.call(this);
- /**
- * negation is done by multiplying by -1
- * @type {Tone.Multiply}
- * @private
- */
- this._multiply = this.input = this.output = new Tone.Multiply(-1);
- };
- Tone.extend(Tone.Negate, Tone.SignalBase);
- /**
- * clean up
- * @returns {Tone.Negate} this
- */
- Tone.Negate.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._multiply.dispose();
- this._multiply = null;
- return this;
- };
- return Tone.Negate;
- });
- Module(function (Tone) {
-
- /**
- * @class Subtract the signal connected to input[1] from the signal connected
- * to input[0]. If an argument is provided in the constructor, the
- * signals .value will be subtracted from the incoming signal.
- *
- * @extends {Tone.Signal}
- * @constructor
- * @param {number=} value The value to subtract from the incoming signal. If the value
- * is omitted, it will subtract the second signal from the first.
- * @example
- * var sub = new Tone.Subtract(1);
- * var sig = new Tone.Signal(4).connect(sub);
- * //the output of sub is 3.
- * @example
- * var sub = new Tone.Subtract();
- * var sigA = new Tone.Signal(10);
- * var sigB = new Tone.Signal(2.5);
- * sigA.connect(sub, 0, 0);
- * sigB.connect(sub, 0, 1);
- * //output of sub is 7.5
- */
- Tone.Subtract = function (value) {
- Tone.Signal.call(this);
- this.createInsOuts(2, 0);
- /**
- * the summing node
- * @type {GainNode}
- * @private
- */
- this._sum = this.input[0] = this.output = new Tone.Gain();
- /**
- * negate the input of the second input before connecting it
- * to the summing node.
- * @type {Tone.Negate}
- * @private
- */
- this._neg = new Tone.Negate();
- /**
- * the node where the value is set
- * @private
- * @type {Tone.Signal}
- */
- this._param = this.input[1] = new Tone.Signal(value);
- this._param.chain(this._neg, this._sum);
- };
- Tone.extend(Tone.Subtract, Tone.Signal);
- /**
- * Clean up.
- * @returns {Tone.SignalBase} this
- */
- Tone.Subtract.prototype.dispose = function () {
- Tone.Signal.prototype.dispose.call(this);
- this._neg.dispose();
- this._neg = null;
- this._sum.disconnect();
- this._sum = null;
- return this;
- };
- return Tone.Subtract;
- });
- Module(function (Tone) {
-
- /**
- * @class GreaterThanZero outputs 1 when the input is strictly greater than zero
- *
- * @constructor
- * @extends {Tone.SignalBase}
- * @example
- * var gt0 = new Tone.GreaterThanZero();
- * var sig = new Tone.Signal(0.01).connect(gt0);
- * //the output of gt0 is 1.
- * sig.value = 0;
- * //the output of gt0 is 0.
- */
- Tone.GreaterThanZero = function () {
- Tone.SignalBase.call(this);
- /**
- * @type {Tone.WaveShaper}
- * @private
- */
- this._thresh = this.output = new Tone.WaveShaper(function (val) {
- if (val <= 0) {
- return 0;
- } else {
- return 1;
- }
- }, 127);
- /**
- * scale the first thresholded signal by a large value.
- * this will help with values which are very close to 0
- * @type {Tone.Multiply}
- * @private
- */
- this._scale = this.input = new Tone.Multiply(10000);
- //connections
- this._scale.connect(this._thresh);
- };
- Tone.extend(Tone.GreaterThanZero, Tone.SignalBase);
- /**
- * dispose method
- * @returns {Tone.GreaterThanZero} this
- */
- Tone.GreaterThanZero.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._scale.dispose();
- this._scale = null;
- this._thresh.dispose();
- this._thresh = null;
- return this;
- };
- return Tone.GreaterThanZero;
- });
- Module(function (Tone) {
-
- /**
- * @class Output 1 if the signal is greater than the value, otherwise outputs 0.
- * can compare two signals or a signal and a number.
- *
- * @constructor
- * @extends {Tone.Signal}
- * @param {number} [value=0] the value to compare to the incoming signal
- * @example
- * var gt = new Tone.GreaterThan(2);
- * var sig = new Tone.Signal(4).connect(gt);
- * //output of gt is equal 1.
- */
- Tone.GreaterThan = function (value) {
- Tone.Signal.call(this);
- this.createInsOuts(2, 0);
- /**
- * subtract the amount from the incoming signal
- * @type {Tone.Subtract}
- * @private
- */
- this._param = this.input[0] = new Tone.Subtract(value);
- this.input[1] = this._param.input[1];
- /**
- * compare that amount to zero
- * @type {Tone.GreaterThanZero}
- * @private
- */
- this._gtz = this.output = new Tone.GreaterThanZero();
- //connect
- this._param.connect(this._gtz);
- };
- Tone.extend(Tone.GreaterThan, Tone.Signal);
- /**
- * dispose method
- * @returns {Tone.GreaterThan} this
- */
- Tone.GreaterThan.prototype.dispose = function () {
- Tone.Signal.prototype.dispose.call(this);
- this._gtz.dispose();
- this._gtz = null;
- return this;
- };
- return Tone.GreaterThan;
- });
- Module(function (Tone) {
-
- /**
- * @class Return the absolute value of an incoming signal.
- *
- * @constructor
- * @extends {Tone.SignalBase}
- * @example
- * var signal = new Tone.Signal(-1);
- * var abs = new Tone.Abs();
- * signal.connect(abs);
- * //the output of abs is 1.
- */
- Tone.Abs = function () {
- Tone.SignalBase.call(this);
- /**
- * @type {Tone.LessThan}
- * @private
- */
- this._abs = this.input = this.output = new Tone.WaveShaper(function (val) {
- if (val === 0) {
- return 0;
- } else {
- return Math.abs(val);
- }
- }, 127);
- };
- Tone.extend(Tone.Abs, Tone.SignalBase);
- /**
- * dispose method
- * @returns {Tone.Abs} this
- */
- Tone.Abs.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._abs.dispose();
- this._abs = null;
- return this;
- };
- return Tone.Abs;
- });
- Module(function (Tone) {
-
- /**
- * @class Signal-rate modulo operator. Only works in AudioRange [-1, 1] and for modulus
- * values in the NormalRange.
- *
- * @constructor
- * @extends {Tone.SignalBase}
- * @param {NormalRange} modulus The modulus to apply.
- * @example
- * var mod = new Tone.Modulo(0.2)
- * var sig = new Tone.Signal(0.5).connect(mod);
- * //mod outputs 0.1
- */
- Tone.Modulo = function (modulus) {
- Tone.SignalBase.call(this);
- this.createInsOuts(1, 0);
- /**
- * A waveshaper gets the integer multiple of
- * the input signal and the modulus.
- * @private
- * @type {Tone.WaveShaper}
- */
- this._shaper = new Tone.WaveShaper(Math.pow(2, 16));
- /**
- * the integer multiple is multiplied by the modulus
- * @type {Tone.Multiply}
- * @private
- */
- this._multiply = new Tone.Multiply();
- /**
- * and subtracted from the input signal
- * @type {Tone.Subtract}
- * @private
- */
- this._subtract = this.output = new Tone.Subtract();
- /**
- * the modulus signal
- * @type {Tone.Signal}
- * @private
- */
- this._modSignal = new Tone.Signal(modulus);
- //connections
- this.input.fan(this._shaper, this._subtract);
- this._modSignal.connect(this._multiply, 0, 0);
- this._shaper.connect(this._multiply, 0, 1);
- this._multiply.connect(this._subtract, 0, 1);
- this._setWaveShaper(modulus);
- };
- Tone.extend(Tone.Modulo, Tone.SignalBase);
- /**
- * @param {number} mod the modulus to apply
- * @private
- */
- Tone.Modulo.prototype._setWaveShaper = function (mod) {
- this._shaper.setMap(function (val) {
- var multiple = Math.floor((val + 0.0001) / mod);
- return multiple;
- });
- };
- /**
- * The modulus value.
- * @memberOf Tone.Modulo#
- * @type {NormalRange}
- * @name value
- */
- Object.defineProperty(Tone.Modulo.prototype, 'value', {
- get: function () {
- return this._modSignal.value;
- },
- set: function (mod) {
- this._modSignal.value = mod;
- this._setWaveShaper(mod);
- }
- });
- /**
- * clean up
- * @returns {Tone.Modulo} this
- */
- Tone.Modulo.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._shaper.dispose();
- this._shaper = null;
- this._multiply.dispose();
- this._multiply = null;
- this._subtract.dispose();
- this._subtract = null;
- this._modSignal.dispose();
- this._modSignal = null;
- return this;
- };
- return Tone.Modulo;
- });
- Module(function (Tone) {
-
- /**
- * @class AudioToGain converts an input in AudioRange [-1,1] to NormalRange [0,1].
- * See Tone.GainToAudio.
- *
- * @extends {Tone.SignalBase}
- * @constructor
- * @example
- * var a2g = new Tone.AudioToGain();
- */
- Tone.AudioToGain = function () {
- Tone.SignalBase.call(this);
- /**
- * @type {WaveShaperNode}
- * @private
- */
- this._norm = this.input = this.output = new Tone.WaveShaper(function (x) {
- return (x + 1) / 2;
- });
- };
- Tone.extend(Tone.AudioToGain, Tone.SignalBase);
- /**
- * clean up
- * @returns {Tone.AudioToGain} this
- */
- Tone.AudioToGain.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._norm.dispose();
- this._norm = null;
- return this;
- };
- return Tone.AudioToGain;
- });
- Module(function (Tone) {
-
- /**
- * @class Evaluate an expression at audio rate. input[0].
- * @type {Tone.Gain}
- */
- this.a = this.input[0] = new Tone.Gain();
- /**
- * Alias for input[1].
- * @type {Tone.Gain}
- */
- this.b = this.input[1] = new Tone.Gain();
- /**
- * The mix between the two inputs. A fade value of 0
- * will output 100% input[0] and
- * a value of 1 will output 100% input[1].
- * @type {NormalRange}
- * @signal
- */
- this.fade = new Tone.Signal(Tone.defaultArg(initialFade, 0.5), Tone.Type.NormalRange);
- /**
- * equal power gain cross fade
- * @private
- * @type {Tone.EqualPowerGain}
- */
- this._equalPowerA = new Tone.EqualPowerGain();
- /**
- * equal power gain cross fade
- * @private
- * @type {Tone.EqualPowerGain}
- */
- this._equalPowerB = new Tone.EqualPowerGain();
- /**
- * invert the incoming signal
- * @private
- * @type {Tone}
- */
- this._invert = new Tone.Expr('1 - $0');
- //connections
- this.a.connect(this.output);
- this.b.connect(this.output);
- this.fade.chain(this._equalPowerB, this.b.gain);
- this.fade.chain(this._invert, this._equalPowerA, this.a.gain);
- this._readOnly('fade');
- };
- Tone.extend(Tone.CrossFade, Tone.AudioNode);
- /**
- * clean up
- * @returns {Tone.CrossFade} this
- */
- Tone.CrossFade.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._writable('fade');
- this._equalPowerA.dispose();
- this._equalPowerA = null;
- this._equalPowerB.dispose();
- this._equalPowerB = null;
- this.fade.dispose();
- this.fade = null;
- this._invert.dispose();
- this._invert = null;
- this.a.dispose();
- this.a = null;
- this.b.dispose();
- this.b = null;
- return this;
- };
- return Tone.CrossFade;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Filter is a filter which allows for all of the same native methods
- * as the [BiquadFilterNode](http://webaudio.github.io/web-audio-api/#the-biquadfilternode-interface).
- * Tone.Filter has the added ability to set the filter rolloff at -12
- * (default), -24 and -48.
- *
- * @constructor
- * @extends {Tone.AudioNode}
- * @param {Frequency|Object} [frequency] The cutoff frequency of the filter.
- * @param {string=} type The type of filter.
- * @param {number=} rolloff The drop in decibels per octave after the cutoff frequency.
- * 3 choices: -12, -24, and -48
- * @example
- * var filter = new Tone.Filter(200, "highpass");
- */
- Tone.Filter = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'type',
- 'rolloff'
- ], Tone.Filter);
- Tone.AudioNode.call(this);
- this.createInsOuts(1, 1);
- /**
- * the filter(s)
- * @type {Array}
- * @private
- */
- this._filters = [];
- /**
- * The cutoff frequency of the filter.
- * @type {Frequency}
- * @signal
- */
- this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
- /**
- * The detune parameter
- * @type {Cents}
- * @signal
- */
- this.detune = new Tone.Signal(0, Tone.Type.Cents);
- /**
- * The gain of the filter, only used in certain filter types
- * @type {Number}
- * @signal
- */
- this.gain = new Tone.Signal({
- 'value': options.gain,
- 'convert': false
- });
- /**
- * The Q or Quality of the filter
- * @type {Positive}
- * @signal
- */
- this.Q = new Tone.Signal(options.Q);
- /**
- * the type of the filter
- * @type {string}
- * @private
- */
- this._type = options.type;
- /**
- * the rolloff value of the filter
- * @type {number}
- * @private
- */
- this._rolloff = options.rolloff;
- //set the rolloff;
- this.rolloff = options.rolloff;
- this._readOnly([
- 'detune',
- 'frequency',
- 'gain',
- 'Q'
- ]);
- };
- Tone.extend(Tone.Filter, Tone.AudioNode);
- /**
- * the default parameters
- *
- * @static
- * @type {Object}
- */
- Tone.Filter.defaults = {
- 'type': 'lowpass',
- 'frequency': 350,
- 'rolloff': -12,
- 'Q': 1,
- 'gain': 0
- };
- /**
- * The type of the filter. Types: "lowpass", "highpass",
- * "bandpass", "lowshelf", "highshelf", "notch", "allpass", or "peaking".
- * @memberOf Tone.Filter#
- * @type {string}
- * @name type
- */
- Object.defineProperty(Tone.Filter.prototype, 'type', {
- get: function () {
- return this._type;
- },
- set: function (type) {
- var types = [
- 'lowpass',
- 'highpass',
- 'bandpass',
- 'lowshelf',
- 'highshelf',
- 'notch',
- 'allpass',
- 'peaking'
- ];
- if (types.indexOf(type) === -1) {
- throw new TypeError('Tone.Filter: invalid type ' + type);
- }
- this._type = type;
- for (var i = 0; i < this._filters.length; i++) {
- this._filters[i].type = type;
- }
- }
- });
- /**
- * The rolloff of the filter which is the drop in db
- * per octave. Implemented internally by cascading filters.
- * Only accepts the values -12, -24, -48 and -96.
- * @memberOf Tone.Filter#
- * @type {number}
- * @name rolloff
- */
- Object.defineProperty(Tone.Filter.prototype, 'rolloff', {
- get: function () {
- return this._rolloff;
- },
- set: function (rolloff) {
- rolloff = parseInt(rolloff, 10);
- var possibilities = [
- -12,
- -24,
- -48,
- -96
- ];
- var cascadingCount = possibilities.indexOf(rolloff);
- //check the rolloff is valid
- if (cascadingCount === -1) {
- throw new RangeError('Tone.Filter: rolloff can only be -12, -24, -48 or -96');
- }
- cascadingCount += 1;
- this._rolloff = rolloff;
- //first disconnect the filters and throw them away
- this.input.disconnect();
- for (var i = 0; i < this._filters.length; i++) {
- this._filters[i].disconnect();
- this._filters[i] = null;
- }
- this._filters = new Array(cascadingCount);
- for (var count = 0; count < cascadingCount; count++) {
- var filter = this.context.createBiquadFilter();
- filter.type = this._type;
- this.frequency.connect(filter.frequency);
- this.detune.connect(filter.detune);
- this.Q.connect(filter.Q);
- this.gain.connect(filter.gain);
- this._filters[count] = filter;
- }
- //connect them up
- var connectionChain = [this.input].concat(this._filters).concat([this.output]);
- Tone.connectSeries.apply(Tone, connectionChain);
- }
- });
- /**
- * Clean up.
- * @return {Tone.Filter} this
- */
- Tone.Filter.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- for (var i = 0; i < this._filters.length; i++) {
- this._filters[i].disconnect();
- this._filters[i] = null;
- }
- this._filters = null;
- this._writable([
- 'detune',
- 'frequency',
- 'gain',
- 'Q'
- ]);
- this.frequency.dispose();
- this.Q.dispose();
- this.frequency = null;
- this.Q = null;
- this.detune.dispose();
- this.detune = null;
- this.gain.dispose();
- this.gain = null;
- return this;
- };
- return Tone.Filter;
- });
- Module(function (Tone) {
-
- /**
- * @class Split the incoming signal into three bands (low, mid, high)
- * with two crossover frequency controls.
- *
- * @extends {Tone.AudioNode}
- * @constructor
- * @param {Frequency|Object} [lowFrequency] the low/mid crossover frequency
- * @param {Frequency} [highFrequency] the mid/high crossover frequency
- */
- Tone.MultibandSplit = function () {
- var options = Tone.defaults(arguments, [
- 'lowFrequency',
- 'highFrequency'
- ], Tone.MultibandSplit);
- Tone.AudioNode.call(this);
- /**
- * the input
- * @type {Tone.Gain}
- * @private
- */
- this.input = new Tone.Gain();
- /**
- * the outputs
- * @type {Array}
- * @private
- */
- this.output = new Array(3);
- /**
- * The low band. Alias for output[0]
- * @type {Tone.Filter}
- */
- this.low = this.output[0] = new Tone.Filter(0, 'lowpass');
- /**
- * the lower filter of the mid band
- * @type {Tone.Filter}
- * @private
- */
- this._lowMidFilter = new Tone.Filter(0, 'highpass');
- /**
- * The mid band output. Alias for output[1]
- * @type {Tone.Filter}
- */
- this.mid = this.output[1] = new Tone.Filter(0, 'lowpass');
- /**
- * The high band output. Alias for output[2]
- * @type {Tone.Filter}
- */
- this.high = this.output[2] = new Tone.Filter(0, 'highpass');
- /**
- * The low/mid crossover frequency.
- * @type {Frequency}
- * @signal
- */
- this.lowFrequency = new Tone.Signal(options.lowFrequency, Tone.Type.Frequency);
- /**
- * The mid/high crossover frequency.
- * @type {Frequency}
- * @signal
- */
- this.highFrequency = new Tone.Signal(options.highFrequency, Tone.Type.Frequency);
- /**
- * The quality of all the filters
- * @type {Number}
- * @signal
- */
- this.Q = new Tone.Signal(options.Q);
- this.input.fan(this.low, this.high);
- this.input.chain(this._lowMidFilter, this.mid);
- //the frequency control signal
- this.lowFrequency.connect(this.low.frequency);
- this.lowFrequency.connect(this._lowMidFilter.frequency);
- this.highFrequency.connect(this.mid.frequency);
- this.highFrequency.connect(this.high.frequency);
- //the Q value
- this.Q.connect(this.low.Q);
- this.Q.connect(this._lowMidFilter.Q);
- this.Q.connect(this.mid.Q);
- this.Q.connect(this.high.Q);
- this._readOnly([
- 'high',
- 'mid',
- 'low',
- 'highFrequency',
- 'lowFrequency'
- ]);
- };
- Tone.extend(Tone.MultibandSplit, Tone.AudioNode);
- /**
- * @private
- * @static
- * @type {Object}
- */
- Tone.MultibandSplit.defaults = {
- 'lowFrequency': 400,
- 'highFrequency': 2500,
- 'Q': 1
- };
- /**
- * Clean up.
- * @returns {Tone.MultibandSplit} this
- */
- Tone.MultibandSplit.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._writable([
- 'high',
- 'mid',
- 'low',
- 'highFrequency',
- 'lowFrequency'
- ]);
- this.low.dispose();
- this.low = null;
- this._lowMidFilter.dispose();
- this._lowMidFilter = null;
- this.mid.dispose();
- this.mid = null;
- this.high.dispose();
- this.high = null;
- this.lowFrequency.dispose();
- this.lowFrequency = null;
- this.highFrequency.dispose();
- this.highFrequency = null;
- this.Q.dispose();
- this.Q = null;
- return this;
- };
- return Tone.MultibandSplit;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.EQ3 is a three band EQ with control over low, mid, and high gain as
- * well as the low and high crossover frequencies.
- *
- * @constructor
- * @extends {Tone.AudioNode}
- *
- * @param {Decibels|Object} [lowLevel] The gain applied to the lows.
- * @param {Decibels} [midLevel] The gain applied to the mid.
- * @param {Decibels} [highLevel] The gain applied to the high.
- * @example
- * var eq = new Tone.EQ3(-10, 3, -20);
- */
- Tone.EQ3 = function () {
- var options = Tone.defaults(arguments, [
- 'low',
- 'mid',
- 'high'
- ], Tone.EQ3);
- Tone.AudioNode.call(this);
- /**
- * the output node
- * @type {GainNode}
- * @private
- */
- this.output = new Tone.Gain();
- /**
- * the multiband split
- * @type {Tone.MultibandSplit}
- * @private
- */
- this._multibandSplit = this.input = new Tone.MultibandSplit({
- 'lowFrequency': options.lowFrequency,
- 'highFrequency': options.highFrequency
- });
- /**
- * The gain for the lower signals
- * @type {Tone.Gain}
- * @private
- */
- this._lowGain = new Tone.Gain(options.low, Tone.Type.Decibels);
- /**
- * The gain for the mid signals
- * @type {Tone.Gain}
- * @private
- */
- this._midGain = new Tone.Gain(options.mid, Tone.Type.Decibels);
- /**
- * The gain in decibels of the high part
- * @type {Tone.Gain}
- * @private
- */
- this._highGain = new Tone.Gain(options.high, Tone.Type.Decibels);
- /**
- * The gain in decibels of the low part
- * @type {Decibels}
- * @signal
- */
- this.low = this._lowGain.gain;
- /**
- * The gain in decibels of the mid part
- * @type {Decibels}
- * @signal
- */
- this.mid = this._midGain.gain;
- /**
- * The gain in decibels of the high part
- * @type {Decibels}
- * @signal
- */
- this.high = this._highGain.gain;
- /**
- * The Q value for all of the filters.
- * @type {Positive}
- * @signal
- */
- this.Q = this._multibandSplit.Q;
- /**
- * The low/mid crossover frequency.
- * @type {Frequency}
- * @signal
- */
- this.lowFrequency = this._multibandSplit.lowFrequency;
- /**
- * The mid/high crossover frequency.
- * @type {Frequency}
- * @signal
- */
- this.highFrequency = this._multibandSplit.highFrequency;
- //the frequency bands
- this._multibandSplit.low.chain(this._lowGain, this.output);
- this._multibandSplit.mid.chain(this._midGain, this.output);
- this._multibandSplit.high.chain(this._highGain, this.output);
- this._readOnly([
- 'low',
- 'mid',
- 'high',
- 'lowFrequency',
- 'highFrequency'
- ]);
- };
- Tone.extend(Tone.EQ3, Tone.AudioNode);
- /**
- * the default values
- */
- Tone.EQ3.defaults = {
- 'low': 0,
- 'mid': 0,
- 'high': 0,
- 'lowFrequency': 400,
- 'highFrequency': 2500
- };
- /**
- * clean up
- * @returns {Tone.EQ3} this
- */
- Tone.EQ3.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._writable([
- 'low',
- 'mid',
- 'high',
- 'lowFrequency',
- 'highFrequency'
- ]);
- this._multibandSplit.dispose();
- this._multibandSplit = null;
- this.lowFrequency = null;
- this.highFrequency = null;
- this._lowGain.dispose();
- this._lowGain = null;
- this._midGain.dispose();
- this._midGain = null;
- this._highGain.dispose();
- this._highGain = null;
- this.low = null;
- this.mid = null;
- this.high = null;
- this.Q = null;
- return this;
- };
- return Tone.EQ3;
- });
- Module(function (Tone) {
-
- /**
- * @class Performs a linear scaling on an input signal.
- * Scales a NormalRange input to between
- * outputMin and outputMax.
- *
- * @constructor
- * @extends {Tone.SignalBase}
- * @param {number} [outputMin=0] The output value when the input is 0.
- * @param {number} [outputMax=1] The output value when the input is 1.
- * @example
- * var scale = new Tone.Scale(50, 100);
- * var signal = new Tone.Signal(0.5).connect(scale);
- * //the output of scale equals 75
- */
- Tone.Scale = function (outputMin, outputMax) {
- Tone.SignalBase.call(this);
- /**
- * @private
- * @type {number}
- */
- this._outputMin = Tone.defaultArg(outputMin, 0);
- /**
- * @private
- * @type {number}
- */
- this._outputMax = Tone.defaultArg(outputMax, 1);
- /**
- * @private
- * @type {Tone.Multiply}
- * @private
- */
- this._scale = this.input = new Tone.Multiply(1);
- /**
- * @private
- * @type {Tone.Add}
- * @private
- */
- this._add = this.output = new Tone.Add(0);
- this._scale.connect(this._add);
- this._setRange();
- };
- Tone.extend(Tone.Scale, Tone.SignalBase);
- /**
- * The minimum output value. This number is output when
- * the value input value is 0.
- * @memberOf Tone.Scale#
- * @type {number}
- * @name min
- */
- Object.defineProperty(Tone.Scale.prototype, 'min', {
- get: function () {
- return this._outputMin;
- },
- set: function (min) {
- this._outputMin = min;
- this._setRange();
- }
- });
- /**
- * The maximum output value. This number is output when
- * the value input value is 1.
- * @memberOf Tone.Scale#
- * @type {number}
- * @name max
- */
- Object.defineProperty(Tone.Scale.prototype, 'max', {
- get: function () {
- return this._outputMax;
- },
- set: function (max) {
- this._outputMax = max;
- this._setRange();
- }
- });
- /**
- * set the values
- * @private
- */
- Tone.Scale.prototype._setRange = function () {
- this._add.value = this._outputMin;
- this._scale.value = this._outputMax - this._outputMin;
- };
- /**
- * Clean up.
- * @returns {Tone.Scale} this
- */
- Tone.Scale.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._add.dispose();
- this._add = null;
- this._scale.dispose();
- this._scale = null;
- return this;
- };
- return Tone.Scale;
- });
- Module(function (Tone) {
- /**
- * @class Performs an exponential scaling on an input signal.
- * Scales a NormalRange value [0,1] exponentially
- * to the output range of outputMin to outputMax.
- *
- * @constructor
- * @extends {Tone.SignalBase}
- * @param {number} [outputMin=0] The output value when the input is 0.
- * @param {number} [outputMax=1] The output value when the input is 1.
- * @param {number} [exponent=2] The exponent which scales the incoming signal.
- * @example
- * var scaleExp = new Tone.ScaleExp(0, 100, 2);
- * var signal = new Tone.Signal(0.5).connect(scaleExp);
- */
- Tone.ScaleExp = function (outputMin, outputMax, exponent) {
- Tone.SignalBase.call(this);
- /**
- * scale the input to the output range
- * @type {Tone.Scale}
- * @private
- */
- this._scale = this.output = new Tone.Scale(outputMin, outputMax);
- /**
- * @private
- * @type {Tone.Pow}
- * @private
- */
- this._exp = this.input = new Tone.Pow(Tone.defaultArg(exponent, 2));
- this._exp.connect(this._scale);
- };
- Tone.extend(Tone.ScaleExp, Tone.SignalBase);
- /**
- * Instead of interpolating linearly between the min and
- * max values, setting the exponent will interpolate between
- * the two values with an exponential curve.
- * @memberOf Tone.ScaleExp#
- * @type {number}
- * @name exponent
- */
- Object.defineProperty(Tone.ScaleExp.prototype, 'exponent', {
- get: function () {
- return this._exp.value;
- },
- set: function (exp) {
- this._exp.value = exp;
- }
- });
- /**
- * The minimum output value. This number is output when
- * the value input value is 0.
- * @memberOf Tone.ScaleExp#
- * @type {number}
- * @name min
- */
- Object.defineProperty(Tone.ScaleExp.prototype, 'min', {
- get: function () {
- return this._scale.min;
- },
- set: function (min) {
- this._scale.min = min;
- }
- });
- /**
- * The maximum output value. This number is output when
- * the value input value is 1.
- * @memberOf Tone.ScaleExp#
- * @type {number}
- * @name max
- */
- Object.defineProperty(Tone.ScaleExp.prototype, 'max', {
- get: function () {
- return this._scale.max;
- },
- set: function (max) {
- this._scale.max = max;
- }
- });
- /**
- * Clean up.
- * @returns {Tone.ScaleExp} this
- */
- Tone.ScaleExp.prototype.dispose = function () {
- Tone.SignalBase.prototype.dispose.call(this);
- this._scale.dispose();
- this._scale = null;
- this._exp.dispose();
- this._exp = null;
- return this;
- };
- return Tone.ScaleExp;
- });
- Module(function (Tone) {
-
- /**
- * createDelay shim
- * @private
- */
- if (window.DelayNode && !AudioContext.prototype.createDelay) {
- AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode;
- }
- /**
- * @class Wrapper around Web Audio's native [DelayNode](http://webaudio.github.io/web-audio-api/#the-delaynode-interface).
- * @extends {Tone}
- * @param {Time=} delayTime The delay applied to the incoming signal.
- * @param {Time=} maxDelay The maximum delay time.
- */
- Tone.Delay = function () {
- var options = Tone.defaults(arguments, [
- 'delayTime',
- 'maxDelay'
- ], Tone.Delay);
- Tone.AudioNode.call(this);
- /**
- * The native delay node
- * @type {DelayNode}
- * @private
- */
- this._delayNode = this.input = this.output = this.context.createDelay(this.toSeconds(options.maxDelay));
- /**
- * The amount of time the incoming signal is
- * delayed.
- * @type {Time}
- * @signal
- */
- this.delayTime = new Tone.Param({
- 'param': this._delayNode.delayTime,
- 'units': Tone.Type.Time,
- 'value': options.delayTime
- });
- this._readOnly('delayTime');
- };
- Tone.extend(Tone.Delay, Tone.AudioNode);
- /**
- * The defaults
- * @const
- * @type {Object}
- */
- Tone.Delay.defaults = {
- 'maxDelay': 1,
- 'delayTime': 0
- };
- /**
- * Clean up.
- * @return {Tone.Delay} this
- */
- Tone.Delay.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._delayNode.disconnect();
- this._delayNode = null;
- this._writable('delayTime');
- this.delayTime = null;
- return this;
- };
- return Tone.Delay;
- });
- Module(function (Tone) {
-
- /**
- * @class Comb filters are basic building blocks for physical modeling. Read more
- * about comb filters on [CCRMA's website](https://ccrma.stanford.edu/~jos/pasp/Feedback_Comb_Filters.html).
- *
- * @extends {Tone.AudioNode}
- * @constructor
- * @param {Time|Object} [delayTime] The delay time of the filter.
- * @param {NormalRange=} resonance The amount of feedback the filter has.
- */
- Tone.FeedbackCombFilter = function () {
- var options = Tone.defaults(arguments, [
- 'delayTime',
- 'resonance'
- ], Tone.FeedbackCombFilter);
- Tone.AudioNode.call(this);
- /**
- * the delay node
- * @type {DelayNode}
- * @private
- */
- this._delay = this.input = this.output = new Tone.Delay(options.delayTime);
- /**
- * The amount of delay of the comb filter.
- * @type {Time}
- * @signal
- */
- this.delayTime = this._delay.delayTime;
- /**
- * the feedback node
- * @type {GainNode}
- * @private
- */
- this._feedback = new Tone.Gain(options.resonance, Tone.Type.NormalRange);
- /**
- * The amount of feedback of the delayed signal.
- * @type {NormalRange}
- * @signal
- */
- this.resonance = this._feedback.gain;
- this._delay.chain(this._feedback, this._delay);
- this._readOnly([
- 'resonance',
- 'delayTime'
- ]);
- };
- Tone.extend(Tone.FeedbackCombFilter, Tone.AudioNode);
- /**
- * the default parameters
- * @static
- * @const
- * @type {Object}
- */
- Tone.FeedbackCombFilter.defaults = {
- 'delayTime': 0.1,
- 'resonance': 0.5
- };
- /**
- * clean up
- * @returns {Tone.FeedbackCombFilter} this
- */
- Tone.FeedbackCombFilter.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._writable([
- 'resonance',
- 'delayTime'
- ]);
- this._delay.dispose();
- this._delay = null;
- this.delayTime = null;
- this._feedback.dispose();
- this._feedback = null;
- this.resonance = null;
- return this;
- };
- return Tone.FeedbackCombFilter;
- });
- Module(function (Tone) {
- /**
- * @class Get the current waveform data of the connected audio source.
- * @extends {Tone.AudioNode}
- * @param {Number=} size The size of the FFT. Value must be a power of
- * two in the range 32 to 32768.
- */
- Tone.FFT = function () {
- var options = Tone.defaults(arguments, ['size'], Tone.FFT);
- options.type = Tone.Analyser.Type.FFT;
- Tone.AudioNode.call(this);
- /**
- * The analyser node.
- * @private
- * @type {Tone.Analyser}
- */
- this._analyser = this.input = this.output = new Tone.Analyser(options);
- };
- Tone.extend(Tone.FFT, Tone.AudioNode);
- /**
- * The default values.
- * @type {Object}
- * @const
- */
- Tone.FFT.defaults = { 'size': 1024 };
- /**
- * Gets the waveform of the audio source. Returns the waveform data
- * of length [size](#size) as a Float32Array with values between -1 and 1.
- * @returns {TypedArray}
- */
- Tone.FFT.prototype.getValue = function () {
- return this._analyser.getValue();
- };
- /**
- * The size of analysis. This must be a power of two in the range 32 to 32768.
- * @memberOf Tone.FFT#
- * @type {Number}
- * @name size
- */
- Object.defineProperty(Tone.FFT.prototype, 'size', {
- get: function () {
- return this._analyser.size;
- },
- set: function (size) {
- this._analyser.size = size;
- }
- });
- /**
- * Clean up.
- * @return {Tone.FFT} this
- */
- Tone.FFT.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._analyser.dispose();
- this._analyser = null;
- };
- return Tone.FFT;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Follower is a crude envelope follower which will follow
- * the amplitude of an incoming signal.
- * Take care with small (< 0.02) attack or decay values
- * as follower has some ripple which is exaggerated
- * at these values. Read more about envelope followers (also known
- * as envelope detectors) on [Wikipedia](https://en.wikipedia.org/wiki/Envelope_detector).
- *
- * @constructor
- * @extends {Tone.AudioNode}
- * @param {Time|Object} [attack] The rate at which the follower rises.
- * @param {Time=} release The rate at which the folower falls.
- * @example
- * var follower = new Tone.Follower(0.2, 0.4);
- */
- Tone.Follower = function () {
- var options = Tone.defaults(arguments, [
- 'attack',
- 'release'
- ], Tone.Follower);
- Tone.AudioNode.call(this);
- this.createInsOuts(1, 1);
- /**
- * @type {Tone.Abs}
- * @private
- */
- this._abs = new Tone.Abs();
- /**
- * the lowpass filter which smooths the input
- * @type {BiquadFilterNode}
- * @private
- */
- this._filter = this.context.createBiquadFilter();
- this._filter.type = 'lowpass';
- this._filter.frequency.value = 0;
- this._filter.Q.value = -100;
- /**
- * @type {WaveShaperNode}
- * @private
- */
- this._frequencyValues = new Tone.WaveShaper();
- /**
- * @type {Tone.Subtract}
- * @private
- */
- this._sub = new Tone.Subtract();
- /**
- * @type {Tone.Delay}
- * @private
- */
- this._delay = new Tone.Delay(this.blockTime);
- /**
- * this keeps it far from 0, even for very small differences
- * @type {Tone.Multiply}
- * @private
- */
- this._mult = new Tone.Multiply(10000);
- /**
- * @private
- * @type {number}
- */
- this._attack = options.attack;
- /**
- * @private
- * @type {number}
- */
- this._release = options.release;
- //the smoothed signal to get the values
- this.input.chain(this._abs, this._filter, this.output);
- //the difference path
- this._abs.connect(this._sub, 0, 1);
- this._filter.chain(this._delay, this._sub);
- //threshold the difference and use the thresh to set the frequency
- this._sub.chain(this._mult, this._frequencyValues, this._filter.frequency);
- //set the attack and release values in the table
- this._setAttackRelease(this._attack, this._release);
- };
- Tone.extend(Tone.Follower, Tone.AudioNode);
- /**
- * @static
- * @type {Object}
- */
- Tone.Follower.defaults = {
- 'attack': 0.05,
- 'release': 0.5
- };
- /**
- * sets the attack and release times in the wave shaper
- * @param {Time} attack
- * @param {Time} release
- * @private
- */
- Tone.Follower.prototype._setAttackRelease = function (attack, release) {
- var minTime = this.blockTime;
- attack = Tone.Time(attack).toFrequency();
- release = Tone.Time(release).toFrequency();
- attack = Math.max(attack, minTime);
- release = Math.max(release, minTime);
- this._frequencyValues.setMap(function (val) {
- if (val <= 0) {
- return attack;
- } else {
- return release;
- }
- });
- };
- /**
- * The attack time.
- * @memberOf Tone.Follower#
- * @type {Time}
- * @name attack
- */
- Object.defineProperty(Tone.Follower.prototype, 'attack', {
- get: function () {
- return this._attack;
- },
- set: function (attack) {
- this._attack = attack;
- this._setAttackRelease(this._attack, this._release);
- }
- });
- /**
- * The release time.
- * @memberOf Tone.Follower#
- * @type {Time}
- * @name release
- */
- Object.defineProperty(Tone.Follower.prototype, 'release', {
- get: function () {
- return this._release;
- },
- set: function (release) {
- this._release = release;
- this._setAttackRelease(this._attack, this._release);
- }
- });
- /**
- * Borrows the connect method from Signal so that the output can be used
- * as a Tone.Signal control signal.
- * @function
- */
- Tone.Follower.prototype.connect = Tone.Signal.prototype.connect;
- /**
- * dispose
- * @returns {Tone.Follower} this
- */
- Tone.Follower.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._filter.disconnect();
- this._filter = null;
- this._frequencyValues.disconnect();
- this._frequencyValues = null;
- this._delay.dispose();
- this._delay = null;
- this._sub.disconnect();
- this._sub = null;
- this._abs.dispose();
- this._abs = null;
- this._mult.dispose();
- this._mult = null;
- this._curve = null;
- return this;
- };
- return Tone.Follower;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.ScaledEnvelop is an envelope which can be scaled
- * to any range. It's useful for applying an envelope
- * to a frequency or any other non-NormalRange signal
- * parameter.
- *
- * @extends {Tone.Envelope}
- * @constructor
- * @param {Time|Object} [attack] the attack time in seconds
- * @param {Time} [decay] the decay time in seconds
- * @param {number} [sustain] a percentage (0-1) of the full amplitude
- * @param {Time} [release] the release time in seconds
- * @example
- * var scaledEnv = new Tone.ScaledEnvelope({
- * "attack" : 0.2,
- * "min" : 200,
- * "max" : 2000
- * });
- * scaledEnv.connect(oscillator.frequency);
- */
- Tone.ScaledEnvelope = function () {
- //get all of the defaults
- var options = Tone.defaults(arguments, [
- 'attack',
- 'decay',
- 'sustain',
- 'release'
- ], Tone.Envelope);
- Tone.Envelope.call(this, options);
- options = Tone.defaultArg(options, Tone.ScaledEnvelope.defaults);
- /**
- * scale the incoming signal by an exponent
- * @type {Tone.Pow}
- * @private
- */
- this._exp = this.output = new Tone.Pow(options.exponent);
- /**
- * scale the signal to the desired range
- * @type {Tone.Multiply}
- * @private
- */
- this._scale = this.output = new Tone.Scale(options.min, options.max);
- this._sig.chain(this._exp, this._scale);
- };
- Tone.extend(Tone.ScaledEnvelope, Tone.Envelope);
- /**
- * the default parameters
- * @static
- */
- Tone.ScaledEnvelope.defaults = {
- 'min': 0,
- 'max': 1,
- 'exponent': 1
- };
- /**
- * The envelope's min output value. This is the value which it
- * starts at.
- * @memberOf Tone.ScaledEnvelope#
- * @type {number}
- * @name min
- */
- Object.defineProperty(Tone.ScaledEnvelope.prototype, 'min', {
- get: function () {
- return this._scale.min;
- },
- set: function (min) {
- this._scale.min = min;
- }
- });
- /**
- * The envelope's max output value. In other words, the value
- * at the peak of the attack portion of the envelope.
- * @memberOf Tone.ScaledEnvelope#
- * @type {number}
- * @name max
- */
- Object.defineProperty(Tone.ScaledEnvelope.prototype, 'max', {
- get: function () {
- return this._scale.max;
- },
- set: function (max) {
- this._scale.max = max;
- }
- });
- /**
- * The envelope's exponent value.
- * @memberOf Tone.ScaledEnvelope#
- * @type {number}
- * @name exponent
- */
- Object.defineProperty(Tone.ScaledEnvelope.prototype, 'exponent', {
- get: function () {
- return this._exp.value;
- },
- set: function (exp) {
- this._exp.value = exp;
- }
- });
- /**
- * clean up
- * @returns {Tone.ScaledEnvelope} this
- */
- Tone.ScaledEnvelope.prototype.dispose = function () {
- Tone.Envelope.prototype.dispose.call(this);
- this._scale.dispose();
- this._scale = null;
- this._exp.dispose();
- this._exp = null;
- return this;
- };
- return Tone.ScaledEnvelope;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.FrequencyEnvelope is a Tone.ScaledEnvelope, but instead of `min` and `max`
- * it's got a `baseFrequency` and `octaves` parameter.
- *
- * @extends {Tone.Envelope}
- * @constructor
- * @param {Time|Object} [attack] the attack time in seconds
- * @param {Time} [decay] the decay time in seconds
- * @param {number} [sustain] a percentage (0-1) of the full amplitude
- * @param {Time} [release] the release time in seconds
- * @example
- * var env = new Tone.FrequencyEnvelope({
- * "attack" : 0.2,
- * "baseFrequency" : "C2",
- * "octaves" : 4
- * });
- * scaledEnv.connect(oscillator.frequency);
- */
- Tone.FrequencyEnvelope = function () {
- var options = Tone.defaults(arguments, [
- 'attack',
- 'decay',
- 'sustain',
- 'release'
- ], Tone.Envelope);
- Tone.ScaledEnvelope.call(this, options);
- //merge it with the frequency envelope defaults
- options = Tone.defaultArg(options, Tone.FrequencyEnvelope.defaults);
- /**
- * Stores the octave value
- * @type {Positive}
- * @private
- */
- this._octaves = options.octaves;
- //setup
- this.baseFrequency = options.baseFrequency;
- this.octaves = options.octaves;
- };
- Tone.extend(Tone.FrequencyEnvelope, Tone.Envelope);
- /**
- * the default parameters
- * @static
- */
- Tone.FrequencyEnvelope.defaults = {
- 'baseFrequency': 200,
- 'octaves': 4,
- 'exponent': 2
- };
- /**
- * The envelope's mininum output value. This is the value which it
- * starts at.
- * @memberOf Tone.FrequencyEnvelope#
- * @type {Frequency}
- * @name baseFrequency
- */
- Object.defineProperty(Tone.FrequencyEnvelope.prototype, 'baseFrequency', {
- get: function () {
- return this._scale.min;
- },
- set: function (min) {
- this._scale.min = this.toFrequency(min);
- //also update the octaves
- this.octaves = this._octaves;
- }
- });
- /**
- * The number of octaves above the baseFrequency that the
- * envelope will scale to.
- * @memberOf Tone.FrequencyEnvelope#
- * @type {Positive}
- * @name octaves
- */
- Object.defineProperty(Tone.FrequencyEnvelope.prototype, 'octaves', {
- get: function () {
- return this._octaves;
- },
- set: function (octaves) {
- this._octaves = octaves;
- this._scale.max = this.baseFrequency * Math.pow(2, octaves);
- }
- });
- /**
- * The envelope's exponent value.
- * @memberOf Tone.FrequencyEnvelope#
- * @type {number}
- * @name exponent
- */
- Object.defineProperty(Tone.FrequencyEnvelope.prototype, 'exponent', {
- get: function () {
- return this._exp.value;
- },
- set: function (exp) {
- this._exp.value = exp;
- }
- });
- /**
- * clean up
- * @returns {Tone.FrequencyEnvelope} this
- */
- Tone.FrequencyEnvelope.prototype.dispose = function () {
- Tone.ScaledEnvelope.prototype.dispose.call(this);
- return this;
- };
- return Tone.FrequencyEnvelope;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Gate only passes a signal through when the incoming
- * signal exceeds a specified threshold. To do this, Gate uses
- * a Tone.Follower to follow the amplitude of the incoming signal.
- * A common implementation of this class is a [Noise Gate](https://en.wikipedia.org/wiki/Noise_gate).
- *
- * @constructor
- * @extends {Tone.AudioNode}
- * @param {Decibels|Object} [threshold] The threshold above which the gate will open.
- * @param {Time=} attack The follower's attack time
- * @param {Time=} release The follower's release time
- * @example
- * var gate = new Tone.Gate(-30, 0.2, 0.3).toMaster();
- * var mic = new Tone.UserMedia().connect(gate);
- * //the gate will only pass through the incoming
- * //signal when it's louder than -30db
- */
- Tone.Gate = function () {
- var options = Tone.defaults(arguments, [
- 'threshold',
- 'attack',
- 'release'
- ], Tone.Gate);
- Tone.AudioNode.call(this);
- this.createInsOuts(1, 1);
- /**
- * @type {Tone.Follower}
- * @private
- */
- this._follower = new Tone.Follower(options.attack, options.release);
- /**
- * @type {Tone.GreaterThan}
- * @private
- */
- this._gt = new Tone.GreaterThan(Tone.dbToGain(options.threshold));
- //the connections
- this.input.connect(this.output);
- //the control signal
- this.input.chain(this._gt, this._follower, this.output.gain);
- };
- Tone.extend(Tone.Gate, Tone.AudioNode);
- /**
- * @const
- * @static
- * @type {Object}
- */
- Tone.Gate.defaults = {
- 'attack': 0.1,
- 'release': 0.1,
- 'threshold': -40
- };
- /**
- * The threshold of the gate in decibels
- * @memberOf Tone.Gate#
- * @type {Decibels}
- * @name threshold
- */
- Object.defineProperty(Tone.Gate.prototype, 'threshold', {
- get: function () {
- return Tone.gainToDb(this._gt.value);
- },
- set: function (thresh) {
- this._gt.value = Tone.dbToGain(thresh);
- }
- });
- /**
- * The attack speed of the gate
- * @memberOf Tone.Gate#
- * @type {Time}
- * @name attack
- */
- Object.defineProperty(Tone.Gate.prototype, 'attack', {
- get: function () {
- return this._follower.attack;
- },
- set: function (attackTime) {
- this._follower.attack = attackTime;
- }
- });
- /**
- * The release speed of the gate
- * @memberOf Tone.Gate#
- * @type {Time}
- * @name release
- */
- Object.defineProperty(Tone.Gate.prototype, 'release', {
- get: function () {
- return this._follower.release;
- },
- set: function (releaseTime) {
- this._follower.release = releaseTime;
- }
- });
- /**
- * Clean up.
- * @returns {Tone.Gate} this
- */
- Tone.Gate.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._follower.dispose();
- this._gt.dispose();
- this._follower = null;
- this._gt = null;
- return this;
- };
- return Tone.Gate;
- });
- Module(function (Tone) {
- /**
- * @class Tone.TickSignal extends Tone.TimelineSignal, but adds the capability
- * to calculate the number of elapsed ticks. exponential and target curves
- * are approximated with multiple linear ramps.
- *
- * Thank you Bruno Dias, H. Sofia Pinto, and David M. Matos, for your [WAC paper](https://smartech.gatech.edu/bitstream/handle/1853/54588/WAC2016-49.pdf)
- * describing integrating timing functions for tempo calculations.
- *
- * @param {Number} value The initial value of the signal
- * @extends {Tone.TimelineSignal}
- */
- Tone.TickSignal = function (value) {
- value = Tone.defaultArg(value, 1);
- Tone.TimelineSignal.call(this, {
- 'units': Tone.Type.Ticks,
- 'value': value
- });
- //extend the memory
- this._events.memory = Infinity;
- };
- Tone.extend(Tone.TickSignal, Tone.TimelineSignal);
- /**
- * Wraps Tone.TimelineSignal methods so that they also
- * record the ticks.
- * @param {Function} method
- * @return {Function}
- * @private
- */
- function _wrapScheduleMethods(method) {
- return function (value, time) {
- time = this.toSeconds(time);
- method.apply(this, arguments);
- var event = this._events.get(time);
- var previousEvent = this._events.previousEvent(event);
- var ticksUntilTime = this._getTickUntilEvent(previousEvent, time - this.sampleTime);
- event.ticks = Math.max(ticksUntilTime, 0);
- return this;
- };
- }
- Tone.TickSignal.prototype.setValueAtTime = _wrapScheduleMethods(Tone.TimelineSignal.prototype.setValueAtTime);
- Tone.TickSignal.prototype.linearRampToValueAtTime = _wrapScheduleMethods(Tone.TimelineSignal.prototype.linearRampToValueAtTime);
- /**
- * Start exponentially approaching the target value at the given time with
- * a rate having the given time constant.
- * @param {number} value
- * @param {Time} startTime
- * @param {number} timeConstant
- * @returns {Tone.TickSignal} this
- */
- Tone.TickSignal.prototype.setTargetAtTime = function (value, time, constant) {
- //aproximate it with multiple linear ramps
- time = this.toSeconds(time);
- this.setRampPoint(time);
- value = this._fromUnits(value);
- //start from previously scheduled value
- var prevEvent = this._events.get(time);
- var segments = 5;
- for (var i = 0; i <= segments; i++) {
- var segTime = constant * i + time;
- var rampVal = this._exponentialApproach(prevEvent.time, prevEvent.value, value, constant, segTime);
- this.linearRampToValueAtTime(this._toUnits(rampVal), segTime);
- }
- return this;
- };
- /**
- * Schedules an exponential continuous change in parameter value from
- * the previous scheduled parameter value to the given value.
- * @param {number} value
- * @param {Time} endTime
- * @returns {Tone.TickSignal} this
- */
- Tone.TickSignal.prototype.exponentialRampToValueAtTime = function (value, time) {
- //aproximate it with multiple linear ramps
- time = this.toSeconds(time);
- value = this._fromUnits(value);
- //start from previously scheduled value
- var prevEvent = this._events.get(time);
- if (prevEvent === null) {
- prevEvent = {
- 'value': this._initial,
- 'time': 0
- };
- }
- var segments = 5;
- var segmentDur = (time - prevEvent.time) / segments;
- for (var i = 0; i <= segments; i++) {
- var segTime = segmentDur * i + prevEvent.time;
- var rampVal = this._exponentialInterpolate(prevEvent.time, prevEvent.value, time, value, segTime);
- this.linearRampToValueAtTime(this._toUnits(rampVal), segTime);
- }
- return this;
- };
- /**
- * Returns the tick value at the time. Takes into account
- * any automation curves scheduled on the signal.
- * @private
- * @param {Time} time The time to get the tick count at
- * @return {Ticks} The number of ticks which have elapsed at the time
- * given any automations.
- */
- Tone.TickSignal.prototype._getTickUntilEvent = function (event, time) {
- if (event === null) {
- event = {
- 'ticks': 0,
- 'time': 0
- };
- }
- var val0 = this.getValueAtTime(event.time);
- var val1 = this.getValueAtTime(time);
- return 0.5 * (time - event.time) * (val0 + val1) + event.ticks;
- };
- /**
- * Returns the tick value at the time. Takes into account
- * any automation curves scheduled on the signal.
- * @param {Time} time The time to get the tick count at
- * @return {Ticks} The number of ticks which have elapsed at the time
- * given any automations.
- */
- Tone.TickSignal.prototype.getTickAtTime = function (time) {
- time = this.toSeconds(time);
- var event = this._events.get(time);
- return this._getTickUntilEvent(event, time);
- };
- /**
- * Return the elapsed time of the number of ticks from the given time
- * @param {Ticks} ticks The number of ticks to calculate
- * @param {Time} time The time to get the next tick from
- * @return {Seconds} The duration of the number of ticks from the given time in seconds
- */
- Tone.TickSignal.prototype.getDurationOfTicks = function (ticks, time) {
- time = this.toSeconds(time);
- var currentTick = this.getTickAtTime(time);
- return this.getTimeOfTick(currentTick + ticks) - time;
- };
- /**
- * Given a tick, returns the time that tick occurs at.
- * @param {Ticks} tick
- * @return {Time} The time that the tick occurs.
- */
- Tone.TickSignal.prototype.getTimeOfTick = function (tick) {
- var before = this._events.get(tick, 'ticks');
- var after = this._events.getAfter(tick, 'ticks');
- if (before && before.ticks === tick) {
- return before.time;
- } else if (before && after && after.type === Tone.TimelineSignal.Type.Linear && before.value !== after.value) {
- var val0 = this.getValueAtTime(before.time);
- var val1 = this.getValueAtTime(after.time);
- var delta = (val1 - val0) / (after.time - before.time);
- var k = Math.sqrt(Math.pow(val0, 2) - 2 * delta * (before.ticks - tick));
- var sol1 = (-val0 + k) / delta;
- var sol2 = (-val0 - k) / delta;
- return (sol1 > 0 ? sol1 : sol2) + before.time;
- } else if (before) {
- if (before.value === 0) {
- return Infinity;
- } else {
- return before.time + (tick - before.ticks) / before.value;
- }
- } else {
- return tick / this._initial;
- }
- };
- return Tone.TickSignal;
- });
- Module(function (Tone) {
-
- /**
- * @class A Timeline State. Provides the methods: setStateAtTime("state", time)
- * and getValueAtTime(time).
- *
- * @extends {Tone.Timeline}
- * @param {String} initial The initial state of the TimelineState.
- * Defaults to undefined
- */
- Tone.TimelineState = function (initial) {
- Tone.Timeline.call(this);
- /**
- * The initial state
- * @private
- * @type {String}
- */
- this._initial = initial;
- };
- Tone.extend(Tone.TimelineState, Tone.Timeline);
- /**
- * Returns the scheduled state scheduled before or at
- * the given time.
- * @param {Number} time The time to query.
- * @return {String} The name of the state input in setStateAtTime.
- */
- Tone.TimelineState.prototype.getValueAtTime = function (time) {
- var event = this.get(time);
- if (event !== null) {
- return event.state;
- } else {
- return this._initial;
- }
- };
- /**
- * Add a state to the timeline.
- * @param {String} state The name of the state to set.
- * @param {Number} time The time to query.
- * @returns {Tone.TimelineState} this
- */
- Tone.TimelineState.prototype.setStateAtTime = function (state, time) {
- this.add({
- 'state': state,
- 'time': time
- });
- return this;
- };
- return Tone.TimelineState;
- });
- Module(function (Tone) {
-
- /**
- * @class A sample accurate clock which provides a callback at the given rate.
- * While the callback is not sample-accurate (it is still susceptible to
- * loose JS timing), the time passed in as the argument to the callback
- * is precise. For most applications, it is better to use Tone.Transport
- * instead of the Clock by itself since you can synchronize multiple callbacks.
- *
- * @constructor
- * @extends {Tone.Emitter}
- * @param {function} callback The callback to be invoked with the time of the audio event
- * @param {Frequency} frequency The rate of the callback
- * @example
- * //the callback will be invoked approximately once a second
- * //and will print the time exactly once a second apart.
- * var clock = new Tone.Clock(function(time){
- * console.log(time);
- * }, 1);
- */
- Tone.Clock = function () {
- var options = Tone.defaults(arguments, [
- 'callback',
- 'frequency'
- ], Tone.Clock);
- Tone.Emitter.call(this);
- /**
- * The callback function to invoke at the scheduled tick.
- * @type {Function}
- */
- this.callback = options.callback;
- /**
- * The next time the callback is scheduled.
- * @type {Number}
- * @private
- */
- this._nextTick = 0;
- /**
- * The last state of the clock.
- * @type {State}
- * @private
- */
- this._lastState = Tone.State.Stopped;
- /**
- * The rate the callback function should be invoked.
- * @type {BPM}
- * @signal
- */
- this.frequency = new Tone.TickSignal(options.frequency, Tone.Type.Frequency);
- this._readOnly('frequency');
- /**
- * The number of times the callback was invoked. Starts counting at 0
- * and increments after the callback was invoked.
- * @type {Ticks}
- * @readOnly
- */
- this.ticks = 0;
- /**
- * The state timeline
- * @type {Tone.TimelineState}
- * @private
- */
- this._state = new Tone.TimelineState(Tone.State.Stopped);
- /**
- * The loop function bound to its context.
- * This is necessary to remove the event in the end.
- * @type {Function}
- * @private
- */
- this._boundLoop = this._loop.bind(this);
- //bind a callback to the worker thread
- this.context.on('tick', this._boundLoop);
- };
- Tone.extend(Tone.Clock, Tone.Emitter);
- /**
- * The defaults
- * @const
- * @type {Object}
- */
- Tone.Clock.defaults = {
- 'callback': Tone.noOp,
- 'frequency': 1
- };
- /**
- * Returns the playback state of the source, either "started", "stopped" or "paused".
- * @type {Tone.State}
- * @readOnly
- * @memberOf Tone.Clock#
- * @name state
- */
- Object.defineProperty(Tone.Clock.prototype, 'state', {
- get: function () {
- return this._state.getValueAtTime(this.now());
- }
- });
- /**
- * Start the clock at the given time. Optionally pass in an offset
- * of where to start the tick counter from.
- * @param {Time=} time The time the clock should start
- * @param {Ticks=} offset Where the tick counter starts counting from.
- * @return {Tone.Clock} this
- */
- Tone.Clock.prototype.start = function (time, offset) {
- time = this.toSeconds(time);
- if (this._state.getValueAtTime(time) !== Tone.State.Started) {
- this._state.setStateAtTime(Tone.State.Started, time);
- this._state.get(time).offset = offset;
- }
- return this;
- };
- /**
- * Stop the clock. Stopping the clock resets the tick counter to 0.
- * @param {Time} [time=now] The time when the clock should stop.
- * @returns {Tone.Clock} this
- * @example
- * clock.stop();
- */
- Tone.Clock.prototype.stop = function (time) {
- time = this.toSeconds(time);
- this._state.cancel(time);
- this._state.setStateAtTime(Tone.State.Stopped, time);
- return this;
- };
- /**
- * Pause the clock. Pausing does not reset the tick counter.
- * @param {Time} [time=now] The time when the clock should stop.
- * @returns {Tone.Clock} this
- */
- Tone.Clock.prototype.pause = function (time) {
- time = this.toSeconds(time);
- if (this._state.getValueAtTime(time) === Tone.State.Started) {
- this._state.setStateAtTime(Tone.State.Paused, time);
- }
- return this;
- };
- /**
- * The scheduling loop.
- * @private
- */
- Tone.Clock.prototype._loop = function () {
- //the end of the update interval
- var endTime = this.now() + this.context.updateInterval;
- //the current event at the time of the loop
- var event = this._state.get(endTime);
- if (event) {
- //state change events
- if (event.state !== this._lastState) {
- this._lastState = event.state;
- switch (event.state) {
- case Tone.State.Started:
- if (!Tone.isUndef(event.offset)) {
- this.ticks = event.offset;
- }
- this._nextTick = event.time;
- this.emit('start', event.time, this.ticks);
- break;
- case Tone.State.Stopped:
- this.ticks = 0;
- this.emit('stop', event.time);
- break;
- case Tone.State.Paused:
- this.emit('pause', event.time);
- break;
- }
- }
- //all the tick events
- while (endTime > this._nextTick && this._state) {
- var tickTime = this._nextTick;
- if (this.frequency) {
- this._nextTick += this.frequency.getDurationOfTicks(1, this._nextTick);
- if (event.state === Tone.State.Started) {
- try {
- this.callback(tickTime);
- this.ticks++;
- } catch (e) {
- this.ticks++;
- throw e;
- }
- }
- }
- }
- }
- };
- /**
- * Returns the scheduled state at the given time.
- * @param {Time} time The time to query.
- * @return {String} The name of the state input in setStateAtTime.
- * @example
- * clock.start("+0.1");
- * clock.getStateAtTime("+0.1"); //returns "started"
- */
- Tone.Clock.prototype.getStateAtTime = function (time) {
- time = this.toSeconds(time);
- return this._state.getValueAtTime(time);
- };
- /**
- * Clean up
- * @returns {Tone.Clock} this
- */
- Tone.Clock.prototype.dispose = function () {
- Tone.Emitter.prototype.dispose.call(this);
- this.context.off('tick', this._boundLoop);
- this._writable('frequency');
- this.frequency.dispose();
- this.frequency = null;
- this._boundLoop = null;
- this._nextTick = Infinity;
- this.callback = null;
- this._state.dispose();
- this._state = null;
- };
- return Tone.Clock;
- });
- Module(function (Tone) {
-
- /**
- * @class Similar to Tone.Timeline, but all events represent
- * intervals with both "time" and "duration" times. The
- * events are placed in a tree structure optimized
- * for querying an intersection point with the timeline
- * events. Internally uses an [Interval Tree](https://en.wikipedia.org/wiki/Interval_tree)
- * to represent the data.
- * @extends {Tone}
- */
- Tone.IntervalTimeline = function () {
- Tone.call(this);
- /**
- * The root node of the inteval tree
- * @type {IntervalNode}
- * @private
- */
- this._root = null;
- /**
- * Keep track of the length of the timeline.
- * @type {Number}
- * @private
- */
- this._length = 0;
- };
- Tone.extend(Tone.IntervalTimeline);
- /**
- * The event to add to the timeline. All events must
- * have a time and duration value
- * @param {Object} event The event to add to the timeline
- * @return {Tone.IntervalTimeline} this
- */
- Tone.IntervalTimeline.prototype.add = function (event) {
- if (Tone.isUndef(event.time) || Tone.isUndef(event.duration)) {
- throw new Error('Tone.IntervalTimeline: events must have time and duration parameters');
- }
- var node = new IntervalNode(event.time, event.time + event.duration, event);
- if (this._root === null) {
- this._root = node;
- } else {
- this._root.insert(node);
- }
- this._length++;
- // Restructure tree to be balanced
- while (node !== null) {
- node.updateHeight();
- node.updateMax();
- this._rebalance(node);
- node = node.parent;
- }
- return this;
- };
- /**
- * Remove an event from the timeline.
- * @param {Object} event The event to remove from the timeline
- * @return {Tone.IntervalTimeline} this
- */
- Tone.IntervalTimeline.prototype.remove = function (event) {
- if (this._root !== null) {
- var results = [];
- this._root.search(event.time, results);
- for (var i = 0; i < results.length; i++) {
- var node = results[i];
- if (node.event === event) {
- this._removeNode(node);
- this._length--;
- break;
- }
- }
- }
- return this;
- };
- /**
- * The number of items in the timeline.
- * @type {Number}
- * @memberOf Tone.IntervalTimeline#
- * @name length
- * @readOnly
- */
- Object.defineProperty(Tone.IntervalTimeline.prototype, 'length', {
- get: function () {
- return this._length;
- }
- });
- /**
- * Remove events whose time time is after the given time
- * @param {Number} time The time to query.
- * @returns {Tone.IntervalTimeline} this
- */
- Tone.IntervalTimeline.prototype.cancel = function (after) {
- this.forEachAfter(after, function (event) {
- this.remove(event);
- }.bind(this));
- return this;
- };
- /**
- * Set the root node as the given node
- * @param {IntervalNode} node
- * @private
- */
- Tone.IntervalTimeline.prototype._setRoot = function (node) {
- this._root = node;
- if (this._root !== null) {
- this._root.parent = null;
- }
- };
- /**
- * Replace the references to the node in the node's parent
- * with the replacement node.
- * @param {IntervalNode} node
- * @param {IntervalNode} replacement
- * @private
- */
- Tone.IntervalTimeline.prototype._replaceNodeInParent = function (node, replacement) {
- if (node.parent !== null) {
- if (node.isLeftChild()) {
- node.parent.left = replacement;
- } else {
- node.parent.right = replacement;
- }
- this._rebalance(node.parent);
- } else {
- this._setRoot(replacement);
- }
- };
- /**
- * Remove the node from the tree and replace it with
- * a successor which follows the schema.
- * @param {IntervalNode} node
- * @private
- */
- Tone.IntervalTimeline.prototype._removeNode = function (node) {
- if (node.left === null && node.right === null) {
- this._replaceNodeInParent(node, null);
- } else if (node.right === null) {
- this._replaceNodeInParent(node, node.left);
- } else if (node.left === null) {
- this._replaceNodeInParent(node, node.right);
- } else {
- var balance = node.getBalance();
- var replacement, temp;
- if (balance > 0) {
- if (node.left.right === null) {
- replacement = node.left;
- replacement.right = node.right;
- temp = replacement;
- } else {
- replacement = node.left.right;
- while (replacement.right !== null) {
- replacement = replacement.right;
- }
- replacement.parent.right = replacement.left;
- temp = replacement.parent;
- replacement.left = node.left;
- replacement.right = node.right;
- }
- } else {
- if (node.right.left === null) {
- replacement = node.right;
- replacement.left = node.left;
- temp = replacement;
- } else {
- replacement = node.right.left;
- while (replacement.left !== null) {
- replacement = replacement.left;
- }
- replacement.parent = replacement.parent;
- replacement.parent.left = replacement.right;
- temp = replacement.parent;
- replacement.left = node.left;
- replacement.right = node.right;
- }
- }
- if (node.parent !== null) {
- if (node.isLeftChild()) {
- node.parent.left = replacement;
- } else {
- node.parent.right = replacement;
- }
- } else {
- this._setRoot(replacement);
- }
- // this._replaceNodeInParent(node, replacement);
- this._rebalance(temp);
- }
- node.dispose();
- };
- /**
- * Rotate the tree to the left
- * @param {IntervalNode} node
- * @private
- */
- Tone.IntervalTimeline.prototype._rotateLeft = function (node) {
- var parent = node.parent;
- var isLeftChild = node.isLeftChild();
- // Make node.right the new root of this sub tree (instead of node)
- var pivotNode = node.right;
- node.right = pivotNode.left;
- pivotNode.left = node;
- if (parent !== null) {
- if (isLeftChild) {
- parent.left = pivotNode;
- } else {
- parent.right = pivotNode;
- }
- } else {
- this._setRoot(pivotNode);
- }
- };
- /**
- * Rotate the tree to the right
- * @param {IntervalNode} node
- * @private
- */
- Tone.IntervalTimeline.prototype._rotateRight = function (node) {
- var parent = node.parent;
- var isLeftChild = node.isLeftChild();
- // Make node.left the new root of this sub tree (instead of node)
- var pivotNode = node.left;
- node.left = pivotNode.right;
- pivotNode.right = node;
- if (parent !== null) {
- if (isLeftChild) {
- parent.left = pivotNode;
- } else {
- parent.right = pivotNode;
- }
- } else {
- this._setRoot(pivotNode);
- }
- };
- /**
- * Balance the BST
- * @param {IntervalNode} node
- * @private
- */
- Tone.IntervalTimeline.prototype._rebalance = function (node) {
- var balance = node.getBalance();
- if (balance > 1) {
- if (node.left.getBalance() < 0) {
- this._rotateLeft(node.left);
- } else {
- this._rotateRight(node);
- }
- } else if (balance < -1) {
- if (node.right.getBalance() > 0) {
- this._rotateRight(node.right);
- } else {
- this._rotateLeft(node);
- }
- }
- };
- /**
- * Get an event whose time and duration span the give time. Will
- * return the match whose "time" value is closest to the given time.
- * @param {Object} event The event to add to the timeline
- * @return {Object} The event which spans the desired time
- */
- Tone.IntervalTimeline.prototype.get = function (time) {
- if (this._root !== null) {
- var results = [];
- this._root.search(time, results);
- if (results.length > 0) {
- var max = results[0];
- for (var i = 1; i < results.length; i++) {
- if (results[i].low > max.low) {
- max = results[i];
- }
- }
- return max.event;
- }
- }
- return null;
- };
- /**
- * Iterate over everything in the timeline.
- * @param {Function} callback The callback to invoke with every item
- * @returns {Tone.IntervalTimeline} this
- */
- Tone.IntervalTimeline.prototype.forEach = function (callback) {
- if (this._root !== null) {
- var allNodes = [];
- this._root.traverse(function (node) {
- allNodes.push(node);
- });
- for (var i = 0; i < allNodes.length; i++) {
- var ev = allNodes[i].event;
- if (ev) {
- callback(ev);
- }
- }
- }
- return this;
- };
- /**
- * Iterate over everything in the array in which the given time
- * overlaps with the time and duration time of the event.
- * @param {Number} time The time to check if items are overlapping
- * @param {Function} callback The callback to invoke with every item
- * @returns {Tone.IntervalTimeline} this
- */
- Tone.IntervalTimeline.prototype.forEachAtTime = function (time, callback) {
- if (this._root !== null) {
- var results = [];
- this._root.search(time, results);
- for (var i = results.length - 1; i >= 0; i--) {
- var ev = results[i].event;
- if (ev) {
- callback(ev);
- }
- }
- }
- return this;
- };
- /**
- * Iterate over everything in the array in which the time is greater
- * than the given time.
- * @param {Number} time The time to check if items are before
- * @param {Function} callback The callback to invoke with every item
- * @returns {Tone.IntervalTimeline} this
- */
- Tone.IntervalTimeline.prototype.forEachAfter = function (time, callback) {
- if (this._root !== null) {
- var results = [];
- this._root.searchAfter(time, results);
- for (var i = results.length - 1; i >= 0; i--) {
- var ev = results[i].event;
- callback(ev);
- }
- }
- return this;
- };
- /**
- * Clean up
- * @return {Tone.IntervalTimeline} this
- */
- Tone.IntervalTimeline.prototype.dispose = function () {
- var allNodes = [];
- if (this._root !== null) {
- this._root.traverse(function (node) {
- allNodes.push(node);
- });
- }
- for (var i = 0; i < allNodes.length; i++) {
- allNodes[i].dispose();
- }
- allNodes = null;
- this._root = null;
- return this;
- };
- ///////////////////////////////////////////////////////////////////////////
- // INTERVAL NODE HELPER
- ///////////////////////////////////////////////////////////////////////////
- /**
- * Represents a node in the binary search tree, with the addition
- * of a "high" value which keeps track of the highest value of
- * its children.
- * References:
- * https://brooknovak.wordpress.com/2013/12/07/augmented-interval-tree-in-c/
- * http://www.mif.vu.lt/~valdas/ALGORITMAI/LITERATURA/Cormen/Cormen.pdf
- * @param {Number} low
- * @param {Number} high
- * @private
- */
- var IntervalNode = function (low, high, event) {
- //the event container
- this.event = event;
- //the low value
- this.low = low;
- //the high value
- this.high = high;
- //the high value for this and all child nodes
- this.max = this.high;
- //the nodes to the left
- this._left = null;
- //the nodes to the right
- this._right = null;
- //the parent node
- this.parent = null;
- //the number of child nodes
- this.height = 0;
- };
- /**
- * Insert a node into the correct spot in the tree
- * @param {IntervalNode} node
- */
- IntervalNode.prototype.insert = function (node) {
- if (node.low <= this.low) {
- if (this.left === null) {
- this.left = node;
- } else {
- this.left.insert(node);
- }
- } else {
- if (this.right === null) {
- this.right = node;
- } else {
- this.right.insert(node);
- }
- }
- };
- /**
- * Search the tree for nodes which overlap
- * with the given point
- * @param {Number} point The point to query
- * @param {Array} results The array to put the results
- */
- IntervalNode.prototype.search = function (point, results) {
- // If p is to the right of the rightmost point of any interval
- // in this node and all children, there won't be any matches.
- if (point > this.max) {
- return;
- }
- // Search left children
- if (this.left !== null) {
- this.left.search(point, results);
- }
- // Check this node
- if (this.low <= point && this.high > point) {
- results.push(this);
- }
- // If p is to the left of the time of this interval,
- // then it can't be in any child to the right.
- if (this.low > point) {
- return;
- }
- // Search right children
- if (this.right !== null) {
- this.right.search(point, results);
- }
- };
- /**
- * Search the tree for nodes which are less
- * than the given point
- * @param {Number} point The point to query
- * @param {Array} results The array to put the results
- */
- IntervalNode.prototype.searchAfter = function (point, results) {
- // Check this node
- if (this.low >= point) {
- results.push(this);
- if (this.left !== null) {
- this.left.searchAfter(point, results);
- }
- }
- // search the right side
- if (this.right !== null) {
- this.right.searchAfter(point, results);
- }
- };
- /**
- * Invoke the callback on this element and both it's branches
- * @param {Function} callback
- */
- IntervalNode.prototype.traverse = function (callback) {
- callback(this);
- if (this.left !== null) {
- this.left.traverse(callback);
- }
- if (this.right !== null) {
- this.right.traverse(callback);
- }
- };
- /**
- * Update the height of the node
- */
- IntervalNode.prototype.updateHeight = function () {
- if (this.left !== null && this.right !== null) {
- this.height = Math.max(this.left.height, this.right.height) + 1;
- } else if (this.right !== null) {
- this.height = this.right.height + 1;
- } else if (this.left !== null) {
- this.height = this.left.height + 1;
- } else {
- this.height = 0;
- }
- };
- /**
- * Update the height of the node
- */
- IntervalNode.prototype.updateMax = function () {
- this.max = this.high;
- if (this.left !== null) {
- this.max = Math.max(this.max, this.left.max);
- }
- if (this.right !== null) {
- this.max = Math.max(this.max, this.right.max);
- }
- };
- /**
- * The balance is how the leafs are distributed on the node
- * @return {Number} Negative numbers are balanced to the right
- */
- IntervalNode.prototype.getBalance = function () {
- var balance = 0;
- if (this.left !== null && this.right !== null) {
- balance = this.left.height - this.right.height;
- } else if (this.left !== null) {
- balance = this.left.height + 1;
- } else if (this.right !== null) {
- balance = -(this.right.height + 1);
- }
- return balance;
- };
- /**
- * @returns {Boolean} true if this node is the left child
- * of its parent
- */
- IntervalNode.prototype.isLeftChild = function () {
- return this.parent !== null && this.parent.left === this;
- };
- /**
- * get/set the left node
- * @type {IntervalNode}
- */
- Object.defineProperty(IntervalNode.prototype, 'left', {
- get: function () {
- return this._left;
- },
- set: function (node) {
- this._left = node;
- if (node !== null) {
- node.parent = this;
- }
- this.updateHeight();
- this.updateMax();
- }
- });
- /**
- * get/set the right node
- * @type {IntervalNode}
- */
- Object.defineProperty(IntervalNode.prototype, 'right', {
- get: function () {
- return this._right;
- },
- set: function (node) {
- this._right = node;
- if (node !== null) {
- node.parent = this;
- }
- this.updateHeight();
- this.updateMax();
- }
- });
- /**
- * null out references.
- */
- IntervalNode.prototype.dispose = function () {
- this.parent = null;
- this._left = null;
- this._right = null;
- this.event = null;
- };
- ///////////////////////////////////////////////////////////////////////////
- // END INTERVAL NODE HELPER
- ///////////////////////////////////////////////////////////////////////////
- return Tone.IntervalTimeline;
- });
- Module(function (Tone) {
- /**
- * @class Tone.TransportEvent is an internal class used by (Tone.Transport)[Transport]
- * to schedule events. Do no invoke this class directly, it is
- * handled from within Tone.Transport.
- * @extends {Tone}
- * @param {Object} options
- */
- Tone.TransportEvent = function (Transport, options) {
- options = Tone.defaultArg(options, Tone.TransportEvent.defaults);
- Tone.call(this);
- /**
- * Reference to the Transport that created it
- * @type {Tone.Transport}
- */
- this.Transport = Transport;
- /**
- * The unique id of the event
- * @type {Number}
- */
- this.id = Tone.TransportEvent._eventId++;
- /**
- * The time the event starts
- * @type {Ticks}
- */
- this.time = options.time;
- /**
- * The callback to invoke
- * @type {Function}
- */
- this.callback = options.callback;
- /**
- * If the event should be removed after being created.
- * @type {Boolean}
- * @private
- */
- this._once = options.once;
- };
- Tone.extend(Tone.TransportEvent);
- /**
- * The defaults
- * @static
- * @type {Object}
- */
- Tone.TransportEvent.defaults = {
- 'once': false,
- 'callback': Tone.noOp
- };
- /**
- * Current ID counter
- * @private
- * @static
- * @type {Number}
- */
- Tone.TransportEvent._eventId = 0;
- /**
- * Invoke the callback even callback.
- * @param {Time} time The AudioContext time in seconds of the event
- */
- Tone.TransportEvent.prototype.invoke = function (time) {
- if (this.callback) {
- this.callback(time);
- if (this._once && this.Transport) {
- this.Transport.clear(this.id);
- }
- }
- };
- /**
- * Clean up
- * @return {Tone.TransportEvent} this
- */
- Tone.TransportEvent.prototype.dispose = function () {
- Tone.prototype.dispose.call(this);
- this.Transport = null;
- this.callback = null;
- return this;
- };
- return Tone.TransportEvent;
- });
- Module(function (Tone) {
- /**
- * @class Tone.TransportRepeatEvent is an internal class used by Tone.Transport
- * to schedule repeat events. This class should not be instantiated directly.
- * @extends {Tone.TransportEvent}
- * @param {Object} options
- */
- Tone.TransportRepeatEvent = function (Transport, options) {
- Tone.TransportEvent.call(this, Transport, options);
- options = Tone.defaultArg(options, Tone.TransportRepeatEvent.defaults);
- /**
- * When the event should stop repeating
- * @type {Ticks}
- * @private
- */
- this.duration = options.duration;
- /**
- * The interval of the repeated event
- * @type {Ticks}
- * @private
- */
- this._interval = options.interval;
- /**
- * The ID of the current timeline event
- * @type {Number}
- * @private
- */
- this._currentId = -1;
- /**
- * The ID of the next timeline event
- * @type {Number}
- * @private
- */
- this._nextId = -1;
- /**
- * The time of the next event
- * @type {Ticks}
- * @private
- */
- this._nextTick = this.time;
- /**
- * a reference to the bound start method
- * @type {Function}
- * @private
- */
- this._boundRestart = this._restart.bind(this);
- this.Transport.on('start loopStart', this._boundRestart);
- this._restart();
- };
- Tone.extend(Tone.TransportRepeatEvent, Tone.TransportEvent);
- /**
- * The defaults
- * @static
- * @type {Object}
- */
- Tone.TransportRepeatEvent.defaults = {
- 'duration': Infinity,
- 'interval': 1
- };
- /**
- * Invoke the callback. Returns the tick time which
- * the next event should be scheduled at.
- * @param {Number} time The AudioContext time in seconds of the event
- */
- Tone.TransportRepeatEvent.prototype.invoke = function (time) {
- //create more events if necessary
- this._createEvents();
- //call the super class
- Tone.TransportEvent.prototype.invoke.call(this, time);
- };
- /**
- * Push more events onto the timeline to keep up with the position of the timeline
- * @private
- */
- Tone.TransportRepeatEvent.prototype._createEvents = function () {
- // schedule the next event
- var ticks = this.Transport.ticks;
- if (ticks >= this.time && ticks >= this._nextTick && this._nextTick + this._interval < this.time + this.duration) {
- this._nextTick += this._interval;
- this._currentId = this._nextId;
- this._nextId = this.Transport.scheduleOnce(this.invoke.bind(this), Tone.TransportTime(this._nextTick, 'i'));
- }
- };
- /**
- * Push more events onto the timeline to keep up with the position of the timeline
- * @private
- */
- Tone.TransportRepeatEvent.prototype._restart = function () {
- this.Transport.clear(this._currentId);
- this.Transport.clear(this._nextId);
- var ticks = this.Transport.ticks;
- this._nextTick = this.time;
- if (ticks > this.time) {
- this._nextTick = this.time + Math.ceil((ticks - this.time) / this._interval) * this._interval;
- }
- this._currentId = this.Transport.scheduleOnce(this.invoke.bind(this), Tone.TransportTime(this._nextTick, 'i'));
- this._nextTick += this._interval;
- this._nextId = this.Transport.scheduleOnce(this.invoke.bind(this), Tone.TransportTime(this._nextTick, 'i'));
- };
- /**
- * Clean up
- * @return {Tone.TransportRepeatEvent} this
- */
- Tone.TransportRepeatEvent.prototype.dispose = function () {
- this.Transport.clear(this._currentId);
- this.Transport.clear(this._nextId);
- this.Transport.off('start loopStart', this._boundRestart);
- this._boundCreateEvents = null;
- Tone.TransportEvent.prototype.dispose.call(this);
- return this;
- };
- return Tone.TransportRepeatEvent;
- });
- Module(function (Tone) {
-
- /**
- * @class Transport for timing musical events.
- * Supports tempo curves and time changes. Unlike browser-based timing (setInterval, requestAnimationFrame)
- * Tone.Transport timing events pass in the exact time of the scheduled event
- * in the argument of the callback function. Pass that time value to the object
- * you're scheduling. input[0]
- * @type {GainNode}
- */
- this.left = this.input[0] = new Tone.Gain();
- /**
- * The right input channel.
- * Alias for input[1].
- * @type {GainNode}
- */
- this.right = this.input[1] = new Tone.Gain();
- /**
- * the merger node for the two channels
- * @type {ChannelMergerNode}
- * @private
- */
- this._merger = this.output = this.context.createChannelMerger(2);
- //connections
- this.left.connect(this._merger, 0, 0);
- this.right.connect(this._merger, 0, 1);
- this.left.channelCount = 1;
- this.right.channelCount = 1;
- this.left.channelCountMode = 'explicit';
- this.right.channelCountMode = 'explicit';
- };
- Tone.extend(Tone.Merge, Tone.AudioNode);
- /**
- * Clean up.
- * @returns {Tone.Merge} this
- */
- Tone.Merge.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this.left.dispose();
- this.left = null;
- this.right.dispose();
- this.right = null;
- this._merger.disconnect();
- this._merger = null;
- return this;
- };
- return Tone.Merge;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Meter gets the [RMS](https://en.wikipedia.org/wiki/Root_mean_square)
- * of an input signal with some averaging applied. It can also get the raw
- * value of the input signal.
- *
- * @constructor
- * @extends {Tone.AudioNode}
- * @param {Number} smoothing The amount of smoothing applied between frames.
- * @example
- * var meter = new Tone.Meter();
- * var mic = new Tone.UserMedia().open();
- * //connect mic to the meter
- * mic.connect(meter);
- * //the current level of the mic input in decibels
- * var level = meter.getValue();
- */
- Tone.Meter = function () {
- var options = Tone.defaults(arguments, ['smoothing'], Tone.Meter);
- Tone.AudioNode.call(this);
- /**
- * The analyser node which computes the levels.
- * @private
- * @type {Tone.Analyser}
- */
- this.input = this.output = this._analyser = new Tone.Analyser('waveform', 1024);
- /**
- * The amount of carryover between the current and last frame.
- * Only applied meter for "level" type.
- * @type {Number}
- */
- this.smoothing = options.smoothing;
- };
- Tone.extend(Tone.Meter, Tone.AudioNode);
- /**
- * The defaults
- * @type {Object}
- * @static
- * @const
- */
- Tone.Meter.defaults = { 'smoothing': 0.8 };
- /**
- * Get the current decibel value of the incoming signal
- * @returns {Decibels}
- */
- Tone.Meter.prototype.getLevel = function () {
- this._analyser.type = 'fft';
- var values = this._analyser.getValue();
- var offset = 28;
- // normalizes most signal levels
- // TODO: compute loudness from FFT
- return Math.max.apply(this, values) + offset;
- };
- /**
- * Get the signal value of the incoming signal
- * @returns {Number}
- */
- Tone.Meter.prototype.getValue = function () {
- this._analyser.type = 'waveform';
- var value = this._analyser.getValue();
- return value[0];
- };
- /**
- * A value from 0 -> 1 where 0 represents no time averaging with the last analysis frame.
- * @memberOf Tone.Meter#
- * @type {Number}
- * @name smoothing
- * @readOnly
- */
- Object.defineProperty(Tone.Meter.prototype, 'smoothing', {
- get: function () {
- return this._analyser.smoothing;
- },
- set: function (val) {
- this._analyser.smoothing = val;
- }
- });
- /**
- * Clean up.
- * @returns {Tone.Meter} this
- */
- Tone.Meter.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._analyser.dispose();
- this._analyser = null;
- return this;
- };
- return Tone.Meter;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Split splits an incoming signal into left and right channels.
- *
- * @constructor
- * @extends {Tone.AudioNode}
- * @example
- * var split = new Tone.Split();
- * stereoSignal.connect(split);
- */
- Tone.Split = function () {
- Tone.AudioNode.call(this);
- this.createInsOuts(0, 2);
- /**
- * @type {ChannelSplitterNode}
- * @private
- */
- this._splitter = this.input = this.context.createChannelSplitter(2);
- this._splitter.channelCount = 2;
- this._splitter.channelCountMode = 'explicit';
- /**
- * Left channel output.
- * Alias for output[0]
- * @type {Tone.Gain}
- */
- this.left = this.output[0] = new Tone.Gain();
- /**
- * Right channel output.
- * Alias for output[1]
- * @type {Tone.Gain}
- */
- this.right = this.output[1] = new Tone.Gain();
- //connections
- this._splitter.connect(this.left, 0, 0);
- this._splitter.connect(this.right, 1, 0);
- };
- Tone.extend(Tone.Split, Tone.AudioNode);
- /**
- * Clean up.
- * @returns {Tone.Split} this
- */
- Tone.Split.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._splitter.disconnect();
- this.left.dispose();
- this.left = null;
- this.right.dispose();
- this.right = null;
- this._splitter = null;
- return this;
- };
- return Tone.Split;
- });
- Module(function (Tone) {
-
- /**
- * @class Mid/Side processing separates the the 'mid' signal
- * (which comes out of both the left and the right channel)
- * and the 'side' (which only comes out of the the side channels).
- * Mid = (Left+Right)/sqrt(2); // obtain mid-signal from left and right
- * Side = (Left-Right)/sqrt(2); // obtain side-signal from left and righ
- *
- *
- * @extends {Tone.AudioNode}
- * @constructor
- */
- Tone.MidSideSplit = function () {
- Tone.AudioNode.call(this);
- this.createInsOuts(0, 2);
- /**
- * split the incoming signal into left and right channels
- * @type {Tone.Split}
- * @private
- */
- this._split = this.input = new Tone.Split();
- /**
- * The mid send. Connect to mid processing. Alias for
- * output[0]
- * @type {Tone.Expr}
- */
- this.mid = this.output[0] = new Tone.Expr('($0 + $1) * $2');
- /**
- * The side output. Connect to side processing. Alias for
- * output[1]
- * @type {Tone.Expr}
- */
- this.side = this.output[1] = new Tone.Expr('($0 - $1) * $2');
- this._split.connect(this.mid, 0, 0);
- this._split.connect(this.mid, 1, 1);
- this._split.connect(this.side, 0, 0);
- this._split.connect(this.side, 1, 1);
- this.context.getConstant(Math.SQRT1_2).connect(this.mid, 0, 2);
- this.context.getConstant(Math.SQRT1_2).connect(this.side, 0, 2);
- };
- Tone.extend(Tone.MidSideSplit, Tone.AudioNode);
- /**
- * clean up
- * @returns {Tone.MidSideSplit} this
- */
- Tone.MidSideSplit.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this.mid.dispose();
- this.mid = null;
- this.side.dispose();
- this.side = null;
- this._split.dispose();
- this._split = null;
- return this;
- };
- return Tone.MidSideSplit;
- });
- Module(function (Tone) {
-
- /**
- * @class Mid/Side processing separates the the 'mid' signal
- * (which comes out of both the left and the right channel)
- * and the 'side' (which only comes out of the the side channels).
- * MidSideMerge merges the mid and side signal after they've been seperated
- * by Tone.MidSideSplit.
- * Left = (Mid+Side)/sqrt(2); // obtain left signal from mid and side
- * Right = (Mid-Side)/sqrt(2); // obtain right signal from mid and side
- *
- *
- * @extends {Tone.AudioNode}
- * @constructor
- */
- Tone.MidSideMerge = function () {
- Tone.AudioNode.call(this);
- this.createInsOuts(2, 0);
- /**
- * The mid signal input. Alias for
- * input[0]
- * @type {Tone.Gain}
- */
- this.mid = this.input[0] = new Tone.Gain();
- /**
- * recombine the mid/side into Left
- * @type {Tone.Expr}
- * @private
- */
- this._left = new Tone.Expr('($0 + $1) * $2');
- /**
- * The side signal input. Alias for
- * input[1]
- * @type {Tone.Gain}
- */
- this.side = this.input[1] = new Tone.Gain();
- /**
- * recombine the mid/side into Right
- * @type {Tone.Expr}
- * @private
- */
- this._right = new Tone.Expr('($0 - $1) * $2');
- /**
- * Merge the left/right signal back into a stereo signal.
- * @type {Tone.Merge}
- * @private
- */
- this._merge = this.output = new Tone.Merge();
- this.mid.connect(this._left, 0, 0);
- this.side.connect(this._left, 0, 1);
- this.mid.connect(this._right, 0, 0);
- this.side.connect(this._right, 0, 1);
- this._left.connect(this._merge, 0, 0);
- this._right.connect(this._merge, 0, 1);
- this.context.getConstant(Math.SQRT1_2).connect(this._left, 0, 2);
- this.context.getConstant(Math.SQRT1_2).connect(this._right, 0, 2);
- };
- Tone.extend(Tone.MidSideMerge, Tone.AudioNode);
- /**
- * clean up
- * @returns {Tone.MidSideMerge} this
- */
- Tone.MidSideMerge.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this.mid.dispose();
- this.mid = null;
- this.side.dispose();
- this.side = null;
- this._left.dispose();
- this._left = null;
- this._right.dispose();
- this._right = null;
- this._merge.dispose();
- this._merge = null;
- return this;
- };
- return Tone.MidSideMerge;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.MidSideCompressor applies two different compressors to the mid
- * and side signal components. See Tone.MidSideSplit.
- *
- * @extends {Tone.AudioNode}
- * @param {Object} options The options that are passed to the mid and side
- * compressors.
- * @constructor
- */
- Tone.MidSideCompressor = function (options) {
- Tone.AudioNode.call(this);
- options = Tone.defaultArg(options, Tone.MidSideCompressor.defaults);
- /**
- * the mid/side split
- * @type {Tone.MidSideSplit}
- * @private
- */
- this._midSideSplit = this.input = new Tone.MidSideSplit();
- /**
- * the mid/side recombination
- * @type {Tone.MidSideMerge}
- * @private
- */
- this._midSideMerge = this.output = new Tone.MidSideMerge();
- /**
- * The compressor applied to the mid signal
- * @type {Tone.Compressor}
- */
- this.mid = new Tone.Compressor(options.mid);
- /**
- * The compressor applied to the side signal
- * @type {Tone.Compressor}
- */
- this.side = new Tone.Compressor(options.side);
- this._midSideSplit.mid.chain(this.mid, this._midSideMerge.mid);
- this._midSideSplit.side.chain(this.side, this._midSideMerge.side);
- this._readOnly([
- 'mid',
- 'side'
- ]);
- };
- Tone.extend(Tone.MidSideCompressor, Tone.AudioNode);
- /**
- * @const
- * @static
- * @type {Object}
- */
- Tone.MidSideCompressor.defaults = {
- 'mid': {
- 'ratio': 3,
- 'threshold': -24,
- 'release': 0.03,
- 'attack': 0.02,
- 'knee': 16
- },
- 'side': {
- 'ratio': 6,
- 'threshold': -30,
- 'release': 0.25,
- 'attack': 0.03,
- 'knee': 10
- }
- };
- /**
- * Clean up.
- * @returns {Tone.MidSideCompressor} this
- */
- Tone.MidSideCompressor.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._writable([
- 'mid',
- 'side'
- ]);
- this.mid.dispose();
- this.mid = null;
- this.side.dispose();
- this.side = null;
- this._midSideSplit.dispose();
- this._midSideSplit = null;
- this._midSideMerge.dispose();
- this._midSideMerge = null;
- return this;
- };
- return Tone.MidSideCompressor;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Mono coerces the incoming mono or stereo signal into a mono signal
- * where both left and right channels have the same value. This can be useful
- * for [stereo imaging](https://en.wikipedia.org/wiki/Stereo_imaging).
- *
- * @extends {Tone.AudioNode}
- * @constructor
- */
- Tone.Mono = function () {
- Tone.AudioNode.call(this);
- this.createInsOuts(1, 0);
- /**
- * merge the signal
- * @type {Tone.Merge}
- * @private
- */
- this._merge = this.output = new Tone.Merge();
- this.input.connect(this._merge, 0, 0);
- this.input.connect(this._merge, 0, 1);
- this.input.gain.value = Tone.dbToGain(-10);
- };
- Tone.extend(Tone.Mono);
- /**
- * clean up
- * @returns {Tone.Mono} this
- */
- Tone.Mono.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._merge.dispose();
- this._merge = null;
- return this;
- };
- return Tone.Mono;
- });
- Module(function (Tone) {
-
- /**
- * @class A compressor with seperate controls over low/mid/high dynamics
- *
- * @extends {Tone.AudioNode}
- * @constructor
- * @param {Object} options The low/mid/high compressor settings.
- * @example
- * var multiband = new Tone.MultibandCompressor({
- * "lowFrequency" : 200,
- * "highFrequency" : 1300
- * "low" : {
- * "threshold" : -12
- * }
- * })
- */
- Tone.MultibandCompressor = function (options) {
- Tone.AudioNode.call(this);
- options = Tone.defaultArg(arguments, Tone.MultibandCompressor.defaults);
- /**
- * split the incoming signal into high/mid/low
- * @type {Tone.MultibandSplit}
- * @private
- */
- this._splitter = this.input = new Tone.MultibandSplit({
- 'lowFrequency': options.lowFrequency,
- 'highFrequency': options.highFrequency
- });
- /**
- * low/mid crossover frequency.
- * @type {Frequency}
- * @signal
- */
- this.lowFrequency = this._splitter.lowFrequency;
- /**
- * mid/high crossover frequency.
- * @type {Frequency}
- * @signal
- */
- this.highFrequency = this._splitter.highFrequency;
- /**
- * the output
- * @type {Tone.Gain}
- * @private
- */
- this.output = new Tone.Gain();
- /**
- * The compressor applied to the low frequencies.
- * @type {Tone.Compressor}
- */
- this.low = new Tone.Compressor(options.low);
- /**
- * The compressor applied to the mid frequencies.
- * @type {Tone.Compressor}
- */
- this.mid = new Tone.Compressor(options.mid);
- /**
- * The compressor applied to the high frequencies.
- * @type {Tone.Compressor}
- */
- this.high = new Tone.Compressor(options.high);
- //connect the compressor
- this._splitter.low.chain(this.low, this.output);
- this._splitter.mid.chain(this.mid, this.output);
- this._splitter.high.chain(this.high, this.output);
- this._readOnly([
- 'high',
- 'mid',
- 'low',
- 'highFrequency',
- 'lowFrequency'
- ]);
- };
- Tone.extend(Tone.MultibandCompressor, Tone.AudioNode);
- /**
- * @const
- * @static
- * @type {Object}
- */
- Tone.MultibandCompressor.defaults = {
- 'low': Tone.Compressor.defaults,
- 'mid': Tone.Compressor.defaults,
- 'high': Tone.Compressor.defaults,
- 'lowFrequency': 250,
- 'highFrequency': 2000
- };
- /**
- * clean up
- * @returns {Tone.MultibandCompressor} this
- */
- Tone.MultibandCompressor.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._splitter.dispose();
- this._writable([
- 'high',
- 'mid',
- 'low',
- 'highFrequency',
- 'lowFrequency'
- ]);
- this.low.dispose();
- this.mid.dispose();
- this.high.dispose();
- this._splitter = null;
- this.low = null;
- this.mid = null;
- this.high = null;
- this.lowFrequency = null;
- this.highFrequency = null;
- return this;
- };
- return Tone.MultibandCompressor;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Panner is an equal power Left/Right Panner and does not
- * support 3D. Panner uses the StereoPannerNode when available.
- *
- * @constructor
- * @extends {Tone.AudioNode}
- * @param {NormalRange} [initialPan=0] The initail panner value (center).
- * @example
- * //pan the input signal hard right.
- * var panner = new Tone.Panner(1);
- */
- Tone.Panner = function (initialPan) {
- Tone.AudioNode.call(this);
- if (Tone.Panner.hasStereoPanner) {
- /**
- * the panner node
- * @type {StereoPannerNode}
- * @private
- */
- this._panner = this.input = this.output = this.context.createStereoPanner();
- /**
- * The pan control. -1 = hard left, 1 = hard right.
- * @type {NormalRange}
- * @signal
- */
- this.pan = this._panner.pan;
- } else {
- /**
- * the dry/wet knob
- * @type {Tone.CrossFade}
- * @private
- */
- this._crossFade = new Tone.CrossFade();
- /**
- * @type {Tone.Merge}
- * @private
- */
- this._merger = this.output = new Tone.Merge();
- /**
- * @type {Tone.Split}
- * @private
- */
- this._splitter = this.input = new Tone.Split();
- /**
- * The pan control. -1 = hard left, 1 = hard right.
- * @type {AudioRange}
- * @signal
- */
- this.pan = new Tone.Signal(0, Tone.Type.AudioRange);
- /**
- * always sends 0
- * @type {Tone.Zero}
- * @private
- */
- this._zero = new Tone.Zero();
- /**
- * The analog to gain conversion
- * @type {Tone.AudioToGain}
- * @private
- */
- this._a2g = new Tone.AudioToGain();
- //CONNECTIONS:
- this._zero.connect(this._a2g);
- this.pan.chain(this._a2g, this._crossFade.fade);
- //left channel is a, right channel is b
- this._splitter.connect(this._crossFade, 0, 0);
- this._splitter.connect(this._crossFade, 1, 1);
- //merge it back together
- this._crossFade.a.connect(this._merger, 0, 0);
- this._crossFade.b.connect(this._merger, 0, 1);
- }
- //initial value
- this.pan.value = Tone.defaultArg(initialPan, 0);
- this._readOnly('pan');
- };
- Tone.extend(Tone.Panner, Tone.AudioNode);
- /**
- * Indicates if the panner is using the new StereoPannerNode internally
- * @type {Boolean}
- * @static
- * @private
- * @readOnly
- */
- Tone.Panner.hasStereoPanner = Tone.context && Tone.isFunction(Tone.context.createStereoPanner);
- /**
- * Clean up.
- * @returns {Tone.Panner} this
- */
- Tone.Panner.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._writable('pan');
- if (Tone.Panner.hasStereoPanner) {
- this._panner.disconnect();
- this._panner = null;
- this.pan = null;
- } else {
- this._zero.dispose();
- this._zero = null;
- this._crossFade.dispose();
- this._crossFade = null;
- this._splitter.dispose();
- this._splitter = null;
- this._merger.dispose();
- this._merger = null;
- this.pan.dispose();
- this.pan = null;
- this._a2g.dispose();
- this._a2g = null;
- }
- return this;
- };
- return Tone.Panner;
- });
- Module(function (Tone) {
-
- /**
- * @class A spatialized panner node which supports equalpower or HRTF panning.
- * Tries to normalize the API across various browsers. See Tone.Listener
- *
- * @constructor
- * @extends {Tone.AudioNode}
- * @param {Number} positionX The initial x position.
- * @param {Number} positionY The initial y position.
- * @param {Number} positionZ The initial z position.
- */
- Tone.Panner3D = function () {
- var options = Tone.defaults(arguments, [
- 'positionX',
- 'positionY',
- 'positionZ'
- ], Tone.Panner3D);
- Tone.AudioNode.call(this);
- /**
- * The panner node
- * @type {PannerNode}
- * @private
- */
- this._panner = this.input = this.output = this.context.createPanner();
- //set some values
- this._panner.panningModel = options.panningModel;
- this._panner.maxDistance = options.maxDistance;
- this._panner.distanceModel = options.distanceModel;
- this._panner.coneOuterGain = options.coneOuterGain;
- this._panner.coneOuterAngle = options.coneOuterAngle;
- this._panner.coneInnerAngle = options.coneInnerAngle;
- this._panner.refDistance = options.refDistance;
- this._panner.rolloffFactor = options.rolloffFactor;
- /**
- * Holds the current orientation
- * @type {Array}
- * @private
- */
- this._orientation = [
- options.orientationX,
- options.orientationY,
- options.orientationZ
- ];
- /**
- * Holds the current position
- * @type {Array}
- * @private
- */
- this._position = [
- options.positionX,
- options.positionY,
- options.positionZ
- ];
- // set the default position/orientation
- this.orientationX = options.orientationX;
- this.orientationY = options.orientationY;
- this.orientationZ = options.orientationZ;
- this.positionX = options.positionX;
- this.positionY = options.positionY;
- this.positionZ = options.positionZ;
- };
- Tone.extend(Tone.Panner3D, Tone.AudioNode);
- /**
- * Defaults according to the specification
- * @static
- * @const
- * @type {Object}
- */
- Tone.Panner3D.defaults = {
- 'positionX': 0,
- 'positionY': 0,
- 'positionZ': 0,
- 'orientationX': 0,
- 'orientationY': 0,
- 'orientationZ': 0,
- 'panningModel': 'equalpower',
- 'maxDistance': 10000,
- 'distanceModel': 'inverse',
- 'coneOuterGain': 0,
- 'coneOuterAngle': 360,
- 'coneInnerAngle': 360,
- 'refDistance': 1,
- 'rolloffFactor': 1
- };
- /**
- * The ramp time which is applied to the setTargetAtTime
- * @type {Number}
- * @private
- */
- Tone.Panner3D.prototype._rampTimeConstant = 0.01;
- /**
- * Sets the position of the source in 3d space.
- * @param {Number} x
- * @param {Number} y
- * @param {Number} z
- * @return {Tone.Panner3D} this
- */
- Tone.Panner3D.prototype.setPosition = function (x, y, z) {
- if (this._panner.positionX) {
- var now = this.now();
- this._panner.positionX.setTargetAtTime(x, now, this._rampTimeConstant);
- this._panner.positionY.setTargetAtTime(y, now, this._rampTimeConstant);
- this._panner.positionZ.setTargetAtTime(z, now, this._rampTimeConstant);
- } else {
- this._panner.setPosition(x, y, z);
- }
- this._position = Array.prototype.slice.call(arguments);
- return this;
- };
- /**
- * Sets the orientation of the source in 3d space.
- * @param {Number} x
- * @param {Number} y
- * @param {Number} z
- * @return {Tone.Panner3D} this
- */
- Tone.Panner3D.prototype.setOrientation = function (x, y, z) {
- if (this._panner.orientationX) {
- var now = this.now();
- this._panner.orientationX.setTargetAtTime(x, now, this._rampTimeConstant);
- this._panner.orientationY.setTargetAtTime(y, now, this._rampTimeConstant);
- this._panner.orientationZ.setTargetAtTime(z, now, this._rampTimeConstant);
- } else {
- this._panner.setOrientation(x, y, z);
- }
- this._orientation = Array.prototype.slice.call(arguments);
- return this;
- };
- /**
- * The x position of the panner object.
- * @type {Number}
- * @memberOf Tone.Panner3D#
- * @name positionX
- */
- Object.defineProperty(Tone.Panner3D.prototype, 'positionX', {
- set: function (pos) {
- this._position[0] = pos;
- this.setPosition.apply(this, this._position);
- },
- get: function () {
- return this._position[0];
- }
- });
- /**
- * The y position of the panner object.
- * @type {Number}
- * @memberOf Tone.Panner3D#
- * @name positionY
- */
- Object.defineProperty(Tone.Panner3D.prototype, 'positionY', {
- set: function (pos) {
- this._position[1] = pos;
- this.setPosition.apply(this, this._position);
- },
- get: function () {
- return this._position[1];
- }
- });
- /**
- * The z position of the panner object.
- * @type {Number}
- * @memberOf Tone.Panner3D#
- * @name positionZ
- */
- Object.defineProperty(Tone.Panner3D.prototype, 'positionZ', {
- set: function (pos) {
- this._position[2] = pos;
- this.setPosition.apply(this, this._position);
- },
- get: function () {
- return this._position[2];
- }
- });
- /**
- * The x orientation of the panner object.
- * @type {Number}
- * @memberOf Tone.Panner3D#
- * @name orientationX
- */
- Object.defineProperty(Tone.Panner3D.prototype, 'orientationX', {
- set: function (pos) {
- this._orientation[0] = pos;
- this.setOrientation.apply(this, this._orientation);
- },
- get: function () {
- return this._orientation[0];
- }
- });
- /**
- * The y orientation of the panner object.
- * @type {Number}
- * @memberOf Tone.Panner3D#
- * @name orientationY
- */
- Object.defineProperty(Tone.Panner3D.prototype, 'orientationY', {
- set: function (pos) {
- this._orientation[1] = pos;
- this.setOrientation.apply(this, this._orientation);
- },
- get: function () {
- return this._orientation[1];
- }
- });
- /**
- * The z orientation of the panner object.
- * @type {Number}
- * @memberOf Tone.Panner3D#
- * @name orientationZ
- */
- Object.defineProperty(Tone.Panner3D.prototype, 'orientationZ', {
- set: function (pos) {
- this._orientation[2] = pos;
- this.setOrientation.apply(this, this._orientation);
- },
- get: function () {
- return this._orientation[2];
- }
- });
- /**
- * Proxy a property on the panner to an exposed public propery
- * @param {String} prop
- * @private
- */
- Tone.Panner3D._aliasProperty = function (prop) {
- Object.defineProperty(Tone.Panner3D.prototype, prop, {
- set: function (val) {
- this._panner[prop] = val;
- },
- get: function () {
- return this._panner[prop];
- }
- });
- };
- /**
- * The panning model. Either "equalpower" or "HRTF".
- * @type {String}
- * @memberOf Tone.Panner3D#
- * @name panningModel
- */
- Tone.Panner3D._aliasProperty('panningModel');
- /**
- * A reference distance for reducing volume as source move further from the listener
- * @type {Number}
- * @memberOf Tone.Panner3D#
- * @name refDistance
- */
- Tone.Panner3D._aliasProperty('refDistance');
- /**
- * Describes how quickly the volume is reduced as source moves away from listener.
- * @type {Number}
- * @memberOf Tone.Panner3D#
- * @name rolloffFactor
- */
- Tone.Panner3D._aliasProperty('rolloffFactor');
- /**
- * The distance model used by, "linear", "inverse", or "exponential".
- * @type {String}
- * @memberOf Tone.Panner3D#
- * @name distanceModel
- */
- Tone.Panner3D._aliasProperty('distanceModel');
- /**
- * The angle, in degrees, inside of which there will be no volume reduction
- * @type {Degrees}
- * @memberOf Tone.Panner3D#
- * @name coneInnerAngle
- */
- Tone.Panner3D._aliasProperty('coneInnerAngle');
- /**
- * The angle, in degrees, outside of which the volume will be reduced
- * to a constant value of coneOuterGain
- * @type {Degrees}
- * @memberOf Tone.Panner3D#
- * @name coneOuterAngle
- */
- Tone.Panner3D._aliasProperty('coneOuterAngle');
- /**
- * The gain outside of the coneOuterAngle
- * @type {Gain}
- * @memberOf Tone.Panner3D#
- * @name coneOuterGain
- */
- Tone.Panner3D._aliasProperty('coneOuterGain');
- /**
- * The maximum distance between source and listener,
- * after which the volume will not be reduced any further.
- * @type {Positive}
- * @memberOf Tone.Panner3D#
- * @name maxDistance
- */
- Tone.Panner3D._aliasProperty('maxDistance');
- /**
- * Clean up.
- * @returns {Tone.Panner3D} this
- */
- Tone.Panner3D.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._panner.disconnect();
- this._panner = null;
- this._orientation = null;
- this._position = null;
- return this;
- };
- return Tone.Panner3D;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.PanVol is a Tone.Panner and Tone.Volume in one.
- *
- * @extends {Tone.AudioNode}
- * @constructor
- * @param {AudioRange} pan the initial pan
- * @param {number} volume The output volume.
- * @example
- * //pan the incoming signal left and drop the volume
- * var panVol = new Tone.PanVol(-0.25, -12);
- */
- Tone.PanVol = function () {
- var options = Tone.defaults(arguments, [
- 'pan',
- 'volume'
- ], Tone.PanVol);
- Tone.AudioNode.call(this);
- /**
- * The panning node
- * @type {Tone.Panner}
- * @private
- */
- this._panner = this.input = new Tone.Panner(options.pan);
- /**
- * The L/R panning control.
- * @type {AudioRange}
- * @signal
- */
- this.pan = this._panner.pan;
- /**
- * The volume node
- * @type {Tone.Volume}
- * @private
- */
- this._volume = this.output = new Tone.Volume(options.volume);
- /**
- * The volume control in decibels.
- * @type {Decibels}
- * @signal
- */
- this.volume = this._volume.volume;
- //connections
- this._panner.connect(this._volume);
- this.mute = options.mute;
- this._readOnly([
- 'pan',
- 'volume'
- ]);
- };
- Tone.extend(Tone.PanVol, Tone.AudioNode);
- /**
- * The defaults
- * @type {Object}
- * @const
- * @static
- */
- Tone.PanVol.defaults = {
- 'pan': 0,
- 'volume': 0,
- 'mute': false
- };
- /**
- * Mute/unmute the volume
- * @memberOf Tone.PanVol#
- * @name mute
- * @type {Boolean}
- */
- Object.defineProperty(Tone.PanVol.prototype, 'mute', {
- get: function () {
- return this._volume.mute;
- },
- set: function (mute) {
- this._volume.mute = mute;
- }
- });
- /**
- * clean up
- * @returns {Tone.PanVol} this
- */
- Tone.PanVol.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._writable([
- 'pan',
- 'volume'
- ]);
- this._panner.dispose();
- this._panner = null;
- this.pan = null;
- this._volume.dispose();
- this._volume = null;
- this.volume = null;
- return this;
- };
- return Tone.PanVol;
- });
- Module(function (Tone) {
- /**
- * @class Tone.Solo lets you isolate a specific audio stream. When
- * an instance is set to `solo=true`, it will mute all other instances.
- * @extends {Tone.AudioNode}
- * @example
- * var soloA = new Tone.Solo()
- * var soloB = new Tone.Solo()
- * soloA.solo = true
- * //no audio will pass through soloB
- */
- Tone.Solo = function () {
- var options = Tone.defaults(arguments, ['solo'], Tone.Solo);
- Tone.AudioNode.call(this);
- /**
- * The input and output node
- * @type {Tone.Gain}
- */
- this.input = this.output = new Tone.Gain();
- /**
- * A bound _soloed method
- * @type {Function}
- * @private
- */
- this._soloBind = this._soloed.bind(this);
- //listen for solo events class-wide.
- this.context.on('solo', this._soloBind);
- //set initially
- this.solo = options.solo;
- };
- Tone.extend(Tone.Solo, Tone.AudioNode);
- /**
- * The defaults
- * @type {Object}
- * @static
- */
- Tone.Solo.defaults = { solo: false };
- /**
- * Isolates this instance and mutes all other instances of Tone.Solo.
- * Only one instance can be soloed at a time. A soloed
- * instance will report `solo=false` when another instance is soloed.
- * @memberOf Tone.Solo#
- * @type {Boolean}
- * @name solo
- */
- Object.defineProperty(Tone.Solo.prototype, 'solo', {
- get: function () {
- return this._isSoloed();
- },
- set: function (solo) {
- if (solo) {
- this._addSolo();
- } else {
- this._removeSolo();
- }
- this.context.emit('solo', this);
- }
- });
- /**
- * If the current instance is muted, i.e. another instance is soloed
- * @memberOf Tone.Solo#
- * @type {Boolean}
- * @name muted
- * @readOnly
- */
- Object.defineProperty(Tone.Solo.prototype, 'muted', {
- get: function () {
- return this.input.gain.value === 0;
- }
- });
- /**
- * Add this to the soloed array
- * @private
- */
- Tone.Solo.prototype._addSolo = function () {
- if (!Tone.isArray(this.context._currentSolo)) {
- this.context._currentSolo = [];
- }
- if (!this._isSoloed()) {
- this.context._currentSolo.push(this);
- }
- };
- /**
- * Remove this from the soloed array
- * @private
- */
- Tone.Solo.prototype._removeSolo = function () {
- if (this._isSoloed()) {
- var index = this.context._currentSolo.indexOf(this);
- this.context._currentSolo.splice(index, 1);
- }
- };
- /**
- * @return {Boolean} Is this on the soloed array
- * @private
- */
- Tone.Solo.prototype._isSoloed = function () {
- if (Tone.isArray(this.context._currentSolo)) {
- return this.context._currentSolo.length !== 0 && this.context._currentSolo.indexOf(this) !== -1;
- } else {
- return false;
- }
- };
- /**
- * @return {Boolean} Returns true if no one is soloed
- * @private
- */
- Tone.Solo.prototype._noSolos = function () {
- return !Tone.isArray(this.context._currentSolo) || this.context._currentSolo.length === 0;
- };
- /**
- * Solo the current instance and unsolo all other instances.
- * @param {Tone.Solo} instance The instance which is being soloed/unsoloed.
- * @private
- */
- Tone.Solo.prototype._soloed = function () {
- if (this._isSoloed()) {
- this.input.gain.value = 1;
- } else if (this._noSolos()) {
- //no one is soloed
- this.input.gain.value = 1;
- } else {
- this.input.gain.value = 0;
- }
- };
- /**
- * Clean up
- * @return {Tone.Solo} this
- */
- Tone.Solo.prototype.dispose = function () {
- this.context.off('solo', this._soloBind);
- this._removeSolo();
- this._soloBind = null;
- Tone.AudioNode.prototype.dispose.call(this);
- return this;
- };
- return Tone.Solo;
- });
- Module(function (Tone) {
- /**
- * @class Get the current waveform data of the connected audio source.
- * @extends {Tone.AudioNode}
- * @param {Number=} size The size of the FFT. Value must be a power of
- * two in the range 32 to 32768.
- */
- Tone.Waveform = function () {
- var options = Tone.defaults(arguments, ['size'], Tone.Waveform);
- options.type = Tone.Analyser.Type.Waveform;
- Tone.AudioNode.call(this);
- /**
- * The analyser node.
- * @private
- * @type {Tone.Analyser}
- */
- this._analyser = this.input = this.output = new Tone.Analyser(options);
- };
- Tone.extend(Tone.Waveform, Tone.AudioNode);
- /**
- * The default values.
- * @type {Object}
- * @const
- */
- Tone.Waveform.defaults = { 'size': 1024 };
- /**
- * Gets the waveform of the audio source. Returns the waveform data
- * of length [size](#size) as a Float32Array with values between -1 and 1.
- * @returns {TypedArray}
- */
- Tone.Waveform.prototype.getValue = function () {
- return this._analyser.getValue();
- };
- /**
- * The size of analysis. This must be a power of two in the range 32 to 32768.
- * @memberOf Tone.Waveform#
- * @type {Number}
- * @name size
- */
- Object.defineProperty(Tone.Waveform.prototype, 'size', {
- get: function () {
- return this._analyser.size;
- },
- set: function (size) {
- this._analyser.size = size;
- }
- });
- /**
- * Clean up.
- * @return {Tone.Waveform} this
- */
- Tone.Waveform.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._analyser.dispose();
- this._analyser = null;
- };
- return Tone.Waveform;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.CtrlInterpolate will interpolate between given values based
- * on the "index" property. Passing in an array or object literal
- * will interpolate each of the parameters. Note (i.e. "C3")
- * and Time (i.e. "4n + 2") can be interpolated. All other values are
- * assumed to be numbers.
- * @example
- * var interp = new Tone.CtrlInterpolate([0, 2, 9, 4]);
- * interp.index = 0.75;
- * interp.value; //returns 1.5
- *
- * @example
- * var interp = new Tone.CtrlInterpolate([
- * [2, 4, 5],
- * [9, 3, 2],
- * ]);
- * @param {Array} values The array of values to interpolate over
- * @param {Positive} index The initial interpolation index.
- * @extends {Tone}
- */
- Tone.CtrlInterpolate = function () {
- var options = Tone.defaults(arguments, [
- 'values',
- 'index'
- ], Tone.CtrlInterpolate);
- Tone.call(this);
- /**
- * The values to interpolate between
- * @type {Array}
- */
- this.values = options.values;
- /**
- * The interpolated index between values. For example: a value of 1.5
- * would interpolate equally between the value at index 1
- * and the value at index 2.
- * @example
- * interp.index = 0;
- * interp.value; //returns the value at 0
- * interp.index = 0.5;
- * interp.value; //returns the value between indices 0 and 1.
- * @type {Positive}
- */
- this.index = options.index;
- };
- Tone.extend(Tone.CtrlInterpolate);
- /**
- * The defaults
- * @const
- * @type {Object}
- */
- Tone.CtrlInterpolate.defaults = {
- 'index': 0,
- 'values': []
- };
- /**
- * The current interpolated value based on the index
- * @readOnly
- * @memberOf Tone.CtrlInterpolate#
- * @type {*}
- * @name value
- */
- Object.defineProperty(Tone.CtrlInterpolate.prototype, 'value', {
- get: function () {
- var index = this.index;
- index = Math.min(index, this.values.length - 1);
- var lowerPosition = Math.floor(index);
- var lower = this.values[lowerPosition];
- var upper = this.values[Math.ceil(index)];
- return this._interpolate(index - lowerPosition, lower, upper);
- }
- });
- /**
- * Internal interpolation routine
- * @param {NormalRange} index The index between the lower and upper
- * @param {*} lower
- * @param {*} upper
- * @return {*} The interpolated value
- * @private
- */
- Tone.CtrlInterpolate.prototype._interpolate = function (index, lower, upper) {
- if (Tone.isArray(lower)) {
- var retArray = [];
- for (var i = 0; i < lower.length; i++) {
- retArray[i] = this._interpolate(index, lower[i], upper[i]);
- }
- return retArray;
- } else if (Tone.isObject(lower)) {
- var retObj = {};
- for (var attr in lower) {
- retObj[attr] = this._interpolate(index, lower[attr], upper[attr]);
- }
- return retObj;
- } else {
- lower = this._toNumber(lower);
- upper = this._toNumber(upper);
- return (1 - index) * lower + index * upper;
- }
- };
- /**
- * Convert from the given type into a number
- * @param {Number|String} value
- * @return {Number}
- * @private
- */
- Tone.CtrlInterpolate.prototype._toNumber = function (val) {
- if (Tone.isNumber(val)) {
- return val;
- } else {
- //otherwise assume that it's Time...
- return this.toSeconds(val);
- }
- };
- /**
- * Clean up
- * @return {Tone.CtrlInterpolate} this
- */
- Tone.CtrlInterpolate.prototype.dispose = function () {
- this.values = null;
- };
- return Tone.CtrlInterpolate;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.CtrlMarkov represents a Markov Chain where each call
- * to Tone.CtrlMarkov.next will move to the next state. If the next
- * state choice is an array, the next state is chosen randomly with
- * even probability for all of the choices. For a weighted probability
- * of the next choices, pass in an object with "state" and "probability" attributes.
- * The probabilities will be normalized and then chosen. If no next options
- * are given for the current state, the state will stay there.
- * @extends {Tone}
- * @example
- * var chain = new Tone.CtrlMarkov({
- * "beginning" : ["end", "middle"],
- * "middle" : "end"
- * });
- * chain.value = "beginning";
- * chain.next(); //returns "end" or "middle" with 50% probability
- *
- * @example
- * var chain = new Tone.CtrlMarkov({
- * "beginning" : [{"value" : "end", "probability" : 0.8},
- * {"value" : "middle", "probability" : 0.2}],
- * "middle" : "end"
- * });
- * chain.value = "beginning";
- * chain.next(); //returns "end" with 80% probability or "middle" with 20%.
- * @param {Object} values An object with the state names as the keys
- * and the next state(s) as the values.
- */
- Tone.CtrlMarkov = function (values, initial) {
- Tone.call(this);
- /**
- * The Markov values with states as the keys
- * and next state(s) as the values.
- * @type {Object}
- */
- this.values = Tone.defaultArg(values, {});
- /**
- * The current state of the Markov values. The next
- * state will be evaluated and returned when Tone.CtrlMarkov.next
- * is invoked.
- * @type {String}
- */
- this.value = Tone.defaultArg(initial, Object.keys(this.values)[0]);
- };
- Tone.extend(Tone.CtrlMarkov);
- /**
- * Returns the next state of the Markov values.
- * @return {String}
- */
- Tone.CtrlMarkov.prototype.next = function () {
- if (this.values.hasOwnProperty(this.value)) {
- var next = this.values[this.value];
- if (Tone.isArray(next)) {
- var distribution = this._getProbDistribution(next);
- var rand = Math.random();
- var total = 0;
- for (var i = 0; i < distribution.length; i++) {
- var dist = distribution[i];
- if (rand > total && rand < total + dist) {
- var chosen = next[i];
- if (Tone.isObject(chosen)) {
- this.value = chosen.value;
- } else {
- this.value = chosen;
- }
- }
- total += dist;
- }
- } else {
- this.value = next;
- }
- }
- return this.value;
- };
- /**
- * Choose randomly from an array weighted options in the form
- * {"state" : string, "probability" : number} or an array of values
- * @param {Array} options
- * @return {Array} The randomly selected choice
- * @private
- */
- Tone.CtrlMarkov.prototype._getProbDistribution = function (options) {
- var distribution = [];
- var total = 0;
- var needsNormalizing = false;
- for (var i = 0; i < options.length; i++) {
- var option = options[i];
- if (Tone.isObject(option)) {
- needsNormalizing = true;
- distribution[i] = option.probability;
- } else {
- distribution[i] = 1 / options.length;
- }
- total += distribution[i];
- }
- if (needsNormalizing) {
- //normalize the values
- for (var j = 0; j < distribution.length; j++) {
- distribution[j] = distribution[j] / total;
- }
- }
- return distribution;
- };
- /**
- * Clean up
- * @return {Tone.CtrlMarkov} this
- */
- Tone.CtrlMarkov.prototype.dispose = function () {
- this.values = null;
- };
- return Tone.CtrlMarkov;
- });
- Module(function (Tone) {
-
- /**
- * @class Generate patterns from an array of values.
- * Has a number of arpeggiation and randomized
- * selection patterns.
- *
- * Mid *= 2*(1-width)
- * Side *= 2*width
- *
- *
- * @extends {Tone.MidSideEffect}
- * @constructor
- * @param {NormalRange|Object} [width] The stereo width. A width of 0 is mono and 1 is stereo. 0.5 is no change.
- */
- Tone.StereoWidener = function () {
- var options = Tone.defaults(arguments, ['width'], Tone.StereoWidener);
- Tone.MidSideEffect.call(this, options);
- /**
- * The width control. 0 = 100% mid. 1 = 100% side. 0.5 = no change.
- * @type {NormalRange}
- * @signal
- */
- this.width = new Tone.Signal(options.width, Tone.Type.NormalRange);
- /**
- * Mid multiplier
- * @type {Tone.Expr}
- * @private
- */
- this._midMult = new Tone.Expr('$0 * ($1 * (1 - $2))');
- /**
- * Side multiplier
- * @type {Tone.Expr}
- * @private
- */
- this._sideMult = new Tone.Expr('$0 * ($1 * $2)');
- /**
- * constant output of 2
- * @type {Tone}
- * @private
- */
- this._two = new Tone.Signal(2);
- //the mid chain
- this._two.connect(this._midMult, 0, 1);
- this.width.connect(this._midMult, 0, 2);
- //the side chain
- this._two.connect(this._sideMult, 0, 1);
- this.width.connect(this._sideMult, 0, 2);
- //connect it to the effect send/return
- this.midSend.chain(this._midMult, this.midReturn);
- this.sideSend.chain(this._sideMult, this.sideReturn);
- this._readOnly(['width']);
- };
- Tone.extend(Tone.StereoWidener, Tone.MidSideEffect);
- /**
- * the default values
- * @static
- * @type {Object}
- */
- Tone.StereoWidener.defaults = { 'width': 0.5 };
- /**
- * Clean up.
- * @returns {Tone.StereoWidener} this
- */
- Tone.StereoWidener.prototype.dispose = function () {
- Tone.MidSideEffect.prototype.dispose.call(this);
- this._writable(['width']);
- this.width.dispose();
- this.width = null;
- this._midMult.dispose();
- this._midMult = null;
- this._sideMult.dispose();
- this._sideMult = null;
- this._two.dispose();
- this._two = null;
- return this;
- };
- return Tone.StereoWidener;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Tremolo modulates the amplitude of an incoming signal using a Tone.LFO.
- * The type, frequency, and depth of the LFO is controllable.
- *
- * @extends {Tone.StereoEffect}
- * @constructor
- * @param {Frequency} [frequency] The rate of the effect.
- * @param {NormalRange} [depth] The depth of the effect.
- * @example
- * //create a tremolo and start it's LFO
- * var tremolo = new Tone.Tremolo(9, 0.75).toMaster().start();
- * //route an oscillator through the tremolo and start it
- * var oscillator = new Tone.Oscillator().connect(tremolo).start();
- */
- Tone.Tremolo = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'depth'
- ], Tone.Tremolo);
- Tone.StereoEffect.call(this, options);
- /**
- * The tremelo LFO in the left channel
- * @type {Tone.LFO}
- * @private
- */
- this._lfoL = new Tone.LFO({
- 'phase': options.spread,
- 'min': 1,
- 'max': 0
- });
- /**
- * The tremelo LFO in the left channel
- * @type {Tone.LFO}
- * @private
- */
- this._lfoR = new Tone.LFO({
- 'phase': options.spread,
- 'min': 1,
- 'max': 0
- });
- /**
- * Where the gain is multiplied
- * @type {Tone.Gain}
- * @private
- */
- this._amplitudeL = new Tone.Gain();
- /**
- * Where the gain is multiplied
- * @type {Tone.Gain}
- * @private
- */
- this._amplitudeR = new Tone.Gain();
- /**
- * The frequency of the tremolo.
- * @type {Frequency}
- * @signal
- */
- this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
- /**
- * The depth of the effect. A depth of 0, has no effect
- * on the amplitude, and a depth of 1 makes the amplitude
- * modulate fully between 0 and 1.
- * @type {NormalRange}
- * @signal
- */
- this.depth = new Tone.Signal(options.depth, Tone.Type.NormalRange);
- this._readOnly([
- 'frequency',
- 'depth'
- ]);
- this.effectSendL.chain(this._amplitudeL, this.effectReturnL);
- this.effectSendR.chain(this._amplitudeR, this.effectReturnR);
- this._lfoL.connect(this._amplitudeL.gain);
- this._lfoR.connect(this._amplitudeR.gain);
- this.frequency.fan(this._lfoL.frequency, this._lfoR.frequency);
- this.depth.fan(this._lfoR.amplitude, this._lfoL.amplitude);
- this.type = options.type;
- this.spread = options.spread;
- };
- Tone.extend(Tone.Tremolo, Tone.StereoEffect);
- /**
- * @static
- * @const
- * @type {Object}
- */
- Tone.Tremolo.defaults = {
- 'frequency': 10,
- 'type': 'sine',
- 'depth': 0.5,
- 'spread': 180
- };
- /**
- * Start the tremolo.
- * @param {Time} [time=now] When the tremolo begins.
- * @returns {Tone.Tremolo} this
- */
- Tone.Tremolo.prototype.start = function (time) {
- this._lfoL.start(time);
- this._lfoR.start(time);
- return this;
- };
- /**
- * Stop the tremolo.
- * @param {Time} [time=now] When the tremolo stops.
- * @returns {Tone.Tremolo} this
- */
- Tone.Tremolo.prototype.stop = function (time) {
- this._lfoL.stop(time);
- this._lfoR.stop(time);
- return this;
- };
- /**
- * Sync the effect to the transport.
- * @param {Time} [delay=0] Delay time before starting the effect after the
- * Transport has started.
- * @returns {Tone.AutoFilter} this
- */
- Tone.Tremolo.prototype.sync = function (delay) {
- this._lfoL.sync(delay);
- this._lfoR.sync(delay);
- return this;
- };
- /**
- * Unsync the filter from the transport
- * @returns {Tone.Tremolo} this
- */
- Tone.Tremolo.prototype.unsync = function () {
- this._lfoL.unsync();
- this._lfoR.unsync();
- return this;
- };
- /**
- * The Tremolo's oscillator type.
- * @memberOf Tone.Tremolo#
- * @type {string}
- * @name type
- */
- Object.defineProperty(Tone.Tremolo.prototype, 'type', {
- get: function () {
- return this._lfoL.type;
- },
- set: function (type) {
- this._lfoL.type = type;
- this._lfoR.type = type;
- }
- });
- /**
- * Amount of stereo spread. When set to 0, both LFO's will be panned centrally.
- * When set to 180, LFO's will be panned hard left and right respectively.
- * @memberOf Tone.Tremolo#
- * @type {Degrees}
- * @name spread
- */
- Object.defineProperty(Tone.Tremolo.prototype, 'spread', {
- get: function () {
- return this._lfoR.phase - this._lfoL.phase; //180
- },
- set: function (spread) {
- this._lfoL.phase = 90 - spread / 2;
- this._lfoR.phase = spread / 2 + 90;
- }
- });
- /**
- * clean up
- * @returns {Tone.Tremolo} this
- */
- Tone.Tremolo.prototype.dispose = function () {
- Tone.StereoEffect.prototype.dispose.call(this);
- this._writable([
- 'frequency',
- 'depth'
- ]);
- this._lfoL.dispose();
- this._lfoL = null;
- this._lfoR.dispose();
- this._lfoR = null;
- this._amplitudeL.dispose();
- this._amplitudeL = null;
- this._amplitudeR.dispose();
- this._amplitudeR = null;
- this.frequency = null;
- this.depth = null;
- return this;
- };
- return Tone.Tremolo;
- });
- Module(function (Tone) {
-
- /**
- * @class A Vibrato effect composed of a Tone.Delay and a Tone.LFO. The LFO
- * modulates the delayTime of the delay, causing the pitch to rise
- * and fall.
- * @extends {Tone.Effect}
- * @param {Frequency} frequency The frequency of the vibrato.
- * @param {NormalRange} depth The amount the pitch is modulated.
- */
- Tone.Vibrato = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'depth'
- ], Tone.Vibrato);
- Tone.Effect.call(this, options);
- /**
- * The delay node used for the vibrato effect
- * @type {Tone.Delay}
- * @private
- */
- this._delayNode = new Tone.Delay(0, options.maxDelay);
- /**
- * The LFO used to control the vibrato
- * @type {Tone.LFO}
- * @private
- */
- this._lfo = new Tone.LFO({
- 'type': options.type,
- 'min': 0,
- 'max': options.maxDelay,
- 'frequency': options.frequency,
- 'phase': -90 //offse the phase so the resting position is in the center
- }).start().connect(this._delayNode.delayTime);
- /**
- * The frequency of the vibrato
- * @type {Frequency}
- * @signal
- */
- this.frequency = this._lfo.frequency;
- /**
- * The depth of the vibrato.
- * @type {NormalRange}
- * @signal
- */
- this.depth = this._lfo.amplitude;
- this.depth.value = options.depth;
- this._readOnly([
- 'frequency',
- 'depth'
- ]);
- this.effectSend.chain(this._delayNode, this.effectReturn);
- };
- Tone.extend(Tone.Vibrato, Tone.Effect);
- /**
- * The defaults
- * @type {Object}
- * @const
- */
- Tone.Vibrato.defaults = {
- 'maxDelay': 0.005,
- 'frequency': 5,
- 'depth': 0.1,
- 'type': 'sine'
- };
- /**
- * Type of oscillator attached to the Vibrato.
- * @memberOf Tone.Vibrato#
- * @type {string}
- * @name type
- */
- Object.defineProperty(Tone.Vibrato.prototype, 'type', {
- get: function () {
- return this._lfo.type;
- },
- set: function (type) {
- this._lfo.type = type;
- }
- });
- /**
- * Clean up.
- * @returns {Tone.Vibrato} this
- */
- Tone.Vibrato.prototype.dispose = function () {
- Tone.Effect.prototype.dispose.call(this);
- this._delayNode.dispose();
- this._delayNode = null;
- this._lfo.dispose();
- this._lfo = null;
- this._writable([
- 'frequency',
- 'depth'
- ]);
- this.frequency = null;
- this.depth = null;
- };
- return Tone.Vibrato;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Event abstracts away Tone.Transport.schedule and provides a schedulable
- * callback for a single or repeatable events along the timeline.
- *
- * @extends {Tone}
- * @param {function} callback The callback to invoke at the time.
- * @param {*} value The value or values which should be passed to
- * the callback function on invocation.
- * @example
- * var chord = new Tone.Event(function(time, chord){
- * //the chord as well as the exact time of the event
- * //are passed in as arguments to the callback function
- * }, ["D4", "E4", "F4"]);
- * //start the chord at the beginning of the transport timeline
- * chord.start();
- * //loop it every measure for 8 measures
- * chord.loop = 8;
- * chord.loopEnd = "1m";
- */
- Tone.Event = function () {
- var options = Tone.defaults(arguments, [
- 'callback',
- 'value'
- ], Tone.Event);
- Tone.call(this);
- /**
- * Loop value
- * @type {Boolean|Positive}
- * @private
- */
- this._loop = options.loop;
- /**
- * The callback to invoke.
- * @type {Function}
- */
- this.callback = options.callback;
- /**
- * The value which is passed to the
- * callback function.
- * @type {*}
- * @private
- */
- this.value = options.value;
- /**
- * When the note is scheduled to start.
- * @type {Number}
- * @private
- */
- this._loopStart = this.toTicks(options.loopStart);
- /**
- * When the note is scheduled to start.
- * @type {Number}
- * @private
- */
- this._loopEnd = this.toTicks(options.loopEnd);
- /**
- * Tracks the scheduled events
- * @type {Tone.TimelineState}
- * @private
- */
- this._state = new Tone.TimelineState(Tone.State.Stopped);
- /**
- * The playback speed of the note. A speed of 1
- * is no change.
- * @private
- * @type {Positive}
- */
- this._playbackRate = 1;
- /**
- * A delay time from when the event is scheduled to start
- * @type {Ticks}
- * @private
- */
- this._startOffset = 0;
- /**
- * private holder of probability value
- * @type {NormalRange}
- * @private
- */
- this._probability = options.probability;
- /**
- * the amount of variation from the
- * given time.
- * @type {Boolean|Time}
- * @private
- */
- this._humanize = options.humanize;
- /**
- * If mute is true, the callback won't be
- * invoked.
- * @type {Boolean}
- */
- this.mute = options.mute;
- //set the initial values
- this.playbackRate = options.playbackRate;
- };
- Tone.extend(Tone.Event);
- /**
- * The default values
- * @type {Object}
- * @const
- */
- Tone.Event.defaults = {
- 'callback': Tone.noOp,
- 'loop': false,
- 'loopEnd': '1m',
- 'loopStart': 0,
- 'playbackRate': 1,
- 'value': null,
- 'probability': 1,
- 'mute': false,
- 'humanize': false
- };
- /**
- * Reschedule all of the events along the timeline
- * with the updated values.
- * @param {Time} after Only reschedules events after the given time.
- * @return {Tone.Event} this
- * @private
- */
- Tone.Event.prototype._rescheduleEvents = function (after) {
- //if no argument is given, schedules all of the events
- after = Tone.defaultArg(after, -1);
- this._state.forEachFrom(after, function (event) {
- var duration;
- if (event.state === Tone.State.Started) {
- if (!Tone.isUndef(event.id)) {
- Tone.Transport.clear(event.id);
- }
- var startTick = event.time + Math.round(this.startOffset / this._playbackRate);
- if (this._loop) {
- duration = Infinity;
- if (Tone.isNumber(this._loop)) {
- duration = this._loop * this._getLoopDuration();
- }
- var nextEvent = this._state.getAfter(startTick);
- if (nextEvent !== null) {
- duration = Math.min(duration, nextEvent.time - startTick);
- }
- if (duration !== Infinity) {
- //schedule a stop since it's finite duration
- this._state.setStateAtTime(Tone.State.Stopped, startTick + duration + 1);
- duration = Tone.Time(duration, 'i');
- }
- var interval = Tone.Time(this._getLoopDuration(), 'i');
- event.id = Tone.Transport.scheduleRepeat(this._tick.bind(this), interval, Tone.TransportTime(startTick, 'i'), duration);
- } else {
- event.id = Tone.Transport.schedule(this._tick.bind(this), startTick + 'i');
- }
- }
- }.bind(this));
- return this;
- };
- /**
- * Returns the playback state of the note, either "started" or "stopped".
- * @type {String}
- * @readOnly
- * @memberOf Tone.Event#
- * @name state
- */
- Object.defineProperty(Tone.Event.prototype, 'state', {
- get: function () {
- return this._state.getValueAtTime(Tone.Transport.ticks);
- }
- });
- /**
- * The start from the scheduled start time
- * @type {Ticks}
- * @memberOf Tone.Event#
- * @name startOffset
- * @private
- */
- Object.defineProperty(Tone.Event.prototype, 'startOffset', {
- get: function () {
- return this._startOffset;
- },
- set: function (offset) {
- this._startOffset = offset;
- }
- });
- /**
- * The probability of the notes being triggered.
- * @memberOf Tone.Event#
- * @type {NormalRange}
- * @name probability
- */
- Object.defineProperty(Tone.Event.prototype, 'probability', {
- get: function () {
- return this._probability;
- },
- set: function (prob) {
- this._probability = prob;
- }
- });
- /**
- * If set to true, will apply small random variation
- * to the callback time. If the value is given as a time, it will randomize
- * by that amount.
- * @example
- * event.humanize = true;
- * @type {Boolean|Time}
- * @name humanize
- */
- Object.defineProperty(Tone.Event.prototype, 'humanize', {
- get: function () {
- return this._humanize;
- },
- set: function (variation) {
- this._humanize = variation;
- }
- });
- /**
- * Start the note at the given time.
- * @param {TimelinePosition} time When the note should start.
- * @return {Tone.Event} this
- */
- Tone.Event.prototype.start = function (time) {
- time = this.toTicks(time);
- if (this._state.getValueAtTime(time) === Tone.State.Stopped) {
- this._state.add({
- 'state': Tone.State.Started,
- 'time': time,
- 'id': undefined
- });
- this._rescheduleEvents(time);
- }
- return this;
- };
- /**
- * Stop the Event at the given time.
- * @param {TimelinePosition} time When the note should stop.
- * @return {Tone.Event} this
- */
- Tone.Event.prototype.stop = function (time) {
- this.cancel(time);
- time = this.toTicks(time);
- if (this._state.getValueAtTime(time) === Tone.State.Started) {
- this._state.setStateAtTime(Tone.State.Stopped, time);
- var previousEvent = this._state.getBefore(time);
- var reschedulTime = time;
- if (previousEvent !== null) {
- reschedulTime = previousEvent.time;
- }
- this._rescheduleEvents(reschedulTime);
- }
- return this;
- };
- /**
- * Cancel all scheduled events greater than or equal to the given time
- * @param {TimelinePosition} [time=0] The time after which events will be cancel.
- * @return {Tone.Event} this
- */
- Tone.Event.prototype.cancel = function (time) {
- time = Tone.defaultArg(time, -Infinity);
- time = this.toTicks(time);
- this._state.forEachFrom(time, function (event) {
- Tone.Transport.clear(event.id);
- });
- this._state.cancel(time);
- return this;
- };
- /**
- * The callback function invoker. Also
- * checks if the Event is done playing
- * @param {Number} time The time of the event in seconds
- * @private
- */
- Tone.Event.prototype._tick = function (time) {
- if (!this.mute && this._state.getValueAtTime(Tone.Transport.ticks) === Tone.State.Started) {
- if (this.probability < 1 && Math.random() > this.probability) {
- return;
- }
- if (this.humanize) {
- var variation = 0.02;
- if (!Tone.isBoolean(this.humanize)) {
- variation = this.toSeconds(this.humanize);
- }
- time += (Math.random() * 2 - 1) * variation;
- }
- this.callback(time, this.value);
- }
- };
- /**
- * Get the duration of the loop.
- * @return {Ticks}
- * @private
- */
- Tone.Event.prototype._getLoopDuration = function () {
- return Math.round((this._loopEnd - this._loopStart) / this._playbackRate);
- };
- /**
- * If the note should loop or not
- * between Tone.Event.loopStart and
- * Tone.Event.loopEnd. An integer
- * value corresponds to the number of
- * loops the Event does after it starts.
- * @memberOf Tone.Event#
- * @type {Boolean|Positive}
- * @name loop
- */
- Object.defineProperty(Tone.Event.prototype, 'loop', {
- get: function () {
- return this._loop;
- },
- set: function (loop) {
- this._loop = loop;
- this._rescheduleEvents();
- }
- });
- /**
- * The playback rate of the note. Defaults to 1.
- * @memberOf Tone.Event#
- * @type {Positive}
- * @name playbackRate
- * @example
- * note.loop = true;
- * //repeat the note twice as fast
- * note.playbackRate = 2;
- */
- Object.defineProperty(Tone.Event.prototype, 'playbackRate', {
- get: function () {
- return this._playbackRate;
- },
- set: function (rate) {
- this._playbackRate = rate;
- this._rescheduleEvents();
- }
- });
- /**
- * The loopEnd point is the time the event will loop
- * if Tone.Event.loop is true.
- * @memberOf Tone.Event#
- * @type {TransportTime}
- * @name loopEnd
- */
- Object.defineProperty(Tone.Event.prototype, 'loopEnd', {
- get: function () {
- return Tone.TransportTime(this._loopEnd, 'i').toNotation();
- },
- set: function (loopEnd) {
- this._loopEnd = this.toTicks(loopEnd);
- if (this._loop) {
- this._rescheduleEvents();
- }
- }
- });
- /**
- * The time when the loop should start.
- * @memberOf Tone.Event#
- * @type {TransportTime}
- * @name loopStart
- */
- Object.defineProperty(Tone.Event.prototype, 'loopStart', {
- get: function () {
- return Tone.TransportTime(this._loopStart, 'i').toNotation();
- },
- set: function (loopStart) {
- this._loopStart = this.toTicks(loopStart);
- if (this._loop) {
- this._rescheduleEvents();
- }
- }
- });
- /**
- * The current progress of the loop interval.
- * Returns 0 if the event is not started yet or
- * it is not set to loop.
- * @memberOf Tone.Event#
- * @type {NormalRange}
- * @name progress
- * @readOnly
- */
- Object.defineProperty(Tone.Event.prototype, 'progress', {
- get: function () {
- if (this._loop) {
- var ticks = Tone.Transport.ticks;
- var lastEvent = this._state.get(ticks);
- if (lastEvent !== null && lastEvent.state === Tone.State.Started) {
- var loopDuration = this._getLoopDuration();
- var progress = (ticks - lastEvent.time) % loopDuration;
- return progress / loopDuration;
- } else {
- return 0;
- }
- } else {
- return 0;
- }
- }
- });
- /**
- * Clean up
- * @return {Tone.Event} this
- */
- Tone.Event.prototype.dispose = function () {
- this.cancel();
- this._state.dispose();
- this._state = null;
- this.callback = null;
- this.value = null;
- };
- return Tone.Event;
- });
- Module(function (Tone) {
- /**
- * @class Tone.Loop creates a looped callback at the
- * specified interval. The callback can be
- * started, stopped and scheduled along
- * the Transport's timeline.
- * @example
- * var loop = new Tone.Loop(function(time){
- * //triggered every eighth note.
- * console.log(time);
- * }, "8n").start(0);
- * Tone.Transport.start();
- * @extends {Tone}
- * @param {Function} callback The callback to invoke with the event.
- * @param {Time} interval The time between successive callback calls.
- */
- Tone.Loop = function () {
- var options = Tone.defaults(arguments, [
- 'callback',
- 'interval'
- ], Tone.Loop);
- Tone.call(this);
- /**
- * The event which produces the callbacks
- */
- this._event = new Tone.Event({
- 'callback': this._tick.bind(this),
- 'loop': true,
- 'loopEnd': options.interval,
- 'playbackRate': options.playbackRate,
- 'probability': options.probability
- });
- /**
- * The callback to invoke with the next event in the pattern
- * @type {Function}
- */
- this.callback = options.callback;
- //set the iterations
- this.iterations = options.iterations;
- };
- Tone.extend(Tone.Loop);
- /**
- * The defaults
- * @const
- * @type {Object}
- */
- Tone.Loop.defaults = {
- 'interval': '4n',
- 'callback': Tone.noOp,
- 'playbackRate': 1,
- 'iterations': Infinity,
- 'probability': true,
- 'mute': false
- };
- /**
- * Start the loop at the specified time along the Transport's
- * timeline.
- * @param {TimelinePosition=} time When to start the Loop.
- * @return {Tone.Loop} this
- */
- Tone.Loop.prototype.start = function (time) {
- this._event.start(time);
- return this;
- };
- /**
- * Stop the loop at the given time.
- * @param {TimelinePosition=} time When to stop the Arpeggio
- * @return {Tone.Loop} this
- */
- Tone.Loop.prototype.stop = function (time) {
- this._event.stop(time);
- return this;
- };
- /**
- * Cancel all scheduled events greater than or equal to the given time
- * @param {TimelinePosition} [time=0] The time after which events will be cancel.
- * @return {Tone.Loop} this
- */
- Tone.Loop.prototype.cancel = function (time) {
- this._event.cancel(time);
- return this;
- };
- /**
- * Internal function called when the notes should be called
- * @param {Number} time The time the event occurs
- * @private
- */
- Tone.Loop.prototype._tick = function (time) {
- this.callback(time);
- };
- /**
- * The state of the Loop, either started or stopped.
- * @memberOf Tone.Loop#
- * @type {String}
- * @name state
- * @readOnly
- */
- Object.defineProperty(Tone.Loop.prototype, 'state', {
- get: function () {
- return this._event.state;
- }
- });
- /**
- * The progress of the loop as a value between 0-1. 0, when
- * the loop is stopped or done iterating.
- * @memberOf Tone.Loop#
- * @type {NormalRange}
- * @name progress
- * @readOnly
- */
- Object.defineProperty(Tone.Loop.prototype, 'progress', {
- get: function () {
- return this._event.progress;
- }
- });
- /**
- * The time between successive callbacks.
- * @example
- * loop.interval = "8n"; //loop every 8n
- * @memberOf Tone.Loop#
- * @type {Time}
- * @name interval
- */
- Object.defineProperty(Tone.Loop.prototype, 'interval', {
- get: function () {
- return this._event.loopEnd;
- },
- set: function (interval) {
- this._event.loopEnd = interval;
- }
- });
- /**
- * The playback rate of the loop. The normal playback rate is 1 (no change).
- * A `playbackRate` of 2 would be twice as fast.
- * @memberOf Tone.Loop#
- * @type {Time}
- * @name playbackRate
- */
- Object.defineProperty(Tone.Loop.prototype, 'playbackRate', {
- get: function () {
- return this._event.playbackRate;
- },
- set: function (rate) {
- this._event.playbackRate = rate;
- }
- });
- /**
- * Random variation +/-0.01s to the scheduled time.
- * Or give it a time value which it will randomize by.
- * @type {Boolean|Time}
- * @memberOf Tone.Loop#
- * @name humanize
- */
- Object.defineProperty(Tone.Loop.prototype, 'humanize', {
- get: function () {
- return this._event.humanize;
- },
- set: function (variation) {
- this._event.humanize = variation;
- }
- });
- /**
- * The probably of the callback being invoked.
- * @memberOf Tone.Loop#
- * @type {NormalRange}
- * @name probability
- */
- Object.defineProperty(Tone.Loop.prototype, 'probability', {
- get: function () {
- return this._event.probability;
- },
- set: function (prob) {
- this._event.probability = prob;
- }
- });
- /**
- * Muting the Loop means that no callbacks are invoked.
- * @memberOf Tone.Loop#
- * @type {Boolean}
- * @name mute
- */
- Object.defineProperty(Tone.Loop.prototype, 'mute', {
- get: function () {
- return this._event.mute;
- },
- set: function (mute) {
- this._event.mute = mute;
- }
- });
- /**
- * The number of iterations of the loop. The default
- * value is Infinity (loop forever).
- * @memberOf Tone.Loop#
- * @type {Positive}
- * @name iterations
- */
- Object.defineProperty(Tone.Loop.prototype, 'iterations', {
- get: function () {
- if (this._event.loop === true) {
- return Infinity;
- } else {
- return this._event.loop;
- }
- },
- set: function (iters) {
- if (iters === Infinity) {
- this._event.loop = true;
- } else {
- this._event.loop = iters;
- }
- }
- });
- /**
- * Clean up
- * @return {Tone.Loop} this
- */
- Tone.Loop.prototype.dispose = function () {
- this._event.dispose();
- this._event = null;
- this.callback = null;
- };
- return Tone.Loop;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Part is a collection Tone.Events which can be
- * started/stopped and looped as a single unit.
- *
- * @extends {Tone.Event}
- * @param {Function} callback The callback to invoke on each event
- * @param {Array} events the array of events
- * @example
- * var part = new Tone.Part(function(time, note){
- * //the notes given as the second element in the array
- * //will be passed in as the second argument
- * synth.triggerAttackRelease(note, "8n", time);
- * }, [[0, "C2"], ["0:2", "C3"], ["0:3:2", "G2"]]);
- * @example
- * //use an array of objects as long as the object has a "time" attribute
- * var part = new Tone.Part(function(time, value){
- * //the value is an object which contains both the note and the velocity
- * synth.triggerAttackRelease(value.note, "8n", time, value.velocity);
- * }, [{"time" : 0, "note" : "C3", "velocity": 0.9},
- * {"time" : "0:2", "note" : "C4", "velocity": 0.5}
- * ]).start(0);
- */
- Tone.Part = function () {
- var options = Tone.defaults(arguments, [
- 'callback',
- 'events'
- ], Tone.Part);
- Tone.Event.call(this, options);
- /**
- * An array of Objects.
- * @type {Array}
- * @private
- */
- this._events = [];
- //add the events
- for (var i = 0; i < options.events.length; i++) {
- if (Array.isArray(options.events[i])) {
- this.add(options.events[i][0], options.events[i][1]);
- } else {
- this.add(options.events[i]);
- }
- }
- };
- Tone.extend(Tone.Part, Tone.Event);
- /**
- * The default values
- * @type {Object}
- * @const
- */
- Tone.Part.defaults = {
- 'callback': Tone.noOp,
- 'loop': false,
- 'loopEnd': '1m',
- 'loopStart': 0,
- 'playbackRate': 1,
- 'probability': 1,
- 'humanize': false,
- 'mute': false,
- 'events': []
- };
- /**
- * Start the part at the given time.
- * @param {TransportTime} time When to start the part.
- * @param {Time=} offset The offset from the start of the part
- * to begin playing at.
- * @return {Tone.Part} this
- */
- Tone.Part.prototype.start = function (time, offset) {
- var ticks = this.toTicks(time);
- if (this._state.getValueAtTime(ticks) !== Tone.State.Started) {
- if (this._loop) {
- offset = Tone.defaultArg(offset, this._loopStart);
- } else {
- offset = Tone.defaultArg(offset, 0);
- }
- offset = this.toTicks(offset);
- this._state.add({
- 'state': Tone.State.Started,
- 'time': ticks,
- 'offset': offset
- });
- this._forEach(function (event) {
- this._startNote(event, ticks, offset);
- });
- }
- return this;
- };
- /**
- * Start the event in the given event at the correct time given
- * the ticks and offset and looping.
- * @param {Tone.Event} event
- * @param {Ticks} ticks
- * @param {Ticks} offset
- * @private
- */
- Tone.Part.prototype._startNote = function (event, ticks, offset) {
- ticks -= offset;
- if (this._loop) {
- if (event.startOffset >= this._loopStart && event.startOffset < this._loopEnd) {
- if (event.startOffset < offset) {
- //start it on the next loop
- ticks += this._getLoopDuration();
- }
- event.start(Tone.TransportTime(ticks, 'i'));
- } else if (event.startOffset < this._loopStart && event.startOffset >= offset) {
- event.loop = false;
- event.start(Tone.TransportTime(ticks, 'i'));
- }
- } else {
- if (event.startOffset >= offset) {
- event.start(Tone.TransportTime(ticks, 'i'));
- }
- }
- };
- /**
- * The start from the scheduled start time
- * @type {Ticks}
- * @memberOf Tone.Part#
- * @name startOffset
- * @private
- */
- Object.defineProperty(Tone.Part.prototype, 'startOffset', {
- get: function () {
- return this._startOffset;
- },
- set: function (offset) {
- this._startOffset = offset;
- this._forEach(function (event) {
- event.startOffset += this._startOffset;
- });
- }
- });
- /**
- * Stop the part at the given time.
- * @param {TimelinePosition} time When to stop the part.
- * @return {Tone.Part} this
- */
- Tone.Part.prototype.stop = function (time) {
- var ticks = this.toTicks(time);
- this._state.cancel(ticks);
- this._state.setStateAtTime(Tone.State.Stopped, ticks);
- this._forEach(function (event) {
- event.stop(time);
- });
- return this;
- };
- /**
- * Get/Set an Event's value at the given time.
- * If a value is passed in and no event exists at
- * the given time, one will be created with that value.
- * If two events are at the same time, the first one will
- * be returned.
- * @example
- * part.at("1m"); //returns the part at the first measure
- *
- * part.at("2m", "C2"); //set the value at "2m" to C2.
- * //if an event didn't exist at that time, it will be created.
- * @param {TransportTime} time The time of the event to get or set.
- * @param {*=} value If a value is passed in, the value of the
- * event at the given time will be set to it.
- * @return {Tone.Event} the event at the time
- */
- Tone.Part.prototype.at = function (time, value) {
- time = Tone.TransportTime(time);
- var tickTime = Tone.Time(1, 'i').toSeconds();
- for (var i = 0; i < this._events.length; i++) {
- var event = this._events[i];
- if (Math.abs(time.toTicks() - event.startOffset) < tickTime) {
- if (!Tone.isUndef(value)) {
- event.value = value;
- }
- return event;
- }
- }
- //if there was no event at that time, create one
- if (!Tone.isUndef(value)) {
- this.add(time, value);
- //return the new event
- return this._events[this._events.length - 1];
- } else {
- return null;
- }
- };
- /**
- * Add a an event to the part.
- * @param {Time} time The time the note should start.
- * If an object is passed in, it should
- * have a 'time' attribute and the rest
- * of the object will be used as the 'value'.
- * @param {Tone.Event|*} value
- * @returns {Tone.Part} this
- * @example
- * part.add("1m", "C#+11");
- */
- Tone.Part.prototype.add = function (time, value) {
- //extract the parameters
- if (time.hasOwnProperty('time')) {
- value = time;
- time = value.time;
- }
- time = this.toTicks(time);
- var event;
- if (value instanceof Tone.Event) {
- event = value;
- event.callback = this._tick.bind(this);
- } else {
- event = new Tone.Event({
- 'callback': this._tick.bind(this),
- 'value': value
- });
- }
- //the start offset
- event.startOffset = time;
- //initialize the values
- event.set({
- 'loopEnd': this.loopEnd,
- 'loopStart': this.loopStart,
- 'loop': this.loop,
- 'humanize': this.humanize,
- 'playbackRate': this.playbackRate,
- 'probability': this.probability
- });
- this._events.push(event);
- //start the note if it should be played right now
- this._restartEvent(event);
- return this;
- };
- /**
- * Restart the given event
- * @param {Tone.Event} event
- * @private
- */
- Tone.Part.prototype._restartEvent = function (event) {
- this._state.forEach(function (stateEvent) {
- if (stateEvent.state === Tone.State.Started) {
- this._startNote(event, stateEvent.time, stateEvent.offset);
- } else {
- //stop the note
- event.stop(Tone.TransportTime(stateEvent.time, 'i'));
- }
- }.bind(this));
- };
- /**
- * Remove an event from the part. Will recursively iterate
- * into nested parts to find the event.
- * @param {Time} time The time of the event
- * @param {*} value Optionally select only a specific event value
- * @return {Tone.Part} this
- */
- Tone.Part.prototype.remove = function (time, value) {
- //extract the parameters
- if (time.hasOwnProperty('time')) {
- value = time;
- time = value.time;
- }
- time = this.toTicks(time);
- for (var i = this._events.length - 1; i >= 0; i--) {
- var event = this._events[i];
- if (event instanceof Tone.Part) {
- event.remove(time, value);
- } else {
- if (event.startOffset === time) {
- if (Tone.isUndef(value) || !Tone.isUndef(value) && event.value === value) {
- this._events.splice(i, 1);
- event.dispose();
- }
- }
- }
- }
- return this;
- };
- /**
- * Remove all of the notes from the group.
- * @return {Tone.Part} this
- */
- Tone.Part.prototype.removeAll = function () {
- this._forEach(function (event) {
- event.dispose();
- });
- this._events = [];
- return this;
- };
- /**
- * Cancel scheduled state change events: i.e. "start" and "stop".
- * @param {TimelinePosition} after The time after which to cancel the scheduled events.
- * @return {Tone.Part} this
- */
- Tone.Part.prototype.cancel = function (after) {
- this._forEach(function (event) {
- event.cancel(after);
- });
- this._state.cancel(this.toTicks(after));
- return this;
- };
- /**
- * Iterate over all of the events
- * @param {Function} callback
- * @param {Object} ctx The context
- * @private
- */
- Tone.Part.prototype._forEach = function (callback, ctx) {
- if (this._events) {
- ctx = Tone.defaultArg(ctx, this);
- for (var i = this._events.length - 1; i >= 0; i--) {
- var e = this._events[i];
- if (e instanceof Tone.Part) {
- e._forEach(callback, ctx);
- } else {
- callback.call(ctx, e);
- }
- }
- }
- return this;
- };
- /**
- * Set the attribute of all of the events
- * @param {String} attr the attribute to set
- * @param {*} value The value to set it to
- * @private
- */
- Tone.Part.prototype._setAll = function (attr, value) {
- this._forEach(function (event) {
- event[attr] = value;
- });
- };
- /**
- * Internal tick method
- * @param {Number} time The time of the event in seconds
- * @private
- */
- Tone.Part.prototype._tick = function (time, value) {
- if (!this.mute) {
- this.callback(time, value);
- }
- };
- /**
- * Determine if the event should be currently looping
- * given the loop boundries of this Part.
- * @param {Tone.Event} event The event to test
- * @private
- */
- Tone.Part.prototype._testLoopBoundries = function (event) {
- if (event.startOffset < this._loopStart || event.startOffset >= this._loopEnd) {
- event.cancel(0);
- } else {
- //reschedule it if it's stopped
- if (event.state === Tone.State.Stopped) {
- this._restartEvent(event);
- }
- }
- };
- /**
- * The probability of the notes being triggered.
- * @memberOf Tone.Part#
- * @type {NormalRange}
- * @name probability
- */
- Object.defineProperty(Tone.Part.prototype, 'probability', {
- get: function () {
- return this._probability;
- },
- set: function (prob) {
- this._probability = prob;
- this._setAll('probability', prob);
- }
- });
- /**
- * If set to true, will apply small random variation
- * to the callback time. If the value is given as a time, it will randomize
- * by that amount.
- * @example
- * event.humanize = true;
- * @type {Boolean|Time}
- * @name humanize
- */
- Object.defineProperty(Tone.Part.prototype, 'humanize', {
- get: function () {
- return this._humanize;
- },
- set: function (variation) {
- this._humanize = variation;
- this._setAll('humanize', variation);
- }
- });
- /**
- * If the part should loop or not
- * between Tone.Part.loopStart and
- * Tone.Part.loopEnd. An integer
- * value corresponds to the number of
- * loops the Part does after it starts.
- * @memberOf Tone.Part#
- * @type {Boolean|Positive}
- * @name loop
- * @example
- * //loop the part 8 times
- * part.loop = 8;
- */
- Object.defineProperty(Tone.Part.prototype, 'loop', {
- get: function () {
- return this._loop;
- },
- set: function (loop) {
- this._loop = loop;
- this._forEach(function (event) {
- event._loopStart = this._loopStart;
- event._loopEnd = this._loopEnd;
- event.loop = loop;
- this._testLoopBoundries(event);
- });
- }
- });
- /**
- * The loopEnd point determines when it will
- * loop if Tone.Part.loop is true.
- * @memberOf Tone.Part#
- * @type {TransportTime}
- * @name loopEnd
- */
- Object.defineProperty(Tone.Part.prototype, 'loopEnd', {
- get: function () {
- return Tone.TransportTime(this._loopEnd, 'i').toNotation();
- },
- set: function (loopEnd) {
- this._loopEnd = this.toTicks(loopEnd);
- if (this._loop) {
- this._forEach(function (event) {
- event.loopEnd = loopEnd;
- this._testLoopBoundries(event);
- });
- }
- }
- });
- /**
- * The loopStart point determines when it will
- * loop if Tone.Part.loop is true.
- * @memberOf Tone.Part#
- * @type {TransportTime}
- * @name loopStart
- */
- Object.defineProperty(Tone.Part.prototype, 'loopStart', {
- get: function () {
- return Tone.TransportTime(this._loopStart, 'i').toNotation();
- },
- set: function (loopStart) {
- this._loopStart = this.toTicks(loopStart);
- if (this._loop) {
- this._forEach(function (event) {
- event.loopStart = this.loopStart;
- this._testLoopBoundries(event);
- });
- }
- }
- });
- /**
- * The playback rate of the part
- * @memberOf Tone.Part#
- * @type {Positive}
- * @name playbackRate
- */
- Object.defineProperty(Tone.Part.prototype, 'playbackRate', {
- get: function () {
- return this._playbackRate;
- },
- set: function (rate) {
- this._playbackRate = rate;
- this._setAll('playbackRate', rate);
- }
- });
- /**
- * The number of scheduled notes in the part.
- * @memberOf Tone.Part#
- * @type {Positive}
- * @name length
- * @readOnly
- */
- Object.defineProperty(Tone.Part.prototype, 'length', {
- get: function () {
- return this._events.length;
- }
- });
- /**
- * Clean up
- * @return {Tone.Part} this
- */
- Tone.Part.prototype.dispose = function () {
- this.removeAll();
- this._state.dispose();
- this._state = null;
- this.callback = null;
- this._events = null;
- return this;
- };
- return Tone.Part;
- });
- Module(function (Tone) {
- /**
- * @class Tone.Pattern arpeggiates between the given notes
- * in a number of patterns. See Tone.CtrlPattern for
- * a full list of patterns.
- * @example
- * var pattern = new Tone.Pattern(function(time, note){
- * //the order of the notes passed in depends on the pattern
- * }, ["C2", "D4", "E5", "A6"], "upDown");
- * @extends {Tone.Loop}
- * @param {Function} callback The callback to invoke with the
- * event.
- * @param {Array} values The values to arpeggiate over.
- */
- Tone.Pattern = function () {
- var options = Tone.defaults(arguments, [
- 'callback',
- 'values',
- 'pattern'
- ], Tone.Pattern);
- Tone.Loop.call(this, options);
- /**
- * The pattern manager
- * @type {Tone.CtrlPattern}
- * @private
- */
- this._pattern = new Tone.CtrlPattern({
- 'values': options.values,
- 'type': options.pattern,
- 'index': options.index
- });
- };
- Tone.extend(Tone.Pattern, Tone.Loop);
- /**
- * The defaults
- * @const
- * @type {Object}
- */
- Tone.Pattern.defaults = {
- 'pattern': Tone.CtrlPattern.Type.Up,
- 'callback': Tone.noOp,
- 'values': []
- };
- /**
- * Internal function called when the notes should be called
- * @param {Number} time The time the event occurs
- * @private
- */
- Tone.Pattern.prototype._tick = function (time) {
- this.callback(time, this._pattern.value);
- this._pattern.next();
- };
- /**
- * The current index in the values array.
- * @memberOf Tone.Pattern#
- * @type {Positive}
- * @name index
- */
- Object.defineProperty(Tone.Pattern.prototype, 'index', {
- get: function () {
- return this._pattern.index;
- },
- set: function (i) {
- this._pattern.index = i;
- }
- });
- /**
- * The array of events.
- * @memberOf Tone.Pattern#
- * @type {Array}
- * @name values
- */
- Object.defineProperty(Tone.Pattern.prototype, 'values', {
- get: function () {
- return this._pattern.values;
- },
- set: function (vals) {
- this._pattern.values = vals;
- }
- });
- /**
- * The current value of the pattern.
- * @memberOf Tone.Pattern#
- * @type {*}
- * @name value
- * @readOnly
- */
- Object.defineProperty(Tone.Pattern.prototype, 'value', {
- get: function () {
- return this._pattern.value;
- }
- });
- /**
- * The pattern type. See Tone.CtrlPattern for the full list of patterns.
- * @memberOf Tone.Pattern#
- * @type {String}
- * @name pattern
- */
- Object.defineProperty(Tone.Pattern.prototype, 'pattern', {
- get: function () {
- return this._pattern.type;
- },
- set: function (pattern) {
- this._pattern.type = pattern;
- }
- });
- /**
- * Clean up
- * @return {Tone.Pattern} this
- */
- Tone.Pattern.prototype.dispose = function () {
- Tone.Loop.prototype.dispose.call(this);
- this._pattern.dispose();
- this._pattern = null;
- };
- return Tone.Pattern;
- });
- Module(function (Tone) {
-
- /**
- * @class A sequence is an alternate notation of a part. Instead
- * of passing in an array of [time, event] pairs, pass
- * in an array of events which will be spaced at the
- * given subdivision. Sub-arrays will subdivide that beat
- * by the number of items are in the array.
- * Sequence notation inspiration from [Tidal](http://yaxu.org/tidal/)
- * @param {Function} callback The callback to invoke with every note
- * @param {Array} events The sequence
- * @param {Time} subdivision The subdivision between which events are placed.
- * @extends {Tone.Part}
- * @example
- * var seq = new Tone.Sequence(function(time, note){
- * console.log(note);
- * //straight quater notes
- * }, ["C4", "E4", "G4", "A4"], "4n");
- * @example
- * var seq = new Tone.Sequence(function(time, note){
- * console.log(note);
- * //subdivisions are given as subarrays
- * }, ["C4", ["E4", "D4", "E4"], "G4", ["A4", "G4"]]);
- */
- Tone.Sequence = function () {
- var options = Tone.defaults(arguments, [
- 'callback',
- 'events',
- 'subdivision'
- ], Tone.Sequence);
- //remove the events
- var events = options.events;
- delete options.events;
- Tone.Part.call(this, options);
- /**
- * The subdivison of each note
- * @type {Ticks}
- * @private
- */
- this._subdivision = this.toTicks(options.subdivision);
- //if no time was passed in, the loop end is the end of the cycle
- if (Tone.isUndef(options.loopEnd) && !Tone.isUndef(events)) {
- this._loopEnd = events.length * this._subdivision;
- }
- //defaults to looping
- this._loop = true;
- //add all of the events
- if (!Tone.isUndef(events)) {
- for (var i = 0; i < events.length; i++) {
- this.add(i, events[i]);
- }
- }
- };
- Tone.extend(Tone.Sequence, Tone.Part);
- /**
- * The default values.
- * @type {Object}
- */
- Tone.Sequence.defaults = { 'subdivision': '4n' };
- /**
- * The subdivision of the sequence. This can only be
- * set in the constructor. The subdivision is the
- * interval between successive steps.
- * @type {Time}
- * @memberOf Tone.Sequence#
- * @name subdivision
- * @readOnly
- */
- Object.defineProperty(Tone.Sequence.prototype, 'subdivision', {
- get: function () {
- return Tone.Time(this._subdivision, 'i').toNotation();
- }
- });
- /**
- * Get/Set an index of the sequence. If the index contains a subarray,
- * a Tone.Sequence representing that sub-array will be returned.
- * @example
- * var sequence = new Tone.Sequence(playNote, ["E4", "C4", "F#4", ["A4", "Bb3"]])
- * sequence.at(0)// => returns "E4"
- * //set a value
- * sequence.at(0, "G3");
- * //get a nested sequence
- * sequence.at(3).at(1)// => returns "Bb3"
- * @param {Positive} index The index to get or set
- * @param {*} value Optionally pass in the value to set at the given index.
- */
- Tone.Sequence.prototype.at = function (index, value) {
- //if the value is an array,
- if (Tone.isArray(value)) {
- //remove the current event at that index
- this.remove(index);
- }
- //call the parent's method
- return Tone.Part.prototype.at.call(this, this._indexTime(index), value);
- };
- /**
- * Add an event at an index, if there's already something
- * at that index, overwrite it. If `value` is an array,
- * it will be parsed as a subsequence.
- * @param {Number} index The index to add the event to
- * @param {*} value The value to add at that index
- * @returns {Tone.Sequence} this
- */
- Tone.Sequence.prototype.add = function (index, value) {
- if (value === null) {
- return this;
- }
- if (Tone.isArray(value)) {
- //make a subsequence and add that to the sequence
- var subSubdivision = Math.round(this._subdivision / value.length);
- value = new Tone.Sequence(this._tick.bind(this), value, Tone.Time(subSubdivision, 'i'));
- }
- Tone.Part.prototype.add.call(this, this._indexTime(index), value);
- return this;
- };
- /**
- * Remove a value from the sequence by index
- * @param {Number} index The index of the event to remove
- * @returns {Tone.Sequence} this
- */
- Tone.Sequence.prototype.remove = function (index, value) {
- Tone.Part.prototype.remove.call(this, this._indexTime(index), value);
- return this;
- };
- /**
- * Get the time of the index given the Sequence's subdivision
- * @param {Number} index
- * @return {Time} The time of that index
- * @private
- */
- Tone.Sequence.prototype._indexTime = function (index) {
- if (index instanceof Tone.TransportTime) {
- return index;
- } else {
- return Tone.TransportTime(index * this._subdivision + this.startOffset, 'i');
- }
- };
- /**
- * Clean up.
- * @return {Tone.Sequence} this
- */
- Tone.Sequence.prototype.dispose = function () {
- Tone.Part.prototype.dispose.call(this);
- return this;
- };
- return Tone.Sequence;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.PulseOscillator is a pulse oscillator with control over pulse width,
- * also known as the duty cycle. At 50% duty cycle (width = 0.5) the wave is
- * a square and only odd-numbered harmonics are present. At all other widths
- * even-numbered harmonics are present. Read more
- * [here](https://wigglewave.wordpress.com/2014/08/16/pulse-waveforms-and-harmonics/).
- *
- * @constructor
- * @extends {Tone.Source}
- * @param {Frequency} [frequency] The frequency of the oscillator
- * @param {NormalRange} [width] The width of the pulse
- * @example
- * var pulse = new Tone.PulseOscillator("E5", 0.4).toMaster().start();
- */
- Tone.PulseOscillator = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'width'
- ], Tone.Oscillator);
- Tone.Source.call(this, options);
- /**
- * The width of the pulse.
- * @type {NormalRange}
- * @signal
- */
- this.width = new Tone.Signal(options.width, Tone.Type.NormalRange);
- /**
- * gate the width amount
- * @type {Tone.Gain}
- * @private
- */
- this._widthGate = new Tone.Gain();
- /**
- * the sawtooth oscillator
- * @type {Tone.Oscillator}
- * @private
- */
- this._sawtooth = new Tone.Oscillator({
- frequency: options.frequency,
- detune: options.detune,
- type: 'sawtooth',
- phase: options.phase
- });
- /**
- * The frequency control.
- * @type {Frequency}
- * @signal
- */
- this.frequency = this._sawtooth.frequency;
- /**
- * The detune in cents.
- * @type {Cents}
- * @signal
- */
- this.detune = this._sawtooth.detune;
- /**
- * Threshold the signal to turn it into a square
- * @type {Tone.WaveShaper}
- * @private
- */
- this._thresh = new Tone.WaveShaper(function (val) {
- if (val < 0) {
- return -1;
- } else {
- return 1;
- }
- });
- //connections
- this._sawtooth.chain(this._thresh, this.output);
- this.width.chain(this._widthGate, this._thresh);
- this._readOnly([
- 'width',
- 'frequency',
- 'detune'
- ]);
- };
- Tone.extend(Tone.PulseOscillator, Tone.Source);
- /**
- * The default parameters.
- * @static
- * @const
- * @type {Object}
- */
- Tone.PulseOscillator.defaults = {
- 'frequency': 440,
- 'detune': 0,
- 'phase': 0,
- 'width': 0.2
- };
- /**
- * start the oscillator
- * @param {Time} time
- * @private
- */
- Tone.PulseOscillator.prototype._start = function (time) {
- time = this.toSeconds(time);
- this._sawtooth.start(time);
- this._widthGate.gain.setValueAtTime(1, time);
- };
- /**
- * stop the oscillator
- * @param {Time} time
- * @private
- */
- Tone.PulseOscillator.prototype._stop = function (time) {
- time = this.toSeconds(time);
- this._sawtooth.stop(time);
- //the width is still connected to the output.
- //that needs to be stopped also
- this._widthGate.gain.setValueAtTime(0, time);
- };
- /**
- * The phase of the oscillator in degrees.
- * @memberOf Tone.PulseOscillator#
- * @type {Degrees}
- * @name phase
- */
- Object.defineProperty(Tone.PulseOscillator.prototype, 'phase', {
- get: function () {
- return this._sawtooth.phase;
- },
- set: function (phase) {
- this._sawtooth.phase = phase;
- }
- });
- /**
- * The type of the oscillator. Always returns "pulse".
- * @readOnly
- * @memberOf Tone.PulseOscillator#
- * @type {string}
- * @name type
- */
- Object.defineProperty(Tone.PulseOscillator.prototype, 'type', {
- get: function () {
- return 'pulse';
- }
- });
- /**
- * The partials of the waveform. Cannot set partials for this waveform type
- * @memberOf Tone.PulseOscillator#
- * @type {Array}
- * @name partials
- * @private
- */
- Object.defineProperty(Tone.PulseOscillator.prototype, 'partials', {
- get: function () {
- return [];
- }
- });
- /**
- * Clean up method.
- * @return {Tone.PulseOscillator} this
- */
- Tone.PulseOscillator.prototype.dispose = function () {
- Tone.Source.prototype.dispose.call(this);
- this._sawtooth.dispose();
- this._sawtooth = null;
- this._writable([
- 'width',
- 'frequency',
- 'detune'
- ]);
- this.width.dispose();
- this.width = null;
- this._widthGate.dispose();
- this._widthGate = null;
- this._thresh.dispose();
- this._thresh = null;
- this.frequency = null;
- this.detune = null;
- return this;
- };
- return Tone.PulseOscillator;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.PWMOscillator modulates the width of a Tone.PulseOscillator
- * at the modulationFrequency. This has the effect of continuously
- * changing the timbre of the oscillator by altering the harmonics
- * generated.
- *
- * @extends {Tone.Source}
- * @constructor
- * @param {Frequency} frequency The starting frequency of the oscillator.
- * @param {Frequency} modulationFrequency The modulation frequency of the width of the pulse.
- * @example
- * var pwm = new Tone.PWMOscillator("Ab3", 0.3).toMaster().start();
- */
- Tone.PWMOscillator = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'modulationFrequency'
- ], Tone.PWMOscillator);
- Tone.Source.call(this, options);
- /**
- * the pulse oscillator
- * @type {Tone.PulseOscillator}
- * @private
- */
- this._pulse = new Tone.PulseOscillator(options.modulationFrequency);
- //change the pulse oscillator type
- this._pulse._sawtooth.type = 'sine';
- /**
- * the modulator
- * @type {Tone.Oscillator}
- * @private
- */
- this._modulator = new Tone.Oscillator({
- 'frequency': options.frequency,
- 'detune': options.detune,
- 'phase': options.phase
- });
- /**
- * Scale the oscillator so it doesn't go silent
- * at the extreme values.
- * @type {Tone.Multiply}
- * @private
- */
- this._scale = new Tone.Multiply(2);
- /**
- * The frequency control.
- * @type {Frequency}
- * @signal
- */
- this.frequency = this._modulator.frequency;
- /**
- * The detune of the oscillator.
- * @type {Cents}
- * @signal
- */
- this.detune = this._modulator.detune;
- /**
- * The modulation rate of the oscillator.
- * @type {Frequency}
- * @signal
- */
- this.modulationFrequency = this._pulse.frequency;
- //connections
- this._modulator.chain(this._scale, this._pulse.width);
- this._pulse.connect(this.output);
- this._readOnly([
- 'modulationFrequency',
- 'frequency',
- 'detune'
- ]);
- };
- Tone.extend(Tone.PWMOscillator, Tone.Source);
- /**
- * default values
- * @static
- * @type {Object}
- * @const
- */
- Tone.PWMOscillator.defaults = {
- 'frequency': 440,
- 'detune': 0,
- 'phase': 0,
- 'modulationFrequency': 0.4
- };
- /**
- * start the oscillator
- * @param {Time} [time=now]
- * @private
- */
- Tone.PWMOscillator.prototype._start = function (time) {
- time = this.toSeconds(time);
- this._modulator.start(time);
- this._pulse.start(time);
- };
- /**
- * stop the oscillator
- * @param {Time} time (optional) timing parameter
- * @private
- */
- Tone.PWMOscillator.prototype._stop = function (time) {
- time = this.toSeconds(time);
- this._modulator.stop(time);
- this._pulse.stop(time);
- };
- /**
- * The type of the oscillator. Always returns "pwm".
- * @readOnly
- * @memberOf Tone.PWMOscillator#
- * @type {string}
- * @name type
- */
- Object.defineProperty(Tone.PWMOscillator.prototype, 'type', {
- get: function () {
- return 'pwm';
- }
- });
- /**
- * The partials of the waveform. Cannot set partials for this waveform type
- * @memberOf Tone.PWMOscillator#
- * @type {Array}
- * @name partials
- * @private
- */
- Object.defineProperty(Tone.PWMOscillator.prototype, 'partials', {
- get: function () {
- return [];
- }
- });
- /**
- * The phase of the oscillator in degrees.
- * @memberOf Tone.PWMOscillator#
- * @type {number}
- * @name phase
- */
- Object.defineProperty(Tone.PWMOscillator.prototype, 'phase', {
- get: function () {
- return this._modulator.phase;
- },
- set: function (phase) {
- this._modulator.phase = phase;
- }
- });
- /**
- * Clean up.
- * @return {Tone.PWMOscillator} this
- */
- Tone.PWMOscillator.prototype.dispose = function () {
- Tone.Source.prototype.dispose.call(this);
- this._pulse.dispose();
- this._pulse = null;
- this._scale.dispose();
- this._scale = null;
- this._modulator.dispose();
- this._modulator = null;
- this._writable([
- 'modulationFrequency',
- 'frequency',
- 'detune'
- ]);
- this.frequency = null;
- this.detune = null;
- this.modulationFrequency = null;
- return this;
- };
- return Tone.PWMOscillator;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.FMOscillator
- *
- * @extends {Tone.Source}
- * @constructor
- * @param {Frequency} frequency The starting frequency of the oscillator.
- * @param {String} type The type of the carrier oscillator.
- * @param {String} modulationType The type of the modulator oscillator.
- * @example
- * //a sine oscillator frequency-modulated by a square wave
- * var fmOsc = new Tone.FMOscillator("Ab3", "sine", "square").toMaster().start();
- */
- Tone.FMOscillator = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'type',
- 'modulationType'
- ], Tone.FMOscillator);
- Tone.Source.call(this, options);
- /**
- * The carrier oscillator
- * @type {Tone.Oscillator}
- * @private
- */
- this._carrier = new Tone.Oscillator(options.frequency, options.type);
- /**
- * The oscillator's frequency
- * @type {Frequency}
- * @signal
- */
- this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
- /**
- * The detune control signal.
- * @type {Cents}
- * @signal
- */
- this.detune = this._carrier.detune;
- this.detune.value = options.detune;
- /**
- * The modulation index which is in essence the depth or amount of the modulation. In other terms it is the
- * ratio of the frequency of the modulating signal (mf) to the amplitude of the
- * modulating signal (ma) -- as in ma/mf.
- * @type {Positive}
- * @signal
- */
- this.modulationIndex = new Tone.Multiply(options.modulationIndex);
- this.modulationIndex.units = Tone.Type.Positive;
- /**
- * The modulating oscillator
- * @type {Tone.Oscillator}
- * @private
- */
- this._modulator = new Tone.Oscillator(options.frequency, options.modulationType);
- /**
- * Harmonicity is the frequency ratio between the carrier and the modulator oscillators.
- * A harmonicity of 1 gives both oscillators the same frequency.
- * Harmonicity = 2 means a change of an octave.
- * @type {Positive}
- * @signal
- * @example
- * //pitch the modulator an octave below carrier
- * synth.harmonicity.value = 0.5;
- */
- this.harmonicity = new Tone.Multiply(options.harmonicity);
- this.harmonicity.units = Tone.Type.Positive;
- /**
- * the node where the modulation happens
- * @type {Tone.Gain}
- * @private
- */
- this._modulationNode = new Tone.Gain(0);
- //connections
- this.frequency.connect(this._carrier.frequency);
- this.frequency.chain(this.harmonicity, this._modulator.frequency);
- this.frequency.chain(this.modulationIndex, this._modulationNode);
- this._modulator.connect(this._modulationNode.gain);
- this._modulationNode.connect(this._carrier.frequency);
- this._carrier.connect(this.output);
- this.detune.connect(this._modulator.detune);
- this.phase = options.phase;
- this._readOnly([
- 'modulationIndex',
- 'frequency',
- 'detune',
- 'harmonicity'
- ]);
- };
- Tone.extend(Tone.FMOscillator, Tone.Source);
- /**
- * default values
- * @static
- * @type {Object}
- * @const
- */
- Tone.FMOscillator.defaults = {
- 'frequency': 440,
- 'detune': 0,
- 'phase': 0,
- 'modulationIndex': 2,
- 'modulationType': 'square',
- 'harmonicity': 1
- };
- /**
- * start the oscillator
- * @param {Time} [time=now]
- * @private
- */
- Tone.FMOscillator.prototype._start = function (time) {
- time = this.toSeconds(time);
- this._modulator.start(time);
- this._carrier.start(time);
- };
- /**
- * stop the oscillator
- * @param {Time} time (optional) timing parameter
- * @private
- */
- Tone.FMOscillator.prototype._stop = function (time) {
- time = this.toSeconds(time);
- this._modulator.stop(time);
- this._carrier.stop(time);
- };
- /**
- * The type of the carrier oscillator
- * @memberOf Tone.FMOscillator#
- * @type {string}
- * @name type
- */
- Object.defineProperty(Tone.FMOscillator.prototype, 'type', {
- get: function () {
- return this._carrier.type;
- },
- set: function (type) {
- this._carrier.type = type;
- }
- });
- /**
- * The type of the modulator oscillator
- * @memberOf Tone.FMOscillator#
- * @type {String}
- * @name modulationType
- */
- Object.defineProperty(Tone.FMOscillator.prototype, 'modulationType', {
- get: function () {
- return this._modulator.type;
- },
- set: function (type) {
- this._modulator.type = type;
- }
- });
- /**
- * The phase of the oscillator in degrees.
- * @memberOf Tone.FMOscillator#
- * @type {number}
- * @name phase
- */
- Object.defineProperty(Tone.FMOscillator.prototype, 'phase', {
- get: function () {
- return this._carrier.phase;
- },
- set: function (phase) {
- this._carrier.phase = phase;
- this._modulator.phase = phase;
- }
- });
- /**
- * The partials of the carrier waveform. A partial represents
- * the amplitude at a harmonic. The first harmonic is the
- * fundamental frequency, the second is the octave and so on
- * following the harmonic series.
- * Setting this value will automatically set the type to "custom".
- * The value is an empty array when the type is not "custom".
- * @memberOf Tone.FMOscillator#
- * @type {Array}
- * @name partials
- * @example
- * osc.partials = [1, 0.2, 0.01];
- */
- Object.defineProperty(Tone.FMOscillator.prototype, 'partials', {
- get: function () {
- return this._carrier.partials;
- },
- set: function (partials) {
- this._carrier.partials = partials;
- }
- });
- /**
- * Clean up.
- * @return {Tone.FMOscillator} this
- */
- Tone.FMOscillator.prototype.dispose = function () {
- Tone.Source.prototype.dispose.call(this);
- this._writable([
- 'modulationIndex',
- 'frequency',
- 'detune',
- 'harmonicity'
- ]);
- this.frequency.dispose();
- this.frequency = null;
- this.detune = null;
- this.harmonicity.dispose();
- this.harmonicity = null;
- this._carrier.dispose();
- this._carrier = null;
- this._modulator.dispose();
- this._modulator = null;
- this._modulationNode.dispose();
- this._modulationNode = null;
- this.modulationIndex.dispose();
- this.modulationIndex = null;
- return this;
- };
- return Tone.FMOscillator;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.AMOscillator
- *
- * @extends {Tone.Oscillator}
- * @constructor
- * @param {Frequency} frequency The starting frequency of the oscillator.
- * @param {String} type The type of the carrier oscillator.
- * @param {String} modulationType The type of the modulator oscillator.
- * @example
- * //a sine oscillator frequency-modulated by a square wave
- * var fmOsc = new Tone.AMOscillator("Ab3", "sine", "square").toMaster().start();
- */
- Tone.AMOscillator = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'type',
- 'modulationType'
- ], Tone.AMOscillator);
- Tone.Source.call(this, options);
- /**
- * The carrier oscillator
- * @type {Tone.Oscillator}
- * @private
- */
- this._carrier = new Tone.Oscillator(options.frequency, options.type);
- /**
- * The oscillator's frequency
- * @type {Frequency}
- * @signal
- */
- this.frequency = this._carrier.frequency;
- /**
- * The detune control signal.
- * @type {Cents}
- * @signal
- */
- this.detune = this._carrier.detune;
- this.detune.value = options.detune;
- /**
- * The modulating oscillator
- * @type {Tone.Oscillator}
- * @private
- */
- this._modulator = new Tone.Oscillator(options.frequency, options.modulationType);
- /**
- * convert the -1,1 output to 0,1
- * @type {Tone.AudioToGain}
- * @private
- */
- this._modulationScale = new Tone.AudioToGain();
- /**
- * Harmonicity is the frequency ratio between the carrier and the modulator oscillators.
- * A harmonicity of 1 gives both oscillators the same frequency.
- * Harmonicity = 2 means a change of an octave.
- * @type {Positive}
- * @signal
- * @example
- * //pitch the modulator an octave below carrier
- * synth.harmonicity.value = 0.5;
- */
- this.harmonicity = new Tone.Multiply(options.harmonicity);
- this.harmonicity.units = Tone.Type.Positive;
- /**
- * the node where the modulation happens
- * @type {Tone.Gain}
- * @private
- */
- this._modulationNode = new Tone.Gain(0);
- //connections
- this.frequency.chain(this.harmonicity, this._modulator.frequency);
- this.detune.connect(this._modulator.detune);
- this._modulator.chain(this._modulationScale, this._modulationNode.gain);
- this._carrier.chain(this._modulationNode, this.output);
- this.phase = options.phase;
- this._readOnly([
- 'frequency',
- 'detune',
- 'harmonicity'
- ]);
- };
- Tone.extend(Tone.AMOscillator, Tone.Oscillator);
- /**
- * default values
- * @static
- * @type {Object}
- * @const
- */
- Tone.AMOscillator.defaults = {
- 'frequency': 440,
- 'detune': 0,
- 'phase': 0,
- 'modulationType': 'square',
- 'harmonicity': 1
- };
- /**
- * start the oscillator
- * @param {Time} [time=now]
- * @private
- */
- Tone.AMOscillator.prototype._start = function (time) {
- time = this.toSeconds(time);
- this._modulator.start(time);
- this._carrier.start(time);
- };
- /**
- * stop the oscillator
- * @param {Time} time (optional) timing parameter
- * @private
- */
- Tone.AMOscillator.prototype._stop = function (time) {
- time = this.toSeconds(time);
- this._modulator.stop(time);
- this._carrier.stop(time);
- };
- /**
- * The type of the carrier oscillator
- * @memberOf Tone.AMOscillator#
- * @type {string}
- * @name type
- */
- Object.defineProperty(Tone.AMOscillator.prototype, 'type', {
- get: function () {
- return this._carrier.type;
- },
- set: function (type) {
- this._carrier.type = type;
- }
- });
- /**
- * The type of the modulator oscillator
- * @memberOf Tone.AMOscillator#
- * @type {string}
- * @name modulationType
- */
- Object.defineProperty(Tone.AMOscillator.prototype, 'modulationType', {
- get: function () {
- return this._modulator.type;
- },
- set: function (type) {
- this._modulator.type = type;
- }
- });
- /**
- * The phase of the oscillator in degrees.
- * @memberOf Tone.AMOscillator#
- * @type {number}
- * @name phase
- */
- Object.defineProperty(Tone.AMOscillator.prototype, 'phase', {
- get: function () {
- return this._carrier.phase;
- },
- set: function (phase) {
- this._carrier.phase = phase;
- this._modulator.phase = phase;
- }
- });
- /**
- * The partials of the carrier waveform. A partial represents
- * the amplitude at a harmonic. The first harmonic is the
- * fundamental frequency, the second is the octave and so on
- * following the harmonic series.
- * Setting this value will automatically set the type to "custom".
- * The value is an empty array when the type is not "custom".
- * @memberOf Tone.AMOscillator#
- * @type {Array}
- * @name partials
- * @example
- * osc.partials = [1, 0.2, 0.01];
- */
- Object.defineProperty(Tone.AMOscillator.prototype, 'partials', {
- get: function () {
- return this._carrier.partials;
- },
- set: function (partials) {
- this._carrier.partials = partials;
- }
- });
- /**
- * Clean up.
- * @return {Tone.AMOscillator} this
- */
- Tone.AMOscillator.prototype.dispose = function () {
- Tone.Source.prototype.dispose.call(this);
- this._writable([
- 'frequency',
- 'detune',
- 'harmonicity'
- ]);
- this.frequency = null;
- this.detune = null;
- this.harmonicity.dispose();
- this.harmonicity = null;
- this._carrier.dispose();
- this._carrier = null;
- this._modulator.dispose();
- this._modulator = null;
- this._modulationNode.dispose();
- this._modulationNode = null;
- this._modulationScale.dispose();
- this._modulationScale = null;
- return this;
- };
- return Tone.AMOscillator;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.FatOscillator
- *
- * @extends {Tone.Source}
- * @constructor
- * @param {Frequency} frequency The starting frequency of the oscillator.
- * @param {String} type The type of the carrier oscillator.
- * @param {String} modulationType The type of the modulator oscillator.
- * @example
- * //a sine oscillator frequency-modulated by a square wave
- * var fmOsc = new Tone.FatOscillator("Ab3", "sine", "square").toMaster().start();
- */
- Tone.FatOscillator = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'type',
- 'spread'
- ], Tone.FatOscillator);
- Tone.Source.call(this, options);
- /**
- * The oscillator's frequency
- * @type {Frequency}
- * @signal
- */
- this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
- /**
- * The detune control signal.
- * @type {Cents}
- * @signal
- */
- this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);
- /**
- * The array of oscillators
- * @type {Array}
- * @private
- */
- this._oscillators = [];
- /**
- * The total spread of the oscillators
- * @type {Cents}
- * @private
- */
- this._spread = options.spread;
- /**
- * The type of the oscillator
- * @type {String}
- * @private
- */
- this._type = options.type;
- /**
- * The phase of the oscillators
- * @type {Degrees}
- * @private
- */
- this._phase = options.phase;
- /**
- * The partials array
- * @type {Array}
- * @private
- */
- this._partials = Tone.defaultArg(options.partials, []);
- //set the count initially
- this.count = options.count;
- this._readOnly([
- 'frequency',
- 'detune'
- ]);
- };
- Tone.extend(Tone.FatOscillator, Tone.Source);
- /**
- * default values
- * @static
- * @type {Object}
- * @const
- */
- Tone.FatOscillator.defaults = {
- 'frequency': 440,
- 'detune': 0,
- 'phase': 0,
- 'spread': 20,
- 'count': 3,
- 'type': 'sawtooth'
- };
- /**
- * start the oscillator
- * @param {Time} [time=now]
- * @private
- */
- Tone.FatOscillator.prototype._start = function (time) {
- time = this.toSeconds(time);
- this._forEach(function (osc) {
- osc.start(time);
- });
- };
- /**
- * stop the oscillator
- * @param {Time} time (optional) timing parameter
- * @private
- */
- Tone.FatOscillator.prototype._stop = function (time) {
- time = this.toSeconds(time);
- this._forEach(function (osc) {
- osc.stop(time);
- });
- };
- /**
- * Iterate over all of the oscillators
- * @param {Function} iterator The iterator function
- * @private
- */
- Tone.FatOscillator.prototype._forEach = function (iterator) {
- for (var i = 0; i < this._oscillators.length; i++) {
- iterator.call(this, this._oscillators[i], i);
- }
- };
- /**
- * The type of the carrier oscillator
- * @memberOf Tone.FatOscillator#
- * @type {string}
- * @name type
- */
- Object.defineProperty(Tone.FatOscillator.prototype, 'type', {
- get: function () {
- return this._type;
- },
- set: function (type) {
- this._type = type;
- this._forEach(function (osc) {
- osc.type = type;
- });
- }
- });
- /**
- * The detune spread between the oscillators. If "count" is
- * set to 3 oscillators and the "spread" is set to 40,
- * the three oscillators would be detuned like this: [-20, 0, 20]
- * for a total detune spread of 40 cents.
- * @memberOf Tone.FatOscillator#
- * @type {Cents}
- * @name spread
- */
- Object.defineProperty(Tone.FatOscillator.prototype, 'spread', {
- get: function () {
- return this._spread;
- },
- set: function (spread) {
- this._spread = spread;
- if (this._oscillators.length > 1) {
- var start = -spread / 2;
- var step = spread / (this._oscillators.length - 1);
- this._forEach(function (osc, i) {
- osc.detune.value = start + step * i;
- });
- }
- }
- });
- /**
- * The number of detuned oscillators
- * @memberOf Tone.FatOscillator#
- * @type {Number}
- * @name count
- */
- Object.defineProperty(Tone.FatOscillator.prototype, 'count', {
- get: function () {
- return this._oscillators.length;
- },
- set: function (count) {
- count = Math.max(count, 1);
- if (this._oscillators.length !== count) {
- // var partials = this.partials;
- // var type = this.type;
- //dispose the previous oscillators
- this._forEach(function (osc) {
- osc.dispose();
- });
- this._oscillators = [];
- for (var i = 0; i < count; i++) {
- var osc = new Tone.Oscillator();
- if (this.type === Tone.Oscillator.Type.Custom) {
- osc.partials = this._partials;
- } else {
- osc.type = this._type;
- }
- osc.phase = this._phase;
- osc.volume.value = -6 - count;
- this.frequency.connect(osc.frequency);
- this.detune.connect(osc.detune);
- osc.connect(this.output);
- this._oscillators[i] = osc;
- }
- //set the spread
- this.spread = this._spread;
- if (this.state === Tone.State.Started) {
- this._forEach(function (osc) {
- osc.start();
- });
- }
- }
- }
- });
- /**
- * The phase of the oscillator in degrees.
- * @memberOf Tone.FatOscillator#
- * @type {Number}
- * @name phase
- */
- Object.defineProperty(Tone.FatOscillator.prototype, 'phase', {
- get: function () {
- return this._phase;
- },
- set: function (phase) {
- this._phase = phase;
- this._forEach(function (osc) {
- osc.phase = phase;
- });
- }
- });
- /**
- * The partials of the carrier waveform. A partial represents
- * the amplitude at a harmonic. The first harmonic is the
- * fundamental frequency, the second is the octave and so on
- * following the harmonic series.
- * Setting this value will automatically set the type to "custom".
- * The value is an empty array when the type is not "custom".
- * @memberOf Tone.FatOscillator#
- * @type {Array}
- * @name partials
- * @example
- * osc.partials = [1, 0.2, 0.01];
- */
- Object.defineProperty(Tone.FatOscillator.prototype, 'partials', {
- get: function () {
- return this._partials;
- },
- set: function (partials) {
- this._partials = partials;
- this._type = Tone.Oscillator.Type.Custom;
- this._forEach(function (osc) {
- osc.partials = partials;
- });
- }
- });
- /**
- * Clean up.
- * @return {Tone.FatOscillator} this
- */
- Tone.FatOscillator.prototype.dispose = function () {
- Tone.Source.prototype.dispose.call(this);
- this._writable([
- 'frequency',
- 'detune'
- ]);
- this.frequency.dispose();
- this.frequency = null;
- this.detune.dispose();
- this.detune = null;
- this._forEach(function (osc) {
- osc.dispose();
- });
- this._oscillators = null;
- this._partials = null;
- return this;
- };
- return Tone.FatOscillator;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.OmniOscillator aggregates Tone.Oscillator, Tone.PulseOscillator,
- * Tone.PWMOscillator, Tone.FMOscillator, Tone.AMOscillator, and Tone.FatOscillator
- * into one class. The oscillator class can be changed by setting the `type`.
- * `omniOsc.type = "pwm"` will set it to the Tone.PWMOscillator. Prefixing
- * any of the basic types ("sine", "square4", etc.) with "fm", "am", or "fat"
- * will use the FMOscillator, AMOscillator or FatOscillator respectively.
- * For example: `omniOsc.type = "fatsawtooth"` will create set the oscillator
- * to a FatOscillator of type "sawtooth".
- *
- * @extends {Tone.Source}
- * @constructor
- * @param {Frequency} frequency The initial frequency of the oscillator.
- * @param {String} type The type of the oscillator.
- * @example
- * var omniOsc = new Tone.OmniOscillator("C#4", "pwm");
- */
- Tone.OmniOscillator = function () {
- var options = Tone.defaults(arguments, [
- 'frequency',
- 'type'
- ], Tone.OmniOscillator);
- Tone.Source.call(this, options);
- /**
- * The frequency control.
- * @type {Frequency}
- * @signal
- */
- this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
- /**
- * The detune control
- * @type {Cents}
- * @signal
- */
- this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);
- /**
- * the type of the oscillator source
- * @type {String}
- * @private
- */
- this._sourceType = undefined;
- /**
- * the oscillator
- * @type {Tone.Oscillator}
- * @private
- */
- this._oscillator = null;
- //set the oscillator
- this.type = options.type;
- this._readOnly([
- 'frequency',
- 'detune'
- ]);
- //set the options
- this.set(options);
- };
- Tone.extend(Tone.OmniOscillator, Tone.Source);
- /**
- * default values
- * @static
- * @type {Object}
- * @const
- */
- Tone.OmniOscillator.defaults = {
- 'frequency': 440,
- 'detune': 0,
- 'type': 'sine',
- 'phase': 0
- };
- /**
- * @enum {String}
- * @private
- */
- var OmniOscType = {
- Pulse: 'PulseOscillator',
- PWM: 'PWMOscillator',
- Osc: 'Oscillator',
- FM: 'FMOscillator',
- AM: 'AMOscillator',
- Fat: 'FatOscillator'
- };
- /**
- * start the oscillator
- * @param {Time} [time=now] the time to start the oscillator
- * @private
- */
- Tone.OmniOscillator.prototype._start = function (time) {
- this._oscillator.start(time);
- };
- /**
- * start the oscillator
- * @param {Time} [time=now] the time to start the oscillator
- * @private
- */
- Tone.OmniOscillator.prototype._stop = function (time) {
- this._oscillator.stop(time);
- };
- /**
- * The type of the oscillator. Can be any of the basic types: sine, square, triangle, sawtooth. Or
- * prefix the basic types with "fm", "am", or "fat" to use the FMOscillator, AMOscillator or FatOscillator
- * types. The oscillator could also be set to "pwm" or "pulse". All of the parameters of the
- * oscillator's class are accessible when the oscillator is set to that type, but throws an error
- * when it's not.
- *
- * @memberOf Tone.OmniOscillator#
- * @type {String}
- * @name type
- * @example
- * omniOsc.type = "pwm";
- * //modulationFrequency is parameter which is available
- * //only when the type is "pwm".
- * omniOsc.modulationFrequency.value = 0.5;
- * @example
- * //an square wave frequency modulated by a sawtooth
- * omniOsc.type = "fmsquare";
- * omniOsc.modulationType = "sawtooth";
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'type', {
- get: function () {
- var prefix = '';
- if (this._sourceType === OmniOscType.FM) {
- prefix = 'fm';
- } else if (this._sourceType === OmniOscType.AM) {
- prefix = 'am';
- } else if (this._sourceType === OmniOscType.Fat) {
- prefix = 'fat';
- }
- return prefix + this._oscillator.type;
- },
- set: function (type) {
- if (type.substr(0, 2) === 'fm') {
- this._createNewOscillator(OmniOscType.FM);
- this._oscillator.type = type.substr(2);
- } else if (type.substr(0, 2) === 'am') {
- this._createNewOscillator(OmniOscType.AM);
- this._oscillator.type = type.substr(2);
- } else if (type.substr(0, 3) === 'fat') {
- this._createNewOscillator(OmniOscType.Fat);
- this._oscillator.type = type.substr(3);
- } else if (type === 'pwm') {
- this._createNewOscillator(OmniOscType.PWM);
- } else if (type === 'pulse') {
- this._createNewOscillator(OmniOscType.Pulse);
- } else {
- this._createNewOscillator(OmniOscType.Osc);
- this._oscillator.type = type;
- }
- }
- });
- /**
- * The partials of the waveform. A partial represents
- * the amplitude at a harmonic. The first harmonic is the
- * fundamental frequency, the second is the octave and so on
- * following the harmonic series.
- * Setting this value will automatically set the type to "custom".
- * The value is an empty array when the type is not "custom".
- * This is not available on "pwm" and "pulse" oscillator types.
- * @memberOf Tone.OmniOscillator#
- * @type {Array}
- * @name partials
- * @example
- * osc.partials = [1, 0.2, 0.01];
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'partials', {
- get: function () {
- return this._oscillator.partials;
- },
- set: function (partials) {
- this._oscillator.partials = partials;
- }
- });
- /**
- * Set a member/attribute of the oscillator.
- * @param {Object|String} params
- * @param {number=} value
- * @param {Time=} rampTime
- * @returns {Tone.OmniOscillator} this
- */
- Tone.OmniOscillator.prototype.set = function (params, value) {
- //make sure the type is set first
- if (params === 'type') {
- this.type = value;
- } else if (Tone.isObject(params) && params.hasOwnProperty('type')) {
- this.type = params.type;
- }
- //then set the rest
- Tone.prototype.set.apply(this, arguments);
- return this;
- };
- /**
- * connect the oscillator to the frequency and detune signals
- * @private
- */
- Tone.OmniOscillator.prototype._createNewOscillator = function (oscType) {
- if (oscType !== this._sourceType) {
- this._sourceType = oscType;
- var OscillatorConstructor = Tone[oscType];
- //short delay to avoid clicks on the change
- var now = this.now();
- if (this._oscillator !== null) {
- var oldOsc = this._oscillator;
- oldOsc.stop(now);
- //dispose the old one
- this.context.setTimeout(function () {
- oldOsc.dispose();
- oldOsc = null;
- }, this.blockTime);
- }
- this._oscillator = new OscillatorConstructor();
- this.frequency.connect(this._oscillator.frequency);
- this.detune.connect(this._oscillator.detune);
- this._oscillator.connect(this.output);
- if (this.state === Tone.State.Started) {
- this._oscillator.start(now);
- }
- }
- };
- /**
- * The phase of the oscillator in degrees.
- * @memberOf Tone.OmniOscillator#
- * @type {Degrees}
- * @name phase
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'phase', {
- get: function () {
- return this._oscillator.phase;
- },
- set: function (phase) {
- this._oscillator.phase = phase;
- }
- });
- /**
- * The width of the oscillator (only if the oscillator is set to "pulse")
- * @memberOf Tone.OmniOscillator#
- * @type {NormalRange}
- * @signal
- * @name width
- * @example
- * var omniOsc = new Tone.OmniOscillator(440, "pulse");
- * //can access the width attribute only if type === "pulse"
- * omniOsc.width.value = 0.2;
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'width', {
- get: function () {
- if (this._sourceType === OmniOscType.Pulse) {
- return this._oscillator.width;
- }
- }
- });
- /**
- * The number of detuned oscillators
- * @memberOf Tone.OmniOscillator#
- * @type {Number}
- * @name count
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'count', {
- get: function () {
- if (this._sourceType === OmniOscType.Fat) {
- return this._oscillator.count;
- }
- },
- set: function (count) {
- if (this._sourceType === OmniOscType.Fat) {
- this._oscillator.count = count;
- }
- }
- });
- /**
- * The detune spread between the oscillators. If "count" is
- * set to 3 oscillators and the "spread" is set to 40,
- * the three oscillators would be detuned like this: [-20, 0, 20]
- * for a total detune spread of 40 cents. See Tone.FatOscillator
- * for more info.
- * @memberOf Tone.OmniOscillator#
- * @type {Cents}
- * @name spread
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'spread', {
- get: function () {
- if (this._sourceType === OmniOscType.Fat) {
- return this._oscillator.spread;
- }
- },
- set: function (spread) {
- if (this._sourceType === OmniOscType.Fat) {
- this._oscillator.spread = spread;
- }
- }
- });
- /**
- * The type of the modulator oscillator. Only if the oscillator
- * is set to "am" or "fm" types. see. Tone.AMOscillator or Tone.FMOscillator
- * for more info.
- * @memberOf Tone.OmniOscillator#
- * @type {String}
- * @name modulationType
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'modulationType', {
- get: function () {
- if (this._sourceType === OmniOscType.FM || this._sourceType === OmniOscType.AM) {
- return this._oscillator.modulationType;
- }
- },
- set: function (mType) {
- if (this._sourceType === OmniOscType.FM || this._sourceType === OmniOscType.AM) {
- this._oscillator.modulationType = mType;
- }
- }
- });
- /**
- * The modulation index which is in essence the depth or amount of the modulation. In other terms it is the
- * ratio of the frequency of the modulating signal (mf) to the amplitude of the
- * modulating signal (ma) -- as in ma/mf.
- * See Tone.FMOscillator for more info.
- * @type {Positive}
- * @signal
- * @name modulationIndex
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'modulationIndex', {
- get: function () {
- if (this._sourceType === OmniOscType.FM) {
- return this._oscillator.modulationIndex;
- }
- }
- });
- /**
- * Harmonicity is the frequency ratio between the carrier and the modulator oscillators.
- * A harmonicity of 1 gives both oscillators the same frequency.
- * Harmonicity = 2 means a change of an octave. See Tone.AMOscillator or Tone.FMOscillator
- * for more info.
- * @memberOf Tone.OmniOscillator#
- * @signal
- * @type {Positive}
- * @name harmonicity
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'harmonicity', {
- get: function () {
- if (this._sourceType === OmniOscType.FM || this._sourceType === OmniOscType.AM) {
- return this._oscillator.harmonicity;
- }
- }
- });
- /**
- * The modulationFrequency Signal of the oscillator
- * (only if the oscillator type is set to pwm). See
- * Tone.PWMOscillator for more info.
- * @memberOf Tone.OmniOscillator#
- * @type {Frequency}
- * @signal
- * @name modulationFrequency
- * @example
- * var omniOsc = new Tone.OmniOscillator(440, "pwm");
- * //can access the modulationFrequency attribute only if type === "pwm"
- * omniOsc.modulationFrequency.value = 0.2;
- */
- Object.defineProperty(Tone.OmniOscillator.prototype, 'modulationFrequency', {
- get: function () {
- if (this._sourceType === OmniOscType.PWM) {
- return this._oscillator.modulationFrequency;
- }
- }
- });
- /**
- * Clean up.
- * @return {Tone.OmniOscillator} this
- */
- Tone.OmniOscillator.prototype.dispose = function () {
- Tone.Source.prototype.dispose.call(this);
- this._writable([
- 'frequency',
- 'detune'
- ]);
- this.detune.dispose();
- this.detune = null;
- this.frequency.dispose();
- this.frequency = null;
- this._oscillator.dispose();
- this._oscillator = null;
- this._sourceType = null;
- return this;
- };
- return Tone.OmniOscillator;
- });
- Module(function (Tone) {
-
- /**
- * @class Base-class for all instruments
- *
- * @constructor
- * @extends {Tone.AudioNode}
- */
- Tone.Instrument = function (options) {
- //get the defaults
- options = Tone.defaultArg(options, Tone.Instrument.defaults);
- Tone.AudioNode.call(this);
- /**
- * The output and volume triming node
- * @type {Tone.Volume}
- * @private
- */
- this._volume = this.output = new Tone.Volume(options.volume);
- /**
- * The volume of the output in decibels.
- * @type {Decibels}
- * @signal
- * @example
- * source.volume.value = -6;
- */
- this.volume = this._volume.volume;
- this._readOnly('volume');
- };
- Tone.extend(Tone.Instrument, Tone.AudioNode);
- /**
- * the default attributes
- * @type {object}
- */
- Tone.Instrument.defaults = {
- /** the volume of the output in decibels */
- 'volume': 0
- };
- /**
- * @abstract
- * @param {string|number} note the note to trigger
- * @param {Time} [time=now] the time to trigger the ntoe
- * @param {number} [velocity=1] the velocity to trigger the note
- */
- Tone.Instrument.prototype.triggerAttack = Tone.noOp;
- /**
- * @abstract
- * @param {Time} [time=now] when to trigger the release
- */
- Tone.Instrument.prototype.triggerRelease = Tone.noOp;
- /**
- * Trigger the attack and then the release after the duration.
- * @param {Frequency} note The note to trigger.
- * @param {Time} duration How long the note should be held for before
- * triggering the release. This value must be greater than 0.
- * @param {Time} [time=now] When the note should be triggered.
- * @param {NormalRange} [velocity=1] The velocity the note should be triggered at.
- * @returns {Tone.Instrument} this
- * @example
- * //trigger "C4" for the duration of an 8th note
- * synth.triggerAttackRelease("C4", "8n");
- */
- Tone.Instrument.prototype.triggerAttackRelease = function (note, duration, time, velocity) {
- time = this.toSeconds(time);
- duration = this.toSeconds(duration);
- this.triggerAttack(note, time, velocity);
- this.triggerRelease(time + duration);
- return this;
- };
- /**
- * clean up
- * @returns {Tone.Instrument} this
- */
- Tone.Instrument.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this._volume.dispose();
- this._volume = null;
- this._writable(['volume']);
- this.volume = null;
- return this;
- };
- return Tone.Instrument;
- });
- Module(function (Tone) {
-
- /**
- * @class This is an abstract base class for other monophonic instruments to
- * extend. IMPORTANT: It does not make any sound on its own and
- * shouldn't be directly instantiated.
- *
- * @constructor
- * @abstract
- * @extends {Tone.Instrument}
- */
- Tone.Monophonic = function (options) {
- //get the defaults
- options = Tone.defaultArg(options, Tone.Monophonic.defaults);
- Tone.Instrument.call(this, options);
- /**
- * The glide time between notes.
- * @type {Time}
- */
- this.portamento = options.portamento;
- };
- Tone.extend(Tone.Monophonic, Tone.Instrument);
- /**
- * @static
- * @const
- * @type {Object}
- */
- Tone.Monophonic.defaults = { 'portamento': 0 };
- /**
- * Trigger the attack of the note optionally with a given velocity.
- *
- *
- * @param {Frequency} note The note to trigger.
- * @param {Time} [time=now] When the note should start.
- * @param {number} [velocity=1] velocity The velocity scaler
- * determines how "loud" the note
- * will be triggered.
- * @returns {Tone.Monophonic} this
- * @example
- * synth.triggerAttack("C4");
- * @example
- * //trigger the note a half second from now at half velocity
- * synth.triggerAttack("C4", "+0.5", 0.5);
- */
- Tone.Monophonic.prototype.triggerAttack = function (note, time, velocity) {
- time = this.toSeconds(time);
- this._triggerEnvelopeAttack(time, velocity);
- this.setNote(note, time);
- return this;
- };
- /**
- * Trigger the release portion of the envelope
- * @param {Time} [time=now] If no time is given, the release happens immediatly
- * @returns {Tone.Monophonic} this
- * @example
- * synth.triggerRelease();
- */
- Tone.Monophonic.prototype.triggerRelease = function (time) {
- time = this.toSeconds(time);
- this._triggerEnvelopeRelease(time);
- return this;
- };
- /**
- * override this method with the actual method
- * @abstract
- * @private
- */
- Tone.Monophonic.prototype._triggerEnvelopeAttack = function () {
- };
- /**
- * override this method with the actual method
- * @abstract
- * @private
- */
- Tone.Monophonic.prototype._triggerEnvelopeRelease = function () {
- };
- /**
- * Set the note at the given time. If no time is given, the note
- * will set immediately.
- * @param {Frequency} note The note to change to.
- * @param {Time} [time=now] The time when the note should be set.
- * @returns {Tone.Monophonic} this
- * @example
- * //change to F#6 in one quarter note from now.
- * synth.setNote("F#6", "+4n");
- * @example
- * //change to Bb4 right now
- * synth.setNote("Bb4");
- */
- Tone.Monophonic.prototype.setNote = function (note, time) {
- time = this.toSeconds(time);
- if (this.portamento > 0) {
- var currentNote = this.frequency.value;
- this.frequency.setValueAtTime(currentNote, time);
- var portTime = this.toSeconds(this.portamento);
- this.frequency.exponentialRampToValueAtTime(note, time + portTime);
- } else {
- this.frequency.setValueAtTime(note, time);
- }
- return this;
- };
- return Tone.Monophonic;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Synth is composed simply of a Tone.OmniOscillator
- * routed through a Tone.AmplitudeEnvelope.
- * note * .octaves and ramps to
- * note over the duration of .pitchDecay.
- *
- * @constructor
- * @extends {Tone.Instrument}
- * @param {Object} [options] the options available for the synth
- * see defaults below
- * @example
- * var synth = new Tone.MembraneSynth().toMaster();
- * synth.triggerAttackRelease("C2", "8n");
- */
- Tone.MembraneSynth = function (options) {
- options = Tone.defaultArg(options, Tone.MembraneSynth.defaults);
- Tone.Instrument.call(this, options);
- /**
- * The oscillator.
- * @type {Tone.OmniOscillator}
- */
- this.oscillator = new Tone.OmniOscillator(options.oscillator).start();
- /**
- * The amplitude envelope.
- * @type {Tone.AmplitudeEnvelope}
- */
- this.envelope = new Tone.AmplitudeEnvelope(options.envelope);
- /**
- * The number of octaves the pitch envelope ramps.
- * @type {Positive}
- */
- this.octaves = options.octaves;
- /**
- * The amount of time the frequency envelope takes.
- * @type {Time}
- */
- this.pitchDecay = options.pitchDecay;
- this.oscillator.chain(this.envelope, this.output);
- this._readOnly([
- 'oscillator',
- 'envelope'
- ]);
- };
- Tone.extend(Tone.MembraneSynth, Tone.Instrument);
- /**
- * @static
- * @type {Object}
- */
- Tone.MembraneSynth.defaults = {
- 'pitchDecay': 0.05,
- 'octaves': 10,
- 'oscillator': { 'type': 'sine' },
- 'envelope': {
- 'attack': 0.001,
- 'decay': 0.4,
- 'sustain': 0.01,
- 'release': 1.4,
- 'attackCurve': 'exponential'
- }
- };
- /**
- * Trigger the note at the given time with the given velocity.
- *
- * @param {Frequency} note the note
- * @param {Time} [time=now] the time, if not given is now
- * @param {number} [velocity=1] velocity defaults to 1
- * @returns {Tone.MembraneSynth} this
- * @example
- * kick.triggerAttack(60);
- */
- Tone.MembraneSynth.prototype.triggerAttack = function (note, time, velocity) {
- time = this.toSeconds(time);
- note = this.toFrequency(note);
- var maxNote = note * this.octaves;
- this.oscillator.frequency.setValueAtTime(maxNote, time);
- this.oscillator.frequency.exponentialRampToValueAtTime(note, time + this.toSeconds(this.pitchDecay));
- this.envelope.triggerAttack(time, velocity);
- return this;
- };
- /**
- * Trigger the release portion of the note.
- *
- * @param {Time} [time=now] the time the note will release
- * @returns {Tone.MembraneSynth} this
- */
- Tone.MembraneSynth.prototype.triggerRelease = function (time) {
- this.envelope.triggerRelease(time);
- return this;
- };
- /**
- * Clean up.
- * @returns {Tone.MembraneSynth} this
- */
- Tone.MembraneSynth.prototype.dispose = function () {
- Tone.Instrument.prototype.dispose.call(this);
- this._writable([
- 'oscillator',
- 'envelope'
- ]);
- this.oscillator.dispose();
- this.oscillator = null;
- this.envelope.dispose();
- this.envelope = null;
- return this;
- };
- return Tone.MembraneSynth;
- });
- Module(function (Tone) {
- /**
- * Inharmonic ratio of frequencies based on the Roland TR-808
- * Taken from https://ccrma.stanford.edu/papers/tr-808-cymbal-physically-informed-circuit-bendable-digital-model
- * @private
- * @static
- * @type {Array}
- */
- var inharmRatios = [
- 1,
- 1.483,
- 1.932,
- 2.546,
- 2.63,
- 3.897
- ];
- /**
- * @class A highly inharmonic and spectrally complex source with a highpass filter
- * and amplitude envelope which is good for making metalophone sounds. Based
- * on CymbalSynth by [@polyrhythmatic](https://github.com/polyrhythmatic).
- * Inspiration from [Sound on Sound](https://web.archive.org/web/20160610143924/https://www.soundonsound.com/sos/jul02/articles/synthsecrets0702.asp).
- *
- * @constructor
- * @extends {Tone.Instrument}
- * @param {Object} [options] The options availble for the synth
- * see defaults below
- */
- Tone.MetalSynth = function (options) {
- options = Tone.defaultArg(options, Tone.MetalSynth.defaults);
- Tone.Instrument.call(this, options);
- /**
- * The frequency of the cymbal
- * @type {Frequency}
- * @signal
- */
- this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
- /**
- * The array of FMOscillators
- * @type {Array}
- * @private
- */
- this._oscillators = [];
- /**
- * The frequency multipliers
- * @type {Array}
- * @private
- */
- this._freqMultipliers = [];
- /**
- * The amplitude for the body
- * @type {Tone.Gain}
- * @private
- */
- this._amplitue = new Tone.Gain(0).connect(this.output);
- /**
- * highpass the output
- * @type {Tone.Filter}
- * @private
- */
- this._highpass = new Tone.Filter({
- 'type': 'highpass',
- 'Q': -3.0102999566398125
- }).connect(this._amplitue);
- /**
- * The number of octaves the highpass
- * filter frequency ramps
- * @type {Number}
- * @private
- */
- this._octaves = options.octaves;
- /**
- * Scale the body envelope
- * for the bandpass
- * @type {Tone.Scale}
- * @private
- */
- this._filterFreqScaler = new Tone.Scale(options.resonance, 7000);
- /**
- * The envelope which is connected both to the
- * amplitude and highpass filter's cutoff frequency
- * @type {Tone.Envelope}
- */
- this.envelope = new Tone.Envelope({
- 'attack': options.envelope.attack,
- 'attackCurve': 'linear',
- 'decay': options.envelope.decay,
- 'sustain': 0,
- 'release': options.envelope.release
- }).chain(this._filterFreqScaler, this._highpass.frequency);
- this.envelope.connect(this._amplitue.gain);
- for (var i = 0; i < inharmRatios.length; i++) {
- var osc = new Tone.FMOscillator({
- 'type': 'square',
- 'modulationType': 'square',
- 'harmonicity': options.harmonicity,
- 'modulationIndex': options.modulationIndex
- });
- osc.connect(this._highpass).start();
- this._oscillators[i] = osc;
- var mult = new Tone.Multiply(inharmRatios[i]);
- this._freqMultipliers[i] = mult;
- this.frequency.chain(mult, osc.frequency);
- }
- //set the octaves
- this.octaves = options.octaves;
- };
- Tone.extend(Tone.MetalSynth, Tone.Instrument);
- /**
- * default values
- * @static
- * @const
- * @type {Object}
- */
- Tone.MetalSynth.defaults = {
- 'frequency': 200,
- 'envelope': {
- 'attack': 0.001,
- 'decay': 1.4,
- 'release': 0.2
- },
- 'harmonicity': 5.1,
- 'modulationIndex': 32,
- 'resonance': 4000,
- 'octaves': 1.5
- };
- /**
- * Trigger the attack.
- * @param {Time} time When the attack should be triggered.
- * @param {NormalRange} [velocity=1] The velocity that the envelope should be triggered at.
- * @return {Tone.MetalSynth} this
- */
- Tone.MetalSynth.prototype.triggerAttack = function (time, vel) {
- time = this.toSeconds(time);
- vel = Tone.defaultArg(vel, 1);
- this.envelope.triggerAttack(time, vel);
- return this;
- };
- /**
- * Trigger the release of the envelope.
- * @param {Time} time When the release should be triggered.
- * @return {Tone.MetalSynth} this
- */
- Tone.MetalSynth.prototype.triggerRelease = function (time) {
- time = this.toSeconds(time);
- this.envelope.triggerRelease(time);
- return this;
- };
- /**
- * Trigger the attack and release of the envelope after the given
- * duration.
- * @param {Time} duration The duration before triggering the release
- * @param {Time} time When the attack should be triggered.
- * @param {NormalRange} [velocity=1] The velocity that the envelope should be triggered at.
- * @return {Tone.MetalSynth} this
- */
- Tone.MetalSynth.prototype.triggerAttackRelease = function (duration, time, velocity) {
- time = this.toSeconds(time);
- duration = this.toSeconds(duration);
- this.triggerAttack(time, velocity);
- this.triggerRelease(time + duration);
- return this;
- };
- /**
- * The modulationIndex of the oscillators which make up the source.
- * see Tone.FMOscillator.modulationIndex
- * @memberOf Tone.MetalSynth#
- * @type {Positive}
- * @name modulationIndex
- */
- Object.defineProperty(Tone.MetalSynth.prototype, 'modulationIndex', {
- get: function () {
- return this._oscillators[0].modulationIndex.value;
- },
- set: function (val) {
- for (var i = 0; i < this._oscillators.length; i++) {
- this._oscillators[i].modulationIndex.value = val;
- }
- }
- });
- /**
- * The harmonicity of the oscillators which make up the source.
- * see Tone.FMOscillator.harmonicity
- * @memberOf Tone.MetalSynth#
- * @type {Positive}
- * @name harmonicity
- */
- Object.defineProperty(Tone.MetalSynth.prototype, 'harmonicity', {
- get: function () {
- return this._oscillators[0].harmonicity.value;
- },
- set: function (val) {
- for (var i = 0; i < this._oscillators.length; i++) {
- this._oscillators[i].harmonicity.value = val;
- }
- }
- });
- /**
- * The frequency of the highpass filter attached to the envelope
- * @memberOf Tone.MetalSynth#
- * @type {Frequency}
- * @name resonance
- */
- Object.defineProperty(Tone.MetalSynth.prototype, 'resonance', {
- get: function () {
- return this._filterFreqScaler.min;
- },
- set: function (val) {
- this._filterFreqScaler.min = val;
- this.octaves = this._octaves;
- }
- });
- /**
- * The number of octaves above the "resonance" frequency
- * that the filter ramps during the attack/decay envelope
- * @memberOf Tone.MetalSynth#
- * @type {Number}
- * @name octaves
- */
- Object.defineProperty(Tone.MetalSynth.prototype, 'octaves', {
- get: function () {
- return this._octaves;
- },
- set: function (octs) {
- this._octaves = octs;
- this._filterFreqScaler.max = this._filterFreqScaler.min * Math.pow(2, octs);
- }
- });
- /**
- * Clean up
- * @returns {Tone.MetalSynth} this
- */
- Tone.MetalSynth.prototype.dispose = function () {
- Tone.Instrument.prototype.dispose.call(this);
- for (var i = 0; i < this._oscillators.length; i++) {
- this._oscillators[i].dispose();
- this._freqMultipliers[i].dispose();
- }
- this._oscillators = null;
- this._freqMultipliers = null;
- this.frequency.dispose();
- this.frequency = null;
- this._filterFreqScaler.dispose();
- this._filterFreqScaler = null;
- this._amplitue.dispose();
- this._amplitue = null;
- this.envelope.dispose();
- this.envelope = null;
- this._highpass.dispose();
- this._highpass = null;
- };
- return Tone.MetalSynth;
- });
- Module(function (Tone) {
- /**
- * BufferSource polyfill
- */
- if (window.AudioBufferSourceNode && !AudioBufferSourceNode.prototype.start) {
- AudioBufferSourceNode.prototype.start = AudioBufferSourceNode.prototype.noteGrainOn;
- AudioBufferSourceNode.prototype.stop = AudioBufferSourceNode.prototype.noteOff;
- }
- /**
- * @class Wrapper around the native BufferSourceNode.
- * @extends {Tone.AudioNode}
- * @param {AudioBuffer|Tone.Buffer} buffer The buffer to play
- * @param {Function} onload The callback to invoke when the
- * buffer is done playing.
- */
- Tone.BufferSource = function () {
- var options = Tone.defaults(arguments, [
- 'buffer',
- 'onload'
- ], Tone.BufferSource);
- Tone.AudioNode.call(this);
- /**
- * The callback to invoke after the
- * buffer source is done playing.
- * @type {Function}
- */
- this.onended = options.onended;
- /**
- * The time that the buffer was started.
- * @type {Number}
- * @private
- */
- this._startTime = -1;
- /**
- * The time that the buffer is scheduled to stop.
- * @type {Number}
- * @private
- */
- this._stopTime = -1;
- /**
- * The gain node which envelopes the BufferSource
- * @type {Tone.Gain}
- * @private
- */
- this._gainNode = this.output = new Tone.Gain();
- /**
- * The buffer source
- * @type {AudioBufferSourceNode}
- * @private
- */
- this._source = this.context.createBufferSource();
- this._source.connect(this._gainNode);
- /**
- * The private buffer instance
- * @type {Tone.Buffer}
- * @private
- */
- this._buffer = new Tone.Buffer(options.buffer, options.onload);
- /**
- * The playbackRate of the buffer
- * @type {Positive}
- * @signal
- */
- this.playbackRate = new Tone.Param(this._source.playbackRate, Tone.Type.Positive);
- /**
- * The fadeIn time of the amplitude envelope.
- * @type {Time}
- */
- this.fadeIn = options.fadeIn;
- /**
- * The fadeOut time of the amplitude envelope.
- * @type {Time}
- */
- this.fadeOut = options.fadeOut;
- /**
- * The curve applied to the fades, either "linear" or "exponential"
- * @type {String}
- */
- this.curve = options.curve;
- /**
- * The value that the buffer ramps to
- * @type {Gain}
- * @private
- */
- this._gain = 1;
- /**
- * The onended timeout
- * @type {Number}
- * @private
- */
- this._onendedTimeout = -1;
- //set some values initially
- this.loop = options.loop;
- this.loopStart = options.loopStart;
- this.loopEnd = options.loopEnd;
- this.playbackRate.value = options.playbackRate;
- };
- Tone.extend(Tone.BufferSource, Tone.AudioNode);
- /**
- * The defaults
- * @const
- * @type {Object}
- */
- Tone.BufferSource.defaults = {
- 'onended': Tone.noOp,
- 'onload': Tone.noOp,
- 'loop': false,
- 'loopStart': 0,
- 'loopEnd': 0,
- 'fadeIn': 0,
- 'fadeOut': 0,
- 'curve': 'linear',
- 'playbackRate': 1
- };
- /**
- * Returns the playback state of the source, either "started" or "stopped".
- * @type {Tone.State}
- * @readOnly
- * @memberOf Tone.BufferSource#
- * @name state
- */
- Object.defineProperty(Tone.BufferSource.prototype, 'state', {
- get: function () {
- var now = this.now();
- if (this._startTime !== -1 && now >= this._startTime && now < this._stopTime) {
- return Tone.State.Started;
- } else {
- return Tone.State.Stopped;
- }
- }
- });
- /**
- * Start the buffer
- * @param {Time} [startTime=now] When the player should start.
- * @param {Time} [offset=0] The offset from the beginning of the sample
- * to start at.
- * @param {Time=} duration How long the sample should play. If no duration
- * is given, it will default to the full length
- * of the sample (minus any offset)
- * @param {Gain} [gain=1] The gain to play the buffer back at.
- * @param {Time=} fadeInTime The optional fadeIn ramp time.
- * @return {Tone.BufferSource} this
- */
- Tone.BufferSource.prototype.start = function (time, offset, duration, gain, fadeInTime) {
- if (this._startTime !== -1) {
- throw new Error('Tone.BufferSource can only be started once.');
- }
- if (this.buffer.loaded) {
- time = this.toSeconds(time);
- //if it's a loop the default offset is the loopstart point
- if (this.loop) {
- offset = Tone.defaultArg(offset, this.loopStart);
- } else {
- //otherwise the default offset is 0
- offset = Tone.defaultArg(offset, 0);
- }
- offset = this.toSeconds(offset);
- gain = Tone.defaultArg(gain, 1);
- this._gain = gain;
- fadeInTime = this.toSeconds(Tone.defaultArg(fadeInTime, this.fadeIn));
- this.fadeIn = fadeInTime;
- if (fadeInTime > 0) {
- this._gainNode.gain.setValueAtTime(0, time);
- if (this.curve === 'linear') {
- this._gainNode.gain.linearRampToValueAtTime(this._gain, time + fadeInTime);
- } else {
- this._gainNode.gain.setTargetAtTime(this._gain, time, this._gainNode.gain.getTimeConstant(fadeInTime));
- }
- } else {
- this._gainNode.gain.setValueAtTime(gain, time);
- }
- this._startTime = time;
- var computedDur = this.toSeconds(Tone.defaultArg(duration, this.buffer.duration - offset));
- computedDur = Math.max(computedDur, 0);
- if (!this.loop || this.loop && !Tone.isUndef(duration)) {
- //clip the duration when not looping
- if (!this.loop) {
- computedDur = Math.min(computedDur, this.buffer.duration - offset);
- }
- this.stop(time + computedDur, this.fadeOut);
- }
- //start the buffer source
- if (this.loop) {
- //modify the offset if it's greater than the loop time
- var loopEnd = this.loopEnd || this.buffer.duration;
- var loopStart = this.loopStart;
- var loopDuration = loopEnd - loopStart;
- //move the offset back
- if (offset > loopEnd) {
- offset = (offset - loopStart) % loopDuration + loopStart;
- }
- }
- this._source.buffer = this.buffer.get();
- this._source.loopEnd = this.loopEnd || this.buffer.duration;
- Tone.isPast(time);
- this._source.start(time, offset);
- } else {
- throw new Error('Tone.BufferSource: buffer is either not set or not loaded.');
- }
- return this;
- };
- /**
- * Stop the buffer. Optionally add a ramp time to fade the
- * buffer out.
- * @param {Time=} time The time the buffer should stop.
- * @param {Time=} fadeOutTime How long the gain should fade out for
- * @return {Tone.BufferSource} this
- */
- Tone.BufferSource.prototype.stop = function (time, fadeOutTime) {
- if (this.buffer.loaded) {
- time = this.toSeconds(time);
- //if this is before the previous stop
- if (this._stopTime === -1 || this._stopTime > time) {
- //stop if it's schedule before the start time
- if (time <= this._startTime) {
- this._gainNode.gain.cancelScheduledValues(time);
- this._gainNode.gain.value = 0;
- return this;
- }
- time = Math.max(this._startTime + this.fadeIn + this.sampleTime, time);
- //cancel the previous curve
- this._gainNode.gain.cancelScheduledValues(time);
- this._stopTime = time;
- //the fadeOut time
- fadeOutTime = this.toSeconds(Tone.defaultArg(fadeOutTime, this.fadeOut));
- //set a new one
- var heldDuration = Math.min(time - this._startTime - this.fadeIn - this.sampleTime, this.buffer.duration);
- fadeOutTime = Math.min(heldDuration, fadeOutTime);
- var startFade = time - fadeOutTime;
- if (fadeOutTime > this.sampleTime) {
- this._gainNode.gain.setValueAtTime(this._gain, startFade);
- if (this.curve === 'linear') {
- this._gainNode.gain.linearRampToValueAtTime(0, time);
- } else {
- this._gainNode.gain.setTargetAtTime(0, startFade, this._gainNode.gain.getTimeConstant(fadeOutTime));
- }
- } else {
- this._gainNode.gain.setValueAtTime(0, time);
- }
- Tone.context.clearTimeout(this._onendedTimeout);
- this._onendedTimeout = Tone.context.setTimeout(this._onended.bind(this), this._stopTime - this.now());
- }
- } else {
- throw new Error('Tone.BufferSource: buffer is either not set or not loaded.');
- }
- return this;
- };
- /**
- * Internal callback when the buffer is ended.
- * Invokes `onended` and disposes the node.
- * @private
- */
- Tone.BufferSource.prototype._onended = function () {
- this.onended(this);
- };
- /**
- * If loop is true, the loop will start at this position.
- * @memberOf Tone.BufferSource#
- * @type {Time}
- * @name loopStart
- */
- Object.defineProperty(Tone.BufferSource.prototype, 'loopStart', {
- get: function () {
- return this._source.loopStart;
- },
- set: function (loopStart) {
- this._source.loopStart = this.toSeconds(loopStart);
- }
- });
- /**
- * If loop is true, the loop will end at this position.
- * @memberOf Tone.BufferSource#
- * @type {Time}
- * @name loopEnd
- */
- Object.defineProperty(Tone.BufferSource.prototype, 'loopEnd', {
- get: function () {
- return this._source.loopEnd;
- },
- set: function (loopEnd) {
- this._source.loopEnd = this.toSeconds(loopEnd);
- }
- });
- /**
- * The audio buffer belonging to the player.
- * @memberOf Tone.BufferSource#
- * @type {Tone.Buffer}
- * @name buffer
- */
- Object.defineProperty(Tone.BufferSource.prototype, 'buffer', {
- get: function () {
- return this._buffer;
- },
- set: function (buffer) {
- this._buffer.set(buffer);
- }
- });
- /**
- * If the buffer should loop once it's over.
- * @memberOf Tone.BufferSource#
- * @type {Boolean}
- * @name loop
- */
- Object.defineProperty(Tone.BufferSource.prototype, 'loop', {
- get: function () {
- return this._source.loop;
- },
- set: function (loop) {
- this._source.loop = loop;
- }
- });
- /**
- * Clean up.
- * @return {Tone.BufferSource} this
- */
- Tone.BufferSource.prototype.dispose = function () {
- Tone.AudioNode.prototype.dispose.call(this);
- this.onended = null;
- this._source.disconnect();
- this._source = null;
- this._gainNode.dispose();
- this._gainNode = null;
- this._buffer.dispose();
- this._buffer = null;
- this._startTime = -1;
- this.playbackRate = null;
- Tone.context.clearTimeout(this._onendedTimeout);
- return this;
- };
- return Tone.BufferSource;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.Noise is a noise generator. It uses looped noise buffers to save on performance.
- * Tone.Noise supports the noise types: "pink", "white", and "brown". Read more about
- * colors of noise on [Wikipedia](https://en.wikipedia.org/wiki/Colors_of_noise).
- *
- * @constructor
- * @extends {Tone.Source}
- * @param {string} type the noise type (white|pink|brown)
- * @example
- * //initialize the noise and start
- * var noise = new Tone.Noise("pink").start();
- *
- * //make an autofilter to shape the noise
- * var autoFilter = new Tone.AutoFilter({
- * "frequency" : "8m",
- * "min" : 800,
- * "max" : 15000
- * }).connect(Tone.Master);
- *
- * //connect the noise
- * noise.connect(autoFilter);
- * //start the autofilter LFO
- * autoFilter.start()
- */
- Tone.Noise = function () {
- var options = Tone.defaults(arguments, ['type'], Tone.Noise);
- Tone.Source.call(this, options);
- /**
- * @private
- * @type {AudioBufferSourceNode}
- */
- this._source = null;
- /**
- * the buffer
- * @private
- * @type {AudioBuffer}
- */
- this._type = options.type;
- /**
- * The playback rate of the noise. Affects
- * the "frequency" of the noise.
- * @type {Positive}
- * @signal
- */
- this._playbackRate = options.playbackRate;
- };
- Tone.extend(Tone.Noise, Tone.Source);
- /**
- * the default parameters
- *
- * @static
- * @const
- * @type {Object}
- */
- Tone.Noise.defaults = {
- 'type': 'white',
- 'playbackRate': 1
- };
- /**
- * The type of the noise. Can be "white", "brown", or "pink".
- * @memberOf Tone.Noise#
- * @type {string}
- * @name type
- * @example
- * noise.type = "white";
- */
- Object.defineProperty(Tone.Noise.prototype, 'type', {
- get: function () {
- return this._type;
- },
- set: function (type) {
- if (this._type !== type) {
- if (type in _noiseBuffers) {
- this._type = type;
- //if it's playing, stop and restart it
- if (this.state === Tone.State.Started) {
- var now = this.now();
- this._stop(now);
- this._start(now);
- }
- } else {
- throw new TypeError('Tone.Noise: invalid type: ' + type);
- }
- }
- }
- });
- /**
- * The playback rate of the noise. Affects
- * the "frequency" of the noise.
- * @type {Positive}
- * @signal
- */
- Object.defineProperty(Tone.Noise.prototype, 'playbackRate', {
- get: function () {
- return this._playbackRate;
- },
- set: function (rate) {
- this._playbackRate = rate;
- if (this._source) {
- this._source.playbackRate.value = rate;
- }
- }
- });
- /**
- * internal start method
- *
- * @param {Time} time
- * @private
- */
- Tone.Noise.prototype._start = function (time) {
- var buffer = _noiseBuffers[this._type];
- this._source = new Tone.BufferSource(buffer).connect(this.output);
- this._source.loop = true;
- this._source.playbackRate.value = this._playbackRate;
- this._source.start(this.toSeconds(time), Math.random() * (buffer.duration - 0.001));
- };
- /**
- * internal stop method
- *
- * @param {Time} time
- * @private
- */
- Tone.Noise.prototype._stop = function (time) {
- if (this._source) {
- this._source.stop(this.toSeconds(time));
- this._source = null;
- }
- };
- /**
- * Clean up.
- * @returns {Tone.Noise} this
- */
- Tone.Noise.prototype.dispose = function () {
- Tone.Source.prototype.dispose.call(this);
- if (this._source !== null) {
- this._source.disconnect();
- this._source = null;
- }
- this._buffer = null;
- return this;
- };
- ///////////////////////////////////////////////////////////////////////////
- // THE BUFFERS
- ///////////////////////////////////////////////////////////////////////////
- //Noise buffer stats
- var bufferLength = 44100 * 5;
- var channels = 2;
- /**
- * The noise arrays. Generated on initialization.
- * borrowed heavily from https://github.com/zacharydenton/noise.js
- * (c) 2013 Zach Denton (MIT)
- * @static
- * @private
- * @type {Array}
- */
- var _noiseArrays = {
- 'pink': function () {
- var buffer = [];
- for (var channelNum = 0; channelNum < channels; channelNum++) {
- var channel = new Float32Array(bufferLength);
- buffer[channelNum] = channel;
- var b0, b1, b2, b3, b4, b5, b6;
- b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0;
- for (var i = 0; i < bufferLength; i++) {
- var white = Math.random() * 2 - 1;
- b0 = 0.99886 * b0 + white * 0.0555179;
- b1 = 0.99332 * b1 + white * 0.0750759;
- b2 = 0.969 * b2 + white * 0.153852;
- b3 = 0.8665 * b3 + white * 0.3104856;
- b4 = 0.55 * b4 + white * 0.5329522;
- b5 = -0.7616 * b5 - white * 0.016898;
- 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;
- }(),
- 'brown': function () {
- var buffer = [];
- for (var channelNum = 0; channelNum < channels; channelNum++) {
- var channel = new Float32Array(bufferLength);
- buffer[channelNum] = channel;
- var lastOut = 0;
- for (var i = 0; i < 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;
- }(),
- 'white': function () {
- var buffer = [];
- for (var channelNum = 0; channelNum < channels; channelNum++) {
- var channel = new Float32Array(bufferLength);
- buffer[channelNum] = channel;
- for (var i = 0; i < bufferLength; i++) {
- channel[i] = Math.random() * 2 - 1;
- }
- }
- return buffer;
- }()
- };
- /**
- * static noise buffers
- * @static
- * @private
- * @type {Tone.Buffer}
- */
- var _noiseBuffers = {};
- //create the Tone.Buffers
- function createBuffers() {
- for (var type in _noiseArrays) {
- _noiseBuffers[type] = new Tone.Buffer().fromArray(_noiseArrays[type]);
- }
- }
- //create the noise buffers
- Tone.getContext(createBuffers);
- Tone.Context.on('init', createBuffers);
- return Tone.Noise;
- });
- Module(function (Tone) {
-
- /**
- * @class Tone.NoiseSynth is composed of a noise generator (Tone.Noise), one filter (Tone.Filter),
- * and two envelopes (Tone.Envelop). One envelope controls the amplitude
- * of the noise and the other is controls the cutoff frequency of the filter.
- *