diff options
Diffstat (limited to 'bundle.js')
| -rw-r--r-- | bundle.js | 23022 |
1 files changed, 3 insertions, 23019 deletions
@@ -1,23030 +1,14 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 4); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_RESULT__;(function(root, factory){ - - //UMD - if ( true ) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { - return factory(); - }.call(exports, __webpack_require__, exports, module), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } 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){function e(n){if(i[n])return i[n].exports;var s=i[n]={i:n,l:!1,exports:{}};return t[n].call(s.exports,s,s.exports,e),s.l=!0,s.exports}var i={};e.m=t,e.c=i,e.i=function(t){return t},e.d=function(t,i,n){e.o(t,i)||Object.defineProperty(t,i,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(i,"a",i),i},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=4)}([function(t,e,i){var n;!function(s,o){void 0!==(n=function(){return o()}.call(e,i,e,t))&&(t.exports=n)}(0,function(){"use strict";function t(t){t(e)}var e;/** * 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. It provides - * a lot of methods and functionality to all classes that extend - * it. - * - * @constructor - * @alias Tone - * @param {number} [inputs=1] the number of input nodes - * @param {number} [outputs=1] the number of output nodes - */ - var Tone = function (inputs, outputs) { - /** - * the input node(s) - * @type {GainNode|Array} - */ - if (this.isUndef(inputs) || inputs === 1) { - this.input = this.context.createGain(); - } else if (inputs > 1) { - this.input = new Array(inputs); - } - /** - * the output node(s) - * @type {GainNode|Array} - */ - if (this.isUndef(outputs) || outputs === 1) { - this.output = this.context.createGain(); - } else if (outputs > 1) { - this.output = new Array(inputs); - } - }; - /** - * 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 - * @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 (this.isObject(params)) { - rampTime = value; - } else if (this.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 (this.isUndef(param)) { - continue; - } - if (Tone.Signal && param instanceof Tone.Signal || Tone.Param && param instanceof Tone.Param) { - if (param.value !== value) { - if (this.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. - * @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 (this.isUndef(params)) { - params = this._collectDefaults(this.constructor); - } else if (this.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 (this.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 (!this.isFunction(param) && !this.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 (!this.isUndef(constr.defaults)) { - ret = Object.keys(constr.defaults); - } - if (!this.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; - }; - /** - * @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 (this.isFunction(Tone[className]) && isLetter && sameConstructor) { - return className; - } - } - return 'Tone'; - }; - /////////////////////////////////////////////////////////////////////////// - // CLASS VARS - /////////////////////////////////////////////////////////////////////////// - /** - * The number of inputs feeding into the AudioNode. - * For source nodes, this will be 0. - * @memberOf Tone# - * @name numberOfInputs - * @readOnly - */ - Object.defineProperty(Tone.prototype, 'numberOfInputs', { - get: function () { - if (this.input) { - if (this.isArray(this.input)) { - return this.input.length; - } else { - return 1; - } - } else { - return 0; - } - } - }); - /** - * The number of outputs coming out of the AudioNode. - * For source nodes, this will be 0. - * @memberOf Tone# - * @name numberOfInputs - * @readOnly - */ - Object.defineProperty(Tone.prototype, 'numberOfOutputs', { - get: function () { - if (this.output) { - if (this.isArray(this.output)) { - return this.output.length; - } else { - return 1; - } - } else { - return 0; - } - } - }); - /////////////////////////////////////////////////////////////////////////// - // CONNECTIONS - /////////////////////////////////////////////////////////////////////////// - /** - * disconnect and dispose - * @returns {Tone} this - */ - Tone.prototype.dispose = function () { - if (!this.isUndef(this.input)) { - if (this.input instanceof AudioNode) { - this.input.disconnect(); - } - this.input = null; - } - if (!this.isUndef(this.output)) { - if (this.output instanceof AudioNode) { - this.output.disconnect(); - } - this.output = null; - } - return this; - }; - /** - * 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} this - */ - Tone.prototype.connect = function (unit, outputNum, inputNum) { - if (Array.isArray(this.output)) { - outputNum = this.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} this - */ - Tone.prototype.disconnect = function (destination, outputNum, inputNum) { - if (this.isArray(this.output)) { - if (this.isNumber(destination)) { - this.output[destination].disconnect(); - } else { - outputNum = this.defaultArg(outputNum, 0); - this.output[outputNum].disconnect(destination, 0, inputNum); - } - } else { - this.output.disconnect.apply(this.output, arguments); - } - }; - /** - * connect together all of the arguments in series - * @param {...AudioParam|Tone|AudioNode} nodes - * @returns {Tone} this - */ - Tone.prototype.connectSeries = function () { - if (arguments.length > 1) { - var currentUnit = arguments[0]; - for (var i = 1; 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 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} this - */ - Tone.prototype.chain = function () { - if (arguments.length > 0) { - 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} this - */ - Tone.prototype.fan = function () { - if (arguments.length > 0) { - for (var i = 0; i < arguments.length; i++) { - this.connect(arguments[i]); - } - } - return this; - }; - //give native nodes chain and fan methods - AudioNode.prototype.chain = Tone.prototype.chain; - AudioNode.prototype.fan = Tone.prototype.fan; - /////////////////////////////////////////////////////////////////////////// - // UTILITIES / HELPERS / MATHS - /////////////////////////////////////////////////////////////////////////// - /** - * 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. - * <br><br> - * WARNING: if object is self referential, it will go into an an - * infinite recursive loop. - * - * @param {*} given - * @param {*} fallback - * @return {*} - */ - Tone.prototype.defaultArg = function (given, fallback) { - if (this.isObject(given) && this.isObject(fallback)) { - var ret = {}; - //make a deep copy of the given object - for (var givenProp in given) { - ret[givenProp] = this.defaultArg(fallback[givenProp], given[givenProp]); - } - for (var fallbackProp in fallback) { - ret[fallbackProp] = this.defaultArg(given[fallbackProp], fallback[fallbackProp]); - } - return ret; - } else { - return this.isUndef(given) ? fallback : given; - } - }; - /** - * returns the args as an options object with given arguments - * mapped to the names provided. - * - * if the args given is an array containing only one object, it is assumed - * that that's already the options object and will just return it. - * - * @param {Array} values the 'arguments' object of the function - * @param {Array} keys the names of the arguments as they - * should appear in the options object - * @param {Object=} defaults optional defaults to mixin to the returned - * options object - * @return {Object} the options object with the names mapped to the arguments - */ - Tone.prototype.optionsObject = function (values, keys, defaults) { - var options = {}; - if (values.length === 1 && this.isObject(values[0])) { - options = values[0]; - } else { - for (var i = 0; i < keys.length; i++) { - options[keys[i]] = values[i]; - } - } - if (!this.isUndef(defaults)) { - return this.defaultArg(options, defaults); - } else { - return options; - } - }; - /////////////////////////////////////////////////////////////////////////// - // TYPE CHECKING - /////////////////////////////////////////////////////////////////////////// - /** - * test if the arg is undefined - * @param {*} arg the argument to test - * @returns {boolean} true if the arg is undefined - * @function - */ - Tone.prototype.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 - * @function - */ - Tone.prototype.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 - */ - Tone.prototype.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. - */ - Tone.prototype.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 - */ - Tone.prototype.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 - */ - Tone.prototype.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 - */ - Tone.prototype.isString = function (arg) { - return typeof arg === 'string'; - }; - /** - * 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) - */ - Tone.prototype.equalPowerScale = function (percent) { - var piFactor = 0.5 * Math.PI; - return Math.sin(percent * piFactor); - }; - /** - * Convert decibels into gain. - * @param {Decibels} db - * @return {Number} - */ - Tone.prototype.dbToGain = function (db) { - return Math.pow(2, db / 6); - }; - /** - * Convert gain to decibels. - * @param {Number} gain (0-1) - * @return {Decibels} - */ - Tone.prototype.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 - * @example - * tone.intervalToFrequencyRatio(0); // 1 - * tone.intervalToFrequencyRatio(12); // 2 - * tone.intervalToFrequencyRatio(-12); // 0.5 - */ - Tone.prototype.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 - */ - Tone.prototype.now = function () { - return Tone.context.now(); - }; - /** - * Return the current time of the AudioContext clock. - * @return {Number} the currentTime from the AudioContext - * @static - */ - Tone.now = function () { - return Tone.context.now(); - }; - /////////////////////////////////////////////////////////////////////////// - // 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 - * - * @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.prototype.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|undefined} - */ - var audioContext; - /** - * 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 - if (Tone.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; - }; - /** - * The number of seconds of 1 processing block (128 samples) - * @type {Number} - * @name blockTime - * @memberOf Tone# - * @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# - * @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 - */ - 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; - } - }); - Tone.version = 'r10'; - // 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 Base class for all Signals. Used Internally. - * - * @constructor - * @extends {Tone} - */ - Tone.SignalBase = function () { - }; - Tone.extend(Tone.SignalBase); - /** - * 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 <code>connect</code>. - * - * @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.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) { - /** - * 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) || this.isUndef(mapping)) { - this._curve = new Float32Array(this.defaultArg(mapping, 1024)); - } else if (this.isFunction(mapping)) { - this._curve = new Float32Array(this.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.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 (!this.isUndef(units) || this.isNumber(val)) { - //default units - units = this.defaultArg(units, this._defaultUnits); - var method = this._primaryExpressions[units].method; - this._expr = method.bind(this, val); - } else if (this.isString(val)) { - this.set(val); - } else if (this.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 (!this.isUndef(token)) { - for (var opName in group) { - var op = group[opName]; - if (op.regexp.test(token.value)) { - if (!this.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 (this.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 (this.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 (!this.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 = this.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 - * Override the default value return when no arguments are passed in. - * The default value is 'now' - * @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) { - sixteenths = 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 * this.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 * this.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 + 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) { - - /** - * @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 () { - /** - * 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.prototype.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. - */ - 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; - } - }; - /** - * 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) { - /** - * 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 (context) { - Tone.Emitter.call(this); - if (!context) { - context = new window.AudioContext(); - } - this._context = context; - // extend all of the methods - for (var prop in this._context) { - this._defineProperty(this._context, prop); - } - /////////////////////////////////////////////////////////////////////// - // WORKER - /////////////////////////////////////////////////////////////////////// - /** - * The default latency hint - * @type {String} - * @private - */ - this._latencyHint = 'interactive'; - /** - * The amount of time events are scheduled - * into the future - * @type {Number} - * @private - */ - this._lookAhead = 0.1; - /** - * How often the update look runs - * @type {Number} - * @private - */ - this._updateInterval = this._lookAhead / 3; - /** - * A reference to the actual computed update interval - * @type {Number} - * @private - */ - this._computedUpdateInterval = 0; - /** - * The web worker which is used to update Tone.Clock - * @private - * @type {WebWorker} - */ - this._worker = this._createWorker(); - /** - * An object containing all of the constants AudioBufferSourceNodes - * @type {Object} - * @private - */ - this._constants = {}; - }; - Tone.extend(Tone.Context, Tone.Emitter); - Tone.Emitter.mixin(Tone.Context); - /** - * 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 (this.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; - }; - /** - * Generate a web worker - * @return {WebWorker} - * @private - */ - Tone.Context.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.addEventListener('message', function () { - // tick the clock - this.emit('tick'); - }.bind(this)); - //lag compensation - worker.addEventListener('message', function () { - var now = this.now(); - if (this.isNumber(this._lastUpdate)) { - var diff = now - this._lastUpdate; - this._computedUpdateInterval = Math.max(diff, this._computedUpdateInterval * 0.97); - } - this._lastUpdate = now; - }.bind(this)); - return worker; - }; - /** - * 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; - } - }; - /** - * This is the time that the clock is falling behind - * the scheduled update interval. The Context automatically - * adjusts for the lag and schedules further in advance. - * @type {Number} - * @memberOf Tone.Context - * @name lag - * @static - * @readOnly - */ - Object.defineProperty(Tone.Context.prototype, 'lag', { - get: function () { - var diff = this._computedUpdateInterval - this._updateInterval; - diff = Math.max(diff, 0); - return diff; - } - }); - /** - * The amount of time in advance that events are scheduled. - * The lookAhead will adjust slightly in response to the - * measured update time to try to avoid clicks. - * @type {Number} - * @memberOf Tone.Context - * @name lookAhead - * @static - */ - Object.defineProperty(Tone.Context.prototype, 'lookAhead', { - get: function () { - return this._lookAhead; - }, - set: function (lA) { - this._lookAhead = lA; - } - }); - /** - * 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 - * @static - */ - Object.defineProperty(Tone.Context.prototype, 'updateInterval', { - get: function () { - return this._updateInterval; - }, - set: function (interval) { - this._updateInterval = Math.max(interval, Tone.prototype.blockTime); - this._worker.postMessage(Math.max(interval * 1000, 1)); - } - }); - /** - * 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 - * @static - * @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 (this.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': - lookAhead = 0.01; - break; - } - } - this.lookAhead = lookAhead; - this.updateInterval = lookAhead / 3; - } - }); - /** - * Shim all connect/disconnect and some deprecated methods which are still in - * some older implementations. - * @private - */ - function shimConnect() { - var nativeConnect = AudioNode.prototype.connect; - var nativeDisconnect = AudioNode.prototype.disconnect; - //replace the old connect method - function toneConnect(B, outNum, inNum) { - if (B.input) { - if (Array.isArray(B.input)) { - if (Tone.prototype.isUndef(inNum)) { - inNum = 0; - } - 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 && Array.isArray(B.input)) { - if (Tone.prototype.isUndef(inNum)) { - inNum = 0; - } - this.disconnect(B.input[inNum], outNum, inNum); - } 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) { - shimConnect(); - Tone.context = new Tone.Context(); - } else { - console.warn('This browser does not support Tone.js'); - } - return Tone.Context; - }); - 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). - * - * <ul> - * <li>Numbers, which will be taken literally as the time (in seconds).</li> - * <li>Notation, ("4n", "8t") describes time in BPM and time signature relative values.</li> - * <li>TransportTime, ("4:3:2") will also provide tempo and time signature relative times - * in the form BARS:QUARTERS:SIXTEENTHS.</li> - * <li>Frequency, ("8hz") is converted to the length of the cycle in seconds.</li> - * <li>Now-Relative, ("+1") prefix any of the above with "+" and it will be interpreted as - * "the current time plus whatever expression follows".</li> - * <li>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.</li> - * <li>No Argument, for methods which accept time, no argument will be interpreted as - * "now" (i.e. the currentTime).</li> - * </ul> - * - * @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', - /** - * 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. - * <ul> - * <li>"4n" = quarter note</li> - * <li>"2m" = two measures</li> - * <li>"8t" = eighth-note triplet</li> - * </ul> - * @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|1m|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 (this.isNumber(time)) { - return time; - } else if (this.isUndef(time)) { - return this.now(); - } else if (this.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 (this.isNumber(freq)) { - return freq; - } else if (this.isString(freq) || this.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 (this.isNumber(time) || this.isString(time)) { - return new Tone.TransportTime(time).toTicks(); - } else if (this.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} - * @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 = this.optionsObject(arguments, [ - 'param', - 'units', - 'convert' - ], Tone.Param.defaults); - /** - * 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 (this.isObject(options.lfo)) { - this.value = options.lfo; - } else if (!this.isUndef(options.value)) { - this.value = options.value; - } - }; - Tone.extend(Tone.Param); - /** - * 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 (this.isObject(value)) { - //throw an error if the LFO needs to be included - if (this.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 || this.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 this.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 || this.isUndef(this.convert)) { - switch (this.units) { - case Tone.Type.Decibels: - return this.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) { - value = this._fromUnits(value); - time = this.toSeconds(time); - if (time <= this.now() + this.blockTime) { - this._param.value = value; - } else { - this._param.setValueAtTime(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 = this.defaultArg(now, this.now()); - var currentVal = this._param.value; - // exponentialRampToValueAt cannot ever ramp from or to 0 - // More info: https://bugzilla.mozilla.org/show_bug.cgi?id=1125600#c2 - if (currentVal === 0) { - currentVal = this._minOutput; - } - 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); - this._param.linearRampToValueAtTime(value, this.toSeconds(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); - this._param.exponentialRampToValueAtTime(value, this.toSeconds(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.exponentialRampToValue(2, 4); - */ - Tone.Param.prototype.exponentialRampToValue = 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.linearRampToValue(4, 3); - */ - Tone.Param.prototype.linearRampToValue = function (value, rampTime, startTime) { - startTime = this.toSeconds(startTime); - this.setRampPoint(startTime); - this.linearRampToValueAtTime(value, startTime + this.toSeconds(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) { - for (var i = 0; i < values.length; i++) { - values[i] = this._fromUnits(values[i]); - } - this._param.setValueCurveAtTime(values, this.toSeconds(startTime), this.toSeconds(duration)); - 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; - }; - /** - * 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 = this.defaultArg(rampTime, 0); - if (this.units === Tone.Type.Frequency || this.units === Tone.Type.BPM || this.units === Tone.Type.Decibels) { - this.exponentialRampToValue(value, rampTime, startTime); - } else { - this.linearRampToValue(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.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 = this.optionsObject(arguments, [ - 'gain', - 'units' - ], Tone.Gain.defaults); - /** - * The GainNode - * @type {GainNode} - * @private - */ - this.input = this.output = this._gainNode = this.context.createGain(); - /** - * The gain parameter of the gain node. - * @type {Tone.Param} - * @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); - /** - * The defaults - * @const - * @type {Object} - */ - Tone.Gain.defaults = { - 'gain': 1, - 'convert': true - }; - /** - * Clean up. - * @return {Tone.Gain} this - */ - Tone.Gain.prototype.dispose = function () { - Tone.Param.prototype.dispose.call(this); - this._gainNode.disconnect(); - this._gainNode = null; - this._writable('gain'); - this.gain.dispose(); - this.gain = null; - }; - //STATIC/////////////////////////////////////////////////////////////////// - /** - * Create input and outputs for this object. - * @param {Number} input The number of inputs - * @param {Number=} outputs The number of outputs - * @return {Tone} this - * @internal - */ - Tone.prototype.createInsOuts = function (inputs, outputs) { - if (inputs === 1) { - this.input = new Tone.Gain(); - } else if (inputs > 1) { - this.input = new Array(inputs); - } - if (outputs === 1) { - this.output = new Tone.Gain(); - } else if (outputs > 1) { - this.output = new Array(inputs); - } - }; - /////////////////////////////////////////////////////////////////////////// - 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 = this.optionsObject(arguments, [ - 'value', - 'units' - ], Tone.Signal.defaults); - /** - * The node where the constant signal value is scaled. - * @type {GainNode} - * @private - */ - this.output = this._gain = this.context.createGain(); - options.param = this._gain.gain; - Tone.Param.call(this, options); - /** - * The node where the value is set. - * @type {Tone.Param} - * @private - */ - this.input = this._param = this._gain.gain; - //connect the const output to the node output - this.context.getConstant(1).chain(this._gain); - }; - 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 <code>connect</code>. - * - * @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); - this._param = null; - this._gain.disconnect(); - this._gain = null; - return this; - }; - return Tone.Signal; - }); - 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 = this.optionsObject(arguments, ['memory'], Tone.Timeline.defaults); - /** - * 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 = []; - /** - * Flag if the tieline 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 (this.isUndef(event.time)) { - throw new Error('Tone.Timeline: events must have a time attribute'); - } - if (this._timeline.length) { - var index = this._search(event.time); - this._timeline.splice(index + 1, 0, event); - } else { - this._timeline.push(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. - * @returns {Object} The event object set after that time. - */ - Tone.Timeline.prototype.get = function (time) { - var index = this._search(time); - 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. - * @returns {Object} The event object after the given time - */ - Tone.Timeline.prototype.getAfter = function (time) { - var index = this._search(time); - 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. - * @returns {Object} The event object before the given time - */ - Tone.Timeline.prototype.getBefore = function (time) { - var len = this._timeline.length; - //if it's after the last item, return the last item - if (len > 0 && this._timeline[len - 1].time < time) { - return this._timeline[len - 1]; - } - var index = this._search(time); - 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) { - if (this._timeline.length) { - var index = this._search(time); - if (index >= 0) { - this._timeline = this._timeline.slice(index + 1); - } - } - return this; - }; - /** - * Does a binary serach 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 - * @return {Number} the index in the timeline array - * @private - */ - Tone.Timeline.prototype._search = function (time) { - var beginning = 0; - var len = this._timeline.length; - var end = len; - if (len > 0 && this._timeline[len - 1].time <= 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.time === 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.time === time) { - midPoint = i; - } - } - return midPoint; - } else if (event.time < time && nextEvent.time > time) { - return midPoint; - } else if (event.time > time) { - //search lower - end = midPoint; - } else if (event.time < time) { - //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 = this.defaultArg(lowerBound, 0); - upperBound = this.defaultArg(upperBound, this._timeline.length - 1); - for (var i = lowerBound; i <= upperBound; i++) { - callback(this._timeline[i]); - } - this._iterating = false; - if (this._toRemove.length > 0) { - for (var j = 0; j < this._toRemove.length; j++) { - var index = this._timeline.indexOf(this._toRemove[j]); - if (index !== -1) { - this._timeline.splice(index, 1); - } - } - this._toRemove = []; - } - }; - /** - * 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(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; - }; - return Tone.Timeline; - }); - 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.Param} - * @param {Number=} value The initial value of the signal - * @param {String=} units The conversion units of the signal. - */ - Tone.TimelineSignal = function () { - var options = this.optionsObject(arguments, [ - 'value', - 'units' - ], Tone.Signal.defaults); - /** - * The scheduled events - * @type {Tone.Timeline} - * @private - */ - this._events = new Tone.Timeline(10); - //constructors - Tone.Signal.apply(this, options); - options.param = this._param; - Tone.Param.call(this, options); - /** - * The initial scheduled value - * @type {Number} - * @private - */ - this._initial = this._fromUnits(this._param.value); - }; - Tone.extend(Tone.TimelineSignal, Tone.Param); - /** - * The event types of a schedulable signal. - * @enum {String} - * @private - */ - Tone.TimelineSignal.Type = { - Linear: 'linear', - Exponential: 'exponential', - Target: 'target', - Curve: 'curve', - 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) { - 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 = this.defaultArg(scaling, 1); - //copy the array - var floats = new Array(values.length); - for (var i = 0; i < floats.length; i++) { - floats[i] = this._fromUnits(values[i]) * scaling; - } - startTime = this.toSeconds(startTime); - duration = this.toSeconds(duration); - this._events.add({ - 'type': Tone.TimelineSignal.Type.Curve, - 'value': floats, - 'time': startTime, - 'duration': duration - }); - //set the first value - this._param.setValueAtTime(floats[0], startTime); - //schedule a lienar ramp for each of the segments - for (var j = 1; j < floats.length; j++) { - var segmentTime = startTime + j / (floats.length - 1) * duration; - this._param.linearRampToValueAtTime(floats[j], segmentTime); - } - 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; - }; - /** - * 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 if (before && before.type === Tone.TimelineSignal.Type.Curve && before.time + before.duration > time) { - //if the curve is still playing - //cancel the curve - this.cancelScheduledValues(time); - this.linearRampToValueAtTime(val, time); - } 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 previouVal; - if (previous === null) { - previouVal = this._initial; - } else { - previouVal = previous.value; - } - value = this._exponentialApproach(before.time, previouVal, before.value, before.constant, time); - } else if (before.type === Tone.TimelineSignal.Type.Curve) { - value = this._curveInterpolate(before.time, before.value, before.duration, 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 <code>connect</code>. - * - * @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)); - }; - /** - * Calculates the the value along the curve produced by setValueCurveAtTime - * @private - */ - Tone.TimelineSignal.prototype._curveInterpolate = function (start, curve, duration, time) { - var len = curve.length; - // If time is after duration, return the last curve value - if (time >= start + duration) { - return curve[len - 1]; - } else if (time <= start) { - return curve[0]; - } else { - var progress = (time - start) / duration; - var lowerIndex = Math.floor((len - 1) * progress); - var upperIndex = Math.ceil((len - 1) * progress); - var lowerVal = curve[lowerIndex]; - var upperVal = curve[upperIndex]; - if (upperIndex === lowerIndex) { - return lowerVal; - } else { - return this._linearInterpolate(lowerIndex, lowerVal, upperIndex, upperVal, progress * (len - 1)); - } - } - }; - /** - * Clean up. - * @return {Tone.TimelineSignal} this - */ - Tone.TimelineSignal.prototype.dispose = function () { - Tone.Signal.prototype.dispose.call(this); - Tone.Param.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) { - /** - * the exponent - * @private - * @type {number} - */ - this._exp = this.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.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. - * <img src="https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg"> - * - * @constructor - * @extends {Tone} - * @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 = this.optionsObject(arguments, [ - 'attack', - 'decay', - 'sustain', - 'release' - ], Tone.Envelope.defaults); - /** - * 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); - /** - * 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: - * <ul> - * <li>linear</li> - * <li>exponential</li> - * <li>sine</li> - * <li>cosine</li> - * <li>bounce</li> - * <li>ripple</li> - * <li>step</li> - * </ul> - * Can also be an array which describes the curve. Values - * in the array are evenly subdivided and linearly - * interpolated over the duration of the attack. - * @memberOf Tone.Envelope# - * @type {String|Array} - * @name attackCurve - * @example - * env.attackCurve = "linear"; - * @example - * //can also be an array - * env.attackCurve = [0, 0.2, 0.3, 0.4, 1] - */ - Object.defineProperty(Tone.Envelope.prototype, 'attackCurve', { - get: function () { - if (this.isString(this._attackCurve)) { - return this._attackCurve; - } else if (this.isArray(this._attackCurve)) { - //look up the name in the curves array - for (var type in Tone.Envelope.Type) { - if (Tone.Envelope.Type[type].In === this._attackCurve) { - return type; - } - } - //otherwise just return the array - return this._attackCurve; - } - }, - set: function (curve) { - //check if it's a valid type - if (Tone.Envelope.Type.hasOwnProperty(curve)) { - var curveDef = Tone.Envelope.Type[curve]; - if (this.isObject(curveDef)) { - this._attackCurve = curveDef.In; - } else { - this._attackCurve = curveDef; - } - } else if (this.isArray(curve)) { - this._attackCurve = curve; - } else { - throw new Error('Tone.Envelope: invalid curve: ' + curve); - } - } - }); - /** - * The shape of the release. See the attack curve types. - * @memberOf Tone.Envelope# - * @type {String|Array} - * @name releaseCurve - * @example - * env.releaseCurve = "linear"; - */ - Object.defineProperty(Tone.Envelope.prototype, 'releaseCurve', { - get: function () { - if (this.isString(this._releaseCurve)) { - return this._releaseCurve; - } else if (this.isArray(this._releaseCurve)) { - //look up the name in the curves array - for (var type in Tone.Envelope.Type) { - if (Tone.Envelope.Type[type].Out === this._releaseCurve) { - return type; - } - } - //otherwise just return the array - return this._releaseCurve; - } - }, - set: function (curve) { - //check if it's a valid type - if (Tone.Envelope.Type.hasOwnProperty(curve)) { - var curveDef = Tone.Envelope.Type[curve]; - if (this.isObject(curveDef)) { - this._releaseCurve = curveDef.Out; - } else { - this._releaseCurve = curveDef; - } - } else if (this.isArray(curve)) { - this._releaseCurve = curve; - } else { - throw new Error('Tone.Envelope: invalid curve: ' + curve); - } - } - }); - /** - * Trigger the attack/decay portion of the ADSR envelope. - * @param {Time} [time=now] When the attack should start. - * @param {NormalRange} [velocity=1] The velocity of the envelope scales the vales. - * number between 0-1 - * @returns {Tone.Envelope} this - * @example - * //trigger the attack 0.5 seconds from now with a velocity of 0.2 - * env.triggerAttack("+0.5", 0.2); - */ - Tone.Envelope.prototype.triggerAttack = function (time, velocity) { - time = this.toSeconds(time); - var originalAttack = this.toSeconds(this.attack); - var attack = originalAttack; - var decay = this.toSeconds(this.decay); - velocity = this.defaultArg(velocity, 1); - //check if it's not a complete attack - var currentValue = this.getValueAtTime(time); - if (currentValue > 0) { - //subtract the current value from the attack time - var attackRate = 1 / attack; - var remainingDistance = 1 - currentValue; - //the attack is now the remaining time - attack = remainingDistance / attackRate; - } - //attack - if (this._attackCurve === 'linear') { - this._sig.linearRampToValue(velocity, attack, time); - } else if (this._attackCurve === 'exponential') { - this._sig.exponentialRampToValue(velocity, attack, time); - } else if (attack > 0) { - this._sig.setRampPoint(time); - var curve = this._attackCurve; - //take only a portion of the curve - if (attack < originalAttack) { - var percentComplete = 1 - attack / originalAttack; - var sliceIndex = Math.floor(percentComplete * this._attackCurve.length); - curve = this._attackCurve.slice(sliceIndex); - //the first index is the current value - curve[0] = currentValue; - } - this._sig.setValueCurveAtTime(curve, time, attack, velocity); - } - //decay - this._sig.exponentialRampToValue(velocity * this.sustain, decay, attack + time); - return this; - }; - /** - * Triggers the release of the envelope. - * @param {Time} [time=now] When the release portion of the envelope should start. - * @returns {Tone.Envelope} this - * @example - * //trigger release immediately - * env.triggerRelease(); - */ - Tone.Envelope.prototype.triggerRelease = function (time) { - time = this.toSeconds(time); - var currentValue = this.getValueAtTime(time); - if (currentValue > 0) { - var release = this.toSeconds(this.release); - if (this._releaseCurve === 'linear') { - this._sig.linearRampToValue(0, release, time); - } else if (this._releaseCurve === 'exponential') { - this._sig.exponentialRampToValue(0, release, time); - } else { - var curve = this._releaseCurve; - if (this.isArray(curve)) { - this._sig.setRampPoint(time); - this._sig.setValueCurveAtTime(curve, time, release, currentValue); - } - } - } - return this; - }; - /** - * 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.Envelope.prototype.getValueAtTime = function (time) { - return this._sig.getValueAtTime(time); - }; - /** - * triggerAttackRelease is shorthand for triggerAttack, then waiting - * some duration, then triggerRelease. - * @param {Time} duration The duration of the sustain. - * @param {Time} [time=now] When the attack should be triggered. - * @param {number} [velocity=1] The velocity of the envelope. - * @returns {Tone.Envelope} this - * @example - * //trigger the attack and then the release after 0.6 seconds. - * env.triggerAttackRelease(0.6); - */ - Tone.Envelope.prototype.triggerAttackRelease = function (duration, time, velocity) { - time = this.toSeconds(time); - this.triggerAttack(time, velocity); - this.triggerRelease(time + this.toSeconds(duration)); - return this; - }; - /** - * Cancels all scheduled envelope changes after the given time. - * @param {Time} after - * @returns {Tone.Envelope} this - */ - Tone.Envelope.prototype.cancel = function (after) { - this._sig.cancelScheduledValues(after); - return this; - }; - /** - * Borrows the connect method from Tone.Signal. - * @function - * @private - */ - Tone.Envelope.prototype.connect = Tone.Signal.prototype.connect; - /** - * Generate some complex envelope curves. - */ - (function _createCurves() { - var curveLen = 128; - var i, k; - //cosine curve - var cosineCurve = []; - for (i = 0; i < curveLen; i++) { - cosineCurve[i] = Math.sin(i / (curveLen - 1) * (Math.PI / 2)); - } - //ripple curve - var rippleCurve = []; - var rippleCurveFreq = 6.4; - for (i = 0; i < curveLen - 1; i++) { - k = i / (curveLen - 1); - var sineWave = Math.sin(k * (Math.PI * 2) * rippleCurveFreq - Math.PI / 2) + 1; - rippleCurve[i] = sineWave / 10 + k * 0.83; - } - rippleCurve[curveLen - 1] = 1; - //stairs curve - var stairsCurve = []; - var steps = 5; - for (i = 0; i < curveLen; i++) { - stairsCurve[i] = Math.ceil(i / (curveLen - 1) * steps) / steps; - } - //in-out easing curve - var sineCurve = []; - for (i = 0; i < curveLen; i++) { - k = i / (curveLen - 1); - sineCurve[i] = 0.5 * (1 - Math.cos(Math.PI * k)); - } - //a bounce curve - var bounceCurve = []; - for (i = 0; i < curveLen; i++) { - k = i / (curveLen - 1); - var freq = Math.pow(k, 3) * 4 + 0.2; - var val = Math.cos(freq * Math.PI * 2 * k); - bounceCurve[i] = Math.abs(val * (1 - k)); - } - /** - * Invert a value curve to make it work for the release - * @private - */ - function invertCurve(curve) { - var out = new Array(curve.length); - for (var j = 0; j < curve.length; j++) { - out[j] = 1 - curve[j]; - } - return out; - } - /** - * reverse the curve - * @private - */ - function reverseCurve(curve) { - return curve.slice(0).reverse(); - } - /** - * attack and release curve arrays - * @type {Object} - * @private - */ - Tone.Envelope.Type = { - 'linear': 'linear', - 'exponential': 'exponential', - 'bounce': { - In: invertCurve(bounceCurve), - Out: bounceCurve - }, - 'cosine': { - In: cosineCurve, - Out: reverseCurve(cosineCurve) - }, - 'step': { - In: stairsCurve, - Out: invertCurve(stairsCurve) - }, - 'ripple': { - In: rippleCurve, - Out: invertCurve(rippleCurve) - }, - 'sine': { - In: sineCurve, - Out: invertCurve(sineCurve) - } - }; - }()); - /** - * Disconnect and dispose. - * @returns {Tone.Envelope} this - */ - Tone.Envelope.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._sig.dispose(); - this._sig = null; - this._attackCurve = null; - this._releaseCurve = null; - return this; - }; - return Tone.Envelope; - }); - Module(function (Tone) { - - /** - * @class Tone.AmplitudeEnvelope is a Tone.Envelope connected to a gain node. - * Unlike Tone.Envelope, which outputs the envelope's value, Tone.AmplitudeEnvelope accepts - * an audio signal as the input and will apply the envelope to the amplitude - * of the signal. Read more about ADSR Envelopes on [Wikipedia](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope). - * - * @constructor - * @extends {Tone.Envelope} - * @param {Time|Object} [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 - * var ampEnv = new Tone.AmplitudeEnvelope({ - * "attack": 0.1, - * "decay": 0.2, - * "sustain": 1.0, - * "release": 0.8 - * }).toMaster(); - * //create an oscillator and connect it - * var osc = new Tone.Oscillator().connect(ampEnv).start(); - * //trigger the envelopes attack and release "8t" apart - * ampEnv.triggerAttackRelease("8t"); - */ - Tone.AmplitudeEnvelope = function () { - Tone.Envelope.apply(this, arguments); - /** - * the input node - * @type {GainNode} - * @private - */ - this.input = this.output = new Tone.Gain(); - this._sig.connect(this.output.gain); - }; - Tone.extend(Tone.AmplitudeEnvelope, Tone.Envelope); - /** - * Clean up - * @return {Tone.AmplitudeEnvelope} this - */ - Tone.AmplitudeEnvelope.prototype.dispose = function () { - this.input.dispose(); - this.input = null; - Tone.Envelope.prototype.dispose.call(this); - return this; - }; - return Tone.AmplitudeEnvelope; - }); - Module(function (Tone) { - - /** - * AnalyserNode.getFloatTimeDomainData polyfill - * @private - */ - if (window.AnalyserNode && !AnalyserNode.prototype.getFloatTimeDomainData) { - //referenced https://github.com/mohayonao/get-float-time-domain-data - AnalyserNode.prototype.getFloatTimeDomainData = function (array) { - var uint8 = new Uint8Array(array.length); - this.getByteTimeDomainData(uint8); - for (var i = 0; i < uint8.length; i++) { - array[i] = (uint8[i] - 128) / 128; - } - }; - } - /** - * @class Wrapper around the native Web Audio's - * [AnalyserNode](http://webaudio.github.io/web-audio-api/#idl-def-AnalyserNode). - * Extracts FFT or Waveform data from the incoming signal. - * @extends {Tone} - * @param {String=} type The return type of the analysis, either "fft", or "waveform". - * @param {Number=} size The size of the FFT. Value must be a power of - * two in the range 32 to 32768. - */ - Tone.Analyser = function () { - var options = this.optionsObject(arguments, [ - 'type', - 'size' - ], Tone.Analyser.defaults); - /** - * The analyser node. - * @private - * @type {AnalyserNode} - */ - this._analyser = this.input = this.output = this.context.createAnalyser(); - /** - * The analysis type - * @type {String} - * @private - */ - this._type = options.type; - /** - * The return type of the analysis - * @type {String} - * @private - */ - this._returnType = options.returnType; - /** - * The buffer that the FFT data is written to - * @type {TypedArray} - * @private - */ - this._buffer = null; - //set the values initially - this.size = options.size; - this.type = options.type; - this.returnType = options.returnType; - this.minDecibels = options.minDecibels; - this.maxDecibels = options.maxDecibels; - }; - Tone.extend(Tone.Analyser); - /** - * The default values. - * @type {Object} - * @const - */ - Tone.Analyser.defaults = { - 'size': 1024, - 'returnType': 'byte', - 'type': 'fft', - 'smoothing': 0.8, - 'maxDecibels': -30, - 'minDecibels': -100 - }; - /** - * Possible return types of Tone.Analyser.analyse() - * @enum {String} - */ - Tone.Analyser.Type = { - Waveform: 'waveform', - FFT: 'fft' - }; - /** - * Possible return types of Tone.Analyser.analyse(). - * byte values are between [0,255]. float values are between - * [-1, 1] when the type is set to "waveform" and between - * [minDecibels,maxDecibels] when the type is "fft". - * @enum {String} - */ - Tone.Analyser.ReturnType = { - Byte: 'byte', - Float: 'float' - }; - /** - * Run the analysis given the current settings and return the - * result as a TypedArray. - * @returns {TypedArray} - */ - Tone.Analyser.prototype.analyse = function () { - if (this._type === Tone.Analyser.Type.FFT) { - if (this._returnType === Tone.Analyser.ReturnType.Byte) { - this._analyser.getByteFrequencyData(this._buffer); - } else { - this._analyser.getFloatFrequencyData(this._buffer); - } - } else if (this._type === Tone.Analyser.Type.Waveform) { - if (this._returnType === Tone.Analyser.ReturnType.Byte) { - this._analyser.getByteTimeDomainData(this._buffer); - } else { - this._analyser.getFloatTimeDomainData(this._buffer); - } - } - return this._buffer; - }; - /** - * The size of analysis. This must be a power of two in the range 32 to 32768. - * @memberOf Tone.Analyser# - * @type {Number} - * @name size - */ - Object.defineProperty(Tone.Analyser.prototype, 'size', { - get: function () { - return this._analyser.frequencyBinCount; - }, - set: function (size) { - this._analyser.fftSize = size * 2; - this.type = this._type; - } - }); - /** - * The return type of Tone.Analyser.analyse(), either "byte" or "float". - * When the type is set to "byte" the range of values returned in the array - * are between 0-255. "float" values are between - * [-1, 1] when the type is set to "waveform" and between - * [minDecibels,maxDecibels] when the type is "fft". - * @memberOf Tone.Analyser# - * @type {String} - * @name type - */ - Object.defineProperty(Tone.Analyser.prototype, 'returnType', { - get: function () { - return this._returnType; - }, - set: function (type) { - if (type === Tone.Analyser.ReturnType.Byte) { - this._buffer = new Uint8Array(this._analyser.frequencyBinCount); - } else if (type === Tone.Analyser.ReturnType.Float) { - this._buffer = new Float32Array(this._analyser.frequencyBinCount); - } else { - throw new TypeError('Tone.Analayser: invalid return type: ' + type); - } - this._returnType = type; - } - }); - /** - * The analysis function returned by Tone.Analyser.analyse(), either "fft" or "waveform". - * @memberOf Tone.Analyser# - * @type {String} - * @name type - */ - Object.defineProperty(Tone.Analyser.prototype, 'type', { - get: function () { - return this._type; - }, - set: function (type) { - if (type !== Tone.Analyser.Type.Waveform && type !== Tone.Analyser.Type.FFT) { - throw new TypeError('Tone.Analyser: invalid type: ' + type); - } - this._type = type; - } - }); - /** - * 0 represents no time averaging with the last analysis frame. - * @memberOf Tone.Analyser# - * @type {NormalRange} - * @name smoothing - */ - Object.defineProperty(Tone.Analyser.prototype, 'smoothing', { - get: function () { - return this._analyser.smoothingTimeConstant; - }, - set: function (val) { - this._analyser.smoothingTimeConstant = val; - } - }); - /** - * The smallest decibel value which is analysed by the FFT. - * @memberOf Tone.Analyser# - * @type {Decibels} - * @name minDecibels - */ - Object.defineProperty(Tone.Analyser.prototype, 'minDecibels', { - get: function () { - return this._analyser.minDecibels; - }, - set: function (val) { - this._analyser.minDecibels = val; - } - }); - /** - * The largest decibel value which is analysed by the FFT. - * @memberOf Tone.Analyser# - * @type {Decibels} - * @name maxDecibels - */ - Object.defineProperty(Tone.Analyser.prototype, 'maxDecibels', { - get: function () { - return this._analyser.maxDecibels; - }, - set: function (val) { - this._analyser.maxDecibels = val; - } - }); - /** - * Clean up. - * @return {Tone.Analyser} this - */ - Tone.Analyser.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._analyser.disconnect(); - this._analyser = null; - this._buffer = null; - }; - return Tone.Analyser; - }); - Module(function (Tone) { - - /** - * @class Tone.Compressor is a thin wrapper around the Web Audio - * [DynamicsCompressorNode](http://webaudio.github.io/web-audio-api/#the-dynamicscompressornode-interface). - * Compression reduces the volume of loud sounds or amplifies quiet sounds - * by narrowing or "compressing" an audio signal's dynamic range. - * Read more on [Wikipedia](https://en.wikipedia.org/wiki/Dynamic_range_compression). - * - * @extends {Tone} - * @constructor - * @param {Decibels|Object} [threshold] The value above which the compression starts to be applied. - * @param {Positive} [ratio] The gain reduction ratio. - * @example - * var comp = new Tone.Compressor(-30, 3); - */ - Tone.Compressor = function () { - var options = this.optionsObject(arguments, [ - 'threshold', - 'ratio' - ], Tone.Compressor.defaults); - /** - * the compressor node - * @type {DynamicsCompressorNode} - * @private - */ - this._compressor = this.input = this.output = this.context.createDynamicsCompressor(); - /** - * the threshold vaue - * @type {Decibels} - * @signal - */ - this.threshold = new Tone.Param({ - 'param': this._compressor.threshold, - 'units': Tone.Type.Decibels, - 'convert': false - }); - /** - * The attack parameter - * @type {Time} - * @signal - */ - this.attack = new Tone.Param(this._compressor.attack, Tone.Type.Time); - /** - * The release parameter - * @type {Time} - * @signal - */ - this.release = new Tone.Param(this._compressor.release, Tone.Type.Time); - /** - * The knee parameter - * @type {Decibels} - * @signal - */ - this.knee = new Tone.Param({ - 'param': this._compressor.knee, - 'units': Tone.Type.Decibels, - 'convert': false - }); - /** - * The ratio value - * @type {Number} - * @signal - */ - this.ratio = new Tone.Param({ - 'param': this._compressor.ratio, - 'convert': false - }); - //set the defaults - this._readOnly([ - 'knee', - 'release', - 'attack', - 'ratio', - 'threshold' - ]); - this.set(options); - }; - Tone.extend(Tone.Compressor); - /** - * @static - * @const - * @type {Object} - */ - Tone.Compressor.defaults = { - 'ratio': 12, - 'threshold': -24, - 'release': 0.25, - 'attack': 0.003, - 'knee': 30 - }; - /** - * clean up - * @returns {Tone.Compressor} this - */ - Tone.Compressor.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._writable([ - 'knee', - 'release', - 'attack', - 'ratio', - 'threshold' - ]); - this._compressor.disconnect(); - this._compressor = null; - this.attack.dispose(); - this.attack = null; - this.release.dispose(); - this.release = null; - this.threshold.dispose(); - this.threshold = null; - this.ratio.dispose(); - this.ratio = null; - this.knee.dispose(); - this.knee = null; - return this; - }; - return Tone.Compressor; - }); - Module(function (Tone) { - - /** - * @class Add a signal and a number or two signals. When no value is - * passed into the constructor, Tone.Add will sum <code>input[0]</code> - * and <code>input[1]</code>. 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) { - 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.prototype.dispose.call(this); - this._sum.dispose(); - this._sum = null; - this._param.dispose(); - this._param = 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) { - 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 = this.defaultArg(value, 0); - }; - Tone.extend(Tone.Multiply, Tone.Signal); - /** - * clean up - * @returns {Tone.Multiply} this - */ - Tone.Multiply.prototype.dispose = function () { - Tone.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 () { - /** - * 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.prototype.dispose.call(this); - this._multiply.dispose(); - this._multiply = null; - return this; - }; - return Tone.Negate; - }); - Module(function (Tone) { - - /** - * @class Subtract the signal connected to <code>input[1]</code> from the signal connected - * to <code>input[0]</code>. If an argument is provided in the constructor, the - * signals <code>.value</code> 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) { - 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.prototype.dispose.call(this); - this._neg.dispose(); - this._neg = null; - this._sum.disconnect(); - this._sum = null; - this._param.dispose(); - this._param = 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 () { - /** - * @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.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) { - 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.prototype.dispose.call(this); - this._param.dispose(); - this._param = null; - 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 () { - /** - * @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.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) { - 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.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 () { - /** - * @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.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. <br><br> - * Parsing code modified from https://code.google.com/p/tapdigit/ - * Copyright 2011 2012 Ariya Hidayat, New BSD License - * - * @extends {Tone.SignalBase} - * @constructor - * @param {string} expr the expression to generate - * @example - * //adds the signals from input[0] and input[1]. - * var expr = new Tone.Expr("$0 + $1"); - */ - Tone.Expr = function () { - var expr = this._replacements(Array.prototype.slice.call(arguments)); - var inputCount = this._parseInputs(expr); - /** - * hold onto all of the nodes for disposal - * @type {Array} - * @private - */ - this._nodes = []; - /** - * The inputs. The length is determined by the expression. - * @type {Array} - */ - this.input = new Array(inputCount); - //create a gain for each input - for (var i = 0; i < inputCount; i++) { - this.input[i] = this.context.createGain(); - } - //parse the syntax tree - var tree = this._parseTree(expr); - //evaluate the results - var result; - try { - result = this._eval(tree); - } catch (e) { - this._disposeNodes(); - throw new Error('Tone.Expr: Could evaluate expression: ' + expr); - } - /** - * The output node is the result of the expression - * @type {Tone} - */ - this.output = result; - }; - Tone.extend(Tone.Expr, Tone.SignalBase); - //some helpers to cut down the amount of code - function applyBinary(Constructor, args, self) { - var op = new Constructor(); - self._eval(args[0]).connect(op, 0, 0); - self._eval(args[1]).connect(op, 0, 1); - return op; - } - function applyUnary(Constructor, args, self) { - var op = new Constructor(); - self._eval(args[0]).connect(op, 0, 0); - return op; - } - function getNumber(arg) { - return arg ? parseFloat(arg) : undefined; - } - function literalNumber(arg) { - return arg && arg.args ? parseFloat(arg.args) : undefined; - } - /* - * the Expressions that Tone.Expr can parse. - * - * each expression belongs to a group and contains a regexp - * for selecting the operator as well as that operators method - * - * @type {Object} - * @private - */ - Tone.Expr._Expressions = { - //values - 'value': { - 'signal': { - regexp: /^\d+\.\d+|^\d+/, - method: function (arg) { - var sig = new Tone.Signal(getNumber(arg)); - return sig; - } - }, - 'input': { - regexp: /^\$\d/, - method: function (arg, self) { - return self.input[getNumber(arg.substr(1))]; - } - } - }, - //syntactic glue - 'glue': { - '(': { regexp: /^\(/ }, - ')': { regexp: /^\)/ }, - ',': { regexp: /^,/ } - }, - //functions - 'func': { - 'abs': { - regexp: /^abs/, - method: applyUnary.bind(this, Tone.Abs) - }, - 'mod': { - regexp: /^mod/, - method: function (args, self) { - var modulus = literalNumber(args[1]); - var op = new Tone.Modulo(modulus); - self._eval(args[0]).connect(op); - return op; - } - }, - 'pow': { - regexp: /^pow/, - method: function (args, self) { - var exp = literalNumber(args[1]); - var op = new Tone.Pow(exp); - self._eval(args[0]).connect(op); - return op; - } - }, - 'a2g': { - regexp: /^a2g/, - method: function (args, self) { - var op = new Tone.AudioToGain(); - self._eval(args[0]).connect(op); - return op; - } - } - }, - //binary expressions - 'binary': { - '+': { - regexp: /^\+/, - precedence: 1, - method: applyBinary.bind(this, Tone.Add) - }, - '-': { - regexp: /^\-/, - precedence: 1, - method: function (args, self) { - //both unary and binary op - if (args.length === 1) { - return applyUnary(Tone.Negate, args, self); - } else { - return applyBinary(Tone.Subtract, args, self); - } - } - }, - '*': { - regexp: /^\*/, - precedence: 0, - method: applyBinary.bind(this, Tone.Multiply) - } - }, - //unary expressions - 'unary': { - '-': { - regexp: /^\-/, - method: applyUnary.bind(this, Tone.Negate) - }, - '!': { - regexp: /^\!/, - method: applyUnary.bind(this, Tone.NOT) - } - } - }; - /** - * @param {string} expr the expression string - * @return {number} the input count - * @private - */ - Tone.Expr.prototype._parseInputs = function (expr) { - var inputArray = expr.match(/\$\d/g); - var inputMax = 0; - if (inputArray !== null) { - for (var i = 0; i < inputArray.length; i++) { - var inputNum = parseInt(inputArray[i].substr(1)) + 1; - inputMax = Math.max(inputMax, inputNum); - } - } - return inputMax; - }; - /** - * @param {Array} args an array of arguments - * @return {string} the results of the replacements being replaced - * @private - */ - Tone.Expr.prototype._replacements = function (args) { - var expr = args.shift(); - for (var i = 0; i < args.length; i++) { - expr = expr.replace(/\%/i, args[i]); - } - return expr; - }; - /** - * 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.Expr.prototype._tokenize = function (expr) { - var position = -1; - var tokens = []; - while (expr.length > 0) { - expr = expr.trim(); - var token = getNextToken(expr); - tokens.push(token); - expr = expr.substr(token.value.length); - } - function getNextToken(expr) { - for (var type in Tone.Expr._Expressions) { - var group = Tone.Expr._Expressions[type]; - for (var opName in group) { - var op = group[opName]; - var reg = op.regexp; - var match = expr.match(reg); - if (match !== null) { - return { - type: type, - value: match[0], - method: op.method - }; - } - } - } - throw new SyntaxError('Tone.Expr: Unexpected token ' + expr); - } - return { - next: function () { - return tokens[++position]; - }, - peek: function () { - return tokens[position + 1]; - } - }; - }; - /** - * recursively parse the string expression into a syntax tree - * - * @param {string} expr - * @return {Object} - * @private - */ - Tone.Expr.prototype._parseTree = function (expr) { - var lexer = this._tokenize(expr); - var isUndef = this.isUndef.bind(this); - function matchSyntax(token, syn) { - return !isUndef(token) && token.type === 'glue' && token.value === syn; - } - function matchGroup(token, groupName, prec) { - var ret = false; - var group = Tone.Expr._Expressions[groupName]; - if (!isUndef(token)) { - for (var opName in group) { - var op = group[opName]; - if (op.regexp.test(token.value)) { - if (!isUndef(prec)) { - if (op.precedence === prec) { - return true; - } - } else { - return true; - } - } - } - } - return ret; - } - function parseExpression(precedence) { - if (isUndef(precedence)) { - precedence = 5; - } - var expr; - if (precedence < 0) { - expr = parseUnary(); - } else { - expr = parseExpression(precedence - 1); - } - var token = lexer.peek(); - while (matchGroup(token, 'binary', precedence)) { - token = lexer.next(); - expr = { - operator: token.value, - method: token.method, - args: [ - expr, - parseExpression(precedence - 1) - ] - }; - token = lexer.peek(); - } - return expr; - } - function parseUnary() { - var token, expr; - token = lexer.peek(); - if (matchGroup(token, 'unary')) { - token = lexer.next(); - expr = parseUnary(); - return { - operator: token.value, - method: token.method, - args: [expr] - }; - } - return parsePrimary(); - } - function parsePrimary() { - var token, expr; - token = lexer.peek(); - if (isUndef(token)) { - throw new SyntaxError('Tone.Expr: Unexpected termination of expression'); - } - if (token.type === 'func') { - token = lexer.next(); - return parseFunctionCall(token); - } - if (token.type === 'value') { - token = lexer.next(); - return { - method: token.method, - args: token.value - }; - } - if (matchSyntax(token, '(')) { - lexer.next(); - expr = parseExpression(); - token = lexer.next(); - if (!matchSyntax(token, ')')) { - throw new SyntaxError('Expected )'); - } - return expr; - } - throw new SyntaxError('Tone.Expr: Parse error, cannot process token ' + token.value); - } - function parseFunctionCall(func) { - var token, args = []; - token = lexer.next(); - if (!matchSyntax(token, '(')) { - throw new SyntaxError('Tone.Expr: Expected ( in a function call "' + func.value + '"'); - } - token = lexer.peek(); - if (!matchSyntax(token, ')')) { - args = parseArgumentList(); - } - token = lexer.next(); - if (!matchSyntax(token, ')')) { - throw new SyntaxError('Tone.Expr: Expected ) in a function call "' + func.value + '"'); - } - return { - method: func.method, - args: args, - name: name - }; - } - function parseArgumentList() { - var token, expr, args = []; - while (true) { - expr = parseExpression(); - if (isUndef(expr)) { - // TODO maybe throw exception? - break; - } - args.push(expr); - token = lexer.peek(); - if (!matchSyntax(token, ',')) { - break; - } - lexer.next(); - } - return args; - } - return parseExpression(); - }; - /** - * recursively evaluate the expression tree - * @param {Object} tree - * @return {AudioNode} the resulting audio node from the expression - * @private - */ - Tone.Expr.prototype._eval = function (tree) { - if (!this.isUndef(tree)) { - var node = tree.method(tree.args, this); - this._nodes.push(node); - return node; - } - }; - /** - * dispose all the nodes - * @private - */ - Tone.Expr.prototype._disposeNodes = function () { - for (var i = 0; i < this._nodes.length; i++) { - var node = this._nodes[i]; - if (this.isFunction(node.dispose)) { - node.dispose(); - } else if (this.isFunction(node.disconnect)) { - node.disconnect(); - } - node = null; - this._nodes[i] = null; - } - this._nodes = null; - }; - /** - * clean up - */ - Tone.Expr.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._disposeNodes(); - }; - return Tone.Expr; - }); - Module(function (Tone) { - - /** - * @class Convert an incoming signal between 0, 1 to an equal power gain scale. - * - * @extends {Tone.SignalBase} - * @constructor - * @example - * var eqPowGain = new Tone.EqualPowerGain(); - */ - Tone.EqualPowerGain = function () { - /** - * @type {Tone.WaveShaper} - * @private - */ - this._eqPower = this.input = this.output = new Tone.WaveShaper(function (val) { - if (Math.abs(val) < 0.001) { - //should output 0 when input is 0 - return 0; - } else { - return this.equalPowerScale(val); - } - }.bind(this), 4096); - }; - Tone.extend(Tone.EqualPowerGain, Tone.SignalBase); - /** - * clean up - * @returns {Tone.EqualPowerGain} this - */ - Tone.EqualPowerGain.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._eqPower.dispose(); - this._eqPower = null; - return this; - }; - return Tone.EqualPowerGain; - }); - Module(function (Tone) { - - /** - * @class Tone.Crossfade provides equal power fading between two inputs. - * More on crossfading technique [here](https://en.wikipedia.org/wiki/Fade_(audio_engineering)#Crossfading). - * - * @constructor - * @extends {Tone} - * @param {NormalRange} [initialFade=0.5] - * @example - * var crossFade = new Tone.CrossFade(0.5); - * //connect effect A to crossfade from - * //effect output 0 to crossfade input 0 - * effectA.connect(crossFade, 0, 0); - * //connect effect B to crossfade from - * //effect output 0 to crossfade input 1 - * effectB.connect(crossFade, 0, 1); - * crossFade.fade.value = 0; - * // ^ only effectA is output - * crossFade.fade.value = 1; - * // ^ only effectB is output - * crossFade.fade.value = 0.5; - * // ^ the two signals are mixed equally. - */ - Tone.CrossFade = function (initialFade) { - this.createInsOuts(2, 1); - /** - * Alias for <code>input[0]</code>. - * @type {Tone.Gain} - */ - this.a = this.input[0] = new Tone.Gain(); - /** - * Alias for <code>input[1]</code>. - * @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% <code>input[0]</code> and - * a value of 1 will output 100% <code>input[1]</code>. - * @type {NormalRange} - * @signal - */ - this.fade = new Tone.Signal(this.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); - /** - * clean up - * @returns {Tone.CrossFade} this - */ - Tone.CrossFade.prototype.dispose = function () { - Tone.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} - * @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 () { - this.createInsOuts(1, 1); - var options = this.optionsObject(arguments, [ - 'frequency', - 'type', - 'rolloff' - ], Tone.Filter.defaults); - /** - * 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); - /** - * 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]); - this.connectSeries.apply(this, connectionChain); - } - }); - /** - * Clean up. - * @return {Tone.Filter} this - */ - Tone.Filter.prototype.dispose = function () { - Tone.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} - * @constructor - * @param {Frequency|Object} [lowFrequency] the low/mid crossover frequency - * @param {Frequency} [highFrequency] the mid/high crossover frequency - */ - Tone.MultibandSplit = function () { - var options = this.optionsObject(arguments, [ - 'lowFrequency', - 'highFrequency' - ], Tone.MultibandSplit.defaults); - /** - * 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 <code>output[0]</code> - * @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 <code>output[1]</code> - * @type {Tone.Filter} - */ - this.mid = this.output[1] = new Tone.Filter(0, 'lowpass'); - /** - * The high band output. Alias for <code>output[2]</code> - * @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); - /** - * @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.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} - * - * @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 = this.optionsObject(arguments, [ - 'low', - 'mid', - 'high' - ], Tone.EQ3.defaults); - /** - * 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); - /** - * 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.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) { - /** - * @private - * @type {number} - */ - this._outputMin = this.defaultArg(outputMin, 0); - /** - * @private - * @type {number} - */ - this._outputMax = this.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.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) { - /** - * 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(this.defaultArg(exponent, 2)); - this._exp.connect(this._scale); - }; - Tone.extend(Tone.ScaleExp, Tone.SignalBase); - /** - * Instead of interpolating linearly between the <code>min</code> and - * <code>max</code> 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.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 = this.optionsObject(arguments, [ - 'delayTime', - 'maxDelay' - ], Tone.Delay.defaults); - /** - * 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 {Tone.Param} - * @signal - */ - this.delayTime = new Tone.Param({ - 'param': this._delayNode.delayTime, - 'units': Tone.Type.Time, - 'value': options.delayTime - }); - this._readOnly('delayTime'); - }; - Tone.extend(Tone.Delay); - /** - * The defaults - * @const - * @type {Object} - */ - Tone.Delay.defaults = { - 'maxDelay': 1, - 'delayTime': 0 - }; - /** - * Clean up. - * @return {Tone.Delay} this - */ - Tone.Delay.prototype.dispose = function () { - Tone.Param.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} - * @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 = this.optionsObject(arguments, [ - 'delayTime', - 'resonance' - ], Tone.FeedbackCombFilter.defaults); - /** - * 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); - /** - * 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.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 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} - * @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 () { - this.createInsOuts(1, 1); - var options = this.optionsObject(arguments, [ - 'attack', - 'release' - ], Tone.Follower.defaults); - /** - * @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); - /** - * @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.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 = this.optionsObject(arguments, [ - 'attack', - 'decay', - 'sustain', - 'release' - ], Tone.Envelope.defaults); - Tone.Envelope.call(this, options); - options = this.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 = this.optionsObject(arguments, [ - 'attack', - 'decay', - 'sustain', - 'release' - ], Tone.Envelope.defaults); - Tone.ScaledEnvelope.call(this, options); - options = this.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} - * @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 () { - this.createInsOuts(1, 1); - var options = this.optionsObject(arguments, [ - 'threshold', - 'attack', - 'release' - ], Tone.Gate.defaults); - /** - * @type {Tone.Follower} - * @private - */ - this._follower = new Tone.Follower(options.attack, options.release); - /** - * @type {Tone.GreaterThan} - * @private - */ - this._gt = new Tone.GreaterThan(this.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); - /** - * @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 this.gainToDb(this._gt.value); - }, - set: function (thresh) { - this._gt.value = this.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.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 A Timeline State. Provides the methods: <code>setStateAtTime("state", time)</code> - * and <code>getValueAtTime(time)</code>. - * - * @extends {Tone.Timeline} - * @param {String} initial The initial state of the TimelineState. - * Defaults to <code>undefined</code> - */ - 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; - } - }; - /** - * Returns the scheduled state scheduled before or at - * the given time. - * @param {String} state The name of the state to set. - * @param {Number} time The time to query. - */ - Tone.TimelineState.prototype.setStateAtTime = function (state, time) { - this.add({ - 'state': state, - 'time': time - }); - }; - 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 () { - Tone.Emitter.call(this); - var options = this.optionsObject(arguments, [ - 'callback', - 'frequency' - ], Tone.Clock.defaults); - /** - * 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.TimelineSignal(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, - 'lookAhead': 'auto' - }; - /** - * 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.add({ - 'state': Tone.State.Started, - 'time': 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. - * @param {Number} time The current page time starting from 0 - * when the page was loaded. - * @private - */ - Tone.Clock.prototype._loop = function () { - //get the frequency value to compute the value of the next loop - var now = this.now(); - //if it's started - var lookAhead = this.context.lookAhead; - var updateInterval = this.context.updateInterval; - var lagCompensation = this.context.lag * 2; - var loopInterval = now + lookAhead + updateInterval + lagCompensation; - while (loopInterval > this._nextTick && this._state) { - var currentState = this._state.getValueAtTime(this._nextTick); - if (currentState !== this._lastState) { - this._lastState = currentState; - var event = this._state.get(this._nextTick); - // emit an event - if (currentState === Tone.State.Started) { - //correct the time - this._nextTick = event.time; - if (!this.isUndef(event.offset)) { - this.ticks = event.offset; - } - this.emit('start', event.time, this.ticks); - } else if (currentState === Tone.State.Stopped) { - this.ticks = 0; - this.emit('stop', event.time); - } else if (currentState === Tone.State.Paused) { - this.emit('pause', event.time); - } - } - var tickTime = this._nextTick; - if (this.frequency) { - this._nextTick += 1 / this.frequency.getValueAtTime(this._nextTick); - if (currentState === Tone.State.Started) { - this.callback(tickTime); - this.ticks++; - } - } - } - }; - /** - * 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 () { - /** - * 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 (this.isUndef(event.time) || this.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 = []; - if (this._root !== null) { - 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; - if (ev) { - 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 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. <br><br> - * A single transport is created for you when the library is initialized. - * <br><br> - * The transport emits the events: "start", "stop", "pause", and "loop" which are - * called with the time of that event as the argument. - * - * @extends {Tone.Emitter} - * @singleton - * @example - * //repeated event every 8th note - * Tone.Transport.scheduleRepeat(function(time){ - * //do something with the time - * }, "8n"); - * @example - * //schedule an event on the 16th measure - * Tone.Transport.schedule(function(time){ - * //do something with the time - * }, "16:0:0"); - */ - Tone.Transport = function () { - Tone.Emitter.call(this); - /////////////////////////////////////////////////////////////////////// - // LOOPING - ////////////////////////////////////////////////////////////////////// - /** - * If the transport loops or not. - * @type {boolean} - */ - this.loop = false; - /** - * The loop start position in ticks - * @type {Ticks} - * @private - */ - this._loopStart = 0; - /** - * The loop end position in ticks - * @type {Ticks} - * @private - */ - this._loopEnd = 0; - /////////////////////////////////////////////////////////////////////// - // CLOCK/TEMPO - ////////////////////////////////////////////////////////////////////// - /** - * Pulses per quarter is the number of ticks per quarter note. - * @private - * @type {Number} - */ - this._ppq = TransportConstructor.defaults.PPQ; - /** - * watches the main oscillator for timing ticks - * initially starts at 120bpm - * @private - * @type {Tone.Clock} - */ - this._clock = new Tone.Clock({ - 'callback': this._processTick.bind(this), - 'frequency': 0 - }); - this._bindClockEvents(); - /** - * The Beats Per Minute of the Transport. - * @type {BPM} - * @signal - * @example - * Tone.Transport.bpm.value = 80; - * //ramp the bpm to 120 over 10 seconds - * Tone.Transport.bpm.rampTo(120, 10); - */ - this.bpm = this._clock.frequency; - this.bpm._toUnits = this._toUnits.bind(this); - this.bpm._fromUnits = this._fromUnits.bind(this); - this.bpm.units = Tone.Type.BPM; - this.bpm.value = TransportConstructor.defaults.bpm; - this._readOnly('bpm'); - /** - * The time signature, or more accurately the numerator - * of the time signature over a denominator of 4. - * @type {Number} - * @private - */ - this._timeSignature = TransportConstructor.defaults.timeSignature; - /////////////////////////////////////////////////////////////////////// - // TIMELINE EVENTS - ////////////////////////////////////////////////////////////////////// - /** - * All the events in an object to keep track by ID - * @type {Object} - * @private - */ - this._scheduledEvents = {}; - /** - * The event ID counter - * @type {Number} - * @private - */ - this._eventID = 0; - /** - * The scheduled events. - * @type {Tone.Timeline} - * @private - */ - this._timeline = new Tone.Timeline(); - /** - * Repeated events - * @type {Array} - * @private - */ - this._repeatedEvents = new Tone.IntervalTimeline(); - /** - * Events that occur once - * @type {Array} - * @private - */ - this._onceEvents = new Tone.Timeline(); - /** - * All of the synced Signals - * @private - * @type {Array} - */ - this._syncedSignals = []; - /////////////////////////////////////////////////////////////////////// - // SWING - ////////////////////////////////////////////////////////////////////// - /** - * The subdivision of the swing - * @type {Ticks} - * @private - */ - this._swingTicks = TransportConstructor.defaults.PPQ / 2; - //8n - /** - * The swing amount - * @type {NormalRange} - * @private - */ - this._swingAmount = 0; - }; - Tone.extend(Tone.Transport, Tone.Emitter); - /** - * the defaults - * @type {Object} - * @const - * @static - */ - Tone.Transport.defaults = { - 'bpm': 120, - 'swing': 0, - 'swingSubdivision': '8n', - 'timeSignature': 4, - 'loopStart': 0, - 'loopEnd': '4m', - 'PPQ': 192 - }; - /////////////////////////////////////////////////////////////////////////////// - // TICKS - /////////////////////////////////////////////////////////////////////////////// - /** - * called on every tick - * @param {number} tickTime clock relative tick time - * @private - */ - Tone.Transport.prototype._processTick = function (tickTime) { - var ticks = this._clock.ticks; - //handle swing - if (this._swingAmount > 0 && ticks % this._ppq !== 0 && //not on a downbeat - ticks % (this._swingTicks * 2) !== 0) { - //add some swing - var progress = ticks % (this._swingTicks * 2) / (this._swingTicks * 2); - var amount = Math.sin(progress * Math.PI) * this._swingAmount; - tickTime += Tone.Time(this._swingTicks * 2 / 3, 'i') * amount; - } - //do the loop test - if (this.loop) { - if (ticks === this._loopEnd) { - this.emit('loopEnd', tickTime); - this._clock.ticks = this._loopStart; - ticks = this._loopStart; - this.emit('loopStart', tickTime, this.seconds); - this.emit('loop', tickTime); - } - } - //process the single occurrence events - this._onceEvents.forEachBefore(ticks, function (event) { - event.callback(tickTime); - //remove the event - delete this._scheduledEvents[event.id.toString()]; - }.bind(this)); - //and clear the single occurrence timeline - this._onceEvents.cancelBefore(ticks); - //fire the next tick events if their time has come - this._timeline.forEachAtTime(ticks, function (event) { - event.callback(tickTime); - }); - //process the repeated events - this._repeatedEvents.forEachAtTime(ticks, function (event) { - if ((ticks - event.time) % event.interval === 0) { - event.callback(tickTime); - } - }); - }; - /////////////////////////////////////////////////////////////////////////////// - // SCHEDULABLE EVENTS - /////////////////////////////////////////////////////////////////////////////// - /** - * Schedule an event along the timeline. - * @param {Function} callback The callback to be invoked at the time. - * @param {TransportTime} time The time to invoke the callback at. - * @return {Number} The id of the event which can be used for canceling the event. - * @example - * //trigger the callback when the Transport reaches the desired time - * Tone.Transport.schedule(function(time){ - * envelope.triggerAttack(time); - * }, "128i"); - */ - Tone.Transport.prototype.schedule = function (callback, time) { - var event = { - 'time': this.toTicks(time), - 'callback': callback - }; - var id = this._eventID++; - this._scheduledEvents[id.toString()] = { - 'event': event, - 'timeline': this._timeline - }; - this._timeline.add(event); - return id; - }; - /** - * Schedule a repeated event along the timeline. The event will fire - * at the `interval` starting at the `startTime` and for the specified - * `duration`. - * @param {Function} callback The callback to invoke. - * @param {Time} interval The duration between successive - * callbacks. - * @param {TimelinePosition=} startTime When along the timeline the events should - * start being invoked. - * @param {Time} [duration=Infinity] How long the event should repeat. - * @return {Number} The ID of the scheduled event. Use this to cancel - * the event. - * @example - * //a callback invoked every eighth note after the first measure - * Tone.Transport.scheduleRepeat(callback, "8n", "1m"); - */ - Tone.Transport.prototype.scheduleRepeat = function (callback, interval, startTime, duration) { - if (interval <= 0) { - throw new Error('Tone.Transport: repeat events must have an interval larger than 0'); - } - var event = { - 'time': this.toTicks(startTime), - 'duration': this.toTicks(this.defaultArg(duration, Infinity)), - 'interval': this.toTicks(interval), - 'callback': callback - }; - var id = this._eventID++; - this._scheduledEvents[id.toString()] = { - 'event': event, - 'timeline': this._repeatedEvents - }; - this._repeatedEvents.add(event); - return id; - }; - /** - * Schedule an event that will be removed after it is invoked. - * Note that if the given time is less than the current transport time, - * the event will be invoked immediately. - * @param {Function} callback The callback to invoke once. - * @param {TransportTime} time The time the callback should be invoked. - * @returns {Number} The ID of the scheduled event. - */ - Tone.Transport.prototype.scheduleOnce = function (callback, time) { - var id = this._eventID++; - var event = { - 'time': this.toTicks(time), - 'callback': callback, - 'id': id - }; - this._scheduledEvents[id.toString()] = { - 'event': event, - 'timeline': this._onceEvents - }; - this._onceEvents.add(event); - return id; - }; - /** - * Clear the passed in event id from the timeline - * @param {Number} eventId The id of the event. - * @returns {Tone.Transport} this - */ - Tone.Transport.prototype.clear = function (eventId) { - if (this._scheduledEvents.hasOwnProperty(eventId)) { - var item = this._scheduledEvents[eventId.toString()]; - item.timeline.remove(item.event); - delete this._scheduledEvents[eventId.toString()]; - } - return this; - }; - /** - * Remove scheduled events from the timeline after - * the given time. Repeated events will be removed - * if their startTime is after the given time - * @param {TransportTime} [after=0] Clear all events after - * this time. - * @returns {Tone.Transport} this - */ - Tone.Transport.prototype.cancel = function (after) { - after = this.defaultArg(after, 0); - after = this.toTicks(after); - this._timeline.cancel(after); - this._onceEvents.cancel(after); - this._repeatedEvents.cancel(after); - return this; - }; - /////////////////////////////////////////////////////////////////////////////// - // START/STOP/PAUSE - /////////////////////////////////////////////////////////////////////////////// - /** - * Bind start/stop/pause events from the clock and emit them. - */ - Tone.Transport.prototype._bindClockEvents = function () { - this._clock.on('start', function (time, offset) { - offset = Tone.Time(this._clock.ticks, 'i').toSeconds(); - this.emit('start', time, offset); - }.bind(this)); - this._clock.on('stop', function (time) { - this.emit('stop', time); - }.bind(this)); - this._clock.on('pause', function (time) { - this.emit('pause', time); - }.bind(this)); - }; - /** - * Returns the playback state of the source, either "started", "stopped", or "paused" - * @type {Tone.State} - * @readOnly - * @memberOf Tone.Transport# - * @name state - */ - Object.defineProperty(Tone.Transport.prototype, 'state', { - get: function () { - return this._clock.getStateAtTime(this.now()); - } - }); - /** - * Start the transport and all sources synced to the transport. - * @param {Time} [time=now] The time when the transport should start. - * @param {TransportTime=} offset The timeline offset to start the transport. - * @returns {Tone.Transport} this - * @example - * //start the transport in one second starting at beginning of the 5th measure. - * Tone.Transport.start("+1", "4:0:0"); - */ - Tone.Transport.prototype.start = function (time, offset) { - //start the clock - if (!this.isUndef(offset)) { - offset = this.toTicks(offset); - } - this._clock.start(time, offset); - return this; - }; - /** - * Stop the transport and all sources synced to the transport. - * @param {Time} [time=now] The time when the transport should stop. - * @returns {Tone.Transport} this - * @example - * Tone.Transport.stop(); - */ - Tone.Transport.prototype.stop = function (time) { - this._clock.stop(time); - return this; - }; - /** - * Pause the transport and all sources synced to the transport. - * @param {Time} [time=now] - * @returns {Tone.Transport} this - */ - Tone.Transport.prototype.pause = function (time) { - this._clock.pause(time); - return this; - }; - /////////////////////////////////////////////////////////////////////////////// - // SETTERS/GETTERS - /////////////////////////////////////////////////////////////////////////////// - /** - * The time signature as just the numerator over 4. - * For example 4/4 would be just 4 and 6/8 would be 3. - * @memberOf Tone.Transport# - * @type {Number|Array} - * @name timeSignature - * @example - * //common time - * Tone.Transport.timeSignature = 4; - * // 7/8 - * Tone.Transport.timeSignature = [7, 8]; - * //this will be reduced to a single number - * Tone.Transport.timeSignature; //returns 3.5 - */ - Object.defineProperty(Tone.Transport.prototype, 'timeSignature', { - get: function () { - return this._timeSignature; - }, - set: function (timeSig) { - if (this.isArray(timeSig)) { - timeSig = timeSig[0] / timeSig[1] * 4; - } - this._timeSignature = timeSig; - } - }); - /** - * When the Tone.Transport.loop = true, this is the starting position of the loop. - * @memberOf Tone.Transport# - * @type {TransportTime} - * @name loopStart - */ - Object.defineProperty(Tone.Transport.prototype, 'loopStart', { - get: function () { - return Tone.TransportTime(this._loopStart, 'i').toSeconds(); - }, - set: function (startPosition) { - this._loopStart = this.toTicks(startPosition); - } - }); - /** - * When the Tone.Transport.loop = true, this is the ending position of the loop. - * @memberOf Tone.Transport# - * @type {TransportTime} - * @name loopEnd - */ - Object.defineProperty(Tone.Transport.prototype, 'loopEnd', { - get: function () { - return Tone.TransportTime(this._loopEnd, 'i').toSeconds(); - }, - set: function (endPosition) { - this._loopEnd = this.toTicks(endPosition); - } - }); - /** - * Set the loop start and stop at the same time. - * @param {TransportTime} startPosition - * @param {TransportTime} endPosition - * @returns {Tone.Transport} this - * @example - * //loop over the first measure - * Tone.Transport.setLoopPoints(0, "1m"); - * Tone.Transport.loop = true; - */ - Tone.Transport.prototype.setLoopPoints = function (startPosition, endPosition) { - this.loopStart = startPosition; - this.loopEnd = endPosition; - return this; - }; - /** - * The swing value. Between 0-1 where 1 equal to - * the note + half the subdivision. - * @memberOf Tone.Transport# - * @type {NormalRange} - * @name swing - */ - Object.defineProperty(Tone.Transport.prototype, 'swing', { - get: function () { - return this._swingAmount; - }, - set: function (amount) { - //scale the values to a normal range - this._swingAmount = amount; - } - }); - /** - * Set the subdivision which the swing will be applied to. - * The default value is an 8th note. Value must be less - * than a quarter note. - * - * @memberOf Tone.Transport# - * @type {Time} - * @name swingSubdivision - */ - Object.defineProperty(Tone.Transport.prototype, 'swingSubdivision', { - get: function () { - return Tone.Time(this._swingTicks, 'i').toNotation(); - }, - set: function (subdivision) { - this._swingTicks = this.toTicks(subdivision); - } - }); - /** - * The Transport's position in Bars:Beats:Sixteenths. - * Setting the value will jump to that position right away. - * @memberOf Tone.Transport# - * @type {BarsBeatsSixteenths} - * @name position - */ - Object.defineProperty(Tone.Transport.prototype, 'position', { - get: function () { - return Tone.TransportTime(this.ticks, 'i').toBarsBeatsSixteenths(); - }, - set: function (progress) { - var ticks = this.toTicks(progress); - this.ticks = ticks; - } - }); - /** - * The Transport's position in seconds - * Setting the value will jump to that position right away. - * @memberOf Tone.Transport# - * @type {Seconds} - * @name seconds - */ - Object.defineProperty(Tone.Transport.prototype, 'seconds', { - get: function () { - return Tone.TransportTime(this.ticks, 'i').toSeconds(); - }, - set: function (progress) { - var ticks = this.toTicks(progress); - this.ticks = ticks; - } - }); - /** - * The Transport's loop position as a normalized value. Always - * returns 0 if the transport if loop is not true. - * @memberOf Tone.Transport# - * @name progress - * @type {NormalRange} - */ - Object.defineProperty(Tone.Transport.prototype, 'progress', { - get: function () { - if (this.loop) { - return (this.ticks - this._loopStart) / (this._loopEnd - this._loopStart); - } else { - return 0; - } - } - }); - /** - * The transports current tick position. - * - * @memberOf Tone.Transport# - * @type {Ticks} - * @name ticks - */ - Object.defineProperty(Tone.Transport.prototype, 'ticks', { - get: function () { - return this._clock.ticks; - }, - set: function (t) { - if (this._clock.ticks !== t) { - var now = this.now(); - //stop everything synced to the transport - if (this.state === Tone.State.Started) { - this.emit('stop', now); - this._clock.ticks = t; - //restart it with the new time - this.emit('start', now, this.seconds); - } else { - this._clock.ticks = t; - } - } - } - }); - /** - * Pulses Per Quarter note. This is the smallest resolution - * the Transport timing supports. This should be set once - * on initialization and not set again. Changing this value - * after other objects have been created can cause problems. - * - * @memberOf Tone.Transport# - * @type {Number} - * @name PPQ - */ - Object.defineProperty(Tone.Transport.prototype, 'PPQ', { - get: function () { - return this._ppq; - }, - set: function (ppq) { - var bpm = this.bpm.value; - this._ppq = ppq; - this.bpm.value = bpm; - } - }); - /** - * The hint to the type of playback. 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). - * @memberOf Tone.Transport# - * @type {Seconds|String} - * @name latencyHint - */ - Object.defineProperty(Tone.Transport.prototype, 'latencyHint', { - get: function () { - return Tone.Clock.latencyHint; - }, - set: function (hint) { - Tone.Clock.latencyHint = hint; - } - }); - /** - * Convert from BPM to frequency (factoring in PPQ) - * @param {BPM} bpm The BPM value to convert to frequency - * @return {Frequency} The BPM as a frequency with PPQ factored in. - * @private - */ - Tone.Transport.prototype._fromUnits = function (bpm) { - return 1 / (60 / bpm / this.PPQ); - }; - /** - * Convert from frequency (with PPQ) into BPM - * @param {Frequency} freq The clocks frequency to convert to BPM - * @return {BPM} The frequency value as BPM. - * @private - */ - Tone.Transport.prototype._toUnits = function (freq) { - return freq / this.PPQ * 60; - }; - /////////////////////////////////////////////////////////////////////////////// - // SYNCING - /////////////////////////////////////////////////////////////////////////////// - /** - * Returns the time aligned to the next subdivision - * of the Transport. If the Transport is not started, - * it will return 0. - * Note: this will not work precisely during tempo ramps. - * @param {Time} subdivision The subdivision to quantize to - * @return {Number} The context time of the next subdivision. - * @example - * Tone.Transport.start(); //the transport must be started - * Tone.Transport.nextSubdivision("4n"); - */ - Tone.Transport.prototype.nextSubdivision = function (subdivision) { - subdivision = this.toSeconds(subdivision); - //if the transport's not started, return 0 - var now; - if (this.state === Tone.State.Started) { - now = this._clock._nextTick; - } else { - return 0; - } - var transportPos = Tone.Time(this.ticks, 'i'); - var remainingTime = subdivision - transportPos % subdivision; - if (remainingTime === 0) { - remainingTime = subdivision; - } - return now + remainingTime; - }; - /** - * Attaches the signal to the tempo control signal so that - * any changes in the tempo will change the signal in the same - * ratio. - * - * @param {Tone.Signal} signal - * @param {number=} ratio Optionally pass in the ratio between - * the two signals. Otherwise it will be computed - * based on their current values. - * @returns {Tone.Transport} this - */ - Tone.Transport.prototype.syncSignal = function (signal, ratio) { - if (!ratio) { - //get the sync ratio - if (signal._param.value !== 0) { - ratio = signal._param.value / this.bpm._param.value; - } else { - ratio = 0; - } - } - var ratioSignal = new Tone.Gain(ratio); - this.bpm.chain(ratioSignal, signal._param); - this._syncedSignals.push({ - 'ratio': ratioSignal, - 'signal': signal, - 'initial': signal._param.value - }); - signal._param.value = 0; - return this; - }; - /** - * Unsyncs a previously synced signal from the transport's control. - * See Tone.Transport.syncSignal. - * @param {Tone.Signal} signal - * @returns {Tone.Transport} this - */ - Tone.Transport.prototype.unsyncSignal = function (signal) { - for (var i = this._syncedSignals.length - 1; i >= 0; i--) { - var syncedSignal = this._syncedSignals[i]; - if (syncedSignal.signal === signal) { - syncedSignal.ratio.dispose(); - syncedSignal.signal._param.value = syncedSignal.initial; - this._syncedSignals.splice(i, 1); - } - } - return this; - }; - /** - * Clean up. - * @returns {Tone.Transport} this - * @private - */ - Tone.Transport.prototype.dispose = function () { - Tone.Emitter.prototype.dispose.call(this); - this._clock.dispose(); - this._clock = null; - this._writable('bpm'); - this.bpm = null; - this._timeline.dispose(); - this._timeline = null; - this._onceEvents.dispose(); - this._onceEvents = null; - this._repeatedEvents.dispose(); - this._repeatedEvents = null; - return this; - }; - /////////////////////////////////////////////////////////////////////////////// - // INITIALIZATION - /////////////////////////////////////////////////////////////////////////////// - var TransportConstructor = Tone.Transport; - Tone.Transport = new TransportConstructor(); - Tone.Context.on('init', function (context) { - if (context.Transport instanceof TransportConstructor) { - Tone.Transport = context.Transport; - } else { - Tone.Transport = new TransportConstructor(); - //store the Transport on the context so it can be retrieved later - context.Transport = Tone.Transport; - } - }); - return Tone.Transport; - }); - Module(function (Tone) { - - /** - * @class Tone.Volume is a simple volume node, useful for creating a volume fader. - * - * @extends {Tone} - * @constructor - * @param {Decibels} [volume=0] the initial volume - * @example - * var vol = new Tone.Volume(-12); - * instrument.chain(vol, Tone.Master); - */ - Tone.Volume = function () { - var options = this.optionsObject(arguments, ['volume'], Tone.Volume.defaults); - /** - * the output node - * @type {GainNode} - * @private - */ - this.output = this.input = new Tone.Gain(options.volume, Tone.Type.Decibels); - /** - * The unmuted volume - * @type {Decibels} - * @private - */ - this._unmutedVolume = options.volume; - /** - * The volume control in decibels. - * @type {Decibels} - * @signal - */ - this.volume = this.output.gain; - this._readOnly('volume'); - //set the mute initially - this.mute = options.mute; - }; - Tone.extend(Tone.Volume); - /** - * Defaults - * @type {Object} - * @const - * @static - */ - Tone.Volume.defaults = { - 'volume': 0, - 'mute': false - }; - /** - * Mute the output. - * @memberOf Tone.Volume# - * @type {boolean} - * @name mute - * @example - * //mute the output - * volume.mute = true; - */ - Object.defineProperty(Tone.Volume.prototype, 'mute', { - get: function () { - return this.volume.value === -Infinity; - }, - set: function (mute) { - if (!this.mute && mute) { - this._unmutedVolume = this.volume.value; - //maybe it should ramp here? - this.volume.value = -Infinity; - } else if (this.mute && !mute) { - this.volume.value = this._unmutedVolume; - } - } - }); - /** - * clean up - * @returns {Tone.Volume} this - */ - Tone.Volume.prototype.dispose = function () { - this.input.dispose(); - Tone.prototype.dispose.call(this); - this._writable('volume'); - this.volume.dispose(); - this.volume = null; - return this; - }; - return Tone.Volume; - }); - Module(function (Tone) { - - /** - * @class A single master output which is connected to the - * AudioDestinationNode (aka your speakers). - * It provides useful conveniences such as the ability - * to set the volume and mute the entire application. - * It also gives you the ability to apply master effects to your application. - * <br><br> - * Like Tone.Transport, A single Tone.Master is created - * on initialization and you do not need to explicitly construct one. - * - * @constructor - * @extends {Tone} - * @singleton - * @example - * //the audio will go from the oscillator to the speakers - * oscillator.connect(Tone.Master); - * //a convenience for connecting to the master output is also provided: - * oscillator.toMaster(); - * //the above two examples are equivalent. - */ - Tone.Master = function () { - this.createInsOuts(1, 1); - /** - * The private volume node - * @type {Tone.Volume} - * @private - */ - this._volume = this.output = new Tone.Volume(); - /** - * The volume of the master output. - * @type {Decibels} - * @signal - */ - this.volume = this._volume.volume; - this._readOnly('volume'); - //connections - this.input.chain(this.output, this.context.destination); - }; - Tone.extend(Tone.Master); - /** - * @type {Object} - * @const - */ - Tone.Master.defaults = { - 'volume': 0, - 'mute': false - }; - /** - * Mute the output. - * @memberOf Tone.Master# - * @type {boolean} - * @name mute - * @example - * //mute the output - * Tone.Master.mute = true; - */ - Object.defineProperty(Tone.Master.prototype, 'mute', { - get: function () { - return this._volume.mute; - }, - set: function (mute) { - this._volume.mute = mute; - } - }); - /** - * Add a master effects chain. NOTE: this will disconnect any nodes which were previously - * chained in the master effects chain. - * @param {AudioNode|Tone...} args All arguments will be connected in a row - * and the Master will be routed through it. - * @return {Tone.Master} this - * @example - * //some overall compression to keep the levels in check - * var masterCompressor = new Tone.Compressor({ - * "threshold" : -6, - * "ratio" : 3, - * "attack" : 0.5, - * "release" : 0.1 - * }); - * //give a little boost to the lows - * var lowBump = new Tone.Filter(200, "lowshelf"); - * //route everything through the filter - * //and compressor before going to the speakers - * Tone.Master.chain(lowBump, masterCompressor); - */ - Tone.Master.prototype.chain = function () { - this.input.disconnect(); - this.input.chain.apply(this.input, arguments); - arguments[arguments.length - 1].connect(this.output); - }; - /** - * Clean up - * @return {Tone.Master} this - */ - Tone.Master.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._writable('volume'); - this._volume.dispose(); - this._volume = null; - this.volume = null; - }; - /////////////////////////////////////////////////////////////////////////// - // AUGMENT TONE's PROTOTYPE - /////////////////////////////////////////////////////////////////////////// - /** - * Connect 'this' to the master output. Shorthand for this.connect(Tone.Master) - * @returns {Tone} this - * @example - * //connect an oscillator to the master output - * var osc = new Tone.Oscillator().toMaster(); - */ - Tone.prototype.toMaster = function () { - this.connect(Tone.Master); - return this; - }; - /** - * Also augment AudioNode's prototype to include toMaster - * as a convenience - * @returns {AudioNode} this - */ - AudioNode.prototype.toMaster = function () { - this.connect(Tone.Master); - return this; - }; - /** - * initialize the module and listen for new audio contexts - */ - var MasterConstructor = Tone.Master; - Tone.Master = new MasterConstructor(); - Tone.Context.on('init', function (context) { - // if it already exists, just restore it - if (context.Master instanceof MasterConstructor) { - Tone.Master = context.Master; - } else { - Tone.Master = new MasterConstructor(); - } - context.Master = Tone.Master; - }); - return Tone.Master; - }); - Module(function (Tone) { - - /** - * @class Base class for sources. Sources have start/stop methods - * and the ability to be synced to the - * start/stop of Tone.Transport. - * - * @constructor - * @extends {Tone} - * @example - * //Multiple state change events can be chained together, - * //but must be set in the correct order and with ascending times - * - * // OK - * state.start().stop("+0.2"); - * // AND - * state.start().stop("+0.2").start("+0.4").stop("+0.7") - * - * // BAD - * state.stop("+0.2").start(); - * // OR - * state.start("+0.3").stop("+0.2"); - * - */ - Tone.Source = function (options) { - // this.createInsOuts(0, 1); - options = this.defaultArg(options, Tone.Source.defaults); - /** - * The output volume node - * @type {Tone.Volume} - * @private - */ - this._volume = this.output = new Tone.Volume(options.volume); - /** - * The volume of the output in decibels. - * @type {Decibels} - * @signal - * @example - * source.volume.value = -6; - */ - this.volume = this._volume.volume; - this._readOnly('volume'); - /** - * Keep track of the scheduled state. - * @type {Tone.TimelineState} - * @private - */ - this._state = new Tone.TimelineState(Tone.State.Stopped); - this._state.memory = 10; - /** - * The synced `start` callback function from the transport - * @type {Function} - * @private - */ - this._synced = false; - /** - * Keep track of all of the scheduled event ids - * @type {Array} - * @private - */ - this._scheduled = []; - //make the output explicitly stereo - this._volume.output.output.channelCount = 2; - this._volume.output.output.channelCountMode = 'explicit'; - //mute initially - this.mute = options.mute; - }; - Tone.extend(Tone.Source); - /** - * The default parameters - * @static - * @const - * @type {Object} - */ - Tone.Source.defaults = { - 'volume': 0, - 'mute': false - }; - /** - * Returns the playback state of the source, either "started" or "stopped". - * @type {Tone.State} - * @readOnly - * @memberOf Tone.Source# - * @name state - */ - Object.defineProperty(Tone.Source.prototype, 'state', { - get: function () { - if (this._synced) { - if (Tone.Transport.state === Tone.State.Started) { - return this._state.getValueAtTime(Tone.Transport.seconds); - } else { - return Tone.State.Stopped; - } - } else { - return this._state.getValueAtTime(this.now()); - } - } - }); - /** - * Mute the output. - * @memberOf Tone.Source# - * @type {boolean} - * @name mute - * @example - * //mute the output - * source.mute = true; - */ - Object.defineProperty(Tone.Source.prototype, 'mute', { - get: function () { - return this._volume.mute; - }, - set: function (mute) { - this._volume.mute = mute; - } - }); - //overwrite these functions - Tone.Source.prototype._start = Tone.noOp; - Tone.Source.prototype._stop = Tone.noOp; - /** - * Start the source at the specified time. If no time is given, - * start the source now. - * @param {Time} [time=now] When the source should be started. - * @returns {Tone.Source} this - * @example - * source.start("+0.5"); //starts the source 0.5 seconds from now - */ - Tone.Source.prototype.start = function (time, offset, duration) { - if (this.isUndef(time) && this._synced) { - time = Tone.Transport.seconds; - } else { - time = this.toSeconds(time); - } - //if it's started, stop it and restart it - if (!this.retrigger && this._state.getValueAtTime(time) === Tone.State.Started) { - this.stop(time); - } - this._state.setStateAtTime(Tone.State.Started, time); - if (this._synced) { - // add the offset time to the event - var event = this._state.get(time); - event.offset = this.defaultArg(offset, 0); - event.duration = duration; - var sched = Tone.Transport.schedule(function (t) { - this._start(t, offset, duration); - }.bind(this), time); - this._scheduled.push(sched); - } else { - this._start.apply(this, arguments); - } - return this; - }; - /** - * Stop the source at the specified time. If no time is given, - * stop the source now. - * @param {Time} [time=now] When the source should be stopped. - * @returns {Tone.Source} this - * @example - * source.stop(); // stops the source immediately - */ - Tone.Source.prototype.stop = function (time) { - if (this.isUndef(time) && this._synced) { - time = Tone.Transport.seconds; - } else { - time = this.toSeconds(time); - } - this._state.cancel(time); - this._state.setStateAtTime(Tone.State.Stopped, time); - if (!this._synced) { - this._stop.apply(this, arguments); - } else { - var sched = Tone.Transport.schedule(this._stop.bind(this), time); - this._scheduled.push(sched); - } - return this; - }; - /** - * Sync the source to the Transport so that all subsequent - * calls to `start` and `stop` are synced to the TransportTime - * instead of the AudioContext time. - * - * @returns {Tone.Source} this - * @example - * //sync the source so that it plays between 0 and 0.3 on the Transport's timeline - * source.sync().start(0).stop(0.3); - * //start the transport. - * Tone.Transport.start(); - * - * @example - * //start the transport with an offset and the sync'ed sources - * //will start in the correct position - * source.sync().start(0.1); - * //the source will be invoked with an offset of 0.4 - * Tone.Transport.start("+0.5", 0.5); - */ - Tone.Source.prototype.sync = function () { - this._synced = true; - Tone.Transport.on('start loopStart', function (time, offset) { - if (offset > 0) { - // get the playback state at that time - var stateEvent = this._state.get(offset); - // listen for start events which may occur in the middle of the sync'ed time - if (stateEvent && stateEvent.state === Tone.State.Started && stateEvent.time !== offset) { - // get the offset - var startOffset = offset - this.toSeconds(stateEvent.time); - var duration; - if (stateEvent.duration) { - duration = this.toSeconds(stateEvent.duration) - startOffset; - } - this._start(time, this.toSeconds(stateEvent.offset) + startOffset, duration); - } - } - }.bind(this)); - Tone.Transport.on('stop pause loopEnd', function (time) { - if (this._state.getValueAtTime(Tone.Transport.seconds) === Tone.State.Started) { - this._stop(time); - } - }.bind(this)); - return this; - }; - /** - * Unsync the source to the Transport. See Tone.Source.sync - * @returns {Tone.Source} this - */ - Tone.Source.prototype.unsync = function () { - this._synced = false; - Tone.Transport.off('start stop pause loopEnd loopStart'); - // clear all of the scheduled ids - for (var i = 0; i < this._scheduled.length; i++) { - var id = this._scheduled[i]; - Tone.Transport.clear(id); - } - this._scheduled = []; - this._state.cancel(0); - return this; - }; - /** - * Clean up. - * @return {Tone.Source} this - */ - Tone.Source.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this.unsync(); - this._scheduled = null; - this._writable('volume'); - this._volume.dispose(); - this._volume = null; - this.volume = null; - this._state.dispose(); - this._state = null; - }; - return Tone.Source; - }); - Module(function (Tone) { - - /** - * OscillatorNode shim - * @private - */ - if (window.OscillatorNode && !OscillatorNode.prototype.start) { - OscillatorNode.prototype.start = OscillatorNode.prototype.noteOn; - OscillatorNode.prototype.stop = OscillatorNode.prototype.noteOff; - if (!OscillatorNode.prototype.setPeriodicWave) { - OscillatorNode.prototype.setPeriodicWave = OscillatorNode.prototype.setWaveTable; - } - if (!AudioContext.prototype.createPeriodicWave) { - AudioContext.prototype.createPeriodicWave = AudioContext.prototype.createWaveTable; - } - } - /** - * @class Tone.Oscillator supports a number of features including - * phase rotation, multiple oscillator types (see Tone.Oscillator.type), - * and Transport syncing (see Tone.Oscillator.syncFrequency). - * - * @constructor - * @extends {Tone.Source} - * @param {Frequency} [frequency] Starting frequency - * @param {string} [type] The oscillator type. Read more about type below. - * @example - * //make and start a 440hz sine tone - * var osc = new Tone.Oscillator(440, "sine").toMaster().start(); - */ - Tone.Oscillator = function () { - var options = this.optionsObject(arguments, [ - 'frequency', - 'type' - ], Tone.Oscillator.defaults); - Tone.Source.call(this, options); - /** - * the main oscillator - * @type {OscillatorNode} - * @private - */ - this._oscillator = null; - /** - * The frequency control. - * @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 periodic wave - * @type {PeriodicWave} - * @private - */ - this._wave = null; - /** - * The partials of the oscillator - * @type {Array} - * @private - */ - this._partials = this.defaultArg(options.partials, [1]); - /** - * the phase of the oscillator - * between 0 - 360 - * @type {number} - * @private - */ - this._phase = options.phase; - /** - * the type of the oscillator - * @type {string} - * @private - */ - this._type = null; - //setup - this.type = options.type; - this.phase = this._phase; - this._readOnly([ - 'frequency', - 'detune' - ]); - }; - Tone.extend(Tone.Oscillator, Tone.Source); - /** - * the default parameters - * @type {Object} - */ - Tone.Oscillator.defaults = { - 'type': 'sine', - 'frequency': 440, - 'detune': 0, - 'phase': 0, - 'partials': [] - }; - /** - * The Oscillator types - * @enum {String} - */ - Tone.Oscillator.Type = { - Sine: 'sine', - Triangle: 'triangle', - Sawtooth: 'sawtooth', - Square: 'square', - Custom: 'custom' - }; - /** - * start the oscillator - * @param {Time} [time=now] - * @private - */ - Tone.Oscillator.prototype._start = function (time) { - //new oscillator with previous values - this._oscillator = this.context.createOscillator(); - this._oscillator.setPeriodicWave(this._wave); - //connect the control signal to the oscillator frequency & detune - this._oscillator.connect(this.output); - this.frequency.connect(this._oscillator.frequency); - this.detune.connect(this._oscillator.detune); - //start the oscillator - this._oscillator.start(this.toSeconds(time)); - }; - /** - * stop the oscillator - * @private - * @param {Time} [time=now] (optional) timing parameter - * @returns {Tone.Oscillator} this - */ - Tone.Oscillator.prototype._stop = function (time) { - if (this._oscillator) { - this._oscillator.stop(this.toSeconds(time)); - this._oscillator = null; - } - return this; - }; - /** - * Sync the signal to the Transport's bpm. Any changes to the transports bpm, - * will also affect the oscillators frequency. - * @returns {Tone.Oscillator} this - * @example - * Tone.Transport.bpm.value = 120; - * osc.frequency.value = 440; - * //the ration between the bpm and the frequency will be maintained - * osc.syncFrequency(); - * Tone.Transport.bpm.value = 240; - * // the frequency of the oscillator is doubled to 880 - */ - Tone.Oscillator.prototype.syncFrequency = function () { - Tone.Transport.syncSignal(this.frequency); - return this; - }; - /** - * Unsync the oscillator's frequency from the Transport. - * See Tone.Oscillator.syncFrequency - * @returns {Tone.Oscillator} this - */ - Tone.Oscillator.prototype.unsyncFrequency = function () { - Tone.Transport.unsyncSignal(this.frequency); - return this; - }; - /** - * The type of the oscillator: either sine, square, triangle, or sawtooth. Also capable of - * setting the first x number of partials of the oscillator. For example: "sine4" would - * set be the first 4 partials of the sine wave and "triangle8" would set the first - * 8 partials of the triangle wave. - * <br><br> - * Uses PeriodicWave internally even for native types so that it can set the phase. - * PeriodicWave equations are from the - * [Webkit Web Audio implementation](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp&sq=package:chromium). - * - * @memberOf Tone.Oscillator# - * @type {string} - * @name type - * @example - * //set it to a square wave - * osc.type = "square"; - * @example - * //set the first 6 partials of a sawtooth wave - * osc.type = "sawtooth6"; - */ - Object.defineProperty(Tone.Oscillator.prototype, 'type', { - get: function () { - return this._type; - }, - set: function (type) { - var coefs = this._getRealImaginary(type, this._phase); - var periodicWave = this.context.createPeriodicWave(coefs[0], coefs[1]); - this._wave = periodicWave; - if (this._oscillator !== null) { - this._oscillator.setPeriodicWave(this._wave); - } - this._type = type; - } - }); - /** - * Returns the real and imaginary components based - * on the oscillator type. - * @returns {Array} [real, imaginary] - * @private - */ - Tone.Oscillator.prototype._getRealImaginary = function (type, phase) { - var fftSize = 4096; - var periodicWaveSize = fftSize / 2; - var real = new Float32Array(periodicWaveSize); - var imag = new Float32Array(periodicWaveSize); - var partialCount = 1; - if (type === Tone.Oscillator.Type.Custom) { - partialCount = this._partials.length + 1; - periodicWaveSize = partialCount; - } else { - var partial = /^(sine|triangle|square|sawtooth)(\d+)$/.exec(type); - if (partial) { - partialCount = parseInt(partial[2]) + 1; - type = partial[1]; - partialCount = Math.max(partialCount, 2); - periodicWaveSize = partialCount; - } - } - for (var n = 1; n < periodicWaveSize; ++n) { - var piFactor = 2 / (n * Math.PI); - var b; - switch (type) { - case Tone.Oscillator.Type.Sine: - b = n <= partialCount ? 1 : 0; - break; - case Tone.Oscillator.Type.Square: - b = n & 1 ? 2 * piFactor : 0; - break; - case Tone.Oscillator.Type.Sawtooth: - b = piFactor * (n & 1 ? 1 : -1); - break; - case Tone.Oscillator.Type.Triangle: - if (n & 1) { - b = 2 * (piFactor * piFactor) * (n - 1 >> 1 & 1 ? -1 : 1); - } else { - b = 0; - } - break; - case Tone.Oscillator.Type.Custom: - b = this._partials[n - 1]; - break; - default: - throw new TypeError('Tone.Oscillator: invalid type: ' + type); - } - if (b !== 0) { - real[n] = -b * Math.sin(phase * n); - imag[n] = b * Math.cos(phase * n); - } else { - real[n] = 0; - imag[n] = 0; - } - } - return [ - real, - imag - ]; - }; - /** - * Compute the inverse FFT for a given phase. - * @param {Float32Array} real - * @param {Float32Array} imag - * @param {NormalRange} phase - * @return {AudioRange} - * @private - */ - Tone.Oscillator.prototype._inverseFFT = function (real, imag, phase) { - var sum = 0; - var len = real.length; - for (var i = 0; i < len; i++) { - sum += real[i] * Math.cos(i * phase) + imag[i] * Math.sin(i * phase); - } - return sum; - }; - /** - * Returns the initial value of the oscillator. - * @return {AudioRange} - * @private - */ - Tone.Oscillator.prototype._getInitialValue = function () { - var coefs = this._getRealImaginary(this._type, 0); - var real = coefs[0]; - var imag = coefs[1]; - var maxValue = 0; - var twoPi = Math.PI * 2; - //check for peaks in 8 places - for (var i = 0; i < 8; i++) { - maxValue = Math.max(this._inverseFFT(real, imag, i / 8 * twoPi), maxValue); - } - return -this._inverseFFT(real, imag, this._phase) / maxValue; - }; - /** - * 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". - * @memberOf Tone.Oscillator# - * @type {Array} - * @name partials - * @example - * osc.partials = [1, 0.2, 0.01]; - */ - Object.defineProperty(Tone.Oscillator.prototype, 'partials', { - get: function () { - if (this._type !== Tone.Oscillator.Type.Custom) { - return []; - } else { - return this._partials; - } - }, - set: function (partials) { - this._partials = partials; - this.type = Tone.Oscillator.Type.Custom; - } - }); - /** - * The phase of the oscillator in degrees. - * @memberOf Tone.Oscillator# - * @type {Degrees} - * @name phase - * @example - * osc.phase = 180; //flips the phase of the oscillator - */ - Object.defineProperty(Tone.Oscillator.prototype, 'phase', { - get: function () { - return this._phase * (180 / Math.PI); - }, - set: function (phase) { - this._phase = phase * Math.PI / 180; - //reset the type - this.type = this._type; - } - }); - /** - * Dispose and disconnect. - * @return {Tone.Oscillator} this - */ - Tone.Oscillator.prototype.dispose = function () { - Tone.Source.prototype.dispose.call(this); - if (this._oscillator !== null) { - this._oscillator.disconnect(); - this._oscillator = null; - } - this._wave = null; - this._writable([ - 'frequency', - 'detune' - ]); - this.frequency.dispose(); - this.frequency = null; - this.detune.dispose(); - this.detune = null; - this._partials = null; - return this; - }; - return Tone.Oscillator; - }); - Module(function (Tone) { - /** - * @class Tone.Zero outputs 0's at audio-rate. The reason this has to be - * it's own class is that many browsers optimize out Tone.Signal - * with a value of 0 and will not process nodes further down the graph. - * @extends {Tone} - */ - Tone.Zero = function () { - /** - * The gain node - * @type {Tone.Gain} - * @private - */ - this._gain = this.input = this.output = new Tone.Gain(); - this.context.getConstant(0).connect(this._gain); - }; - Tone.extend(Tone.Zero); - /** - * clean up - * @return {Tone.Zero} this - */ - Tone.Zero.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._gain.dispose(); - this._gain = null; - return this; - }; - return Tone.Zero; - }); - Module(function (Tone) { - - /** - * @class LFO stands for low frequency oscillator. Tone.LFO produces an output signal - * which can be attached to an AudioParam or Tone.Signal - * in order to modulate that parameter with an oscillator. The LFO can - * also be synced to the transport to start/stop and change when the tempo changes. - * - * @constructor - * @extends {Tone.Oscillator} - * @param {Frequency|Object} [frequency] The frequency of the oscillation. Typically, LFOs will be - * in the frequency range of 0.1 to 10 hertz. - * @param {number=} min The minimum output value of the LFO. - * @param {number=} max The maximum value of the LFO. - * @example - * var lfo = new Tone.LFO("4n", 400, 4000); - * lfo.connect(filter.frequency); - */ - Tone.LFO = function () { - var options = this.optionsObject(arguments, [ - 'frequency', - 'min', - 'max' - ], Tone.LFO.defaults); - /** - * The oscillator. - * @type {Tone.Oscillator} - * @private - */ - this._oscillator = new Tone.Oscillator({ - 'frequency': options.frequency, - 'type': options.type - }); - /** - * the lfo's frequency - * @type {Frequency} - * @signal - */ - this.frequency = this._oscillator.frequency; - /** - * The amplitude of the LFO, which controls the output range between - * the min and max output. For example if the min is -10 and the max - * is 10, setting the amplitude to 0.5 would make the LFO modulate - * between -5 and 5. - * @type {Number} - * @signal - */ - this.amplitude = this._oscillator.volume; - this.amplitude.units = Tone.Type.NormalRange; - this.amplitude.value = options.amplitude; - /** - * The signal which is output when the LFO is stopped - * @type {Tone.Signal} - * @private - */ - this._stoppedSignal = new Tone.Signal(0, Tone.Type.AudioRange); - /** - * Just outputs zeros. - * @type {Tone.Zero} - * @private - */ - this._zeros = new Tone.Zero(); - /** - * The value that the LFO outputs when it's stopped - * @type {AudioRange} - * @private - */ - this._stoppedValue = 0; - /** - * @type {Tone.AudioToGain} - * @private - */ - this._a2g = new Tone.AudioToGain(); - /** - * @type {Tone.Scale} - * @private - */ - this._scaler = this.output = new Tone.Scale(options.min, options.max); - /** - * the units of the LFO (used for converting) - * @type {Tone.Type} - * @private - */ - this._units = Tone.Type.Default; - this.units = options.units; - //connect it up - this._oscillator.chain(this._a2g, this._scaler); - this._zeros.connect(this._a2g); - this._stoppedSignal.connect(this._a2g); - this._readOnly([ - 'amplitude', - 'frequency' - ]); - this.phase = options.phase; - }; - Tone.extend(Tone.LFO, Tone.Oscillator); - /** - * the default parameters - * - * @static - * @const - * @type {Object} - */ - Tone.LFO.defaults = { - 'type': 'sine', - 'min': 0, - 'max': 1, - 'phase': 0, - 'frequency': '4n', - 'amplitude': 1, - 'units': Tone.Type.Default - }; - /** - * Start the LFO. - * @param {Time} [time=now] the time the LFO will start - * @returns {Tone.LFO} this - */ - Tone.LFO.prototype.start = function (time) { - time = this.toSeconds(time); - this._stoppedSignal.setValueAtTime(0, time); - this._oscillator.start(time); - return this; - }; - /** - * Stop the LFO. - * @param {Time} [time=now] the time the LFO will stop - * @returns {Tone.LFO} this - */ - Tone.LFO.prototype.stop = function (time) { - time = this.toSeconds(time); - this._stoppedSignal.setValueAtTime(this._stoppedValue, time); - this._oscillator.stop(time); - return this; - }; - /** - * Sync the start/stop/pause to the transport - * and the frequency to the bpm of the transport - * @returns {Tone.LFO} this - * @example - * lfo.frequency.value = "8n"; - * lfo.sync().start(0) - * //the rate of the LFO will always be an eighth note, - * //even as the tempo changes - */ - Tone.LFO.prototype.sync = function () { - this._oscillator.sync(); - this._oscillator.syncFrequency(); - return this; - }; - /** - * unsync the LFO from transport control - * @returns {Tone.LFO} this - */ - Tone.LFO.prototype.unsync = function () { - this._oscillator.unsync(); - this._oscillator.unsyncFrequency(); - return this; - }; - /** - * The miniumum output of the LFO. - * @memberOf Tone.LFO# - * @type {number} - * @name min - */ - Object.defineProperty(Tone.LFO.prototype, 'min', { - get: function () { - return this._toUnits(this._scaler.min); - }, - set: function (min) { - min = this._fromUnits(min); - this._scaler.min = min; - } - }); - /** - * The maximum output of the LFO. - * @memberOf Tone.LFO# - * @type {number} - * @name max - */ - Object.defineProperty(Tone.LFO.prototype, 'max', { - get: function () { - return this._toUnits(this._scaler.max); - }, - set: function (max) { - max = this._fromUnits(max); - this._scaler.max = max; - } - }); - /** - * The type of the oscillator: sine, square, sawtooth, triangle. - * @memberOf Tone.LFO# - * @type {string} - * @name type - */ - Object.defineProperty(Tone.LFO.prototype, 'type', { - get: function () { - return this._oscillator.type; - }, - set: function (type) { - this._oscillator.type = type; - this._stoppedValue = this._oscillator._getInitialValue(); - this._stoppedSignal.value = this._stoppedValue; - } - }); - /** - * The phase of the LFO. - * @memberOf Tone.LFO# - * @type {number} - * @name phase - */ - Object.defineProperty(Tone.LFO.prototype, 'phase', { - get: function () { - return this._oscillator.phase; - }, - set: function (phase) { - this._oscillator.phase = phase; - this._stoppedValue = this._oscillator._getInitialValue(); - this._stoppedSignal.value = this._stoppedValue; - } - }); - /** - * The output units of the LFO. - * @memberOf Tone.LFO# - * @type {Tone.Type} - * @name units - */ - Object.defineProperty(Tone.LFO.prototype, 'units', { - get: function () { - return this._units; - }, - set: function (val) { - var currentMin = this.min; - var currentMax = this.max; - //convert the min and the max - this._units = val; - this.min = currentMin; - this.max = currentMax; - } - }); - /** - * Mute the output. - * @memberOf Tone.LFO# - * @type {Boolean} - * @name mute - */ - Object.defineProperty(Tone.LFO.prototype, 'mute', { - get: function () { - return this._oscillator.mute; - }, - set: function (mute) { - this._oscillator.mute = mute; - } - }); - /** - * Returns the playback state of the source, either "started" or "stopped". - * @type {Tone.State} - * @readOnly - * @memberOf Tone.LFO# - * @name state - */ - Object.defineProperty(Tone.LFO.prototype, 'state', { - get: function () { - return this._oscillator.state; - } - }); - /** - * Connect the output of the LFO to an AudioParam, AudioNode, or Tone Node. - * Tone.LFO will automatically convert to the destination units of the - * will get the units from the connected node. - * @param {Tone | AudioParam | AudioNode} node - * @param {number} [outputNum=0] optionally which output to connect from - * @param {number} [inputNum=0] optionally which input to connect to - * @returns {Tone.LFO} this - * @private - */ - Tone.LFO.prototype.connect = function (node) { - if (node.constructor === Tone.Signal || node.constructor === Tone.Param || node.constructor === Tone.TimelineSignal) { - this.convert = node.convert; - this.units = node.units; - } - Tone.Signal.prototype.connect.apply(this, arguments); - return this; - }; - /** - * private method borrowed from Param converts - * units from their destination value - * @function - * @private - */ - Tone.LFO.prototype._fromUnits = Tone.Param.prototype._fromUnits; - /** - * private method borrowed from Param converts - * units to their destination value - * @function - * @private - */ - Tone.LFO.prototype._toUnits = Tone.Param.prototype._toUnits; - /** - * disconnect and dispose - * @returns {Tone.LFO} this - */ - Tone.LFO.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._writable([ - 'amplitude', - 'frequency' - ]); - this._oscillator.dispose(); - this._oscillator = null; - this._stoppedSignal.dispose(); - this._stoppedSignal = null; - this._zeros.dispose(); - this._zeros = null; - this._scaler.dispose(); - this._scaler = null; - this._a2g.dispose(); - this._a2g = null; - this.frequency = null; - this.amplitude = null; - return this; - }; - return Tone.LFO; - }); - Module(function (Tone) { - - /** - * @class Tone.Limiter will limit the loudness of an incoming signal. - * It is composed of a Tone.Compressor with a fast attack - * and release. Limiters are commonly used to safeguard against - * signal clipping. Unlike a compressor, limiters do not provide - * smooth gain reduction and almost completely prevent - * additional gain above the threshold. - * - * @extends {Tone} - * @constructor - * @param {number} threshold The theshold above which the limiting is applied. - * @example - * var limiter = new Tone.Limiter(-6); - */ - Tone.Limiter = function () { - var options = this.optionsObject(arguments, ['threshold'], Tone.Limiter.defaults); - /** - * the compressor - * @private - * @type {Tone.Compressor} - */ - this._compressor = this.input = this.output = new Tone.Compressor({ - 'attack': 0.001, - 'decay': 0.001, - 'threshold': options.threshold - }); - /** - * The threshold of of the limiter - * @type {Decibel} - * @signal - */ - this.threshold = this._compressor.threshold; - this._readOnly('threshold'); - }; - Tone.extend(Tone.Limiter); - /** - * The default value - * @type {Object} - * @const - * @static - */ - Tone.Limiter.defaults = { 'threshold': -12 }; - /** - * Clean up. - * @returns {Tone.Limiter} this - */ - Tone.Limiter.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._compressor.dispose(); - this._compressor = null; - this._writable('threshold'); - this.threshold = null; - return this; - }; - return Tone.Limiter; - }); - Module(function (Tone) { - - /** - * @class Tone.Lowpass is a lowpass feedback comb filter. It is similar to - * Tone.FeedbackCombFilter, but includes a lowpass filter. - * - * @extends {Tone} - * @constructor - * @param {Time|Object} [delayTime] The delay time of the comb filter - * @param {NormalRange=} resonance The resonance (feedback) of the comb filter - * @param {Frequency=} dampening The cutoff of the lowpass filter dampens the - * signal as it is fedback. - */ - Tone.LowpassCombFilter = function () { - this.createInsOuts(1, 1); - var options = this.optionsObject(arguments, [ - 'delayTime', - 'resonance', - 'dampening' - ], Tone.LowpassCombFilter.defaults); - /** - * the delay node - * @type {DelayNode} - * @private - */ - this._delay = this.input = new Tone.Delay(options.delayTime); - /** - * The delayTime of the comb filter. - * @type {Time} - * @signal - */ - this.delayTime = this._delay.delayTime; - /** - * the lowpass filter - * @type {BiquadFilterNode} - * @private - */ - this._lowpass = this.output = this.context.createBiquadFilter(); - this._lowpass.Q.value = -3.0102999566398125; - this._lowpass.type = 'lowpass'; - /** - * The dampening control of the feedback - * @type {Frequency} - * @signal - */ - this.dampening = new Tone.Param({ - 'param': this._lowpass.frequency, - 'units': Tone.Type.Frequency, - 'value': options.dampening - }); - /** - * the feedback gain - * @type {Tone.Gain} - * @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; - //connections - this._delay.chain(this._lowpass, this._feedback, this._delay); - this._readOnly([ - 'dampening', - 'resonance', - 'delayTime' - ]); - }; - Tone.extend(Tone.LowpassCombFilter); - /** - * the default parameters - * @static - * @const - * @type {Object} - */ - Tone.LowpassCombFilter.defaults = { - 'delayTime': 0.1, - 'resonance': 0.5, - 'dampening': 3000 - }; - /** - * Clean up. - * @returns {Tone.LowpassCombFilter} this - */ - Tone.LowpassCombFilter.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._writable([ - 'dampening', - 'resonance', - 'delayTime' - ]); - this.dampening.dispose(); - this.dampening = null; - this.resonance.dispose(); - this.resonance = null; - this._delay.dispose(); - this._delay = null; - this.delayTime = null; - this._lowpass.disconnect(); - this._lowpass = null; - this._feedback.disconnect(); - this._feedback = null; - return this; - }; - return Tone.LowpassCombFilter; - }); - Module(function (Tone) { - - /** - * @class Tone.Merge brings two signals into the left and right - * channels of a single stereo channel. - * - * @constructor - * @extends {Tone} - * @example - * var merge = new Tone.Merge().toMaster(); - * //routing a sine tone in the left channel - * //and noise in the right channel - * var osc = new Tone.Oscillator().connect(merge.left); - * var noise = new Tone.Noise().connect(merge.right); - * //starting our oscillators - * noise.start(); - * osc.start(); - */ - Tone.Merge = function () { - this.createInsOuts(2, 0); - /** - * The left input channel. - * Alias for <code>input[0]</code> - * @type {GainNode} - */ - this.left = this.input[0] = new Tone.Gain(); - /** - * The right input channel. - * Alias for <code>input[1]</code>. - * @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); - /** - * Clean up. - * @returns {Tone.Merge} this - */ - Tone.Merge.prototype.dispose = function () { - Tone.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} - * @param {String} type Either "level" or "signal". - * @param {Number} smoothing The amount of smoothing applied between frames. - * @example - * var meter = new Tone.Meter(); - * var mic = new Tone.UserMedia().start(); - * //connect mic to the meter - * mic.connect(meter); - * //the current level of the mic input - * var level = meter.value; - */ - Tone.Meter = function () { - var options = this.optionsObject(arguments, [ - 'type', - 'smoothing' - ], Tone.Meter.defaults); - /** - * The type of the meter, either "level" or "signal". - * A "level" meter will return the volume level (rms) of the - * input signal and a "signal" meter will return - * the signal value of the input. - * @type {String} - */ - this.type = options.type; - /** - * The analyser node which computes the levels. - * @private - * @type {Tone.Analyser} - */ - this.input = this.output = this._analyser = new Tone.Analyser('waveform', 512); - this._analyser.returnType = 'float'; - /** - * The amount of carryover between the current and last frame. - * Only applied meter for "level" type. - * @type {Number} - */ - this.smoothing = options.smoothing; - /** - * The last computed value - * @type {Number} - * @private - */ - this._lastValue = 0; - }; - Tone.extend(Tone.Meter); - /** - * @private - * @enum {String} - */ - Tone.Meter.Type = { - Level: 'level', - Signal: 'signal' - }; - /** - * The defaults - * @type {Object} - * @static - * @const - */ - Tone.Meter.defaults = { - 'smoothing': 0.8, - 'type': Tone.Meter.Type.Level - }; - /** - * The current value of the meter. A value of 1 is - * "unity". - * @memberOf Tone.Meter# - * @type {Number} - * @name value - * @readOnly - */ - Object.defineProperty(Tone.Meter.prototype, 'value', { - get: function () { - var signal = this._analyser.analyse(); - if (this.type === Tone.Meter.Type.Level) { - //rms - var sum = 0; - for (var i = 0; i < signal.length; i++) { - sum += Math.pow(signal[i], 2); - } - var rms = Math.sqrt(sum / signal.length); - //smooth it - rms = Math.max(rms, this._lastValue * this.smoothing); - this._lastValue = rms; - //scale it - var unity = 0.35; - var val = rms / unity; - //scale the output curve - return Math.sqrt(val); - } else { - return signal[0]; - } - } - }); - /** - * Clean up. - * @returns {Tone.Meter} this - */ - Tone.Meter.prototype.dispose = function () { - Tone.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} - * @example - * var split = new Tone.Split(); - * stereoSignal.connect(split); - */ - Tone.Split = function () { - this.createInsOuts(0, 2); - /** - * @type {ChannelSplitterNode} - * @private - */ - this._splitter = this.input = this.context.createChannelSplitter(2); - /** - * Left channel output. - * Alias for <code>output[0]</code> - * @type {Tone.Gain} - */ - this.left = this.output[0] = new Tone.Gain(); - /** - * Right channel output. - * Alias for <code>output[1]</code> - * @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); - /** - * Clean up. - * @returns {Tone.Split} this - */ - Tone.Split.prototype.dispose = function () { - Tone.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). <br><br> - * <code> - * Mid = (Left+Right)/sqrt(2); // obtain mid-signal from left and right<br> - * Side = (Left-Right)/sqrt(2); // obtain side-signal from left and righ<br> - * </code> - * - * @extends {Tone} - * @constructor - */ - Tone.MidSideSplit = function () { - 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 - * <code>output[0]</code> - * @type {Tone.Expr} - */ - this.mid = this.output[0] = new Tone.Expr('($0 + $1) * $2'); - /** - * The side output. Connect to side processing. Alias for - * <code>output[1]</code> - * @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); - /** - * clean up - * @returns {Tone.MidSideSplit} this - */ - Tone.MidSideSplit.prototype.dispose = function () { - Tone.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.<br><br> - * <code> - * Left = (Mid+Side)/sqrt(2); // obtain left signal from mid and side<br> - * Right = (Mid-Side)/sqrt(2); // obtain right signal from mid and side<br> - * </code> - * - * @extends {Tone.StereoEffect} - * @constructor - */ - Tone.MidSideMerge = function () { - this.createInsOuts(2, 0); - /** - * The mid signal input. Alias for - * <code>input[0]</code> - * @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 - * <code>input[1]</code> - * @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); - /** - * clean up - * @returns {Tone.MidSideMerge} this - */ - Tone.MidSideMerge.prototype.dispose = function () { - Tone.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} - * @param {Object} options The options that are passed to the mid and side - * compressors. - * @constructor - */ - Tone.MidSideCompressor = function (options) { - options = this.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); - /** - * @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.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} - * @constructor - */ - Tone.Mono = function () { - 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 = this.dbToGain(-10); - }; - Tone.extend(Tone.Mono); - /** - * clean up - * @returns {Tone.Mono} this - */ - Tone.Mono.prototype.dispose = function () { - Tone.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} - * @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) { - options = this.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); - /** - * @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.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} - * @param {NormalRange} [initialPan=0] The initail panner value (defaults to 0 = center) - * @example - * //pan the input signal hard right. - * var panner = new Tone.Panner(1); - */ - Tone.Panner = function (initialPan) { - if (this._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 = this.defaultArg(initialPan, 0); - this._readOnly('pan'); - }; - Tone.extend(Tone.Panner); - /** - * indicates if the panner is using the new StereoPannerNode internally - * @type {boolean} - * @private - */ - Tone.Panner.prototype._hasStereoPanner = Tone.prototype.isFunction(Tone.context.createStereoPanner); - /** - * Clean up. - * @returns {Tone.Panner} this - */ - Tone.Panner.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._writable('pan'); - if (this._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} - * @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 = this.optionsObject(arguments, [ - 'positionX', - 'positionY', - 'positionZ' - ], Tone.Panner3D.defaults); - /** - * 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); - /** - * the default parameters - * @static - * @const - * @type {Object} - * Defaults according to the specification - */ - 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 () { - 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} - * @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 = this.optionsObject(arguments, [ - 'pan', - 'volume' - ], Tone.PanVol.defaults); - /** - * 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} - */ - 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._readOnly([ - 'pan', - 'volume' - ]); - }; - Tone.extend(Tone.PanVol); - /** - * The defaults - * @type {Object} - * @const - * @static - */ - Tone.PanVol.defaults = { - 'pan': 0.5, - 'volume': 0 - }; - /** - * clean up - * @returns {Tone.PanVol} this - */ - Tone.PanVol.prototype.dispose = function () { - Tone.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.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 = this.optionsObject(arguments, [ - 'values', - 'index' - ], Tone.CtrlInterpolate.defaults); - /** - * 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 (this.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 (this.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 (this.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) { - /** - * The Markov values with states as the keys - * and next state(s) as the values. - * @type {Object} - */ - this.values = this.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 = this.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 (this.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 (this.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 (this.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. - * <ul> - * <li>"up" - cycles upward</li> - * <li>"down" - cycles downward</li> - * <li>"upDown" - up then and down</li> - * <li>"downUp" - cycles down then and up</li> - * <li>"alternateUp" - jump up two and down one</li> - * <li>"alternateDown" - jump down two and up one</li> - * <li>"random" - randomly select an index</li> - * <li>"randomWalk" - randomly moves one index away from the current position</li> - * <li>"randomOnce" - randomly select an index without repeating until all values have been chosen.</li> - * </ul> - * @param {Array} values An array of options to choose from. - * @param {Tone.CtrlPattern.Type=} type The name of the pattern. - * @extends {Tone} - */ - Tone.CtrlPattern = function () { - var options = this.optionsObject(arguments, [ - 'values', - 'type' - ], Tone.CtrlPattern.defaults); - /** - * The array of values to arpeggiate over - * @type {Array} - */ - this.values = options.values; - /** - * The current position in the values array - * @type {Number} - */ - this.index = 0; - /** - * The type placeholder - * @type {Tone.CtrlPattern.Type} - * @private - */ - this._type = null; - /** - * Shuffled values for the RandomOnce type - * @type {Array} - * @private - */ - this._shuffled = null; - /** - * The direction of the movement - * @type {String} - * @private - */ - this._direction = null; - this.type = options.type; - }; - Tone.extend(Tone.CtrlPattern); - /** - * The Control Patterns - * @type {Object} - * @static - */ - Tone.CtrlPattern.Type = { - Up: 'up', - Down: 'down', - UpDown: 'upDown', - DownUp: 'downUp', - AlternateUp: 'alternateUp', - AlternateDown: 'alternateDown', - Random: 'random', - RandomWalk: 'randomWalk', - RandomOnce: 'randomOnce' - }; - /** - * The default values. - * @type {Object} - */ - Tone.CtrlPattern.defaults = { - 'type': Tone.CtrlPattern.Type.Up, - 'values': [] - }; - /** - * The value at the current index of the pattern. - * @readOnly - * @memberOf Tone.CtrlPattern# - * @type {*} - * @name value - */ - Object.defineProperty(Tone.CtrlPattern.prototype, 'value', { - get: function () { - //some safeguards - if (this.values.length === 0) { - return; - } else if (this.values.length === 1) { - return this.values[0]; - } - this.index = Math.min(this.index, this.values.length - 1); - var val = this.values[this.index]; - if (this.type === Tone.CtrlPattern.Type.RandomOnce) { - if (this.values.length !== this._shuffled.length) { - this._shuffleValues(); - } - val = this.values[this._shuffled[this.index]]; - } - return val; - } - }); - /** - * The pattern used to select the next - * item from the values array - * @memberOf Tone.CtrlPattern# - * @type {Tone.CtrlPattern.Type} - * @name type - */ - Object.defineProperty(Tone.CtrlPattern.prototype, 'type', { - get: function () { - return this._type; - }, - set: function (type) { - this._type = type; - this._shuffled = null; - //the first index - if (this._type === Tone.CtrlPattern.Type.Up || this._type === Tone.CtrlPattern.Type.UpDown || this._type === Tone.CtrlPattern.Type.RandomOnce || this._type === Tone.CtrlPattern.Type.AlternateUp) { - this.index = 0; - } else if (this._type === Tone.CtrlPattern.Type.Down || this._type === Tone.CtrlPattern.Type.DownUp || this._type === Tone.CtrlPattern.Type.AlternateDown) { - this.index = this.values.length - 1; - } - //the direction - if (this._type === Tone.CtrlPattern.Type.UpDown || this._type === Tone.CtrlPattern.Type.AlternateUp) { - this._direction = Tone.CtrlPattern.Type.Up; - } else if (this._type === Tone.CtrlPattern.Type.DownUp || this._type === Tone.CtrlPattern.Type.AlternateDown) { - this._direction = Tone.CtrlPattern.Type.Down; - } - //randoms - if (this._type === Tone.CtrlPattern.Type.RandomOnce) { - this._shuffleValues(); - } else if (this._type === Tone.CtrlPattern.Random) { - this.index = Math.floor(Math.random() * this.values.length); - } - } - }); - /** - * Return the next value given the current position - * and pattern. - * @return {*} The next value - */ - Tone.CtrlPattern.prototype.next = function () { - var type = this.type; - //choose the next index - if (type === Tone.CtrlPattern.Type.Up) { - this.index++; - if (this.index >= this.values.length) { - this.index = 0; - } - } else if (type === Tone.CtrlPattern.Type.Down) { - this.index--; - if (this.index < 0) { - this.index = this.values.length - 1; - } - } else if (type === Tone.CtrlPattern.Type.UpDown || type === Tone.CtrlPattern.Type.DownUp) { - if (this._direction === Tone.CtrlPattern.Type.Up) { - this.index++; - } else { - this.index--; - } - if (this.index < 0) { - this.index = 1; - this._direction = Tone.CtrlPattern.Type.Up; - } else if (this.index >= this.values.length) { - this.index = this.values.length - 2; - this._direction = Tone.CtrlPattern.Type.Down; - } - } else if (type === Tone.CtrlPattern.Type.Random) { - this.index = Math.floor(Math.random() * this.values.length); - } else if (type === Tone.CtrlPattern.Type.RandomWalk) { - if (Math.random() < 0.5) { - this.index--; - this.index = Math.max(this.index, 0); - } else { - this.index++; - this.index = Math.min(this.index, this.values.length - 1); - } - } else if (type === Tone.CtrlPattern.Type.RandomOnce) { - this.index++; - if (this.index >= this.values.length) { - this.index = 0; - //reshuffle the values for next time - this._shuffleValues(); - } - } else if (type === Tone.CtrlPattern.Type.AlternateUp) { - if (this._direction === Tone.CtrlPattern.Type.Up) { - this.index += 2; - this._direction = Tone.CtrlPattern.Type.Down; - } else { - this.index -= 1; - this._direction = Tone.CtrlPattern.Type.Up; - } - if (this.index >= this.values.length) { - this.index = 0; - this._direction = Tone.CtrlPattern.Type.Up; - } - } else if (type === Tone.CtrlPattern.Type.AlternateDown) { - if (this._direction === Tone.CtrlPattern.Type.Up) { - this.index += 1; - this._direction = Tone.CtrlPattern.Type.Down; - } else { - this.index -= 2; - this._direction = Tone.CtrlPattern.Type.Up; - } - if (this.index < 0) { - this.index = this.values.length - 1; - this._direction = Tone.CtrlPattern.Type.Down; - } - } - return this.value; - }; - /** - * Shuffles the values and places the results into the _shuffled - * @private - */ - Tone.CtrlPattern.prototype._shuffleValues = function () { - var copy = []; - this._shuffled = []; - for (var i = 0; i < this.values.length; i++) { - copy[i] = i; - } - while (copy.length > 0) { - var randVal = copy.splice(Math.floor(copy.length * Math.random()), 1); - this._shuffled.push(randVal[0]); - } - }; - /** - * Clean up - * @returns {Tone.CtrlPattern} this - */ - Tone.CtrlPattern.prototype.dispose = function () { - this._shuffled = null; - this.values = null; - }; - return Tone.CtrlPattern; - }); - Module(function (Tone) { - - /** - * @class Choose a random value. - * @extends {Tone} - * @example - * var randomWalk = new Tone.CtrlRandom({ - * "min" : 0, - * "max" : 10, - * "integer" : true - * }); - * randomWalk.eval(); - * - * @param {Number|Time=} min The minimum return value. - * @param {Number|Time=} max The maximum return value. - */ - Tone.CtrlRandom = function () { - var options = this.optionsObject(arguments, [ - 'min', - 'max' - ], Tone.CtrlRandom.defaults); - /** - * The minimum return value - * @type {Number|Time} - */ - this.min = options.min; - /** - * The maximum return value - * @type {Number|Time} - */ - this.max = options.max; - /** - * If the return value should be an integer - * @type {Boolean} - */ - this.integer = options.integer; - }; - Tone.extend(Tone.CtrlRandom); - /** - * The defaults - * @const - * @type {Object} - */ - Tone.CtrlRandom.defaults = { - 'min': 0, - 'max': 1, - 'integer': false - }; - /** - * Return a random value between min and max. - * @readOnly - * @memberOf Tone.CtrlRandom# - * @type {*} - * @name value - */ - Object.defineProperty(Tone.CtrlRandom.prototype, 'value', { - get: function () { - var min = this.toSeconds(this.min); - var max = this.toSeconds(this.max); - var rand = Math.random(); - var val = rand * min + (1 - rand) * max; - if (this.integer) { - val = Math.floor(val); - } - return val; - } - }); - return Tone.CtrlRandom; - }); - Module(function (Tone) { - - /** - * AudioBuffer.copyToChannel polyfill - * @private - */ - if (window.AudioBuffer && !AudioBuffer.prototype.copyToChannel) { - AudioBuffer.prototype.copyToChannel = function (src, chanNum, start) { - var channel = this.getChannelData(chanNum); - start = start || 0; - for (var i = 0; i < channel.length; i++) { - channel[i + start] = src[i]; - } - }; - AudioBuffer.prototype.copyFromChannel = function (dest, chanNum, start) { - var channel = this.getChannelData(chanNum); - start = start || 0; - for (var i = 0; i < channel.length; i++) { - dest[i] = channel[i + start]; - } - }; - } - /** - * @class Buffer loading and storage. Tone.Buffer is used internally by all - * classes that make requests for audio files such as Tone.Player, - * Tone.Sampler and Tone.Convolver. - * <br><br> - * Aside from load callbacks from individual buffers, Tone.Buffer - * provides static methods which keep track of the loading progress - * of all of the buffers. These methods are Tone.Buffer.on("load" / "progress" / "error") - * - * @constructor - * @extends {Tone} - * @param {AudioBuffer|string} url The url to load, or the audio buffer to set. - * @param {Function=} onload A callback which is invoked after the buffer is loaded. - * It's recommended to use Tone.Buffer.onload instead - * since it will give you a callback when ALL buffers are loaded. - * @param {Function=} onerror The callback to invoke if there is an error - * @example - * var buffer = new Tone.Buffer("path/to/sound.mp3", function(){ - * //the buffer is now available. - * var buff = buffer.get(); - * }); - */ - Tone.Buffer = function () { - var options = this.optionsObject(arguments, [ - 'url', - 'onload', - 'onerror' - ], Tone.Buffer.defaults); - /** - * stores the loaded AudioBuffer - * @type {AudioBuffer} - * @private - */ - this._buffer = null; - /** - * indicates if the buffer should be reversed or not - * @type {Boolean} - * @private - */ - this._reversed = options.reverse; - /** - * The XHR - * @type {XMLHttpRequest} - * @private - */ - this._xhr = null; - if (options.url instanceof AudioBuffer || options.url instanceof Tone.Buffer) { - this.set(options.url); - // invoke the onload callback - if (options.onload) { - options.onload(this); - } - } else if (this.isString(options.url)) { - this.load(options.url, options.onload, options.onerror); - } - }; - Tone.extend(Tone.Buffer); - /** - * the default parameters - * @type {Object} - */ - Tone.Buffer.defaults = { - 'url': undefined, - 'reverse': false - }; - /** - * Pass in an AudioBuffer or Tone.Buffer to set the value - * of this buffer. - * @param {AudioBuffer|Tone.Buffer} buffer the buffer - * @returns {Tone.Buffer} this - */ - Tone.Buffer.prototype.set = function (buffer) { - if (buffer instanceof Tone.Buffer) { - this._buffer = buffer.get(); - } else { - this._buffer = buffer; - } - return this; - }; - /** - * @return {AudioBuffer} The audio buffer stored in the object. - */ - Tone.Buffer.prototype.get = function () { - return this._buffer; - }; - /** - * Makes an xhr reqest for the selected url then decodes - * the file as an audio buffer. Invokes - * the callback once the audio buffer loads. - * @param {String} url The url of the buffer to load. - * filetype support depends on the - * browser. - * @returns {Promise} returns a Promise which resolves with the Tone.Buffer - */ - Tone.Buffer.prototype.load = function (url, onload, onerror) { - var promise = new Promise(function (load, error) { - this._xhr = Tone.Buffer.load(url, //success - function (buff) { - this._xhr = null; - this.set(buff); - load(this); - if (onload) { - onload(this); - } - }.bind(this), //error - function (err) { - this._xhr = null; - error(err); - if (onerror) { - onerror(err); - } - }.bind(this)); - }.bind(this)); - return promise; - }; - /** - * dispose and disconnect - * @returns {Tone.Buffer} this - */ - Tone.Buffer.prototype.dispose = function () { - Tone.Emitter.prototype.dispose.call(this); - this._buffer = null; - if (this._xhr) { - Tone.Buffer._currentDownloads--; - this._xhr.abort(); - this._xhr = null; - } - return this; - }; - /** - * If the buffer is loaded or not - * @memberOf Tone.Buffer# - * @type {Boolean} - * @name loaded - * @readOnly - */ - Object.defineProperty(Tone.Buffer.prototype, 'loaded', { - get: function () { - return this.length > 0; - } - }); - /** - * The duration of the buffer. - * @memberOf Tone.Buffer# - * @type {Number} - * @name duration - * @readOnly - */ - Object.defineProperty(Tone.Buffer.prototype, 'duration', { - get: function () { - if (this._buffer) { - return this._buffer.duration; - } else { - return 0; - } - } - }); - /** - * The length of the buffer in samples - * @memberOf Tone.Buffer# - * @type {Number} - * @name length - * @readOnly - */ - Object.defineProperty(Tone.Buffer.prototype, 'length', { - get: function () { - if (this._buffer) { - return this._buffer.length; - } else { - return 0; - } - } - }); - /** - * The number of discrete audio channels. Returns 0 if no buffer - * is loaded. - * @memberOf Tone.Buffer# - * @type {Number} - * @name numberOfChannels - * @readOnly - */ - Object.defineProperty(Tone.Buffer.prototype, 'numberOfChannels', { - get: function () { - if (this._buffer) { - return this._buffer.numberOfChannels; - } else { - return 0; - } - } - }); - /** - * Set the audio buffer from the array - * @param {Float32Array} array The array to fill the audio buffer - * @param {Number} [channels=1] The number of channels contained in the array. - * If the channel is more than 1, the input array - * is expected to be a multidimensional array - * with dimensions equal to the number of channels. - * @return {Tone.Buffer} this - */ - Tone.Buffer.prototype.fromArray = function (array) { - var isMultidimensional = array[0].length > 0; - var channels = isMultidimensional ? array.length : 1; - var len = isMultidimensional ? array[0].length : array.length; - var buffer = this.context.createBuffer(channels, len, this.context.sampleRate); - if (!isMultidimensional && channels === 1) { - array = [array]; - } - for (var c = 0; c < channels; c++) { - buffer.copyToChannel(array[c], c); - } - this._buffer = buffer; - return this; - }; - /** - * Sums muliple channels into 1 channel - * @param {Number=} channel Optionally only copy a single channel from the array. - * @return {Array} - */ - Tone.Buffer.prototype.toMono = function (chanNum) { - if (this.isNumber(chanNum)) { - this.fromArray(this.toArray(chanNum)); - } else { - var outputArray = new Float32Array(this.length); - var numChannels = this.numberOfChannels; - for (var channel = 0; channel < numChannels; channel++) { - var channelArray = this.toArray(channel); - for (var i = 0; i < channelArray.length; i++) { - outputArray[i] += channelArray[i]; - } - } - //divide by the number of channels - outputArray = outputArray.map(function (sample) { - return sample / numChannels; - }); - this.fromArray(outputArray); - } - return this; - }; - /** - * Get the buffer as an array. Single channel buffers will return a 1-dimensional - * Float32Array, and multichannel buffers will return multidimensional arrays. - * @param {Number=} channel Optionally only copy a single channel from the array. - * @return {Array} - */ - Tone.Buffer.prototype.toArray = function (channel) { - if (this.isNumber(channel)) { - return this.getChannelData(channel); - } else if (this.numberOfChannels === 1) { - return this.toArray(0); - } else { - var ret = []; - for (var c = 0; c < this.numberOfChannels; c++) { - ret[c] = this.getChannelData(c); - } - return ret; - } - }; - /** - * Returns the Float32Array representing the PCM audio data for the specific channel. - * @param {Number} channel The channel number to return - * @return {Float32Array} The audio as a TypedArray - */ - Tone.Buffer.prototype.getChannelData = function (channel) { - return this._buffer.getChannelData(channel); - }; - /** - * Cut a subsection of the array and return a buffer of the - * subsection. Does not modify the original buffer - * @param {Time} start The time to start the slice - * @param {Time=} end The end time to slice. If none is given - * will default to the end of the buffer - * @return {Tone.Buffer} this - */ - Tone.Buffer.prototype.slice = function (start, end) { - end = this.defaultArg(end, this.duration); - var startSamples = Math.floor(this.context.sampleRate * this.toSeconds(start)); - var endSamples = Math.floor(this.context.sampleRate * this.toSeconds(end)); - var replacement = []; - for (var i = 0; i < this.numberOfChannels; i++) { - replacement[i] = this.toArray(i).slice(startSamples, endSamples); - } - var retBuffer = new Tone.Buffer().fromArray(replacement); - return retBuffer; - }; - /** - * Reverse the buffer. - * @private - * @return {Tone.Buffer} this - */ - Tone.Buffer.prototype._reverse = function () { - if (this.loaded) { - for (var i = 0; i < this.numberOfChannels; i++) { - Array.prototype.reverse.call(this.getChannelData(i)); - } - } - return this; - }; - /** - * Reverse the buffer. - * @memberOf Tone.Buffer# - * @type {Boolean} - * @name reverse - */ - Object.defineProperty(Tone.Buffer.prototype, 'reverse', { - get: function () { - return this._reversed; - }, - set: function (rev) { - if (this._reversed !== rev) { - this._reversed = rev; - this._reverse(); - } - } - }); - /////////////////////////////////////////////////////////////////////////// - // STATIC METHODS - /////////////////////////////////////////////////////////////////////////// - //statically inherits Emitter methods - Tone.Emitter.mixin(Tone.Buffer); - /** - * the static queue for all of the xhr requests - * @type {Array} - * @private - */ - Tone.Buffer._downloadQueue = []; - /** - * the total number of downloads - * @type {Number} - * @private - */ - Tone.Buffer._currentDownloads = 0; - /** - * A path which is prefixed before every url. - * @type {String} - * @static - */ - Tone.Buffer.baseUrl = ''; - /** - * Loads a url using XMLHttpRequest. - * @param {String} url - * @param {Function} onload - * @param {Function} onerror - * @param {Function} onprogress - * @return {XMLHttpRequest} - */ - Tone.Buffer.load = function (url, onload, onerror) { - //default - onload = onload || Tone.noOp; - function onError(e) { - if (onerror) { - onerror(e); - Tone.Buffer.emit('error', e); - } else { - throw new Error(e); - } - } - function onProgress() { - //calculate the progress - var totalProgress = 0; - for (var i = 0; i < Tone.Buffer._downloadQueue.length; i++) { - totalProgress += Tone.Buffer._downloadQueue[i].progress; - } - Tone.Buffer.emit('progress', totalProgress / Tone.Buffer._downloadQueue.length); - } - var request = new XMLHttpRequest(); - request.open('GET', Tone.Buffer.baseUrl + url, true); - request.responseType = 'arraybuffer'; - //start out as 0 - request.progress = 0; - Tone.Buffer._currentDownloads++; - Tone.Buffer._downloadQueue.push(request); - request.addEventListener('load', function () { - if (request.status === 200) { - Tone.context.decodeAudioData(request.response, function (buff) { - request.progress = 1; - onProgress(); - onload(buff); - Tone.Buffer._currentDownloads--; - if (Tone.Buffer._currentDownloads === 0) { - // clear the downloads - Tone.Buffer._downloadQueue = []; - //emit the event at the end - Tone.Buffer.emit('load'); - } - }, function () { - onError('Tone.Buffer: could not decode audio data: ' + url); - }); - } else { - onError('Tone.Buffer: could not locate file: ' + url); - } - }); - request.addEventListener('error', onError); - request.addEventListener('progress', function (event) { - if (event.lengthComputable) { - //only go to 95%, the last 5% is when the audio is decoded - request.progress = event.loaded / event.total * 0.95; - onProgress(); - } - }); - request.send(); - return request; - }; - /** - * Stop all of the downloads in progress - * @return {Tone.Buffer} - * @static - */ - Tone.Buffer.cancelDownloads = function () { - Tone.Buffer._downloadQueue.forEach(function (request) { - request.abort(); - }); - Tone.Buffer._currentDownloads = 0; - return Tone.Buffer; - }; - /** - * Checks a url's extension to see if the current browser can play that file type. - * @param {String} url The url/extension to test - * @return {Boolean} If the file extension can be played - * @static - * @example - * Tone.Buffer.supportsType("wav"); //returns true - * Tone.Buffer.supportsType("path/to/file.wav"); //returns true - */ - Tone.Buffer.supportsType = function (url) { - var extension = url.split('.'); - extension = extension[extension.length - 1]; - var response = document.createElement('audio').canPlayType('audio/' + extension); - return response !== ''; - }; - /** - * Returns a Promise which resolves when all of the buffers have loaded - * @return {Promise} - */ - Tone.loaded = function () { - var onload, onerror; - function removeEvents() { - //remove the events when it's resolved - Tone.Buffer.off('load', onload); - Tone.Buffer.off('error', onerror); - } - return new Promise(function (success, fail) { - onload = function () { - success(); - }; - onerror = function () { - fail(); - }; - //add the event listeners - Tone.Buffer.on('load', onload); - Tone.Buffer.on('error', onerror); - }).then(removeEvents).catch(function (e) { - removeEvents(); - throw new Error(e); - }); - }; - return Tone.Buffer; - }); - Module(function (Tone) { - /** - * @class A data structure for holding multiple buffers. - * - * @param {Object|Array} urls An object literal or array - * of urls to load. - * @param {Function=} callback The callback to invoke when - * the buffers are loaded. - * @extends {Tone} - * @example - * //load a whole bank of piano samples - * var pianoSamples = new Tone.Buffers({ - * "C4" : "path/to/C4.mp3" - * "C#4" : "path/to/C#4.mp3" - * "D4" : "path/to/D4.mp3" - * "D#4" : "path/to/D#4.mp3" - * ... - * }, function(){ - * //play one of the samples when they all load - * player.buffer = pianoSamples.get("C4"); - * player.start(); - * }); - * - */ - Tone.Buffers = function (urls, onload, baseUrl) { - /** - * All of the buffers - * @type {Object} - * @private - */ - this._buffers = {}; - /** - * A path which is prefixed before every url. - * @type {String} - */ - this.baseUrl = this.defaultArg(baseUrl, ''); - urls = this._flattenUrls(urls); - this._loadingCount = 0; - //add each one - for (var key in urls) { - this._loadingCount++; - this.add(key, urls[key], this._bufferLoaded.bind(this, onload)); - } - }; - Tone.extend(Tone.Buffers); - /** - * True if the buffers object has a buffer by that name. - * @param {String|Number} name The key or index of the - * buffer. - * @return {Boolean} - */ - Tone.Buffers.prototype.has = function (name) { - return this._buffers.hasOwnProperty(name); - }; - /** - * Get a buffer by name. If an array was loaded, - * then use the array index. - * @param {String|Number} name The key or index of the - * buffer. - * @return {Tone.Buffer} - */ - Tone.Buffers.prototype.get = function (name) { - if (this.has(name)) { - return this._buffers[name]; - } else { - throw new Error('Tone.Buffers: no buffer named ' + name); - } - }; - /** - * A buffer was loaded. decrement the counter. - * @param {Function} callback - * @private - */ - Tone.Buffers.prototype._bufferLoaded = function (callback) { - this._loadingCount--; - if (this._loadingCount === 0 && callback) { - callback(this); - } - }; - /** - * If the buffers are loaded or not - * @memberOf Tone.Buffers# - * @type {Boolean} - * @name loaded - * @readOnly - */ - Object.defineProperty(Tone.Buffers.prototype, 'loaded', { - get: function () { - var isLoaded = true; - for (var buffName in this._buffers) { - var buff = this.get(buffName); - isLoaded = isLoaded && buff.loaded; - } - return isLoaded; - } - }); - /** - * Add a buffer by name and url to the Buffers - * @param {String} name A unique name to give - * the buffer - * @param {String|Tone.Buffer|Audiobuffer} url Either the url of the bufer, - * or a buffer which will be added - * with the given name. - * @param {Function=} callback The callback to invoke - * when the url is loaded. - */ - Tone.Buffers.prototype.add = function (name, url, callback) { - callback = this.defaultArg(callback, Tone.noOp); - if (url instanceof Tone.Buffer) { - this._buffers[name] = url; - callback(this); - } else if (url instanceof AudioBuffer) { - this._buffers[name] = new Tone.Buffer(url); - callback(this); - } else if (this.isString(url)) { - this._buffers[name] = new Tone.Buffer(this.baseUrl + url, callback); - } - return this; - }; - /** - * Flatten an object into a single depth object. - * thanks to https://gist.github.com/penguinboy/762197 - * @param {Object} ob - * @return {Object} - * @private - */ - Tone.Buffers.prototype._flattenUrls = function (ob) { - var toReturn = {}; - for (var i in ob) { - if (!ob.hasOwnProperty(i)) - continue; - if (this.isObject(ob[i])) { - var flatObject = this._flattenUrls(ob[i]); - for (var x in flatObject) { - if (!flatObject.hasOwnProperty(x)) - continue; - toReturn[i + '.' + x] = flatObject[x]; - } - } else { - toReturn[i] = ob[i]; - } - } - return toReturn; - }; - /** - * Clean up. - * @return {Tone.Buffers} this - */ - Tone.Buffers.prototype.dispose = function () { - for (var name in this._buffers) { - this._buffers[name].dispose(); - } - this._buffers = null; - return this; - }; - return Tone.Buffers; - }); - Module(function (Tone) { - - /** - * buses are another way of routing audio - * - * augments Tone.prototype to include send and recieve - */ - /** - * All of the routes - * - * @type {Object} - * @static - * @private - */ - var Buses = {}; - /** - * Send this signal to the channel name. - * @param {string} channelName A named channel to send the signal to. - * @param {Decibels} amount The amount of the source to send to the bus. - * @return {GainNode} The gain node which connects this node to the desired channel. - * Can be used to adjust the levels of the send. - * @example - * source.send("reverb", -12); - */ - Tone.prototype.send = function (channelName, amount) { - if (!Buses.hasOwnProperty(channelName)) { - Buses[channelName] = this.context.createGain(); - } - amount = this.defaultArg(amount, 0); - var sendKnob = new Tone.Gain(amount, Tone.Type.Decibels); - this.output.chain(sendKnob, Buses[channelName]); - return sendKnob; - }; - /** - * Recieve the input from the desired channelName to the input - * - * @param {string} channelName A named channel to send the signal to. - * @param {AudioNode} [input] If no input is selected, the - * input of the current node is - * chosen. - * @returns {Tone} this - * @example - * reverbEffect.receive("reverb"); - */ - Tone.prototype.receive = function (channelName, input) { - if (!Buses.hasOwnProperty(channelName)) { - Buses[channelName] = this.context.createGain(); - } - if (this.isUndef(input)) { - input = this.input; - } - Buses[channelName].connect(input); - return this; - }; - //remove all the send/receives when a new audio context is passed in - Tone.Context.on('init', function (context) { - if (context.Buses) { - Buses = context.Buses; - } else { - Buses = {}; - context.Buses = Buses; - } - }); - return Tone; - }); - Module(function (Tone) { - - /** - * @class Tone.Draw is useful for synchronizing visuals and audio events. - * Callbacks from Tone.Transport or any of the Tone.Event classes - * always happen _before_ the scheduled time and are not synchronized - * to the animation frame so they are not good for triggering tightly - * synchronized visuals and sound. Tone.Draw makes it easy to schedule - * callbacks using the AudioContext time and uses requestAnimationFrame. - * - * @singleton - * @extends {Tone} - * @example - * Tone.Transport.schedule(function(time){ - * //use the time argument to schedule a callback with Tone.Draw - * Tone.Draw.schedule(function(){ - * //do drawing or DOM manipulation here - * }, time) - * }, "+0.5") - */ - Tone.Draw = function () { - /** - * All of the events. - * @type {Tone.Timeline} - * @private - */ - this._events = new Tone.Timeline(); - /** - * The duration after which events are not invoked. - * @type {Number} - * @default 0.25 - */ - this.expiration = 0.25; - /** - * The amount of time before the scheduled time - * that the callback can be invoked. Default is - * half the time of an animation frame (0.008 seconds). - * @type {Number} - * @default 0.008 - */ - this.anticipation = 0.008; - /** - * The draw loop - * @type {Function} - * @private - */ - this._boundDrawLoop = this._drawLoop.bind(this); - }; - Tone.extend(Tone.Draw); - /** - * Schedule a function at the given time to be invoked - * on the nearest animation frame. - * @param {Function} callback Callback is invoked at the given time. - * @param {Time} time The time relative to the AudioContext time - * to invoke the callback. - * @return {Tone.Draw} this - */ - Tone.Draw.prototype.schedule = function (callback, time) { - this._events.add({ - callback: callback, - time: this.toSeconds(time) - }); - //start the draw loop on the first event - if (this._events.length === 1) { - requestAnimationFrame(this._boundDrawLoop); - } - return this; - }; - /** - * Cancel events scheduled after the given time - * @param {Time=} after Time after which scheduled events will - * be removed from the scheduling timeline. - * @return {Tone.Draw} this - */ - Tone.Draw.prototype.cancel = function (after) { - this._events.cancel(this.toSeconds(after)); - return this; - }; - /** - * The draw loop - * @private - */ - Tone.Draw.prototype._drawLoop = function () { - var now = Tone.now(); - while (this._events.length && this._events.peek().time - this.anticipation <= now) { - var event = this._events.shift(); - if (now - event.time <= this.expiration) { - event.callback(); - } - } - if (this._events.length > 0) { - requestAnimationFrame(this._boundDrawLoop); - } - }; - //make a singleton - Tone.Draw = new Tone.Draw(); - return Tone.Draw; - }); - Module(function (Tone) { - - /** - * @class Both Tone.Panner3D and Tone.Listener have a position in 3D space - * using a right-handed cartesian coordinate system. - * The units used in the coordinate system are not defined; - * these coordinates are independent/invariant of any particular - * units such as meters or feet. Tone.Panner3D objects have an forward - * vector representing the direction the sound is projecting. Additionally, - * they have a sound cone representing how directional the sound is. - * For example, the sound could be omnidirectional, in which case it would - * be heard anywhere regardless of its forward, or it can be more directional - * and heard only if it is facing the listener. Tone.Listener objects - * (representing a person's ears) have an forward and up vector - * representing in which direction the person is facing. Because both the - * source stream and the listener can be moving, they both have a velocity - * vector representing both the speed and direction of movement. Taken together, - * these two velocities can be used to generate a doppler shift effect which changes the pitch. - * <br><br> - * Note: the position of the Listener will have no effect on nodes not connected to a Tone.Panner3D - * - * @constructor - * @extends {Tone} - * @singleton - * @param {Number} positionX The initial x position. - * @param {Number} positionY The initial y position. - * @param {Number} positionZ The initial z position. - */ - Tone.Listener = function () { - var options = this.optionsObject(arguments, [ - 'positionX', - 'positionY', - 'positionZ' - ], ListenerConstructor.defaults); - /** - * Holds the current forward orientation - * @type {Array} - * @private - */ - this._orientation = [ - options.forwardX, - options.forwardY, - options.forwardZ, - options.upX, - options.upY, - options.upZ - ]; - /** - * Holds the current position - * @type {Array} - * @private - */ - this._position = [ - options.positionX, - options.positionY, - options.positionZ - ]; - // set the default position/forward - this.forwardX = options.forwardX; - this.forwardY = options.forwardY; - this.forwardZ = options.forwardZ; - this.upX = options.upX; - this.upY = options.upY; - this.upZ = options.upZ; - this.positionX = options.positionX; - this.positionY = options.positionY; - this.positionZ = options.positionZ; - }; - Tone.extend(Tone.Listener); - /** - * the default parameters - * @static - * @const - * @type {Object} - * Defaults according to the specification - */ - Tone.Listener.defaults = { - 'positionX': 0, - 'positionY': 0, - 'positionZ': 0, - 'forwardX': 0, - 'forwardY': 0, - 'forwardZ': 1, - 'upX': 0, - 'upY': 1, - 'upZ': 0 - }; - /** - * The ramp time which is applied to the setTargetAtTime - * @type {Number} - * @private - */ - Tone.Listener.prototype._rampTimeConstant = 0.01; - /** - * Sets the position of the listener in 3d space. - * @param {Number} x - * @param {Number} y - * @param {Number} z - * @return {Tone.Listener} this - */ - Tone.Listener.prototype.setPosition = function (x, y, z) { - if (this.context.listener.positionX) { - var now = this.now(); - this.context.listener.positionX.setTargetAtTime(x, now, this._rampTimeConstant); - this.context.listener.positionY.setTargetAtTime(y, now, this._rampTimeConstant); - this.context.listener.positionZ.setTargetAtTime(z, now, this._rampTimeConstant); - } else { - this.context.listener.setPosition(x, y, z); - } - this._position = Array.prototype.slice.call(arguments); - return this; - }; - /** - * Sets the orientation of the listener using two vectors, the forward - * vector (which direction the listener is facing) and the up vector - * (which the up direction of the listener). An up vector - * of 0, 0, 1 is equivalent to the listener standing up in the Z direction. - * @param {Number} x - * @param {Number} y - * @param {Number} z - * @param {Number} upX - * @param {Number} upY - * @param {Number} upZ - * @return {Tone.Listener} this - */ - Tone.Listener.prototype.setOrientation = function (x, y, z, upX, upY, upZ) { - if (this.context.listener.forwardX) { - var now = this.now(); - this.context.listener.forwardX.setTargetAtTime(x, now, this._rampTimeConstant); - this.context.listener.forwardY.setTargetAtTime(y, now, this._rampTimeConstant); - this.context.listener.forwardZ.setTargetAtTime(z, now, this._rampTimeConstant); - this.context.listener.upX.setTargetAtTime(upX, now, this._rampTimeConstant); - this.context.listener.upY.setTargetAtTime(upY, now, this._rampTimeConstant); - this.context.listener.upZ.setTargetAtTime(upZ, now, this._rampTimeConstant); - } else { - this.context.listener.setOrientation(x, y, z, upX, upY, upZ); - } - this._orientation = Array.prototype.slice.call(arguments); - return this; - }; - /** - * The x position of the panner object. - * @type {Number} - * @memberOf Tone.Listener# - * @name positionX - */ - Object.defineProperty(Tone.Listener.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.Listener# - * @name positionY - */ - Object.defineProperty(Tone.Listener.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.Listener# - * @name positionZ - */ - Object.defineProperty(Tone.Listener.prototype, 'positionZ', { - set: function (pos) { - this._position[2] = pos; - this.setPosition.apply(this, this._position); - }, - get: function () { - return this._position[2]; - } - }); - /** - * The x coordinate of the listeners front direction. i.e. - * which way they are facing. - * @type {Number} - * @memberOf Tone.Listener# - * @name forwardX - */ - Object.defineProperty(Tone.Listener.prototype, 'forwardX', { - set: function (pos) { - this._orientation[0] = pos; - this.setOrientation.apply(this, this._orientation); - }, - get: function () { - return this._orientation[0]; - } - }); - /** - * The y coordinate of the listeners front direction. i.e. - * which way they are facing. - * @type {Number} - * @memberOf Tone.Listener# - * @name forwardY - */ - Object.defineProperty(Tone.Listener.prototype, 'forwardY', { - set: function (pos) { - this._orientation[1] = pos; - this.setOrientation.apply(this, this._orientation); - }, - get: function () { - return this._orientation[1]; - } - }); - /** - * The z coordinate of the listeners front direction. i.e. - * which way they are facing. - * @type {Number} - * @memberOf Tone.Listener# - * @name forwardZ - */ - Object.defineProperty(Tone.Listener.prototype, 'forwardZ', { - set: function (pos) { - this._orientation[2] = pos; - this.setOrientation.apply(this, this._orientation); - }, - get: function () { - return this._orientation[2]; - } - }); - /** - * The x coordinate of the listener's up direction. i.e. - * the direction the listener is standing in. - * @type {Number} - * @memberOf Tone.Listener# - * @name upX - */ - Object.defineProperty(Tone.Listener.prototype, 'upX', { - set: function (pos) { - this._orientation[3] = pos; - this.setOrientation.apply(this, this._orientation); - }, - get: function () { - return this._orientation[3]; - } - }); - /** - * The y coordinate of the listener's up direction. i.e. - * the direction the listener is standing in. - * @type {Number} - * @memberOf Tone.Listener# - * @name upY - */ - Object.defineProperty(Tone.Listener.prototype, 'upY', { - set: function (pos) { - this._orientation[4] = pos; - this.setOrientation.apply(this, this._orientation); - }, - get: function () { - return this._orientation[4]; - } - }); - /** - * The z coordinate of the listener's up direction. i.e. - * the direction the listener is standing in. - * @type {Number} - * @memberOf Tone.Listener# - * @name upZ - */ - Object.defineProperty(Tone.Listener.prototype, 'upZ', { - set: function (pos) { - this._orientation[5] = pos; - this.setOrientation.apply(this, this._orientation); - }, - get: function () { - return this._orientation[5]; - } - }); - /** - * Clean up. - * @returns {Tone.Listener} this - */ - Tone.Listener.prototype.dispose = function () { - this._orientation = null; - this._position = null; - return this; - }; - //SINGLETON SETUP - var ListenerConstructor = Tone.Listener; - Tone.Listener = new ListenerConstructor(); - Tone.Context.on('init', function (context) { - if (context.Listener instanceof ListenerConstructor) { - //a single listener object - Tone.Listener = context.Listener; - } else { - //make new Listener insides - Tone.Listener = new ListenerConstructor(); - } - context.Listener = Tone.Listener; - }); - //END SINGLETON SETUP - return Tone.Listener; - }); - Module(function (Tone) { - /** - * shim - * @private - */ - if (!window.hasOwnProperty('OfflineAudioContext') && window.hasOwnProperty('webkitOfflineAudioContext')) { - window.OfflineAudioContext = window.webkitOfflineAudioContext; - } - /** - * @class Wrapper around the OfflineAudioContext - * @extends {Tone.Context - * @param {Number} channels The number of channels to render - * @param {Number} duration The duration to render in samples - * @param {Number} sampleRate the sample rate to render at - */ - Tone.OfflineContext = function (channels, duration, sampleRate) { - /** - * The offline context - * @private - * @type {OfflineAudioContext} - */ - var offlineContext = new OfflineAudioContext(channels, duration * sampleRate, sampleRate); - //wrap the methods/members - Tone.Context.call(this, offlineContext); - /** - * A private reference to the duration - * @private - * @type {Number} - */ - this._duration = duration; - /** - * An artificial clock source - * @type {Number} - * @private - */ - this._currentTime = 0; - //modify the lookAhead and updateInterval to one block - this.lookAhead = this.blockTime; - this.updateInterval = this.blockTime; - }; - Tone.extend(Tone.OfflineContext, Tone.Context); - /** - * Override the now method to point to the internal clock time - * @return {Number} - */ - Tone.OfflineContext.prototype.now = function () { - return this._currentTime; - }; - /** - * Overwrite this method since the worker is not necessary for the offline context - * @private - */ - Tone.OfflineContext.prototype._createWorker = function () { - //dummy worker that does nothing - return { - postMessage: function () { - } - }; - }; - /** - * Render the output of the OfflineContext - * @return {Promise} - */ - Tone.OfflineContext.prototype.render = function () { - while (this._duration - this._currentTime >= 0) { - //invoke all the callbacks on that time - this.emit('tick'); - //increment the clock - this._currentTime += Tone.prototype.blockTime; - } - //promise returned is not yet implemented in all browsers - return new Promise(function (done) { - this._context.oncomplete = function (e) { - done(e.renderedBuffer); - }; - this._context.startRendering(); - }.bind(this)); - }; - return Tone.OfflineContext; - }); - Module(function (Tone) { - /** - * Generate a buffer by rendering all of the Tone.js code within the callback using the OfflineAudioContext. - * The OfflineAudioContext is capable of rendering much faster than real time in many cases. - * The callback function also passes in an offline instance of Tone.Transport which can be used - * to schedule events along the Transport. - * @param {Function} callback All Tone.js nodes which are created and scheduled within this callback are recorded into the output Buffer. - * @param {Time} duration the amount of time to record for. - * @return {Promise} The promise which is invoked with the Tone.Buffer of the recorded output. - * @example - * //render 2 seconds of the oscillator - * Tone.Offline(function(){ - * //only nodes created in this callback will be recorded - * var oscillator = new Tone.Oscillator().toMaster().start(0) - * //schedule their events - * }, 2).then(function(buffer){ - * //do something with the output buffer - * }) - * @example - * //can also schedule events along the Transport - * //using the passed in Offline Transport - * Tone.Offline(function(Transport){ - * var osc = new Tone.Oscillator().toMaster() - * Transport.schedule(function(time){ - * osc.start(time).stop(time + 0.1) - * }, 1) - * Transport.start(0.2) - * }, 4).then(function(buffer){ - * //do something with the output buffer - * }) - */ - Tone.Offline = function (callback, duration) { - //set the OfflineAudioContext - var sampleRate = Tone.context.sampleRate; - var originalContext = Tone.context; - var context = new Tone.OfflineContext(2, duration, sampleRate); - Tone.context = context; - //invoke the callback/scheduling - callback(Tone.Transport); - //process the audio - var rendered = context.render(); - //return the original AudioContext - Tone.context = originalContext; - //return the audio - return rendered.then(function (buffer) { - //wrap it in a Tone.Buffer - return new Tone.Buffer(buffer); - }); - }; - return Tone.Offline; - }); - Module(function (Tone) { - - /** - * @class Tone.Effect is the base class for effects. Connect the effect between - * the effectSend and effectReturn GainNodes, then control the amount of - * effect which goes to the output using the wet control. - * - * @constructor - * @extends {Tone} - * @param {NormalRange|Object} [wet] The starting wet value. - */ - Tone.Effect = function () { - this.createInsOuts(1, 1); - //get all of the defaults - var options = this.optionsObject(arguments, ['wet'], Tone.Effect.defaults); - /** - * the drywet knob to control the amount of effect - * @type {Tone.CrossFade} - * @private - */ - this._dryWet = new Tone.CrossFade(options.wet); - /** - * The wet control is how much of the effected - * will pass through to the output. 1 = 100% effected - * signal, 0 = 100% dry signal. - * @type {NormalRange} - * @signal - */ - this.wet = this._dryWet.fade; - /** - * connect the effectSend to the input of hte effect - * @type {Tone.Gain} - * @private - */ - this.effectSend = new Tone.Gain(); - /** - * connect the output of the effect to the effectReturn - * @type {Tone.Gain} - * @private - */ - this.effectReturn = new Tone.Gain(); - //connections - this.input.connect(this._dryWet.a); - this.input.connect(this.effectSend); - this.effectReturn.connect(this._dryWet.b); - this._dryWet.connect(this.output); - this._readOnly(['wet']); - }; - Tone.extend(Tone.Effect); - /** - * @static - * @type {Object} - */ - Tone.Effect.defaults = { 'wet': 1 }; - /** - * chains the effect in between the effectSend and effectReturn - * @param {Tone} effect - * @private - * @returns {Tone.Effect} this - */ - Tone.Effect.prototype.connectEffect = function (effect) { - this.effectSend.chain(effect, this.effectReturn); - return this; - }; - /** - * Clean up. - * @returns {Tone.Effect} this - */ - Tone.Effect.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._dryWet.dispose(); - this._dryWet = null; - this.effectSend.dispose(); - this.effectSend = null; - this.effectReturn.dispose(); - this.effectReturn = null; - this._writable(['wet']); - this.wet = null; - return this; - }; - return Tone.Effect; - }); - Module(function (Tone) { - - /** - * @class Tone.AutoFilter is a Tone.Filter with a Tone.LFO connected to the filter cutoff frequency. - * Setting the LFO rate and depth allows for control over the filter modulation rate - * and depth. - * - * @constructor - * @extends {Tone.Effect} - * @param {Time|Object} [frequency] The rate of the LFO. - * @param {Frequency=} baseFrequency The lower value of the LFOs oscillation - * @param {Frequency=} octaves The number of octaves above the baseFrequency - * @example - * //create an autofilter and start it's LFO - * var autoFilter = new Tone.AutoFilter("4n").toMaster().start(); - * //route an oscillator through the filter and start it - * var oscillator = new Tone.Oscillator().connect(autoFilter).start(); - */ - Tone.AutoFilter = function () { - var options = this.optionsObject(arguments, [ - 'frequency', - 'baseFrequency', - 'octaves' - ], Tone.AutoFilter.defaults); - Tone.Effect.call(this, options); - /** - * the lfo which drives the filter cutoff - * @type {Tone.LFO} - * @private - */ - this._lfo = new Tone.LFO({ - 'frequency': options.frequency, - 'amplitude': options.depth - }); - /** - * The range of the filter modulating between the min and max frequency. - * 0 = no modulation. 1 = full modulation. - * @type {NormalRange} - * @signal - */ - this.depth = this._lfo.amplitude; - /** - * How fast the filter modulates between min and max. - * @type {Frequency} - * @signal - */ - this.frequency = this._lfo.frequency; - /** - * The filter node - * @type {Tone.Filter} - */ - this.filter = new Tone.Filter(options.filter); - /** - * The octaves placeholder - * @type {Positive} - * @private - */ - this._octaves = 0; - //connections - this.connectEffect(this.filter); - this._lfo.connect(this.filter.frequency); - this.type = options.type; - this._readOnly([ - 'frequency', - 'depth' - ]); - this.octaves = options.octaves; - this.baseFrequency = options.baseFrequency; - }; - //extend Effect - Tone.extend(Tone.AutoFilter, Tone.Effect); - /** - * defaults - * @static - * @type {Object} - */ - Tone.AutoFilter.defaults = { - 'frequency': 1, - 'type': 'sine', - 'depth': 1, - 'baseFrequency': 200, - 'octaves': 2.6, - 'filter': { - 'type': 'lowpass', - 'rolloff': -12, - 'Q': 1 - } - }; - /** - * Start the effect. - * @param {Time} [time=now] When the LFO will start. - * @returns {Tone.AutoFilter} this - */ - Tone.AutoFilter.prototype.start = function (time) { - this._lfo.start(time); - return this; - }; - /** - * Stop the effect. - * @param {Time} [time=now] When the LFO will stop. - * @returns {Tone.AutoFilter} this - */ - Tone.AutoFilter.prototype.stop = function (time) { - this._lfo.stop(time); - return this; - }; - /** - * Sync the filter to the transport. - * @param {Time} [delay=0] Delay time before starting the effect after the - * Transport has started. - * @returns {Tone.AutoFilter} this - */ - Tone.AutoFilter.prototype.sync = function (delay) { - this._lfo.sync(delay); - return this; - }; - /** - * Unsync the filter from the transport. - * @returns {Tone.AutoFilter} this - */ - Tone.AutoFilter.prototype.unsync = function () { - this._lfo.unsync(); - return this; - }; - /** - * Type of oscillator attached to the AutoFilter. - * Possible values: "sine", "square", "triangle", "sawtooth". - * @memberOf Tone.AutoFilter# - * @type {string} - * @name type - */ - Object.defineProperty(Tone.AutoFilter.prototype, 'type', { - get: function () { - return this._lfo.type; - }, - set: function (type) { - this._lfo.type = type; - } - }); - /** - * The minimum value of the filter's cutoff frequency. - * @memberOf Tone.AutoFilter# - * @type {Frequency} - * @name min - */ - Object.defineProperty(Tone.AutoFilter.prototype, 'baseFrequency', { - get: function () { - return this._lfo.min; - }, - set: function (freq) { - this._lfo.min = this.toFrequency(freq); - //and set the max - this.octaves = this._octaves; - } - }); - /** - * The maximum value of the filter's cutoff frequency. - * @memberOf Tone.AutoFilter# - * @type {Positive} - * @name octaves - */ - Object.defineProperty(Tone.AutoFilter.prototype, 'octaves', { - get: function () { - return this._octaves; - }, - set: function (oct) { - this._octaves = oct; - this._lfo.max = this.baseFrequency * Math.pow(2, oct); - } - }); - /** - * Clean up. - * @returns {Tone.AutoFilter} this - */ - Tone.AutoFilter.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this._lfo.dispose(); - this._lfo = null; - this.filter.dispose(); - this.filter = null; - this._writable([ - 'frequency', - 'depth' - ]); - this.frequency = null; - this.depth = null; - return this; - }; - return Tone.AutoFilter; - }); - Module(function (Tone) { - - /** - * @class Tone.AutoPanner is a Tone.Panner with an LFO connected to the pan amount. - * More on using autopanners [here](https://www.ableton.com/en/blog/autopan-chopper-effect-and-more-liveschool/). - * - * @constructor - * @extends {Tone.Effect} - * @param {Frequency|Object} [frequency] Rate of left-right oscillation. - * @example - * //create an autopanner and start it's LFO - * var autoPanner = new Tone.AutoPanner("4n").toMaster().start(); - * //route an oscillator through the panner and start it - * var oscillator = new Tone.Oscillator().connect(autoPanner).start(); - */ - Tone.AutoPanner = function () { - var options = this.optionsObject(arguments, ['frequency'], Tone.AutoPanner.defaults); - Tone.Effect.call(this, options); - /** - * the lfo which drives the panning - * @type {Tone.LFO} - * @private - */ - this._lfo = new Tone.LFO({ - 'frequency': options.frequency, - 'amplitude': options.depth, - 'min': -1, - 'max': 1 - }); - /** - * The amount of panning between left and right. - * 0 = always center. 1 = full range between left and right. - * @type {NormalRange} - * @signal - */ - this.depth = this._lfo.amplitude; - /** - * the panner node which does the panning - * @type {Tone.Panner} - * @private - */ - this._panner = new Tone.Panner(); - /** - * How fast the panner modulates between left and right. - * @type {Frequency} - * @signal - */ - this.frequency = this._lfo.frequency; - //connections - this.connectEffect(this._panner); - this._lfo.connect(this._panner.pan); - this.type = options.type; - this._readOnly([ - 'depth', - 'frequency' - ]); - }; - //extend Effect - Tone.extend(Tone.AutoPanner, Tone.Effect); - /** - * defaults - * @static - * @type {Object} - */ - Tone.AutoPanner.defaults = { - 'frequency': 1, - 'type': 'sine', - 'depth': 1 - }; - /** - * Start the effect. - * @param {Time} [time=now] When the LFO will start. - * @returns {Tone.AutoPanner} this - */ - Tone.AutoPanner.prototype.start = function (time) { - this._lfo.start(time); - return this; - }; - /** - * Stop the effect. - * @param {Time} [time=now] When the LFO will stop. - * @returns {Tone.AutoPanner} this - */ - Tone.AutoPanner.prototype.stop = function (time) { - this._lfo.stop(time); - return this; - }; - /** - * Sync the panner to the transport. - * @param {Time} [delay=0] Delay time before starting the effect after the - * Transport has started. - * @returns {Tone.AutoPanner} this - */ - Tone.AutoPanner.prototype.sync = function (delay) { - this._lfo.sync(delay); - return this; - }; - /** - * Unsync the panner from the transport - * @returns {Tone.AutoPanner} this - */ - Tone.AutoPanner.prototype.unsync = function () { - this._lfo.unsync(); - return this; - }; - /** - * Type of oscillator attached to the AutoFilter. - * Possible values: "sine", "square", "triangle", "sawtooth". - * @memberOf Tone.AutoFilter# - * @type {string} - * @name type - */ - Object.defineProperty(Tone.AutoPanner.prototype, 'type', { - get: function () { - return this._lfo.type; - }, - set: function (type) { - this._lfo.type = type; - } - }); - /** - * clean up - * @returns {Tone.AutoPanner} this - */ - Tone.AutoPanner.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this._lfo.dispose(); - this._lfo = null; - this._panner.dispose(); - this._panner = null; - this._writable([ - 'depth', - 'frequency' - ]); - this.frequency = null; - this.depth = null; - return this; - }; - return Tone.AutoPanner; - }); - Module(function (Tone) { - - /** - * @class Tone.AutoWah connects a Tone.Follower to a bandpass filter (Tone.Filter). - * The frequency of the filter is adjusted proportionally to the - * incoming signal's amplitude. Inspiration from [Tuna.js](https://github.com/Dinahmoe/tuna). - * - * @constructor - * @extends {Tone.Effect} - * @param {Frequency|Object} [baseFrequency] The frequency the filter is set - * to at the low point of the wah - * @param {Positive} [octaves] The number of octaves above the baseFrequency - * the filter will sweep to when fully open - * @param {Decibels} [sensitivity] The decibel threshold sensitivity for - * the incoming signal. Normal range of -40 to 0. - * @example - * var autoWah = new Tone.AutoWah(50, 6, -30).toMaster(); - * //initialize the synth and connect to autowah - * var synth = new Synth.connect(autoWah); - * //Q value influences the effect of the wah - default is 2 - * autoWah.Q.value = 6; - * //more audible on higher notes - * synth.triggerAttackRelease("C4", "8n") - */ - Tone.AutoWah = function () { - var options = this.optionsObject(arguments, [ - 'baseFrequency', - 'octaves', - 'sensitivity' - ], Tone.AutoWah.defaults); - Tone.Effect.call(this, options); - /** - * The envelope follower. Set the attack/release - * timing to adjust how the envelope is followed. - * @type {Tone.Follower} - * @private - */ - this.follower = new Tone.Follower(options.follower); - /** - * scales the follower value to the frequency domain - * @type {Tone} - * @private - */ - this._sweepRange = new Tone.ScaleExp(0, 1, 0.5); - /** - * @type {number} - * @private - */ - this._baseFrequency = options.baseFrequency; - /** - * @type {number} - * @private - */ - this._octaves = options.octaves; - /** - * the input gain to adjust the sensitivity - * @type {Tone.Gain} - * @private - */ - this._inputBoost = new Tone.Gain(); - /** - * @type {BiquadFilterNode} - * @private - */ - this._bandpass = new Tone.Filter({ - 'rolloff': -48, - 'frequency': 0, - 'Q': options.Q - }); - /** - * @type {Tone.Filter} - * @private - */ - this._peaking = new Tone.Filter(0, 'peaking'); - this._peaking.gain.value = options.gain; - /** - * The gain of the filter. - * @type {Number} - * @signal - */ - this.gain = this._peaking.gain; - /** - * The quality of the filter. - * @type {Positive} - * @signal - */ - this.Q = this._bandpass.Q; - //the control signal path - this.effectSend.chain(this._inputBoost, this.follower, this._sweepRange); - this._sweepRange.connect(this._bandpass.frequency); - this._sweepRange.connect(this._peaking.frequency); - //the filtered path - this.effectSend.chain(this._bandpass, this._peaking, this.effectReturn); - //set the initial value - this._setSweepRange(); - this.sensitivity = options.sensitivity; - this._readOnly([ - 'gain', - 'Q' - ]); - }; - Tone.extend(Tone.AutoWah, Tone.Effect); - /** - * @static - * @type {Object} - */ - Tone.AutoWah.defaults = { - 'baseFrequency': 100, - 'octaves': 6, - 'sensitivity': 0, - 'Q': 2, - 'gain': 2, - 'follower': { - 'attack': 0.3, - 'release': 0.5 - } - }; - /** - * The number of octaves that the filter will sweep above the - * baseFrequency. - * @memberOf Tone.AutoWah# - * @type {Number} - * @name octaves - */ - Object.defineProperty(Tone.AutoWah.prototype, 'octaves', { - get: function () { - return this._octaves; - }, - set: function (octaves) { - this._octaves = octaves; - this._setSweepRange(); - } - }); - /** - * The base frequency from which the sweep will start from. - * @memberOf Tone.AutoWah# - * @type {Frequency} - * @name baseFrequency - */ - Object.defineProperty(Tone.AutoWah.prototype, 'baseFrequency', { - get: function () { - return this._baseFrequency; - }, - set: function (baseFreq) { - this._baseFrequency = baseFreq; - this._setSweepRange(); - } - }); - /** - * The sensitivity to control how responsive to the input signal the filter is. - * @memberOf Tone.AutoWah# - * @type {Decibels} - * @name sensitivity - */ - Object.defineProperty(Tone.AutoWah.prototype, 'sensitivity', { - get: function () { - return this.gainToDb(1 / this._inputBoost.gain.value); - }, - set: function (sensitivy) { - this._inputBoost.gain.value = 1 / this.dbToGain(sensitivy); - } - }); - /** - * sets the sweep range of the scaler - * @private - */ - Tone.AutoWah.prototype._setSweepRange = function () { - this._sweepRange.min = this._baseFrequency; - this._sweepRange.max = Math.min(this._baseFrequency * Math.pow(2, this._octaves), this.context.sampleRate / 2); - }; - /** - * Clean up. - * @returns {Tone.AutoWah} this - */ - Tone.AutoWah.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this.follower.dispose(); - this.follower = null; - this._sweepRange.dispose(); - this._sweepRange = null; - this._bandpass.dispose(); - this._bandpass = null; - this._peaking.dispose(); - this._peaking = null; - this._inputBoost.dispose(); - this._inputBoost = null; - this._writable([ - 'gain', - 'Q' - ]); - this.gain = null; - this.Q = null; - return this; - }; - return Tone.AutoWah; - }); - Module(function (Tone) { - - /** - * @class Tone.Bitcrusher downsamples the incoming signal to a different bitdepth. - * Lowering the bitdepth of the signal creates distortion. Read more about Bitcrushing - * on [Wikipedia](https://en.wikipedia.org/wiki/Bitcrusher). - * - * @constructor - * @extends {Tone.Effect} - * @param {Number} bits The number of bits to downsample the signal. Nominal range - * of 1 to 8. - * @example - * //initialize crusher and route a synth through it - * var crusher = new Tone.BitCrusher(4).toMaster(); - * var synth = new Tone.MonoSynth().connect(crusher); - */ - Tone.BitCrusher = function () { - var options = this.optionsObject(arguments, ['bits'], Tone.BitCrusher.defaults); - Tone.Effect.call(this, options); - var invStepSize = 1 / Math.pow(2, options.bits - 1); - /** - * Subtract the input signal and the modulus of the input signal - * @type {Tone.Subtract} - * @private - */ - this._subtract = new Tone.Subtract(); - /** - * The mod function - * @type {Tone.Modulo} - * @private - */ - this._modulo = new Tone.Modulo(invStepSize); - /** - * keeps track of the bits - * @type {number} - * @private - */ - this._bits = options.bits; - //connect it up - this.effectSend.fan(this._subtract, this._modulo); - this._modulo.connect(this._subtract, 0, 1); - this._subtract.connect(this.effectReturn); - }; - Tone.extend(Tone.BitCrusher, Tone.Effect); - /** - * the default values - * @static - * @type {Object} - */ - Tone.BitCrusher.defaults = { 'bits': 4 }; - /** - * The bit depth of the effect. Nominal range of 1-8. - * @memberOf Tone.BitCrusher# - * @type {number} - * @name bits - */ - Object.defineProperty(Tone.BitCrusher.prototype, 'bits', { - get: function () { - return this._bits; - }, - set: function (bits) { - this._bits = bits; - var invStepSize = 1 / Math.pow(2, bits - 1); - this._modulo.value = invStepSize; - } - }); - /** - * Clean up. - * @returns {Tone.BitCrusher} this - */ - Tone.BitCrusher.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this._subtract.dispose(); - this._subtract = null; - this._modulo.dispose(); - this._modulo = null; - return this; - }; - return Tone.BitCrusher; - }); - Module(function (Tone) { - - /** - * @class Tone.ChebyShev is a Chebyshev waveshaper, an effect which is good - * for making different types of distortion sounds. - * Note that odd orders sound very different from even ones, - * and order = 1 is no change. - * Read more at [music.columbia.edu](http://music.columbia.edu/cmc/musicandcomputers/chapter4/04_06.php). - * - * @extends {Tone.Effect} - * @constructor - * @param {Positive|Object} [order] The order of the chebyshev polynomial. Normal range between 1-100. - * @example - * //create a new cheby - * var cheby = new Tone.Chebyshev(50); - * //create a monosynth connected to our cheby - * synth = new Tone.MonoSynth().connect(cheby); - */ - Tone.Chebyshev = function () { - var options = this.optionsObject(arguments, ['order'], Tone.Chebyshev.defaults); - Tone.Effect.call(this, options); - /** - * @type {WaveShaperNode} - * @private - */ - this._shaper = new Tone.WaveShaper(4096); - /** - * holds onto the order of the filter - * @type {number} - * @private - */ - this._order = options.order; - this.connectEffect(this._shaper); - this.order = options.order; - this.oversample = options.oversample; - }; - Tone.extend(Tone.Chebyshev, Tone.Effect); - /** - * @static - * @const - * @type {Object} - */ - Tone.Chebyshev.defaults = { - 'order': 1, - 'oversample': 'none' - }; - /** - * get the coefficient for that degree - * @param {number} x the x value - * @param {number} degree - * @param {Object} memo memoize the computed value. - * this speeds up computation greatly. - * @return {number} the coefficient - * @private - */ - Tone.Chebyshev.prototype._getCoefficient = function (x, degree, memo) { - if (memo.hasOwnProperty(degree)) { - return memo[degree]; - } else if (degree === 0) { - memo[degree] = 0; - } else if (degree === 1) { - memo[degree] = x; - } else { - memo[degree] = 2 * x * this._getCoefficient(x, degree - 1, memo) - this._getCoefficient(x, degree - 2, memo); - } - return memo[degree]; - }; - /** - * The order of the Chebyshev polynomial which creates - * the equation which is applied to the incoming - * signal through a Tone.WaveShaper. The equations - * are in the form:<br> - * order 2: 2x^2 + 1<br> - * order 3: 4x^3 + 3x <br> - * @memberOf Tone.Chebyshev# - * @type {Positive} - * @name order - */ - Object.defineProperty(Tone.Chebyshev.prototype, 'order', { - get: function () { - return this._order; - }, - set: function (order) { - this._order = order; - var curve = new Array(4096); - var len = curve.length; - for (var i = 0; i < len; ++i) { - var x = i * 2 / len - 1; - if (x === 0) { - //should output 0 when input is 0 - curve[i] = 0; - } else { - curve[i] = this._getCoefficient(x, order, {}); - } - } - this._shaper.curve = curve; - } - }); - /** - * The oversampling of the effect. Can either be "none", "2x" or "4x". - * @memberOf Tone.Chebyshev# - * @type {string} - * @name oversample - */ - Object.defineProperty(Tone.Chebyshev.prototype, 'oversample', { - get: function () { - return this._shaper.oversample; - }, - set: function (oversampling) { - this._shaper.oversample = oversampling; - } - }); - /** - * Clean up. - * @returns {Tone.Chebyshev} this - */ - Tone.Chebyshev.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this._shaper.dispose(); - this._shaper = null; - return this; - }; - return Tone.Chebyshev; - }); - Module(function (Tone) { - - /** - * @class Base class for Stereo effects. Provides effectSendL/R and effectReturnL/R. - * - * @constructor - * @extends {Tone.Effect} - */ - Tone.StereoEffect = function () { - this.createInsOuts(1, 1); - //get the defaults - var options = this.optionsObject(arguments, ['wet'], Tone.Effect.defaults); - /** - * the drywet knob to control the amount of effect - * @type {Tone.CrossFade} - * @private - */ - this._dryWet = new Tone.CrossFade(options.wet); - /** - * The wet control, i.e. how much of the effected - * will pass through to the output. - * @type {NormalRange} - * @signal - */ - this.wet = this._dryWet.fade; - /** - * then split it - * @type {Tone.Split} - * @private - */ - this._split = new Tone.Split(); - /** - * the effects send LEFT - * @type {GainNode} - * @private - */ - this.effectSendL = this._split.left; - /** - * the effects send RIGHT - * @type {GainNode} - * @private - */ - this.effectSendR = this._split.right; - /** - * the stereo effect merger - * @type {Tone.Merge} - * @private - */ - this._merge = new Tone.Merge(); - /** - * the effect return LEFT - * @type {GainNode} - * @private - */ - this.effectReturnL = this._merge.left; - /** - * the effect return RIGHT - * @type {GainNode} - * @private - */ - this.effectReturnR = this._merge.right; - //connections - this.input.connect(this._split); - //dry wet connections - this.input.connect(this._dryWet, 0, 0); - this._merge.connect(this._dryWet, 0, 1); - this._dryWet.connect(this.output); - this._readOnly(['wet']); - }; - Tone.extend(Tone.StereoEffect, Tone.Effect); - /** - * Clean up. - * @returns {Tone.StereoEffect} this - */ - Tone.StereoEffect.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._dryWet.dispose(); - this._dryWet = null; - this._split.dispose(); - this._split = null; - this._merge.dispose(); - this._merge = null; - this.effectSendL = null; - this.effectSendR = null; - this.effectReturnL = null; - this.effectReturnR = null; - this._writable(['wet']); - this.wet = null; - return this; - }; - return Tone.StereoEffect; - }); - Module(function (Tone) { - - /** - * @class Tone.FeedbackEffect provides a loop between an - * audio source and its own output. This is a base-class - * for feedback effects. - * - * @constructor - * @extends {Tone.Effect} - * @param {NormalRange|Object} [feedback] The initial feedback value. - */ - Tone.FeedbackEffect = function () { - var options = this.optionsObject(arguments, ['feedback']); - options = this.defaultArg(options, Tone.FeedbackEffect.defaults); - Tone.Effect.call(this, options); - /** - * the gain which controls the feedback - * @type {Tone.Gain} - * @private - */ - this._feedbackGain = new Tone.Gain(options.feedback, Tone.Type.NormalRange); - /** - * The amount of signal which is fed back into the effect input. - * @type {NormalRange} - * @signal - */ - this.feedback = this._feedbackGain.gain; - //the feedback loop - this.effectReturn.chain(this._feedbackGain, this.effectSend); - this._readOnly(['feedback']); - }; - Tone.extend(Tone.FeedbackEffect, Tone.Effect); - /** - * @static - * @type {Object} - */ - Tone.FeedbackEffect.defaults = { 'feedback': 0.125 }; - /** - * Clean up. - * @returns {Tone.FeedbackEffect} this - */ - Tone.FeedbackEffect.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this._writable(['feedback']); - this._feedbackGain.dispose(); - this._feedbackGain = null; - this.feedback = null; - return this; - }; - return Tone.FeedbackEffect; - }); - Module(function (Tone) { - - /** - * @class Just like a stereo feedback effect, but the feedback is routed from left to right - * and right to left instead of on the same channel. - * - * @constructor - * @extends {Tone.FeedbackEffect} - */ - Tone.StereoXFeedbackEffect = function () { - var options = this.optionsObject(arguments, ['feedback'], Tone.FeedbackEffect.defaults); - Tone.StereoEffect.call(this, options); - /** - * The amount of feedback from the output - * back into the input of the effect (routed - * across left and right channels). - * @type {NormalRange} - * @signal - */ - this.feedback = new Tone.Signal(options.feedback, Tone.Type.NormalRange); - /** - * the left side feeback - * @type {Tone.Gain} - * @private - */ - this._feedbackLR = new Tone.Gain(); - /** - * the right side feeback - * @type {Tone.Gain} - * @private - */ - this._feedbackRL = new Tone.Gain(); - //connect it up - this.effectReturnL.chain(this._feedbackLR, this.effectSendR); - this.effectReturnR.chain(this._feedbackRL, this.effectSendL); - this.feedback.fan(this._feedbackLR.gain, this._feedbackRL.gain); - this._readOnly(['feedback']); - }; - Tone.extend(Tone.StereoXFeedbackEffect, Tone.FeedbackEffect); - /** - * clean up - * @returns {Tone.StereoXFeedbackEffect} this - */ - Tone.StereoXFeedbackEffect.prototype.dispose = function () { - Tone.StereoEffect.prototype.dispose.call(this); - this._writable(['feedback']); - this.feedback.dispose(); - this.feedback = null; - this._feedbackLR.dispose(); - this._feedbackLR = null; - this._feedbackRL.dispose(); - this._feedbackRL = null; - return this; - }; - return Tone.StereoXFeedbackEffect; - }); - Module(function (Tone) { - - /** - * @class Tone.Chorus is a stereo chorus effect with feedback composed of - * a left and right delay with a Tone.LFO applied to the delayTime of each channel. - * Inspiration from [Tuna.js](https://github.com/Dinahmoe/tuna/blob/master/tuna.js). - * Read more on the chorus effect on [SoundOnSound](http://www.soundonsound.com/sos/jun04/articles/synthsecrets.htm). - * - * @constructor - * @extends {Tone.StereoXFeedbackEffect} - * @param {Frequency|Object} [frequency] The frequency of the LFO. - * @param {Milliseconds} [delayTime] The delay of the chorus effect in ms. - * @param {NormalRange} [depth] The depth of the chorus. - * @example - * var chorus = new Tone.Chorus(4, 2.5, 0.5); - * var synth = new Tone.PolySynth(4, Tone.MonoSynth).connect(chorus); - * synth.triggerAttackRelease(["C3","E3","G3"], "8n"); - */ - Tone.Chorus = function () { - var options = this.optionsObject(arguments, [ - 'frequency', - 'delayTime', - 'depth' - ], Tone.Chorus.defaults); - Tone.StereoXFeedbackEffect.call(this, options); - /** - * the depth of the chorus - * @type {number} - * @private - */ - this._depth = options.depth; - /** - * the delayTime - * @type {number} - * @private - */ - this._delayTime = options.delayTime / 1000; - /** - * the lfo which controls the delayTime - * @type {Tone.LFO} - * @private - */ - this._lfoL = new Tone.LFO({ - 'frequency': options.frequency, - 'min': 0, - 'max': 1 - }); - /** - * another LFO for the right side with a 180 degree phase diff - * @type {Tone.LFO} - * @private - */ - this._lfoR = new Tone.LFO({ - 'frequency': options.frequency, - 'min': 0, - 'max': 1, - 'phase': 180 - }); - /** - * delay for left - * @type {Tone.Delay} - * @private - */ - this._delayNodeL = new Tone.Delay(); - /** - * delay for right - * @type {Tone.Delay} - * @private - */ - this._delayNodeR = new Tone.Delay(); - /** - * The frequency of the LFO which modulates the delayTime. - * @type {Frequency} - * @signal - */ - this.frequency = this._lfoL.frequency; - //connections - this.effectSendL.chain(this._delayNodeL, this.effectReturnL); - this.effectSendR.chain(this._delayNodeR, this.effectReturnR); - //and pass through to make the detune apparent - this.effectSendL.connect(this.effectReturnL); - this.effectSendR.connect(this.effectReturnR); - //lfo setup - this._lfoL.connect(this._delayNodeL.delayTime); - this._lfoR.connect(this._delayNodeR.delayTime); - //start the lfo - this._lfoL.start(); - this._lfoR.start(); - //have one LFO frequency control the other - this._lfoL.frequency.connect(this._lfoR.frequency); - //set the initial values - this.depth = this._depth; - this.frequency.value = options.frequency; - this.type = options.type; - this._readOnly(['frequency']); - this.spread = options.spread; - }; - Tone.extend(Tone.Chorus, Tone.StereoXFeedbackEffect); - /** - * @static - * @type {Object} - */ - Tone.Chorus.defaults = { - 'frequency': 1.5, - 'delayTime': 3.5, - 'depth': 0.7, - 'feedback': 0.1, - 'type': 'sine', - 'spread': 180 - }; - /** - * The depth of the effect. A depth of 1 makes the delayTime - * modulate between 0 and 2*delayTime (centered around the delayTime). - * @memberOf Tone.Chorus# - * @type {NormalRange} - * @name depth - */ - Object.defineProperty(Tone.Chorus.prototype, 'depth', { - get: function () { - return this._depth; - }, - set: function (depth) { - this._depth = depth; - var deviation = this._delayTime * depth; - this._lfoL.min = Math.max(this._delayTime - deviation, 0); - this._lfoL.max = this._delayTime + deviation; - this._lfoR.min = Math.max(this._delayTime - deviation, 0); - this._lfoR.max = this._delayTime + deviation; - } - }); - /** - * The delayTime in milliseconds of the chorus. A larger delayTime - * will give a more pronounced effect. Nominal range a delayTime - * is between 2 and 20ms. - * @memberOf Tone.Chorus# - * @type {Milliseconds} - * @name delayTime - */ - Object.defineProperty(Tone.Chorus.prototype, 'delayTime', { - get: function () { - return this._delayTime * 1000; - }, - set: function (delayTime) { - this._delayTime = delayTime / 1000; - this.depth = this._depth; - } - }); - /** - * The oscillator type of the LFO. - * @memberOf Tone.Chorus# - * @type {string} - * @name type - */ - Object.defineProperty(Tone.Chorus.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.Chorus# - * @type {Degrees} - * @name spread - */ - Object.defineProperty(Tone.Chorus.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.Chorus} this - */ - Tone.Chorus.prototype.dispose = function () { - Tone.StereoXFeedbackEffect.prototype.dispose.call(this); - this._lfoL.dispose(); - this._lfoL = null; - this._lfoR.dispose(); - this._lfoR = null; - this._delayNodeL.dispose(); - this._delayNodeL = null; - this._delayNodeR.dispose(); - this._delayNodeR = null; - this._writable('frequency'); - this.frequency = null; - return this; - }; - return Tone.Chorus; - }); - Module(function (Tone) { - - /** - * @class Tone.Convolver is a wrapper around the Native Web Audio - * [ConvolverNode](http://webaudio.github.io/web-audio-api/#the-convolvernode-interface). - * Convolution is useful for reverb and filter emulation. Read more about convolution reverb on - * [Wikipedia](https://en.wikipedia.org/wiki/Convolution_reverb). - * - * @constructor - * @extends {Tone.Effect} - * @param {string|Tone.Buffer|Object} [url] The URL of the impulse response or the Tone.Buffer - * contianing the impulse response. - * @param {Function} onload The callback to invoke when the url is loaded. - * @example - * //initializing the convolver with an impulse response - * var convolver = new Tone.Convolver("./path/to/ir.wav").toMaster(); - */ - Tone.Convolver = function () { - var options = this.optionsObject(arguments, [ - 'url', - 'onload' - ], Tone.Convolver.defaults); - Tone.Effect.call(this, options); - /** - * convolver node - * @type {ConvolverNode} - * @private - */ - this._convolver = this.context.createConvolver(); - /** - * the convolution buffer - * @type {Tone.Buffer} - * @private - */ - this._buffer = new Tone.Buffer(); - if (this.isString(options.url)) { - this._buffer.load(options.url, function (buffer) { - this.buffer = buffer; - options.onload(); - }.bind(this)); - } else if (options.url) { - this.buffer = options.url; - options.onload(); - } - this.connectEffect(this._convolver); - }; - Tone.extend(Tone.Convolver, Tone.Effect); - /** - * @static - * @const - * @type {Object} - */ - Tone.Convolver.defaults = { 'onload': Tone.noOp }; - /** - * The convolver's buffer - * @memberOf Tone.Convolver# - * @type {AudioBuffer} - * @name buffer - */ - Object.defineProperty(Tone.Convolver.prototype, 'buffer', { - get: function () { - return this._buffer.get(); - }, - set: function (buffer) { - this._buffer.set(buffer); - this._convolver.buffer = this._buffer.get(); - } - }); - /** - * Load an impulse response url as an audio buffer. - * Decodes the audio asynchronously and invokes - * the callback once the audio buffer loads. - * @param {string} url The url of the buffer to load. - * filetype support depends on the - * browser. - * @param {function=} callback - * @returns {Promise} - */ - Tone.Convolver.prototype.load = function (url, callback) { - return this._buffer.load(url, function (buff) { - this.buffer = buff; - if (callback) { - callback(); - } - }.bind(this)); - }; - /** - * Clean up. - * @returns {Tone.Convolver} this - */ - Tone.Convolver.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this._convolver.disconnect(); - this._convolver = null; - this._buffer.dispose(); - this._buffer = null; - return this; - }; - return Tone.Convolver; - }); - Module(function (Tone) { - - /** - * @class Tone.Distortion is a simple distortion effect using Tone.WaveShaper. - * Algorithm from [a stackoverflow answer](http://stackoverflow.com/a/22313408). - * - * @extends {Tone.Effect} - * @constructor - * @param {Number|Object} [distortion] The amount of distortion (nominal range of 0-1) - * @example - * var dist = new Tone.Distortion(0.8).toMaster(); - * var fm = new Tone.SimpleFM().connect(dist); - * //this sounds good on bass notes - * fm.triggerAttackRelease("A1", "8n"); - */ - Tone.Distortion = function () { - var options = this.optionsObject(arguments, ['distortion'], Tone.Distortion.defaults); - Tone.Effect.call(this, options); - /** - * @type {Tone.WaveShaper} - * @private - */ - this._shaper = new Tone.WaveShaper(4096); - /** - * holds the distortion amount - * @type {number} - * @private - */ - this._distortion = options.distortion; - this.connectEffect(this._shaper); - this.distortion = options.distortion; - this.oversample = options.oversample; - }; - Tone.extend(Tone.Distortion, Tone.Effect); - /** - * @static - * @const - * @type {Object} - */ - Tone.Distortion.defaults = { - 'distortion': 0.4, - 'oversample': 'none' - }; - /** - * The amount of distortion. - * @memberOf Tone.Distortion# - * @type {NormalRange} - * @name distortion - */ - Object.defineProperty(Tone.Distortion.prototype, 'distortion', { - get: function () { - return this._distortion; - }, - set: function (amount) { - this._distortion = amount; - var k = amount * 100; - var deg = Math.PI / 180; - this._shaper.setMap(function (x) { - if (Math.abs(x) < 0.001) { - //should output 0 when input is 0 - return 0; - } else { - return (3 + k) * x * 20 * deg / (Math.PI + k * Math.abs(x)); - } - }); - } - }); - /** - * The oversampling of the effect. Can either be "none", "2x" or "4x". - * @memberOf Tone.Distortion# - * @type {string} - * @name oversample - */ - Object.defineProperty(Tone.Distortion.prototype, 'oversample', { - get: function () { - return this._shaper.oversample; - }, - set: function (oversampling) { - this._shaper.oversample = oversampling; - } - }); - /** - * Clean up. - * @returns {Tone.Distortion} this - */ - Tone.Distortion.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this._shaper.dispose(); - this._shaper = null; - return this; - }; - return Tone.Distortion; - }); - Module(function (Tone) { - - /** - * @class Tone.FeedbackDelay is a DelayNode in which part of output - * signal is fed back into the delay. - * - * @constructor - * @extends {Tone.FeedbackEffect} - * @param {Time|Object} [delayTime] The delay applied to the incoming signal. - * @param {NormalRange=} feedback The amount of the effected signal which - * is fed back through the delay. - * @example - * var feedbackDelay = new Tone.FeedbackDelay("8n", 0.5).toMaster(); - * var tom = new Tone.DrumSynth({ - * "octaves" : 4, - * "pitchDecay" : 0.1 - * }).connect(feedbackDelay); - * tom.triggerAttackRelease("A2","32n"); - */ - Tone.FeedbackDelay = function () { - var options = this.optionsObject(arguments, [ - 'delayTime', - 'feedback' - ], Tone.FeedbackDelay.defaults); - Tone.FeedbackEffect.call(this, options); - /** - * the delay node - * @type {Tone.Delay} - * @private - */ - this._delayNode = new Tone.Delay(options.delayTime); - /** - * The delayTime of the DelayNode. - * @type {Time} - * @signal - */ - this.delayTime = this._delayNode.delayTime; - // connect it up - this.connectEffect(this._delayNode); - this._readOnly(['delayTime']); - }; - Tone.extend(Tone.FeedbackDelay, Tone.FeedbackEffect); - /** - * The default values. - * @const - * @static - * @type {Object} - */ - Tone.FeedbackDelay.defaults = { 'delayTime': 0.25 }; - /** - * clean up - * @returns {Tone.FeedbackDelay} this - */ - Tone.FeedbackDelay.prototype.dispose = function () { - Tone.FeedbackEffect.prototype.dispose.call(this); - this._delayNode.dispose(); - this._delayNode = null; - this._writable(['delayTime']); - this.delayTime = null; - return this; - }; - return Tone.FeedbackDelay; - }); - Module(function (Tone) { - - /** - * an array of comb filter delay values from Freeverb implementation - * @static - * @private - * @type {Array} - */ - var combFilterTunings = [ - 1557 / 44100, - 1617 / 44100, - 1491 / 44100, - 1422 / 44100, - 1277 / 44100, - 1356 / 44100, - 1188 / 44100, - 1116 / 44100 - ]; - /** - * an array of allpass filter frequency values from Freeverb implementation - * @private - * @static - * @type {Array} - */ - var allpassFilterFrequencies = [ - 225, - 556, - 441, - 341 - ]; - /** - * @class Tone.Freeverb is a reverb based on [Freeverb](https://ccrma.stanford.edu/~jos/pasp/Freeverb.html). - * Read more on reverb on [SoundOnSound](http://www.soundonsound.com/sos/may00/articles/reverb.htm). - * - * @extends {Tone.Effect} - * @constructor - * @param {NormalRange|Object} [roomSize] Correlated to the decay time. - * @param {Frequency} [dampening] The cutoff frequency of a lowpass filter as part - * of the reverb. - * @example - * var freeverb = new Tone.Freeverb().toMaster(); - * freeverb.dampening.value = 1000; - * //routing synth through the reverb - * var synth = new Tone.AMSynth().connect(freeverb); - */ - Tone.Freeverb = function () { - var options = this.optionsObject(arguments, [ - 'roomSize', - 'dampening' - ], Tone.Freeverb.defaults); - Tone.StereoEffect.call(this, options); - /** - * The roomSize value between. A larger roomSize - * will result in a longer decay. - * @type {NormalRange} - * @signal - */ - this.roomSize = new Tone.Signal(options.roomSize, Tone.Type.NormalRange); - /** - * The amount of dampening of the reverberant signal. - * @type {Frequency} - * @signal - */ - this.dampening = new Tone.Signal(options.dampening, Tone.Type.Frequency); - /** - * the comb filters - * @type {Array} - * @private - */ - this._combFilters = []; - /** - * the allpass filters on the left - * @type {Array} - * @private - */ - this._allpassFiltersL = []; - /** - * the allpass filters on the right - * @type {Array} - * @private - */ - this._allpassFiltersR = []; - //make the allpass filters on the right - for (var l = 0; l < allpassFilterFrequencies.length; l++) { - var allpassL = this.context.createBiquadFilter(); - allpassL.type = 'allpass'; - allpassL.frequency.value = allpassFilterFrequencies[l]; - this._allpassFiltersL.push(allpassL); - } - //make the allpass filters on the left - for (var r = 0; r < allpassFilterFrequencies.length; r++) { - var allpassR = this.context.createBiquadFilter(); - allpassR.type = 'allpass'; - allpassR.frequency.value = allpassFilterFrequencies[r]; - this._allpassFiltersR.push(allpassR); - } - //make the comb filters - for (var c = 0; c < combFilterTunings.length; c++) { - var lfpf = new Tone.LowpassCombFilter(combFilterTunings[c]); - if (c < combFilterTunings.length / 2) { - this.effectSendL.chain(lfpf, this._allpassFiltersL[0]); - } else { - this.effectSendR.chain(lfpf, this._allpassFiltersR[0]); - } - this.roomSize.connect(lfpf.resonance); - this.dampening.connect(lfpf.dampening); - this._combFilters.push(lfpf); - } - //chain the allpass filters togetehr - this.connectSeries.apply(this, this._allpassFiltersL); - this.connectSeries.apply(this, this._allpassFiltersR); - this._allpassFiltersL[this._allpassFiltersL.length - 1].connect(this.effectReturnL); - this._allpassFiltersR[this._allpassFiltersR.length - 1].connect(this.effectReturnR); - this._readOnly([ - 'roomSize', - 'dampening' - ]); - }; - Tone.extend(Tone.Freeverb, Tone.StereoEffect); - /** - * @static - * @type {Object} - */ - Tone.Freeverb.defaults = { - 'roomSize': 0.7, - 'dampening': 3000 - }; - /** - * Clean up. - * @returns {Tone.Freeverb} this - */ - Tone.Freeverb.prototype.dispose = function () { - Tone.StereoEffect.prototype.dispose.call(this); - for (var al = 0; al < this._allpassFiltersL.length; al++) { - this._allpassFiltersL[al].disconnect(); - this._allpassFiltersL[al] = null; - } - this._allpassFiltersL = null; - for (var ar = 0; ar < this._allpassFiltersR.length; ar++) { - this._allpassFiltersR[ar].disconnect(); - this._allpassFiltersR[ar] = null; - } - this._allpassFiltersR = null; - for (var cf = 0; cf < this._combFilters.length; cf++) { - this._combFilters[cf].dispose(); - this._combFilters[cf] = null; - } - this._combFilters = null; - this._writable([ - 'roomSize', - 'dampening' - ]); - this.roomSize.dispose(); - this.roomSize = null; - this.dampening.dispose(); - this.dampening = null; - return this; - }; - return Tone.Freeverb; - }); - Module(function (Tone) { - - /** - * an array of the comb filter delay time values - * @private - * @static - * @type {Array} - */ - var combFilterDelayTimes = [ - 1687 / 25000, - 1601 / 25000, - 2053 / 25000, - 2251 / 25000 - ]; - /** - * the resonances of each of the comb filters - * @private - * @static - * @type {Array} - */ - var combFilterResonances = [ - 0.773, - 0.802, - 0.753, - 0.733 - ]; - /** - * the allpass filter frequencies - * @private - * @static - * @type {Array} - */ - var allpassFilterFreqs = [ - 347, - 113, - 37 - ]; - /** - * @class Tone.JCReverb is a simple [Schroeder Reverberator](https://ccrma.stanford.edu/~jos/pasp/Schroeder_Reverberators.html) - * tuned by John Chowning in 1970. - * It is made up of three allpass filters and four Tone.FeedbackCombFilter. - * - * - * @extends {Tone.Effect} - * @constructor - * @param {NormalRange|Object} [roomSize] Coorelates to the decay time. - * @example - * var reverb = new Tone.JCReverb(0.4).connect(Tone.Master); - * var delay = new Tone.FeedbackDelay(0.5); - * //connecting the synth to reverb through delay - * var synth = new Tone.DuoSynth().chain(delay, reverb); - * synth.triggerAttackRelease("A4","8n"); - */ - Tone.JCReverb = function () { - var options = this.optionsObject(arguments, ['roomSize'], Tone.JCReverb.defaults); - Tone.StereoEffect.call(this, options); - /** - * room size control values between [0,1] - * @type {NormalRange} - * @signal - */ - this.roomSize = new Tone.Signal(options.roomSize, Tone.Type.NormalRange); - /** - * scale the room size - * @type {Tone.Scale} - * @private - */ - this._scaleRoomSize = new Tone.Scale(-0.733, 0.197); - /** - * a series of allpass filters - * @type {Array} - * @private - */ - this._allpassFilters = []; - /** - * parallel feedback comb filters - * @type {Array} - * @private - */ - this._feedbackCombFilters = []; - //make the allpass filters - for (var af = 0; af < allpassFilterFreqs.length; af++) { - var allpass = this.context.createBiquadFilter(); - allpass.type = 'allpass'; - allpass.frequency.value = allpassFilterFreqs[af]; - this._allpassFilters.push(allpass); - } - //and the comb filters - for (var cf = 0; cf < combFilterDelayTimes.length; cf++) { - var fbcf = new Tone.FeedbackCombFilter(combFilterDelayTimes[cf], 0.1); - this._scaleRoomSize.connect(fbcf.resonance); - fbcf.resonance.value = combFilterResonances[cf]; - this._allpassFilters[this._allpassFilters.length - 1].connect(fbcf); - if (cf < combFilterDelayTimes.length / 2) { - fbcf.connect(this.effectReturnL); - } else { - fbcf.connect(this.effectReturnR); - } - this._feedbackCombFilters.push(fbcf); - } - //chain the allpass filters together - this.roomSize.connect(this._scaleRoomSize); - this.connectSeries.apply(this, this._allpassFilters); - this.effectSendL.connect(this._allpassFilters[0]); - this.effectSendR.connect(this._allpassFilters[0]); - this._readOnly(['roomSize']); - }; - Tone.extend(Tone.JCReverb, Tone.StereoEffect); - /** - * the default values - * @static - * @const - * @type {Object} - */ - Tone.JCReverb.defaults = { 'roomSize': 0.5 }; - /** - * Clean up. - * @returns {Tone.JCReverb} this - */ - Tone.JCReverb.prototype.dispose = function () { - Tone.StereoEffect.prototype.dispose.call(this); - for (var apf = 0; apf < this._allpassFilters.length; apf++) { - this._allpassFilters[apf].disconnect(); - this._allpassFilters[apf] = null; - } - this._allpassFilters = null; - for (var fbcf = 0; fbcf < this._feedbackCombFilters.length; fbcf++) { - this._feedbackCombFilters[fbcf].dispose(); - this._feedbackCombFilters[fbcf] = null; - } - this._feedbackCombFilters = null; - this._writable(['roomSize']); - this.roomSize.dispose(); - this.roomSize = null; - this._scaleRoomSize.dispose(); - this._scaleRoomSize = null; - return this; - }; - return Tone.JCReverb; - }); - 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) - * and effects them separately before being recombined. - * Applies a Mid/Side seperation and recombination. - * Algorithm found in [kvraudio forums](http://www.kvraudio.com/forum/viewtopic.php?t=212587). - * <br><br> - * This is a base-class for Mid/Side Effects. - * - * @extends {Tone.Effect} - * @constructor - */ - Tone.MidSideEffect = function () { - Tone.Effect.apply(this, arguments); - /** - * The mid/side split - * @type {Tone.MidSideSplit} - * @private - */ - this._midSideSplit = new Tone.MidSideSplit(); - /** - * The mid/side merge - * @type {Tone.MidSideMerge} - * @private - */ - this._midSideMerge = new Tone.MidSideMerge(); - /** - * The mid send. Connect to mid processing - * @type {Tone.Expr} - * @private - */ - this.midSend = this._midSideSplit.mid; - /** - * The side send. Connect to side processing - * @type {Tone.Expr} - * @private - */ - this.sideSend = this._midSideSplit.side; - /** - * The mid return connection - * @type {GainNode} - * @private - */ - this.midReturn = this._midSideMerge.mid; - /** - * The side return connection - * @type {GainNode} - * @private - */ - this.sideReturn = this._midSideMerge.side; - //the connections - this.effectSend.connect(this._midSideSplit); - this._midSideMerge.connect(this.effectReturn); - }; - Tone.extend(Tone.MidSideEffect, Tone.Effect); - /** - * Clean up. - * @returns {Tone.MidSideEffect} this - */ - Tone.MidSideEffect.prototype.dispose = function () { - Tone.Effect.prototype.dispose.call(this); - this._midSideSplit.dispose(); - this._midSideSplit = null; - this._midSideMerge.dispose(); - this._midSideMerge = null; - this.midSend = null; - this.sideSend = null; - this.midReturn = null; - this.sideReturn = null; - return this; - }; - return Tone.MidSideEffect; - }); - Module(function (Tone) { - - /** - * @class Tone.Phaser is a phaser effect. Phasers work by changing the phase - * of different frequency components of an incoming signal. Read more on - * [Wikipedia](https://en.wikipedia.org/wiki/Phaser_(effect)). - * Inspiration for this phaser comes from [Tuna.js](https://github.com/Dinahmoe/tuna/). - * - * @extends {Tone.StereoEffect} - * @constructor - * @param {Frequency|Object} [frequency] The speed of the phasing. - * @param {number} [octaves] The octaves of the effect. - * @param {Frequency} [baseFrequency] The base frequency of the filters. - * @example - * var phaser = new Tone.Phaser({ - * "frequency" : 15, - * "octaves" : 5, - * "baseFrequency" : 1000 - * }).toMaster(); - * var synth = new Tone.FMSynth().connect(phaser); - * synth.triggerAttackRelease("E3", "2n"); - */ - Tone.Phaser = function () { - //set the defaults - var options = this.optionsObject(arguments, [ - 'frequency', - 'octaves', - 'baseFrequency' - ], Tone.Phaser.defaults); - Tone.StereoEffect.call(this, options); - /** - * the lfo which controls the frequency on the left side - * @type {Tone.LFO} - * @private - */ - this._lfoL = new Tone.LFO(options.frequency, 0, 1); - /** - * the lfo which controls the frequency on the right side - * @type {Tone.LFO} - * @private - */ - this._lfoR = new Tone.LFO(options.frequency, 0, 1); - this._lfoR.phase = 180; - /** - * the base modulation frequency - * @type {number} - * @private - */ - this._baseFrequency = options.baseFrequency; - /** - * the octaves of the phasing - * @type {number} - * @private - */ - this._octaves = options.octaves; - /** - * The quality factor of the filters - * @type {Positive} - * @signal - */ - this.Q = new Tone.Signal(options.Q, Tone.Type.Positive); - /** - * the array of filters for the left side - * @type {Array} - * @private - */ - this._filtersL = this._makeFilters(options.stages, this._lfoL, this.Q); - /** - * the array of filters for the left side - * @type {Array} - * @private - */ - this._filtersR = this._makeFilters(options.stages, this._lfoR, this.Q); - /** - * the frequency of the effect - * @type {Tone.Signal} - */ - this.frequency = this._lfoL.frequency; - this.frequency.value = options.frequency; - //connect them up - this.effectSendL.connect(this._filtersL[0]); - this.effectSendR.connect(this._filtersR[0]); - this._filtersL[options.stages - 1].connect(this.effectReturnL); - this._filtersR[options.stages - 1].connect(this.effectReturnR); - //control the frequency with one LFO - this._lfoL.frequency.connect(this._lfoR.frequency); - //set the options - this.baseFrequency = options.baseFrequency; - this.octaves = options.octaves; - //start the lfo - this._lfoL.start(); - this._lfoR.start(); - this._readOnly([ - 'frequency', - 'Q' - ]); - }; - Tone.extend(Tone.Phaser, Tone.StereoEffect); - /** - * defaults - * @static - * @type {object} - */ - Tone.Phaser.defaults = { - 'frequency': 0.5, - 'octaves': 3, - 'stages': 10, - 'Q': 10, - 'baseFrequency': 350 - }; - /** - * @param {number} stages - * @returns {Array} the number of filters all connected together - * @private - */ - Tone.Phaser.prototype._makeFilters = function (stages, connectToFreq, Q) { - var filters = new Array(stages); - //make all the filters - for (var i = 0; i < stages; i++) { - var filter = this.context.createBiquadFilter(); - filter.type = 'allpass'; - Q.connect(filter.Q); - connectToFreq.connect(filter.frequency); - filters[i] = filter; - } - this.connectSeries.apply(this, filters); - return filters; - }; - /** - * The number of octaves the phase goes above - * the baseFrequency - * @memberOf Tone.Phaser# - * @type {Positive} - * @name octaves - */ - Object.defineProperty(Tone.Phaser.prototype, 'octaves', { - get: function () { - return this._octaves; - }, - set: function (octaves) { - this._octaves = octaves; - var max = this._baseFrequency * Math.pow(2, octaves); - this._lfoL.max = max; - this._lfoR.max = max; - } - }); - /** - * The the base frequency of the filters. - * @memberOf Tone.Phaser# - * @type {number} - * @name baseFrequency - */ - Object.defineProperty(Tone.Phaser.prototype, 'baseFrequency', { - get: function () { - return this._baseFrequency; - }, - set: function (freq) { - this._baseFrequency = freq; - this._lfoL.min = freq; - this._lfoR.min = freq; - this.octaves = this._octaves; - } - }); - /** - * clean up - * @returns {Tone.Phaser} this - */ - Tone.Phaser.prototype.dispose = function () { - Tone.StereoEffect.prototype.dispose.call(this); - this._writable([ - 'frequency', - 'Q' - ]); - this.Q.dispose(); - this.Q = null; - this._lfoL.dispose(); - this._lfoL = null; - this._lfoR.dispose(); - this._lfoR = null; - for (var i = 0; i < this._filtersL.length; i++) { - this._filtersL[i].disconnect(); - this._filtersL[i] = null; - } - this._filtersL = null; - for (var j = 0; j < this._filtersR.length; j++) { - this._filtersR[j].disconnect(); - this._filtersR[j] = null; - } - this._filtersR = null; - this.frequency = null; - return this; - }; - return Tone.Phaser; - }); - Module(function (Tone) { - - /** - * @class Tone.PingPongDelay is a feedback delay effect where the echo is heard - * first in one channel and next in the opposite channel. In a stereo - * system these are the right and left channels. - * PingPongDelay in more simplified terms is two Tone.FeedbackDelays - * with independent delay values. Each delay is routed to one channel - * (left or right), and the channel triggered second will always - * trigger at the same interval after the first. - * - * @constructor - * @extends {Tone.StereoXFeedbackEffect} - * @param {Time|Object} [delayTime] The delayTime between consecutive echos. - * @param {NormalRange=} feedback The amount of the effected signal which - * is fed back through the delay. - * @example - * var pingPong = new Tone.PingPongDelay("4n", 0.2).toMaster(); - * var drum = new Tone.DrumSynth().connect(pingPong); - * drum.triggerAttackRelease("C4", "32n"); - */ - Tone.PingPongDelay = function () { - var options = this.optionsObject(arguments, [ - 'delayTime', - 'feedback' - ], Tone.PingPongDelay.defaults); - Tone.StereoXFeedbackEffect.call(this, options); - /** - * the delay node on the left side - * @type {Tone.Delay} - * @private - */ - this._leftDelay = new Tone.Delay(0, options.maxDelayTime); - /** - * the delay node on the right side - * @type {Tone.Delay} - * @private - */ - this._rightDelay = new Tone.Delay(0, options.maxDelayTime); - /** - * the predelay on the right side - * @type {Tone.Delay} - * @private - */ - this._rightPreDelay = new Tone.Delay(0, options.maxDelayTime); - /** - * the delay time signal - * @type {Time} - * @signal - */ - this.delayTime = new Tone.Signal(options.delayTime, Tone.Type.Time); - //connect it up - this.effectSendL.chain(this._leftDelay, this.effectReturnL); - this.effectSendR.chain(this._rightPreDelay, this._rightDelay, this.effectReturnR); - this.delayTime.fan(this._leftDelay.delayTime, this._rightDelay.delayTime, this._rightPreDelay.delayTime); - //rearranged the feedback to be after the rightPreDelay - this._feedbackLR.disconnect(); - this._feedbackLR.connect(this._rightDelay); - this._readOnly(['delayTime']); - }; - Tone.extend(Tone.PingPongDelay, Tone.StereoXFeedbackEffect); - /** - * @static - * @type {Object} - */ - Tone.PingPongDelay.defaults = { - 'delayTime': 0.25, - 'maxDelayTime': 1 - }; - /** - * Clean up. - * @returns {Tone.PingPongDelay} this - */ - Tone.PingPongDelay.prototype.dispose = function () { - Tone.StereoXFeedbackEffect.prototype.dispose.call(this); - this._leftDelay.dispose(); - this._leftDelay = null; - this._rightDelay.dispose(); - this._rightDelay = null; - this._rightPreDelay.dispose(); - this._rightPreDelay = null; - this._writable(['delayTime']); - this.delayTime.dispose(); - this.delayTime = null; - return this; - }; - return Tone.PingPongDelay; - }); - Module(function (Tone) { - - /** - * @class Tone.PitchShift does near-realtime pitch shifting to the incoming signal. - * The effect is achieved by speeding up or slowing down the delayTime - * of a DelayNode using a sawtooth wave. - * Algorithm found in [this pdf](http://dsp-book.narod.ru/soundproc.pdf). - * Additional reference by [Miller Pucket](http://msp.ucsd.edu/techniques/v0.11/book-html/node115.html). - * - * @extends {Tone.FeedbackEffect} - * @param {Interval=} pitch The interval to transpose the incoming signal by. - */ - Tone.PitchShift = function () { - var options = this.optionsObject(arguments, ['pitch'], Tone.PitchShift.defaults); - Tone.FeedbackEffect.call(this, options); - /** - * The pitch signal - * @type {Tone.Signal} - * @private - */ - this._frequency = new Tone.Signal(0); - /** - * Uses two DelayNodes to cover up the jump in - * the sawtooth wave. - * @type {DelayNode} - * @private - */ - this._delayA = new Tone.Delay(0, 1); - /** - * The first LFO. - * @type {Tone.LFO} - * @private - */ - this._lfoA = new Tone.LFO({ - 'min': 0, - 'max': 0.1, - 'type': 'sawtooth' - }).connect(this._delayA.delayTime); - /** - * The second DelayNode - * @type {DelayNode} - * @private - */ - this._delayB = new Tone.Delay(0, 1); - /** - * The first LFO. - * @type {Tone.LFO} - * @private - */ - this._lfoB = new Tone.LFO({ - 'min': 0, - 'max': 0.1, - 'type': 'sawtooth', - 'phase': 180 - }).connect(this._delayB.delayTime); - /** - * Crossfade quickly between the two delay lines - * to cover up the jump in the sawtooth wave - * @type {Tone.CrossFade} - * @private - */ - this._crossFade = new Tone.CrossFade(); - /** - * LFO which alternates between the two - * delay lines to cover up the disparity in the - * sawtooth wave. - * @type {Tone.LFO} - * @private - */ - this._crossFadeLFO = new Tone.LFO({ - 'min': 0, - 'max': 1, - 'type': 'triangle', - 'phase': 90 - }).connect(this._crossFade.fade); - /** - * The delay node - * @type {Tone.Delay} - * @private - */ - this._feedbackDelay = new Tone.Delay(options.delayTime); - /** - * The amount of delay on the input signal - * @type {Time} - * @signal - */ - this.delayTime = this._feedbackDelay.delayTime; - this._readOnly('delayTime'); - /** - * Hold the current pitch - * @type {Number} - * @private - */ - this._pitch = options.pitch; - /** - * Hold the current windowSize - * @type {Number} - * @private - */ - this._windowSize = options.windowSize; - //connect the two delay lines up - this._delayA.connect(this._crossFade.a); - this._delayB.connect(this._crossFade.b); - //connect the frequency - this._frequency.fan(this._lfoA.frequency, this._lfoB.frequency, this._crossFadeLFO.frequency); - //route the input - this.effectSend.fan(this._delayA, this._delayB); - this._crossFade.chain(this._feedbackDelay, this.effectReturn); - //start the LFOs at the same time - var now = this.now(); - this._lfoA.start(now); - this._lfoB.start(now); - this._crossFadeLFO.start(now); - //set the initial value - this.windowSize = this._windowSize; - }; - Tone.extend(Tone.PitchShift, Tone.FeedbackEffect); - /** - * default values - * @static - * @type {Object} - * @const - */ - Tone.PitchShift.defaults = { - 'pitch': 0, - 'windowSize': 0.1, - 'delayTime': 0, - 'feedback': 0 - }; - /** - * Repitch the incoming signal by some interval (measured - * in semi-tones). - * @memberOf Tone.PitchShift# - * @type {Interval} - * @name pitch - * @example - * pitchShift.pitch = -12; //down one octave - * pitchShift.pitch = 7; //up a fifth - */ - Object.defineProperty(Tone.PitchShift.prototype, 'pitch', { - get: function () { - return this._pitch; - }, - set: function (interval) { - this._pitch = interval; - var factor = 0; - if (interval < 0) { - this._lfoA.min = 0; - this._lfoA.max = this._windowSize; - this._lfoB.min = 0; - this._lfoB.max = this._windowSize; - factor = this.intervalToFrequencyRatio(interval - 1) + 1; - } else { - this._lfoA.min = this._windowSize; - this._lfoA.max = 0; - this._lfoB.min = this._windowSize; - this._lfoB.max = 0; - factor = this.intervalToFrequencyRatio(interval) - 1; - } - this._frequency.value = factor * (1.2 / this._windowSize); - } - }); - /** - * The window size corresponds roughly to the sample length in a looping sampler. - * Smaller values are desirable for a less noticeable delay time of the pitch shifted - * signal, but larger values will result in smoother pitch shifting for larger intervals. - * A nominal range of 0.03 to 0.1 is recommended. - * @memberOf Tone.PitchShift# - * @type {Time} - * @name windowSize - * @example - * pitchShift.windowSize = 0.1; - */ - Object.defineProperty(Tone.PitchShift.prototype, 'windowSize', { - get: function () { - return this._windowSize; - }, - set: function (size) { - this._windowSize = this.toSeconds(size); - this.pitch = this._pitch; - } - }); - /** - * Clean up. - * @return {Tone.PitchShift} this - */ - Tone.PitchShift.prototype.dispose = function () { - Tone.FeedbackEffect.prototype.dispose.call(this); - this._frequency.dispose(); - this._frequency = null; - this._delayA.disconnect(); - this._delayA = null; - this._delayB.disconnect(); - this._delayB = null; - this._lfoA.dispose(); - this._lfoA = null; - this._lfoB.dispose(); - this._lfoB = null; - this._crossFade.dispose(); - this._crossFade = null; - this._crossFadeLFO.dispose(); - this._crossFadeLFO = null; - this._writable('delayTime'); - this._feedbackDelay.dispose(); - this._feedbackDelay = null; - this.delayTime = null; - return this; - }; - return Tone.PitchShift; - }); - Module(function (Tone) { - - /** - * @class Base class for stereo feedback effects where the effectReturn - * is fed back into the same channel. - * - * @constructor - * @extends {Tone.FeedbackEffect} - */ - Tone.StereoFeedbackEffect = function () { - var options = this.optionsObject(arguments, ['feedback'], Tone.FeedbackEffect.defaults); - Tone.StereoEffect.call(this, options); - /** - * controls the amount of feedback - * @type {NormalRange} - * @signal - */ - this.feedback = new Tone.Signal(options.feedback, Tone.Type.NormalRange); - /** - * the left side feeback - * @type {Tone.Gain} - * @private - */ - this._feedbackL = new Tone.Gain(); - /** - * the right side feeback - * @type {Tone.Gain} - * @private - */ - this._feedbackR = new Tone.Gain(); - //connect it up - this.effectReturnL.chain(this._feedbackL, this.effectSendL); - this.effectReturnR.chain(this._feedbackR, this.effectSendR); - this.feedback.fan(this._feedbackL.gain, this._feedbackR.gain); - this._readOnly(['feedback']); - }; - Tone.extend(Tone.StereoFeedbackEffect, Tone.FeedbackEffect); - /** - * clean up - * @returns {Tone.StereoFeedbackEffect} this - */ - Tone.StereoFeedbackEffect.prototype.dispose = function () { - Tone.StereoEffect.prototype.dispose.call(this); - this._writable(['feedback']); - this.feedback.dispose(); - this.feedback = null; - this._feedbackL.dispose(); - this._feedbackL = null; - this._feedbackR.dispose(); - this._feedbackR = null; - return this; - }; - return Tone.StereoFeedbackEffect; - }); - Module(function (Tone) { - - /** - * @class Applies a width factor to the mid/side seperation. - * 0 is all mid and 1 is all side. - * Algorithm found in [kvraudio forums](http://www.kvraudio.com/forum/viewtopic.php?t=212587). - * <br><br> - * <code> - * Mid *= 2*(1-width)<br> - * Side *= 2*width - * </code> - * - * @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 = this.optionsObject(arguments, ['width'], Tone.StereoWidener.defaults); - 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 = this.optionsObject(arguments, [ - 'frequency', - 'depth' - ], Tone.Tremolo.defaults); - 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 = this.optionsObject(arguments, [ - 'frequency', - 'depth' - ], Tone.Vibrato.defaults); - 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 = this.optionsObject(arguments, [ - 'callback', - 'value' - ], Tone.Event.defaults); - /** - * 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; - /** - * The probability that the callback will be invoked - * at the scheduled time. - * @type {NormalRange} - * @example - * //the callback will be invoked 50% of the time - * event.probability = 0.5; - */ - this.probability = options.probability; - /** - * If set to true, will apply small (+/-0.02 seconds) 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} - */ - 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 = this.defaultArg(after, -1); - this._state.forEachFrom(after, function (event) { - var duration; - if (event.state === Tone.State.Started) { - if (!this.isUndef(event.id)) { - Tone.Transport.clear(event.id); - } - var startTick = event.time + Math.round(this.startOffset / this._playbackRate); - if (this._loop) { - duration = Infinity; - if (this.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; - } - }); - /** - * 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 = this.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 (!this.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 = this.optionsObject(arguments, [ - 'callback', - 'interval' - ], Tone.Loop.defaults); - /** - * 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; - } - return this._pattern.index; - }, - 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/stoped 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 = this.optionsObject(arguments, [ - 'callback', - 'events' - ], Tone.Part.defaults); - /** - * If the part is looping or not - * @type {Boolean|Positive} - * @private - */ - this._loop = options.loop; - /** - * When the note is scheduled to start. - * @type {Ticks} - * @private - */ - this._loopStart = this.toTicks(options.loopStart); - /** - * When the note is scheduled to start. - * @type {Ticks} - * @private - */ - this._loopEnd = this.toTicks(options.loopEnd); - /** - * The playback rate of the part - * @type {Positive} - * @private - */ - this._playbackRate = options.playbackRate; - /** - * 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; - /** - * The start offset - * @type {Ticks} - * @private - */ - this._startOffset = 0; - /** - * Keeps track of the current state - * @type {Tone.TimelineState} - * @private - */ - this._state = new Tone.TimelineState(Tone.State.Stopped); - /** - * An array of Objects. - * @type {Array} - * @private - */ - this._events = []; - /** - * The callback to invoke at all the scheduled events. - * @type {Function} - */ - this.callback = options.callback; - /** - * If mute is true, the callback won't be - * invoked. - * @type {Boolean} - */ - this.mute = options.mute; - //add the events - var events = this.defaultArg(options.events, []); - if (!this.isUndef(options.events)) { - for (var i = 0; i < events.length; i++) { - if (Array.isArray(events[i])) { - this.add(events[i][0], events[i][1]); - } else { - this.add(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 - }; - /** - * 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 = this.defaultArg(offset, this._loopStart); - } else { - offset = this.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 (!this.isUndef(value)) { - event.value = value; - } - return event; - } - } - //if there was no event at that time, create one - if (!this.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 (this.isUndef(value) || !this.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) { - after = this.toTicks(after); - this._forEach(function (event) { - event.cancel(after); - }); - this._state.cancel(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) { - ctx = this.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 = this.optionsObject(arguments, [ - 'callback', - 'values', - 'pattern' - ], Tone.Pattern.defaults); - 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, - '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 = this.optionsObject(arguments, [ - 'callback', - 'events', - 'subdivision' - ], Tone.Sequence.defaults); - //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 (this.isUndef(options.loopEnd) && !this.isUndef(events)) { - this._loopEnd = events.length * this._subdivision; - } - //defaults to looping - this._loop = true; - //add all of the events - if (!this.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 (this.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 (this.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.Oscillator} - * @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 = this.optionsObject(arguments, [ - 'frequency', - 'width' - ], Tone.Oscillator.defaults); - 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.Oscillator); - /** - * 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.Oscillator} - * @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 = this.optionsObject(arguments, [ - 'frequency', - 'modulationFrequency' - ], Tone.PWMOscillator.defaults); - 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.Oscillator); - /** - * 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.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.FMOscillator("Ab3", "sine", "square").toMaster().start(); - */ - Tone.FMOscillator = function () { - var options = this.optionsObject(arguments, [ - 'frequency', - 'type', - 'modulationType' - ], Tone.FMOscillator.defaults); - 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.Oscillator); - /** - * 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 = this.optionsObject(arguments, [ - 'frequency', - 'type', - 'modulationType' - ], Tone.AMOscillator.defaults); - 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.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.FatOscillator("Ab3", "sine", "square").toMaster().start(); - */ - Tone.FatOscillator = function () { - var options = this.optionsObject(arguments, [ - 'frequency', - 'type', - 'spread' - ], Tone.FatOscillator.defaults); - 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 = this.defaultArg(options.partials, []); - //set the count initially - this.count = options.count; - this._readOnly([ - 'frequency', - 'detune' - ]); - }; - Tone.extend(Tone.FatOscillator, Tone.Oscillator); - /** - * 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.Oscillator} - * @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 = this.optionsObject(arguments, [ - 'frequency', - 'type' - ], Tone.OmniOscillator.defaults); - 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.Oscillator); - /** - * 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 (this.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() + this.blockTime; - if (this._oscillator !== null) { - var oldOsc = this._oscillator; - oldOsc.stop(now); - //dispose the old one - setTimeout(function () { - oldOsc.dispose(); - oldOsc = null; - }, this.blockTime * 1000); - } - 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} - */ - Tone.Instrument = function (options) { - //get the defaults - options = this.defaultArg(options, Tone.Instrument.defaults); - /** - * 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); - /** - * 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) { - if (this.isUndef(time)) { - time = this.now() + this.blockTime; - } else { - 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.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 = this.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) { - if (this.isUndef(time)) { - time = this.now() + this.blockTime; - } else { - 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) { - if (this.isUndef(time)) { - time = this.now() + this.blockTime; - } else { - 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. - * <img src="https://docs.google.com/drawings/d/1-1_0YW2Z1J2EPI36P8fNCMcZG7N1w1GZluPs4og4evo/pub?w=1163&h=231"> - * - * @constructor - * @extends {Tone.Monophonic} - * @param {Object} [options] the options available for the synth - * see defaults below - * @example - * var synth = new Tone.Synth().toMaster(); - * synth.triggerAttackRelease("C4", "8n"); - */ - Tone.Synth = function (options) { - //get the defaults - options = this.defaultArg(options, Tone.Synth.defaults); - Tone.Monophonic.call(this, options); - /** - * The oscillator. - * @type {Tone.OmniOscillator} - */ - this.oscillator = new Tone.OmniOscillator(options.oscillator); - /** - * The frequency control. - * @type {Frequency} - * @signal - */ - this.frequency = this.oscillator.frequency; - /** - * The detune control. - * @type {Cents} - * @signal - */ - this.detune = this.oscillator.detune; - /** - * The amplitude envelope. - * @type {Tone.AmplitudeEnvelope} - */ - this.envelope = new Tone.AmplitudeEnvelope(options.envelope); - //connect the oscillators to the output - this.oscillator.chain(this.envelope, this.output); - //start the oscillators - this.oscillator.start(); - this._readOnly([ - 'oscillator', - 'frequency', - 'detune', - 'envelope' - ]); - }; - Tone.extend(Tone.Synth, Tone.Monophonic); - /** - * @const - * @static - * @type {Object} - */ - Tone.Synth.defaults = { - 'oscillator': { 'type': 'triangle' }, - 'envelope': { - 'attack': 0.005, - 'decay': 0.1, - 'sustain': 0.3, - 'release': 1 - } - }; - /** - * start the attack portion of the envelope - * @param {Time} [time=now] the time the attack should start - * @param {number} [velocity=1] the velocity of the note (0-1) - * @returns {Tone.Synth} this - * @private - */ - Tone.Synth.prototype._triggerEnvelopeAttack = function (time, velocity) { - //the envelopes - this.envelope.triggerAttack(time, velocity); - return this; - }; - /** - * start the release portion of the envelope - * @param {Time} [time=now] the time the release should start - * @returns {Tone.Synth} this - * @private - */ - Tone.Synth.prototype._triggerEnvelopeRelease = function (time) { - this.envelope.triggerRelease(time); - return this; - }; - /** - * clean up - * @returns {Tone.Synth} this - */ - Tone.Synth.prototype.dispose = function () { - Tone.Monophonic.prototype.dispose.call(this); - this._writable([ - 'oscillator', - 'frequency', - 'detune', - 'envelope' - ]); - this.oscillator.dispose(); - this.oscillator = null; - this.envelope.dispose(); - this.envelope = null; - this.frequency = null; - this.detune = null; - return this; - }; - return Tone.Synth; - }); - Module(function (Tone) { - - /** - * @class AMSynth uses the output of one Tone.Synth to modulate the - * amplitude of another Tone.Synth. The harmonicity (the ratio between - * the two signals) affects the timbre of the output signal greatly. - * Read more about Amplitude Modulation Synthesis on - * [SoundOnSound](http://www.soundonsound.com/sos/mar00/articles/synthsecrets.htm). - * <img src="https://docs.google.com/drawings/d/1TQu8Ed4iFr1YTLKpB3U1_hur-UwBrh5gdBXc8BxfGKw/pub?w=1009&h=457"> - * - * @constructor - * @extends {Tone.Monophonic} - * @param {Object} [options] the options available for the synth - * see defaults below - * @example - * var synth = new Tone.AMSynth().toMaster(); - * synth.triggerAttackRelease("C4", "4n"); - */ - Tone.AMSynth = function (options) { - options = this.defaultArg(options, Tone.AMSynth.defaults); - Tone.Monophonic.call(this, options); - /** - * The carrier voice. - * @type {Tone.Synth} - * @private - */ - this._carrier = new Tone.Synth(); - this._carrier.volume.value = -10; - /** - * The carrier's oscillator - * @type {Tone.Oscillator} - */ - this.oscillator = this._carrier.oscillator; - /** - * The carrier's envelope - * @type {Tone.AmplitudeEnvelope} - */ - this.envelope = this._carrier.envelope.set(options.envelope); - /** - * The modulator voice. - * @type {Tone.Synth} - * @private - */ - this._modulator = new Tone.Synth(); - this._modulator.volume.value = -10; - /** - * The modulator's oscillator which is applied - * to the amplitude of the oscillator - * @type {Tone.Oscillator} - */ - this.modulation = this._modulator.oscillator.set(options.modulation); - /** - * The modulator's envelope - * @type {Tone.AmplitudeEnvelope} - */ - this.modulationEnvelope = this._modulator.envelope.set(options.modulationEnvelope); - /** - * The frequency. - * @type {Frequency} - * @signal - */ - this.frequency = new Tone.Signal(440, Tone.Type.Frequency); - /** - * The detune in cents - * @type {Cents} - * @signal - */ - this.detune = new Tone.Signal(options.detune, Tone.Type.Cents); - /** - * Harmonicity is the ratio between the two voices. A harmonicity of - * 1 is no change. Harmonicity = 2 means a change of an octave. - * @type {Positive} - * @signal - * @example - * //pitch voice1 an octave below voice0 - * synth.harmonicity.value = 0.5; - */ - this.harmonicity = new Tone.Multiply(options.harmonicity); - this.harmonicity.units = Tone.Type.Positive; - /** - * convert the -1,1 output to 0,1 - * @type {Tone.AudioToGain} - * @private - */ - this._modulationScale = new Tone.AudioToGain(); - /** - * the node where the modulation happens - * @type {Tone.Gain} - * @private - */ - this._modulationNode = new Tone.Gain(); - //control the two voices frequency - this.frequency.connect(this._carrier.frequency); - this.frequency.chain(this.harmonicity, this._modulator.frequency); - this.detune.fan(this._carrier.detune, this._modulator.detune); - this._modulator.chain(this._modulationScale, this._modulationNode.gain); - this._carrier.chain(this._modulationNode, this.output); - this._readOnly([ - 'frequency', - 'harmonicity', - 'oscillator', - 'envelope', - 'modulation', - 'modulationEnvelope', - 'detune' - ]); - }; - Tone.extend(Tone.AMSynth, Tone.Monophonic); - /** - * @static - * @type {Object} - */ - Tone.AMSynth.defaults = { - 'harmonicity': 3, - 'detune': 0, - 'oscillator': { 'type': 'sine' }, - 'envelope': { - 'attack': 0.01, - 'decay': 0.01, - 'sustain': 1, - 'release': 0.5 - }, - 'modulation': { 'type': 'square' }, - 'modulationEnvelope': { - 'attack': 0.5, - 'decay': 0, - 'sustain': 1, - 'release': 0.5 - } - }; - /** - * trigger the attack portion of the note - * - * @param {Time} [time=now] the time the note will occur - * @param {NormalRange} [velocity=1] the velocity of the note - * @private - * @returns {Tone.AMSynth} this - */ - Tone.AMSynth.prototype._triggerEnvelopeAttack = function (time, velocity) { - //the port glide - time = this.toSeconds(time); - //the envelopes - this.envelope.triggerAttack(time, velocity); - this.modulationEnvelope.triggerAttack(time, velocity); - return this; - }; - /** - * trigger the release portion of the note - * - * @param {Time} [time=now] the time the note will release - * @private - * @returns {Tone.AMSynth} this - */ - Tone.AMSynth.prototype._triggerEnvelopeRelease = function (time) { - this.envelope.triggerRelease(time); - this.modulationEnvelope.triggerRelease(time); - return this; - }; - /** - * clean up - * @returns {Tone.AMSynth} this - */ - Tone.AMSynth.prototype.dispose = function () { - Tone.Monophonic.prototype.dispose.call(this); - this._writable([ - 'frequency', - 'harmonicity', - 'oscillator', - 'envelope', - 'modulation', - 'modulationEnvelope', - 'detune' - ]); - this._carrier.dispose(); - this._carrier = null; - this._modulator.dispose(); - this._modulator = null; - this.frequency.dispose(); - this.frequency = null; - this.detune.dispose(); - this.detune = null; - this.harmonicity.dispose(); - this.harmonicity = null; - this._modulationScale.dispose(); - this._modulationScale = null; - this._modulationNode.dispose(); - this._modulationNode = null; - this.oscillator = null; - this.envelope = null; - this.modulationEnvelope = null; - this.modulation = null; - return this; - }; - return Tone.AMSynth; - }); - Module(function (Tone) { - - /** - * @class Tone.MonoSynth is composed of one oscillator, one filter, and two envelopes. - * The amplitude of the Tone.Oscillator and the cutoff frequency of the - * Tone.Filter are controlled by Tone.Envelopes. - * <img src="https://docs.google.com/drawings/d/1gaY1DF9_Hzkodqf8JI1Cg2VZfwSElpFQfI94IQwad38/pub?w=924&h=240"> - * - * @constructor - * @extends {Tone.Monophonic} - * @param {Object} [options] the options available for the synth - * see defaults below - * @example - * var synth = new Tone.MonoSynth({ - * "oscillator" : { - * "type" : "square" - * }, - * "envelope" : { - * "attack" : 0.1 - * } - * }).toMaster(); - * synth.triggerAttackRelease("C4", "8n"); - */ - Tone.MonoSynth = function (options) { - //get the defaults - options = this.defaultArg(options, Tone.MonoSynth.defaults); - Tone.Monophonic.call(this, options); - /** - * The oscillator. - * @type {Tone.OmniOscillator} - */ - this.oscillator = new Tone.OmniOscillator(options.oscillator); - /** - * The frequency control. - * @type {Frequency} - * @signal - */ - this.frequency = this.oscillator.frequency; - /** - * The detune control. - * @type {Cents} - * @signal - */ - this.detune = this.oscillator.detune; - /** - * The filter. - * @type {Tone.Filter} - */ - this.filter = new Tone.Filter(options.filter); - /** - * The filter envelope. - * @type {Tone.FrequencyEnvelope} - */ - this.filterEnvelope = new Tone.FrequencyEnvelope(options.filterEnvelope); - /** - * The amplitude envelope. - * @type {Tone.AmplitudeEnvelope} - */ - this.envelope = new Tone.AmplitudeEnvelope(options.envelope); - //connect the oscillators to the output - this.oscillator.chain(this.filter, this.envelope, this.output); - //start the oscillators - this.oscillator.start(); - //connect the filter envelope - this.filterEnvelope.connect(this.filter.frequency); - this._readOnly([ - 'oscillator', - 'frequency', - 'detune', - 'filter', - 'filterEnvelope', - 'envelope' - ]); - }; - Tone.extend(Tone.MonoSynth, Tone.Monophonic); - /** - * @const - * @static - * @type {Object} - */ - Tone.MonoSynth.defaults = { - 'frequency': 'C4', - 'detune': 0, - 'oscillator': { 'type': 'square' }, - 'filter': { - 'Q': 6, - 'type': 'lowpass', - 'rolloff': -24 - }, - 'envelope': { - 'attack': 0.005, - 'decay': 0.1, - 'sustain': 0.9, - 'release': 1 - }, - 'filterEnvelope': { - 'attack': 0.06, - 'decay': 0.2, - 'sustain': 0.5, - 'release': 2, - 'baseFrequency': 200, - 'octaves': 7, - 'exponent': 2 - } - }; - /** - * start the attack portion of the envelope - * @param {Time} [time=now] the time the attack should start - * @param {NormalRange} [velocity=1] the velocity of the note (0-1) - * @returns {Tone.MonoSynth} this - * @private - */ - Tone.MonoSynth.prototype._triggerEnvelopeAttack = function (time, velocity) { - //the envelopes - this.envelope.triggerAttack(time, velocity); - this.filterEnvelope.triggerAttack(time); - return this; - }; - /** - * start the release portion of the envelope - * @param {Time} [time=now] the time the release should start - * @returns {Tone.MonoSynth} this - * @private - */ - Tone.MonoSynth.prototype._triggerEnvelopeRelease = function (time) { - this.envelope.triggerRelease(time); - this.filterEnvelope.triggerRelease(time); - return this; - }; - /** - * clean up - * @returns {Tone.MonoSynth} this - */ - Tone.MonoSynth.prototype.dispose = function () { - Tone.Monophonic.prototype.dispose.call(this); - this._writable([ - 'oscillator', - 'frequency', - 'detune', - 'filter', - 'filterEnvelope', - 'envelope' - ]); - this.oscillator.dispose(); - this.oscillator = null; - this.envelope.dispose(); - this.envelope = null; - this.filterEnvelope.dispose(); - this.filterEnvelope = null; - this.filter.dispose(); - this.filter = null; - this.frequency = null; - this.detune = null; - return this; - }; - return Tone.MonoSynth; - }); - Module(function (Tone) { - - /** - * @class Tone.DuoSynth is a monophonic synth composed of two - * MonoSynths run in parallel with control over the - * frequency ratio between the two voices and vibrato effect. - * <img src="https://docs.google.com/drawings/d/1bL4GXvfRMMlqS7XyBm9CjL9KJPSUKbcdBNpqOlkFLxk/pub?w=1012&h=448"> - * - * @constructor - * @extends {Tone.Monophonic} - * @param {Object} [options] the options available for the synth - * see defaults below - * @example - * var duoSynth = new Tone.DuoSynth().toMaster(); - * duoSynth.triggerAttackRelease("C4", "2n"); - */ - Tone.DuoSynth = function (options) { - options = this.defaultArg(options, Tone.DuoSynth.defaults); - Tone.Monophonic.call(this, options); - /** - * the first voice - * @type {Tone.MonoSynth} - */ - this.voice0 = new Tone.MonoSynth(options.voice0); - this.voice0.volume.value = -10; - /** - * the second voice - * @type {Tone.MonoSynth} - */ - this.voice1 = new Tone.MonoSynth(options.voice1); - this.voice1.volume.value = -10; - /** - * The vibrato LFO. - * @type {Tone.LFO} - * @private - */ - this._vibrato = new Tone.LFO(options.vibratoRate, -50, 50); - this._vibrato.start(); - /** - * the vibrato frequency - * @type {Frequency} - * @signal - */ - this.vibratoRate = this._vibrato.frequency; - /** - * the vibrato gain - * @type {Tone.Gain} - * @private - */ - this._vibratoGain = new Tone.Gain(options.vibratoAmount, Tone.Type.Positive); - /** - * The amount of vibrato - * @type {Positive} - * @signal - */ - this.vibratoAmount = this._vibratoGain.gain; - /** - * the frequency control - * @type {Frequency} - * @signal - */ - this.frequency = new Tone.Signal(440, Tone.Type.Frequency); - /** - * Harmonicity is the ratio between the two voices. A harmonicity of - * 1 is no change. Harmonicity = 2 means a change of an octave. - * @type {Positive} - * @signal - * @example - * //pitch voice1 an octave below voice0 - * duoSynth.harmonicity.value = 0.5; - */ - this.harmonicity = new Tone.Multiply(options.harmonicity); - this.harmonicity.units = Tone.Type.Positive; - //control the two voices frequency - this.frequency.connect(this.voice0.frequency); - this.frequency.chain(this.harmonicity, this.voice1.frequency); - this._vibrato.connect(this._vibratoGain); - this._vibratoGain.fan(this.voice0.detune, this.voice1.detune); - this.voice0.connect(this.output); - this.voice1.connect(this.output); - this._readOnly([ - 'voice0', - 'voice1', - 'frequency', - 'vibratoAmount', - 'vibratoRate' - ]); - }; - Tone.extend(Tone.DuoSynth, Tone.Monophonic); - /** - * @static - * @type {Object} - */ - Tone.DuoSynth.defaults = { - 'vibratoAmount': 0.5, - 'vibratoRate': 5, - 'harmonicity': 1.5, - 'voice0': { - 'volume': -10, - 'portamento': 0, - 'oscillator': { 'type': 'sine' }, - 'filterEnvelope': { - 'attack': 0.01, - 'decay': 0, - 'sustain': 1, - 'release': 0.5 - }, - 'envelope': { - 'attack': 0.01, - 'decay': 0, - 'sustain': 1, - 'release': 0.5 - } - }, - 'voice1': { - 'volume': -10, - 'portamento': 0, - 'oscillator': { 'type': 'sine' }, - 'filterEnvelope': { - 'attack': 0.01, - 'decay': 0, - 'sustain': 1, - 'release': 0.5 - }, - 'envelope': { - 'attack': 0.01, - 'decay': 0, - 'sustain': 1, - 'release': 0.5 - } - } - }; - /** - * start the attack portion of the envelopes - * - * @param {Time} [time=now] the time the attack should start - * @param {NormalRange} [velocity=1] the velocity of the note (0-1) - * @returns {Tone.DuoSynth} this - * @private - */ - Tone.DuoSynth.prototype._triggerEnvelopeAttack = function (time, velocity) { - time = this.toSeconds(time); - this.voice0.envelope.triggerAttack(time, velocity); - this.voice1.envelope.triggerAttack(time, velocity); - this.voice0.filterEnvelope.triggerAttack(time); - this.voice1.filterEnvelope.triggerAttack(time); - return this; - }; - /** - * start the release portion of the envelopes - * - * @param {Time} [time=now] the time the release should start - * @returns {Tone.DuoSynth} this - * @private - */ - Tone.DuoSynth.prototype._triggerEnvelopeRelease = function (time) { - this.voice0.triggerRelease(time); - this.voice1.triggerRelease(time); - return this; - }; - /** - * clean up - * @returns {Tone.DuoSynth} this - */ - Tone.DuoSynth.prototype.dispose = function () { - Tone.Monophonic.prototype.dispose.call(this); - this._writable([ - 'voice0', - 'voice1', - 'frequency', - 'vibratoAmount', - 'vibratoRate' - ]); - this.voice0.dispose(); - this.voice0 = null; - this.voice1.dispose(); - this.voice1 = null; - this.frequency.dispose(); - this.frequency = null; - this._vibratoGain.dispose(); - this._vibratoGain = null; - this._vibrato = null; - this.harmonicity.dispose(); - this.harmonicity = null; - this.vibratoAmount.dispose(); - this.vibratoAmount = null; - this.vibratoRate = null; - return this; - }; - return Tone.DuoSynth; - }); - Module(function (Tone) { - - /** - * @class FMSynth is composed of two Tone.Synths where one Tone.Synth modulates - * the frequency of a second Tone.Synth. A lot of spectral content - * can be explored using the modulationIndex parameter. Read more about - * frequency modulation synthesis on [SoundOnSound](http://www.soundonsound.com/sos/apr00/articles/synthsecrets.htm). - * <img src="https://docs.google.com/drawings/d/1h0PUDZXPgi4Ikx6bVT6oncrYPLluFKy7lj53puxj-DM/pub?w=902&h=462"> - * - * @constructor - * @extends {Tone.Monophonic} - * @param {Object} [options] the options available for the synth - * see defaults below - * @example - * var fmSynth = new Tone.FMSynth().toMaster(); - * fmSynth.triggerAttackRelease("C5", "4n"); - */ - Tone.FMSynth = function (options) { - options = this.defaultArg(options, Tone.FMSynth.defaults); - Tone.Monophonic.call(this, options); - /** - * The carrier voice. - * @type {Tone.Synth} - * @private - */ - this._carrier = new Tone.Synth(options.carrier); - this._carrier.volume.value = -10; - /** - * The carrier's oscillator - * @type {Tone.Oscillator} - */ - this.oscillator = this._carrier.oscillator; - /** - * The carrier's envelope - * @type {Tone.Oscillator} - */ - this.envelope = this._carrier.envelope.set(options.envelope); - /** - * The modulator voice. - * @type {Tone.Synth} - * @private - */ - this._modulator = new Tone.Synth(options.modulator); - this._modulator.volume.value = -10; - /** - * The modulator's oscillator which is applied - * to the amplitude of the oscillator - * @type {Tone.Oscillator} - */ - this.modulation = this._modulator.oscillator.set(options.modulation); - /** - * The modulator's envelope - * @type {Tone.Oscillator} - */ - this.modulationEnvelope = this._modulator.envelope.set(options.modulationEnvelope); - /** - * The frequency control. - * @type {Frequency} - * @signal - */ - this.frequency = new Tone.Signal(440, Tone.Type.Frequency); - /** - * The detune in cents - * @type {Cents} - * @signal - */ - this.detune = new Tone.Signal(options.detune, Tone.Type.Cents); - /** - * Harmonicity is the ratio between the two voices. A harmonicity of - * 1 is no change. Harmonicity = 2 means a change of an octave. - * @type {Positive} - * @signal - * @example - * //pitch voice1 an octave below voice0 - * synth.harmonicity.value = 0.5; - */ - this.harmonicity = new Tone.Multiply(options.harmonicity); - this.harmonicity.units = Tone.Type.Positive; - /** - * The modulation index which essentially the depth or amount of the modulation. 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 node where the modulation happens - * @type {GainNode} - * @private - */ - this._modulationNode = new Tone.Gain(0); - //control the two voices frequency - this.frequency.connect(this._carrier.frequency); - this.frequency.chain(this.harmonicity, this._modulator.frequency); - this.frequency.chain(this.modulationIndex, this._modulationNode); - this.detune.fan(this._carrier.detune, this._modulator.detune); - this._modulator.connect(this._modulationNode.gain); - this._modulationNode.connect(this._carrier.frequency); - this._carrier.connect(this.output); - this._readOnly([ - 'frequency', - 'harmonicity', - 'modulationIndex', - 'oscillator', - 'envelope', - 'modulation', - 'modulationEnvelope', - 'detune' - ]); - }; - Tone.extend(Tone.FMSynth, Tone.Monophonic); - /** - * @static - * @type {Object} - */ - Tone.FMSynth.defaults = { - 'harmonicity': 3, - 'modulationIndex': 10, - 'detune': 0, - 'oscillator': { 'type': 'sine' }, - 'envelope': { - 'attack': 0.01, - 'decay': 0.01, - 'sustain': 1, - 'release': 0.5 - }, - 'modulation': { 'type': 'square' }, - 'modulationEnvelope': { - 'attack': 0.5, - 'decay': 0, - 'sustain': 1, - 'release': 0.5 - } - }; - /** - * trigger the attack portion of the note - * - * @param {Time} [time=now] the time the note will occur - * @param {number} [velocity=1] the velocity of the note - * @returns {Tone.FMSynth} this - * @private - */ - Tone.FMSynth.prototype._triggerEnvelopeAttack = function (time, velocity) { - time = this.toSeconds(time); - //the envelopes - this.envelope.triggerAttack(time, velocity); - this.modulationEnvelope.triggerAttack(time); - return this; - }; - /** - * trigger the release portion of the note - * - * @param {Time} [time=now] the time the note will release - * @returns {Tone.FMSynth} this - * @private - */ - Tone.FMSynth.prototype._triggerEnvelopeRelease = function (time) { - time = this.toSeconds(time); - this.envelope.triggerRelease(time); - this.modulationEnvelope.triggerRelease(time); - return this; - }; - /** - * clean up - * @returns {Tone.FMSynth} this - */ - Tone.FMSynth.prototype.dispose = function () { - Tone.Monophonic.prototype.dispose.call(this); - this._writable([ - 'frequency', - 'harmonicity', - 'modulationIndex', - 'oscillator', - 'envelope', - 'modulation', - 'modulationEnvelope', - 'detune' - ]); - this._carrier.dispose(); - this._carrier = null; - this._modulator.dispose(); - this._modulator = null; - this.frequency.dispose(); - this.frequency = null; - this.detune.dispose(); - this.detune = null; - this.modulationIndex.dispose(); - this.modulationIndex = null; - this.harmonicity.dispose(); - this.harmonicity = null; - this._modulationNode.dispose(); - this._modulationNode = null; - this.oscillator = null; - this.envelope = null; - this.modulationEnvelope = null; - this.modulation = null; - return this; - }; - return Tone.FMSynth; - }); - Module(function (Tone) { - - /** - * @class Tone.MembraneSynth makes kick and tom sounds using a single oscillator - * with an amplitude envelope and frequency ramp. A Tone.OmniOscillator - * is routed through a Tone.AmplitudeEnvelope to the output. The drum - * quality of the sound comes from the frequency envelope applied - * during during Tone.MembraneSynth.triggerAttack(note). The frequency - * envelope starts at <code>note * .octaves</code> and ramps to - * <code>note</code> over the duration of <code>.pitchDecay</code>. - * - * @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 = this.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](http://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 = this.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(0); - 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=1} velocity 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 = this.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=1} velocity 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. - * @param {AudioBuffer|Tone.Buffer} buffer The buffer to play - * @param {Function} onended The callback to invoke when the - * buffer is done playing. - */ - Tone.BufferSource = function () { - var options = this.optionsObject(arguments, [ - 'buffer', - 'onended' - ], Tone.BufferSource.defaults); - /** - * 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 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 value that the buffer ramps to - * @type {Gain} - * @private - */ - this._gain = 1; - /** - * The onended timeout - * @type {Number} - * @private - */ - this._onendedTimeout = -1; - //set the buffer initially - if (!this.isUndef(options.buffer)) { - this.buffer = options.buffer; - } - this.loop = options.loop; - }; - Tone.extend(Tone.BufferSource); - /** - * The defaults - * @const - * @type {Object} - */ - Tone.BufferSource.defaults = { - 'onended': Tone.noOp, - 'fadeIn': 0, - 'fadeOut': 0 - }; - /** - * 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) { - time = this.toSeconds(time); - //if it's a loop the default offset is the loopstart point - if (this.loop) { - offset = this.defaultArg(offset, this.loopStart); - } else { - //otherwise the default offset is 0 - offset = this.defaultArg(offset, 0); - } - offset = this.toSeconds(offset); - //the values in seconds - time = this.toSeconds(time); - this._source.start(time, offset); - gain = this.defaultArg(gain, 1); - this._gain = gain; - //the fadeIn time - if (this.isUndef(fadeInTime)) { - fadeInTime = this.toSeconds(this.fadeIn); - } else { - fadeInTime = this.toSeconds(fadeInTime); - } - if (fadeInTime > 0) { - this._gainNode.gain.setValueAtTime(0, time); - this._gainNode.gain.linearRampToValueAtTime(this._gain, time + fadeInTime); - } else { - this._gainNode.gain.setValueAtTime(gain, time); - } - this._startTime = time + fadeInTime; - if (!this.isUndef(duration)) { - duration = this.defaultArg(duration, this.buffer.duration - offset); - duration = this.toSeconds(duration); - this.stop(time + duration + fadeInTime, fadeInTime); - } - } - 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) { - time = this.toSeconds(time); - //the fadeOut time - if (this.isUndef(fadeOutTime)) { - fadeOutTime = this.toSeconds(this.fadeOut); - } else { - fadeOutTime = this.toSeconds(fadeOutTime); - } - this._stopTime = time + fadeOutTime; - //cancel the end curve - this._gainNode.gain.cancelScheduledValues(this._startTime + this.sampleTime); - //set a new one - if (fadeOutTime > 0) { - this._gainNode.gain.setValueAtTime(this._gain, time); - this._gainNode.gain.linearRampToValueAtTime(0, time + fadeOutTime); - time += fadeOutTime; - } else { - this._gainNode.gain.setValueAtTime(0, time); - } - // fix for safari bug and old FF - if (!this.isNumber(this._source.playbackState) || this._source.playbackState === 2) { - this._source.stop(time); - } - clearTimeout(this._onendedTimeout); - this._onendedTimeout = setTimeout(this._onended.bind(this), (this._stopTime - this.now()) * 1000); - } - return this; - }; - /** - * Internal callback when the buffer is ended. - * Invokes `onended` and disposes the node. - * @private - */ - Tone.BufferSource.prototype._onended = function () { - this.onended(this); - this.dispose(); - }; - /** - * 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 {AudioBuffer} - * @name buffer - */ - Object.defineProperty(Tone.BufferSource.prototype, 'buffer', { - get: function () { - if (this._source) { - return this._source.buffer; - } else { - return null; - } - }, - set: function (buffer) { - if (buffer instanceof Tone.Buffer) { - this._source.buffer = buffer.get(); - } else { - this._source.buffer = 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 () { - this.onended = null; - if (this._source) { - this._source.disconnect(); - this._source = null; - } - if (this._gainNode) { - this._gainNode.dispose(); - this._gainNode = null; - } - this._startTime = -1; - this.playbackRate = null; - this.output = null; - 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 = this.optionsObject(arguments, ['type'], Tone.Noise.defaults); - 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.blockTime; - 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. only generated once on init - * @static - * @private - * @type {Array} - * borrowed heavily from https://github.com/zacharydenton/noise.js - * (c) 2013 Zach Denton (MIT) - */ - 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]); - } - } - 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. - * <img src="https://docs.google.com/drawings/d/1rqzuX9rBlhT50MRvD2TKml9bnZhcZmzXF1rf_o7vdnE/pub?w=918&h=242"> - * - * @constructor - * @extends {Tone.Instrument} - * @param {Object} [options] the options available for the synth - * see defaults below - * @example - * var noiseSynth = new Tone.NoiseSynth().toMaster(); - * noiseSynth.triggerAttackRelease("8n"); - */ - Tone.NoiseSynth = function (options) { - //get the defaults - options = this.defaultArg(options, Tone.NoiseSynth.defaults); - Tone.Instrument.call(this, options); - /** - * The noise source. - * @type {Tone.Noise} - * @example - * noiseSynth.set("noise.type", "brown"); - */ - this.noise = new Tone.Noise(); - /** - * The amplitude envelope. - * @type {Tone.AmplitudeEnvelope} - */ - this.envelope = new Tone.AmplitudeEnvelope(options.envelope); - //connect the noise to the output - this.noise.chain(this.envelope, this.output); - //start the noise - this.noise.start(); - this._readOnly([ - 'noise', - 'envelope' - ]); - }; - Tone.extend(Tone.NoiseSynth, Tone.Instrument); - /** - * @const - * @static - * @type {Object} - */ - Tone.NoiseSynth.defaults = { - 'noise': { 'type': 'white' }, - 'envelope': { - 'attack': 0.005, - 'decay': 0.1, - 'sustain': 0 - } - }; - /** - * Start the attack portion of the envelopes. Unlike other - * instruments, Tone.NoiseSynth doesn't have a note. - * @param {Time} [time=now] the time the attack should start - * @param {number} [velocity=1] the velocity of the note (0-1) - * @returns {Tone.NoiseSynth} this - * @example - * noiseSynth.triggerAttack(); - */ - Tone.NoiseSynth.prototype.triggerAttack = function (time, velocity) { - //the envelopes - this.envelope.triggerAttack(time, velocity); - return this; - }; - /** - * Start the release portion of the envelopes. - * @param {Time} [time=now] the time the release should start - * @returns {Tone.NoiseSynth} this - */ - Tone.NoiseSynth.prototype.triggerRelease = function (time) { - this.envelope.triggerRelease(time); - return this; - }; - /** - * Trigger the attack and then the release. - * @param {Time} duration the duration of the note - * @param {Time} [time=now] the time of the attack - * @param {number} [velocity=1] the velocity - * @returns {Tone.NoiseSynth} this - */ - Tone.NoiseSynth.prototype.triggerAttackRelease = function (duration, time, velocity) { - time = this.toSeconds(time); - duration = this.toSeconds(duration); - this.triggerAttack(time, velocity); - this.triggerRelease(time + duration); - return this; - }; - /** - * Clean up. - * @returns {Tone.NoiseSynth} this - */ - Tone.NoiseSynth.prototype.dispose = function () { - Tone.Instrument.prototype.dispose.call(this); - this._writable([ - 'noise', - 'envelope' - ]); - this.noise.dispose(); - this.noise = null; - this.envelope.dispose(); - this.envelope = null; - return this; - }; - return Tone.NoiseSynth; - }); - Module(function (Tone) { - - /** - * @class Karplus-String string synthesis. Often out of tune. - * Will change when the AudioWorkerNode is available across - * browsers. - * - * @constructor - * @extends {Tone.Instrument} - * @param {Object} [options] see the defaults - * @example - * var plucky = new Tone.PluckSynth().toMaster(); - * plucky.triggerAttack("C4"); - */ - Tone.PluckSynth = function (options) { - options = this.defaultArg(options, Tone.PluckSynth.defaults); - Tone.Instrument.call(this, options); - /** - * @type {Tone.Noise} - * @private - */ - this._noise = new Tone.Noise('pink'); - /** - * The amount of noise at the attack. - * Nominal range of [0.1, 20] - * @type {number} - */ - this.attackNoise = options.attackNoise; - /** - * the LFCF - * @type {Tone.LowpassCombFilter} - * @private - */ - this._lfcf = new Tone.LowpassCombFilter({ - 'resonance': options.resonance, - 'dampening': options.dampening - }); - /** - * The resonance control. - * @type {NormalRange} - * @signal - */ - this.resonance = this._lfcf.resonance; - /** - * The dampening control. i.e. the lowpass filter frequency of the comb filter - * @type {Frequency} - * @signal - */ - this.dampening = this._lfcf.dampening; - //connections - this._noise.connect(this._lfcf); - this._lfcf.connect(this.output); - this._readOnly([ - 'resonance', - 'dampening' - ]); - }; - Tone.extend(Tone.PluckSynth, Tone.Instrument); - /** - * @static - * @const - * @type {Object} - */ - Tone.PluckSynth.defaults = { - 'attackNoise': 1, - 'dampening': 4000, - 'resonance': 0.9 - }; - /** - * Trigger the note. - * @param {Frequency} note The note to trigger. - * @param {Time} [time=now] When the note should be triggered. - * @returns {Tone.PluckSynth} this - */ - Tone.PluckSynth.prototype.triggerAttack = function (note, time) { - note = this.toFrequency(note); - time = this.toSeconds(time); - var delayAmount = 1 / note; - this._lfcf.delayTime.setValueAtTime(delayAmount, time); - this._noise.start(time); - this._noise.stop(time + delayAmount * this.attackNoise); - return this; - }; - /** - * Clean up. - * @returns {Tone.PluckSynth} this - */ - Tone.PluckSynth.prototype.dispose = function () { - Tone.Instrument.prototype.dispose.call(this); - this._noise.dispose(); - this._lfcf.dispose(); - this._noise = null; - this._lfcf = null; - this._writable([ - 'resonance', - 'dampening' - ]); - this.dampening = null; - this.resonance = null; - return this; - }; - return Tone.PluckSynth; - }); - Module(function (Tone) { - - /** - * @class Tone.PolySynth handles voice creation and allocation for any - * instruments passed in as the second paramter. PolySynth is - * not a synthesizer by itself, it merely manages voices of - * one of the other types of synths, allowing any of the - * monophonic synthesizers to be polyphonic. - * - * @constructor - * @extends {Tone.Instrument} - * @param {number|Object} [polyphony=4] The number of voices to create - * @param {function} [voice=Tone.Synth] The constructor of the voices - * uses Tone.Synth by default. - * @example - * //a polysynth composed of 6 Voices of Synth - * var synth = new Tone.PolySynth(6, Tone.Synth).toMaster(); - * //set the attributes using the set interface - * synth.set("detune", -1200); - * //play a chord - * synth.triggerAttackRelease(["C4", "E4", "A4"], "4n"); - */ - Tone.PolySynth = function () { - Tone.Instrument.call(this); - var options = this.optionsObject(arguments, [ - 'polyphony', - 'voice' - ], Tone.PolySynth.defaults); - options = this.defaultArg(options, Tone.Instrument.defaults); - //max polyphony - options.polyphony = Math.min(Tone.PolySynth.MAX_POLYPHONY, options.polyphony); - /** - * the array of voices - * @type {Array} - */ - this.voices = new Array(options.polyphony); - /** - * The queue of voices with data about last trigger - * and the triggered note - * @private - * @type {Array} - */ - this._triggers = new Array(options.polyphony); - /** - * The detune in cents - * @type {Cents} - * @signal - */ - this.detune = new Tone.Signal(options.detune, Tone.Type.Cents); - this._readOnly('detune'); - //create the voices - for (var i = 0; i < options.polyphony; i++) { - var v = new options.voice(arguments[2], arguments[3]); - this.voices[i] = v; - v.connect(this.output); - if (v.hasOwnProperty('detune')) { - this.detune.connect(v.detune); - } - this._triggers[i] = { - release: -1, - note: null, - voice: v - }; - } - //set the volume initially - this.volume.value = options.volume; - }; - Tone.extend(Tone.PolySynth, Tone.Instrument); - /** - * the defaults - * @const - * @static - * @type {Object} - */ - Tone.PolySynth.defaults = { - 'polyphony': 4, - 'volume': 0, - 'detune': 0, - 'voice': Tone.Synth - }; - /** - * Trigger the attack portion of the note - * @param {Frequency|Array} notes The notes to play. Accepts a single - * Frequency or an array of frequencies. - * @param {Time} [time=now] The start time of the note. - * @param {number} [velocity=1] The velocity of the note. - * @returns {Tone.PolySynth} this - * @example - * //trigger a chord immediately with a velocity of 0.2 - * poly.triggerAttack(["Ab3", "C4", "F5"], undefined, 0.2); - */ - Tone.PolySynth.prototype.triggerAttack = function (notes, time, velocity) { - if (!Array.isArray(notes)) { - notes = [notes]; - } - time = this.toSeconds(time); - for (var i = 0; i < notes.length; i++) { - var val = notes[i]; - //trigger the oldest voice - var oldest = this._triggers[0]; - var oldestIndex = 0; - for (var j = 1; j < this._triggers.length; j++) { - if (this._triggers[j].release < oldest.release) { - oldest = this._triggers[j]; - oldestIndex = j; - } - } - oldest.release = Infinity; - oldest.note = JSON.stringify(val); - oldest.voice.triggerAttack(val, time, velocity); - } - return this; - }; - /** - * Trigger the attack and release after the specified duration - * - * @param {Frequency|Array} notes The notes to play. Accepts a single - * Frequency or an array of frequencies. - * @param {Time} duration the duration of the note - * @param {Time} [time=now] if no time is given, defaults to now - * @param {number} [velocity=1] the velocity of the attack (0-1) - * @returns {Tone.PolySynth} this - * @example - * //trigger a chord for a duration of a half note - * poly.triggerAttackRelease(["Eb3", "G4", "C5"], "2n"); - * @example - * //can pass in an array of durations as well - * poly.triggerAttackRelease(["Eb3", "G4", "C5"], ["2n", "4n", "4n"]); - */ - Tone.PolySynth.prototype.triggerAttackRelease = function (notes, duration, time, velocity) { - time = this.toSeconds(time); - this.triggerAttack(notes, time, velocity); - if (this.isArray(duration) && this.isArray(notes)) { - for (var i = 0; i < notes.length; i++) { - var d = duration[Math.min(i, duration.length - 1)]; - this.triggerRelease(notes[i], time + this.toSeconds(d)); - } - } else { - this.triggerRelease(notes, time + this.toSeconds(duration)); - } - return this; - }; - /** - * Trigger the release of the note. Unlike monophonic instruments, - * a note (or array of notes) needs to be passed in as the first argument. - * @param {Frequency|Array} notes The notes to play. Accepts a single - * Frequency or an array of frequencies. - * @param {Time} [time=now] When the release will be triggered. - * @returns {Tone.PolySynth} this - * @example - * poly.triggerRelease(["Ab3", "C4", "F5"], "+2n"); - */ - Tone.PolySynth.prototype.triggerRelease = function (notes, time) { - if (!Array.isArray(notes)) { - notes = [notes]; - } - time = this.toSeconds(time); - for (var i = 0; i < notes.length; i++) { - //get the voice - var stringified = JSON.stringify(notes[i]); - for (var v = 0; v < this._triggers.length; v++) { - var desc = this._triggers[v]; - if (desc.note === stringified && desc.release > time) { - desc.voice.triggerRelease(time); - desc.release = time; - } - } - } - return this; - }; - /** - * Set a member/attribute of the voices. - * @param {Object|string} params - * @param {number=} value - * @param {Time=} rampTime - * @returns {Tone.PolySynth} this - * @example - * poly.set({ - * "filter" : { - * "type" : "highpass" - * }, - * "envelope" : { - * "attack" : 0.25 - * } - * }); - */ - Tone.PolySynth.prototype.set = function (params, value, rampTime) { - for (var i = 0; i < this.voices.length; i++) { - this.voices[i].set(params, value, rampTime); - } - return this; - }; - /** - * Get the synth'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. - * @param {Array=} params the parameters to get, otherwise will return - * all available. - */ - Tone.PolySynth.prototype.get = function (params) { - return this.voices[0].get(params); - }; - /** - * Trigger the release portion of all the currently active voices. - * @param {Time} [time=now] When the notes should be released. - * @return {Tone.PolySynth} this - */ - Tone.PolySynth.prototype.releaseAll = function (time) { - time = this.toSeconds(time); - for (var i = 0; i < this._triggers.length; i++) { - var desc = this._triggers[i]; - if (desc.release > time) { - desc.release = time; - desc.voice.triggerRelease(time); - } - } - return this; - }; - /** - * Clean up. - * @returns {Tone.PolySynth} this - */ - Tone.PolySynth.prototype.dispose = function () { - Tone.Instrument.prototype.dispose.call(this); - for (var i = 0; i < this.voices.length; i++) { - this.voices[i].dispose(); - this.voices[i] = null; - } - this._writable('detune'); - this.detune.dispose(); - this.detune = null; - this.voices = null; - this._triggers = null; - return this; - }; - /** - * The maximum number of notes that can be allocated - * to a polysynth. - * @type {Number} - * @static - */ - Tone.PolySynth.MAX_POLYPHONY = 20; - return Tone.PolySynth; - }); - Module(function (Tone) { - - /** - * @class Tone.Player is an audio file player with start, loop, and stop functions. - * - * @constructor - * @extends {Tone.Source} - * @param {string|AudioBuffer} url Either the AudioBuffer or the url from - * which to load the AudioBuffer - * @param {function=} onload The function to invoke when the buffer is loaded. - * Recommended to use Tone.Buffer.on('load') instead. - * @example - * var player = new Tone.Player("./path/to/sample.mp3").toMaster(); - * //play as soon as the buffer is loaded - * player.autostart = true; - */ - Tone.Player = function (url) { - var options; - if (url instanceof Tone.Buffer) { - url = url.get(); - options = Tone.Player.defaults; - } else { - options = this.optionsObject(arguments, [ - 'url', - 'onload' - ], Tone.Player.defaults); - } - Tone.Source.call(this, options); - /** - * @private - * @type {AudioBufferSourceNode} - */ - this._source = null; - /** - * If the file should play as soon - * as the buffer is loaded. - * @type {boolean} - * @example - * //will play as soon as it's loaded - * var player = new Tone.Player({ - * "url" : "./path/to/sample.mp3", - * "autostart" : true, - * }).toMaster(); - */ - this.autostart = options.autostart; - /** - * the buffer - * @private - * @type {Tone.Buffer} - */ - this._buffer = new Tone.Buffer({ - 'url': options.url, - 'onload': this._onload.bind(this, options.onload), - 'reverse': options.reverse - }); - if (url instanceof AudioBuffer) { - this._buffer.set(url); - } - /** - * if the buffer should loop once it's over - * @type {boolean} - * @private - */ - this._loop = options.loop; - /** - * if 'loop' is true, the loop will start at this position - * @type {Time} - * @private - */ - this._loopStart = options.loopStart; - /** - * if 'loop' is true, the loop will end at this position - * @type {Time} - * @private - */ - this._loopEnd = options.loopEnd; - /** - * the playback rate - * @private - * @type {number} - */ - this._playbackRate = options.playbackRate; - /** - * Enabling retrigger will allow a player to be restarted - * before the the previous 'start' is done playing. Otherwise, - * successive calls to Tone.Player.start will only start - * the sample if it had played all the way through. - * @type {boolean} - */ - this.retrigger = options.retrigger; - }; - Tone.extend(Tone.Player, Tone.Source); - /** - * the default parameters - * @static - * @const - * @type {Object} - */ - Tone.Player.defaults = { - 'onload': Tone.noOp, - 'playbackRate': 1, - 'loop': false, - 'autostart': false, - 'loopStart': 0, - 'loopEnd': 0, - 'retrigger': false, - 'reverse': false - }; - /** - * Load the audio file as an audio buffer. - * Decodes the audio asynchronously and invokes - * the callback once the audio buffer loads. - * Note: this does not need to be called if a url - * was passed in to the constructor. Only use this - * if you want to manually load a new url. - * @param {string} url The url of the buffer to load. - * Filetype support depends on the - * browser. - * @param {function=} callback The function to invoke once - * the sample is loaded. - * @returns {Promise} - */ - Tone.Player.prototype.load = function (url, callback) { - return this._buffer.load(url, this._onload.bind(this, callback)); - }; - /** - * Internal callback when the buffer is loaded. - * @private - */ - Tone.Player.prototype._onload = function (callback) { - callback = this.defaultArg(callback, Tone.noOp); - callback(this); - if (this.autostart) { - this.start(); - } - }; - /** - * Play the buffer at the given startTime. Optionally add an offset - * and/or duration which will play the buffer from a position - * within the buffer for the given duration. - * - * @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) - * @returns {Tone.Player} this - * @memberOf Tone.Player# - * @method start - * @name start - */ - /** - * Internal start method - * @private - */ - Tone.Player.prototype._start = function (startTime, offset, duration) { - if (this._buffer.loaded) { - //if it's a loop the default offset is the loopstart point - if (this._loop) { - offset = this.defaultArg(offset, this._loopStart); - } else { - //otherwise the default offset is 0 - offset = this.defaultArg(offset, 0); - } - offset = this.toSeconds(offset); - //make sure it has a positive duration - duration = this.defaultArg(duration, Math.max(this._buffer.duration - offset, 0)); - duration = this.toSeconds(duration); - //the values in seconds - startTime = this.toSeconds(startTime); - //make the source - this._source = this.context.createBufferSource(); - this._source.buffer = this._buffer.get(); - //set the looping properties - if (this._loop) { - this._source.loop = this._loop; - this._source.loopStart = this.toSeconds(this._loopStart); - this._source.loopEnd = this.toSeconds(this._loopEnd); - } else if (!this._synced) { - //if it's not looping, set the state change at the end of the sample - this._state.setStateAtTime(Tone.State.Stopped, startTime + duration); - } - //and other properties - this._source.playbackRate.value = this._playbackRate; - this._source.connect(this.output); - //start it - if (this._loop) { - //modify the offset if it's greater than the loop time - var loopEnd = this._source.loopEnd || this._buffer.duration; - var loopStart = this._source.loopStart; - var loopDuration = loopEnd - loopStart; - if (offset > loopEnd) { - //move the offset back - while (offset > loopEnd) { - offset -= loopDuration; - } - } - this._source.start(startTime, offset); - } else { - this._source.start(startTime, offset, duration); - } - } else { - throw Error('Tone.Player: tried to start Player before the buffer was loaded'); - } - return this; - }; - /** - * Stop playback. - * @private - * @param {Time} [time=now] - * @returns {Tone.Player} this - */ - Tone.Player.prototype._stop = function (time) { - if (this._source) { - this._source.stop(this.toSeconds(time)); - this._source = null; - } - return this; - }; - /** - * Seek to a specific time in the player's buffer. If the - * source is no longer playing at that time, it will stop. - * If you seek to a time that - * @param {Time} offset The time to seek to. - * @param {Time=} time The time for the seek event to occur. - * @return {Tone.Player} this - * @example - * source.start(0.2); - * source.stop(0.4); - */ - Tone.Player.prototype.seek = function (offset, time) { - time = this.toSeconds(time); - if (this._state.getValueAtTime(time) === Tone.State.Started) { - offset = this.toSeconds(offset); - // if it's currently playing, stop it - this._stop(time); - //restart it at the given time - this._start(time, offset); - } - return this; - }; - /** - * Set the loop start and end. Will only loop if loop is - * set to true. - * @param {Time} loopStart The loop end time - * @param {Time} loopEnd The loop end time - * @returns {Tone.Player} this - * @example - * //loop 0.1 seconds of the file. - * player.setLoopPoints(0.2, 0.3); - * player.loop = true; - */ - Tone.Player.prototype.setLoopPoints = function (loopStart, loopEnd) { - this.loopStart = loopStart; - this.loopEnd = loopEnd; - return this; - }; - /** - * If loop is true, the loop will start at this position. - * @memberOf Tone.Player# - * @type {Time} - * @name loopStart - */ - Object.defineProperty(Tone.Player.prototype, 'loopStart', { - get: function () { - return this._loopStart; - }, - set: function (loopStart) { - this._loopStart = loopStart; - if (this._source) { - this._source.loopStart = this.toSeconds(loopStart); - } - } - }); - /** - * If loop is true, the loop will end at this position. - * @memberOf Tone.Player# - * @type {Time} - * @name loopEnd - */ - Object.defineProperty(Tone.Player.prototype, 'loopEnd', { - get: function () { - return this._loopEnd; - }, - set: function (loopEnd) { - this._loopEnd = loopEnd; - if (this._source) { - this._source.loopEnd = this.toSeconds(loopEnd); - } - } - }); - /** - * The audio buffer belonging to the player. - * @memberOf Tone.Player# - * @type {Tone.Buffer} - * @name buffer - */ - Object.defineProperty(Tone.Player.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.Player# - * @type {boolean} - * @name loop - */ - Object.defineProperty(Tone.Player.prototype, 'loop', { - get: function () { - return this._loop; - }, - set: function (loop) { - this._loop = loop; - if (this._source) { - this._source.loop = loop; - } - } - }); - /** - * The playback speed. 1 is normal speed. This is not a signal because - * Safari and iOS currently don't support playbackRate as a signal. - * @memberOf Tone.Player# - * @type {number} - * @name playbackRate - */ - Object.defineProperty(Tone.Player.prototype, 'playbackRate', { - get: function () { - return this._playbackRate; - }, - set: function (rate) { - this._playbackRate = rate; - if (this._source) { - this._source.playbackRate.value = rate; - } - } - }); - /** - * The direction the buffer should play in - * @memberOf Tone.Player# - * @type {boolean} - * @name reverse - */ - Object.defineProperty(Tone.Player.prototype, 'reverse', { - get: function () { - return this._buffer.reverse; - }, - set: function (rev) { - this._buffer.reverse = rev; - } - }); - /** - * Dispose and disconnect. - * @return {Tone.Player} this - */ - Tone.Player.prototype.dispose = function () { - Tone.Source.prototype.dispose.call(this); - if (this._source !== null) { - this._source.disconnect(); - this._source = null; - } - this._buffer.dispose(); - this._buffer = null; - return this; - }; - return Tone.Player; - }); - Module(function (Tone) { - - /** - * @class Sampler wraps Tone.Player in an AmplitudeEnvelope. - * - * @constructor - * @extends {Tone.Instrument} - * @param {String} url the url of the audio file - * @param {Function=} onload The callback to invoke when the sample is loaded. - * @example - * var sampler = new Sampler("./audio/casio/A1.mp3", function(){ - * //repitch the sample down a half step - * sampler.triggerAttack(-1); - * }).toMaster(); - */ - Tone.Sampler = function () { - var options = this.optionsObject(arguments, [ - 'url', - 'onload' - ], Tone.Sampler.defaults); - Tone.Instrument.call(this, options); - /** - * The sample player. - * @type {Tone.Player} - */ - this.player = new Tone.Player(options.url, options.onload); - this.player.retrigger = true; - /** - * The amplitude envelope. - * @type {Tone.AmplitudeEnvelope} - */ - this.envelope = new Tone.AmplitudeEnvelope(options.envelope); - this.player.chain(this.envelope, this.output); - this._readOnly([ - 'player', - 'envelope' - ]); - this.loop = options.loop; - this.reverse = options.reverse; - }; - Tone.extend(Tone.Sampler, Tone.Instrument); - /** - * the default parameters - * @static - */ - Tone.Sampler.defaults = { - 'onload': Tone.noOp, - 'loop': false, - 'reverse': false, - 'envelope': { - 'attack': 0.001, - 'decay': 0, - 'sustain': 1, - 'release': 0.1 - } - }; - /** - * Trigger the start of the sample. - * @param {Interval} [pitch=0] The amount the sample should - * be repitched. - * @param {Time} [time=now] The time when the sample should start - * @param {NormalRange} [velocity=1] The velocity of the note - * @returns {Tone.Sampler} this - * @example - * sampler.triggerAttack(0, "+0.1", 0.5); - */ - Tone.Sampler.prototype.triggerAttack = function (pitch, time, velocity) { - time = this.toSeconds(time); - pitch = this.defaultArg(pitch, 0); - this.player.playbackRate = this.intervalToFrequencyRatio(pitch); - this.player.start(time); - this.envelope.triggerAttack(time, velocity); - return this; - }; - /** - * Start the release portion of the sample. Will stop the sample once the - * envelope has fully released. - * - * @param {Time} [time=now] The time when the note should release - * @returns {Tone.Sampler} this - * @example - * sampler.triggerRelease(); - */ - Tone.Sampler.prototype.triggerRelease = function (time) { - time = this.toSeconds(time); - this.envelope.triggerRelease(time); - this.player.stop(this.toSeconds(this.envelope.release) + time); - return this; - }; - /** - * Trigger the attack and then the release after the duration. - * @param {Interval} interval The interval in half-steps that the - * sample should be pitch shifted. - * @param {Time} duration How long the note should be held for before - * triggering the release. - * @param {Time} [time=now] When the note should be triggered. - * @param {NormalRange} [velocity=1] The velocity the note should be triggered at. - * @returns {Tone.Sampler} this - * @example - * //trigger the unpitched note for the duration of an 8th note - * synth.triggerAttackRelease(0, "8n"); - * @memberOf Tone.Sampler# - * @name triggerAttackRelease - * @method triggerAttackRelease - */ - /** - * If the output sample should loop or not. - * @memberOf Tone.Sampler# - * @type {number|string} - * @name loop - */ - Object.defineProperty(Tone.Sampler.prototype, 'loop', { - get: function () { - return this.player.loop; - }, - set: function (loop) { - this.player.loop = loop; - } - }); - /** - * The direction the buffer should play in - * @memberOf Tone.Sampler# - * @type {boolean} - * @name reverse - */ - Object.defineProperty(Tone.Sampler.prototype, 'reverse', { - get: function () { - return this.player.reverse; - }, - set: function (rev) { - this.player.reverse = rev; - } - }); - /** - * The buffer to play. - * @memberOf Tone.Sampler# - * @type {Tone.Buffer} - * @name buffer - */ - Object.defineProperty(Tone.Sampler.prototype, 'buffer', { - get: function () { - return this.player.buffer; - }, - set: function (buff) { - this.player.buffer = buff; - } - }); - /** - * Clean up. - * @returns {Tone.Sampler} this - */ - Tone.Sampler.prototype.dispose = function () { - Tone.Instrument.prototype.dispose.call(this); - this._writable([ - 'player', - 'envelope' - ]); - this.player.dispose(); - this.player = null; - this.envelope.dispose(); - this.envelope = null; - return this; - }; - return Tone.Sampler; - }); - Module(function (Tone) { - - /** - * @class Maps a NormalRange [0, 1] to an AudioRange [-1, 1]. - * See also Tone.AudioToGain. - * - * @extends {Tone.SignalBase} - * @constructor - * @example - * var g2a = new Tone.GainToAudio(); - */ - Tone.GainToAudio = function () { - /** - * @type {WaveShaperNode} - * @private - */ - this._norm = this.input = this.output = new Tone.WaveShaper(function (x) { - return Math.abs(x) * 2 - 1; - }); - }; - Tone.extend(Tone.GainToAudio, Tone.SignalBase); - /** - * clean up - * @returns {Tone.GainToAudio} this - */ - Tone.GainToAudio.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._norm.dispose(); - this._norm = null; - return this; - }; - return Tone.GainToAudio; - }); - Module(function (Tone) { - - /** - * @class Normalize takes an input min and max and maps it linearly to NormalRange [0,1] - * - * @extends {Tone.SignalBase} - * @constructor - * @param {number} inputMin the min input value - * @param {number} inputMax the max input value - * @example - * var norm = new Tone.Normalize(2, 4); - * var sig = new Tone.Signal(3).connect(norm); - * //output of norm is 0.5. - */ - Tone.Normalize = function (inputMin, inputMax) { - /** - * the min input value - * @type {number} - * @private - */ - this._inputMin = this.defaultArg(inputMin, 0); - /** - * the max input value - * @type {number} - * @private - */ - this._inputMax = this.defaultArg(inputMax, 1); - /** - * subtract the min from the input - * @type {Tone.Add} - * @private - */ - this._sub = this.input = new Tone.Add(0); - /** - * divide by the difference between the input and output - * @type {Tone.Multiply} - * @private - */ - this._div = this.output = new Tone.Multiply(1); - this._sub.connect(this._div); - this._setRange(); - }; - Tone.extend(Tone.Normalize, Tone.SignalBase); - /** - * The minimum value the input signal will reach. - * @memberOf Tone.Normalize# - * @type {number} - * @name min - */ - Object.defineProperty(Tone.Normalize.prototype, 'min', { - get: function () { - return this._inputMin; - }, - set: function (min) { - this._inputMin = min; - this._setRange(); - } - }); - /** - * The maximum value the input signal will reach. - * @memberOf Tone.Normalize# - * @type {number} - * @name max - */ - Object.defineProperty(Tone.Normalize.prototype, 'max', { - get: function () { - return this._inputMax; - }, - set: function (max) { - this._inputMax = max; - this._setRange(); - } - }); - /** - * set the values - * @private - */ - Tone.Normalize.prototype._setRange = function () { - this._sub.value = -this._inputMin; - this._div.value = 1 / (this._inputMax - this._inputMin); - }; - /** - * clean up - * @returns {Tone.Normalize} this - */ - Tone.Normalize.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._sub.dispose(); - this._sub = null; - this._div.dispose(); - this._div = null; - return this; - }; - return Tone.Normalize; - }); - Module(function (Tone) { - /** - * @class Tone.MultiPlayer is well suited for one-shots, multi-sampled instruments - * or any time you need to play a bunch of audio buffers. - * @param {Object|Array|Tone.Buffers} buffers The buffers which are available - * to the MultiPlayer - * @param {Function} onload The callback to invoke when all of the buffers are loaded. - * @extends {Tone} - * @example - * var multiPlayer = new MultiPlayer({ - * "kick" : "path/to/kick.mp3", - * "snare" : "path/to/snare.mp3", - * }, function(){ - * multiPlayer.start("kick"); - * }); - * @example - * //can also store the values in an array - * var multiPlayer = new MultiPlayer(["path/to/kick.mp3", "path/to/snare.mp3"], - * function(){ - * //if an array is passed in, the samples are referenced to by index - * multiPlayer.start(1); - * }); - */ - Tone.MultiPlayer = function () { - var options = this.optionsObject(arguments, [ - 'urls', - 'onload' - ], Tone.MultiPlayer.defaults); - if (options.urls instanceof Tone.Buffers) { - /** - * All the buffers belonging to the player. - * @type {Tone.Buffers} - */ - this.buffers = options.urls; - } else { - this.buffers = new Tone.Buffers(options.urls, options.onload); - } - /** - * Keeps track of the currently playing sources. - * @type {Object} - * @private - */ - this._activeSources = {}; - /** - * The fade in envelope which is applied - * to the beginning of the BufferSource - * @type {Time} - */ - this.fadeIn = options.fadeIn; - /** - * The fade out envelope which is applied - * to the end of the BufferSource - * @type {Time} - */ - this.fadeOut = options.fadeOut; - /** - * The output volume node - * @type {Tone.Volume} - * @private - */ - this._volume = this.output = new Tone.Volume(options.volume); - /** - * The volume of the output in decibels. - * @type {Decibels} - * @signal - * @example - * source.volume.value = -6; - */ - this.volume = this._volume.volume; - this._readOnly('volume'); - //make the output explicitly stereo - this._volume.output.output.channelCount = 2; - this._volume.output.output.channelCountMode = 'explicit'; - //mute initially - this.mute = options.mute; - }; - Tone.extend(Tone.MultiPlayer, Tone.Source); - /** - * The defaults - * @type {Object} - */ - Tone.MultiPlayer.defaults = { - 'onload': Tone.noOp, - 'fadeIn': 0, - 'fadeOut': 0 - }; - /** - * Make the source from the buffername - * @param {String} bufferName - * @return {Tone.BufferSource} - * @private - */ - Tone.MultiPlayer.prototype._makeSource = function (bufferName) { - var buffer; - if (this.isString(bufferName) || this.isNumber(bufferName)) { - buffer = this.buffers.get(bufferName).get(); - } else if (bufferName instanceof Tone.Buffer) { - buffer = bufferName.get(); - } else if (bufferName instanceof AudioBuffer) { - buffer = bufferName; - } - var source = new Tone.BufferSource(buffer).connect(this.output); - if (!this._activeSources.hasOwnProperty(bufferName)) { - this._activeSources[bufferName] = []; - } - this._activeSources[bufferName].push(source); - return source; - }; - /** - * Start a buffer by name. The `start` method allows a number of options - * to be passed in such as offset, interval, and gain. This is good for multi-sampled - * instruments and sound sprites where samples are repitched played back at different velocities. - * @param {String} bufferName The name of the buffer to start. - * @param {Time} time When to start the buffer. - * @param {Time} [offset=0] The offset into the buffer to play from. - * @param {Time=} duration How long to play the buffer for. - * @param {Interval} [pitch=0] The interval to repitch the buffer. - * @param {Gain} [gain=1] The gain to play the sample at. - * @return {Tone.MultiPlayer} this - */ - Tone.MultiPlayer.prototype.start = function (bufferName, time, offset, duration, pitch, gain) { - time = this.toSeconds(time); - var source = this._makeSource(bufferName); - source.start(time, offset, duration, this.defaultArg(gain, 1), this.fadeIn); - if (duration) { - source.stop(time + this.toSeconds(duration), this.fadeOut); - } - pitch = this.defaultArg(pitch, 0); - source.playbackRate.value = this.intervalToFrequencyRatio(pitch); - return this; - }; - /** - * Start a looping buffer by name. Similar to `start`, but the buffer - * is looped instead of played straight through. Can still be stopped with `stop`. - * @param {String} bufferName The name of the buffer to start. - * @param {Time} time When to start the buffer. - * @param {Time} [offset=0] The offset into the buffer to play from. - * @param {Time=} loopStart The start of the loop. - * @param {Time=} loopEnd The end of the loop. - * @param {Interval} [pitch=0] The interval to repitch the buffer. - * @param {Gain} [gain=1] The gain to play the sample at. - * @return {Tone.MultiPlayer} this - */ - Tone.MultiPlayer.prototype.startLoop = function (bufferName, time, offset, loopStart, loopEnd, pitch, gain) { - time = this.toSeconds(time); - var source = this._makeSource(bufferName); - source.loop = true; - source.loopStart = this.toSeconds(this.defaultArg(loopStart, 0)); - source.loopEnd = this.toSeconds(this.defaultArg(loopEnd, 0)); - source.start(time, offset, undefined, this.defaultArg(gain, 1), this.fadeIn); - pitch = this.defaultArg(pitch, 0); - source.playbackRate.value = this.intervalToFrequencyRatio(pitch); - return this; - }; - /** - * Stop the first played instance of the buffer name. - * @param {String} bufferName The buffer to stop. - * @param {Time=} time When to stop the buffer - * @return {Tone.MultiPlayer} this - */ - Tone.MultiPlayer.prototype.stop = function (bufferName, time) { - if (this._activeSources[bufferName] && this._activeSources[bufferName].length) { - time = this.toSeconds(time); - this._activeSources[bufferName].shift().stop(time, this.fadeOut); - } else { - throw new Error('Tone.MultiPlayer: cannot stop a buffer that hasn\'t been started or is already stopped'); - } - return this; - }; - /** - * Stop all currently playing buffers at the given time. - * @param {Time=} time When to stop the buffers. - * @return {Tone.MultiPlayer} this - */ - Tone.MultiPlayer.prototype.stopAll = function (time) { - time = this.toSeconds(time); - for (var bufferName in this._activeSources) { - var sources = this._activeSources[bufferName]; - for (var i = 0; i < sources.length; i++) { - sources[i].stop(time); - } - } - return this; - }; - /** - * Add another buffer to the available buffers. - * @param {String} name The name to that the buffer is refered - * to in start/stop methods. - * @param {String|Tone.Buffer} url The url of the buffer to load - * or the buffer. - * @param {Function} callback The function to invoke after the buffer is loaded. - */ - Tone.MultiPlayer.prototype.add = function (name, url, callback) { - this.buffers.add(name, url, callback); - return this; - }; - /** - * Returns the playback state of the source. "started" - * if there are any buffers playing. "stopped" otherwise. - * @type {Tone.State} - * @readOnly - * @memberOf Tone.MultiPlayer# - * @name state - */ - Object.defineProperty(Tone.MultiPlayer.prototype, 'state', { - get: function () { - return this._activeSources.length > 0 ? Tone.State.Started : Tone.State.Stopped; - } - }); - /** - * Mute the output. - * @memberOf Tone.MultiPlayer# - * @type {boolean} - * @name mute - * @example - * //mute the output - * source.mute = true; - */ - Object.defineProperty(Tone.MultiPlayer.prototype, 'mute', { - get: function () { - return this._volume.mute; - }, - set: function (mute) { - this._volume.mute = mute; - } - }); - /** - * Clean up. - * @return {Tone.MultiPlayer} this - */ - Tone.MultiPlayer.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._volume.dispose(); - this._volume = null; - this._writable('volume'); - this.volume = null; - for (var bufferName in this._activeSources) { - this._activeSources[bufferName].forEach(function (source) { - source.dispose(); - }); - } - this.buffers.dispose(); - this.buffers = null; - this._activeSources = null; - return this; - }; - return Tone.MultiPlayer; - }); - Module(function (Tone) { - /** - * @class Tone.GrainPlayer implements [granular synthesis](https://en.wikipedia.org/wiki/Granular_synthesis). - * Granular Synthesis enables you to adjust pitch and playback rate independently. The grainSize is the - * amount of time each small chunk of audio is played for and the overlap is the - * amount of crossfading transition time between successive grains. - * @extends {Tone} - * @param {String|Tone.Buffer} url The url to load, or the Tone.Buffer to play. - * @param {Function=} callback The callback to invoke after the url is loaded. - */ - Tone.GrainPlayer = function () { - var options = this.optionsObject(arguments, [ - 'url', - 'onload' - ], Tone.GrainPlayer.defaults); - Tone.Source.call(this); - /** - * The audio buffer belonging to the player. - * @type {Tone.Buffer} - */ - this.buffer = new Tone.Buffer(options.url, options.onload); - /** - * Plays the buffer with a small envelope - * @type {Tone.MultiPlayer} - * @private - */ - this._player = new Tone.MultiPlayer().connect(this.output); - /** - * Create a repeating tick to schedule - * the grains. - * @type {Tone.Clock} - * @private - */ - this._clock = new Tone.Clock(this._tick.bind(this), 1); - /** - * @type {Number} - * @private - */ - this._loopStart = 0; - /** - * @type {Number} - * @private - */ - this._loopEnd = 0; - /** - * @type {Number} - * @private - */ - this._playbackRate = options.playbackRate; - /** - * @type {Number} - * @private - */ - this._grainSize = options.grainSize; - /** - * @private - * @type {Number} - */ - this._overlap = options.overlap; - /** - * Adjust the pitch independently of the playbackRate. - * @type {Cents} - */ - this.detune = options.detune; - /** - * The amount of time randomly added - * or subtracted from the grain's offset - * @type {Time} - */ - this.drift = options.drift; - //setup - this.overlap = options.overlap; - this.loop = options.loop; - this.playbackRate = options.playbackRate; - this.grainSize = options.grainSize; - this.loopStart = options.loopStart; - this.loopEnd = options.loopEnd; - this.reverse = options.reverse; - }; - Tone.extend(Tone.GrainPlayer, Tone.Source); - /** - * the default parameters - * @static - * @const - * @type {Object} - */ - Tone.GrainPlayer.defaults = { - 'onload': Tone.noOp, - 'overlap': 0.1, - 'grainSize': 0.2, - 'drift': 0, - 'playbackRate': 1, - 'detune': 0, - 'loop': false, - 'loopStart': 0, - 'loopEnd': 0, - 'reverse': false - }; - /** - * Play the buffer at the given startTime. Optionally add an offset - * and/or duration which will play the buffer from a position - * within the buffer for the given duration. - * - * @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) - * @returns {Tone.GrainPlayer} this - * @memberOf Tone.GrainPlayer# - * @method start - * @name start - */ - /** - * Internal start method - * @param {Time} time - * @param {Time} offset - * @private - */ - Tone.GrainPlayer.prototype._start = function (time, offset, duration) { - offset = this.defaultArg(offset, 0); - offset = this.toSeconds(offset); - time = this.toSeconds(time); - this._offset = offset; - this._clock.start(time); - //unmute the player - this._player.volume.setValueAtTime(0, time); - if (duration) { - this._stop(time + this.toSeconds(duration)); - } - }; - /** - * Internal start method - * @param {Time} time - * @private - */ - Tone.GrainPlayer.prototype._stop = function (time) { - this._clock.stop(time); - //mute the player - this._player.volume.cancelScheduledValues(time); - this._player.volume.setValueAtTime(-Infinity, time); - }; - /** - * Invoked on each clock tick. scheduled a new - * grain at this time. - * @param {Time} time - * @private - */ - Tone.GrainPlayer.prototype._tick = function (time) { - var bufferDuration = this.buffer.duration; - if (this.loop && this._loopEnd > 0) { - bufferDuration = this._loopEnd; - } - var drift = (Math.random() * 2 - 1) * this.drift; - var offset = this._offset - this._overlap + drift; - var detune = this.detune / 100; - //keep the offset within the limits of the buffer - offset = Math.max(offset, 0); - offset = Math.min(offset, bufferDuration); - var originalFadeIn = this._player.fadeIn; - if (this.loop && this._offset > bufferDuration) { - //play the end - var endSegmentDuration = this._offset - bufferDuration; - this._player.start(this.buffer, time, offset, endSegmentDuration + this._overlap, detune); - //and play the beginning - offset = this._offset % bufferDuration; - this._offset = this._loopStart; - this._player.fadeIn = 0; - this._player.start(this.buffer, time + endSegmentDuration, this._offset, offset + this._overlap, detune); - } else if (this._offset > bufferDuration) { - //set the state to stopped. - this.stop(time); - } else { - if (offset === 0) { - this._player.fadeIn = 0; - } - this._player.start(this.buffer, time, offset, this.grainSize + this._overlap, detune); - } - this._player.fadeIn = originalFadeIn; - //increment the offset - var duration = this._clock._nextTick - time; - this._offset += duration * this._playbackRate; - }; - /** - * Jump to a specific time and play it. - * @param {Time} offset The offset to jump to. - * @param {Time=} time When to make the jump. - * @return {[type]} [description] - */ - Tone.GrainPlayer.prototype.scrub = function (offset, time) { - this._offset = this.toSeconds(offset); - this._tick(this.toSeconds(time)); - return this; - }; - /** - * The playback rate of the sample - * @memberOf Tone.GrainPlayer# - * @type {Positive} - * @name playbackRate - */ - Object.defineProperty(Tone.GrainPlayer.prototype, 'playbackRate', { - get: function () { - return this._playbackRate; - }, - set: function (rate) { - this._playbackRate = rate; - this.grainSize = this._grainSize; - } - }); - /** - * The loop start time. - * @memberOf Tone.GrainPlayer# - * @type {Time} - * @name loopStart - */ - Object.defineProperty(Tone.GrainPlayer.prototype, 'loopStart', { - get: function () { - return this._loopStart; - }, - set: function (time) { - this._loopStart = this.toSeconds(time); - } - }); - /** - * The loop end time. - * @memberOf Tone.GrainPlayer# - * @type {Time} - * @name loopEnd - */ - Object.defineProperty(Tone.GrainPlayer.prototype, 'loopEnd', { - get: function () { - return this._loopEnd; - }, - set: function (time) { - this._loopEnd = this.toSeconds(time); - } - }); - /** - * The direction the buffer should play in - * @memberOf Tone.GrainPlayer# - * @type {boolean} - * @name reverse - */ - Object.defineProperty(Tone.GrainPlayer.prototype, 'reverse', { - get: function () { - return this.buffer.reverse; - }, - set: function (rev) { - this.buffer.reverse = rev; - } - }); - /** - * The size of each chunk of audio that the - * buffer is chopped into and played back at. - * @memberOf Tone.GrainPlayer# - * @type {Time} - * @name grainSize - */ - Object.defineProperty(Tone.GrainPlayer.prototype, 'grainSize', { - get: function () { - return this._grainSize; - }, - set: function (size) { - this._grainSize = this.toSeconds(size); - this._clock.frequency.value = this._playbackRate / this._grainSize; - } - }); - /** - * This is the duration of the cross-fade between - * sucessive grains. - * @memberOf Tone.GrainPlayer# - * @type {Time} - * @name overlap - */ - Object.defineProperty(Tone.GrainPlayer.prototype, 'overlap', { - get: function () { - return this._overlap; - }, - set: function (time) { - time = this.toSeconds(time); - this._overlap = time; - if (this._overlap < 0) { - this._player.fadeIn = 0.01; - this._player.fadeOut = 0.01; - } else { - this._player.fadeIn = time; - this._player.fadeOut = time; - } - } - }); - /** - * Clean up - * @return {Tone.GrainPlayer} this - */ - Tone.GrainPlayer.prototype.dispose = function () { - Tone.Source.prototype.dispose.call(this); - this.buffer.dispose(); - this.buffer = null; - this._player.dispose(); - this._player = null; - this._clock.dispose(); - this._clock = null; - return this; - }; - return Tone.GrainPlayer; - }); - Module(function (Tone) { - - /** - * @class Tone.UserMedia uses MediaDevices.getUserMedia to open up - * and external microphone or audio input. Check - * [MediaDevices API Support](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) - * to see which browsers are supported. Access to an external input - * is limited to secure (HTTPS) connections. - * - * @constructor - * @extends {Tone} - * @param {Decibels=} volume The level of the input - * @example - * //list the inputs and open the third one - * var motu = new Tone.UserMedia(); - * - * //opening the input asks the user to activate their mic - * motu.open().then(function(){ - * //opening is activates the microphone - * //starting lets audio through - * motu.start(10); - * }); - */ - Tone.UserMedia = function () { - var options = this.optionsObject(arguments, ['volume'], Tone.UserMedia.defaults); - /** - * The MediaStreamNode - * @type {MediaStreamAudioSourceNode} - * @private - */ - this._mediaStream = null; - /** - * The media stream created by getUserMedia. - * @type {LocalMediaStream} - * @private - */ - this._stream = null; - /** - * The open device - * @type {MediaDeviceInfo} - * @private - */ - this._device = null; - /** - * The output volume node - * @type {Tone.Volume} - * @private - */ - this._volume = this.output = new Tone.Volume(options.volume); - /** - * The volume of the output in decibels. - * @type {Decibels} - * @signal - * @example - * input.volume.value = -6; - */ - this.volume = this._volume.volume; - this._readOnly('volume'); - this.mute = options.mute; - }; - Tone.extend(Tone.UserMedia); - /** - * the default parameters - * @type {Object} - */ - Tone.UserMedia.defaults = { - 'volume': 0, - 'mute': false - }; - /** - * Open the media stream. If a string is passed in, it is assumed - * to be the label or id of the stream, if a number is passed in, - * it is the input number of the stream. - * @param {String|Number} [labelOrId="default"] The label or id of the audio input media device. - * With no argument, the default stream is opened. - * @return {Promise} The promise is resolved when the stream is open. - */ - Tone.UserMedia.prototype.open = function (labelOrId) { - labelOrId = this.defaultArg(labelOrId, 'default'); - return this.enumerateDevices().then(function (devices) { - var device; - if (this.isNumber(labelOrId)) { - device = devices[labelOrId]; - } else { - device = devices.find(function (device) { - return device.label === labelOrId || device.deviceId === labelOrId; - }); - if (!device) { - //otherwise just take the first one - device = devices[0]; - } - } - //didn't find a matching device - if (!device) { - throw new Error('Tone.UserMedia: no matching audio inputs.'); - } - this._device = device; - //do getUserMedia - var constraints = { - audio: { - 'deviceId': device.deviceId, - 'echoCancellation': false, - 'sampleRate': this.context.sampleRate - } - }; - return navigator.mediaDevices.getUserMedia(constraints).then(function (stream) { - //start a new source only if the previous one is closed - if (!this._stream) { - this._stream = stream; - //Wrap a MediaStreamSourceNode around the live input stream. - this._mediaStream = this.context.createMediaStreamSource(stream); - //Connect the MediaStreamSourceNode to a gate gain node - this._mediaStream.connect(this.output); - } - return this; - }.bind(this)); - }.bind(this)); - }; - /** - * Close the media stream - * @return {Tone.UserMedia} this - */ - Tone.UserMedia.prototype.close = function () { - if (this._stream) { - this._stream.getAudioTracks().forEach(function (track) { - track.stop(); - }); - this._stream = null; - //remove the old media stream - this._mediaStream.disconnect(); - this._mediaStream = null; - } - this._device = null; - return this; - }; - /** - * Returns a promise which resolves with the list of audio input devices available. - * @return {Promise} The promise that is resolved with the devices - * @example - * extInput.enumerateDevices().then(function(devices){ - * console.log(devices) - * }) - */ - Tone.UserMedia.prototype.enumerateDevices = function () { - return navigator.mediaDevices.enumerateDevices().then(function (devices) { - return devices.filter(function (device) { - return device.kind === 'audioinput'; - }); - }); - }; - /** - * Returns the playback state of the source, "started" when the microphone is open - * and "stopped" when the mic is closed. - * @type {Tone.State} - * @readOnly - * @memberOf Tone.UserMedia# - * @name state - */ - Object.defineProperty(Tone.UserMedia.prototype, 'state', { - get: function () { - return this._stream && this._stream.active ? Tone.State.Started : Tone.State.Stopped; - } - }); - /** - * Returns an identifier for the represented device that is - * persisted across sessions. It is un-guessable by other applications and - * unique to the origin of the calling application. It is reset when the - * user clears cookies (for Private Browsing, a different identifier is - * used that is not persisted across sessions). Returns undefined when the - * device is not open. - * @type {String} - * @readOnly - * @memberOf Tone.UserMedia# - * @name deviceId - */ - Object.defineProperty(Tone.UserMedia.prototype, 'deviceId', { - get: function () { - if (this._device) { - return this._device.deviceId; - } - } - }); - /** - * Returns a group identifier. Two devices have the - * same group identifier if they belong to the same physical device. - * Returns undefined when the device is not open. - * @type {String} - * @readOnly - * @memberOf Tone.UserMedia# - * @name groupId - */ - Object.defineProperty(Tone.UserMedia.prototype, 'groupId', { - get: function () { - if (this._device) { - return this._device.groupId; - } - } - }); - /** - * Returns a label describing this device (for example "Built-in Microphone"). - * Returns undefined when the device is not open or label is not available - * because of permissions. - * @type {String} - * @readOnly - * @memberOf Tone.UserMedia# - * @name groupId - */ - Object.defineProperty(Tone.UserMedia.prototype, 'label', { - get: function () { - if (this._device) { - return this._device.label; - } - } - }); - /** - * Mute the output. - * @memberOf Tone.UserMedia# - * @type {boolean} - * @name mute - * @example - * //mute the output - * userMedia.mute = true; - */ - Object.defineProperty(Tone.UserMedia.prototype, 'mute', { - get: function () { - return this._volume.mute; - }, - set: function (mute) { - this._volume.mute = mute; - } - }); - /** - * Clean up. - * @return {Tone.UserMedia} this - */ - Tone.UserMedia.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this.close(); - this._writable('volume'); - this._volume.dispose(); - this._volume = null; - this.volume = null; - return this; - }; - /** - * If getUserMedia is supported by the browser. - * @type {Boolean} - * @memberOf Tone.UserMedia# - * @name supported - * @static - * @readOnly - */ - Object.defineProperty(Tone.UserMedia, 'supported', { - get: function () { - return !Tone.prototype.isUndef(navigator.mediaDevices) && Tone.prototype.isFunction(navigator.mediaDevices.getUserMedia); - } - }); - return Tone.UserMedia; - }); - - return Tone; -})); - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var palettes = [[[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [0.00, 0.33, 0.67]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [0.00, 0.10, 0.20]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [0.30, 0.20, 0.20]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 0.5], [0.80, 0.90, 0.30]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 0.7, 0.4], [0.00, 0.15, 0.20]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [2.0, 1.0, 0.0], [0.50, 0.20, 0.25]], [[0.8, 0.5, 0.4], [0.2, 0.4, 0.2], [2.0, 1.0, 1.0], [0.00, 0.25, 0.25]]]; - -var palette = palettes[0]; - -function channel(t, a, b, c, d, add, mul) { - return a + b * Math.cos(2 * Math.PI * (c * t + d)) * mul + add; -} - -function color(t, add, mul) { - var a = void 0, - b = void 0, - c = void 0, - d = void 0; - var rgb = []; - for (var i = 0; i < 3; i++) { - a = palette[0][i]; - b = palette[1][i]; - c = palette[2][i]; - d = palette[3][i]; - rgb[i] = Math.round(channel(t, a, b, c, d, add, mul) * 255); - } - return 'rgb(' + rgb + ')'; -} - -exports.default = color; - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -var keys = {}; -var key_numbers = {}; -var letters = "zxcvbnmasdfghjklqwertyuiop"; -var numbers = "1234567890"; - -var callback = function callback() {}; - -letters.toUpperCase().split("").map(function (k, i) { - keys[k.charCodeAt(0)] = i; -}); - -numbers.split("").map(function (k, i) { - keys[k.charCodeAt(0)] = i + letters.length; - key_numbers[k.charCodeAt(0)] = true; -}); - -window.addEventListener("keydown", keydown, true); -function keydown(e) { - if (e.altKey || e.ctrlKey || e.metaKey) { - e.stopPropagation(); - return; - } - if (document.activeElement instanceof HTMLInputElement && e.keyCode in key_numbers) { - e.stopPropagation(); - return; - } - if (!(e.keyCode in keys)) return; - var index = keys[e.keyCode]; - if (e.shiftKey) index += letters.length; - index -= 7; - callback(index); -} - -function listen(fn) { - callback = fn; -} - -exports.default = { listen: listen }; - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.requestAudioContext = exports.firstTouch = exports.browser = exports.clamp = exports.mod = exports.choice = undefined; - -var _tone = __webpack_require__(0); - -var _tone2 = _interopRequireDefault(_tone); - -var _startAudioContext = __webpack_require__(5); - -var _startAudioContext2 = _interopRequireDefault(_startAudioContext); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var isIphone = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i); -var isIpad = navigator.userAgent.match(/iPad/i); -var isAndroid = navigator.userAgent.match(/Android/i); -var isMobile = isIphone || isIpad || isAndroid; -var isDesktop = !isMobile; - -document.body.classList.add(isMobile ? 'mobile' : 'desktop'); - -var browser = { isIphone: isIphone, isIpad: isIpad, isMobile: isMobile, isDesktop: isDesktop }; - -function clamp(n, a, b) { - return n < a ? a : n < b ? n : b; -} -function choice(a) { - return a[Math.floor(Math.random() * a.length)]; -} -function mod(n, m) { - return n - m * Math.floor(n / m); -} -function firstTouch(f) { - return function (e) { - e.preventDefault();f(e.touches[0]); - }; -} - -function requestAudioContext(fn) { - if (isMobile) { - var container = document.createElement('div'); - var button = document.createElement('div'); - button.innerHTML = 'Tap to start - please unmute your phone'; - Object.assign(container.style, { - display: 'block', - position: 'absolute', - width: '100%', - height: '100%', - zIndex: '10000', - top: '0px', - left: '0px', - backgroundColor: 'rgba(0, 0, 0, 0.8)' - }); - Object.assign(button.style, { - display: 'block', - position: 'absolute', - left: '50%', - top: '50%', - padding: '20px', - backgroundColor: '#7F33ED', - color: 'white', - fontFamily: 'monospace', - borderRadius: '3px', - transform: 'translate3D(-50%,-50%,0)', - textAlign: 'center', - lineHeight: '1.5', - width: '150px' - }); - container.appendChild(button); - document.body.appendChild(container); - _startAudioContext2.default.setContext(_tone2.default.context); - _startAudioContext2.default.on(button); - _startAudioContext2.default.onStarted(function (_) { - container.remove(); - fn(); - }); - } else { - fn(); - } -} - -exports.choice = choice; -exports.mod = mod; -exports.clamp = clamp; -exports.browser = browser; -exports.firstTouch = firstTouch; -exports.requestAudioContext = requestAudioContext; - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _tone = __webpack_require__(0); - -var _tone2 = _interopRequireDefault(_tone); - -var _keys = __webpack_require__(2); - -var _keys2 = _interopRequireDefault(_keys); - -var _color = __webpack_require__(1); - -var _color2 = _interopRequireDefault(_color); - -var _util = __webpack_require__(3); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var compressor = new _tone2.default.Compressor(-30, 3).toMaster(); - -var GRAIN_TIME = 1 / 2; -var SAMPLE_RATE = 44100; -var GRAIN_SIZE = GRAIN_TIME * SAMPLE_RATE; - -(0, _util.requestAudioContext)(function () { - var clock = new _tone2.default.Clock(tick, 1 / GRAIN_TIME); - clock.start(); - console.log('ready'); -}); - -var offsets = []; - -var player = new _tone2.default.MultiPlayer({ - applause: 'applause.mp3' -}, function () { - var data = player.buffers.get('applause').get().getChannelData(0); - var intensities = []; - for (var i = 0, len = Math.floor(data.length / GRAIN_SIZE); i < len; i++) { - var z = 0; - for (var j = i * GRAIN_SIZE, max = (i + 1) * GRAIN_SIZE; j < max; j++) { - z += Math.abs(data[j]); - } - intensities[i] = [z / GRAIN_SIZE, i]; - } - offsets = intensities.sort(function (a, b) { - return a[0] < b[0] ? -1 : a[0] == b[0] ? 0 : 1; - }).map(function (a, i) { - return a[1]; - }); -}); - -player.fadeIn = 0.25; -player.fadeOut = 0.25; -player.connect(compressor); - -var intensity = 0, - inertialIntensity = 0, - inertia = 5; - -function tick(time) { - if (!offsets.length) return; - // let offsetIndex = clamp( Math.floor(mouse.y * offsets.length + Math.cos(time/20)), 0, offsets.length-1 ) - inertialIntensity = Math.max(intensity, (intensity + inertialIntensity * (inertia - 1)) / inertia); - console.log(inertialIntensity); - var offsetIntensity = 0.94 * inertialIntensity + 0.02; - var offsetIndex = Math.floor(offsetIntensity * offsets.length + Math.cos(time)); - var offset = Math.max((offsets[offsetIndex] || 0) * GRAIN_TIME + 0.25 * Math.sin(time * 17 / 7), 0); - // console.log(offset, offsets[offsetIndex] * GRAIN_TIME, ( 0.25 * Math.cos(time*13/7))) - player.start('applause', time, offset, GRAIN_TIME * 4, 0, inertialIntensity); -} - -var mouse = { x: 0, y: 0 }; -var drawing = false; -var canvas = document.createElement('canvas'); -canvas.width = window.innerWidth; -canvas.height = window.innerHeight; -var ctx = canvas.getContext('2d'); -document.body.appendChild(canvas); - -function down(e) { - drawing = true; - mouse.x = e.pageX / window.innerWidth; - mouse.y = e.pageY / window.innerHeight; -} -function move(e) { - var x = e.pageX / window.innerWidth; - var y = e.pageY / window.innerHeight; - var dx = mouse.x - x; - var dy = mouse.y - y; - var v = Math.sqrt(dx * dx + dy * dy); - if (drawing) { - intensity = Math.min(0.999, intensity + v * 0.1); - inertialIntensity = Math.min(0.999, intensity); - if (intensity == 0.999) intensity -= Math.random() * 0.4; - if (inertialIntensity == 0.999) inertialIntensity -= Math.random() * 0.3; - var gray = Math.floor((0, _util.clamp)(10 * v, 0, 1) * 127); - ctx.fillStyle = 'rgb(' + [gray, gray, gray * 2] + ')'; - ctx.beginPath(); - ctx.arc(x * window.innerWidth, y * window.innerHeight, v * 500, 0, Math.PI * 2); - ctx.fill(); - } - mouse.x = x; - mouse.y = y; -} -function up(e) { - drawing = false; - intensity = 0; -} -setInterval(function () { - inertialIntensity += 0.001; -}, 5000); - -if (_util.browser.isMobile) { - document.body.addEventListener('touchstart', (0, _util.firstTouch)(down)); - document.body.addEventListener('touchmove', (0, _util.firstTouch)(move)); - window.addEventListener('touchend', (0, _util.firstTouch)(up)); -} else { - document.body.addEventListener('mousedown', down); - document.body.addEventListener('mousemove', move); - window.addEventListener('mouseup', up); -} - -function animate() { - requestAnimationFrame(animate); - ctx.save(); - ctx.fillStyle = 'rgba(0,0,0,' + (1 - (intensity || 0.01)) + ')'; - ctx.globalAlpha = 0.4; - ctx.rotate(0.001); - ctx.drawImage(canvas, -2, -2, canvas.width + 4, canvas.height + 4); - ctx.rotate(-0.001); - ctx.globalAlpha = 0.05 * Math.random(); - ctx.fillRect(0, 0, window.innerWidth, window.innerHeight); - ctx.restore(); -} -animate(); - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -/** +return function(t){e=t()}(function(){var t=function(t,e){this.isUndef(t)||1===t?this.input=this.context.createGain():t>1&&(this.input=new Array(t)),this.isUndef(e)||1===e?this.output=this.context.createGain():e>1&&(this.output=new Array(t))};t.prototype.set=function(e,i,n){if(this.isObject(e))n=i;else if(this.isString(e)){var s={};s[e]=i,e=s}t:for(var o in e){i=e[o];var r=this;if(-1!==o.indexOf(".")){for(var a=o.split("."),h=0;h<a.length-1;h++)if((r=r[a[h]])instanceof t){a.splice(0,h+1);var l=a.join(".");r.set(l,i);continue t}o=a[a.length-1]}var u=r[o];this.isUndef(u)||(t.Signal&&u instanceof t.Signal||t.Param&&u instanceof t.Param?u.value!==i&&(this.isUndef(n)?u.value=i:u.rampTo(i,n)):u instanceof AudioParam?u.value!==i&&(u.value=i):u instanceof t?u.set(i):u!==i&&(r[o]=i))}return this},t.prototype.get=function(e){this.isUndef(e)?e=this._collectDefaults(this.constructor):this.isString(e)&&(e=[e]);for(var i={},n=0;n<e.length;n++){var s=e[n],o=this,r=i;if(-1!==s.indexOf(".")){for(var a=s.split("."),h=0;h<a.length-1;h++){var l=a[h];r[l]=r[l]||{},r=r[l],o=o[l]}s=a[a.length-1]}var u=o[s];this.isObject(e[s])?r[s]=u.get():t.Signal&&u instanceof t.Signal?r[s]=u.value:t.Param&&u instanceof t.Param?r[s]=u.value:u instanceof AudioParam?r[s]=u.value:u instanceof t?r[s]=u.get():this.isFunction(u)||this.isUndef(u)||(r[s]=u)}return i},t.prototype._collectDefaults=function(t){var e=[];if(this.isUndef(t.defaults)||(e=Object.keys(t.defaults)),!this.isUndef(t._super))for(var i=this._collectDefaults(t._super),n=0;n<i.length;n++)-1===e.indexOf(i[n])&&e.push(i[n]);return e},t.prototype.toString=function(){for(var e in t){var i=e[0].match(/^[A-Z]$/),n=t[e]===this.constructor;if(this.isFunction(t[e])&&i&&n)return e}return"Tone"},Object.defineProperty(t.prototype,"numberOfInputs",{get:function(){return this.input?this.isArray(this.input)?this.input.length:1:0}}),Object.defineProperty(t.prototype,"numberOfOutputs",{get:function(){return this.output?this.isArray(this.output)?this.output.length:1:0}}),t.prototype.dispose=function(){return this.isUndef(this.input)||(this.input instanceof AudioNode&&this.input.disconnect(),this.input=null),this.isUndef(this.output)||(this.output instanceof AudioNode&&this.output.disconnect(),this.output=null),this},t.prototype.connect=function(t,e,i){return Array.isArray(this.output)?(e=this.defaultArg(e,0),this.output[e].connect(t,0,i)):this.output.connect(t,e,i),this},t.prototype.disconnect=function(t,e,i){this.isArray(this.output)?this.isNumber(t)?this.output[t].disconnect():(e=this.defaultArg(e,0),this.output[e].disconnect(t,0,i)):this.output.disconnect.apply(this.output,arguments)},t.prototype.connectSeries=function(){if(arguments.length>1)for(var t=arguments[0],e=1;e<arguments.length;e++){var i=arguments[e];t.connect(i),t=i}return this},t.prototype.chain=function(){if(arguments.length>0)for(var t=this,e=0;e<arguments.length;e++){var i=arguments[e];t.connect(i),t=i}return this},t.prototype.fan=function(){if(arguments.length>0)for(var t=0;t<arguments.length;t++)this.connect(arguments[t]);return this},AudioNode.prototype.chain=t.prototype.chain,AudioNode.prototype.fan=t.prototype.fan,t.prototype.defaultArg=function(t,e){if(this.isObject(t)&&this.isObject(e)){var i={};for(var n in t)i[n]=this.defaultArg(e[n],t[n]);for(var s in e)i[s]=this.defaultArg(t[s],e[s]);return i}return this.isUndef(t)?e:t},t.prototype.optionsObject=function(t,e,i){var n={};if(1===t.length&&this.isObject(t[0]))n=t[0];else for(var s=0;s<e.length;s++)n[e[s]]=t[s];return this.isUndef(i)?n:this.defaultArg(n,i)},t.prototype.isUndef=function(t){return void 0===t},t.prototype.isFunction=function(t){return"function"==typeof t},t.prototype.isNumber=function(t){return"number"==typeof t},t.prototype.isObject=function(t){return"[object Object]"===Object.prototype.toString.call(t)&&t.constructor===Object},t.prototype.isBoolean=function(t){return"boolean"==typeof t},t.prototype.isArray=function(t){return Array.isArray(t)},t.prototype.isString=function(t){return"string"==typeof t},t.noOp=function(){},t.prototype._readOnly=function(t){if(Array.isArray(t))for(var e=0;e<t.length;e++)this._readOnly(t[e]);else Object.defineProperty(this,t,{writable:!1,enumerable:!0})},t.prototype._writable=function(t){if(Array.isArray(t))for(var e=0;e<t.length;e++)this._writable(t[e]);else Object.defineProperty(this,t,{writable:!0})},t.State={Started:"started",Stopped:"stopped",Paused:"paused"},t.prototype.equalPowerScale=function(t){var e=.5*Math.PI;return Math.sin(t*e)},t.prototype.dbToGain=function(t){return Math.pow(2,t/6)},t.prototype.gainToDb=function(t){return Math.log(t)/Math.LN10*20},t.prototype.intervalToFrequencyRatio=function(t){return Math.pow(2,t/12)},t.prototype.now=function(){return t.context.now()},t.now=function(){return t.context.now()},t.extend=function(e,i){function n(){}t.prototype.isUndef(i)&&(i=t),n.prototype=i.prototype,e.prototype=new n,e.prototype.constructor=e,e._super=i};var e;return Object.defineProperty(t,"context",{get:function(){return e},set:function(i){e=t.Context&&i instanceof t.Context?i:new t.Context(i),t.Context&&t.Context.emit("init",e)}}),Object.defineProperty(t.prototype,"context",{get:function(){return t.context}}),t.setContext=function(e){t.context=e},Object.defineProperty(t.prototype,"blockTime",{get:function(){return 128/this.context.sampleRate}}),Object.defineProperty(t.prototype,"sampleTime",{get:function(){return 1/this.context.sampleRate}}),Object.defineProperty(t,"supported",{get:function(){var t=window.hasOwnProperty("AudioContext")||window.hasOwnProperty("webkitAudioContext"),e=window.hasOwnProperty("Promise"),i=window.hasOwnProperty("Worker");return t&&e&&i}}),t.version="r10",window.TONE_SILENCE_VERSION_LOGGING||console.log("%c * Tone.js "+t.version+" * ","background: #000; color: #fff"),t}),t(function(t){return t.SignalBase=function(){},t.extend(t.SignalBase),t.SignalBase.prototype.connect=function(e,i,n){return t.Signal&&t.Signal===e.constructor||t.Param&&t.Param===e.constructor||t.TimelineSignal&&t.TimelineSignal===e.constructor?(e._param.cancelScheduledValues(0),e._param.value=0,e.overridden=!0):e instanceof AudioParam&&(e.cancelScheduledValues(0),e.value=0),t.prototype.connect.call(this,e,i,n),this},t.SignalBase}),t(function(t){return t.WaveShaper=function(t,e){this._shaper=this.input=this.output=this.context.createWaveShaper(),this._curve=null,Array.isArray(t)?this.curve=t:isFinite(t)||this.isUndef(t)?this._curve=new Float32Array(this.defaultArg(t,1024)):this.isFunction(t)&&(this._curve=new Float32Array(this.defaultArg(e,1024)),this.setMap(t))},t.extend(t.WaveShaper,t.SignalBase),t.WaveShaper.prototype.setMap=function(t){for(var e=0,i=this._curve.length;e<i;e++){var n=e/(i-1)*2-1;this._curve[e]=t(n,e)}return this._shaper.curve=this._curve,this},Object.defineProperty(t.WaveShaper.prototype,"curve",{get:function(){return this._shaper.curve},set:function(t){this._curve=new Float32Array(t),this._shaper.curve=this._curve}}),Object.defineProperty(t.WaveShaper.prototype,"oversample",{get:function(){return this._shaper.oversample},set:function(t){if(-1===["none","2x","4x"].indexOf(t))throw new RangeError("Tone.WaveShaper: oversampling must be either 'none', '2x', or '4x'");this._shaper.oversample=t}}),t.WaveShaper.prototype.dispose=function(){return t.prototype.dispose.call(this),this._shaper.disconnect(),this._shaper=null,this._curve=null,this},t.WaveShaper}),t(function(t){return t.TimeBase=function(e,i){if(!(this instanceof t.TimeBase))return new t.TimeBase(e,i);if(this._expr=this._noOp,e instanceof t.TimeBase)this.copy(e);else if(!this.isUndef(i)||this.isNumber(e)){i=this.defaultArg(i,this._defaultUnits);var n=this._primaryExpressions[i].method;this._expr=n.bind(this,e)}else this.isString(e)?this.set(e):this.isUndef(e)&&(this._expr=this._defaultExpr())},t.extend(t.TimeBase),t.TimeBase.prototype.set=function(t){return this._expr=this._parseExprString(t),this},t.TimeBase.prototype.clone=function(){var t=new this.constructor;return t.copy(this),t},t.TimeBase.prototype.copy=function(t){var e=t._expr();return this.set(e)},t.TimeBase.prototype._primaryExpressions={n:{regexp:/^(\d+)n/i,method:function(t){return t=parseInt(t),1===t?this._beatsToUnits(this._timeSignature()):this._beatsToUnits(4/t)}},t:{regexp:/^(\d+)t/i,method:function(t){return t=parseInt(t),this._beatsToUnits(8/(3*parseInt(t)))}},m:{regexp:/^(\d+)m/i,method:function(t){return this._beatsToUnits(parseInt(t)*this._timeSignature())}},i:{regexp:/^(\d+)i/i,method:function(t){return this._ticksToUnits(parseInt(t))}},hz:{regexp:/^(\d+(?:\.\d+)?)hz/i,method:function(t){return this._frequencyToUnits(parseFloat(t))}},tr:{regexp:/^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,method:function(t,e,i){var n=0;return t&&"0"!==t&&(n+=this._beatsToUnits(this._timeSignature()*parseFloat(t))),e&&"0"!==e&&(n+=this._beatsToUnits(parseFloat(e))),i&&"0"!==i&&(n+=this._beatsToUnits(parseFloat(i)/4)),n}},s:{regexp:/^(\d+(?:\.\d+)?s)/,method:function(t){return this._secondsToUnits(parseFloat(t))}},samples:{regexp:/^(\d+)samples/,method:function(t){return parseInt(t)/this.context.sampleRate}},default:{regexp:/^(\d+(?:\.\d+)?)/,method:function(t){return this._primaryExpressions[this._defaultUnits].method.call(this,t)}}},t.TimeBase.prototype._binaryExpressions={"+":{regexp:/^\+/,precedence:2,method:function(t,e){return t()+e()}},"-":{regexp:/^\-/,precedence:2,method:function(t,e){return t()-e()}},"*":{regexp:/^\*/,precedence:1,method:function(t,e){return t()*e()}},"/":{regexp:/^\//,precedence:1,method:function(t,e){return t()/e()}}},t.TimeBase.prototype._unaryExpressions={neg:{regexp:/^\-/,method:function(t){return-t()}}},t.TimeBase.prototype._syntaxGlue={"(":{regexp:/^\(/},")":{regexp:/^\)/}},t.TimeBase.prototype._tokenize=function(t){for(var e=-1,i=[];t.length>0;){t=t.trim();var n=function(t,e){for(var i=["_binaryExpressions","_unaryExpressions","_primaryExpressions","_syntaxGlue"],n=0;n<i.length;n++){var s=e[i[n]];for(var o in s){var r=s[o],a=r.regexp,h=t.match(a);if(null!==h)return{method:r.method,precedence:r.precedence,regexp:r.regexp,value:h[0]}}}throw new SyntaxError("Tone.TimeBase: Unexpected token "+t)}(t,this);i.push(n),t=t.substr(n.value.length)}return{next:function(){return i[++e]},peek:function(){return i[e+1]}}},t.TimeBase.prototype._matchGroup=function(t,e,i){if(!this.isUndef(t))for(var n in e){var s=e[n];if(s.regexp.test(t.value)){if(this.isUndef(i))return s;if(s.precedence===i)return s}}return!1},t.TimeBase.prototype._parseBinary=function(t,e){this.isUndef(e)&&(e=2);var i;i=e<0?this._parseUnary(t):this._parseBinary(t,e-1);for(var n=t.peek();n&&this._matchGroup(n,this._binaryExpressions,e);)n=t.next(),i=n.method.bind(this,i,this._parseBinary(t,e-1)),n=t.peek();return i},t.TimeBase.prototype._parseUnary=function(t){var e,i;e=t.peek();var n=this._matchGroup(e,this._unaryExpressions);return n?(e=t.next(),i=this._parseUnary(t),n.method.bind(this,i)):this._parsePrimary(t)},t.TimeBase.prototype._parsePrimary=function(t){var e,i;if(e=t.peek(),this.isUndef(e))throw new SyntaxError("Tone.TimeBase: Unexpected end of expression");if(this._matchGroup(e,this._primaryExpressions)){e=t.next();var n=e.value.match(e.regexp);return e.method.bind(this,n[1],n[2],n[3])}if(e&&"("===e.value){if(t.next(),i=this._parseBinary(t),!(e=t.next())||")"!==e.value)throw new SyntaxError("Expected )");return i}throw new SyntaxError("Tone.TimeBase: Cannot process token "+e.value)},t.TimeBase.prototype._parseExprString=function(t){this.isString(t)||(t=t.toString());var e=this._tokenize(t);return this._parseBinary(e)},t.TimeBase.prototype._noOp=function(){return 0},t.TimeBase.prototype._defaultExpr=function(){return this._noOp},t.TimeBase.prototype._defaultUnits="s",t.TimeBase.prototype._frequencyToUnits=function(t){return 1/t},t.TimeBase.prototype._beatsToUnits=function(e){return 60/t.Transport.bpm.value*e},t.TimeBase.prototype._secondsToUnits=function(t){return t},t.TimeBase.prototype._ticksToUnits=function(e){return e*(this._beatsToUnits(1)/t.Transport.PPQ)},t.TimeBase.prototype._timeSignature=function(){return t.Transport.timeSignature},t.TimeBase.prototype._pushExpr=function(e,i,n){return e instanceof t.TimeBase||(e=new this.constructor(e,n)),this._expr=this._binaryExpressions[i].method.bind(this,this._expr,e._expr),this},t.TimeBase.prototype.add=function(t,e){return this._pushExpr(t,"+",e)},t.TimeBase.prototype.sub=function(t,e){return this._pushExpr(t,"-",e)},t.TimeBase.prototype.mult=function(t,e){return this._pushExpr(t,"*",e)},t.TimeBase.prototype.div=function(t,e){return this._pushExpr(t,"/",e)},t.TimeBase.prototype.valueOf=function(){return this._expr()},t.TimeBase.prototype.dispose=function(){this._expr=null},t.TimeBase}),t(function(t){return t.Time=function(e,i){if(!(this instanceof t.Time))return new t.Time(e,i);this._plusNow=!1,t.TimeBase.call(this,e,i)},t.extend(t.Time,t.TimeBase),t.Time.prototype._unaryExpressions=Object.create(t.TimeBase.prototype._unaryExpressions),t.Time.prototype._unaryExpressions.quantize={regexp:/^@/,method:function(e){return t.Transport.nextSubdivision(e())}},t.Time.prototype._unaryExpressions.now={regexp:/^\+/,method:function(t){return this._plusNow=!0,t()}},t.Time.prototype.quantize=function(t,e){return e=this.defaultArg(e,1),this._expr=function(t,e,i){return t=t(),e=e.toSeconds(),t+(Math.round(t/e)*e-t)*i}.bind(this,this._expr,new this.constructor(t),e),this},t.Time.prototype.addNow=function(){return this._plusNow=!0,this},t.Time.prototype._defaultExpr=function(){return this._plusNow=!0,this._noOp},t.Time.prototype.copy=function(e){return t.TimeBase.prototype.copy.call(this,e),this._plusNow=e._plusNow,this},t.Time.prototype.toNotation=function(){var t=this.toSeconds(),e=["1m","2n","4n","8n","16n","32n","64n","128n"],i=this._toNotationHelper(t,e),n=["1m","2n","2t","4n","4t","8n","8t","16n","16t","32n","32t","64n","64t","128n"],s=this._toNotationHelper(t,n);return s.split("+").length<i.split("+").length?s:i},t.Time.prototype._toNotationHelper=function(t,e){for(var i=this._notationToUnits(e[e.length-1]),n="",s=0;s<e.length;s++){var o=this._notationToUnits(e[s]),r=t/o;if(1-r%1<1e-6&&(r+=1e-6),(r=Math.floor(r))>0){if(n+=1===r?e[s]:r.toString()+"*"+e[s],(t-=r*o)<i)break;n+=" + "}}return""===n&&(n="0"),n},t.Time.prototype._notationToUnits=function(t){for(var e=this._primaryExpressions,i=[e.n,e.t,e.m],n=0;n<i.length;n++){var s=i[n],o=t.match(s.regexp);if(o)return s.method.call(this,o[1])}},t.Time.prototype.toBarsBeatsSixteenths=function(){var t=this._beatsToUnits(1),e=this.toSeconds()/t,i=Math.floor(e/this._timeSignature()),n=e%1*4;return e=Math.floor(e)%this._timeSignature(),n=n.toString(),n.length>3&&(n=parseFloat(n).toFixed(3)),[i,e,n].join(":")},t.Time.prototype.toTicks=function(){var e=this._beatsToUnits(1),i=this.valueOf()/e;return Math.floor(i*t.Transport.PPQ)},t.Time.prototype.toSamples=function(){return this.toSeconds()*this.context.sampleRate},t.Time.prototype.toFrequency=function(){return 1/this.toSeconds()},t.Time.prototype.toSeconds=function(){return this.valueOf()},t.Time.prototype.toMilliseconds=function(){return 1e3*this.toSeconds()},t.Time.prototype.valueOf=function(){return this._expr()+(this._plusNow?this.now():0)},t.Time}),t(function(t){t.Frequency=function(e,i){if(!(this instanceof t.Frequency))return new t.Frequency(e,i);t.TimeBase.call(this,e,i)},t.extend(t.Frequency,t.TimeBase),t.Frequency.prototype._primaryExpressions=Object.create(t.TimeBase.prototype._primaryExpressions),t.Frequency.prototype._primaryExpressions.midi={regexp:/^(\d+(?:\.\d+)?midi)/,method:function(t){return this.midiToFrequency(t)}},t.Frequency.prototype._primaryExpressions.note={regexp:/^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i,method:function(t,i){var n=e[t.toLowerCase()],s=n+12*(parseInt(i)+1);return this.midiToFrequency(s)}},t.Frequency.prototype._primaryExpressions.tr={regexp:/^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,method:function(t,e,i){var n=1;return t&&"0"!==t&&(n*=this._beatsToUnits(this._timeSignature()*parseFloat(t))),e&&"0"!==e&&(n*=this._beatsToUnits(parseFloat(e))),i&&"0"!==i&&(n*=this._beatsToUnits(parseFloat(i)/4)),n}},t.Frequency.prototype.transpose=function(t){return this._expr=function(t,e){return t()*this.intervalToFrequencyRatio(e)}.bind(this,this._expr,t),this},t.Frequency.prototype.harmonize=function(t){return this._expr=function(t,e){for(var i=t(),n=[],s=0;s<e.length;s++)n[s]=i*this.intervalToFrequencyRatio(e[s]);return n}.bind(this,this._expr,t),this},t.Frequency.prototype.toMidi=function(){return this.frequencyToMidi(this.valueOf())},t.Frequency.prototype.toNote=function(){var e=this.valueOf(),n=Math.log(e/t.Frequency.A4)/Math.LN2,s=Math.round(12*n)+57,o=Math.floor(s/12);return o<0&&(s+=-12*o),i[s%12]+o.toString()},t.Frequency.prototype.toSeconds=function(){return 1/this.valueOf()},t.Frequency.prototype.toFrequency=function(){return this.valueOf()},t.Frequency.prototype.toTicks=function(){var e=this._beatsToUnits(1),i=this.valueOf()/e;return Math.floor(i*t.Transport.PPQ)},t.Frequency.prototype._frequencyToUnits=function(t){return t},t.Frequency.prototype._ticksToUnits=function(e){return 1/(60*e/(t.Transport.bpm.value*t.Transport.PPQ))},t.Frequency.prototype._beatsToUnits=function(e){return 1/t.TimeBase.prototype._beatsToUnits.call(this,e)},t.Frequency.prototype._secondsToUnits=function(t){return 1/t},t.Frequency.prototype._defaultUnits="hz";var e={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},i=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"];return t.Frequency.A4=440,t.Frequency.prototype.midiToFrequency=function(e){return t.Frequency.A4*Math.pow(2,(e-69)/12)},t.Frequency.prototype.frequencyToMidi=function(e){return 69+12*Math.log(e/t.Frequency.A4)/Math.LN2},t.Frequency}),t(function(t){return t.TransportTime=function(e,i){if(!(this instanceof t.TransportTime))return new t.TransportTime(e,i);t.Time.call(this,e,i)},t.extend(t.TransportTime,t.Time),t.TransportTime.prototype._unaryExpressions=Object.create(t.Time.prototype._unaryExpressions),t.TransportTime.prototype._unaryExpressions.quantize={regexp:/^@/,method:function(e){var i=this._secondsToTicks(e()),n=Math.ceil(t.Transport.ticks/i);return this._ticksToUnits(n*i)}},t.TransportTime.prototype._secondsToTicks=function(e){var i=this._beatsToUnits(1),n=e/i;return Math.round(n*t.Transport.PPQ)},t.TransportTime.prototype.valueOf=function(){return this._secondsToTicks(this._expr())+(this._plusNow?t.Transport.ticks:0)},t.TransportTime.prototype.toTicks=function(){return this.valueOf()},t.TransportTime.prototype.toSeconds=function(){return this._expr()+(this._plusNow?t.Transport.seconds:0)},t.TransportTime.prototype.toFrequency=function(){return 1/this.toSeconds()},t.TransportTime}),t(function(t){return t.Emitter=function(){this._events={}},t.extend(t.Emitter),t.Emitter.prototype.on=function(t,e){for(var i=t.split(/\W+/),n=0;n<i.length;n++){var s=i[n];this._events.hasOwnProperty(s)||(this._events[s]=[]),this._events[s].push(e)}return this},t.Emitter.prototype.off=function(e,i){for(var n=e.split(/\W+/),s=0;s<n.length;s++)if(e=n[s],this._events.hasOwnProperty(e))if(t.prototype.isUndef(i))this._events[e]=[];else for(var o=this._events[e],r=0;r<o.length;r++)o[r]===i&&o.splice(r,1);return this},t.Emitter.prototype.emit=function(t){if(this._events){var e=Array.apply(null,arguments).slice(1);if(this._events.hasOwnProperty(t))for(var i=this._events[t],n=0,s=i.length;n<s;n++)i[n].apply(this,e)}return this},t.Emitter.mixin=function(e){var i=["on","off","emit"];e._events={};for(var n=0;n<i.length;n++){var s=i[n],o=t.Emitter.prototype[s];e[s]=o}},t.Emitter.prototype.dispose=function(){return t.prototype.dispose.call(this),this._events=null,this},t.Emitter}),t(function(t){return!window.hasOwnProperty("AudioContext")&&window.hasOwnProperty("webkitAudioContext")&&(window.AudioContext=window.webkitAudioContext),t.Context=function(e){t.Emitter.call(this),e||(e=new window.AudioContext),this._context=e;for(var i in this._context)this._defineProperty(this._context,i);this._latencyHint="interactive",this._lookAhead=.1,this._updateInterval=this._lookAhead/3,this._computedUpdateInterval=0,this._worker=this._createWorker(),this._constants={}},t.extend(t.Context,t.Emitter),t.Emitter.mixin(t.Context),t.Context.prototype._defineProperty=function(t,e){this.isUndef(this[e])&&Object.defineProperty(this,e,{get:function(){return"function"==typeof t[e]?t[e].bind(t):t[e]},set:function(i){t[e]=i}})},t.Context.prototype.now=function(){return this._context.currentTime},t.Context.prototype._createWorker=function(){window.URL=window.URL||window.webkitURL;var t=new Blob(["var timeoutTime = "+(1e3*this._updateInterval).toFixed(1)+";self.onmessage = function(msg){\ttimeoutTime = parseInt(msg.data);};function tick(){\tsetTimeout(tick, timeoutTime);\tself.postMessage('tick');}tick();"]),e=URL.createObjectURL(t),i=new Worker(e);return i.addEventListener("message",function(){this.emit("tick")}.bind(this)),i.addEventListener("message",function(){var t=this.now();if(this.isNumber(this._lastUpdate)){var e=t-this._lastUpdate;this._computedUpdateInterval=Math.max(e,.97*this._computedUpdateInterval)}this._lastUpdate=t}.bind(this)),i},t.Context.prototype.getConstant=function(t){if(this._constants[t])return this._constants[t];for(var e=this._context.createBuffer(1,128,this._context.sampleRate),i=e.getChannelData(0),n=0;n<i.length;n++)i[n]=t;var s=this._context.createBufferSource();return s.channelCount=1,s.channelCountMode="explicit",s.buffer=e,s.loop=!0,s.start(0),this._constants[t]=s,s},Object.defineProperty(t.Context.prototype,"lag",{get:function(){var t=this._computedUpdateInterval-this._updateInterval;return t=Math.max(t,0)}}),Object.defineProperty(t.Context.prototype,"lookAhead",{get:function(){return this._lookAhead},set:function(t){this._lookAhead=t}}),Object.defineProperty(t.Context.prototype,"updateInterval",{get:function(){return this._updateInterval},set:function(e){this._updateInterval=Math.max(e,t.prototype.blockTime),this._worker.postMessage(Math.max(1e3*e,1))}}),Object.defineProperty(t.Context.prototype,"latencyHint",{get:function(){return this._latencyHint},set:function(t){var e=t;if(this._latencyHint=t,this.isString(t))switch(t){case"interactive":e=.1,this._context.latencyHint=t;break;case"playback":e=.8,this._context.latencyHint=t;break;case"balanced":e=.25,this._context.latencyHint=t;break;case"fastest":e=.01}this.lookAhead=e,this.updateInterval=e/3}}),t.supported?(!function(){function e(e,i,s){if(e.input)Array.isArray(e.input)?(t.prototype.isUndef(s)&&(s=0),this.connect(e.input[s])):this.connect(e.input,i,s);else try{e instanceof AudioNode?n.call(this,e,i,s):n.call(this,e,i)}catch(t){throw new Error("error connecting to node: "+e+"\n"+t)}}function i(e,i,n){if(e&&e.input&&Array.isArray(e.input))t.prototype.isUndef(n)&&(n=0),this.disconnect(e.input[n],i,n);else if(e&&e.input)this.disconnect(e.input,i,n);else try{s.apply(this,arguments)}catch(t){throw new Error("error disconnecting node: "+e+"\n"+t)}}var n=AudioNode.prototype.connect,s=AudioNode.prototype.disconnect;AudioNode.prototype.connect!==e&&(AudioNode.prototype.connect=e,AudioNode.prototype.disconnect=i)}(),t.context=new t.Context):console.warn("This browser does not support Tone.js"),t.Context}),t(function(t){return t.Type={Default:"number",Time:"time",Frequency:"frequency",TransportTime:"transportTime",Ticks:"ticks",NormalRange:"normalRange",AudioRange:"audioRange",Decibels:"db",Interval:"interval",BPM:"bpm",Positive:"positive",Cents:"cents",Degrees:"degrees",MIDI:"midi",BarsBeatsSixteenths:"barsBeatsSixteenths",Samples:"samples",Hertz:"hertz",Note:"note",Milliseconds:"milliseconds",Seconds:"seconds",Notation:"notation"},t.prototype.toSeconds=function(e){return this.isNumber(e)?e:this.isUndef(e)?this.now():this.isString(e)?new t.Time(e).toSeconds():e instanceof t.TimeBase?e.toSeconds():void 0},t.prototype.toFrequency=function(e){return this.isNumber(e)?e:this.isString(e)||this.isUndef(e)?new t.Frequency(e).valueOf():e instanceof t.TimeBase?e.toFrequency():void 0},t.prototype.toTicks=function(e){return this.isNumber(e)||this.isString(e)?new t.TransportTime(e).toTicks():this.isUndef(e)?t.Transport.ticks:e instanceof t.TimeBase?e.toTicks():void 0},t}),t(function(t){return t.Param=function(){var e=this.optionsObject(arguments,["param","units","convert"],t.Param.defaults);this._param=this.input=e.param,this.units=e.units,this.convert=e.convert,this.overridden=!1,this._lfo=null,this.isObject(e.lfo)?this.value=e.lfo:this.isUndef(e.value)||(this.value=e.value)},t.extend(t.Param),t.Param.defaults={units:t.Type.Default,convert:!0,param:void 0},Object.defineProperty(t.Param.prototype,"value",{get:function(){return this._toUnits(this._param.value)},set:function(e){if(this.isObject(e)){if(this.isUndef(t.LFO))throw new Error("Include 'Tone.LFO' to use an LFO as a Param value.");this._lfo&&this._lfo.dispose(),this._lfo=new t.LFO(e).start(),this._lfo.connect(this.input)}else{var i=this._fromUnits(e);this._param.cancelScheduledValues(0),this._param.value=i}}}),t.Param.prototype._fromUnits=function(e){if(!this.convert&&!this.isUndef(this.convert))return e;switch(this.units){case t.Type.Time:return this.toSeconds(e);case t.Type.Frequency:return this.toFrequency(e);case t.Type.Decibels:return this.dbToGain(e);case t.Type.NormalRange:return Math.min(Math.max(e,0),1);case t.Type.AudioRange:return Math.min(Math.max(e,-1),1);case t.Type.Positive:return Math.max(e,0);default:return e}},t.Param.prototype._toUnits=function(e){if(!this.convert&&!this.isUndef(this.convert))return e;switch(this.units){case t.Type.Decibels:return this.gainToDb(e);default:return e}},t.Param.prototype._minOutput=1e-5,t.Param.prototype.setValueAtTime=function(t,e){return t=this._fromUnits(t),e=this.toSeconds(e),e<=this.now()+this.blockTime?this._param.value=t:this._param.setValueAtTime(t,e),this},t.Param.prototype.setRampPoint=function(t){t=this.defaultArg(t,this.now());var e=this._param.value;return 0===e&&(e=this._minOutput),this._param.setValueAtTime(e,t),this},t.Param.prototype.linearRampToValueAtTime=function(t,e){return t=this._fromUnits(t),this._param.linearRampToValueAtTime(t,this.toSeconds(e)),this},t.Param.prototype.exponentialRampToValueAtTime=function(t,e){return t=this._fromUnits(t),t=Math.max(this._minOutput,t),this._param.exponentialRampToValueAtTime(t,this.toSeconds(e)),this},t.Param.prototype.exponentialRampToValue=function(t,e,i){return i=this.toSeconds(i),this.setRampPoint(i),this.exponentialRampToValueAtTime(t,i+this.toSeconds(e)),this},t.Param.prototype.linearRampToValue=function(t,e,i){return i=this.toSeconds(i),this.setRampPoint(i),this.linearRampToValueAtTime(t,i+this.toSeconds(e)),this},t.Param.prototype.setTargetAtTime=function(t,e,i){return t=this._fromUnits(t),t=Math.max(this._minOutput,t),i=Math.max(this._minOutput,i),this._param.setTargetAtTime(t,this.toSeconds(e),i),this},t.Param.prototype.setValueCurveAtTime=function(t,e,i){for(var n=0;n<t.length;n++)t[n]=this._fromUnits(t[n]);return this._param.setValueCurveAtTime(t,this.toSeconds(e),this.toSeconds(i)),this},t.Param.prototype.cancelScheduledValues=function(t){return this._param.cancelScheduledValues(this.toSeconds(t)),this},t.Param.prototype.rampTo=function(e,i,n){return i=this.defaultArg(i,0),this.units===t.Type.Frequency||this.units===t.Type.BPM||this.units===t.Type.Decibels?this.exponentialRampToValue(e,i,n):this.linearRampToValue(e,i,n),this},Object.defineProperty(t.Param.prototype,"lfo",{get:function(){return this._lfo}}),t.Param.prototype.dispose=function(){return t.prototype.dispose.call(this),this._param=null,this._lfo&&(this._lfo.dispose(),this._lfo=null),this},t.Param}),t(function(t){return window.GainNode&&!AudioContext.prototype.createGain&&(AudioContext.prototype.createGain=AudioContext.prototype.createGainNode),t.Gain=function(){var e=this.optionsObject(arguments,["gain","units"],t.Gain.defaults);this.input=this.output=this._gainNode=this.context.createGain(),this.gain=new t.Param({param:this._gainNode.gain,units:e.units,value:e.gain,convert:e.convert}),this._readOnly("gain")},t.extend(t.Gain),t.Gain.defaults={gain:1,convert:!0},t.Gain.prototype.dispose=function(){t.Param.prototype.dispose.call(this),this._gainNode.disconnect(),this._gainNode=null,this._writable("gain"),this.gain.dispose(),this.gain=null},t.prototype.createInsOuts=function(e,i){1===e?this.input=new t.Gain:e>1&&(this.input=new Array(e)),1===i?this.output=new t.Gain:i>1&&(this.output=new Array(e))},t.Gain}),t(function(t){return t.Signal=function(){var e=this.optionsObject(arguments,["value","units"],t.Signal.defaults);this.output=this._gain=this.context.createGain(),e.param=this._gain.gain,t.Param.call(this,e),this.input=this._param=this._gain.gain,this.context.getConstant(1).chain(this._gain)},t.extend(t.Signal,t.Param),t.Signal.defaults={value:0,units:t.Type.Default,convert:!0},t.Signal.prototype.connect=t.SignalBase.prototype.connect,t.Signal.prototype.dispose=function(){return t.Param.prototype.dispose.call(this),this._param=null,this._gain.disconnect(),this._gain=null,this},t.Signal}),t(function(t){return t.Timeline=function(){var e=this.optionsObject(arguments,["memory"],t.Timeline.defaults);this._timeline=[],this._toRemove=[],this._iterating=!1,this.memory=e.memory},t.extend(t.Timeline),t.Timeline.defaults={memory:1/0},Object.defineProperty(t.Timeline.prototype,"length",{get:function(){return this._timeline.length}}),t.Timeline.prototype.add=function(t){if(this.isUndef(t.time))throw new Error("Tone.Timeline: events must have a time attribute");if(this._timeline.length){var e=this._search(t.time);this._timeline.splice(e+1,0,t)}else this._timeline.push(t);if(this.length>this.memory){var i=this.length-this.memory;this._timeline.splice(0,i)}return this},t.Timeline.prototype.remove=function(t){if(this._iterating)this._toRemove.push(t);else{var e=this._timeline.indexOf(t);-1!==e&&this._timeline.splice(e,1)}return this},t.Timeline.prototype.get=function(t){var e=this._search(t);return-1!==e?this._timeline[e]:null},t.Timeline.prototype.peek=function(){return this._timeline[0]},t.Timeline.prototype.shift=function(){return this._timeline.shift()},t.Timeline.prototype.getAfter=function(t){var e=this._search(t);return e+1<this._timeline.length?this._timeline[e+1]:null},t.Timeline.prototype.getBefore=function(t){var e=this._timeline.length;if(e>0&&this._timeline[e-1].time<t)return this._timeline[e-1];var i=this._search(t);return i-1>=0?this._timeline[i-1]:null},t.Timeline.prototype.cancel=function(t){if(this._timeline.length>1){var e=this._search(t);if(e>=0)if(this._timeline[e].time===t){for(var i=e;i>=0&&this._timeline[i].time===t;i--)e=i;this._timeline=this._timeline.slice(0,e)}else this._timeline=this._timeline.slice(0,e+1);else this._timeline=[]}else 1===this._timeline.length&&this._timeline[0].time>=t&&(this._timeline=[]);return this},t.Timeline.prototype.cancelBefore=function(t){if(this._timeline.length){var e=this._search(t);e>=0&&(this._timeline=this._timeline.slice(e+1))}return this},t.Timeline.prototype._search=function(t){var e=0,i=this._timeline.length,n=i;if(i>0&&this._timeline[i-1].time<=t)return i-1;for(;e<n;){var s=Math.floor(e+(n-e)/2),o=this._timeline[s],r=this._timeline[s+1];if(o.time===t){for(var a=s;a<this._timeline.length;a++){this._timeline[a].time===t&&(s=a)}return s}if(o.time<t&&r.time>t)return s;o.time>t?n=s:o.time<t&&(e=s+1)}return-1},t.Timeline.prototype._iterate=function(t,e,i){this._iterating=!0,e=this.defaultArg(e,0),i=this.defaultArg(i,this._timeline.length-1);for(var n=e;n<=i;n++)t(this._timeline[n]);if(this._iterating=!1,this._toRemove.length>0){for(var s=0;s<this._toRemove.length;s++){var o=this._timeline.indexOf(this._toRemove[s]);-1!==o&&this._timeline.splice(o,1)}this._toRemove=[]}},t.Timeline.prototype.forEach=function(t){return this._iterate(t),this},t.Timeline.prototype.forEachBefore=function(t,e){var i=this._search(t);return-1!==i&&this._iterate(e,0,i),this},t.Timeline.prototype.forEachAfter=function(t,e){var i=this._search(t);return this._iterate(e,i+1),this},t.Timeline.prototype.forEachFrom=function(t,e){for(var i=this._search(t);i>=0&&this._timeline[i].time>=t;)i--;return this._iterate(e,i+1),this},t.Timeline.prototype.forEachAtTime=function(t,e){var i=this._search(t);return-1!==i&&this._iterate(function(i){i.time===t&&e(i)},0,i),this},t.Timeline.prototype.dispose=function(){t.prototype.dispose.call(this),this._timeline=null,this._toRemove=null},t.Timeline}),t(function(t){return t.TimelineSignal=function(){var e=this.optionsObject(arguments,["value","units"],t.Signal.defaults);this._events=new t.Timeline(10),t.Signal.apply(this,e),e.param=this._param,t.Param.call(this,e),this._initial=this._fromUnits(this._param.value)},t.extend(t.TimelineSignal,t.Param),t.TimelineSignal.Type={Linear:"linear",Exponential:"exponential",Target:"target",Curve:"curve",Set:"set"},Object.defineProperty(t.TimelineSignal.prototype,"value",{get:function(){var t=this.now(),e=this.getValueAtTime(t);return this._toUnits(e)},set:function(t){var e=this._fromUnits(t);this._initial=e,this.cancelScheduledValues(),this._param.value=e}}),t.TimelineSignal.prototype.setValueAtTime=function(e,i){return e=this._fromUnits(e),i=this.toSeconds(i),this._events.add({type:t.TimelineSignal.Type.Set,value:e,time:i}),this._param.setValueAtTime(e,i),this},t.TimelineSignal.prototype.linearRampToValueAtTime=function(e,i){return e=this._fromUnits(e),i=this.toSeconds(i),this._events.add({type:t.TimelineSignal.Type.Linear,value:e,time:i}),this._param.linearRampToValueAtTime(e,i),this},t.TimelineSignal.prototype.exponentialRampToValueAtTime=function(e,i){i=this.toSeconds(i);var n=this._searchBefore(i);n&&0===n.value&&this.setValueAtTime(this._minOutput,n.time),e=this._fromUnits(e);var s=Math.max(e,this._minOutput);return this._events.add({type:t.TimelineSignal.Type.Exponential,value:s,time:i}),e<this._minOutput?(this._param.exponentialRampToValueAtTime(this._minOutput,i-this.sampleTime),this.setValueAtTime(0,i)):this._param.exponentialRampToValueAtTime(e,i),this},t.TimelineSignal.prototype.setTargetAtTime=function(e,i,n){return e=this._fromUnits(e),e=Math.max(this._minOutput,e),n=Math.max(this._minOutput,n),i=this.toSeconds(i),this._events.add({type:t.TimelineSignal.Type.Target,value:e,time:i,constant:n}),this._param.setTargetAtTime(e,i,n),this},t.TimelineSignal.prototype.setValueCurveAtTime=function(e,i,n,s){s=this.defaultArg(s,1);for(var o=new Array(e.length),r=0;r<o.length;r++)o[r]=this._fromUnits(e[r])*s;i=this.toSeconds(i),n=this.toSeconds(n),this._events.add({type:t.TimelineSignal.Type.Curve,value:o,time:i,duration:n}),this._param.setValueAtTime(o[0],i);for(var a=1;a<o.length;a++){var h=i+a/(o.length-1)*n;this._param.linearRampToValueAtTime(o[a],h)}return this},t.TimelineSignal.prototype.cancelScheduledValues=function(t){return t=this.toSeconds(t),this._events.cancel(t),this._param.cancelScheduledValues(t),this},t.TimelineSignal.prototype.setRampPoint=function(e){e=this.toSeconds(e);var i=this._toUnits(this.getValueAtTime(e)),n=this._searchBefore(e);if(n&&n.time===e)this.cancelScheduledValues(e+this.sampleTime);else if(n&&n.type===t.TimelineSignal.Type.Curve&&n.time+n.duration>e)this.cancelScheduledValues(e),this.linearRampToValueAtTime(i,e);else{var s=this._searchAfter(e);s&&(this.cancelScheduledValues(e),s.type===t.TimelineSignal.Type.Linear?this.linearRampToValueAtTime(i,e):s.type===t.TimelineSignal.Type.Exponential&&this.exponentialRampToValueAtTime(i,e)),this.setValueAtTime(i,e)}return this},t.TimelineSignal.prototype.linearRampToValueBetween=function(t,e,i){return this.setRampPoint(e),this.linearRampToValueAtTime(t,i),this},t.TimelineSignal.prototype.exponentialRampToValueBetween=function(t,e,i){return this.setRampPoint(e),this.exponentialRampToValueAtTime(t,i),this},t.TimelineSignal.prototype._searchBefore=function(t){return this._events.get(t)},t.TimelineSignal.prototype._searchAfter=function(t){return this._events.getAfter(t)},t.TimelineSignal.prototype.getValueAtTime=function(e){e=this.toSeconds(e);var i=this._searchAfter(e),n=this._searchBefore(e),s=this._initial;if(null===n)s=this._initial;else if(n.type===t.TimelineSignal.Type.Target){var o,r=this._events.getBefore(n.time);o=null===r?this._initial:r.value,s=this._exponentialApproach(n.time,o,n.value,n.constant,e)}else s=n.type===t.TimelineSignal.Type.Curve?this._curveInterpolate(n.time,n.value,n.duration,e):null===i?n.value:i.type===t.TimelineSignal.Type.Linear?this._linearInterpolate(n.time,n.value,i.time,i.value,e):i.type===t.TimelineSignal.Type.Exponential?this._exponentialInterpolate(n.time,n.value,i.time,i.value,e):n.value;return s},t.TimelineSignal.prototype.connect=t.SignalBase.prototype.connect,t.TimelineSignal.prototype._exponentialApproach=function(t,e,i,n,s){return i+(e-i)*Math.exp(-(s-t)/n)},t.TimelineSignal.prototype._linearInterpolate=function(t,e,i,n,s){return e+(s-t)/(i-t)*(n-e)},t.TimelineSignal.prototype._exponentialInterpolate=function(t,e,i,n,s){return(e=Math.max(this._minOutput,e))*Math.pow(n/e,(s-t)/(i-t))},t.TimelineSignal.prototype._curveInterpolate=function(t,e,i,n){var s=e.length;if(n>=t+i)return e[s-1];if(n<=t)return e[0];var o=(n-t)/i,r=Math.floor((s-1)*o),a=Math.ceil((s-1)*o),h=e[r],l=e[a];return a===r?h:this._linearInterpolate(r,h,a,l,o*(s-1))},t.TimelineSignal.prototype.dispose=function(){t.Signal.prototype.dispose.call(this),t.Param.prototype.dispose.call(this),this._events.dispose(),this._events=null},t.TimelineSignal}),t(function(t){return t.Pow=function(e){this._exp=this.defaultArg(e,1),this._expScaler=this.input=this.output=new t.WaveShaper(this._expFunc(this._exp),8192)},t.extend(t.Pow,t.SignalBase),Object.defineProperty(t.Pow.prototype,"value",{get:function(){return this._exp},set:function(t){this._exp=t,this._expScaler.setMap(this._expFunc(this._exp))}}),t.Pow.prototype._expFunc=function(t){return function(e){return Math.pow(Math.abs(e),t)}},t.Pow.prototype.dispose=function(){return t.prototype.dispose.call(this),this._expScaler.dispose(),this._expScaler=null,this},t.Pow}),t(function(t){return t.Envelope=function(){var e=this.optionsObject(arguments,["attack","decay","sustain","release"],t.Envelope.defaults);this.attack=e.attack,this.decay=e.decay,this.sustain=e.sustain,this.release=e.release,this._attackCurve="linear",this._releaseCurve="exponential",this._sig=this.output=new t.TimelineSignal,this._sig.setValueAtTime(0,0),this.attackCurve=e.attackCurve,this.releaseCurve=e.releaseCurve},t.extend(t.Envelope),t.Envelope.defaults={attack:.01,decay:.1,sustain:.5,release:1,attackCurve:"linear",releaseCurve:"exponential"},Object.defineProperty(t.Envelope.prototype,"value",{get:function(){return this.getValueAtTime(this.now())}}),Object.defineProperty(t.Envelope.prototype,"attackCurve",{get:function(){if(this.isString(this._attackCurve))return this._attackCurve;if(this.isArray(this._attackCurve)){for(var e in t.Envelope.Type)if(t.Envelope.Type[e].In===this._attackCurve)return e;return this._attackCurve}},set:function(e){if(t.Envelope.Type.hasOwnProperty(e)){var i=t.Envelope.Type[e];this.isObject(i)?this._attackCurve=i.In:this._attackCurve=i}else{if(!this.isArray(e))throw new Error("Tone.Envelope: invalid curve: "+e);this._attackCurve=e}}}),Object.defineProperty(t.Envelope.prototype,"releaseCurve",{get:function(){if(this.isString(this._releaseCurve))return this._releaseCurve;if(this.isArray(this._releaseCurve)){for(var e in t.Envelope.Type)if(t.Envelope.Type[e].Out===this._releaseCurve)return e;return this._releaseCurve}},set:function(e){if(t.Envelope.Type.hasOwnProperty(e)){var i=t.Envelope.Type[e];this.isObject(i)?this._releaseCurve=i.Out:this._releaseCurve=i}else{if(!this.isArray(e))throw new Error("Tone.Envelope: invalid curve: "+e);this._releaseCurve=e}}}),t.Envelope.prototype.triggerAttack=function(t,e){t=this.toSeconds(t);var i=this.toSeconds(this.attack),n=i,s=this.toSeconds(this.decay);e=this.defaultArg(e,1);var o=this.getValueAtTime(t);if(o>0){n=(1-o)/(1/n)}if("linear"===this._attackCurve)this._sig.linearRampToValue(e,n,t);else if("exponential"===this._attackCurve)this._sig.exponentialRampToValue(e,n,t);else if(n>0){this._sig.setRampPoint(t);var r=this._attackCurve;if(n<i){var a=1-n/i,h=Math.floor(a*this._attackCurve.length);r=this._attackCurve.slice(h),r[0]=o}this._sig.setValueCurveAtTime(r,t,n,e)}return this._sig.exponentialRampToValue(e*this.sustain,s,n+t),this},t.Envelope.prototype.triggerRelease=function(t){t=this.toSeconds(t);var e=this.getValueAtTime(t);if(e>0){var i=this.toSeconds(this.release);if("linear"===this._releaseCurve)this._sig.linearRampToValue(0,i,t);else if("exponential"===this._releaseCurve)this._sig.exponentialRampToValue(0,i,t);else{var n=this._releaseCurve;this.isArray(n)&&(this._sig.setRampPoint(t),this._sig.setValueCurveAtTime(n,t,i,e))}}return this},t.Envelope.prototype.getValueAtTime=function(t){return this._sig.getValueAtTime(t)},t.Envelope.prototype.triggerAttackRelease=function(t,e,i){return e=this.toSeconds(e),this.triggerAttack(e,i),this.triggerRelease(e+this.toSeconds(t)),this},t.Envelope.prototype.cancel=function(t){return this._sig.cancelScheduledValues(t),this},t.Envelope.prototype.connect=t.Signal.prototype.connect,function(){function e(t){for(var e=new Array(t.length),i=0;i<t.length;i++)e[i]=1-t[i];return e}var i,n,s=[];for(i=0;i<128;i++)s[i]=Math.sin(i/127*(Math.PI/2));var o=[];for(i=0;i<127;i++){n=i/127;var r=Math.sin(n*(2*Math.PI)*6.4-Math.PI/2)+1;o[i]=r/10+.83*n}o[127]=1;var a=[];for(i=0;i<128;i++)a[i]=Math.ceil(i/127*5)/5;var h=[];for(i=0;i<128;i++)n=i/127,h[i]=.5*(1-Math.cos(Math.PI*n));var l=[];for(i=0;i<128;i++){n=i/127;var u=4*Math.pow(n,3)+.2,p=Math.cos(u*Math.PI*2*n);l[i]=Math.abs(p*(1-n))}t.Envelope.Type={linear:"linear",exponential:"exponential",bounce:{In:e(l),Out:l},cosine:{In:s,Out:function(t){return t.slice(0).reverse()}(s)},step:{In:a,Out:e(a)},ripple:{In:o,Out:e(o)},sine:{In:h,Out:e(h)}}}(),t.Envelope.prototype.dispose=function(){return t.prototype.dispose.call(this),this._sig.dispose(),this._sig=null,this._attackCurve=null,this._releaseCurve=null,this},t.Envelope}),t(function(t){return t.AmplitudeEnvelope=function(){t.Envelope.apply(this,arguments),this.input=this.output=new t.Gain,this._sig.connect(this.output.gain)},t.extend(t.AmplitudeEnvelope,t.Envelope),t.AmplitudeEnvelope.prototype.dispose=function(){return this.input.dispose(),this.input=null,t.Envelope.prototype.dispose.call(this),this},t.AmplitudeEnvelope}),t(function(t){return window.AnalyserNode&&!AnalyserNode.prototype.getFloatTimeDomainData&&(AnalyserNode.prototype.getFloatTimeDomainData=function(t){var e=new Uint8Array(t.length);this.getByteTimeDomainData(e);for(var i=0;i<e.length;i++)t[i]=(e[i]-128)/128}),t.Analyser=function(){var e=this.optionsObject(arguments,["type","size"],t.Analyser.defaults);this._analyser=this.input=this.output=this.context.createAnalyser(),this._type=e.type,this._returnType=e.returnType,this._buffer=null,this.size=e.size,this.type=e.type,this.returnType=e.returnType,this.minDecibels=e.minDecibels,this.maxDecibels=e.maxDecibels},t.extend(t.Analyser),t.Analyser.defaults={size:1024,returnType:"byte",type:"fft",smoothing:.8,maxDecibels:-30,minDecibels:-100},t.Analyser.Type={Waveform:"waveform",FFT:"fft"},t.Analyser.ReturnType={Byte:"byte",Float:"float"},t.Analyser.prototype.analyse=function(){return this._type===t.Analyser.Type.FFT?this._returnType===t.Analyser.ReturnType.Byte?this._analyser.getByteFrequencyData(this._buffer):this._analyser.getFloatFrequencyData(this._buffer):this._type===t.Analyser.Type.Waveform&&(this._returnType===t.Analyser.ReturnType.Byte?this._analyser.getByteTimeDomainData(this._buffer):this._analyser.getFloatTimeDomainData(this._buffer)),this._buffer},Object.defineProperty(t.Analyser.prototype,"size",{get:function(){return this._analyser.frequencyBinCount},set:function(t){this._analyser.fftSize=2*t,this.type=this._type}}),Object.defineProperty(t.Analyser.prototype,"returnType",{get:function(){return this._returnType},set:function(e){if(e===t.Analyser.ReturnType.Byte)this._buffer=new Uint8Array(this._analyser.frequencyBinCount);else{if(e!==t.Analyser.ReturnType.Float)throw new TypeError("Tone.Analayser: invalid return type: "+e);this._buffer=new Float32Array(this._analyser.frequencyBinCount)}this._returnType=e}}),Object.defineProperty(t.Analyser.prototype,"type",{get:function(){return this._type},set:function(e){if(e!==t.Analyser.Type.Waveform&&e!==t.Analyser.Type.FFT)throw new TypeError("Tone.Analyser: invalid type: "+e);this._type=e}}),Object.defineProperty(t.Analyser.prototype,"smoothing",{get:function(){return this._analyser.smoothingTimeConstant},set:function(t){this._analyser.smoothingTimeConstant=t}}),Object.defineProperty(t.Analyser.prototype,"minDecibels",{get:function(){return this._analyser.minDecibels},set:function(t){this._analyser.minDecibels=t}}),Object.defineProperty(t.Analyser.prototype,"maxDecibels",{get:function(){return this._analyser.maxDecibels},set:function(t){this._analyser.maxDecibels=t}}),t.Analyser.prototype.dispose=function(){t.prototype.dispose.call(this),this._analyser.disconnect(),this._analyser=null,this._buffer=null},t.Analyser}),t(function(t){return t.Compressor=function(){var e=this.optionsObject(arguments,["threshold","ratio"],t.Compressor.defaults);this._compressor=this.input=this.output=this.context.createDynamicsCompressor(),this.threshold=new t.Param({param:this._compressor.threshold,units:t.Type.Decibels,convert:!1}),this.attack=new t.Param(this._compressor.attack,t.Type.Time),this.release=new t.Param(this._compressor.release,t.Type.Time),this.knee=new t.Param({param:this._compressor.knee,units:t.Type.Decibels,convert:!1}),this.ratio=new t.Param({param:this._compressor.ratio,convert:!1}),this._readOnly(["knee","release","attack","ratio","threshold"]),this.set(e)},t.extend(t.Compressor),t.Compressor.defaults={ratio:12,threshold:-24,release:.25,attack:.003,knee:30},t.Compressor.prototype.dispose=function(){return t.prototype.dispose.call(this),this._writable(["knee","release","attack","ratio","threshold"]),this._compressor.disconnect(),this._compressor=null,this.attack.dispose(),this.attack=null,this.release.dispose(),this.release=null,this.threshold.dispose(),this.threshold=null,this.ratio.dispose(),this.ratio=null,this.knee.dispose(),this.knee=null,this},t.Compressor}),t(function(t){return t.Add=function(e){this.createInsOuts(2,0),this._sum=this.input[0]=this.input[1]=this.output=new t.Gain,this._param=this.input[1]=new t.Signal(e),this._param.connect(this._sum)},t.extend(t.Add,t.Signal),t.Add.prototype.dispose=function(){return t.prototype.dispose.call(this),this._sum.dispose(),this._sum=null,this._param.dispose(),this._param=null,this},t.Add}),t(function(t){return t.Multiply=function(e){this.createInsOuts(2,0),this._mult=this.input[0]=this.output=new t.Gain,this._param=this.input[1]=this.output.gain,this._param.value=this.defaultArg(e,0)},t.extend(t.Multiply,t.Signal),t.Multiply.prototype.dispose=function(){return t.prototype.dispose.call(this),this._mult.dispose(),this._mult=null,this._param=null,this},t.Multiply}),t(function(t){return t.Negate=function(){this._multiply=this.input=this.output=new t.Multiply(-1)},t.extend(t.Negate,t.SignalBase),t.Negate.prototype.dispose=function(){return t.prototype.dispose.call(this),this._multiply.dispose(),this._multiply=null,this},t.Negate}),t(function(t){return t.Subtract=function(e){this.createInsOuts(2,0),this._sum=this.input[0]=this.output=new t.Gain,this._neg=new t.Negate,this._param=this.input[1]=new t.Signal(e),this._param.chain(this._neg,this._sum)},t.extend(t.Subtract,t.Signal),t.Subtract.prototype.dispose=function(){return t.prototype.dispose.call(this),this._neg.dispose(),this._neg=null,this._sum.disconnect(),this._sum=null,this._param.dispose(),this._param=null,this},t.Subtract}),t(function(t){return t.GreaterThanZero=function(){this._thresh=this.output=new t.WaveShaper(function(t){return t<=0?0:1},127),this._scale=this.input=new t.Multiply(1e4),this._scale.connect(this._thresh)},t.extend(t.GreaterThanZero,t.SignalBase),t.GreaterThanZero.prototype.dispose=function(){return t.prototype.dispose.call(this),this._scale.dispose(),this._scale=null,this._thresh.dispose(),this._thresh=null,this},t.GreaterThanZero}),t(function(t){return t.GreaterThan=function(e){this.createInsOuts(2,0),this._param=this.input[0]=new t.Subtract(e),this.input[1]=this._param.input[1],this._gtz=this.output=new t.GreaterThanZero,this._param.connect(this._gtz)},t.extend(t.GreaterThan,t.Signal),t.GreaterThan.prototype.dispose=function(){return t.prototype.dispose.call(this),this._param.dispose(),this._param=null,this._gtz.dispose(),this._gtz=null,this},t.GreaterThan}),t(function(t){return t.Abs=function(){this._abs=this.input=this.output=new t.WaveShaper(function(t){return 0===t?0:Math.abs(t)},127)},t.extend(t.Abs,t.SignalBase),t.Abs.prototype.dispose=function(){return t.prototype.dispose.call(this),this._abs.dispose(),this._abs=null,this},t.Abs}),t(function(t){return t.Modulo=function(e){this.createInsOuts(1,0),this._shaper=new t.WaveShaper(Math.pow(2,16)),this._multiply=new t.Multiply,this._subtract=this.output=new t.Subtract,this._modSignal=new t.Signal(e),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(e)},t.extend(t.Modulo,t.SignalBase),t.Modulo.prototype._setWaveShaper=function(t){this._shaper.setMap(function(e){return Math.floor((e+1e-4)/t)})},Object.defineProperty(t.Modulo.prototype,"value",{get:function(){return this._modSignal.value},set:function(t){this._modSignal.value=t,this._setWaveShaper(t)}}),t.Modulo.prototype.dispose=function(){return t.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,this},t.Modulo}),t(function(t){return t.AudioToGain=function(){this._norm=this.input=this.output=new t.WaveShaper(function(t){return(t+1)/2})},t.extend(t.AudioToGain,t.SignalBase),t.AudioToGain.prototype.dispose=function(){return t.prototype.dispose.call(this),this._norm.dispose(),this._norm=null,this},t.AudioToGain}),t(function(t){function e(t,e,i){var n=new t;return i._eval(e[0]).connect(n,0,0),i._eval(e[1]).connect(n,0,1),n}function i(t,e,i){var n=new t;return i._eval(e[0]).connect(n,0,0),n}function n(t){return t?parseFloat(t):void 0}function s(t){return t&&t.args?parseFloat(t.args):void 0}return t.Expr=function(){var t=this._replacements(Array.prototype.slice.call(arguments)),e=this._parseInputs(t);this._nodes=[],this.input=new Array(e);for(var i=0;i<e;i++)this.input[i]=this.context.createGain();var n,s=this._parseTree(t);try{n=this._eval(s)}catch(e){throw this._disposeNodes(),new Error("Tone.Expr: Could evaluate expression: "+t)}this.output=n},t.extend(t.Expr,t.SignalBase),t.Expr._Expressions={value:{signal:{regexp:/^\d+\.\d+|^\d+/,method:function(e){return new t.Signal(n(e))}},input:{regexp:/^\$\d/,method:function(t,e){return e.input[n(t.substr(1))]}}},glue:{"(":{regexp:/^\(/},")":{regexp:/^\)/},",":{regexp:/^,/}},func:{abs:{regexp:/^abs/,method:i.bind(this,t.Abs)},mod:{regexp:/^mod/,method:function(e,i){var n=s(e[1]),o=new t.Modulo(n);return i._eval(e[0]).connect(o),o}},pow:{regexp:/^pow/,method:function(e,i){var n=s(e[1]),o=new t.Pow(n);return i._eval(e[0]).connect(o),o}},a2g:{regexp:/^a2g/,method:function(e,i){var n=new t.AudioToGain;return i._eval(e[0]).connect(n),n}}},binary:{"+":{regexp:/^\+/,precedence:1,method:e.bind(this,t.Add)},"-":{regexp:/^\-/,precedence:1,method:function(n,s){return 1===n.length?i(t.Negate,n,s):e(t.Subtract,n,s)}},"*":{regexp:/^\*/,precedence:0,method:e.bind(this,t.Multiply)}},unary:{"-":{regexp:/^\-/,method:i.bind(this,t.Negate)},"!":{regexp:/^\!/,method:i.bind(this,t.NOT)}}},t.Expr.prototype._parseInputs=function(t){var e=t.match(/\$\d/g),i=0;if(null!==e)for(var n=0;n<e.length;n++){var s=parseInt(e[n].substr(1))+1;i=Math.max(i,s)}return i},t.Expr.prototype._replacements=function(t){for(var e=t.shift(),i=0;i<t.length;i++)e=e.replace(/\%/i,t[i]);return e},t.Expr.prototype._tokenize=function(e){for(var i=-1,n=[];e.length>0;){e=e.trim();var s=function(e){for(var i in t.Expr._Expressions){var n=t.Expr._Expressions[i];for(var s in n){var o=n[s],r=o.regexp,a=e.match(r);if(null!==a)return{type:i,value:a[0],method:o.method}}}throw new SyntaxError("Tone.Expr: Unexpected token "+e)}(e);n.push(s),e=e.substr(s.value.length)}return{next:function(){return n[++i]},peek:function(){return n[i+1]}}},t.Expr.prototype._parseTree=function(e){function i(t,e){return!u(t)&&"glue"===t.type&&t.value===e}function n(e,i,n){var s=t.Expr._Expressions[i];if(!u(e))for(var o in s){var r=s[o];if(r.regexp.test(e.value)){if(u(n))return!0;if(r.precedence===n)return!0}}return!1}function s(t){u(t)&&(t=5);var e;e=t<0?o():s(t-1);for(var i=l.peek();n(i,"binary",t);)i=l.next(),e={operator:i.value,method:i.method,args:[e,s(t-1)]},i=l.peek();return e}function o(){var t,e;return t=l.peek(),n(t,"unary")?(t=l.next(),e=o(),{operator:t.value,method:t.method,args:[e]}):r()}function r(){var t,e;if(t=l.peek(),u(t))throw new SyntaxError("Tone.Expr: Unexpected termination of expression");if("func"===t.type)return t=l.next(),a(t);if("value"===t.type)return t=l.next(),{method:t.method,args:t.value};if(i(t,"(")){if(l.next(),e=s(),t=l.next(),!i(t,")"))throw new SyntaxError("Expected )");return e}throw new SyntaxError("Tone.Expr: Parse error, cannot process token "+t.value)}function a(t){var e,n=[];if(e=l.next(),!i(e,"("))throw new SyntaxError('Tone.Expr: Expected ( in a function call "'+t.value+'"');if(e=l.peek(),i(e,")")||(n=h()),e=l.next(),!i(e,")"))throw new SyntaxError('Tone.Expr: Expected ) in a function call "'+t.value+'"');return{method:t.method,args:n,name:name}}function h(){for(var t,e,n=[];;){if(e=s(),u(e))break;if(n.push(e),t=l.peek(),!i(t,","))break;l.next()}return n}var l=this._tokenize(e),u=this.isUndef.bind(this);return s()},t.Expr.prototype._eval=function(t){if(!this.isUndef(t)){var e=t.method(t.args,this);return this._nodes.push(e),e}},t.Expr.prototype._disposeNodes=function(){for(var t=0;t<this._nodes.length;t++){var e=this._nodes[t];this.isFunction(e.dispose)?e.dispose():this.isFunction(e.disconnect)&&e.disconnect(),e=null,this._nodes[t]=null}this._nodes=null},t.Expr.prototype.dispose=function(){t.prototype.dispose.call(this),this._disposeNodes()},t.Expr}),t(function(t){return t.EqualPowerGain=function(){this._eqPower=this.input=this.output=new t.WaveShaper(function(t){return Math.abs(t)<.001?0:this.equalPowerScale(t)}.bind(this),4096)},t.extend(t.EqualPowerGain,t.SignalBase),t.EqualPowerGain.prototype.dispose=function(){return t.prototype.dispose.call(this),this._eqPower.dispose(),this._eqPower=null,this},t.EqualPowerGain}),t(function(t){return t.CrossFade=function(e){this.createInsOuts(2,1),this.a=this.input[0]=new t.Gain,this.b=this.input[1]=new t.Gain,this.fade=new t.Signal(this.defaultArg(e,.5),t.Type.NormalRange),this._equalPowerA=new t.EqualPowerGain,this._equalPowerB=new t.EqualPowerGain,this._invert=new t.Expr("1 - $0"),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")},t.extend(t.CrossFade),t.CrossFade.prototype.dispose=function(){return t.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,this},t.CrossFade}),t(function(t){return t.Filter=function(){this.createInsOuts(1,1);var e=this.optionsObject(arguments,["frequency","type","rolloff"],t.Filter.defaults);this._filters=[],this.frequency=new t.Signal(e.frequency,t.Type.Frequency),this.detune=new t.Signal(0,t.Type.Cents),this.gain=new t.Signal({value:e.gain,convert:!1}),this.Q=new t.Signal(e.Q),this._type=e.type,this._rolloff=e.rolloff,this.rolloff=e.rolloff,this._readOnly(["detune","frequency","gain","Q"])},t.extend(t.Filter),t.Filter.defaults={type:"lowpass",frequency:350,rolloff:-12,Q:1,gain:0},Object.defineProperty(t.Filter.prototype,"type",{get:function(){return this._type},set:function(t){if(-1===["lowpass","highpass","bandpass","lowshelf","highshelf","notch","allpass","peaking"].indexOf(t))throw new TypeError("Tone.Filter: invalid type "+t);this._type=t;for(var e=0;e<this._filters.length;e++)this._filters[e].type=t}}),Object.defineProperty(t.Filter.prototype,"rolloff",{get:function(){return this._rolloff},set:function(t){t=parseInt(t,10);var e=[-12,-24,-48,-96],i=e.indexOf(t);if(-1===i)throw new RangeError("Tone.Filter: rolloff can only be -12, -24, -48 or -96");i+=1,this._rolloff=t,this.input.disconnect();for(var n=0;n<this._filters.length;n++)this._filters[n].disconnect(),this._filters[n]=null;this._filters=new Array(i);for(var s=0;s<i;s++){var o=this.context.createBiquadFilter();o.type=this._type,this.frequency.connect(o.frequency),this.detune.connect(o.detune),this.Q.connect(o.Q),this.gain.connect(o.gain),this._filters[s]=o}var r=[this.input].concat(this._filters).concat([this.output]);this.connectSeries.apply(this,r)}}),t.Filter.prototype.dispose=function(){t.prototype.dispose.call(this);for(var e=0;e<this._filters.length;e++)this._filters[e].disconnect(),this._filters[e]=null;return 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,this},t.Filter}),t(function(t){return t.MultibandSplit=function(){var e=this.optionsObject(arguments,["lowFrequency","highFrequency"],t.MultibandSplit.defaults);this.input=new t.Gain,this.output=new Array(3),this.low=this.output[0]=new t.Filter(0,"lowpass"),this._lowMidFilter=new t.Filter(0,"highpass"),this.mid=this.output[1]=new t.Filter(0,"lowpass"),this.high=this.output[2]=new t.Filter(0,"highpass"),this.lowFrequency=new t.Signal(e.lowFrequency,t.Type.Frequency),this.highFrequency=new t.Signal(e.highFrequency,t.Type.Frequency),this.Q=new t.Signal(e.Q),this.input.fan(this.low,this.high),this.input.chain(this._lowMidFilter,this.mid),this.lowFrequency.connect(this.low.frequency),this.lowFrequency.connect(this._lowMidFilter.frequency),this.highFrequency.connect(this.mid.frequency),this.highFrequency.connect(this.high.frequency),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"])},t.extend(t.MultibandSplit),t.MultibandSplit.defaults={lowFrequency:400,highFrequency:2500,Q:1},t.MultibandSplit.prototype.dispose=function(){return t.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,this},t.MultibandSplit}),t(function(t){return t.EQ3=function(){var e=this.optionsObject(arguments,["low","mid","high"],t.EQ3.defaults);this.output=new t.Gain,this._multibandSplit=this.input=new t.MultibandSplit({lowFrequency:e.lowFrequency,highFrequency:e.highFrequency}),this._lowGain=new t.Gain(e.low,t.Type.Decibels),this._midGain=new t.Gain(e.mid,t.Type.Decibels),this._highGain=new t.Gain(e.high,t.Type.Decibels),this.low=this._lowGain.gain,this.mid=this._midGain.gain,this.high=this._highGain.gain,this.Q=this._multibandSplit.Q,this.lowFrequency=this._multibandSplit.lowFrequency,this.highFrequency=this._multibandSplit.highFrequency,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"])},t.extend(t.EQ3),t.EQ3.defaults={low:0,mid:0,high:0,lowFrequency:400,highFrequency:2500},t.EQ3.prototype.dispose=function(){return t.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,this},t.EQ3}),t(function(t){return t.Scale=function(e,i){this._outputMin=this.defaultArg(e,0),this._outputMax=this.defaultArg(i,1),this._scale=this.input=new t.Multiply(1),this._add=this.output=new t.Add(0),this._scale.connect(this._add),this._setRange()},t.extend(t.Scale,t.SignalBase),Object.defineProperty(t.Scale.prototype,"min",{get:function(){return this._outputMin},set:function(t){this._outputMin=t,this._setRange()}}),Object.defineProperty(t.Scale.prototype,"max",{get:function(){return this._outputMax},set:function(t){this._outputMax=t,this._setRange()}}),t.Scale.prototype._setRange=function(){this._add.value=this._outputMin,this._scale.value=this._outputMax-this._outputMin},t.Scale.prototype.dispose=function(){return t.prototype.dispose.call(this),this._add.dispose(),this._add=null,this._scale.dispose(),this._scale=null,this},t.Scale}),t(function(t){return t.ScaleExp=function(e,i,n){this._scale=this.output=new t.Scale(e,i),this._exp=this.input=new t.Pow(this.defaultArg(n,2)),this._exp.connect(this._scale)},t.extend(t.ScaleExp,t.SignalBase),Object.defineProperty(t.ScaleExp.prototype,"exponent",{get:function(){return this._exp.value},set:function(t){this._exp.value=t}}),Object.defineProperty(t.ScaleExp.prototype,"min",{get:function(){return this._scale.min},set:function(t){this._scale.min=t}}),Object.defineProperty(t.ScaleExp.prototype,"max",{get:function(){return this._scale.max},set:function(t){this._scale.max=t}}),t.ScaleExp.prototype.dispose=function(){return t.prototype.dispose.call(this),this._scale.dispose(),this._scale=null,this._exp.dispose(),this._exp=null,this},t.ScaleExp}),t(function(t){return window.DelayNode&&!AudioContext.prototype.createDelay&&(AudioContext.prototype.createDelay=AudioContext.prototype.createDelayNode),t.Delay=function(){var e=this.optionsObject(arguments,["delayTime","maxDelay"],t.Delay.defaults);this._delayNode=this.input=this.output=this.context.createDelay(this.toSeconds(e.maxDelay)),this.delayTime=new t.Param({param:this._delayNode.delayTime,units:t.Type.Time,value:e.delayTime}),this._readOnly("delayTime")},t.extend(t.Delay),t.Delay.defaults={maxDelay:1,delayTime:0},t.Delay.prototype.dispose=function(){return t.Param.prototype.dispose.call(this),this._delayNode.disconnect(),this._delayNode=null,this._writable("delayTime"),this.delayTime=null,this},t.Delay}),t(function(t){return t.FeedbackCombFilter=function(){var e=this.optionsObject(arguments,["delayTime","resonance"],t.FeedbackCombFilter.defaults);this._delay=this.input=this.output=new t.Delay(e.delayTime),this.delayTime=this._delay.delayTime,this._feedback=new t.Gain(e.resonance,t.Type.NormalRange),this.resonance=this._feedback.gain,this._delay.chain(this._feedback,this._delay),this._readOnly(["resonance","delayTime"])},t.extend(t.FeedbackCombFilter),t.FeedbackCombFilter.defaults={delayTime:.1,resonance:.5},t.FeedbackCombFilter.prototype.dispose=function(){return t.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,this},t.FeedbackCombFilter}),t(function(t){return t.Follower=function(){this.createInsOuts(1,1);var e=this.optionsObject(arguments,["attack","release"],t.Follower.defaults);this._abs=new t.Abs,this._filter=this.context.createBiquadFilter(),this._filter.type="lowpass",this._filter.frequency.value=0,this._filter.Q.value=-100,this._frequencyValues=new t.WaveShaper,this._sub=new t.Subtract,this._delay=new t.Delay(this.blockTime),this._mult=new t.Multiply(1e4),this._attack=e.attack,this._release=e.release,this.input.chain(this._abs,this._filter,this.output),this._abs.connect(this._sub,0,1),this._filter.chain(this._delay,this._sub),this._sub.chain(this._mult,this._frequencyValues,this._filter.frequency),this._setAttackRelease(this._attack,this._release)},t.extend(t.Follower),t.Follower.defaults={attack:.05,release:.5},t.Follower.prototype._setAttackRelease=function(e,i){var n=this.blockTime;e=t.Time(e).toFrequency(),i=t.Time(i).toFrequency(),e=Math.max(e,n),i=Math.max(i,n),this._frequencyValues.setMap(function(t){return t<=0?e:i})},Object.defineProperty(t.Follower.prototype,"attack",{get:function(){return this._attack},set:function(t){this._attack=t,this._setAttackRelease(this._attack,this._release)}}),Object.defineProperty(t.Follower.prototype,"release",{get:function(){return this._release},set:function(t){this._release=t,this._setAttackRelease(this._attack,this._release)}}),t.Follower.prototype.connect=t.Signal.prototype.connect,t.Follower.prototype.dispose=function(){return t.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,this},t.Follower}),t(function(t){return t.ScaledEnvelope=function(){var e=this.optionsObject(arguments,["attack","decay","sustain","release"],t.Envelope.defaults);t.Envelope.call(this,e),e=this.defaultArg(e,t.ScaledEnvelope.defaults),this._exp=this.output=new t.Pow(e.exponent),this._scale=this.output=new t.Scale(e.min,e.max),this._sig.chain(this._exp,this._scale)},t.extend(t.ScaledEnvelope,t.Envelope),t.ScaledEnvelope.defaults={min:0,max:1,exponent:1},Object.defineProperty(t.ScaledEnvelope.prototype,"min",{get:function(){return this._scale.min},set:function(t){this._scale.min=t}}),Object.defineProperty(t.ScaledEnvelope.prototype,"max",{get:function(){return this._scale.max},set:function(t){this._scale.max=t}}),Object.defineProperty(t.ScaledEnvelope.prototype,"exponent",{get:function(){return this._exp.value},set:function(t){this._exp.value=t}}),t.ScaledEnvelope.prototype.dispose=function(){return t.Envelope.prototype.dispose.call(this),this._scale.dispose(),this._scale=null,this._exp.dispose(),this._exp=null,this},t.ScaledEnvelope}),t(function(t){return t.FrequencyEnvelope=function(){var e=this.optionsObject(arguments,["attack","decay","sustain","release"],t.Envelope.defaults);t.ScaledEnvelope.call(this,e),e=this.defaultArg(e,t.FrequencyEnvelope.defaults),this._octaves=e.octaves,this.baseFrequency=e.baseFrequency,this.octaves=e.octaves},t.extend(t.FrequencyEnvelope,t.Envelope),t.FrequencyEnvelope.defaults={baseFrequency:200,octaves:4,exponent:2},Object.defineProperty(t.FrequencyEnvelope.prototype,"baseFrequency",{get:function(){return this._scale.min},set:function(t){this._scale.min=this.toFrequency(t),this.octaves=this._octaves}}),Object.defineProperty(t.FrequencyEnvelope.prototype,"octaves",{get:function(){return this._octaves},set:function(t){this._octaves=t,this._scale.max=this.baseFrequency*Math.pow(2,t)}}),Object.defineProperty(t.FrequencyEnvelope.prototype,"exponent",{get:function(){return this._exp.value},set:function(t){this._exp.value=t}}),t.FrequencyEnvelope.prototype.dispose=function(){return t.ScaledEnvelope.prototype.dispose.call(this),this},t.FrequencyEnvelope}),t(function(t){return t.Gate=function(){this.createInsOuts(1,1);var e=this.optionsObject(arguments,["threshold","attack","release"],t.Gate.defaults);this._follower=new t.Follower(e.attack,e.release),this._gt=new t.GreaterThan(this.dbToGain(e.threshold)),this.input.connect(this.output),this.input.chain(this._gt,this._follower,this.output.gain)},t.extend(t.Gate),t.Gate.defaults={attack:.1,release:.1,threshold:-40},Object.defineProperty(t.Gate.prototype,"threshold",{get:function(){return this.gainToDb(this._gt.value)},set:function(t){this._gt.value=this.dbToGain(t)}}),Object.defineProperty(t.Gate.prototype,"attack",{get:function(){return this._follower.attack},set:function(t){this._follower.attack=t}}),Object.defineProperty(t.Gate.prototype,"release",{get:function(){return this._follower.release},set:function(t){this._follower.release=t}}),t.Gate.prototype.dispose=function(){return t.prototype.dispose.call(this),this._follower.dispose(),this._gt.dispose(),this._follower=null,this._gt=null,this},t.Gate}),t(function(t){return t.TimelineState=function(e){t.Timeline.call(this),this._initial=e},t.extend(t.TimelineState,t.Timeline),t.TimelineState.prototype.getValueAtTime=function(t){var e=this.get(t);return null!==e?e.state:this._initial},t.TimelineState.prototype.setStateAtTime=function(t,e){this.add({state:t,time:e})},t.TimelineState}),t(function(t){return t.Clock=function(){t.Emitter.call(this);var e=this.optionsObject(arguments,["callback","frequency"],t.Clock.defaults);this.callback=e.callback,this._nextTick=0,this._lastState=t.State.Stopped,this.frequency=new t.TimelineSignal(e.frequency,t.Type.Frequency),this._readOnly("frequency"),this.ticks=0,this._state=new t.TimelineState(t.State.Stopped),this._boundLoop=this._loop.bind(this),this.context.on("tick",this._boundLoop)},t.extend(t.Clock,t.Emitter),t.Clock.defaults={callback:t.noOp,frequency:1,lookAhead:"auto"},Object.defineProperty(t.Clock.prototype,"state",{get:function(){return this._state.getValueAtTime(this.now())}}),t.Clock.prototype.start=function(e,i){return e=this.toSeconds(e),this._state.getValueAtTime(e)!==t.State.Started&&this._state.add({state:t.State.Started,time:e,offset:i}),this},t.Clock.prototype.stop=function(e){return e=this.toSeconds(e),this._state.cancel(e),this._state.setStateAtTime(t.State.Stopped,e),this},t.Clock.prototype.pause=function(e){return e=this.toSeconds(e),this._state.getValueAtTime(e)===t.State.Started&&this._state.setStateAtTime(t.State.Paused,e),this},t.Clock.prototype._loop=function(){for(var e=this.now(),i=this.context.lookAhead,n=this.context.updateInterval,s=2*this.context.lag,o=e+i+n+s;o>this._nextTick&&this._state;){var r=this._state.getValueAtTime(this._nextTick);if(r!==this._lastState){this._lastState=r;var a=this._state.get(this._nextTick);r===t.State.Started?(this._nextTick=a.time,this.isUndef(a.offset)||(this.ticks=a.offset),this.emit("start",a.time,this.ticks)):r===t.State.Stopped?(this.ticks=0,this.emit("stop",a.time)):r===t.State.Paused&&this.emit("pause",a.time)}var h=this._nextTick;this.frequency&&(this._nextTick+=1/this.frequency.getValueAtTime(this._nextTick),r===t.State.Started&&(this.callback(h),this.ticks++))}},t.Clock.prototype.getStateAtTime=function(t){return t=this.toSeconds(t),this._state.getValueAtTime(t)},t.Clock.prototype.dispose=function(){t.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=1/0,this.callback=null,this._state.dispose(),this._state=null},t.Clock}),t(function(t){t.IntervalTimeline=function(){this._root=null,this._length=0},t.extend(t.IntervalTimeline),t.IntervalTimeline.prototype.add=function(t){if(this.isUndef(t.time)||this.isUndef(t.duration))throw new Error("Tone.IntervalTimeline: events must have time and duration parameters");var i=new e(t.time,t.time+t.duration,t);for(null===this._root?this._root=i:this._root.insert(i),this._length++;null!==i;)i.updateHeight(),i.updateMax(),this._rebalance(i),i=i.parent;return this},t.IntervalTimeline.prototype.remove=function(t){if(null!==this._root){var e=[];this._root.search(t.time,e);for(var i=0;i<e.length;i++){var n=e[i];if(n.event===t){this._removeNode(n),this._length--;break}}}return this},Object.defineProperty(t.IntervalTimeline.prototype,"length",{get:function(){return this._length}}),t.IntervalTimeline.prototype.cancel=function(t){return this.forEachAfter(t,function(t){this.remove(t)}.bind(this)),this},t.IntervalTimeline.prototype._setRoot=function(t){this._root=t,null!==this._root&&(this._root.parent=null)},t.IntervalTimeline.prototype._replaceNodeInParent=function(t,e){null!==t.parent?(t.isLeftChild()?t.parent.left=e:t.parent.right=e,this._rebalance(t.parent)):this._setRoot(e)},t.IntervalTimeline.prototype._removeNode=function(t){if(null===t.left&&null===t.right)this._replaceNodeInParent(t,null);else if(null===t.right)this._replaceNodeInParent(t,t.left);else if(null===t.left)this._replaceNodeInParent(t,t.right);else{var e,i,n=t.getBalance();if(n>0)if(null===t.left.right)e=t.left,e.right=t.right,i=e;else{for(e=t.left.right;null!==e.right;)e=e.right;e.parent.right=e.left,i=e.parent,e.left=t.left,e.right=t.right}else if(null===t.right.left)e=t.right,e.left=t.left,i=e;else{for(e=t.right.left;null!==e.left;)e=e.left;e.parent=e.parent,e.parent.left=e.right,i=e.parent,e.left=t.left,e.right=t.right}null!==t.parent?t.isLeftChild()?t.parent.left=e:t.parent.right=e:this._setRoot(e),this._rebalance(i)}t.dispose()},t.IntervalTimeline.prototype._rotateLeft=function(t){var e=t.parent,i=t.isLeftChild(),n=t.right;t.right=n.left,n.left=t,null!==e?i?e.left=n:e.right=n:this._setRoot(n)},t.IntervalTimeline.prototype._rotateRight=function(t){var e=t.parent,i=t.isLeftChild(),n=t.left;t.left=n.right,n.right=t,null!==e?i?e.left=n:e.right=n:this._setRoot(n)},t.IntervalTimeline.prototype._rebalance=function(t){var e=t.getBalance();e>1?t.left.getBalance()<0?this._rotateLeft(t.left):this._rotateRight(t):e<-1&&(t.right.getBalance()>0?this._rotateRight(t.right):this._rotateLeft(t))},t.IntervalTimeline.prototype.get=function(t){if(null!==this._root){var e=[];if(this._root.search(t,e),e.length>0){for(var i=e[0],n=1;n<e.length;n++)e[n].low>i.low&&(i=e[n]);return i.event}}return null},t.IntervalTimeline.prototype.forEach=function(t){if(null!==this._root){var e=[];null!==this._root&&this._root.traverse(function(t){e.push(t)});for(var i=0;i<e.length;i++){var n=e[i].event;n&&t(n)}}return this},t.IntervalTimeline.prototype.forEachAtTime=function(t,e){if(null!==this._root){var i=[];this._root.search(t,i);for(var n=i.length-1;n>=0;n--){var s=i[n].event;s&&e(s)}}return this},t.IntervalTimeline.prototype.forEachAfter=function(t,e){if(null!==this._root){var i=[];this._root.searchAfter(t,i);for(var n=i.length-1;n>=0;n--){var s=i[n].event;s&&e(s)}}return this},t.IntervalTimeline.prototype.dispose=function(){var t=[];null!==this._root&&this._root.traverse(function(e){t.push(e)});for(var e=0;e<t.length;e++)t[e].dispose();return t=null,this._root=null,this};var e=function(t,e,i){this.event=i,this.low=t,this.high=e,this.max=this.high,this._left=null,this._right=null,this.parent=null,this.height=0};return e.prototype.insert=function(t){t.low<=this.low?null===this.left?this.left=t:this.left.insert(t):null===this.right?this.right=t:this.right.insert(t)},e.prototype.search=function(t,e){t>this.max||(null!==this.left&&this.left.search(t,e),this.low<=t&&this.high>t&&e.push(this),this.low>t||null!==this.right&&this.right.search(t,e))},e.prototype.searchAfter=function(t,e){this.low>=t&&(e.push(this),null!==this.left&&this.left.searchAfter(t,e)),null!==this.right&&this.right.searchAfter(t,e)},e.prototype.traverse=function(t){t(this),null!==this.left&&this.left.traverse(t),null!==this.right&&this.right.traverse(t)},e.prototype.updateHeight=function(){null!==this.left&&null!==this.right?this.height=Math.max(this.left.height,this.right.height)+1:null!==this.right?this.height=this.right.height+1:null!==this.left?this.height=this.left.height+1:this.height=0},e.prototype.updateMax=function(){this.max=this.high,null!==this.left&&(this.max=Math.max(this.max,this.left.max)),null!==this.right&&(this.max=Math.max(this.max,this.right.max))},e.prototype.getBalance=function(){var t=0;return null!==this.left&&null!==this.right?t=this.left.height-this.right.height:null!==this.left?t=this.left.height+1:null!==this.right&&(t=-(this.right.height+1)),t},e.prototype.isLeftChild=function(){return null!==this.parent&&this.parent.left===this},Object.defineProperty(e.prototype,"left",{get:function(){return this._left},set:function(t){this._left=t,null!==t&&(t.parent=this),this.updateHeight(),this.updateMax()}}),Object.defineProperty(e.prototype,"right",{get:function(){return this._right},set:function(t){this._right=t,null!==t&&(t.parent=this),this.updateHeight(),this.updateMax()}}),e.prototype.dispose=function(){this.parent=null,this._left=null,this._right=null,this.event=null},t.IntervalTimeline}),t(function(t){t.Transport=function(){t.Emitter.call(this),this.loop=!1,this._loopStart=0,this._loopEnd=0,this._ppq=e.defaults.PPQ,this._clock=new t.Clock({callback:this._processTick.bind(this),frequency:0}),this._bindClockEvents(),this.bpm=this._clock.frequency,this.bpm._toUnits=this._toUnits.bind(this),this.bpm._fromUnits=this._fromUnits.bind(this),this.bpm.units=t.Type.BPM,this.bpm.value=e.defaults.bpm,this._readOnly("bpm"),this._timeSignature=e.defaults.timeSignature,this._scheduledEvents={},this._eventID=0,this._timeline=new t.Timeline,this._repeatedEvents=new t.IntervalTimeline,this._onceEvents=new t.Timeline,this._syncedSignals=[],this._swingTicks=e.defaults.PPQ/2,this._swingAmount=0},t.extend(t.Transport,t.Emitter),t.Transport.defaults={bpm:120,swing:0,swingSubdivision:"8n",timeSignature:4,loopStart:0,loopEnd:"4m",PPQ:192},t.Transport.prototype._processTick=function(e){var i=this._clock.ticks;if(this._swingAmount>0&&i%this._ppq!=0&&i%(2*this._swingTicks)!=0){var n=i%(2*this._swingTicks)/(2*this._swingTicks),s=Math.sin(n*Math.PI)*this._swingAmount;e+=t.Time(2*this._swingTicks/3,"i")*s}this.loop&&i===this._loopEnd&&(this.emit("loopEnd",e),this._clock.ticks=this._loopStart,i=this._loopStart,this.emit("loopStart",e,this.seconds),this.emit("loop",e)),this._onceEvents.forEachBefore(i,function(t){t.callback(e),delete this._scheduledEvents[t.id.toString()]}.bind(this)),this._onceEvents.cancelBefore(i),this._timeline.forEachAtTime(i,function(t){t.callback(e)}),this._repeatedEvents.forEachAtTime(i,function(t){(i-t.time)%t.interval==0&&t.callback(e)})},t.Transport.prototype.schedule=function(t,e){var i={time:this.toTicks(e),callback:t},n=this._eventID++;return this._scheduledEvents[n.toString()]={event:i,timeline:this._timeline},this._timeline.add(i),n},t.Transport.prototype.scheduleRepeat=function(t,e,i,n){if(e<=0)throw new Error("Tone.Transport: repeat events must have an interval larger than 0");var s={time:this.toTicks(i),duration:this.toTicks(this.defaultArg(n,1/0)),interval:this.toTicks(e),callback:t},o=this._eventID++;return this._scheduledEvents[o.toString()]={event:s,timeline:this._repeatedEvents},this._repeatedEvents.add(s),o},t.Transport.prototype.scheduleOnce=function(t,e){var i=this._eventID++,n={time:this.toTicks(e),callback:t,id:i};return this._scheduledEvents[i.toString()]={event:n,timeline:this._onceEvents},this._onceEvents.add(n),i},t.Transport.prototype.clear=function(t){if(this._scheduledEvents.hasOwnProperty(t)){var e=this._scheduledEvents[t.toString()];e.timeline.remove(e.event),delete this._scheduledEvents[t.toString()]}return this},t.Transport.prototype.cancel=function(t){return t=this.defaultArg(t,0),t=this.toTicks(t),this._timeline.cancel(t),this._onceEvents.cancel(t),this._repeatedEvents.cancel(t),this},t.Transport.prototype._bindClockEvents=function(){this._clock.on("start",function(e,i){i=t.Time(this._clock.ticks,"i").toSeconds(),this.emit("start",e,i)}.bind(this)),this._clock.on("stop",function(t){this.emit("stop",t)}.bind(this)),this._clock.on("pause",function(t){this.emit("pause",t)}.bind(this))},Object.defineProperty(t.Transport.prototype,"state",{get:function(){return this._clock.getStateAtTime(this.now())}}),t.Transport.prototype.start=function(t,e){return this.isUndef(e)||(e=this.toTicks(e)),this._clock.start(t,e),this},t.Transport.prototype.stop=function(t){return this._clock.stop(t),this},t.Transport.prototype.pause=function(t){return this._clock.pause(t),this},Object.defineProperty(t.Transport.prototype,"timeSignature",{get:function(){return this._timeSignature},set:function(t){this.isArray(t)&&(t=t[0]/t[1]*4),this._timeSignature=t}}),Object.defineProperty(t.Transport.prototype,"loopStart",{get:function(){return t.TransportTime(this._loopStart,"i").toSeconds()},set:function(t){this._loopStart=this.toTicks(t)}}),Object.defineProperty(t.Transport.prototype,"loopEnd",{get:function(){return t.TransportTime(this._loopEnd,"i").toSeconds()},set:function(t){this._loopEnd=this.toTicks(t)}}),t.Transport.prototype.setLoopPoints=function(t,e){return this.loopStart=t,this.loopEnd=e,this},Object.defineProperty(t.Transport.prototype,"swing",{get:function(){return this._swingAmount},set:function(t){this._swingAmount=t}}),Object.defineProperty(t.Transport.prototype,"swingSubdivision",{get:function(){return t.Time(this._swingTicks,"i").toNotation()},set:function(t){this._swingTicks=this.toTicks(t)}}),Object.defineProperty(t.Transport.prototype,"position",{get:function(){return t.TransportTime(this.ticks,"i").toBarsBeatsSixteenths()},set:function(t){var e=this.toTicks(t);this.ticks=e}}),Object.defineProperty(t.Transport.prototype,"seconds",{get:function(){return t.TransportTime(this.ticks,"i").toSeconds()},set:function(t){var e=this.toTicks(t);this.ticks=e}}),Object.defineProperty(t.Transport.prototype,"progress",{get:function(){return this.loop?(this.ticks-this._loopStart)/(this._loopEnd-this._loopStart):0}}),Object.defineProperty(t.Transport.prototype,"ticks",{get:function(){return this._clock.ticks},set:function(e){if(this._clock.ticks!==e){var i=this.now();this.state===t.State.Started?(this.emit("stop",i),this._clock.ticks=e,this.emit("start",i,this.seconds)):this._clock.ticks=e}}}),Object.defineProperty(t.Transport.prototype,"PPQ",{get:function(){return this._ppq},set:function(t){var e=this.bpm.value;this._ppq=t,this.bpm.value=e}}),Object.defineProperty(t.Transport.prototype,"latencyHint",{get:function(){return t.Clock.latencyHint},set:function(e){t.Clock.latencyHint=e}}),t.Transport.prototype._fromUnits=function(t){return 1/(60/t/this.PPQ)},t.Transport.prototype._toUnits=function(t){return t/this.PPQ*60},t.Transport.prototype.nextSubdivision=function(e){e=this.toSeconds(e);var i;if(this.state!==t.State.Started)return 0;i=this._clock._nextTick;var n=t.Time(this.ticks,"i"),s=e-n%e;return 0===s&&(s=e),i+s},t.Transport.prototype.syncSignal=function(e,i){i||(i=0!==e._param.value?e._param.value/this.bpm._param.value:0);var n=new t.Gain(i);return this.bpm.chain(n,e._param),this._syncedSignals.push({ratio:n,signal:e,initial:e._param.value}),e._param.value=0,this},t.Transport.prototype.unsyncSignal=function(t){for(var e=this._syncedSignals.length-1;e>=0;e--){var i=this._syncedSignals[e];i.signal===t&&(i.ratio.dispose(),i.signal._param.value=i.initial,this._syncedSignals.splice(e,1))}return this},t.Transport.prototype.dispose=function(){return t.Emitter.prototype.dispose.call(this),this._clock.dispose(),this._clock=null,this._writable("bpm"),this.bpm=null,this._timeline.dispose(),this._timeline=null,this._onceEvents.dispose(),this._onceEvents=null,this._repeatedEvents.dispose(),this._repeatedEvents=null,this};var e=t.Transport;return t.Transport=new e,t.Context.on("init",function(i){i.Transport instanceof e?t.Transport=i.Transport:(t.Transport=new e,i.Transport=t.Transport)}),t.Transport}),t(function(t){return t.Volume=function(){var e=this.optionsObject(arguments,["volume"],t.Volume.defaults);this.output=this.input=new t.Gain(e.volume,t.Type.Decibels),this._unmutedVolume=e.volume,this.volume=this.output.gain,this._readOnly("volume"),this.mute=e.mute},t.extend(t.Volume),t.Volume.defaults={volume:0,mute:!1},Object.defineProperty(t.Volume.prototype,"mute",{get:function(){return this.volume.value===-1/0},set:function(t){!this.mute&&t?(this._unmutedVolume=this.volume.value,this.volume.value=-1/0):this.mute&&!t&&(this.volume.value=this._unmutedVolume)}}),t.Volume.prototype.dispose=function(){return this.input.dispose(),t.prototype.dispose.call(this),this._writable("volume"),this.volume.dispose(),this.volume=null,this},t.Volume}),t(function(t){t.Master=function(){this.createInsOuts(1,1),this._volume=this.output=new t.Volume,this.volume=this._volume.volume,this._readOnly("volume"),this.input.chain(this.output,this.context.destination)},t.extend(t.Master),t.Master.defaults={volume:0,mute:!1},Object.defineProperty(t.Master.prototype,"mute",{get:function(){return this._volume.mute},set:function(t){this._volume.mute=t}}),t.Master.prototype.chain=function(){this.input.disconnect(),this.input.chain.apply(this.input,arguments),arguments[arguments.length-1].connect(this.output)},t.Master.prototype.dispose=function(){t.prototype.dispose.call(this),this._writable("volume"),this._volume.dispose(),this._volume=null,this.volume=null},t.prototype.toMaster=function(){return this.connect(t.Master),this},AudioNode.prototype.toMaster=function(){return this.connect(t.Master),this};var e=t.Master;return t.Master=new e,t.Context.on("init",function(i){i.Master instanceof e?t.Master=i.Master:t.Master=new e,i.Master=t.Master}),t.Master}),t(function(t){return t.Source=function(e){e=this.defaultArg(e,t.Source.defaults),this._volume=this.output=new t.Volume(e.volume),this.volume=this._volume.volume,this._readOnly("volume"),this._state=new t.TimelineState(t.State.Stopped),this._state.memory=10,this._synced=!1,this._scheduled=[],this._volume.output.output.channelCount=2,this._volume.output.output.channelCountMode="explicit",this.mute=e.mute},t.extend(t.Source),t.Source.defaults={volume:0,mute:!1},Object.defineProperty(t.Source.prototype,"state",{get:function(){return this._synced?t.Transport.state===t.State.Started?this._state.getValueAtTime(t.Transport.seconds):t.State.Stopped:this._state.getValueAtTime(this.now())}}),Object.defineProperty(t.Source.prototype,"mute",{get:function(){return this._volume.mute},set:function(t){this._volume.mute=t}}),t.Source.prototype._start=t.noOp,t.Source.prototype._stop=t.noOp,t.Source.prototype.start=function(e,i,n){if(e=this.isUndef(e)&&this._synced?t.Transport.seconds:this.toSeconds(e),this.retrigger||this._state.getValueAtTime(e)!==t.State.Started||this.stop(e),this._state.setStateAtTime(t.State.Started,e),this._synced){var s=this._state.get(e);s.offset=this.defaultArg(i,0),s.duration=n;var o=t.Transport.schedule(function(t){this._start(t,i,n)}.bind(this),e);this._scheduled.push(o)}else this._start.apply(this,arguments);return this},t.Source.prototype.stop=function(e){if(e=this.isUndef(e)&&this._synced?t.Transport.seconds:this.toSeconds(e),this._state.cancel(e),this._state.setStateAtTime(t.State.Stopped,e),this._synced){var i=t.Transport.schedule(this._stop.bind(this),e);this._scheduled.push(i)}else this._stop.apply(this,arguments);return this},t.Source.prototype.sync=function(){return this._synced=!0,t.Transport.on("start loopStart",function(e,i){if(i>0){var n=this._state.get(i);if(n&&n.state===t.State.Started&&n.time!==i){var s,o=i-this.toSeconds(n.time);n.duration&&(s=this.toSeconds(n.duration)-o),this._start(e,this.toSeconds(n.offset)+o,s)}}}.bind(this)),t.Transport.on("stop pause loopEnd",function(e){this._state.getValueAtTime(t.Transport.seconds)===t.State.Started&&this._stop(e)}.bind(this)),this},t.Source.prototype.unsync=function(){this._synced=!1,t.Transport.off("start stop pause loopEnd loopStart");for(var e=0;e<this._scheduled.length;e++){var i=this._scheduled[e];t.Transport.clear(i)}return this._scheduled=[],this._state.cancel(0),this},t.Source.prototype.dispose=function(){t.prototype.dispose.call(this),this.unsync(),this._scheduled=null,this._writable("volume"),this._volume.dispose(),this._volume=null,this.volume=null,this._state.dispose(),this._state=null},t.Source}),t(function(t){return window.OscillatorNode&&!OscillatorNode.prototype.start&&(OscillatorNode.prototype.start=OscillatorNode.prototype.noteOn,OscillatorNode.prototype.stop=OscillatorNode.prototype.noteOff,OscillatorNode.prototype.setPeriodicWave||(OscillatorNode.prototype.setPeriodicWave=OscillatorNode.prototype.setWaveTable),AudioContext.prototype.createPeriodicWave||(AudioContext.prototype.createPeriodicWave=AudioContext.prototype.createWaveTable)),t.Oscillator=function(){var e=this.optionsObject(arguments,["frequency","type"],t.Oscillator.defaults);t.Source.call(this,e),this._oscillator=null,this.frequency=new t.Signal(e.frequency,t.Type.Frequency),this.detune=new t.Signal(e.detune,t.Type.Cents),this._wave=null,this._partials=this.defaultArg(e.partials,[1]),this._phase=e.phase,this._type=null,this.type=e.type,this.phase=this._phase,this._readOnly(["frequency","detune"])},t.extend(t.Oscillator,t.Source),t.Oscillator.defaults={type:"sine",frequency:440,detune:0,phase:0,partials:[]},t.Oscillator.Type={Sine:"sine",Triangle:"triangle",Sawtooth:"sawtooth",Square:"square",Custom:"custom"},t.Oscillator.prototype._start=function(t){this._oscillator=this.context.createOscillator(),this._oscillator.setPeriodicWave(this._wave),this._oscillator.connect(this.output),this.frequency.connect(this._oscillator.frequency),this.detune.connect(this._oscillator.detune),this._oscillator.start(this.toSeconds(t))},t.Oscillator.prototype._stop=function(t){return this._oscillator&&(this._oscillator.stop(this.toSeconds(t)),this._oscillator=null),this},t.Oscillator.prototype.syncFrequency=function(){return t.Transport.syncSignal(this.frequency),this},t.Oscillator.prototype.unsyncFrequency=function(){return t.Transport.unsyncSignal(this.frequency),this},Object.defineProperty(t.Oscillator.prototype,"type",{get:function(){return this._type},set:function(t){var e=this._getRealImaginary(t,this._phase),i=this.context.createPeriodicWave(e[0],e[1]);this._wave=i,null!==this._oscillator&&this._oscillator.setPeriodicWave(this._wave),this._type=t}}),t.Oscillator.prototype._getRealImaginary=function(e,i){var n=2048,s=new Float32Array(n),o=new Float32Array(n),r=1;if(e===t.Oscillator.Type.Custom)r=this._partials.length+1,n=r;else{var a=/^(sine|triangle|square|sawtooth)(\d+)$/.exec(e);a&&(r=parseInt(a[2])+1,e=a[1],r=Math.max(r,2),n=r)}for(var h=1;h<n;++h){var l,u=2/(h*Math.PI);switch(e){case t.Oscillator.Type.Sine:l=h<=r?1:0;break;case t.Oscillator.Type.Square:l=1&h?2*u:0;break;case t.Oscillator.Type.Sawtooth:l=u*(1&h?1:-1);break;case t.Oscillator.Type.Triangle:l=1&h?u*u*2*(h-1>>1&1?-1:1):0;break;case t.Oscillator.Type.Custom:l=this._partials[h-1];break;default:throw new TypeError("Tone.Oscillator: invalid type: "+e)}0!==l?(s[h]=-l*Math.sin(i*h),o[h]=l*Math.cos(i*h)):(s[h]=0,o[h]=0)}return[s,o]},t.Oscillator.prototype._inverseFFT=function(t,e,i){for(var n=0,s=t.length,o=0;o<s;o++)n+=t[o]*Math.cos(o*i)+e[o]*Math.sin(o*i);return n},t.Oscillator.prototype._getInitialValue=function(){for(var t=this._getRealImaginary(this._type,0),e=t[0],i=t[1],n=0,s=2*Math.PI,o=0;o<8;o++)n=Math.max(this._inverseFFT(e,i,o/8*s),n);return-this._inverseFFT(e,i,this._phase)/n},Object.defineProperty(t.Oscillator.prototype,"partials",{get:function(){return this._type!==t.Oscillator.Type.Custom?[]:this._partials},set:function(e){this._partials=e,this.type=t.Oscillator.Type.Custom}}),Object.defineProperty(t.Oscillator.prototype,"phase",{get:function(){return this._phase*(180/Math.PI)},set:function(t){this._phase=t*Math.PI/180,this.type=this._type}}),t.Oscillator.prototype.dispose=function(){return t.Source.prototype.dispose.call(this),null!==this._oscillator&&(this._oscillator.disconnect(),this._oscillator=null),this._wave=null,this._writable(["frequency","detune"]),this.frequency.dispose(),this.frequency=null,this.detune.dispose(),this.detune=null,this._partials=null,this},t.Oscillator}),t(function(t){return t.Zero=function(){this._gain=this.input=this.output=new t.Gain,this.context.getConstant(0).connect(this._gain)},t.extend(t.Zero),t.Zero.prototype.dispose=function(){return t.prototype.dispose.call(this),this._gain.dispose(),this._gain=null,this},t.Zero}),t(function(t){return t.LFO=function(){var e=this.optionsObject(arguments,["frequency","min","max"],t.LFO.defaults);this._oscillator=new t.Oscillator({frequency:e.frequency,type:e.type}),this.frequency=this._oscillator.frequency,this.amplitude=this._oscillator.volume,this.amplitude.units=t.Type.NormalRange,this.amplitude.value=e.amplitude,this._stoppedSignal=new t.Signal(0,t.Type.AudioRange),this._zeros=new t.Zero,this._stoppedValue=0,this._a2g=new t.AudioToGain,this._scaler=this.output=new t.Scale(e.min,e.max),this._units=t.Type.Default,this.units=e.units,this._oscillator.chain(this._a2g,this._scaler),this._zeros.connect(this._a2g),this._stoppedSignal.connect(this._a2g),this._readOnly(["amplitude","frequency"]),this.phase=e.phase},t.extend(t.LFO,t.Oscillator),t.LFO.defaults={type:"sine",min:0,max:1,phase:0,frequency:"4n",amplitude:1,units:t.Type.Default},t.LFO.prototype.start=function(t){return t=this.toSeconds(t),this._stoppedSignal.setValueAtTime(0,t),this._oscillator.start(t),this},t.LFO.prototype.stop=function(t){return t=this.toSeconds(t),this._stoppedSignal.setValueAtTime(this._stoppedValue,t),this._oscillator.stop(t),this},t.LFO.prototype.sync=function(){return this._oscillator.sync(),this._oscillator.syncFrequency(),this},t.LFO.prototype.unsync=function(){return this._oscillator.unsync(),this._oscillator.unsyncFrequency(),this},Object.defineProperty(t.LFO.prototype,"min",{get:function(){return this._toUnits(this._scaler.min)},set:function(t){t=this._fromUnits(t),this._scaler.min=t}}),Object.defineProperty(t.LFO.prototype,"max",{get:function(){return this._toUnits(this._scaler.max)},set:function(t){t=this._fromUnits(t),this._scaler.max=t}}),Object.defineProperty(t.LFO.prototype,"type",{get:function(){return this._oscillator.type},set:function(t){this._oscillator.type=t,this._stoppedValue=this._oscillator._getInitialValue(),this._stoppedSignal.value=this._stoppedValue}}),Object.defineProperty(t.LFO.prototype,"phase",{get:function(){return this._oscillator.phase},set:function(t){this._oscillator.phase=t,this._stoppedValue=this._oscillator._getInitialValue(),this._stoppedSignal.value=this._stoppedValue}}),Object.defineProperty(t.LFO.prototype,"units",{get:function(){return this._units},set:function(t){var e=this.min,i=this.max;this._units=t,this.min=e,this.max=i}}),Object.defineProperty(t.LFO.prototype,"mute",{get:function(){return this._oscillator.mute},set:function(t){this._oscillator.mute=t}}),Object.defineProperty(t.LFO.prototype,"state",{get:function(){return this._oscillator.state}}),t.LFO.prototype.connect=function(e){return e.constructor!==t.Signal&&e.constructor!==t.Param&&e.constructor!==t.TimelineSignal||(this.convert=e.convert,this.units=e.units),t.Signal.prototype.connect.apply(this,arguments),this},t.LFO.prototype._fromUnits=t.Param.prototype._fromUnits,t.LFO.prototype._toUnits=t.Param.prototype._toUnits,t.LFO.prototype.dispose=function(){return t.prototype.dispose.call(this),this._writable(["amplitude","frequency"]),this._oscillator.dispose(),this._oscillator=null,this._stoppedSignal.dispose(),this._stoppedSignal=null,this._zeros.dispose(),this._zeros=null,this._scaler.dispose(),this._scaler=null,this._a2g.dispose(),this._a2g=null,this.frequency=null,this.amplitude=null,this},t.LFO}),t(function(t){return t.Limiter=function(){var e=this.optionsObject(arguments,["threshold"],t.Limiter.defaults);this._compressor=this.input=this.output=new t.Compressor({attack:.001,decay:.001,threshold:e.threshold}),this.threshold=this._compressor.threshold,this._readOnly("threshold")},t.extend(t.Limiter),t.Limiter.defaults={threshold:-12},t.Limiter.prototype.dispose=function(){return t.prototype.dispose.call(this),this._compressor.dispose(),this._compressor=null,this._writable("threshold"),this.threshold=null,this},t.Limiter}),t(function(t){return t.LowpassCombFilter=function(){this.createInsOuts(1,1);var e=this.optionsObject(arguments,["delayTime","resonance","dampening"],t.LowpassCombFilter.defaults);this._delay=this.input=new t.Delay(e.delayTime),this.delayTime=this._delay.delayTime,this._lowpass=this.output=this.context.createBiquadFilter(),this._lowpass.Q.value=-3.0102999566398125,this._lowpass.type="lowpass",this.dampening=new t.Param({param:this._lowpass.frequency,units:t.Type.Frequency,value:e.dampening}),this._feedback=new t.Gain(e.resonance,t.Type.NormalRange),this.resonance=this._feedback.gain,this._delay.chain(this._lowpass,this._feedback,this._delay),this._readOnly(["dampening","resonance","delayTime"])},t.extend(t.LowpassCombFilter),t.LowpassCombFilter.defaults={delayTime:.1,resonance:.5,dampening:3e3},t.LowpassCombFilter.prototype.dispose=function(){return t.prototype.dispose.call(this),this._writable(["dampening","resonance","delayTime"]),this.dampening.dispose(),this.dampening=null,this.resonance.dispose(),this.resonance=null,this._delay.dispose(),this._delay=null,this.delayTime=null,this._lowpass.disconnect(),this._lowpass=null,this._feedback.disconnect(),this._feedback=null,this},t.LowpassCombFilter}),t(function(t){return t.Merge=function(){this.createInsOuts(2,0),this.left=this.input[0]=new t.Gain,this.right=this.input[1]=new t.Gain,this._merger=this.output=this.context.createChannelMerger(2),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"},t.extend(t.Merge),t.Merge.prototype.dispose=function(){return t.prototype.dispose.call(this),this.left.dispose(),this.left=null,this.right.dispose(),this.right=null,this._merger.disconnect(),this._merger=null,this},t.Merge}),t(function(t){return t.Meter=function(){var e=this.optionsObject(arguments,["type","smoothing"],t.Meter.defaults);this.type=e.type,this.input=this.output=this._analyser=new t.Analyser("waveform",512),this._analyser.returnType="float",this.smoothing=e.smoothing,this._lastValue=0},t.extend(t.Meter),t.Meter.Type={Level:"level",Signal:"signal"},t.Meter.defaults={smoothing:.8,type:t.Meter.Type.Level},Object.defineProperty(t.Meter.prototype,"value",{get:function(){var e=this._analyser.analyse();if(this.type===t.Meter.Type.Level){for(var i=0,n=0;n<e.length;n++)i+=Math.pow(e[n],2);var s=Math.sqrt(i/e.length);s=Math.max(s,this._lastValue*this.smoothing),this._lastValue=s;var o=s/.35;return Math.sqrt(o)}return e[0]}}),t.Meter.prototype.dispose=function(){return t.prototype.dispose.call(this),this._analyser.dispose(),this._analyser=null,this},t.Meter}),t(function(t){return t.Split=function(){this.createInsOuts(0,2),this._splitter=this.input=this.context.createChannelSplitter(2),this.left=this.output[0]=new t.Gain,this.right=this.output[1]=new t.Gain,this._splitter.connect(this.left,0,0),this._splitter.connect(this.right,1,0)},t.extend(t.Split),t.Split.prototype.dispose=function(){return t.prototype.dispose.call(this),this._splitter.disconnect(),this.left.dispose(),this.left=null,this.right.dispose(),this.right=null,this._splitter=null,this},t.Split}),t(function(t){return t.MidSideSplit=function(){this.createInsOuts(0,2),this._split=this.input=new t.Split,this.mid=this.output[0]=new t.Expr("($0 + $1) * $2"),this.side=this.output[1]=new t.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)},t.extend(t.MidSideSplit),t.MidSideSplit.prototype.dispose=function(){return t.prototype.dispose.call(this),this.mid.dispose(),this.mid=null,this.side.dispose(),this.side=null,this._split.dispose(),this._split=null,this},t.MidSideSplit}),t(function(t){return t.MidSideMerge=function(){this.createInsOuts(2,0),this.mid=this.input[0]=new t.Gain,this._left=new t.Expr("($0 + $1) * $2"),this.side=this.input[1]=new t.Gain,this._right=new t.Expr("($0 - $1) * $2"),this._merge=this.output=new t.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)},t.extend(t.MidSideMerge),t.MidSideMerge.prototype.dispose=function(){return t.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,this},t.MidSideMerge}),t(function(t){return t.MidSideCompressor=function(e){e=this.defaultArg(e,t.MidSideCompressor.defaults),this._midSideSplit=this.input=new t.MidSideSplit,this._midSideMerge=this.output=new t.MidSideMerge,this.mid=new t.Compressor(e.mid),this.side=new t.Compressor(e.side),this._midSideSplit.mid.chain(this.mid,this._midSideMerge.mid),this._midSideSplit.side.chain(this.side,this._midSideMerge.side),this._readOnly(["mid","side"])},t.extend(t.MidSideCompressor),t.MidSideCompressor.defaults={mid:{ratio:3,threshold:-24,release:.03,attack:.02,knee:16},side:{ratio:6,threshold:-30,release:.25,attack:.03,knee:10}},t.MidSideCompressor.prototype.dispose=function(){return t.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,this},t.MidSideCompressor}),t(function(t){return t.Mono=function(){this.createInsOuts(1,0),this._merge=this.output=new t.Merge,this.input.connect(this._merge,0,0),this.input.connect(this._merge,0,1),this.input.gain.value=this.dbToGain(-10)},t.extend(t.Mono),t.Mono.prototype.dispose=function(){return t.prototype.dispose.call(this),this._merge.dispose(),this._merge=null,this},t.Mono}),t(function(t){return t.MultibandCompressor=function(e){e=this.defaultArg(arguments,t.MultibandCompressor.defaults),this._splitter=this.input=new t.MultibandSplit({lowFrequency:e.lowFrequency,highFrequency:e.highFrequency}),this.lowFrequency=this._splitter.lowFrequency,this.highFrequency=this._splitter.highFrequency,this.output=new t.Gain,this.low=new t.Compressor(e.low),this.mid=new t.Compressor(e.mid),this.high=new t.Compressor(e.high),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"])},t.extend(t.MultibandCompressor),t.MultibandCompressor.defaults={low:t.Compressor.defaults,mid:t.Compressor.defaults,high:t.Compressor.defaults,lowFrequency:250,highFrequency:2e3},t.MultibandCompressor.prototype.dispose=function(){return t.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,this},t.MultibandCompressor}),t(function(t){return t.Panner=function(e){this._hasStereoPanner?(this._panner=this.input=this.output=this.context.createStereoPanner(),this.pan=this._panner.pan):(this._crossFade=new t.CrossFade,this._merger=this.output=new t.Merge,this._splitter=this.input=new t.Split,this.pan=new t.Signal(0,t.Type.AudioRange),this._zero=new t.Zero,this._a2g=new t.AudioToGain,this._zero.connect(this._a2g),this.pan.chain(this._a2g,this._crossFade.fade),this._splitter.connect(this._crossFade,0,0),this._splitter.connect(this._crossFade,1,1),this._crossFade.a.connect(this._merger,0,0),this._crossFade.b.connect(this._merger,0,1)),this.pan.value=this.defaultArg(e,0),this._readOnly("pan")},t.extend(t.Panner),t.Panner.prototype._hasStereoPanner=t.prototype.isFunction(t.context.createStereoPanner),t.Panner.prototype.dispose=function(){return t.prototype.dispose.call(this),this._writable("pan"),this._hasStereoPanner?(this._panner.disconnect(),this._panner=null,this.pan=null):(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),this},t.Panner}),t(function(t){return t.Panner3D=function(){var e=this.optionsObject(arguments,["positionX","positionY","positionZ"],t.Panner3D.defaults);this._panner=this.input=this.output=this.context.createPanner(),this._panner.panningModel=e.panningModel,this._panner.maxDistance=e.maxDistance,this._panner.distanceModel=e.distanceModel,this._panner.coneOuterGain=e.coneOuterGain,this._panner.coneOuterAngle=e.coneOuterAngle,this._panner.coneInnerAngle=e.coneInnerAngle,this._panner.refDistance=e.refDistance,this._panner.rolloffFactor=e.rolloffFactor,this._orientation=[e.orientationX,e.orientationY,e.orientationZ],this._position=[e.positionX,e.positionY,e.positionZ],this.orientationX=e.orientationX,this.orientationY=e.orientationY,this.orientationZ=e.orientationZ,this.positionX=e.positionX,this.positionY=e.positionY,this.positionZ=e.positionZ},t.extend(t.Panner3D),t.Panner3D.defaults={positionX:0,positionY:0,positionZ:0,orientationX:0,orientationY:0,orientationZ:0,panningModel:"equalpower",maxDistance:1e4,distanceModel:"inverse",coneOuterGain:0,coneOuterAngle:360,coneInnerAngle:360,refDistance:1,rolloffFactor:1},t.Panner3D.prototype._rampTimeConstant=.01,t.Panner3D.prototype.setPosition=function(t,e,i){if(this._panner.positionX){var n=this.now();this._panner.positionX.setTargetAtTime(t,n,this._rampTimeConstant),this._panner.positionY.setTargetAtTime(e,n,this._rampTimeConstant),this._panner.positionZ.setTargetAtTime(i,n,this._rampTimeConstant)}else this._panner.setPosition(t,e,i);return this._position=Array.prototype.slice.call(arguments),this},t.Panner3D.prototype.setOrientation=function(t,e,i){if(this._panner.orientationX){var n=this.now();this._panner.orientationX.setTargetAtTime(t,n,this._rampTimeConstant),this._panner.orientationY.setTargetAtTime(e,n,this._rampTimeConstant),this._panner.orientationZ.setTargetAtTime(i,n,this._rampTimeConstant)}else this._panner.setOrientation(t,e,i);return this._orientation=Array.prototype.slice.call(arguments),this},Object.defineProperty(t.Panner3D.prototype,"positionX",{set:function(t){this._position[0]=t,this.setPosition.apply(this,this._position)},get:function(){return this._position[0]}}),Object.defineProperty(t.Panner3D.prototype,"positionY",{set:function(t){this._position[1]=t,this.setPosition.apply(this,this._position)},get:function(){return this._position[1]}}),Object.defineProperty(t.Panner3D.prototype,"positionZ",{set:function(t){this._position[2]=t,this.setPosition.apply(this,this._position)},get:function(){return this._position[2]}}),Object.defineProperty(t.Panner3D.prototype,"orientationX",{set:function(t){this._orientation[0]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[0]}}),Object.defineProperty(t.Panner3D.prototype,"orientationY",{set:function(t){this._orientation[1]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[1]}}),Object.defineProperty(t.Panner3D.prototype,"orientationZ",{set:function(t){this._orientation[2]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[2]}}),t.Panner3D._aliasProperty=function(e){Object.defineProperty(t.Panner3D.prototype,e,{set:function(t){this._panner[e]=t},get:function(){return this._panner[e]}})},t.Panner3D._aliasProperty("panningModel"),t.Panner3D._aliasProperty("refDistance"),t.Panner3D._aliasProperty("rolloffFactor"),t.Panner3D._aliasProperty("distanceModel"),t.Panner3D._aliasProperty("coneInnerAngle"),t.Panner3D._aliasProperty("coneOuterAngle"),t.Panner3D._aliasProperty("coneOuterGain"),t.Panner3D._aliasProperty("maxDistance"),t.Panner3D.prototype.dispose=function(){return this._panner.disconnect(),this._panner=null,this._orientation=null,this._position=null,this},t.Panner3D}),t(function(t){return t.PanVol=function(){var e=this.optionsObject(arguments,["pan","volume"],t.PanVol.defaults);this._panner=this.input=new t.Panner(e.pan),this.pan=this._panner.pan,this._volume=this.output=new t.Volume(e.volume),this.volume=this._volume.volume,this._panner.connect(this._volume),this._readOnly(["pan","volume"])},t.extend(t.PanVol),t.PanVol.defaults={pan:.5,volume:0},t.PanVol.prototype.dispose=function(){return t.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,this},t.PanVol}),t(function(t){return t.CtrlInterpolate=function(){var e=this.optionsObject(arguments,["values","index"],t.CtrlInterpolate.defaults);this.values=e.values,this.index=e.index},t.extend(t.CtrlInterpolate),t.CtrlInterpolate.defaults={index:0,values:[]},Object.defineProperty(t.CtrlInterpolate.prototype,"value",{get:function(){var t=this.index;t=Math.min(t,this.values.length-1);var e=Math.floor(t),i=this.values[e],n=this.values[Math.ceil(t)];return this._interpolate(t-e,i,n)}}),t.CtrlInterpolate.prototype._interpolate=function(t,e,i){if(this.isArray(e)){for(var n=[],s=0;s<e.length;s++)n[s]=this._interpolate(t,e[s],i[s]);return n}if(this.isObject(e)){var o={};for(var r in e)o[r]=this._interpolate(t,e[r],i[r]);return o}return e=this._toNumber(e),i=this._toNumber(i),(1-t)*e+t*i},t.CtrlInterpolate.prototype._toNumber=function(t){return this.isNumber(t)?t:this.toSeconds(t)},t.CtrlInterpolate.prototype.dispose=function(){this.values=null},t.CtrlInterpolate}),t(function(t){return t.CtrlMarkov=function(t,e){this.values=this.defaultArg(t,{}),this.value=this.defaultArg(e,Object.keys(this.values)[0])},t.extend(t.CtrlMarkov),t.CtrlMarkov.prototype.next=function(){if(this.values.hasOwnProperty(this.value)){var t=this.values[this.value];if(this.isArray(t))for(var e=this._getProbDistribution(t),i=Math.random(),n=0,s=0;s<e.length;s++){var o=e[s];if(i>n&&i<n+o){var r=t[s];this.isObject(r)?this.value=r.value:this.value=r}n+=o}else this.value=t}return this.value},t.CtrlMarkov.prototype._getProbDistribution=function(t){for(var e=[],i=0,n=!1,s=0;s<t.length;s++){var o=t[s];this.isObject(o)?(n=!0,e[s]=o.probability):e[s]=1/t.length,i+=e[s]}if(n)for(var r=0;r<e.length;r++)e[r]=e[r]/i;return e},t.CtrlMarkov.prototype.dispose=function(){this.values=null},t.CtrlMarkov}),t(function(t){return t.CtrlPattern=function(){var e=this.optionsObject(arguments,["values","type"],t.CtrlPattern.defaults);this.values=e.values,this.index=0,this._type=null,this._shuffled=null,this._direction=null,this.type=e.type},t.extend(t.CtrlPattern),t.CtrlPattern.Type={Up:"up",Down:"down",UpDown:"upDown",DownUp:"downUp",AlternateUp:"alternateUp",AlternateDown:"alternateDown",Random:"random",RandomWalk:"randomWalk",RandomOnce:"randomOnce"},t.CtrlPattern.defaults={type:t.CtrlPattern.Type.Up,values:[]},Object.defineProperty(t.CtrlPattern.prototype,"value",{get:function(){if(0!==this.values.length){if(1===this.values.length)return this.values[0];this.index=Math.min(this.index,this.values.length-1);var e=this.values[this.index];return this.type===t.CtrlPattern.Type.RandomOnce&&(this.values.length!==this._shuffled.length&&this._shuffleValues(),e=this.values[this._shuffled[this.index]]),e}}}),Object.defineProperty(t.CtrlPattern.prototype,"type",{get:function(){return this._type},set:function(e){this._type=e,this._shuffled=null,this._type===t.CtrlPattern.Type.Up||this._type===t.CtrlPattern.Type.UpDown||this._type===t.CtrlPattern.Type.RandomOnce||this._type===t.CtrlPattern.Type.AlternateUp?this.index=0:this._type!==t.CtrlPattern.Type.Down&&this._type!==t.CtrlPattern.Type.DownUp&&this._type!==t.CtrlPattern.Type.AlternateDown||(this.index=this.values.length-1),this._type===t.CtrlPattern.Type.UpDown||this._type===t.CtrlPattern.Type.AlternateUp?this._direction=t.CtrlPattern.Type.Up:this._type!==t.CtrlPattern.Type.DownUp&&this._type!==t.CtrlPattern.Type.AlternateDown||(this._direction=t.CtrlPattern.Type.Down),this._type===t.CtrlPattern.Type.RandomOnce?this._shuffleValues():this._type===t.CtrlPattern.Random&&(this.index=Math.floor(Math.random()*this.values.length))}}),t.CtrlPattern.prototype.next=function(){var e=this.type;return e===t.CtrlPattern.Type.Up?++this.index>=this.values.length&&(this.index=0):e===t.CtrlPattern.Type.Down?--this.index<0&&(this.index=this.values.length-1):e===t.CtrlPattern.Type.UpDown||e===t.CtrlPattern.Type.DownUp?(this._direction===t.CtrlPattern.Type.Up?this.index++:this.index--,this.index<0?(this.index=1,this._direction=t.CtrlPattern.Type.Up):this.index>=this.values.length&&(this.index=this.values.length-2,this._direction=t.CtrlPattern.Type.Down)):e===t.CtrlPattern.Type.Random?this.index=Math.floor(Math.random()*this.values.length):e===t.CtrlPattern.Type.RandomWalk?Math.random()<.5?(this.index--,this.index=Math.max(this.index,0)):(this.index++,this.index=Math.min(this.index,this.values.length-1)):e===t.CtrlPattern.Type.RandomOnce?++this.index>=this.values.length&&(this.index=0,this._shuffleValues()):e===t.CtrlPattern.Type.AlternateUp?(this._direction===t.CtrlPattern.Type.Up?(this.index+=2,this._direction=t.CtrlPattern.Type.Down):(this.index-=1,this._direction=t.CtrlPattern.Type.Up),this.index>=this.values.length&&(this.index=0,this._direction=t.CtrlPattern.Type.Up)):e===t.CtrlPattern.Type.AlternateDown&&(this._direction===t.CtrlPattern.Type.Up?(this.index+=1,this._direction=t.CtrlPattern.Type.Down):(this.index-=2,this._direction=t.CtrlPattern.Type.Up),this.index<0&&(this.index=this.values.length-1,this._direction=t.CtrlPattern.Type.Down)),this.value},t.CtrlPattern.prototype._shuffleValues=function(){var t=[];this._shuffled=[];for(var e=0;e<this.values.length;e++)t[e]=e;for(;t.length>0;){var i=t.splice(Math.floor(t.length*Math.random()),1);this._shuffled.push(i[0])}},t.CtrlPattern.prototype.dispose=function(){this._shuffled=null,this.values=null},t.CtrlPattern}),t(function(t){return t.CtrlRandom=function(){var e=this.optionsObject(arguments,["min","max"],t.CtrlRandom.defaults);this.min=e.min,this.max=e.max,this.integer=e.integer},t.extend(t.CtrlRandom),t.CtrlRandom.defaults={min:0,max:1,integer:!1},Object.defineProperty(t.CtrlRandom.prototype,"value",{get:function(){var t=this.toSeconds(this.min),e=this.toSeconds(this.max),i=Math.random(),n=i*t+(1-i)*e;return this.integer&&(n=Math.floor(n)),n}}),t.CtrlRandom}),t(function(t){return window.AudioBuffer&&!AudioBuffer.prototype.copyToChannel&&(AudioBuffer.prototype.copyToChannel=function(t,e,i){var n=this.getChannelData(e);i=i||0;for(var s=0;s<n.length;s++)n[s+i]=t[s]},AudioBuffer.prototype.copyFromChannel=function(t,e,i){var n=this.getChannelData(e);i=i||0;for(var s=0;s<n.length;s++)t[s]=n[s+i]}),t.Buffer=function(){var e=this.optionsObject(arguments,["url","onload","onerror"],t.Buffer.defaults);this._buffer=null,this._reversed=e.reverse,this._xhr=null,e.url instanceof AudioBuffer||e.url instanceof t.Buffer?(this.set(e.url),e.onload&&e.onload(this)):this.isString(e.url)&&this.load(e.url,e.onload,e.onerror)},t.extend(t.Buffer),t.Buffer.defaults={url:void 0,reverse:!1},t.Buffer.prototype.set=function(e){return e instanceof t.Buffer?this._buffer=e.get():this._buffer=e,this},t.Buffer.prototype.get=function(){return this._buffer},t.Buffer.prototype.load=function(e,i,n){return new Promise(function(s,o){this._xhr=t.Buffer.load(e,function(t){this._xhr=null,this.set(t),s(this),i&&i(this)}.bind(this),function(t){this._xhr=null,o(t),n&&n(t)}.bind(this))}.bind(this))},t.Buffer.prototype.dispose=function(){return t.Emitter.prototype.dispose.call(this),this._buffer=null,this._xhr&&(t.Buffer._currentDownloads--,this._xhr.abort(),this._xhr=null),this},Object.defineProperty(t.Buffer.prototype,"loaded",{get:function(){return this.length>0}}),Object.defineProperty(t.Buffer.prototype,"duration",{get:function(){return this._buffer?this._buffer.duration:0}}),Object.defineProperty(t.Buffer.prototype,"length",{get:function(){return this._buffer?this._buffer.length:0}}),Object.defineProperty(t.Buffer.prototype,"numberOfChannels",{get:function(){return this._buffer?this._buffer.numberOfChannels:0}}),t.Buffer.prototype.fromArray=function(t){var e=t[0].length>0,i=e?t.length:1,n=e?t[0].length:t.length,s=this.context.createBuffer(i,n,this.context.sampleRate);e||1!==i||(t=[t]);for(var o=0;o<i;o++)s.copyToChannel(t[o],o);return this._buffer=s,this},t.Buffer.prototype.toMono=function(t){if(this.isNumber(t))this.fromArray(this.toArray(t));else{for(var e=new Float32Array(this.length),i=this.numberOfChannels,n=0;n<i;n++)for(var s=this.toArray(n),o=0;o<s.length;o++)e[o]+=s[o];e=e.map(function(t){return t/i}),this.fromArray(e)}return this},t.Buffer.prototype.toArray=function(t){if(this.isNumber(t))return this.getChannelData(t);if(1===this.numberOfChannels)return this.toArray(0);for(var e=[],i=0;i<this.numberOfChannels;i++)e[i]=this.getChannelData(i);return e},t.Buffer.prototype.getChannelData=function(t){return this._buffer.getChannelData(t)},t.Buffer.prototype.slice=function(e,i){i=this.defaultArg(i,this.duration);for(var n=Math.floor(this.context.sampleRate*this.toSeconds(e)),s=Math.floor(this.context.sampleRate*this.toSeconds(i)),o=[],r=0;r<this.numberOfChannels;r++)o[r]=this.toArray(r).slice(n,s);return(new t.Buffer).fromArray(o)},t.Buffer.prototype._reverse=function(){if(this.loaded)for(var t=0;t<this.numberOfChannels;t++)Array.prototype.reverse.call(this.getChannelData(t));return this},Object.defineProperty(t.Buffer.prototype,"reverse",{get:function(){return this._reversed},set:function(t){this._reversed!==t&&(this._reversed=t,this._reverse())}}),t.Emitter.mixin(t.Buffer),t.Buffer._downloadQueue=[],t.Buffer._currentDownloads=0,t.Buffer.baseUrl="",t.Buffer.load=function(e,i,n){function s(e){if(!n)throw new Error(e);n(e),t.Buffer.emit("error",e)}function o(){for(var e=0,i=0;i<t.Buffer._downloadQueue.length;i++)e+=t.Buffer._downloadQueue[i].progress;t.Buffer.emit("progress",e/t.Buffer._downloadQueue.length)}i=i||t.noOp;var r=new XMLHttpRequest;return r.open("GET",t.Buffer.baseUrl+e,!0),r.responseType="arraybuffer",r.progress=0,t.Buffer._currentDownloads++,t.Buffer._downloadQueue.push(r),r.addEventListener("load",function(){200===r.status?t.context.decodeAudioData(r.response,function(e){r.progress=1,o(),i(e),0===--t.Buffer._currentDownloads&&(t.Buffer._downloadQueue=[],t.Buffer.emit("load"))},function(){s("Tone.Buffer: could not decode audio data: "+e)}):s("Tone.Buffer: could not locate file: "+e)}),r.addEventListener("error",s),r.addEventListener("progress",function(t){t.lengthComputable&&(r.progress=t.loaded/t.total*.95,o())}),r.send(),r},t.Buffer.cancelDownloads=function(){return t.Buffer._downloadQueue.forEach(function(t){t.abort()}),t.Buffer._currentDownloads=0,t.Buffer},t.Buffer.supportsType=function(t){var e=t.split(".");return e=e[e.length-1],""!==document.createElement("audio").canPlayType("audio/"+e)},t.loaded=function(){function e(){t.Buffer.off("load",i),t.Buffer.off("error",n)}var i,n;return new Promise(function(e,s){i=function(){e()},n=function(){s()},t.Buffer.on("load",i),t.Buffer.on("error",n)}).then(e).catch(function(t){throw e(),new Error(t)})},t.Buffer}),t(function(t){return t.Buffers=function(t,e,i){this._buffers={},this.baseUrl=this.defaultArg(i,""),t=this._flattenUrls(t),this._loadingCount=0;for(var n in t)this._loadingCount++,this.add(n,t[n],this._bufferLoaded.bind(this,e))},t.extend(t.Buffers),t.Buffers.prototype.has=function(t){return this._buffers.hasOwnProperty(t)},t.Buffers.prototype.get=function(t){if(this.has(t))return this._buffers[t];throw new Error("Tone.Buffers: no buffer named "+t)},t.Buffers.prototype._bufferLoaded=function(t){0===--this._loadingCount&&t&&t(this)},Object.defineProperty(t.Buffers.prototype,"loaded",{get:function(){var t=!0;for(var e in this._buffers){var i=this.get(e);t=t&&i.loaded}return t}}),t.Buffers.prototype.add=function(e,i,n){return n=this.defaultArg(n,t.noOp),i instanceof t.Buffer?(this._buffers[e]=i,n(this)):i instanceof AudioBuffer?(this._buffers[e]=new t.Buffer(i),n(this)):this.isString(i)&&(this._buffers[e]=new t.Buffer(this.baseUrl+i,n)),this},t.Buffers.prototype._flattenUrls=function(t){var e={};for(var i in t)if(t.hasOwnProperty(i))if(this.isObject(t[i])){var n=this._flattenUrls(t[i]);for(var s in n)n.hasOwnProperty(s)&&(e[i+"."+s]=n[s])}else e[i]=t[i];return e},t.Buffers.prototype.dispose=function(){for(var t in this._buffers)this._buffers[t].dispose();return this._buffers=null,this},t.Buffers}),t(function(t){var e={};return t.prototype.send=function(i,n){e.hasOwnProperty(i)||(e[i]=this.context.createGain()),n=this.defaultArg(n,0);var s=new t.Gain(n,t.Type.Decibels);return this.output.chain(s,e[i]),s},t.prototype.receive=function(t,i){return e.hasOwnProperty(t)||(e[t]=this.context.createGain()),this.isUndef(i)&&(i=this.input),e[t].connect(i),this},t.Context.on("init",function(t){t.Buses?e=t.Buses:(e={},t.Buses=e)}),t}),t(function(t){return t.Draw=function(){this._events=new t.Timeline,this.expiration=.25,this.anticipation=.008,this._boundDrawLoop=this._drawLoop.bind(this)},t.extend(t.Draw),t.Draw.prototype.schedule=function(t,e){return this._events.add({callback:t,time:this.toSeconds(e)}),1===this._events.length&&requestAnimationFrame(this._boundDrawLoop),this},t.Draw.prototype.cancel=function(t){return this._events.cancel(this.toSeconds(t)),this},t.Draw.prototype._drawLoop=function(){for(var e=t.now();this._events.length&&this._events.peek().time-this.anticipation<=e;){var i=this._events.shift();e-i.time<=this.expiration&&i.callback()}this._events.length>0&&requestAnimationFrame(this._boundDrawLoop)},t.Draw=new t.Draw,t.Draw}),t(function(t){t.Listener=function(){var t=this.optionsObject(arguments,["positionX","positionY","positionZ"],e.defaults);this._orientation=[t.forwardX,t.forwardY,t.forwardZ,t.upX,t.upY,t.upZ],this._position=[t.positionX,t.positionY,t.positionZ],this.forwardX=t.forwardX,this.forwardY=t.forwardY,this.forwardZ=t.forwardZ,this.upX=t.upX,this.upY=t.upY,this.upZ=t.upZ,this.positionX=t.positionX,this.positionY=t.positionY,this.positionZ=t.positionZ},t.extend(t.Listener),t.Listener.defaults={positionX:0,positionY:0,positionZ:0,forwardX:0,forwardY:0,forwardZ:1,upX:0,upY:1,upZ:0},t.Listener.prototype._rampTimeConstant=.01,t.Listener.prototype.setPosition=function(t,e,i){if(this.context.listener.positionX){var n=this.now();this.context.listener.positionX.setTargetAtTime(t,n,this._rampTimeConstant),this.context.listener.positionY.setTargetAtTime(e,n,this._rampTimeConstant),this.context.listener.positionZ.setTargetAtTime(i,n,this._rampTimeConstant)}else this.context.listener.setPosition(t,e,i);return this._position=Array.prototype.slice.call(arguments),this},t.Listener.prototype.setOrientation=function(t,e,i,n,s,o){if(this.context.listener.forwardX){var r=this.now();this.context.listener.forwardX.setTargetAtTime(t,r,this._rampTimeConstant),this.context.listener.forwardY.setTargetAtTime(e,r,this._rampTimeConstant),this.context.listener.forwardZ.setTargetAtTime(i,r,this._rampTimeConstant),this.context.listener.upX.setTargetAtTime(n,r,this._rampTimeConstant),this.context.listener.upY.setTargetAtTime(s,r,this._rampTimeConstant),this.context.listener.upZ.setTargetAtTime(o,r,this._rampTimeConstant)}else this.context.listener.setOrientation(t,e,i,n,s,o);return this._orientation=Array.prototype.slice.call(arguments),this},Object.defineProperty(t.Listener.prototype,"positionX",{set:function(t){this._position[0]=t,this.setPosition.apply(this,this._position)},get:function(){return this._position[0]}}),Object.defineProperty(t.Listener.prototype,"positionY",{set:function(t){this._position[1]=t,this.setPosition.apply(this,this._position)},get:function(){return this._position[1]}}),Object.defineProperty(t.Listener.prototype,"positionZ",{set:function(t){this._position[2]=t,this.setPosition.apply(this,this._position)},get:function(){return this._position[2]}}),Object.defineProperty(t.Listener.prototype,"forwardX",{set:function(t){this._orientation[0]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[0]}}),Object.defineProperty(t.Listener.prototype,"forwardY",{set:function(t){this._orientation[1]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[1]}}),Object.defineProperty(t.Listener.prototype,"forwardZ",{set:function(t){this._orientation[2]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[2]}}),Object.defineProperty(t.Listener.prototype,"upX",{set:function(t){this._orientation[3]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[3]}}),Object.defineProperty(t.Listener.prototype,"upY",{set:function(t){this._orientation[4]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[4]}}),Object.defineProperty(t.Listener.prototype,"upZ",{set:function(t){this._orientation[5]=t,this.setOrientation.apply(this,this._orientation)},get:function(){return this._orientation[5]}}),t.Listener.prototype.dispose=function(){return this._orientation=null,this._position=null,this};var e=t.Listener;return t.Listener=new e,t.Context.on("init",function(i){i.Listener instanceof e?t.Listener=i.Listener:t.Listener=new e,i.Listener=t.Listener}),t.Listener}),t(function(t){return!window.hasOwnProperty("OfflineAudioContext")&&window.hasOwnProperty("webkitOfflineAudioContext")&&(window.OfflineAudioContext=window.webkitOfflineAudioContext),t.OfflineContext=function(e,i,n){var s=new OfflineAudioContext(e,i*n,n);t.Context.call(this,s),this._duration=i,this._currentTime=0,this.lookAhead=this.blockTime,this.updateInterval=this.blockTime},t.extend(t.OfflineContext,t.Context),t.OfflineContext.prototype.now=function(){return this._currentTime},t.OfflineContext.prototype._createWorker=function(){return{postMessage:function(){}}},t.OfflineContext.prototype.render=function(){for(;this._duration-this._currentTime>=0;)this.emit("tick"),this._currentTime+=t.prototype.blockTime;return new Promise(function(t){this._context.oncomplete=function(e){t(e.renderedBuffer)},this._context.startRendering()}.bind(this))},t.OfflineContext}),t(function(t){return t.Offline=function(e,i){var n=t.context.sampleRate,s=t.context,o=new t.OfflineContext(2,i,n);t.context=o,e(t.Transport);var r=o.render();return t.context=s,r.then(function(e){return new t.Buffer(e)})},t.Offline}),t(function(t){return t.Effect=function(){this.createInsOuts(1,1);var e=this.optionsObject(arguments,["wet"],t.Effect.defaults);this._dryWet=new t.CrossFade(e.wet),this.wet=this._dryWet.fade,this.effectSend=new t.Gain,this.effectReturn=new t.Gain,this.input.connect(this._dryWet.a),this.input.connect(this.effectSend),this.effectReturn.connect(this._dryWet.b),this._dryWet.connect(this.output),this._readOnly(["wet"])},t.extend(t.Effect),t.Effect.defaults={wet:1},t.Effect.prototype.connectEffect=function(t){return this.effectSend.chain(t,this.effectReturn),this},t.Effect.prototype.dispose=function(){return t.prototype.dispose.call(this),this._dryWet.dispose(),this._dryWet=null,this.effectSend.dispose(),this.effectSend=null,this.effectReturn.dispose(),this.effectReturn=null,this._writable(["wet"]),this.wet=null,this},t.Effect}),t(function(t){return t.AutoFilter=function(){var e=this.optionsObject(arguments,["frequency","baseFrequency","octaves"],t.AutoFilter.defaults);t.Effect.call(this,e),this._lfo=new t.LFO({frequency:e.frequency,amplitude:e.depth}),this.depth=this._lfo.amplitude,this.frequency=this._lfo.frequency,this.filter=new t.Filter(e.filter),this._octaves=0,this.connectEffect(this.filter),this._lfo.connect(this.filter.frequency),this.type=e.type,this._readOnly(["frequency","depth"]),this.octaves=e.octaves,this.baseFrequency=e.baseFrequency},t.extend(t.AutoFilter,t.Effect),t.AutoFilter.defaults={frequency:1,type:"sine",depth:1,baseFrequency:200,octaves:2.6,filter:{type:"lowpass",rolloff:-12,Q:1}},t.AutoFilter.prototype.start=function(t){return this._lfo.start(t),this},t.AutoFilter.prototype.stop=function(t){return this._lfo.stop(t),this},t.AutoFilter.prototype.sync=function(t){return this._lfo.sync(t),this},t.AutoFilter.prototype.unsync=function(){return this._lfo.unsync(),this},Object.defineProperty(t.AutoFilter.prototype,"type",{get:function(){return this._lfo.type},set:function(t){this._lfo.type=t}}),Object.defineProperty(t.AutoFilter.prototype,"baseFrequency",{get:function(){return this._lfo.min},set:function(t){this._lfo.min=this.toFrequency(t),this.octaves=this._octaves}}),Object.defineProperty(t.AutoFilter.prototype,"octaves",{get:function(){return this._octaves},set:function(t){this._octaves=t,this._lfo.max=this.baseFrequency*Math.pow(2,t)}}),t.AutoFilter.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this._lfo.dispose(),this._lfo=null,this.filter.dispose(),this.filter=null,this._writable(["frequency","depth"]),this.frequency=null,this.depth=null,this},t.AutoFilter}),t(function(t){return t.AutoPanner=function(){var e=this.optionsObject(arguments,["frequency"],t.AutoPanner.defaults);t.Effect.call(this,e),this._lfo=new t.LFO({frequency:e.frequency,amplitude:e.depth,min:-1,max:1}),this.depth=this._lfo.amplitude,this._panner=new t.Panner,this.frequency=this._lfo.frequency,this.connectEffect(this._panner),this._lfo.connect(this._panner.pan),this.type=e.type,this._readOnly(["depth","frequency"])},t.extend(t.AutoPanner,t.Effect),t.AutoPanner.defaults={frequency:1,type:"sine",depth:1},t.AutoPanner.prototype.start=function(t){return this._lfo.start(t),this},t.AutoPanner.prototype.stop=function(t){return this._lfo.stop(t),this},t.AutoPanner.prototype.sync=function(t){return this._lfo.sync(t),this},t.AutoPanner.prototype.unsync=function(){return this._lfo.unsync(),this},Object.defineProperty(t.AutoPanner.prototype,"type",{get:function(){return this._lfo.type},set:function(t){this._lfo.type=t}}),t.AutoPanner.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this._lfo.dispose(),this._lfo=null,this._panner.dispose(),this._panner=null,this._writable(["depth","frequency"]),this.frequency=null,this.depth=null,this},t.AutoPanner}),t(function(t){return t.AutoWah=function(){var e=this.optionsObject(arguments,["baseFrequency","octaves","sensitivity"],t.AutoWah.defaults);t.Effect.call(this,e),this.follower=new t.Follower(e.follower),this._sweepRange=new t.ScaleExp(0,1,.5),this._baseFrequency=e.baseFrequency,this._octaves=e.octaves,this._inputBoost=new t.Gain,this._bandpass=new t.Filter({rolloff:-48,frequency:0,Q:e.Q}),this._peaking=new t.Filter(0,"peaking"),this._peaking.gain.value=e.gain,this.gain=this._peaking.gain,this.Q=this._bandpass.Q,this.effectSend.chain(this._inputBoost,this.follower,this._sweepRange),this._sweepRange.connect(this._bandpass.frequency),this._sweepRange.connect(this._peaking.frequency),this.effectSend.chain(this._bandpass,this._peaking,this.effectReturn),this._setSweepRange(),this.sensitivity=e.sensitivity,this._readOnly(["gain","Q"])},t.extend(t.AutoWah,t.Effect),t.AutoWah.defaults={baseFrequency:100,octaves:6,sensitivity:0,Q:2,gain:2,follower:{attack:.3,release:.5}},Object.defineProperty(t.AutoWah.prototype,"octaves",{get:function(){return this._octaves},set:function(t){this._octaves=t,this._setSweepRange()}}),Object.defineProperty(t.AutoWah.prototype,"baseFrequency",{get:function(){return this._baseFrequency},set:function(t){this._baseFrequency=t,this._setSweepRange()}}),Object.defineProperty(t.AutoWah.prototype,"sensitivity",{get:function(){return this.gainToDb(1/this._inputBoost.gain.value)},set:function(t){this._inputBoost.gain.value=1/this.dbToGain(t)}}),t.AutoWah.prototype._setSweepRange=function(){this._sweepRange.min=this._baseFrequency,this._sweepRange.max=Math.min(this._baseFrequency*Math.pow(2,this._octaves),this.context.sampleRate/2)},t.AutoWah.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this.follower.dispose(),this.follower=null,this._sweepRange.dispose(),this._sweepRange=null,this._bandpass.dispose(),this._bandpass=null,this._peaking.dispose(),this._peaking=null,this._inputBoost.dispose(),this._inputBoost=null,this._writable(["gain","Q"]),this.gain=null,this.Q=null,this},t.AutoWah}),t(function(t){return t.BitCrusher=function(){var e=this.optionsObject(arguments,["bits"],t.BitCrusher.defaults);t.Effect.call(this,e);var i=1/Math.pow(2,e.bits-1);this._subtract=new t.Subtract,this._modulo=new t.Modulo(i),this._bits=e.bits,this.effectSend.fan(this._subtract,this._modulo),this._modulo.connect(this._subtract,0,1),this._subtract.connect(this.effectReturn)},t.extend(t.BitCrusher,t.Effect),t.BitCrusher.defaults={bits:4},Object.defineProperty(t.BitCrusher.prototype,"bits",{get:function(){return this._bits},set:function(t){this._bits=t;var e=1/Math.pow(2,t-1);this._modulo.value=e}}),t.BitCrusher.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this._subtract.dispose(),this._subtract=null,this._modulo.dispose(),this._modulo=null,this},t.BitCrusher}),t(function(t){return t.Chebyshev=function(){var e=this.optionsObject(arguments,["order"],t.Chebyshev.defaults);t.Effect.call(this,e),this._shaper=new t.WaveShaper(4096),this._order=e.order,this.connectEffect(this._shaper),this.order=e.order,this.oversample=e.oversample},t.extend(t.Chebyshev,t.Effect),t.Chebyshev.defaults={order:1,oversample:"none"},t.Chebyshev.prototype._getCoefficient=function(t,e,i){return i.hasOwnProperty(e)?i[e]:(i[e]=0===e?0:1===e?t:2*t*this._getCoefficient(t,e-1,i)-this._getCoefficient(t,e-2,i),i[e])},Object.defineProperty(t.Chebyshev.prototype,"order",{get:function(){return this._order},set:function(t){this._order=t;for(var e=new Array(4096),i=e.length,n=0;n<i;++n){var s=2*n/i-1;e[n]=0===s?0:this._getCoefficient(s,t,{})}this._shaper.curve=e}}),Object.defineProperty(t.Chebyshev.prototype,"oversample",{get:function(){return this._shaper.oversample},set:function(t){this._shaper.oversample=t}}),t.Chebyshev.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this._shaper.dispose(),this._shaper=null,this},t.Chebyshev}),t(function(t){return t.StereoEffect=function(){this.createInsOuts(1,1);var e=this.optionsObject(arguments,["wet"],t.Effect.defaults);this._dryWet=new t.CrossFade(e.wet),this.wet=this._dryWet.fade,this._split=new t.Split,this.effectSendL=this._split.left,this.effectSendR=this._split.right,this._merge=new t.Merge,this.effectReturnL=this._merge.left,this.effectReturnR=this._merge.right,this.input.connect(this._split),this.input.connect(this._dryWet,0,0),this._merge.connect(this._dryWet,0,1),this._dryWet.connect(this.output),this._readOnly(["wet"])},t.extend(t.StereoEffect,t.Effect),t.StereoEffect.prototype.dispose=function(){return t.prototype.dispose.call(this),this._dryWet.dispose(),this._dryWet=null,this._split.dispose(),this._split=null,this._merge.dispose(),this._merge=null,this.effectSendL=null,this.effectSendR=null,this.effectReturnL=null,this.effectReturnR=null,this._writable(["wet"]),this.wet=null,this},t.StereoEffect}),t(function(t){return t.FeedbackEffect=function(){var e=this.optionsObject(arguments,["feedback"]);e=this.defaultArg(e,t.FeedbackEffect.defaults),t.Effect.call(this,e),this._feedbackGain=new t.Gain(e.feedback,t.Type.NormalRange),this.feedback=this._feedbackGain.gain,this.effectReturn.chain(this._feedbackGain,this.effectSend),this._readOnly(["feedback"])},t.extend(t.FeedbackEffect,t.Effect),t.FeedbackEffect.defaults={feedback:.125},t.FeedbackEffect.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this._writable(["feedback"]),this._feedbackGain.dispose(),this._feedbackGain=null,this.feedback=null,this},t.FeedbackEffect}),t(function(t){return t.StereoXFeedbackEffect=function(){var e=this.optionsObject(arguments,["feedback"],t.FeedbackEffect.defaults);t.StereoEffect.call(this,e),this.feedback=new t.Signal(e.feedback,t.Type.NormalRange),this._feedbackLR=new t.Gain,this._feedbackRL=new t.Gain,this.effectReturnL.chain(this._feedbackLR,this.effectSendR),this.effectReturnR.chain(this._feedbackRL,this.effectSendL),this.feedback.fan(this._feedbackLR.gain,this._feedbackRL.gain),this._readOnly(["feedback"])},t.extend(t.StereoXFeedbackEffect,t.FeedbackEffect),t.StereoXFeedbackEffect.prototype.dispose=function(){return t.StereoEffect.prototype.dispose.call(this),this._writable(["feedback"]),this.feedback.dispose(),this.feedback=null,this._feedbackLR.dispose(),this._feedbackLR=null,this._feedbackRL.dispose(),this._feedbackRL=null,this},t.StereoXFeedbackEffect}),t(function(t){return t.Chorus=function(){var e=this.optionsObject(arguments,["frequency","delayTime","depth"],t.Chorus.defaults);t.StereoXFeedbackEffect.call(this,e),this._depth=e.depth,this._delayTime=e.delayTime/1e3,this._lfoL=new t.LFO({frequency:e.frequency,min:0,max:1}),this._lfoR=new t.LFO({frequency:e.frequency,min:0,max:1,phase:180}),this._delayNodeL=new t.Delay,this._delayNodeR=new t.Delay,this.frequency=this._lfoL.frequency,this.effectSendL.chain(this._delayNodeL,this.effectReturnL),this.effectSendR.chain(this._delayNodeR,this.effectReturnR),this.effectSendL.connect(this.effectReturnL),this.effectSendR.connect(this.effectReturnR),this._lfoL.connect(this._delayNodeL.delayTime),this._lfoR.connect(this._delayNodeR.delayTime),this._lfoL.start(),this._lfoR.start(),this._lfoL.frequency.connect(this._lfoR.frequency),this.depth=this._depth,this.frequency.value=e.frequency,this.type=e.type,this._readOnly(["frequency"]),this.spread=e.spread},t.extend(t.Chorus,t.StereoXFeedbackEffect),t.Chorus.defaults={frequency:1.5,delayTime:3.5,depth:.7,feedback:.1,type:"sine",spread:180},Object.defineProperty(t.Chorus.prototype,"depth",{get:function(){return this._depth},set:function(t){this._depth=t;var e=this._delayTime*t;this._lfoL.min=Math.max(this._delayTime-e,0),this._lfoL.max=this._delayTime+e,this._lfoR.min=Math.max(this._delayTime-e,0),this._lfoR.max=this._delayTime+e}}),Object.defineProperty(t.Chorus.prototype,"delayTime",{get:function(){return 1e3*this._delayTime},set:function(t){this._delayTime=t/1e3,this.depth=this._depth}}),Object.defineProperty(t.Chorus.prototype,"type",{get:function(){return this._lfoL.type},set:function(t){this._lfoL.type=t,this._lfoR.type=t}}),Object.defineProperty(t.Chorus.prototype,"spread",{get:function(){return this._lfoR.phase-this._lfoL.phase},set:function(t){this._lfoL.phase=90-t/2,this._lfoR.phase=t/2+90}}),t.Chorus.prototype.dispose=function(){return t.StereoXFeedbackEffect.prototype.dispose.call(this),this._lfoL.dispose(),this._lfoL=null,this._lfoR.dispose(),this._lfoR=null,this._delayNodeL.dispose(),this._delayNodeL=null,this._delayNodeR.dispose(),this._delayNodeR=null,this._writable("frequency"),this.frequency=null,this},t.Chorus}),t(function(t){return t.Convolver=function(){var e=this.optionsObject(arguments,["url","onload"],t.Convolver.defaults);t.Effect.call(this,e),this._convolver=this.context.createConvolver(),this._buffer=new t.Buffer,this.isString(e.url)?this._buffer.load(e.url,function(t){this.buffer=t,e.onload()}.bind(this)):e.url&&(this.buffer=e.url,e.onload()),this.connectEffect(this._convolver)},t.extend(t.Convolver,t.Effect),t.Convolver.defaults={onload:t.noOp},Object.defineProperty(t.Convolver.prototype,"buffer",{get:function(){return this._buffer.get()},set:function(t){this._buffer.set(t),this._convolver.buffer=this._buffer.get()}}),t.Convolver.prototype.load=function(t,e){return this._buffer.load(t,function(t){this.buffer=t,e&&e()}.bind(this))},t.Convolver.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this._convolver.disconnect(),this._convolver=null,this._buffer.dispose(),this._buffer=null,this},t.Convolver}),t(function(t){return t.Distortion=function(){var e=this.optionsObject(arguments,["distortion"],t.Distortion.defaults);t.Effect.call(this,e),this._shaper=new t.WaveShaper(4096),this._distortion=e.distortion,this.connectEffect(this._shaper),this.distortion=e.distortion,this.oversample=e.oversample},t.extend(t.Distortion,t.Effect),t.Distortion.defaults={distortion:.4,oversample:"none"},Object.defineProperty(t.Distortion.prototype,"distortion",{get:function(){return this._distortion},set:function(t){this._distortion=t;var e=100*t,i=Math.PI/180;this._shaper.setMap(function(t){return Math.abs(t)<.001?0:(3+e)*t*20*i/(Math.PI+e*Math.abs(t))})}}),Object.defineProperty(t.Distortion.prototype,"oversample",{get:function(){return this._shaper.oversample},set:function(t){this._shaper.oversample=t}}),t.Distortion.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this._shaper.dispose(),this._shaper=null,this},t.Distortion}),t(function(t){return t.FeedbackDelay=function(){var e=this.optionsObject(arguments,["delayTime","feedback"],t.FeedbackDelay.defaults);t.FeedbackEffect.call(this,e),this._delayNode=new t.Delay(e.delayTime),this.delayTime=this._delayNode.delayTime,this.connectEffect(this._delayNode),this._readOnly(["delayTime"])},t.extend(t.FeedbackDelay,t.FeedbackEffect),t.FeedbackDelay.defaults={delayTime:.25},t.FeedbackDelay.prototype.dispose=function(){return t.FeedbackEffect.prototype.dispose.call(this),this._delayNode.dispose(),this._delayNode=null,this._writable(["delayTime"]),this.delayTime=null,this},t.FeedbackDelay}),t(function(t){var e=[1557/44100,1617/44100,1491/44100,1422/44100,1277/44100,1356/44100,1188/44100,1116/44100],i=[225,556,441,341];return t.Freeverb=function(){var n=this.optionsObject(arguments,["roomSize","dampening"],t.Freeverb.defaults);t.StereoEffect.call(this,n),this.roomSize=new t.Signal(n.roomSize,t.Type.NormalRange),this.dampening=new t.Signal(n.dampening,t.Type.Frequency),this._combFilters=[],this._allpassFiltersL=[],this._allpassFiltersR=[];for(var s=0;s<i.length;s++){var o=this.context.createBiquadFilter();o.type="allpass",o.frequency.value=i[s],this._allpassFiltersL.push(o)}for(var r=0;r<i.length;r++){var a=this.context.createBiquadFilter();a.type="allpass",a.frequency.value=i[r],this._allpassFiltersR.push(a)}for(var h=0;h<e.length;h++){var l=new t.LowpassCombFilter(e[h]);h<e.length/2?this.effectSendL.chain(l,this._allpassFiltersL[0]):this.effectSendR.chain(l,this._allpassFiltersR[0]),this.roomSize.connect(l.resonance),this.dampening.connect(l.dampening),this._combFilters.push(l)}this.connectSeries.apply(this,this._allpassFiltersL),this.connectSeries.apply(this,this._allpassFiltersR),this._allpassFiltersL[this._allpassFiltersL.length-1].connect(this.effectReturnL),this._allpassFiltersR[this._allpassFiltersR.length-1].connect(this.effectReturnR),this._readOnly(["roomSize","dampening"])},t.extend(t.Freeverb,t.StereoEffect),t.Freeverb.defaults={roomSize:.7,dampening:3e3},t.Freeverb.prototype.dispose=function(){t.StereoEffect.prototype.dispose.call(this);for(var e=0;e<this._allpassFiltersL.length;e++)this._allpassFiltersL[e].disconnect(),this._allpassFiltersL[e]=null;this._allpassFiltersL=null;for(var i=0;i<this._allpassFiltersR.length;i++)this._allpassFiltersR[i].disconnect(),this._allpassFiltersR[i]=null;this._allpassFiltersR=null;for(var n=0;n<this._combFilters.length;n++)this._combFilters[n].dispose(),this._combFilters[n]=null;return this._combFilters=null,this._writable(["roomSize","dampening"]),this.roomSize.dispose(),this.roomSize=null,this.dampening.dispose(),this.dampening=null,this},t.Freeverb}),t(function(t){var e=[.06748,.06404,.08212,.09004],i=[.773,.802,.753,.733],n=[347,113,37];return t.JCReverb=function(){var s=this.optionsObject(arguments,["roomSize"],t.JCReverb.defaults);t.StereoEffect.call(this,s),this.roomSize=new t.Signal(s.roomSize,t.Type.NormalRange),this._scaleRoomSize=new t.Scale(-.733,.197),this._allpassFilters=[],this._feedbackCombFilters=[];for(var o=0;o<n.length;o++){var r=this.context.createBiquadFilter();r.type="allpass",r.frequency.value=n[o],this._allpassFilters.push(r)}for(var a=0;a<e.length;a++){var h=new t.FeedbackCombFilter(e[a],.1);this._scaleRoomSize.connect(h.resonance),h.resonance.value=i[a],this._allpassFilters[this._allpassFilters.length-1].connect(h),a<e.length/2?h.connect(this.effectReturnL):h.connect(this.effectReturnR),this._feedbackCombFilters.push(h)}this.roomSize.connect(this._scaleRoomSize),this.connectSeries.apply(this,this._allpassFilters),this.effectSendL.connect(this._allpassFilters[0]),this.effectSendR.connect(this._allpassFilters[0]),this._readOnly(["roomSize"])},t.extend(t.JCReverb,t.StereoEffect),t.JCReverb.defaults={roomSize:.5},t.JCReverb.prototype.dispose=function(){t.StereoEffect.prototype.dispose.call(this);for(var e=0;e<this._allpassFilters.length;e++)this._allpassFilters[e].disconnect(),this._allpassFilters[e]=null;this._allpassFilters=null;for(var i=0;i<this._feedbackCombFilters.length;i++)this._feedbackCombFilters[i].dispose(),this._feedbackCombFilters[i]=null;return this._feedbackCombFilters=null,this._writable(["roomSize"]),this.roomSize.dispose(),this.roomSize=null,this._scaleRoomSize.dispose(),this._scaleRoomSize=null,this},t.JCReverb}),t(function(t){return t.MidSideEffect=function(){t.Effect.apply(this,arguments),this._midSideSplit=new t.MidSideSplit,this._midSideMerge=new t.MidSideMerge,this.midSend=this._midSideSplit.mid,this.sideSend=this._midSideSplit.side,this.midReturn=this._midSideMerge.mid,this.sideReturn=this._midSideMerge.side,this.effectSend.connect(this._midSideSplit),this._midSideMerge.connect(this.effectReturn)},t.extend(t.MidSideEffect,t.Effect),t.MidSideEffect.prototype.dispose=function(){return t.Effect.prototype.dispose.call(this),this._midSideSplit.dispose(),this._midSideSplit=null,this._midSideMerge.dispose(),this._midSideMerge=null,this.midSend=null,this.sideSend=null,this.midReturn=null,this.sideReturn=null,this},t.MidSideEffect}),t(function(t){return t.Phaser=function(){var e=this.optionsObject(arguments,["frequency","octaves","baseFrequency"],t.Phaser.defaults);t.StereoEffect.call(this,e),this._lfoL=new t.LFO(e.frequency,0,1),this._lfoR=new t.LFO(e.frequency,0,1),this._lfoR.phase=180,this._baseFrequency=e.baseFrequency,this._octaves=e.octaves,this.Q=new t.Signal(e.Q,t.Type.Positive),this._filtersL=this._makeFilters(e.stages,this._lfoL,this.Q),this._filtersR=this._makeFilters(e.stages,this._lfoR,this.Q),this.frequency=this._lfoL.frequency,this.frequency.value=e.frequency,this.effectSendL.connect(this._filtersL[0]),this.effectSendR.connect(this._filtersR[0]),this._filtersL[e.stages-1].connect(this.effectReturnL),this._filtersR[e.stages-1].connect(this.effectReturnR),this._lfoL.frequency.connect(this._lfoR.frequency),this.baseFrequency=e.baseFrequency,this.octaves=e.octaves,this._lfoL.start(),this._lfoR.start(),this._readOnly(["frequency","Q"])},t.extend(t.Phaser,t.StereoEffect),t.Phaser.defaults={frequency:.5,octaves:3,stages:10,Q:10,baseFrequency:350},t.Phaser.prototype._makeFilters=function(t,e,i){for(var n=new Array(t),s=0;s<t;s++){var o=this.context.createBiquadFilter();o.type="allpass",i.connect(o.Q),e.connect(o.frequency),n[s]=o}return this.connectSeries.apply(this,n),n},Object.defineProperty(t.Phaser.prototype,"octaves",{get:function(){return this._octaves},set:function(t){this._octaves=t;var e=this._baseFrequency*Math.pow(2,t);this._lfoL.max=e,this._lfoR.max=e}}),Object.defineProperty(t.Phaser.prototype,"baseFrequency",{get:function(){return this._baseFrequency},set:function(t){this._baseFrequency=t,this._lfoL.min=t,this._lfoR.min=t,this.octaves=this._octaves}}),t.Phaser.prototype.dispose=function(){t.StereoEffect.prototype.dispose.call(this),this._writable(["frequency","Q"]),this.Q.dispose(),this.Q=null,this._lfoL.dispose(),this._lfoL=null,this._lfoR.dispose(),this._lfoR=null;for(var e=0;e<this._filtersL.length;e++)this._filtersL[e].disconnect(),this._filtersL[e]=null;this._filtersL=null;for(var i=0;i<this._filtersR.length;i++)this._filtersR[i].disconnect(),this._filtersR[i]=null;return this._filtersR=null,this.frequency=null,this},t.Phaser}),t(function(t){return t.PingPongDelay=function(){var e=this.optionsObject(arguments,["delayTime","feedback"],t.PingPongDelay.defaults);t.StereoXFeedbackEffect.call(this,e),this._leftDelay=new t.Delay(0,e.maxDelayTime),this._rightDelay=new t.Delay(0,e.maxDelayTime),this._rightPreDelay=new t.Delay(0,e.maxDelayTime),this.delayTime=new t.Signal(e.delayTime,t.Type.Time),this.effectSendL.chain(this._leftDelay,this.effectReturnL),this.effectSendR.chain(this._rightPreDelay,this._rightDelay,this.effectReturnR),this.delayTime.fan(this._leftDelay.delayTime,this._rightDelay.delayTime,this._rightPreDelay.delayTime),this._feedbackLR.disconnect(),this._feedbackLR.connect(this._rightDelay),this._readOnly(["delayTime"])},t.extend(t.PingPongDelay,t.StereoXFeedbackEffect),t.PingPongDelay.defaults={delayTime:.25,maxDelayTime:1},t.PingPongDelay.prototype.dispose=function(){return t.StereoXFeedbackEffect.prototype.dispose.call(this),this._leftDelay.dispose(),this._leftDelay=null,this._rightDelay.dispose(),this._rightDelay=null,this._rightPreDelay.dispose(),this._rightPreDelay=null,this._writable(["delayTime"]),this.delayTime.dispose(),this.delayTime=null,this},t.PingPongDelay}),t(function(t){return t.PitchShift=function(){var e=this.optionsObject(arguments,["pitch"],t.PitchShift.defaults);t.FeedbackEffect.call(this,e),this._frequency=new t.Signal(0),this._delayA=new t.Delay(0,1),this._lfoA=new t.LFO({min:0,max:.1,type:"sawtooth"}).connect(this._delayA.delayTime),this._delayB=new t.Delay(0,1),this._lfoB=new t.LFO({min:0,max:.1,type:"sawtooth",phase:180}).connect(this._delayB.delayTime),this._crossFade=new t.CrossFade,this._crossFadeLFO=new t.LFO({min:0,max:1,type:"triangle",phase:90}).connect(this._crossFade.fade),this._feedbackDelay=new t.Delay(e.delayTime),this.delayTime=this._feedbackDelay.delayTime,this._readOnly("delayTime"),this._pitch=e.pitch,this._windowSize=e.windowSize,this._delayA.connect(this._crossFade.a),this._delayB.connect(this._crossFade.b),this._frequency.fan(this._lfoA.frequency,this._lfoB.frequency,this._crossFadeLFO.frequency),this.effectSend.fan(this._delayA,this._delayB),this._crossFade.chain(this._feedbackDelay,this.effectReturn);var i=this.now();this._lfoA.start(i),this._lfoB.start(i),this._crossFadeLFO.start(i),this.windowSize=this._windowSize},t.extend(t.PitchShift,t.FeedbackEffect),t.PitchShift.defaults={pitch:0,windowSize:.1,delayTime:0,feedback:0},Object.defineProperty(t.PitchShift.prototype,"pitch",{get:function(){return this._pitch},set:function(t){this._pitch=t;var e=0;t<0?(this._lfoA.min=0,this._lfoA.max=this._windowSize,this._lfoB.min=0,this._lfoB.max=this._windowSize,e=this.intervalToFrequencyRatio(t-1)+1):(this._lfoA.min=this._windowSize,this._lfoA.max=0,this._lfoB.min=this._windowSize,this._lfoB.max=0,e=this.intervalToFrequencyRatio(t)-1),this._frequency.value=e*(1.2/this._windowSize)}}),Object.defineProperty(t.PitchShift.prototype,"windowSize",{get:function(){return this._windowSize},set:function(t){this._windowSize=this.toSeconds(t),this.pitch=this._pitch}}),t.PitchShift.prototype.dispose=function(){return t.FeedbackEffect.prototype.dispose.call(this),this._frequency.dispose(),this._frequency=null,this._delayA.disconnect(),this._delayA=null,this._delayB.disconnect(),this._delayB=null,this._lfoA.dispose(),this._lfoA=null,this._lfoB.dispose(),this._lfoB=null,this._crossFade.dispose(),this._crossFade=null,this._crossFadeLFO.dispose(),this._crossFadeLFO=null,this._writable("delayTime"),this._feedbackDelay.dispose(),this._feedbackDelay=null,this.delayTime=null,this},t.PitchShift}),t(function(t){return t.StereoFeedbackEffect=function(){var e=this.optionsObject(arguments,["feedback"],t.FeedbackEffect.defaults);t.StereoEffect.call(this,e),this.feedback=new t.Signal(e.feedback,t.Type.NormalRange),this._feedbackL=new t.Gain,this._feedbackR=new t.Gain,this.effectReturnL.chain(this._feedbackL,this.effectSendL),this.effectReturnR.chain(this._feedbackR,this.effectSendR),this.feedback.fan(this._feedbackL.gain,this._feedbackR.gain),this._readOnly(["feedback"])},t.extend(t.StereoFeedbackEffect,t.FeedbackEffect),t.StereoFeedbackEffect.prototype.dispose=function(){return t.StereoEffect.prototype.dispose.call(this),this._writable(["feedback"]),this.feedback.dispose(),this.feedback=null,this._feedbackL.dispose(),this._feedbackL=null,this._feedbackR.dispose(),this._feedbackR=null,this},t.StereoFeedbackEffect}),t(function(t){return t.StereoWidener=function(){var e=this.optionsObject(arguments,["width"],t.StereoWidener.defaults);t.MidSideEffect.call(this,e),this.width=new t.Signal(e.width,t.Type.NormalRange),this._midMult=new t.Expr("$0 * ($1 * (1 - $2))"),this._sideMult=new t.Expr("$0 * ($1 * $2)"),this._two=new t.Signal(2),this._two.connect(this._midMult,0,1),this.width.connect(this._midMult,0,2),this._two.connect(this._sideMult,0,1),this.width.connect(this._sideMult,0,2),this.midSend.chain(this._midMult,this.midReturn),this.sideSend.chain(this._sideMult,this.sideReturn),this._readOnly(["width"])},t.extend(t.StereoWidener,t.MidSideEffect),t.StereoWidener.defaults={width:.5},t.StereoWidener.prototype.dispose=function(){return t.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,this},t.StereoWidener}),t(function(t){return t.Tremolo=function(){var e=this.optionsObject(arguments,["frequency","depth"],t.Tremolo.defaults);t.StereoEffect.call(this,e),this._lfoL=new t.LFO({phase:e.spread,min:1,max:0}),this._lfoR=new t.LFO({phase:e.spread,min:1,max:0}),this._amplitudeL=new t.Gain,this._amplitudeR=new t.Gain,this.frequency=new t.Signal(e.frequency,t.Type.Frequency),this.depth=new t.Signal(e.depth,t.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=e.type,this.spread=e.spread},t.extend(t.Tremolo,t.StereoEffect),t.Tremolo.defaults={frequency:10,type:"sine",depth:.5,spread:180},t.Tremolo.prototype.start=function(t){return this._lfoL.start(t),this._lfoR.start(t),this},t.Tremolo.prototype.stop=function(t){return this._lfoL.stop(t),this._lfoR.stop(t),this},t.Tremolo.prototype.sync=function(t){return this._lfoL.sync(t),this._lfoR.sync(t),this},t.Tremolo.prototype.unsync=function(){return this._lfoL.unsync(),this._lfoR.unsync(),this},Object.defineProperty(t.Tremolo.prototype,"type",{get:function(){return this._lfoL.type},set:function(t){this._lfoL.type=t,this._lfoR.type=t}}),Object.defineProperty(t.Tremolo.prototype,"spread",{get:function(){return this._lfoR.phase-this._lfoL.phase},set:function(t){this._lfoL.phase=90-t/2,this._lfoR.phase=t/2+90}}),t.Tremolo.prototype.dispose=function(){return t.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,this},t.Tremolo}),t(function(t){return t.Vibrato=function(){var e=this.optionsObject(arguments,["frequency","depth"],t.Vibrato.defaults);t.Effect.call(this,e),this._delayNode=new t.Delay(0,e.maxDelay),this._lfo=new t.LFO({type:e.type,min:0,max:e.maxDelay,frequency:e.frequency,phase:-90}).start().connect(this._delayNode.delayTime),this.frequency=this._lfo.frequency,this.depth=this._lfo.amplitude,this.depth.value=e.depth,this._readOnly(["frequency","depth"]),this.effectSend.chain(this._delayNode,this.effectReturn)},t.extend(t.Vibrato,t.Effect),t.Vibrato.defaults={maxDelay:.005,frequency:5,depth:.1,type:"sine"},Object.defineProperty(t.Vibrato.prototype,"type",{get:function(){return this._lfo.type},set:function(t){this._lfo.type=t}}),t.Vibrato.prototype.dispose=function(){t.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},t.Vibrato}),t(function(t){return t.Event=function(){var e=this.optionsObject(arguments,["callback","value"],t.Event.defaults);this._loop=e.loop,this.callback=e.callback,this.value=e.value,this._loopStart=this.toTicks(e.loopStart),this._loopEnd=this.toTicks(e.loopEnd),this._state=new t.TimelineState(t.State.Stopped),this._playbackRate=1,this._startOffset=0,this.probability=e.probability,this.humanize=e.humanize,this.mute=e.mute,this.playbackRate=e.playbackRate},t.extend(t.Event),t.Event.defaults={callback:t.noOp,loop:!1,loopEnd:"1m",loopStart:0,playbackRate:1,value:null,probability:1,mute:!1,humanize:!1},t.Event.prototype._rescheduleEvents=function(e){return e=this.defaultArg(e,-1),this._state.forEachFrom(e,function(e){var i;if(e.state===t.State.Started){this.isUndef(e.id)||t.Transport.clear(e.id);var n=e.time+Math.round(this.startOffset/this._playbackRate);if(this._loop){i=1/0,this.isNumber(this._loop)&&(i=this._loop*this._getLoopDuration());var s=this._state.getAfter(n);null!==s&&(i=Math.min(i,s.time-n)),i!==1/0&&(this._state.setStateAtTime(t.State.Stopped,n+i+1),i=t.Time(i,"i"));var o=t.Time(this._getLoopDuration(),"i");e.id=t.Transport.scheduleRepeat(this._tick.bind(this),o,t.TransportTime(n,"i"),i)}else e.id=t.Transport.schedule(this._tick.bind(this),n+"i")}}.bind(this)),this},Object.defineProperty(t.Event.prototype,"state",{get:function(){return this._state.getValueAtTime(t.Transport.ticks)}}),Object.defineProperty(t.Event.prototype,"startOffset",{get:function(){return this._startOffset},set:function(t){this._startOffset=t}}),t.Event.prototype.start=function(e){return e=this.toTicks(e),this._state.getValueAtTime(e)===t.State.Stopped&&(this._state.add({state:t.State.Started,time:e,id:void 0}),this._rescheduleEvents(e)),this},t.Event.prototype.stop=function(e){if(this.cancel(e),e=this.toTicks(e),this._state.getValueAtTime(e)===t.State.Started){this._state.setStateAtTime(t.State.Stopped,e);var i=this._state.getBefore(e),n=e;null!==i&&(n=i.time),this._rescheduleEvents(n)}return this},t.Event.prototype.cancel=function(e){return e=this.defaultArg(e,-1/0),e=this.toTicks(e),this._state.forEachFrom(e,function(e){t.Transport.clear(e.id)}),this._state.cancel(e),this},t.Event.prototype._tick=function(e){if(!this.mute&&this._state.getValueAtTime(t.Transport.ticks)===t.State.Started){if(this.probability<1&&Math.random()>this.probability)return;if(this.humanize){var i=.02;this.isBoolean(this.humanize)||(i=this.toSeconds(this.humanize)),e+=(2*Math.random()-1)*i}this.callback(e,this.value)}},t.Event.prototype._getLoopDuration=function(){return Math.round((this._loopEnd-this._loopStart)/this._playbackRate)},Object.defineProperty(t.Event.prototype,"loop",{get:function(){return this._loop},set:function(t){this._loop=t,this._rescheduleEvents()}}),Object.defineProperty(t.Event.prototype,"playbackRate",{get:function(){return this._playbackRate},set:function(t){this._playbackRate=t,this._rescheduleEvents()}}),Object.defineProperty(t.Event.prototype,"loopEnd",{get:function(){return t.TransportTime(this._loopEnd,"i").toNotation()},set:function(t){this._loopEnd=this.toTicks(t),this._loop&&this._rescheduleEvents()}}),Object.defineProperty(t.Event.prototype,"loopStart",{get:function(){return t.TransportTime(this._loopStart,"i").toNotation()},set:function(t){this._loopStart=this.toTicks(t),this._loop&&this._rescheduleEvents()}}),Object.defineProperty(t.Event.prototype,"progress",{get:function(){if(this._loop){var e=t.Transport.ticks,i=this._state.get(e);if(null!==i&&i.state===t.State.Started){var n=this._getLoopDuration();return(e-i.time)%n/n}return 0}return 0}}),t.Event.prototype.dispose=function(){this.cancel(),this._state.dispose(),this._state=null,this.callback=null,this.value=null},t.Event}),t(function(t){return t.Loop=function(){var e=this.optionsObject(arguments,["callback","interval"],t.Loop.defaults);this._event=new t.Event({callback:this._tick.bind(this),loop:!0,loopEnd:e.interval,playbackRate:e.playbackRate,probability:e.probability}),this.callback=e.callback,this.iterations=e.iterations},t.extend(t.Loop),t.Loop.defaults={interval:"4n",callback:t.noOp,playbackRate:1,iterations:1/0,probability:!0,mute:!1},t.Loop.prototype.start=function(t){return this._event.start(t),this},t.Loop.prototype.stop=function(t){return this._event.stop(t),this},t.Loop.prototype.cancel=function(t){return this._event.cancel(t),this},t.Loop.prototype._tick=function(t){this.callback(t)},Object.defineProperty(t.Loop.prototype,"state",{get:function(){return this._event.state}}),Object.defineProperty(t.Loop.prototype,"progress",{get:function(){return this._event.progress}}),Object.defineProperty(t.Loop.prototype,"interval",{get:function(){return this._event.loopEnd},set:function(t){this._event.loopEnd=t}}),Object.defineProperty(t.Loop.prototype,"playbackRate",{get:function(){return this._event.playbackRate},set:function(t){this._event.playbackRate=t}}),Object.defineProperty(t.Loop.prototype,"humanize",{get:function(){return this._event.humanize},set:function(t){this._event.humanize=t}}),Object.defineProperty(t.Loop.prototype,"probability",{get:function(){return this._event.probability},set:function(t){this._event.probability=t}}),Object.defineProperty(t.Loop.prototype,"mute",{get:function(){return this._event.mute},set:function(t){this._event.mute=t}}),Object.defineProperty(t.Loop.prototype,"iterations",{get:function(){return!0===this._event.loop?1/0:this._event.loop},set:function(t){this._event.loop=t===1/0||t}}),t.Loop.prototype.dispose=function(){this._event.dispose(),this._event=null,this.callback=null},t.Loop}),t(function(t){return t.Part=function(){var e=this.optionsObject(arguments,["callback","events"],t.Part.defaults);this._loop=e.loop,this._loopStart=this.toTicks(e.loopStart),this._loopEnd=this.toTicks(e.loopEnd),this._playbackRate=e.playbackRate,this._probability=e.probability,this._humanize=e.humanize,this._startOffset=0,this._state=new t.TimelineState(t.State.Stopped),this._events=[],this.callback=e.callback,this.mute=e.mute;var i=this.defaultArg(e.events,[]);if(!this.isUndef(e.events))for(var n=0;n<i.length;n++)Array.isArray(i[n])?this.add(i[n][0],i[n][1]):this.add(i[n])},t.extend(t.Part,t.Event),t.Part.defaults={callback:t.noOp,loop:!1,loopEnd:"1m",loopStart:0,playbackRate:1,probability:1,humanize:!1,mute:!1},t.Part.prototype.start=function(e,i){var n=this.toTicks(e);return this._state.getValueAtTime(n)!==t.State.Started&&(i=this._loop?this.defaultArg(i,this._loopStart):this.defaultArg(i,0),i=this.toTicks(i),this._state.add({state:t.State.Started,time:n,offset:i}),this._forEach(function(t){this._startNote(t,n,i)})),this},t.Part.prototype._startNote=function(e,i,n){i-=n,this._loop?e.startOffset>=this._loopStart&&e.startOffset<this._loopEnd?(e.startOffset<n&&(i+=this._getLoopDuration()),e.start(t.TransportTime(i,"i"))):e.startOffset<this._loopStart&&e.startOffset>=n&&(e.loop=!1,e.start(t.TransportTime(i,"i"))):e.startOffset>=n&&e.start(t.TransportTime(i,"i"))},Object.defineProperty(t.Part.prototype,"startOffset",{get:function(){return this._startOffset},set:function(t){this._startOffset=t,this._forEach(function(t){t.startOffset+=this._startOffset})}}),t.Part.prototype.stop=function(e){var i=this.toTicks(e);return this._state.cancel(i),this._state.setStateAtTime(t.State.Stopped,i),this._forEach(function(t){t.stop(e)}),this},t.Part.prototype.at=function(e,i){e=t.TransportTime(e);for(var n=t.Time(1,"i").toSeconds(),s=0;s<this._events.length;s++){var o=this._events[s];if(Math.abs(e.toTicks()-o.startOffset)<n)return this.isUndef(i)||(o.value=i),o}return this.isUndef(i)?null:(this.add(e,i),this._events[this._events.length-1])},t.Part.prototype.add=function(e,i){e.hasOwnProperty("time")&&(i=e,e=i.time),e=this.toTicks(e);var n;return i instanceof t.Event?(n=i,n.callback=this._tick.bind(this)):n=new t.Event({callback:this._tick.bind(this),value:i}),n.startOffset=e,n.set({loopEnd:this.loopEnd,loopStart:this.loopStart,loop:this.loop,humanize:this.humanize,playbackRate:this.playbackRate,probability:this.probability}),this._events.push(n),this._restartEvent(n),this},t.Part.prototype._restartEvent=function(e){this._state.forEach(function(i){i.state===t.State.Started?this._startNote(e,i.time,i.offset):e.stop(t.TransportTime(i.time,"i"))}.bind(this))},t.Part.prototype.remove=function(e,i){e.hasOwnProperty("time")&&(i=e,e=i.time),e=this.toTicks(e);for(var n=this._events.length-1;n>=0;n--){var s=this._events[n];s instanceof t.Part?s.remove(e,i):s.startOffset===e&&(this.isUndef(i)||!this.isUndef(i)&&s.value===i)&&(this._events.splice(n,1),s.dispose())}return this},t.Part.prototype.removeAll=function(){return this._forEach(function(t){t.dispose()}),this._events=[],this},t.Part.prototype.cancel=function(t){return t=this.toTicks(t),this._forEach(function(e){e.cancel(t)}),this._state.cancel(t),this},t.Part.prototype._forEach=function(e,i){i=this.defaultArg(i,this);for(var n=this._events.length-1;n>=0;n--){var s=this._events[n];s instanceof t.Part?s._forEach(e,i):e.call(i,s)}return this},t.Part.prototype._setAll=function(t,e){this._forEach(function(i){i[t]=e})},t.Part.prototype._tick=function(t,e){this.mute||this.callback(t,e)},t.Part.prototype._testLoopBoundries=function(e){e.startOffset<this._loopStart||e.startOffset>=this._loopEnd?e.cancel(0):e.state===t.State.Stopped&&this._restartEvent(e)},Object.defineProperty(t.Part.prototype,"probability",{get:function(){return this._probability},set:function(t){this._probability=t,this._setAll("probability",t)}}),Object.defineProperty(t.Part.prototype,"humanize",{get:function(){return this._humanize},set:function(t){this._humanize=t,this._setAll("humanize",t)}}),Object.defineProperty(t.Part.prototype,"loop",{get:function(){return this._loop},set:function(t){this._loop=t,this._forEach(function(e){e._loopStart=this._loopStart,e._loopEnd=this._loopEnd,e.loop=t,this._testLoopBoundries(e)})}}),Object.defineProperty(t.Part.prototype,"loopEnd",{get:function(){return t.TransportTime(this._loopEnd,"i").toNotation()},set:function(t){this._loopEnd=this.toTicks(t),this._loop&&this._forEach(function(e){e.loopEnd=t,this._testLoopBoundries(e)})}}),Object.defineProperty(t.Part.prototype,"loopStart",{get:function(){return t.TransportTime(this._loopStart,"i").toNotation()},set:function(t){this._loopStart=this.toTicks(t),this._loop&&this._forEach(function(t){t.loopStart=this.loopStart,this._testLoopBoundries(t)})}}),Object.defineProperty(t.Part.prototype,"playbackRate",{get:function(){return this._playbackRate},set:function(t){this._playbackRate=t,this._setAll("playbackRate",t)}}),Object.defineProperty(t.Part.prototype,"length",{get:function(){return this._events.length}}),t.Part.prototype.dispose=function(){return this.removeAll(),this._state.dispose(),this._state=null,this.callback=null,this._events=null,this},t.Part}),t(function(t){return t.Pattern=function(){var e=this.optionsObject(arguments,["callback","values","pattern"],t.Pattern.defaults);t.Loop.call(this,e),this._pattern=new t.CtrlPattern({values:e.values,type:e.pattern,index:e.index})},t.extend(t.Pattern,t.Loop),t.Pattern.defaults={pattern:t.CtrlPattern.Type.Up,values:[]},t.Pattern.prototype._tick=function(t){this.callback(t,this._pattern.value),this._pattern.next()},Object.defineProperty(t.Pattern.prototype,"index",{get:function(){return this._pattern.index},set:function(t){this._pattern.index=t}}),Object.defineProperty(t.Pattern.prototype,"values",{get:function(){return this._pattern.values},set:function(t){this._pattern.values=t}}),Object.defineProperty(t.Pattern.prototype,"value",{get:function(){return this._pattern.value}}),Object.defineProperty(t.Pattern.prototype,"pattern",{get:function(){return this._pattern.type},set:function(t){this._pattern.type=t}}),t.Pattern.prototype.dispose=function(){t.Loop.prototype.dispose.call(this),this._pattern.dispose(),this._pattern=null},t.Pattern}),t(function(t){return t.Sequence=function(){var e=this.optionsObject(arguments,["callback","events","subdivision"],t.Sequence.defaults),i=e.events;if(delete e.events,t.Part.call(this,e),this._subdivision=this.toTicks(e.subdivision),this.isUndef(e.loopEnd)&&!this.isUndef(i)&&(this._loopEnd=i.length*this._subdivision),this._loop=!0,!this.isUndef(i))for(var n=0;n<i.length;n++)this.add(n,i[n])},t.extend(t.Sequence,t.Part),t.Sequence.defaults={subdivision:"4n"},Object.defineProperty(t.Sequence.prototype,"subdivision",{get:function(){return t.Time(this._subdivision,"i").toNotation()}}),t.Sequence.prototype.at=function(e,i){return this.isArray(i)&&this.remove(e),t.Part.prototype.at.call(this,this._indexTime(e),i)},t.Sequence.prototype.add=function(e,i){if(null===i)return this;if(this.isArray(i)){var n=Math.round(this._subdivision/i.length);i=new t.Sequence(this._tick.bind(this),i,t.Time(n,"i"))}return t.Part.prototype.add.call(this,this._indexTime(e),i),this},t.Sequence.prototype.remove=function(e,i){return t.Part.prototype.remove.call(this,this._indexTime(e),i),this},t.Sequence.prototype._indexTime=function(e){return e instanceof t.TransportTime?e:t.TransportTime(e*this._subdivision+this.startOffset,"i")},t.Sequence.prototype.dispose=function(){return t.Part.prototype.dispose.call(this),this},t.Sequence}),t(function(t){return t.PulseOscillator=function(){var e=this.optionsObject(arguments,["frequency","width"],t.Oscillator.defaults);t.Source.call(this,e),this.width=new t.Signal(e.width,t.Type.NormalRange),this._widthGate=new t.Gain,this._sawtooth=new t.Oscillator({frequency:e.frequency,detune:e.detune,type:"sawtooth",phase:e.phase}),this.frequency=this._sawtooth.frequency,this.detune=this._sawtooth.detune,this._thresh=new t.WaveShaper(function(t){return t<0?-1:1}),this._sawtooth.chain(this._thresh,this.output),this.width.chain(this._widthGate,this._thresh),this._readOnly(["width","frequency","detune"])},t.extend(t.PulseOscillator,t.Oscillator),t.PulseOscillator.defaults={frequency:440,detune:0,phase:0,width:.2},t.PulseOscillator.prototype._start=function(t){t=this.toSeconds(t),this._sawtooth.start(t),this._widthGate.gain.setValueAtTime(1,t)},t.PulseOscillator.prototype._stop=function(t){t=this.toSeconds(t),this._sawtooth.stop(t),this._widthGate.gain.setValueAtTime(0,t)},Object.defineProperty(t.PulseOscillator.prototype,"phase",{get:function(){return this._sawtooth.phase},set:function(t){this._sawtooth.phase=t}}),Object.defineProperty(t.PulseOscillator.prototype,"type",{get:function(){return"pulse"}}),Object.defineProperty(t.PulseOscillator.prototype,"partials",{get:function(){return[]}}),t.PulseOscillator.prototype.dispose=function(){return t.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,this},t.PulseOscillator}),t(function(t){return t.PWMOscillator=function(){var e=this.optionsObject(arguments,["frequency","modulationFrequency"],t.PWMOscillator.defaults);t.Source.call(this,e),this._pulse=new t.PulseOscillator(e.modulationFrequency),this._pulse._sawtooth.type="sine",this._modulator=new t.Oscillator({frequency:e.frequency,detune:e.detune,phase:e.phase}),this._scale=new t.Multiply(2),this.frequency=this._modulator.frequency,this.detune=this._modulator.detune,this.modulationFrequency=this._pulse.frequency,this._modulator.chain(this._scale,this._pulse.width),this._pulse.connect(this.output),this._readOnly(["modulationFrequency","frequency","detune"])},t.extend(t.PWMOscillator,t.Oscillator),t.PWMOscillator.defaults={frequency:440,detune:0,phase:0,modulationFrequency:.4},t.PWMOscillator.prototype._start=function(t){t=this.toSeconds(t),this._modulator.start(t),this._pulse.start(t)},t.PWMOscillator.prototype._stop=function(t){t=this.toSeconds(t),this._modulator.stop(t),this._pulse.stop(t)},Object.defineProperty(t.PWMOscillator.prototype,"type",{get:function(){return"pwm"}}),Object.defineProperty(t.PWMOscillator.prototype,"partials",{get:function(){return[]}}),Object.defineProperty(t.PWMOscillator.prototype,"phase",{get:function(){return this._modulator.phase},set:function(t){this._modulator.phase=t}}),t.PWMOscillator.prototype.dispose=function(){return t.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,this},t.PWMOscillator}),t(function(t){return t.FMOscillator=function(){var e=this.optionsObject(arguments,["frequency","type","modulationType"],t.FMOscillator.defaults);t.Source.call(this,e),this._carrier=new t.Oscillator(e.frequency,e.type),this.frequency=new t.Signal(e.frequency,t.Type.Frequency),this.detune=this._carrier.detune,this.detune.value=e.detune,this.modulationIndex=new t.Multiply(e.modulationIndex),this.modulationIndex.units=t.Type.Positive,this._modulator=new t.Oscillator(e.frequency,e.modulationType),this.harmonicity=new t.Multiply(e.harmonicity),this.harmonicity.units=t.Type.Positive,this._modulationNode=new t.Gain(0),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=e.phase,this._readOnly(["modulationIndex","frequency","detune","harmonicity"])},t.extend(t.FMOscillator,t.Oscillator),t.FMOscillator.defaults={frequency:440,detune:0,phase:0,modulationIndex:2,modulationType:"square",harmonicity:1},t.FMOscillator.prototype._start=function(t){t=this.toSeconds(t),this._modulator.start(t),this._carrier.start(t)},t.FMOscillator.prototype._stop=function(t){t=this.toSeconds(t),this._modulator.stop(t),this._carrier.stop(t)},Object.defineProperty(t.FMOscillator.prototype,"type",{get:function(){return this._carrier.type},set:function(t){this._carrier.type=t}}),Object.defineProperty(t.FMOscillator.prototype,"modulationType",{get:function(){return this._modulator.type},set:function(t){this._modulator.type=t}}),Object.defineProperty(t.FMOscillator.prototype,"phase",{get:function(){return this._carrier.phase},set:function(t){this._carrier.phase=t,this._modulator.phase=t}}),Object.defineProperty(t.FMOscillator.prototype,"partials",{get:function(){return this._carrier.partials},set:function(t){this._carrier.partials=t}}),t.FMOscillator.prototype.dispose=function(){return t.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,this},t.FMOscillator}),t(function(t){return t.AMOscillator=function(){var e=this.optionsObject(arguments,["frequency","type","modulationType"],t.AMOscillator.defaults);t.Source.call(this,e),this._carrier=new t.Oscillator(e.frequency,e.type),this.frequency=this._carrier.frequency,this.detune=this._carrier.detune,this.detune.value=e.detune,this._modulator=new t.Oscillator(e.frequency,e.modulationType),this._modulationScale=new t.AudioToGain,this.harmonicity=new t.Multiply(e.harmonicity),this.harmonicity.units=t.Type.Positive,this._modulationNode=new t.Gain(0),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=e.phase,this._readOnly(["frequency","detune","harmonicity"])},t.extend(t.AMOscillator,t.Oscillator),t.AMOscillator.defaults={frequency:440,detune:0,phase:0,modulationType:"square",harmonicity:1},t.AMOscillator.prototype._start=function(t){t=this.toSeconds(t),this._modulator.start(t),this._carrier.start(t)},t.AMOscillator.prototype._stop=function(t){t=this.toSeconds(t),this._modulator.stop(t),this._carrier.stop(t)},Object.defineProperty(t.AMOscillator.prototype,"type",{get:function(){return this._carrier.type},set:function(t){this._carrier.type=t}}),Object.defineProperty(t.AMOscillator.prototype,"modulationType",{get:function(){return this._modulator.type},set:function(t){this._modulator.type=t}}),Object.defineProperty(t.AMOscillator.prototype,"phase",{get:function(){return this._carrier.phase},set:function(t){this._carrier.phase=t,this._modulator.phase=t}}),Object.defineProperty(t.AMOscillator.prototype,"partials",{get:function(){return this._carrier.partials},set:function(t){this._carrier.partials=t}}),t.AMOscillator.prototype.dispose=function(){return t.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,this},t.AMOscillator}),t(function(t){return t.FatOscillator=function(){var e=this.optionsObject(arguments,["frequency","type","spread"],t.FatOscillator.defaults);t.Source.call(this,e),this.frequency=new t.Signal(e.frequency,t.Type.Frequency),this.detune=new t.Signal(e.detune,t.Type.Cents),this._oscillators=[],this._spread=e.spread,this._type=e.type,this._phase=e.phase,this._partials=this.defaultArg(e.partials,[]),this.count=e.count,this._readOnly(["frequency","detune"])},t.extend(t.FatOscillator,t.Oscillator),t.FatOscillator.defaults={frequency:440,detune:0,phase:0,spread:20,count:3,type:"sawtooth"},t.FatOscillator.prototype._start=function(t){t=this.toSeconds(t),this._forEach(function(e){e.start(t)})},t.FatOscillator.prototype._stop=function(t){t=this.toSeconds(t),this._forEach(function(e){e.stop(t)})},t.FatOscillator.prototype._forEach=function(t){for(var e=0;e<this._oscillators.length;e++)t.call(this,this._oscillators[e],e)},Object.defineProperty(t.FatOscillator.prototype,"type",{get:function(){return this._type},set:function(t){this._type=t,this._forEach(function(e){e.type=t})}}),Object.defineProperty(t.FatOscillator.prototype,"spread",{get:function(){return this._spread},set:function(t){if(this._spread=t,this._oscillators.length>1){var e=-t/2,i=t/(this._oscillators.length-1);this._forEach(function(t,n){t.detune.value=e+i*n})}}}),Object.defineProperty(t.FatOscillator.prototype,"count",{get:function(){return this._oscillators.length},set:function(e){if(e=Math.max(e,1),this._oscillators.length!==e){this._forEach(function(t){t.dispose()}),this._oscillators=[];for(var i=0;i<e;i++){var n=new t.Oscillator;this.type===t.Oscillator.Type.Custom?n.partials=this._partials:n.type=this._type,n.phase=this._phase,n.volume.value=-6-e,this.frequency.connect(n.frequency),this.detune.connect(n.detune),n.connect(this.output),this._oscillators[i]=n}this.spread=this._spread,this.state===t.State.Started&&this._forEach(function(t){t.start()})}}}),Object.defineProperty(t.FatOscillator.prototype,"phase",{get:function(){return this._phase},set:function(t){this._phase=t,this._forEach(function(e){e.phase=t})}}),Object.defineProperty(t.FatOscillator.prototype,"partials",{get:function(){return this._partials},set:function(e){this._partials=e,this._type=t.Oscillator.Type.Custom,this._forEach(function(t){t.partials=e})}}),t.FatOscillator.prototype.dispose=function(){return t.Source.prototype.dispose.call(this),this._writable(["frequency","detune"]),this.frequency.dispose(),this.frequency=null,this.detune.dispose(),this.detune=null,this._forEach(function(t){t.dispose()}),this._oscillators=null,this._partials=null,this},t.FatOscillator}),t(function(t){t.OmniOscillator=function(){var e=this.optionsObject(arguments,["frequency","type"],t.OmniOscillator.defaults);t.Source.call(this,e),this.frequency=new t.Signal(e.frequency,t.Type.Frequency),this.detune=new t.Signal(e.detune,t.Type.Cents),this._sourceType=void 0,this._oscillator=null,this.type=e.type,this._readOnly(["frequency","detune"]),this.set(e)},t.extend(t.OmniOscillator,t.Oscillator),t.OmniOscillator.defaults={frequency:440,detune:0,type:"sine",phase:0};var e={Pulse:"PulseOscillator",PWM:"PWMOscillator",Osc:"Oscillator",FM:"FMOscillator",AM:"AMOscillator",Fat:"FatOscillator"};return t.OmniOscillator.prototype._start=function(t){this._oscillator.start(t)},t.OmniOscillator.prototype._stop=function(t){this._oscillator.stop(t)},Object.defineProperty(t.OmniOscillator.prototype,"type",{get:function(){var t="";return this._sourceType===e.FM?t="fm":this._sourceType===e.AM?t="am":this._sourceType===e.Fat&&(t="fat"),t+this._oscillator.type},set:function(t){"fm"===t.substr(0,2)?(this._createNewOscillator(e.FM),this._oscillator.type=t.substr(2)):"am"===t.substr(0,2)?(this._createNewOscillator(e.AM),this._oscillator.type=t.substr(2)):"fat"===t.substr(0,3)?(this._createNewOscillator(e.Fat),this._oscillator.type=t.substr(3)):"pwm"===t?this._createNewOscillator(e.PWM):"pulse"===t?this._createNewOscillator(e.Pulse):(this._createNewOscillator(e.Osc),this._oscillator.type=t)}}),Object.defineProperty(t.OmniOscillator.prototype,"partials",{get:function(){return this._oscillator.partials},set:function(t){this._oscillator.partials=t}}),t.OmniOscillator.prototype.set=function(e,i){return"type"===e?this.type=i:this.isObject(e)&&e.hasOwnProperty("type")&&(this.type=e.type),t.prototype.set.apply(this,arguments),this},t.OmniOscillator.prototype._createNewOscillator=function(e){if(e!==this._sourceType){this._sourceType=e;var i=t[e],n=this.now()+this.blockTime;if(null!==this._oscillator){var s=this._oscillator;s.stop(n),setTimeout(function(){s.dispose(),s=null},1e3*this.blockTime)}this._oscillator=new i,this.frequency.connect(this._oscillator.frequency),this.detune.connect(this._oscillator.detune),this._oscillator.connect(this.output),this.state===t.State.Started&&this._oscillator.start(n)}},Object.defineProperty(t.OmniOscillator.prototype,"phase",{get:function(){return this._oscillator.phase},set:function(t){this._oscillator.phase=t}}),Object.defineProperty(t.OmniOscillator.prototype,"width",{get:function(){if(this._sourceType===e.Pulse)return this._oscillator.width}}),Object.defineProperty(t.OmniOscillator.prototype,"count",{get:function(){if(this._sourceType===e.Fat)return this._oscillator.count},set:function(t){this._sourceType===e.Fat&&(this._oscillator.count=t)}}),Object.defineProperty(t.OmniOscillator.prototype,"spread",{get:function(){if(this._sourceType===e.Fat)return this._oscillator.spread},set:function(t){this._sourceType===e.Fat&&(this._oscillator.spread=t)}}),Object.defineProperty(t.OmniOscillator.prototype,"modulationType",{get:function(){if(this._sourceType===e.FM||this._sourceType===e.AM)return this._oscillator.modulationType},set:function(t){this._sourceType!==e.FM&&this._sourceType!==e.AM||(this._oscillator.modulationType=t)}}),Object.defineProperty(t.OmniOscillator.prototype,"modulationIndex",{get:function(){if(this._sourceType===e.FM)return this._oscillator.modulationIndex}}),Object.defineProperty(t.OmniOscillator.prototype,"harmonicity",{get:function(){if(this._sourceType===e.FM||this._sourceType===e.AM)return this._oscillator.harmonicity}}),Object.defineProperty(t.OmniOscillator.prototype,"modulationFrequency",{get:function(){if(this._sourceType===e.PWM)return this._oscillator.modulationFrequency}}),t.OmniOscillator.prototype.dispose=function(){return t.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,this},t.OmniOscillator}),t(function(t){return t.Instrument=function(e){e=this.defaultArg(e,t.Instrument.defaults),this._volume=this.output=new t.Volume(e.volume),this.volume=this._volume.volume,this._readOnly("volume")},t.extend(t.Instrument),t.Instrument.defaults={volume:0},t.Instrument.prototype.triggerAttack=t.noOp,t.Instrument.prototype.triggerRelease=t.noOp,t.Instrument.prototype.triggerAttackRelease=function(t,e,i,n){return i=this.isUndef(i)?this.now()+this.blockTime:this.toSeconds(i),e=this.toSeconds(e),this.triggerAttack(t,i,n),this.triggerRelease(i+e),this},t.Instrument.prototype.dispose=function(){return t.prototype.dispose.call(this),this._volume.dispose(),this._volume=null,this._writable(["volume"]),this.volume=null,this},t.Instrument}),t(function(t){return t.Monophonic=function(e){e=this.defaultArg(e,t.Monophonic.defaults),t.Instrument.call(this,e),this.portamento=e.portamento},t.extend(t.Monophonic,t.Instrument),t.Monophonic.defaults={portamento:0},t.Monophonic.prototype.triggerAttack=function(t,e,i){return e=this.isUndef(e)?this.now()+this.blockTime:this.toSeconds(e),this._triggerEnvelopeAttack(e,i),this.setNote(t,e),this},t.Monophonic.prototype.triggerRelease=function(t){return t=this.isUndef(t)?this.now()+this.blockTime:this.toSeconds(t),this._triggerEnvelopeRelease(t),this},t.Monophonic.prototype._triggerEnvelopeAttack=function(){},t.Monophonic.prototype._triggerEnvelopeRelease=function(){},t.Monophonic.prototype.setNote=function(t,e){if(e=this.toSeconds(e),this.portamento>0){var i=this.frequency.value;this.frequency.setValueAtTime(i,e);var n=this.toSeconds(this.portamento);this.frequency.exponentialRampToValueAtTime(t,e+n)}else this.frequency.setValueAtTime(t,e);return this},t.Monophonic}),t(function(t){return t.Synth=function(e){e=this.defaultArg(e,t.Synth.defaults),t.Monophonic.call(this,e),this.oscillator=new t.OmniOscillator(e.oscillator),this.frequency=this.oscillator.frequency,this.detune=this.oscillator.detune,this.envelope=new t.AmplitudeEnvelope(e.envelope),this.oscillator.chain(this.envelope,this.output),this.oscillator.start(),this._readOnly(["oscillator","frequency","detune","envelope"])},t.extend(t.Synth,t.Monophonic),t.Synth.defaults={oscillator:{type:"triangle"},envelope:{attack:.005,decay:.1,sustain:.3,release:1}},t.Synth.prototype._triggerEnvelopeAttack=function(t,e){return this.envelope.triggerAttack(t,e),this},t.Synth.prototype._triggerEnvelopeRelease=function(t){return this.envelope.triggerRelease(t),this},t.Synth.prototype.dispose=function(){return t.Monophonic.prototype.dispose.call(this),this._writable(["oscillator","frequency","detune","envelope"]),this.oscillator.dispose(),this.oscillator=null,this.envelope.dispose(),this.envelope=null,this.frequency=null,this.detune=null,this},t.Synth}),t(function(t){return t.AMSynth=function(e){e=this.defaultArg(e,t.AMSynth.defaults),t.Monophonic.call(this,e),this._carrier=new t.Synth,this._carrier.volume.value=-10,this.oscillator=this._carrier.oscillator,this.envelope=this._carrier.envelope.set(e.envelope),this._modulator=new t.Synth,this._modulator.volume.value=-10,this.modulation=this._modulator.oscillator.set(e.modulation),this.modulationEnvelope=this._modulator.envelope.set(e.modulationEnvelope),this.frequency=new t.Signal(440,t.Type.Frequency),this.detune=new t.Signal(e.detune,t.Type.Cents),this.harmonicity=new t.Multiply(e.harmonicity),this.harmonicity.units=t.Type.Positive,this._modulationScale=new t.AudioToGain,this._modulationNode=new t.Gain,this.frequency.connect(this._carrier.frequency),this.frequency.chain(this.harmonicity,this._modulator.frequency),this.detune.fan(this._carrier.detune,this._modulator.detune),this._modulator.chain(this._modulationScale,this._modulationNode.gain),this._carrier.chain(this._modulationNode,this.output),this._readOnly(["frequency","harmonicity","oscillator","envelope","modulation","modulationEnvelope","detune"])},t.extend(t.AMSynth,t.Monophonic),t.AMSynth.defaults={harmonicity:3,detune:0,oscillator:{type:"sine"},envelope:{attack:.01,decay:.01,sustain:1,release:.5},modulation:{type:"square"},modulationEnvelope:{attack:.5,decay:0,sustain:1,release:.5}},t.AMSynth.prototype._triggerEnvelopeAttack=function(t,e){return t=this.toSeconds(t),this.envelope.triggerAttack(t,e),this.modulationEnvelope.triggerAttack(t,e),this},t.AMSynth.prototype._triggerEnvelopeRelease=function(t){return this.envelope.triggerRelease(t),this.modulationEnvelope.triggerRelease(t),this},t.AMSynth.prototype.dispose=function(){return t.Monophonic.prototype.dispose.call(this),this._writable(["frequency","harmonicity","oscillator","envelope","modulation","modulationEnvelope","detune"]),this._carrier.dispose(),this._carrier=null,this._modulator.dispose(),this._modulator=null,this.frequency.dispose(),this.frequency=null,this.detune.dispose(),this.detune=null,this.harmonicity.dispose(),this.harmonicity=null,this._modulationScale.dispose(),this._modulationScale=null,this._modulationNode.dispose(),this._modulationNode=null,this.oscillator=null,this.envelope=null,this.modulationEnvelope=null,this.modulation=null,this},t.AMSynth}),t(function(t){return t.MonoSynth=function(e){e=this.defaultArg(e,t.MonoSynth.defaults),t.Monophonic.call(this,e),this.oscillator=new t.OmniOscillator(e.oscillator),this.frequency=this.oscillator.frequency,this.detune=this.oscillator.detune,this.filter=new t.Filter(e.filter),this.filterEnvelope=new t.FrequencyEnvelope(e.filterEnvelope),this.envelope=new t.AmplitudeEnvelope(e.envelope),this.oscillator.chain(this.filter,this.envelope,this.output),this.oscillator.start(),this.filterEnvelope.connect(this.filter.frequency),this._readOnly(["oscillator","frequency","detune","filter","filterEnvelope","envelope"])},t.extend(t.MonoSynth,t.Monophonic),t.MonoSynth.defaults={frequency:"C4",detune:0,oscillator:{type:"square"},filter:{Q:6,type:"lowpass",rolloff:-24},envelope:{attack:.005,decay:.1,sustain:.9,release:1},filterEnvelope:{attack:.06,decay:.2,sustain:.5,release:2,baseFrequency:200,octaves:7,exponent:2}},t.MonoSynth.prototype._triggerEnvelopeAttack=function(t,e){return this.envelope.triggerAttack(t,e),this.filterEnvelope.triggerAttack(t),this},t.MonoSynth.prototype._triggerEnvelopeRelease=function(t){return this.envelope.triggerRelease(t),this.filterEnvelope.triggerRelease(t),this},t.MonoSynth.prototype.dispose=function(){return t.Monophonic.prototype.dispose.call(this),this._writable(["oscillator","frequency","detune","filter","filterEnvelope","envelope"]),this.oscillator.dispose(),this.oscillator=null,this.envelope.dispose(),this.envelope=null,this.filterEnvelope.dispose(),this.filterEnvelope=null,this.filter.dispose(),this.filter=null,this.frequency=null,this.detune=null,this},t.MonoSynth}),t(function(t){return t.DuoSynth=function(e){e=this.defaultArg(e,t.DuoSynth.defaults),t.Monophonic.call(this,e),this.voice0=new t.MonoSynth(e.voice0),this.voice0.volume.value=-10,this.voice1=new t.MonoSynth(e.voice1),this.voice1.volume.value=-10,this._vibrato=new t.LFO(e.vibratoRate,-50,50),this._vibrato.start(),this.vibratoRate=this._vibrato.frequency,this._vibratoGain=new t.Gain(e.vibratoAmount,t.Type.Positive),this.vibratoAmount=this._vibratoGain.gain,this.frequency=new t.Signal(440,t.Type.Frequency),this.harmonicity=new t.Multiply(e.harmonicity),this.harmonicity.units=t.Type.Positive,this.frequency.connect(this.voice0.frequency),this.frequency.chain(this.harmonicity,this.voice1.frequency),this._vibrato.connect(this._vibratoGain),this._vibratoGain.fan(this.voice0.detune,this.voice1.detune),this.voice0.connect(this.output),this.voice1.connect(this.output),this._readOnly(["voice0","voice1","frequency","vibratoAmount","vibratoRate"])},t.extend(t.DuoSynth,t.Monophonic),t.DuoSynth.defaults={vibratoAmount:.5,vibratoRate:5,harmonicity:1.5,voice0:{volume:-10,portamento:0,oscillator:{type:"sine"},filterEnvelope:{attack:.01,decay:0,sustain:1,release:.5},envelope:{attack:.01,decay:0,sustain:1,release:.5}},voice1:{volume:-10,portamento:0,oscillator:{type:"sine"},filterEnvelope:{attack:.01,decay:0,sustain:1,release:.5},envelope:{attack:.01,decay:0,sustain:1,release:.5}}},t.DuoSynth.prototype._triggerEnvelopeAttack=function(t,e){return t=this.toSeconds(t),this.voice0.envelope.triggerAttack(t,e),this.voice1.envelope.triggerAttack(t,e),this.voice0.filterEnvelope.triggerAttack(t),this.voice1.filterEnvelope.triggerAttack(t),this},t.DuoSynth.prototype._triggerEnvelopeRelease=function(t){return this.voice0.triggerRelease(t),this.voice1.triggerRelease(t),this},t.DuoSynth.prototype.dispose=function(){return t.Monophonic.prototype.dispose.call(this),this._writable(["voice0","voice1","frequency","vibratoAmount","vibratoRate"]),this.voice0.dispose(),this.voice0=null,this.voice1.dispose(),this.voice1=null,this.frequency.dispose(),this.frequency=null,this._vibratoGain.dispose(),this._vibratoGain=null,this._vibrato=null,this.harmonicity.dispose(),this.harmonicity=null,this.vibratoAmount.dispose(),this.vibratoAmount=null,this.vibratoRate=null,this},t.DuoSynth}),t(function(t){return t.FMSynth=function(e){e=this.defaultArg(e,t.FMSynth.defaults),t.Monophonic.call(this,e),this._carrier=new t.Synth(e.carrier),this._carrier.volume.value=-10,this.oscillator=this._carrier.oscillator,this.envelope=this._carrier.envelope.set(e.envelope),this._modulator=new t.Synth(e.modulator),this._modulator.volume.value=-10,this.modulation=this._modulator.oscillator.set(e.modulation),this.modulationEnvelope=this._modulator.envelope.set(e.modulationEnvelope),this.frequency=new t.Signal(440,t.Type.Frequency),this.detune=new t.Signal(e.detune,t.Type.Cents),this.harmonicity=new t.Multiply(e.harmonicity),this.harmonicity.units=t.Type.Positive,this.modulationIndex=new t.Multiply(e.modulationIndex),this.modulationIndex.units=t.Type.Positive,this._modulationNode=new t.Gain(0),this.frequency.connect(this._carrier.frequency),this.frequency.chain(this.harmonicity,this._modulator.frequency),this.frequency.chain(this.modulationIndex,this._modulationNode),this.detune.fan(this._carrier.detune,this._modulator.detune),this._modulator.connect(this._modulationNode.gain),this._modulationNode.connect(this._carrier.frequency),this._carrier.connect(this.output),this._readOnly(["frequency","harmonicity","modulationIndex","oscillator","envelope","modulation","modulationEnvelope","detune"])},t.extend(t.FMSynth,t.Monophonic),t.FMSynth.defaults={harmonicity:3,modulationIndex:10,detune:0,oscillator:{type:"sine"},envelope:{attack:.01,decay:.01,sustain:1,release:.5},modulation:{type:"square"},modulationEnvelope:{attack:.5,decay:0,sustain:1,release:.5}},t.FMSynth.prototype._triggerEnvelopeAttack=function(t,e){return t=this.toSeconds(t),this.envelope.triggerAttack(t,e),this.modulationEnvelope.triggerAttack(t),this},t.FMSynth.prototype._triggerEnvelopeRelease=function(t){return t=this.toSeconds(t),this.envelope.triggerRelease(t),this.modulationEnvelope.triggerRelease(t),this},t.FMSynth.prototype.dispose=function(){return t.Monophonic.prototype.dispose.call(this),this._writable(["frequency","harmonicity","modulationIndex","oscillator","envelope","modulation","modulationEnvelope","detune"]),this._carrier.dispose(),this._carrier=null,this._modulator.dispose(),this._modulator=null,this.frequency.dispose(),this.frequency=null,this.detune.dispose(),this.detune=null,this.modulationIndex.dispose(),this.modulationIndex=null,this.harmonicity.dispose(),this.harmonicity=null,this._modulationNode.dispose(),this._modulationNode=null,this.oscillator=null,this.envelope=null,this.modulationEnvelope=null,this.modulation=null,this},t.FMSynth}),t(function(t){return t.MembraneSynth=function(e){e=this.defaultArg(e,t.MembraneSynth.defaults),t.Instrument.call(this,e),this.oscillator=new t.OmniOscillator(e.oscillator).start(),this.envelope=new t.AmplitudeEnvelope(e.envelope),this.octaves=e.octaves,this.pitchDecay=e.pitchDecay,this.oscillator.chain(this.envelope,this.output),this._readOnly(["oscillator","envelope"])},t.extend(t.MembraneSynth,t.Instrument),t.MembraneSynth.defaults={pitchDecay:.05,octaves:10,oscillator:{type:"sine"},envelope:{attack:.001,decay:.4,sustain:.01,release:1.4,attackCurve:"exponential"}},t.MembraneSynth.prototype.triggerAttack=function(t,e,i){e=this.toSeconds(e),t=this.toFrequency(t);var n=t*this.octaves;return this.oscillator.frequency.setValueAtTime(n,e),this.oscillator.frequency.exponentialRampToValueAtTime(t,e+this.toSeconds(this.pitchDecay)),this.envelope.triggerAttack(e,i),this},t.MembraneSynth.prototype.triggerRelease=function(t){return this.envelope.triggerRelease(t),this},t.MembraneSynth.prototype.dispose=function(){return t.Instrument.prototype.dispose.call(this),this._writable(["oscillator","envelope"]),this.oscillator.dispose(),this.oscillator=null,this.envelope.dispose(),this.envelope=null,this},t.MembraneSynth}),t(function(t){var e=[1,1.483,1.932,2.546,2.63,3.897];return t.MetalSynth=function(i){i=this.defaultArg(i,t.MetalSynth.defaults),t.Instrument.call(this,i),this.frequency=new t.Signal(i.frequency,t.Type.Frequency),this._oscillators=[],this._freqMultipliers=[],this._amplitue=new t.Gain(0).connect(this.output),this._highpass=new t.Filter({type:"highpass",Q:-3.0102999566398125}).connect(this._amplitue),this._octaves=i.octaves,this._filterFreqScaler=new t.Scale(i.resonance,7e3),this.envelope=new t.Envelope({attack:i.envelope.attack,attackCurve:"linear",decay:i.envelope.decay,sustain:0,release:i.envelope.release}).chain(this._filterFreqScaler,this._highpass.frequency),this.envelope.connect(this._amplitue.gain);for(var n=0;n<e.length;n++){var s=new t.FMOscillator({type:"square",modulationType:"square",harmonicity:i.harmonicity,modulationIndex:i.modulationIndex});s.connect(this._highpass).start(0),this._oscillators[n]=s;var o=new t.Multiply(e[n]);this._freqMultipliers[n]=o,this.frequency.chain(o,s.frequency)}this.octaves=i.octaves},t.extend(t.MetalSynth,t.Instrument),t.MetalSynth.defaults={frequency:200,envelope:{attack:.001,decay:1.4,release:.2},harmonicity:5.1,modulationIndex:32,resonance:4e3,octaves:1.5},t.MetalSynth.prototype.triggerAttack=function(t,e){return t=this.toSeconds(t),e=this.defaultArg(e,1),this.envelope.triggerAttack(t,e),this},t.MetalSynth.prototype.triggerRelease=function(t){return t=this.toSeconds(t),this.envelope.triggerRelease(t),this},t.MetalSynth.prototype.triggerAttackRelease=function(t,e,i){return e=this.toSeconds(e),t=this.toSeconds(t),this.triggerAttack(e,i),this.triggerRelease(e+t),this},Object.defineProperty(t.MetalSynth.prototype,"modulationIndex",{get:function(){return this._oscillators[0].modulationIndex.value},set:function(t){for(var e=0;e<this._oscillators.length;e++)this._oscillators[e].modulationIndex.value=t}}),Object.defineProperty(t.MetalSynth.prototype,"harmonicity",{get:function(){return this._oscillators[0].harmonicity.value},set:function(t){for(var e=0;e<this._oscillators.length;e++)this._oscillators[e].harmonicity.value=t}}),Object.defineProperty(t.MetalSynth.prototype,"resonance",{get:function(){return this._filterFreqScaler.min},set:function(t){this._filterFreqScaler.min=t,this.octaves=this._octaves}}),Object.defineProperty(t.MetalSynth.prototype,"octaves",{get:function(){return this._octaves},set:function(t){this._octaves=t,this._filterFreqScaler.max=this._filterFreqScaler.min*Math.pow(2,t)}}),t.MetalSynth.prototype.dispose=function(){t.Instrument.prototype.dispose.call(this);for(var e=0;e<this._oscillators.length;e++)this._oscillators[e].dispose(),this._freqMultipliers[e].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},t.MetalSynth}),t(function(t){return window.AudioBufferSourceNode&&!AudioBufferSourceNode.prototype.start&&(AudioBufferSourceNode.prototype.start=AudioBufferSourceNode.prototype.noteGrainOn,AudioBufferSourceNode.prototype.stop=AudioBufferSourceNode.prototype.noteOff),t.BufferSource=function(){var e=this.optionsObject(arguments,["buffer","onended"],t.BufferSource.defaults);this.onended=e.onended,this._startTime=-1,this._stopTime=-1,this._gainNode=this.output=new t.Gain,this._source=this.context.createBufferSource(),this._source.connect(this._gainNode),this.playbackRate=new t.Param(this._source.playbackRate,t.Type.Positive),this.fadeIn=e.fadeIn,this.fadeOut=e.fadeOut,this._gain=1,this._onendedTimeout=-1,this.isUndef(e.buffer)||(this.buffer=e.buffer),this.loop=e.loop},t.extend(t.BufferSource),t.BufferSource.defaults={onended:t.noOp,fadeIn:0,fadeOut:0},Object.defineProperty(t.BufferSource.prototype,"state",{get:function(){var e=this.now();return-1!==this._startTime&&e>=this._startTime&&e<this._stopTime?t.State.Started:t.State.Stopped}}),t.BufferSource.prototype.start=function(t,e,i,n,s){if(-1!==this._startTime)throw new Error("Tone.BufferSource: can only be started once.");return this.buffer&&(t=this.toSeconds(t),e=this.loop?this.defaultArg(e,this.loopStart):this.defaultArg(e,0),e=this.toSeconds(e),t=this.toSeconds(t),this._source.start(t,e),n=this.defaultArg(n,1),this._gain=n,s=this.isUndef(s)?this.toSeconds(this.fadeIn):this.toSeconds(s),s>0?(this._gainNode.gain.setValueAtTime(0,t),this._gainNode.gain.linearRampToValueAtTime(this._gain,t+s)):this._gainNode.gain.setValueAtTime(n,t),this._startTime=t+s,this.isUndef(i)||(i=this.defaultArg(i,this.buffer.duration-e),i=this.toSeconds(i),this.stop(t+i+s,s))),this},t.BufferSource.prototype.stop=function(t,e){return this.buffer&&(t=this.toSeconds(t),e=this.isUndef(e)?this.toSeconds(this.fadeOut):this.toSeconds(e),this._stopTime=t+e,this._gainNode.gain.cancelScheduledValues(this._startTime+this.sampleTime),e>0?(this._gainNode.gain.setValueAtTime(this._gain,t),this._gainNode.gain.linearRampToValueAtTime(0,t+e),t+=e):this._gainNode.gain.setValueAtTime(0,t),this.isNumber(this._source.playbackState)&&2!==this._source.playbackState||this._source.stop(t),clearTimeout(this._onendedTimeout),this._onendedTimeout=setTimeout(this._onended.bind(this),1e3*(this._stopTime-this.now()))),this},t.BufferSource.prototype._onended=function(){this.onended(this),this.dispose()},Object.defineProperty(t.BufferSource.prototype,"loopStart",{get:function(){return this._source.loopStart},set:function(t){this._source.loopStart=this.toSeconds(t)}}),Object.defineProperty(t.BufferSource.prototype,"loopEnd",{get:function(){return this._source.loopEnd},set:function(t){this._source.loopEnd=this.toSeconds(t)}}),Object.defineProperty(t.BufferSource.prototype,"buffer",{get:function(){return this._source?this._source.buffer:null},set:function(e){e instanceof t.Buffer?this._source.buffer=e.get():this._source.buffer=e}}),Object.defineProperty(t.BufferSource.prototype,"loop",{get:function(){return this._source.loop},set:function(t){this._source.loop=t}}),t.BufferSource.prototype.dispose=function(){return this.onended=null,this._source&&(this._source.disconnect(),this._source=null),this._gainNode&&(this._gainNode.dispose(),this._gainNode=null),this._startTime=-1,this.playbackRate=null,this.output=null,clearTimeout(this._onendedTimeout),this},t.BufferSource}),t(function(t){function e(){for(var e in i)n[e]=(new t.Buffer).fromArray(i[e])}t.Noise=function(){var e=this.optionsObject(arguments,["type"],t.Noise.defaults);t.Source.call(this,e),this._source=null,this._type=e.type,this._playbackRate=e.playbackRate},t.extend(t.Noise,t.Source),t.Noise.defaults={type:"white",playbackRate:1},Object.defineProperty(t.Noise.prototype,"type",{get:function(){return this._type},set:function(e){if(this._type!==e){if(!(e in n))throw new TypeError("Tone.Noise: invalid type: "+e);if(this._type=e,this.state===t.State.Started){var i=this.now()+this.blockTime;this._stop(i),this._start(i)}}}}),Object.defineProperty(t.Noise.prototype,"playbackRate",{get:function(){return this._playbackRate},set:function(t){this._playbackRate=t,this._source&&(this._source.playbackRate.value=t)}}),t.Noise.prototype._start=function(e){var i=n[this._type];this._source=new t.BufferSource(i).connect(this.output),this._source.loop=!0,this._source.playbackRate.value=this._playbackRate,this._source.start(this.toSeconds(e),Math.random()*(i.duration-.001))},t.Noise.prototype._stop=function(t){this._source&&(this._source.stop(this.toSeconds(t)),this._source=null)},t.Noise.prototype.dispose=function(){return t.Source.prototype.dispose.call(this),null!==this._source&&(this._source.disconnect(),this._source=null),this._buffer=null,this};var i={pink:function(){for(var t=[],e=0;e<2;e++){var i=new Float32Array(220500);t[e]=i;var n,s,o,r,a,h,l;n=s=o=r=a=h=l=0;for(var u=0;u<220500;u++){var p=2*Math.random()-1;n=.99886*n+.0555179*p,s=.99332*s+.0750759*p,o=.969*o+.153852*p,r=.8665*r+.3104856*p,a=.55*a+.5329522*p,h=-.7616*h-.016898*p,i[u]=n+s+o+r+a+h+l+.5362*p,i[u]*=.11,l=.115926*p}}return t}(),brown:function(){for(var t=[],e=0;e<2;e++){var i=new Float32Array(220500);t[e]=i;for(var n=0,s=0;s<220500;s++){var o=2*Math.random()-1;i[s]=(n+.02*o)/1.02,n=i[s],i[s]*=3.5}}return t}(),white:function(){for(var t=[],e=0;e<2;e++){var i=new Float32Array(220500);t[e]=i;for(var n=0;n<220500;n++)i[n]=2*Math.random()-1}return t}()},n={};return e(),t.Context.on("init",e),t.Noise}),t(function(t){return t.NoiseSynth=function(e){e=this.defaultArg(e,t.NoiseSynth.defaults),t.Instrument.call(this,e),this.noise=new t.Noise,this.envelope=new t.AmplitudeEnvelope(e.envelope),this.noise.chain(this.envelope,this.output),this.noise.start(),this._readOnly(["noise","envelope"])},t.extend(t.NoiseSynth,t.Instrument),t.NoiseSynth.defaults={noise:{type:"white"},envelope:{attack:.005,decay:.1,sustain:0}},t.NoiseSynth.prototype.triggerAttack=function(t,e){return this.envelope.triggerAttack(t,e),this},t.NoiseSynth.prototype.triggerRelease=function(t){return this.envelope.triggerRelease(t),this},t.NoiseSynth.prototype.triggerAttackRelease=function(t,e,i){return e=this.toSeconds(e),t=this.toSeconds(t),this.triggerAttack(e,i),this.triggerRelease(e+t),this},t.NoiseSynth.prototype.dispose=function(){return t.Instrument.prototype.dispose.call(this),this._writable(["noise","envelope"]),this.noise.dispose(),this.noise=null,this.envelope.dispose(),this.envelope=null,this},t.NoiseSynth}),t(function(t){return t.PluckSynth=function(e){e=this.defaultArg(e,t.PluckSynth.defaults),t.Instrument.call(this,e),this._noise=new t.Noise("pink"),this.attackNoise=e.attackNoise,this._lfcf=new t.LowpassCombFilter({resonance:e.resonance,dampening:e.dampening}),this.resonance=this._lfcf.resonance,this.dampening=this._lfcf.dampening,this._noise.connect(this._lfcf),this._lfcf.connect(this.output),this._readOnly(["resonance","dampening"])},t.extend(t.PluckSynth,t.Instrument),t.PluckSynth.defaults={attackNoise:1,dampening:4e3,resonance:.9},t.PluckSynth.prototype.triggerAttack=function(t,e){t=this.toFrequency(t),e=this.toSeconds(e);var i=1/t;return this._lfcf.delayTime.setValueAtTime(i,e),this._noise.start(e),this._noise.stop(e+i*this.attackNoise),this},t.PluckSynth.prototype.dispose=function(){return t.Instrument.prototype.dispose.call(this),this._noise.dispose(),this._lfcf.dispose(),this._noise=null,this._lfcf=null,this._writable(["resonance","dampening"]),this.dampening=null,this.resonance=null,this},t.PluckSynth}),t(function(t){return t.PolySynth=function(){t.Instrument.call(this);var e=this.optionsObject(arguments,["polyphony","voice"],t.PolySynth.defaults);e=this.defaultArg(e,t.Instrument.defaults),e.polyphony=Math.min(t.PolySynth.MAX_POLYPHONY,e.polyphony),this.voices=new Array(e.polyphony),this._triggers=new Array(e.polyphony),this.detune=new t.Signal(e.detune,t.Type.Cents),this._readOnly("detune");for(var i=0;i<e.polyphony;i++){var n=new e.voice(arguments[2],arguments[3]);this.voices[i]=n,n.connect(this.output),n.hasOwnProperty("detune")&&this.detune.connect(n.detune),this._triggers[i]={release:-1,note:null,voice:n}}this.volume.value=e.volume},t.extend(t.PolySynth,t.Instrument),t.PolySynth.defaults={polyphony:4,volume:0,detune:0,voice:t.Synth},t.PolySynth.prototype.triggerAttack=function(t,e,i){Array.isArray(t)||(t=[t]),e=this.toSeconds(e);for(var n=0;n<t.length;n++){for(var s=t[n],o=this._triggers[0],r=1;r<this._triggers.length;r++)this._triggers[r].release<o.release&&(o=this._triggers[r],r);o.release=1/0,o.note=JSON.stringify(s),o.voice.triggerAttack(s,e,i)}return this},t.PolySynth.prototype.triggerAttackRelease=function(t,e,i,n){if(i=this.toSeconds(i),this.triggerAttack(t,i,n),this.isArray(e)&&this.isArray(t))for(var s=0;s<t.length;s++){var o=e[Math.min(s,e.length-1)];this.triggerRelease(t[s],i+this.toSeconds(o))}else this.triggerRelease(t,i+this.toSeconds(e));return this},t.PolySynth.prototype.triggerRelease=function(t,e){Array.isArray(t)||(t=[t]),e=this.toSeconds(e);for(var i=0;i<t.length;i++)for(var n=JSON.stringify(t[i]),s=0;s<this._triggers.length;s++){var o=this._triggers[s];o.note===n&&o.release>e&&(o.voice.triggerRelease(e),o.release=e)}return this},t.PolySynth.prototype.set=function(t,e,i){for(var n=0;n<this.voices.length;n++)this.voices[n].set(t,e,i);return this},t.PolySynth.prototype.get=function(t){return this.voices[0].get(t)},t.PolySynth.prototype.releaseAll=function(t){t=this.toSeconds(t);for(var e=0;e<this._triggers.length;e++){var i=this._triggers[e];i.release>t&&(i.release=t,i.voice.triggerRelease(t))}return this},t.PolySynth.prototype.dispose=function(){t.Instrument.prototype.dispose.call(this);for(var e=0;e<this.voices.length;e++)this.voices[e].dispose(),this.voices[e]=null;return this._writable("detune"),this.detune.dispose(),this.detune=null,this.voices=null,this._triggers=null,this},t.PolySynth.MAX_POLYPHONY=20,t.PolySynth}),t(function(t){return t.Player=function(e){var i;e instanceof t.Buffer?(e=e.get(),i=t.Player.defaults):i=this.optionsObject(arguments,["url","onload"],t.Player.defaults),t.Source.call(this,i),this._source=null,this.autostart=i.autostart,this._buffer=new t.Buffer({url:i.url,onload:this._onload.bind(this,i.onload),reverse:i.reverse}),e instanceof AudioBuffer&&this._buffer.set(e),this._loop=i.loop,this._loopStart=i.loopStart,this._loopEnd=i.loopEnd,this._playbackRate=i.playbackRate,this.retrigger=i.retrigger},t.extend(t.Player,t.Source),t.Player.defaults={onload:t.noOp,playbackRate:1,loop:!1,autostart:!1,loopStart:0,loopEnd:0,retrigger:!1,reverse:!1},t.Player.prototype.load=function(t,e){return this._buffer.load(t,this._onload.bind(this,e))},t.Player.prototype._onload=function(e){e=this.defaultArg(e,t.noOp),e(this),this.autostart&&this.start()},t.Player.prototype._start=function(e,i,n){if(!this._buffer.loaded)throw Error("Tone.Player: tried to start Player before the buffer was loaded");if(i=this._loop?this.defaultArg(i,this._loopStart):this.defaultArg(i,0),i=this.toSeconds(i),n=this.defaultArg(n,Math.max(this._buffer.duration-i,0)),n=this.toSeconds(n),e=this.toSeconds(e),this._source=this.context.createBufferSource(),this._source.buffer=this._buffer.get(),this._loop?(this._source.loop=this._loop,this._source.loopStart=this.toSeconds(this._loopStart),this._source.loopEnd=this.toSeconds(this._loopEnd)):this._synced||this._state.setStateAtTime(t.State.Stopped,e+n),this._source.playbackRate.value=this._playbackRate,this._source.connect(this.output),this._loop){var s=this._source.loopEnd||this._buffer.duration,o=this._source.loopStart,r=s-o;if(i>s)for(;i>s;)i-=r;this._source.start(e,i)}else this._source.start(e,i,n);return this},t.Player.prototype._stop=function(t){return this._source&&(this._source.stop(this.toSeconds(t)),this._source=null),this},t.Player.prototype.seek=function(e,i){return i=this.toSeconds(i),this._state.getValueAtTime(i)===t.State.Started&&(e=this.toSeconds(e),this._stop(i),this._start(i,e)),this},t.Player.prototype.setLoopPoints=function(t,e){return this.loopStart=t,this.loopEnd=e,this},Object.defineProperty(t.Player.prototype,"loopStart",{get:function(){return this._loopStart},set:function(t){this._loopStart=t,this._source&&(this._source.loopStart=this.toSeconds(t))}}),Object.defineProperty(t.Player.prototype,"loopEnd",{get:function(){return this._loopEnd},set:function(t){this._loopEnd=t,this._source&&(this._source.loopEnd=this.toSeconds(t))}}),Object.defineProperty(t.Player.prototype,"buffer",{get:function(){return this._buffer},set:function(t){this._buffer.set(t)}}),Object.defineProperty(t.Player.prototype,"loop",{get:function(){return this._loop},set:function(t){this._loop=t,this._source&&(this._source.loop=t)}}),Object.defineProperty(t.Player.prototype,"playbackRate",{get:function(){return this._playbackRate},set:function(t){this._playbackRate=t,this._source&&(this._source.playbackRate.value=t)}}),Object.defineProperty(t.Player.prototype,"reverse",{get:function(){return this._buffer.reverse},set:function(t){this._buffer.reverse=t}}),t.Player.prototype.dispose=function(){return t.Source.prototype.dispose.call(this),null!==this._source&&(this._source.disconnect(),this._source=null),this._buffer.dispose(),this._buffer=null,this},t.Player}),t(function(t){return t.Sampler=function(){var e=this.optionsObject(arguments,["url","onload"],t.Sampler.defaults);t.Instrument.call(this,e),this.player=new t.Player(e.url,e.onload),this.player.retrigger=!0,this.envelope=new t.AmplitudeEnvelope(e.envelope),this.player.chain(this.envelope,this.output),this._readOnly(["player","envelope"]),this.loop=e.loop,this.reverse=e.reverse},t.extend(t.Sampler,t.Instrument),t.Sampler.defaults={onload:t.noOp,loop:!1,reverse:!1,envelope:{attack:.001,decay:0,sustain:1,release:.1}},t.Sampler.prototype.triggerAttack=function(t,e,i){return e=this.toSeconds(e),t=this.defaultArg(t,0),this.player.playbackRate=this.intervalToFrequencyRatio(t),this.player.start(e),this.envelope.triggerAttack(e,i),this},t.Sampler.prototype.triggerRelease=function(t){return t=this.toSeconds(t),this.envelope.triggerRelease(t),this.player.stop(this.toSeconds(this.envelope.release)+t),this},Object.defineProperty(t.Sampler.prototype,"loop",{get:function(){return this.player.loop},set:function(t){this.player.loop=t}}),Object.defineProperty(t.Sampler.prototype,"reverse",{get:function(){return this.player.reverse},set:function(t){this.player.reverse=t}}),Object.defineProperty(t.Sampler.prototype,"buffer",{get:function(){return this.player.buffer},set:function(t){this.player.buffer=t}}),t.Sampler.prototype.dispose=function(){return t.Instrument.prototype.dispose.call(this),this._writable(["player","envelope"]),this.player.dispose(),this.player=null,this.envelope.dispose(),this.envelope=null,this},t.Sampler}),t(function(t){return t.GainToAudio=function(){this._norm=this.input=this.output=new t.WaveShaper(function(t){return 2*Math.abs(t)-1})},t.extend(t.GainToAudio,t.SignalBase),t.GainToAudio.prototype.dispose=function(){return t.prototype.dispose.call(this),this._norm.dispose(),this._norm=null,this},t.GainToAudio}),t(function(t){return t.Normalize=function(e,i){this._inputMin=this.defaultArg(e,0),this._inputMax=this.defaultArg(i,1),this._sub=this.input=new t.Add(0),this._div=this.output=new t.Multiply(1),this._sub.connect(this._div),this._setRange()},t.extend(t.Normalize,t.SignalBase),Object.defineProperty(t.Normalize.prototype,"min",{get:function(){return this._inputMin},set:function(t){this._inputMin=t,this._setRange()}}),Object.defineProperty(t.Normalize.prototype,"max",{get:function(){return this._inputMax},set:function(t){this._inputMax=t,this._setRange()}}),t.Normalize.prototype._setRange=function(){this._sub.value=-this._inputMin,this._div.value=1/(this._inputMax-this._inputMin)},t.Normalize.prototype.dispose=function(){return t.prototype.dispose.call(this),this._sub.dispose(),this._sub=null,this._div.dispose(),this._div=null,this},t.Normalize}),t(function(t){return t.MultiPlayer=function(){var e=this.optionsObject(arguments,["urls","onload"],t.MultiPlayer.defaults);e.urls instanceof t.Buffers?this.buffers=e.urls:this.buffers=new t.Buffers(e.urls,e.onload),this._activeSources={},this.fadeIn=e.fadeIn,this.fadeOut=e.fadeOut,this._volume=this.output=new t.Volume(e.volume),this.volume=this._volume.volume,this._readOnly("volume"),this._volume.output.output.channelCount=2,this._volume.output.output.channelCountMode="explicit",this.mute=e.mute},t.extend(t.MultiPlayer,t.Source),t.MultiPlayer.defaults={onload:t.noOp,fadeIn:0,fadeOut:0},t.MultiPlayer.prototype._makeSource=function(e){var i;this.isString(e)||this.isNumber(e)?i=this.buffers.get(e).get():e instanceof t.Buffer?i=e.get():e instanceof AudioBuffer&&(i=e);var n=new t.BufferSource(i).connect(this.output);return this._activeSources.hasOwnProperty(e)||(this._activeSources[e]=[]),this._activeSources[e].push(n),n},t.MultiPlayer.prototype.start=function(t,e,i,n,s,o){e=this.toSeconds(e);var r=this._makeSource(t);return r.start(e,i,n,this.defaultArg(o,1),this.fadeIn),n&&r.stop(e+this.toSeconds(n),this.fadeOut),s=this.defaultArg(s,0),r.playbackRate.value=this.intervalToFrequencyRatio(s),this},t.MultiPlayer.prototype.startLoop=function(t,e,i,n,s,o,r){e=this.toSeconds(e);var a=this._makeSource(t);return a.loop=!0,a.loopStart=this.toSeconds(this.defaultArg(n,0)),a.loopEnd=this.toSeconds(this.defaultArg(s,0)),a.start(e,i,void 0,this.defaultArg(r,1),this.fadeIn),o=this.defaultArg(o,0),a.playbackRate.value=this.intervalToFrequencyRatio(o),this},t.MultiPlayer.prototype.stop=function(t,e){if(!this._activeSources[t]||!this._activeSources[t].length)throw new Error("Tone.MultiPlayer: cannot stop a buffer that hasn't been started or is already stopped");return e=this.toSeconds(e),this._activeSources[t].shift().stop(e,this.fadeOut),this},t.MultiPlayer.prototype.stopAll=function(t){t=this.toSeconds(t);for(var e in this._activeSources)for(var i=this._activeSources[e],n=0;n<i.length;n++)i[n].stop(t);return this},t.MultiPlayer.prototype.add=function(t,e,i){return this.buffers.add(t,e,i),this},Object.defineProperty(t.MultiPlayer.prototype,"state",{get:function(){return this._activeSources.length>0?t.State.Started:t.State.Stopped}}),Object.defineProperty(t.MultiPlayer.prototype,"mute",{get:function(){return this._volume.mute},set:function(t){this._volume.mute=t}}),t.MultiPlayer.prototype.dispose=function(){t.prototype.dispose.call(this),this._volume.dispose(),this._volume=null,this._writable("volume"),this.volume=null;for(var e in this._activeSources)this._activeSources[e].forEach(function(t){t.dispose()});return this.buffers.dispose(),this.buffers=null,this._activeSources=null,this},t.MultiPlayer}),t(function(t){return t.GrainPlayer=function(){var e=this.optionsObject(arguments,["url","onload"],t.GrainPlayer.defaults);t.Source.call(this),this.buffer=new t.Buffer(e.url,e.onload),this._player=(new t.MultiPlayer).connect(this.output),this._clock=new t.Clock(this._tick.bind(this),1),this._loopStart=0,this._loopEnd=0,this._playbackRate=e.playbackRate,this._grainSize=e.grainSize,this._overlap=e.overlap,this.detune=e.detune,this.drift=e.drift,this.overlap=e.overlap,this.loop=e.loop,this.playbackRate=e.playbackRate,this.grainSize=e.grainSize,this.loopStart=e.loopStart,this.loopEnd=e.loopEnd,this.reverse=e.reverse},t.extend(t.GrainPlayer,t.Source),t.GrainPlayer.defaults={onload:t.noOp,overlap:.1,grainSize:.2,drift:0,playbackRate:1,detune:0,loop:!1,loopStart:0,loopEnd:0,reverse:!1},t.GrainPlayer.prototype._start=function(t,e,i){e=this.defaultArg(e,0),e=this.toSeconds(e),t=this.toSeconds(t),this._offset=e,this._clock.start(t),this._player.volume.setValueAtTime(0,t),i&&this._stop(t+this.toSeconds(i))},t.GrainPlayer.prototype._stop=function(t){this._clock.stop(t),this._player.volume.cancelScheduledValues(t),this._player.volume.setValueAtTime(-1/0,t)},t.GrainPlayer.prototype._tick=function(t){var e=this.buffer.duration;this.loop&&this._loopEnd>0&&(e=this._loopEnd);var i=(2*Math.random()-1)*this.drift,n=this._offset-this._overlap+i,s=this.detune/100;n=Math.max(n,0),n=Math.min(n,e);var o=this._player.fadeIn;if(this.loop&&this._offset>e){var r=this._offset-e;this._player.start(this.buffer,t,n,r+this._overlap,s),n=this._offset%e,this._offset=this._loopStart,this._player.fadeIn=0,this._player.start(this.buffer,t+r,this._offset,n+this._overlap,s)}else this._offset>e?this.stop(t):(0===n&&(this._player.fadeIn=0),this._player.start(this.buffer,t,n,this.grainSize+this._overlap,s));this._player.fadeIn=o;var a=this._clock._nextTick-t;this._offset+=a*this._playbackRate},t.GrainPlayer.prototype.scrub=function(t,e){return this._offset=this.toSeconds(t),this._tick(this.toSeconds(e)),this},Object.defineProperty(t.GrainPlayer.prototype,"playbackRate",{get:function(){return this._playbackRate},set:function(t){this._playbackRate=t,this.grainSize=this._grainSize}}),Object.defineProperty(t.GrainPlayer.prototype,"loopStart",{get:function(){return this._loopStart},set:function(t){this._loopStart=this.toSeconds(t)}}),Object.defineProperty(t.GrainPlayer.prototype,"loopEnd",{get:function(){return this._loopEnd},set:function(t){this._loopEnd=this.toSeconds(t)}}),Object.defineProperty(t.GrainPlayer.prototype,"reverse",{get:function(){return this.buffer.reverse},set:function(t){this.buffer.reverse=t}}),Object.defineProperty(t.GrainPlayer.prototype,"grainSize",{get:function(){return this._grainSize},set:function(t){this._grainSize=this.toSeconds(t),this._clock.frequency.value=this._playbackRate/this._grainSize}}),Object.defineProperty(t.GrainPlayer.prototype,"overlap",{get:function(){return this._overlap},set:function(t){t=this.toSeconds(t),this._overlap=t,this._overlap<0?(this._player.fadeIn=.01,this._player.fadeOut=.01):(this._player.fadeIn=t,this._player.fadeOut=t)}}),t.GrainPlayer.prototype.dispose=function(){return t.Source.prototype.dispose.call(this),this.buffer.dispose(),this.buffer=null,this._player.dispose(),this._player=null,this._clock.dispose(),this._clock=null,this},t.GrainPlayer}),t(function(t){return t.UserMedia=function(){var e=this.optionsObject(arguments,["volume"],t.UserMedia.defaults);this._mediaStream=null,this._stream=null,this._device=null,this._volume=this.output=new t.Volume(e.volume),this.volume=this._volume.volume,this._readOnly("volume"),this.mute=e.mute},t.extend(t.UserMedia),t.UserMedia.defaults={volume:0,mute:!1},t.UserMedia.prototype.open=function(t){return t=this.defaultArg(t,"default"),this.enumerateDevices().then(function(e){var i;if(this.isNumber(t)?i=e[t]:(i=e.find(function(e){return e.label===t||e.deviceId===t}))||(i=e[0]),!i)throw new Error("Tone.UserMedia: no matching audio inputs.");this._device=i;var n={audio:{deviceId:i.deviceId,echoCancellation:!1,sampleRate:this.context.sampleRate}};return navigator.mediaDevices.getUserMedia(n).then(function(t){return this._stream||(this._stream=t,this._mediaStream=this.context.createMediaStreamSource(t),this._mediaStream.connect(this.output)),this}.bind(this))}.bind(this))},t.UserMedia.prototype.close=function(){return this._stream&&(this._stream.getAudioTracks().forEach(function(t){t.stop()}),this._stream=null,this._mediaStream.disconnect(),this._mediaStream=null),this._device=null,this},t.UserMedia.prototype.enumerateDevices=function(){return navigator.mediaDevices.enumerateDevices().then(function(t){return t.filter(function(t){return"audioinput"===t.kind})})},Object.defineProperty(t.UserMedia.prototype,"state",{get:function(){return this._stream&&this._stream.active?t.State.Started:t.State.Stopped}}),Object.defineProperty(t.UserMedia.prototype,"deviceId",{get:function(){if(this._device)return this._device.deviceId}}),Object.defineProperty(t.UserMedia.prototype,"groupId",{get:function(){if(this._device)return this._device.groupId}}),Object.defineProperty(t.UserMedia.prototype,"label",{get:function(){if(this._device)return this._device.label}}),Object.defineProperty(t.UserMedia.prototype,"mute",{get:function(){return this._volume.mute},set:function(t){this._volume.mute=t}}),t.UserMedia.prototype.dispose=function(){return t.prototype.dispose.call(this),this.close(),this._writable("volume"),this._volume.dispose(),this._volume=null,this.volume=null,this},Object.defineProperty(t.UserMedia,"supported",{get:function(){return!t.prototype.isUndef(navigator.mediaDevices)&&t.prototype.isFunction(navigator.mediaDevices.getUserMedia)}}),t.UserMedia}),e})},function(t,e,i){"use strict";function n(t,e,i,n,s,o,r){return e+i*Math.cos(2*Math.PI*(n*t+s))*r+o}function s(t,e,i){e=e||0,i=i||1;for(var s=void 0,o=void 0,a=void 0,h=void 0,l=[],u=0;u<3;u++)s=r[0][u],o=r[1][u],a=r[2][u],h=r[3][u],l[u]=Math.round(255*n(t,s,o,a,h,e,i));return"rgb("+l+")"}Object.defineProperty(e,"__esModule",{value:!0});var o=[[[.5,.5,.5],[.5,.5,.5],[1,1,1],[0,.33,.67]],[[.5,.5,.5],[.5,.5,.5],[1,1,1],[0,.1,.2]],[[.5,.5,.5],[.5,.5,.5],[1,1,1],[.3,.2,.2]],[[.5,.5,.5],[.5,.5,.5],[1,1,.5],[.8,.9,.3]],[[.5,.5,.5],[.5,.5,.5],[1,.7,.4],[0,.15,.2]],[[.5,.5,.5],[.5,.5,.5],[2,1,0],[.5,.2,.25]],[[.8,.5,.4],[.2,.4,.2],[2,1,1],[0,.25,.25]]],r=o[5];e.default=s},function(t,e,i){"use strict";function n(t){if(t.altKey||t.ctrlKey||t.metaKey)return void t.stopPropagation();if(document.activeElement instanceof HTMLInputElement&&t.keyCode in r)return void t.stopPropagation();if(t.keyCode in o){var e=o[t.keyCode];t.shiftKey&&(e+=a.length),e-=7,h(e)}}function s(t){h=t}Object.defineProperty(e,"__esModule",{value:!0});var o={},r={},a="zxcvbnmasdfghjklqwertyuiop",h=function(){};a.toUpperCase().split("").map(function(t,e){o[t.charCodeAt(0)]=e}),"1234567890".split("").map(function(t,e){o[t.charCodeAt(0)]=e+a.length,r[t.charCodeAt(0)]=!0}),window.addEventListener("keydown",n,!0),e.default={listen:s}},function(t,e,i){"use strict";function n(t){return t&&t.__esModule?t:{default:t}}function s(t,e,i){return t<e?e:t<i?t:i}function o(t){return t[Math.floor(Math.random()*t.length)]}function r(t,e){return t-e*Math.floor(t/e)}function a(t){return function(e){e.preventDefault(),t(e.touches[0])}}function h(t){if(_){var e=document.createElement("div"),i=document.createElement("div");i.innerHTML="Tap to start - please unmute your phone",Object.assign(e.style,{display:"block",position:"absolute",width:"100%",height:"100%",zIndex:"10000",top:"0px",left:"0px",backgroundColor:"rgba(0, 0, 0, 0.8)"}),Object.assign(i.style,{display:"block",position:"absolute",left:"50%",top:"50%",padding:"20px",backgroundColor:"#7F33ED",color:"white",fontFamily:"monospace",borderRadius:"3px",transform:"translate3D(-50%,-50%,0)",textAlign:"center",lineHeight:"1.5",width:"150px"}),e.appendChild(i),document.body.appendChild(e),c.default.setContext(u.default.context),c.default.on(i),c.default.onStarted(function(i){e.remove(),t()})}else t()}Object.defineProperty(e,"__esModule",{value:!0}),e.requestAudioContext=e.firstTouch=e.browser=e.clamp=e.mod=e.choice=void 0;var l=i(0),u=n(l),p=i(5),c=n(p),f=navigator.userAgent.match(/iPhone/i)||navigator.userAgent.match(/iPod/i),d=navigator.userAgent.match(/iPad/i),y=navigator.userAgent.match(/Android/i),_=f||d||y,m=!_;document.body.classList.add(_?"mobile":"desktop");var v={isIphone:f,isIpad:d,isMobile:_,isDesktop:m};e.choice=o,e.mod=r,e.clamp=s,e.browser=v,e.firstTouch=a,e.requestAudioContext=h},function(t,e,i){"use strict";function n(t){return t&&t.__esModule?t:{default:t}}function s(t){if(g.length){w=Math.max(T,(T+w*(O-1))/O);var e=.94*w+.02,i=Math.floor(e*g.length+Math.cos(t)),n=Math.max((g[i]||0)*m+.25*Math.sin(17*t/7),0);S.start("applause",t,n,4*m,0,w)}}function o(t){P=!0,x.x=t.pageX/window.innerWidth,x.y=t.pageY/window.innerHeight}function r(t){var e=t.pageX/window.innerWidth,i=t.pageY/window.innerHeight,n=x.x-e,s=x.y-i,o=Math.sqrt(n*n+s*s);P&&(T=Math.min(.999,T+.1*o),w=Math.min(.999,T),.999==T&&(T-=.4*Math.random()),.999==w&&(w-=.3*Math.random()),A.fillStyle=(0,d.default)(T),A.beginPath(),A.arc(e*window.innerWidth,i*window.innerHeight,500*o,0,2*Math.PI),A.fill()),x.x=e,x.y=i}function a(t){P=!1,T=0}function h(t){requestAnimationFrame(h),A.save(),A.fillStyle=(0,d.default)(w/2),A.globalAlpha=.4,A.rotate(.005),A.drawImage(k,-5,-5,k.width+10,k.height+10),A.rotate(-.005),A.globalAlpha=.05*Math.random(),A.fillRect(0,0,window.innerWidth,window.innerHeight),A.fillStyle="#fff",A.fillRect(0,0,window.innerWidth,window.innerHeight),A.restore()}function l(){b&&setTimeout(l,100),A.font="100px "+(0,y.choice)(E),A.fillStyle=(0,d.default)(Math.random()),A.fillText("LOADING!",window.innerWidth/2-250,window.innerHeight/2)}var u=i(0),p=n(u),c=i(2),f=(n(c),i(1)),d=n(f),y=i(3),_=new p.default.Compressor(-30,3).toMaster(),m=.5,v=44100*m;(0,y.requestAudioContext)(function(){new p.default.Clock(s,1/m).start(),console.log("ready")});var g=[],b=!0,S=new p.default.MultiPlayer({applause:"applause.mp3"},function(){b=!1;for(var t=S.buffers.get("applause").get().getChannelData(0),e=[],i=0,n=Math.floor(t.length/v);i<n;i++){for(var s=0,o=i*v,r=(i+1)*v;o<r;o++)s+=Math.abs(t[o]);e[i]=[s/v,i]}g=e.sort(function(t,e){return t[0]<e[0]?-1:t[0]==e[0]?0:1}).map(function(t,e){return t[1]})});S.fadeIn=.25,S.fadeOut=.25,S.connect(_);var T=0,w=0,O=5,x={x:0,y:0},P=!1,k=document.createElement("canvas");k.width=window.innerWidth,k.height=window.innerHeight;var A=k.getContext("2d");document.body.appendChild(k),setInterval(function(){w+=.001},5e3),y.browser.isMobile?(document.body.addEventListener("touchstart",(0,y.firstTouch)(o)),document.body.addEventListener("touchmove",(0,y.firstTouch)(r)),window.addEventListener("touchend",(0,y.firstTouch)(a))):(document.body.addEventListener("mousedown",o),document.body.addEventListener("mousemove",r),window.addEventListener("mouseup",a));var E=["Arial","Helvetica","Comic Sans MS","Chalkboard","Georgia"];h(),l()},function(t,e,i){"use strict";var n,s,o;"function"==typeof Symbol&&Symbol.iterator;/** * StartAudioContext.js * @author Yotam Mann * @license http://opensource.org/licenses/MIT MIT License * @copyright 2016 Yotam Mann */ -(function (root, factory) { - if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === 'object' && module.exports) { - module.exports = factory(); - } else { - root.StartAudioContext = factory(); - } -})(undefined, function () { - - /** - * The StartAudioContext object - */ - var StartAudioContext = { - /** - * The audio context passed in by the user - * @type {AudioContext} - */ - context: null, - /** - * The TapListeners bound to the elements - * @type {Array} - * @private - */ - _tapListeners: [], - /** - * Callbacks to invoke when the audio context is started - * @type {Array} - * @private - */ - _onStarted: [] - }; - - /** - * Set the context - * @param {AudioContext} ctx - * @returns {StartAudioContext} - */ - StartAudioContext.setContext = function (ctx) { - StartAudioContext.context = ctx; - return StartAudioContext; - }; - - /** - * Add a tap listener to the audio context - * @param {Array|Element|String|jQuery} element - * @returns {StartAudioContext} - */ - StartAudioContext.on = function (element) { - if (Array.isArray(element) || NodeList && element instanceof NodeList) { - for (var i = 0; i < element.length; i++) { - StartAudioContext.on(element[i]); - } - } else if (typeof element === "string") { - StartAudioContext.on(document.querySelectorAll(element)); - } else if (element.jquery && typeof element.toArray === "function") { - StartAudioContext.on(element.toArray()); - } else if (Element && element instanceof Element) { - //if it's an element, create a TapListener - var tap = new TapListener(element, onTap); - StartAudioContext._tapListeners.push(tap); - } - return StartAudioContext; - }; - - /** - * Bind a callback to when the audio context is started. - * @param {Function} cb - * @return {StartAudioContext} - */ - StartAudioContext.onStarted = function (cb) { - //if it's already started, invoke the callback - if (StartAudioContext.isStarted()) { - cb(); - } else { - StartAudioContext._onStarted.push(cb); - } - return StartAudioContext; - }; - - /** - * returns true if the context is started - * @return {Boolean} - */ - StartAudioContext.isStarted = function () { - return StartAudioContext.context !== null && StartAudioContext.context.state === "running"; - }; - - /** - * @class Listens for non-dragging tap ends on the given element - * @param {Element} element - * @internal - */ - var TapListener = function TapListener(element) { - - this._dragged = false; - - this._element = element; - - this._bindedMove = this._moved.bind(this); - this._bindedEnd = this._ended.bind(this); - - element.addEventListener("touchmove", this._bindedMove); - element.addEventListener("touchend", this._bindedEnd); - element.addEventListener("mouseup", this._bindedEnd); - }; - - /** - * drag move event - */ - TapListener.prototype._moved = function (e) { - this._dragged = true; - }; - - /** - * tap ended listener - */ - TapListener.prototype._ended = function (e) { - if (!this._dragged) { - onTap(); - } - this._dragged = false; - }; - - /** - * remove all the bound events - */ - TapListener.prototype.dispose = function () { - this._element.removeEventListener("touchmove", this._bindedMove); - this._element.removeEventListener("touchend", this._bindedEnd); - this._element.removeEventListener("mouseup", this._bindedEnd); - this._bindedMove = null; - this._bindedEnd = null; - this._element = null; - }; - - /** - * Invoked the first time of the elements is tapped. - * Creates a silent oscillator when a non-dragging touchend - * event has been triggered. - */ - function onTap() { - //start the audio context with a silent oscillator - if (StartAudioContext.context && !StartAudioContext.isStarted()) { - var osc = StartAudioContext.context.createOscillator(); - var silent = StartAudioContext.context.createGain(); - silent.gain.value = 0; - osc.connect(silent); - silent.connect(StartAudioContext.context.destination); - var now = StartAudioContext.context.currentTime; - osc.start(now); - osc.stop(now + 0.5); - } - - //dispose all the tap listeners - if (StartAudioContext._tapListeners) { - for (var i = 0; i < StartAudioContext._tapListeners.length; i++) { - StartAudioContext._tapListeners[i].dispose(); - } - StartAudioContext._tapListeners = null; - } - //the onstarted callbacks - if (StartAudioContext._onStarted) { - for (var j = 0; j < StartAudioContext._onStarted.length; j++) { - StartAudioContext._onStarted[j](); - } - StartAudioContext._onStarted = null; - } - } - - return StartAudioContext; -}); - -/***/ }) -/******/ ]); +!function(i,r){s=[],n=r,void 0!==(o="function"==typeof n?n.apply(e,s):n)&&(t.exports=o)}(0,function(){function t(){if(e.context&&!e.isStarted()){var t=e.context.createOscillator(),i=e.context.createGain();i.gain.value=0,t.connect(i),i.connect(e.context.destination);var n=e.context.currentTime;t.start(n),t.stop(n+.5)}if(e._tapListeners){for(var s=0;s<e._tapListeners.length;s++)e._tapListeners[s].dispose();e._tapListeners=null}if(e._onStarted){for(var o=0;o<e._onStarted.length;o++)e._onStarted[o]();e._onStarted=null}}var e={context:null,_tapListeners:[],_onStarted:[]};e.setContext=function(t){return e.context=t,e},e.on=function(n){if(Array.isArray(n)||NodeList&&n instanceof NodeList)for(var s=0;s<n.length;s++)e.on(n[s]);else if("string"==typeof n)e.on(document.querySelectorAll(n));else if(n.jquery&&"function"==typeof n.toArray)e.on(n.toArray());else if(Element&&n instanceof Element){var o=new i(n,t);e._tapListeners.push(o)}return e},e.onStarted=function(t){return e.isStarted()?t():e._onStarted.push(t),e},e.isStarted=function(){return null!==e.context&&"running"===e.context.state};var i=function(t){this._dragged=!1,this._element=t,this._bindedMove=this._moved.bind(this),this._bindedEnd=this._ended.bind(this),t.addEventListener("touchmove",this._bindedMove),t.addEventListener("touchend",this._bindedEnd),t.addEventListener("mouseup",this._bindedEnd)};return i.prototype._moved=function(t){this._dragged=!0},i.prototype._ended=function(e){this._dragged||t(),this._dragged=!1},i.prototype.dispose=function(){this._element.removeEventListener("touchmove",this._bindedMove),this._element.removeEventListener("touchend",this._bindedEnd),this._element.removeEventListener("mouseup",this._bindedEnd),this._bindedMove=null,this._bindedEnd=null,this._element=null},e})}]); //# sourceMappingURL=bundle.js.map
\ No newline at end of file |
