PageSourceSearch

https://metarythmes.github.io/libraries/p5.sound.js

js metarythmes.github.io collected 2026-10-03 09:36:09 UTC 308,749 bytes, 9,034 lines download raw bytes

1/*! p5.sound.js v0.3.0 2016-01-31 */
2(function (root, factory) {
3  if (typeof define === 'function' && define.amd)
4    define('p5.sound', ['p5'], function (p5) { (factory(p5));});
5  else if (typeof exports === 'object')
6    factory(require('../p5'));
7  else
8    factory(root['p5']);
9}(this, function (p5) {
10  /**
11 *  p5.sound extends p5 with <a href="http://caniuse.com/audio-api"
12 *  target="_blank">Web Audio</a> functionality including audio input,
13 *  playback, analysis and synthesis.
14 *  <br/><br/>
15 *  <a href="#/p5.SoundFile"><b>p5.SoundFile</b></a>: Load and play sound files.<br/>
16 *  <a href="#/p5.Amplitude"><b>p5.Amplitude</b></a>: Get the current volume of a sound.<br/>
17 *  <a href="#/p5.AudioIn"><b>p5.AudioIn</b></a>: Get sound from an input source, typically
18 *    a computer microphone.<br/>
19 *  <a href="#/p5.FFT"><b>p5.FFT</b></a>: Analyze the frequency of sound. Returns
20 *    results from the frequency spectrum or time domain (waveform).<br/>
21 *  <a href="#/p5.Oscillator"><b>p5.Oscillator</b></a>: Generate Sine,
22 *    Triangle, Square and Sawtooth waveforms. Base class of
23 *    <a href="#/p5.Noise">p5.Noise</a> and <a href="#/p5.Pulse">p5.Pulse</a>.
24 *    <br/>
25 *  <a href="#/p5.Env"><b>p5.Env</b></a>: An Envelope is a series
26 *    of fades over time. Often used to control an object's
27 *    output gain level as an "ADSR Envelope" (Attack, Decay,
28 *    Sustain, Release). Can also modulate other parameters.<br/>
29 *  <a href="#/p5.Delay"><b>p5.Delay</b></a>: A delay effect with
30 *    parameters for feedback, delayTime, and lowpass filter.<br/>
31 *  <a href="#/p5.Filter"><b>p5.Filter</b></a>: Filter the frequency range of a
32 *    sound.
33 *  <br/>
34 *  <a href="#/p5.Reverb"><b>p5.Reverb</b></a>: Add reverb to a sound by specifying
35 *    duration and decay. <br/>
36 *  <b><a href="#/p5.Convolver">p5.Convolver</a>:</b> Extends
37 *  <a href="#/p5.Reverb">p5.Reverb</a> to simulate the sound of real
38 *    physical spaces through convolution.<br/>
39 *  <b><a href="#/p5.SoundRecorder">p5.SoundRecorder</a></b>: Record sound for playback 
40 *    / save the .wav file.
41 *  <b><a href="#/p5.Phrase">p5.Phrase</a></b>, <b><a href="#/p5.Part">p5.Part</a></b> and
42 *  <b><a href="#/p5.Score">p5.Score</a></b>: Compose musical sequences.
43 *  <br/><br/>
44 *  p5.sound is on <a href="https://github.com/therewasaguy/p5.sound/">GitHub</a>.
45 *  Download the latest version 
46 *  <a href="https://github.com/therewasaguy/p5.sound/blob/master/lib/p5.sound.js">here</a>.
47 *  
48 *  @module p5.sound
49 *  @submodule p5.sound
50 *  @for p5.sound
51 *  @main
52 */
53/**
54 *  p5.sound developed by Jason Sigal for the Processing Foundation, Google Summer of Code 2014. The MIT License (MIT).
55 *  
56 *  http://github.com/therewasaguy/p5.sound
57 *
58 *  Some of the many audio libraries & resources that inspire p5.sound:
59 *   - TONE.js (c) Yotam Mann, 2014. Licensed under The MIT License (MIT). https://github.com/TONEnoTONE/Tone.js
60 *   - buzz.js (c) Jay Salvat, 2013. Licensed under The MIT License (MIT). http://buzz.jaysalvat.com/
61 *   - Boris Smus Web Audio API book, 2013. Licensed under the Apache License http://www.apache.org/licenses/LICENSE-2.0
62 *   - wavesurfer.js https://github.com/katspaugh/wavesurfer.js
63 *   - Web Audio Components by Jordan Santell https://github.com/web-audio-components
64 *   - Wilm Thoben's Sound library for Processing https://github.com/processing/processing/tree/master/java/libraries/sound
65 *   
66 *   Web Audio API: http://w3.org/TR/webaudio/
67 */
68var sndcore;
69sndcore = function () {
70  'use strict';
71  /* AudioContext Monkeypatch
72     Copyright 2013 Chris Wilson
73     Licensed under the Apache License, Version 2.0 (the "License");
74     you may not use this file except in compliance with the License.
75     You may obtain a copy of the License at
76         http://www.apache.org/licenses/LICENSE-2.0
77     Unless required by applicable law or agreed to in writing, software
78     distributed under the License is distributed on an "AS IS" BASIS,
79     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
80     See the License for the specific language governing permissions and
81     limitations under the License.
82  */
83  (function (global, exports, perf) {
84    exports = exports || {};
85    'use strict';
86    function fixSetTarget(param) {
87      if (!param)
88        // if NYI, just return
89        return;
90      if (!param.setTargetAtTime)
91        param.setTargetAtTime = param.setTargetValueAtTime;
92    }
93    if (window.hasOwnProperty('webkitAudioContext') && !window.hasOwnProperty('AudioContext')) {
94      window.AudioContext = webkitAudioContext;
95      if (!AudioContext.prototype.hasOwnProperty('createGain'))
96        AudioContext.prototype.createGain = AudioContext.prototype.createGainNode;
97      if (!AudioContext.prototype.hasOwnProperty('createDelay'))
98        AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode;
99      if (!AudioContext.prototype.hasOwnProperty('createScriptProcessor'))
100        AudioContext.prototype.createScriptProcessor = AudioContext.prototype.createJavaScriptNode;
101      if (!AudioContext.prototype.hasOwnProperty('createPeriodicWave'))
102        AudioContext.prototype.createPeriodicWave = AudioContext.prototype.createWaveTable;
103      AudioContext.prototype.internal_createGain = AudioContext.prototype.createGain;
104      AudioContext.prototype.createGain = function () {
105        var node = this.internal_createGain();
106        fixSetTarget(node.gain);
107        return node;
108      };
109      AudioContext.prototype.internal_createDelay = AudioContext.prototype.createDelay;
110      AudioContext.prototype.createDelay = function (maxDelayTime) {
111        var node = maxDelayTime ? this.internal_createDelay(maxDelayTime) : this.internal_createDelay();
112        fixSetTarget(node.delayTime);
113        return node;
114      };
115      AudioContext.prototype.internal_createBufferSource = AudioContext.prototype.createBufferSource;
116      AudioContext.prototype.createBufferSource = function () {
117        var node = this.internal_createBufferSource();
118        if (!node.start) {
119          node.start = function (when, offset, duration) {
120            if (offset || duration)
121              this.noteGrainOn(when || 0, offset, duration);
122            else
123              this.noteOn(when || 0);
124          };
125        } else {
126          node.internal_start = node.start;
127          node.start = function (when, offset, duration) {
128            if (typeof duration !== 'undefined')
129              node.internal_start(when || 0, offset, duration);
130            else
131              node.internal_start(when || 0, offset || 0);
132          };
133        }
134        if (!node.stop) {
135          node.stop = function (when) {
136            this.noteOff(when || 0);
137          };
138        } else {
139          node.internal_stop = node.stop;
140          node.stop = function (when) {
141            node.internal_stop(when || 0);
142          };
143        }
144        fixSetTarget(node.playbackRate);
145        return node;
146      };
147      AudioContext.prototype.internal_createDynamicsCompressor = AudioContext.prototype.createDynamicsCompressor;
148      AudioContext.prototype.createDynamicsCompressor = function () {
149        var node = this.internal_createDynamicsCompressor();
150        fixSetTarget(node.threshold);
151        fixSetTarget(node.knee);
152        fixSetTarget(node.ratio);
153        fixSetTarget(node.reduction);
154        fixSetTarget(node.attack);
155        fixSetTarget(node.release);
156        return node;
157      };
158      AudioContext.prototype.internal_createBiquadFilter = AudioContext.prototype.createBiquadFilter;
159      AudioContext.prototype.createBiquadFilter = function () {
160        var node = this.internal_createBiquadFilter();
161        fixSetTarget(node.frequency);
162        fixSetTarget(node.detune);
163        fixSetTarget(node.Q);
164        fixSetTarget(node.gain);
165        return node;
166      };
167      if (AudioContext.prototype.hasOwnProperty('createOscillator')) {
168        AudioContext.prototype.internal_createOscillator = AudioContext.prototype.createOscillator;
169        AudioContext.prototype.createOscillator = function () {
170          var node = this.internal_createOscillator();
171          if (!node.start) {
172            node.start = function (when) {
173              this.noteOn(when || 0);
174            };
175          } else {
176            node.internal_start = node.start;
177            node.start = function (when) {
178              node.internal_start(when || 0);
179            };
180          }
181          if (!node.stop) {
182            node.stop = function (when) {
183              this.noteOff(when || 0);
184            };
185          } else {
186            node.internal_stop = node.stop;
187            node.stop = function (when) {
188              node.internal_stop(when || 0);
189            };
190          }
191          if (!node.setPeriodicWave)
192            node.setPeriodicWave = node.setWaveTable;
193          fixSetTarget(node.frequency);
194          fixSetTarget(node.detune);
195          return node;
196        };
197      }
198    }
199    if (window.hasOwnProperty('webkitOfflineAudioContext') && !window.hasOwnProperty('OfflineAudioContext')) {
200      window.OfflineAudioContext = webkitOfflineAudioContext;
201    }
202    return exports;
203  }(window));
204  // <-- end MonkeyPatch.
205  // Create the Audio Context
206  var audiocontext = new window.AudioContext();
207  /**
208   * <p>Returns the Audio Context for this sketch. Useful for users
209   * who would like to dig deeper into the <a target='_blank' href=
210   * 'http://webaudio.github.io/web-audio-api/'>Web Audio API
211   * </a>.</p>
212   *
213   * @method getAudioContext
214   * @return {Object}    AudioContext for this sketch
215   */
216  p5.prototype.getAudioContext = function () {
217    return audiocontext;
218  };
219  // Polyfill for AudioIn, also handled by p5.dom createCapture
220  navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
221  /**
222   * Determine which filetypes are supported (inspired by buzz.js)
223   * The audio element (el) will only be used to test browser support for various audio formats
224   */
225  var el = document.createElement('audio');
226  p5.prototype.isSupported = function () {
227    return !!el.canPlayType;
228  };
229  var isOGGSupported = function () {
230    return !!el.canPlayType && el.canPlayType('audio/ogg; codecs="vorbis"');
231  };
232  var isMP3Supported = function () {
233    return !!el.canPlayType && el.canPlayType('audio/mpeg;');
234  };
235  var isWAVSupported = function () {
236    return !!el.canPlayType && el.canPlayType('audio/wav; codecs="1"');
237  };
238  var isAACSupported = function () {
239    return !!el.canPlayType && (el.canPlayType('audio/x-m4a;') || el.canPlayType('audio/aac;'));
240  };
241  var isAIFSupported = function () {
242    return !!el.canPlayType && el.canPlayType('audio/x-aiff;');
243  };
244  p5.prototype.isFileSupported = function (extension) {
245    switch (extension.toLowerCase()) {
246    case 'mp3':
247      return isMP3Supported();
248    case 'wav':
249      return isWAVSupported();
250    case 'ogg':
251      return isOGGSupported();
252    case 'aac', 'm4a', 'mp4':
253      return isAACSupported();
254    case 'aif', 'aiff':
255      return isAIFSupported();
256    default:
257      return false;
258    }
259  };
260  // if it is iOS, we have to have a user interaction to start Web Audio
261  // http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
262  var iOS = navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false;
263  if (iOS) {
264    var iosStarted = false;
265    var startIOS = function () {
266      if (iosStarted)
267        return;
268      // create empty buffer
269      var buffer = audiocontext.createBuffer(1, 1, 22050);
270      var source = audiocontext.createBufferSource();
271      source.buffer = buffer;
272      // connect to output (your speakers)
273      source.connect(audiocontext.destination);
274      // play the file
275      source.start(0);
276      console.log('start ios!');
277      if (audiocontext.state === 'running') {
278        iosStarted = true;
279      }
280    };
281    document.addEventListener('touchend', startIOS, false);
282    document.addEventListener('touchstart', startIOS, false);
283  }
284}();
285var master;
286master = function () {
287  'use strict';
288  /**
289   * Master contains AudioContext and the master sound output.
290   */
291  var Master = function () {
292    var audiocontext = p5.prototype.getAudioContext();
293    this.input = audiocontext.createGain();
294    this.output = audiocontext.createGain();
295    //put a hard limiter on the output
296    this.limiter = audiocontext.createDynamicsCompressor();
297    this.limiter.threshold.value = 0;
298    this.limiter.ratio.value = 100;
299    this.audiocontext = audiocontext;
300    this.output.disconnect();
301    // an array of input sources
302    this.inputSources = [];
303    // connect input to limiter
304    this.input.connect(this.limiter);
305    // connect limiter to output
306    this.limiter.connect(this.output);
307    // meter is just for global Amplitude / FFT analysis
308    this.meter = audiocontext.createGain();
309    this.fftMeter = audiocontext.createGain();
310    this.output.connect(this.meter);
311    this.output.connect(this.fftMeter);
312    // connect output to destination
313    this.output.connect(this.audiocontext.destination);
314    // an array of all sounds in the sketch
315    this.soundArray = [];
316    // an array of all musical parts in the sketch
317    this.parts = [];
318    // file extensions to search for
319    this.extensions = [];
320  };
321  // create a single instance of the p5Sound / master output for use within this sketch
322  var p5sound = new Master();
323  /**
324   * Returns a number representing the master amplitude (volume) for sound 
325   * in this sketch.
326   * 
327   * @method getMasterVolume
328   * @return {Number} Master amplitude (volume) for sound in this sketch.
329   *                  Should be between 0.0 (silence) and 1.0.
330   */
331  p5.prototype.getMasterVolume = function () {
332    return p5sound.output.gain.value;
333  };
334  /**
335   *  <p>Scale the output of all sound in this sketch</p>
336   *  Scaled between 0.0 (silence) and 1.0 (full volume).
337   *  1.0 is the maximum amplitude of a digital sound, so multiplying
338   *  by greater than 1.0 may cause digital distortion. To
339   *  fade, provide a <code>rampTime</code> parameter. For more
340   *  complex fades, see the Env class.
341   *
342   *  Alternately, you can pass in a signal source such as an
343   *  oscillator to modulate the amplitude with an audio signal.
344   *
345   *  <p><b>How This Works</b>: When you load the p5.sound module, it
346   *  creates a single instance of p5sound. All sound objects in this
347   *  module output to p5sound before reaching your computer's output.
348   *  So if you change the amplitude of p5sound, it impacts all of the
349   *  sound in this module.</p>
350   *
351   *  <p>If no value is provided, returns a Web Audio API Gain Node</p>
352   *
353   *  @method  masterVolume
354   *  @param {Number|Object} volume  Volume (amplitude) between 0.0
355   *                                     and 1.0 or modulating signal/oscillator
356   *  @param {Number} [rampTime]  Fade for t seconds
357   *  @param {Number} [timeFromNow]  Schedule this event to happen at
358   *                                 t seconds in the future
359   */
360  p5.prototype.masterVolume = function (vol, rampTime, tFromNow) {
361    if (typeof vol === 'number') {
362      var rampTime = rampTime || 0;
363      var tFromNow = tFromNow || 0;
364      var now = p5sound.audiocontext.currentTime;
365      var currentVol = p5sound.output.gain.value;
366      p5sound.output.gain.cancelScheduledValues(now + tFromNow);
367      p5sound.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow);
368      p5sound.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime);
369    } else if (vol) {
370      vol.connect(p5sound.output.gain);
371    } else {
372      // return the Gain Node
373      return p5sound.output.gain;
374    }
375  };
376  /**
377   *  p5.soundOut is the p5.sound master output. It sends output to
378   *  the destination of this window's web audio context. It contains 
379   *  Web Audio API nodes including a dyanmicsCompressor (<code>.limiter</code>),
380   *  and Gain Nodes for <code>.input</code> and <code>.output</code>.
381   *  
382   *  @property p5.soundOut
383   *  @type {Object}
384   */
385  p5.soundOut = p5sound;
386  /**
387   *  a silent connection to the DesinationNode
388   *  which will ensure that anything connected to it
389   *  will not be garbage collected
390   *  
391   *  @private
392   */
393  p5.soundOut._silentNode = p5sound.audiocontext.createGain();
394  p5.soundOut._silentNode.gain.value = 0;
395  p5.soundOut._silentNode.connect(p5sound.audiocontext.destination);
396  return p5sound;
397}(sndcore);
398var helpers;
399helpers = function () {
400  'use strict';
401  var p5sound = master;
402  /**
403   * Returns a number representing the sample rate, in samples per second,
404   * of all sound objects in this audio context. It is determined by the
405   * sampling rate of your operating system's sound card, and it is not
406   * currently possile to change.
407   * It is often 44100, or twice the range of human hearing.
408   *
409   * @method sampleRate
410   * @return {Number} samplerate samples per second
411   */
412  p5.prototype.sampleRate = function () {
413    return p5sound.audiocontext.sampleRate;
414  };
415  /**
416   *  Returns the closest MIDI note value for
417   *  a given frequency.
418   *  
419   *  @param  {Number} frequency A freqeuncy, for example, the "A"
420   *                             above Middle C is 440Hz
421   *  @return {Number}   MIDI note value
422   */
423  p5.prototype.freqToMidi = function (f) {
424    var mathlog2 = Math.log(f / 440) / Math.log(2);
425    var m = Math.round(12 * mathlog2) + 57;
426    return m;
427  };
428  /**
429   *  Returns the frequency value of a MIDI note value.
430   *  General MIDI treats notes as integers where middle C
431   *  is 60, C# is 61, D is 62 etc. Useful for generating
432   *  musical frequencies with oscillators.
433   *  
434   *  @method  midiToFreq
435   *  @param  {Number} midiNote The number of a MIDI note
436   *  @return {Number} Frequency value of the given MIDI note
437   *  @example
438   *  <div><code>
439   *  var notes = [60, 64, 67, 72];
440   *  var i = 0;
441   *  
442   *  function setup() {
443   *    osc = new p5.Oscillator('Triangle');
444   *    osc.start();
445   *    frameRate(1);
446   *  }
447   *  
448   *  function draw() {
449   *    var freq = midiToFreq(notes[i]);
450   *    osc.freq(freq);
451   *    i++;
452   *    if (i >= notes.length){
453   *      i = 0;
454   *    }
455   *  }
456   *  </code></div>
457   */
458  p5.prototype.midiToFreq = function (m) {
459    return 440 * Math.pow(2, (m - 69) / 12);
460  };
461  /**
462   *  List the SoundFile formats that you will include. LoadSound 
463   *  will search your directory for these extensions, and will pick
464   *  a format that is compatable with the client's web browser.
465   *  <a href="http://media.io/">Here</a> is a free online file
466   *  converter.
467   *  
468   *  @method soundFormats
469   *  @param {String|Strings} formats i.e. 'mp3', 'wav', 'ogg'
470   *  @example
471   *  <div><code>
472   *  function preload() {
473   *    // set the global sound formats
474   *    soundFormats('mp3', 'ogg');
475   *    
476   *    // load either beatbox.mp3, or .ogg, depending on browser
477   *    mySound = loadSound('../sounds/beatbox.mp3');
478   *  }
479   *
480   *  function setup() {
481   *    mySound.play();
482   *  }
483   *  </code></div>
484   */
485  p5.prototype.soundFormats = function () {
486    // reset extensions array
487    p5sound.extensions = [];
488    // add extensions
489    for (var i = 0; i < arguments.length; i++) {
490      arguments[i] = arguments[i].toLowerCase();
491      if ([
492          'mp3',
493          'wav',
494          'ogg',
495          'm4a',
496          'aac'
497        ].indexOf(arguments[i]) > -1) {
498        p5sound.extensions.push(arguments[i]);
499      } else {
500        throw arguments[i] + ' is not a valid sound format!';
501      }
502    }
503  };
504  p5.prototype.disposeSound = function () {
505    for (var i = 0; i < p5sound.soundArray.length; i++) {
506      p5sound.soundArray[i].dispose();
507    }
508  };
509  // register removeSound to dispose of p5sound SoundFiles, Convolvers,
510  // Oscillators etc when sketch ends
511  p5.prototype.registerMethod('remove', p5.prototype.disposeSound);
512  p5.prototype._checkFileFormats = function (paths) {
513    var path;
514    // if path is a single string, check to see if extension is provided
515    if (typeof paths === 'string') {
516      path = paths;
517      // see if extension is provided
518      var extTest = path.split('.').pop();
519      // if an extension is provided...
520      if ([
521          'mp3',
522          'wav',
523          'ogg',
524          'm4a',
525          'aac'
526        ].indexOf(extTest) > -1) {
527        var supported = p5.prototype.isFileSupported(extTest);
528        if (supported) {
529          path = path;
530        } else {
531          var pathSplit = path.split('.');
532          var pathCore = pathSplit[pathSplit.length - 1];
533          for (var i = 0; i < p5sound.extensions.length; i++) {
534            var extension = p5sound.extensions[i];
535            var supported = p5.prototype.isFileSupported(extension);
536            if (supported) {
537              pathCore = '';
538              if (pathSplit.length === 2) {
539                pathCore += pathSplit[0];
540              }
541              for (var i = 1; i <= pathSplit.length - 2; i++) {
542                var p = pathSplit[i];
543                pathCore += '.' + p;
544              }
545              path = pathCore += '.';
546              path = path += extension;
547              break;
548            }
549          }
550        }
551      } else {
552        for (var i = 0; i < p5sound.extensions.length; i++) {
553          var extension = p5sound.extensions[i];
554          var supported = p5.prototype.isFileSupported(extension);
555          if (supported) {
556            path = path + '.' + extension;
557            break;
558          }
559        }
560      }
561    } else if (typeof paths === 'object') {
562      for (var i = 0; i < paths.length; i++) {
563        var extension = paths[i].split('.').pop();
564        var supported = p5.prototype.isFileSupported(extension);
565        if (supported) {
566          // console.log('.'+extension + ' is ' + supported +
567          //  ' supported by your browser.');
568          path = paths[i];
569          break;
570        }
571      }
572    }
573    return path;
574  };
575  /**
576   *  Used by Osc and Env to chain signal math
577   */
578  p5.prototype._mathChain = function (o, math, thisChain, nextChain, type) {
579    // if this type of math already exists in the chain, replace it
580    for (var i in o.mathOps) {
581      if (o.mathOps[i] instanceof type) {
582        o.mathOps[i].dispose();
583        thisChain = i;
584        if (thisChain < o.mathOps.length - 1) {
585          nextChain = o.mathOps[i + 1];
586        }
587      }
588    }
589    o.mathOps[thisChain - 1].disconnect();
590    o.mathOps[thisChain - 1].connect(math);
591    math.connect(nextChain);
592    o.mathOps[thisChain] = math;
593    return o;
594  };
595}(master);
596var errorHandler;
597errorHandler = function () {
598  'use strict';
599  /**
600   *  Helper function to generate an error
601   *  with a custom stack trace that points to the sketch
602   *  and removes other parts of the stack trace.
603   *  
604   *  @private
605   *  
606   *  @param  {String} name         custom  error name
607   *  @param  {String} errorTrace   custom error trace
608   *  @param  {String} failedPath     path to the file that failed to load
609   *  @property {String} name custom error name
610   *  @property {String} message custom error message
611   *  @property {String} stack trace the error back to a line in the user's sketch.
612   *                           Note: this edits out stack trace within p5.js and p5.sound.
613   *  @property {String} originalStack unedited, original stack trace
614   *  @property {String} failedPath path to the file that failed to load
615   *  @return {Error}     returns a custom Error object
616   */
617  var CustomError = function (name, errorTrace, failedPath) {
618    var err = new Error();
619    var tempStack, splitStack;
620    err.name = name;
621    err.originalStack = err.stack + errorTrace;
622    tempStack = err.stack + errorTrace;
623    err.failedPath = failedPath;
624    // only print the part of the stack trace that refers to the user co
624de:
625    var splitStack = tempStack.split('\n');
626    splitStack = splitStack.filter(function (ln) {
627      return !ln.match(/(p5.|native code|globalInit)/g);
628    });
629    err.stack = splitStack.join('\n');
630    return err;
631  };
632  return CustomError;
633}();
634var panner;
635panner = function () {
636  'use strict';
637  var p5sound = master;
638  var ac = p5sound.audiocontext;
639  // Stereo panner
640  // if there is a stereo panner node use it
641  if (typeof ac.createStereoPanner !== 'undefined') {
642    p5.Panner = function (input, output, numInputChannels) {
643      this.stereoPanner = this.input = ac.createStereoPanner();
644      input.connect(this.stereoPanner);
645      this.stereoPanner.connect(output);
646    };
647    p5.Panner.prototype.pan = function (val, tFromNow) {
648      var time = tFromNow || 0;
649      var t = ac.currentTime + time;
650      this.stereoPanner.pan.linearRampToValueAtTime(val, t);
651    };
652    p5.Panner.prototype.inputChannels = function (numChannels) {
653    };
654    p5.Panner.prototype.connect = function (obj) {
655      this.stereoPanner.connect(obj);
656    };
657    p5.Panner.prototype.disconnect = function (obj) {
658      this.stereoPanner.disconnect();
659    };
660  } else {
661    // if there is no createStereoPanner object
662    // such as in safari 7.1.7 at the time of writing this
663    // use this method to create the effect
664    p5.Panner = function (input, output, numInputChannels) {
665      this.input = ac.createGain();
666      input.connect(this.input);
667      this.left = ac.createGain();
668      this.right = ac.createGain();
669      this.left.channelInterpretation = 'discrete';
670      this.right.channelInterpretation = 'discrete';
671      // if input is stereo
672      if (numInputChannels > 1) {
673        this.splitter = ac.createChannelSplitter(2);
674        this.input.connect(this.splitter);
675        this.splitter.connect(this.left, 1);
676        this.splitter.connect(this.right, 0);
677      } else {
678        this.input.connect(this.left);
679        this.input.connect(this.right);
680      }
681      this.output = ac.createChannelMerger(2);
682      this.left.connect(this.output, 0, 1);
683      this.right.connect(this.output, 0, 0);
684      this.output.connect(output);
685    };
686    // -1 is left, +1 is right
687    p5.Panner.prototype.pan = function (val, tFromNow) {
688      var time = tFromNow || 0;
689      var t = ac.currentTime + time;
690      var v = (val + 1) / 2;
691      var rightVal = Math.cos(v * Math.PI / 2);
692      var leftVal = Math.sin(v * Math.PI / 2);
693      this.left.gain.linearRampToValueAtTime(leftVal, t);
694      this.right.gain.linearRampToValueAtTime(rightVal, t);
695    };
696    p5.Panner.prototype.inputChannels = function (numChannels) {
697      if (numChannels === 1) {
698        this.input.disconnect();
699        this.input.connect(this.left);
700        this.input.connect(this.right);
701      } else if (numChannels === 2) {
702        if (typeof (this.splitter === 'undefined')) {
703          this.splitter = ac.createChannelSplitter(2);
704        }
705        this.input.disconnect();
706        this.input.connect(this.splitter);
707        this.splitter.connect(this.left, 1);
708        this.splitter.connect(this.right, 0);
709      }
710    };
711    p5.Panner.prototype.connect = function (obj) {
712      this.output.connect(obj);
713    };
714    p5.Panner.prototype.disconnect = function (obj) {
715      this.output.disconnect();
716    };
717  }
718  // 3D panner
719  p5.Panner3D = function (input, output) {
720    var panner3D = ac.createPanner();
721    panner3D.panningModel = 'HRTF';
722    panner3D.distanceModel = 'linear';
723    panner3D.setPosition(0, 0, 0);
724    input.connect(panner3D);
725    panner3D.connect(output);
726    panner3D.pan = function (xVal, yVal, zVal) {
727      panner3D.setPosition(xVal, yVal, zVal);
728    };
729    return panner3D;
730  };
731}(master);
732var soundfile;
733soundfile = function () {
734  'use strict';
735  var CustomError = errorHandler;
736  var p5sound = master;
737  var ac = p5sound.audiocontext;
738  /**
739   *  <p>SoundFile object with a path to a file.</p>
740   *  
741   *  <p>The p5.SoundFile may not be available immediately because
742   *  it loads the file information asynchronously.</p>
743   * 
744   *  <p>To do something with the sound as soon as it loads
745   *  pass the name of a function as the second parameter.</p>
746   *  
747   *  <p>Only one file path is required. However, audio file formats 
748   *  (i.e. mp3, ogg, wav and m4a/aac) are not supported by all
749   *  web browsers. If you want to ensure compatability, instead of a single
750   *  file path, you may include an Array of filepaths, and the browser will
751   *  choose a format that works.</p>
752   * 
753   *  @class p5.SoundFile
754   *  @constructor
755   *  @param {String/Array} path   path to a sound file (String). Optionally,
756   *                               you may include multiple file formats in
757   *                               an array. Alternately, accepts an object
758   *                               from the HTML5 File API, or a p5.File.
759   *  @param {Function} [successCallback]   Name of a function to call once file loads
760   *  @param {Function} [errorCallback]   Name of a function to call if file fails to
761   *                                      load. This function will receive an error or
762   *                                     XMLHttpRequest object with information
763   *                                     about what went wrong.
764   *  @param {Function} [whileLoadingCallback]   Name of a function to call while file
765   *                                             is loading. That function will
766   *                                             receive percentage loaded
767   *                                             (between 0 and 1) as a
768   *                                             parameter.
769   *                                             
770   *  @return {Object}    p5.SoundFile Object
771   *  @example 
772   *  <div><code>
773   *  
774   *  function preload() {
775   *    mySound = loadSound('assets/doorbell.mp3');
776   *  }
777   *
778   *  function setup() {
779   *    mySound.setVolume(0.1);
780   *    mySound.play();
781   *  }
782   * 
783   * </code></div>
784   */
785  p5.SoundFile = function (paths, onload, onerror, whileLoading) {
786    if (typeof paths !== 'undefined') {
787      if (typeof paths == 'string' || typeof paths[0] == 'string') {
788        var path = p5.prototype._checkFileFormats(paths);
789        this.url = path;
790      } else if (typeof paths == 'object') {
791        if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
792          // The File API isn't supported in this browser 
793          throw 'Unable to load file because the File API is not supported';
794        }
795      }
796      // if type is a p5.File...get the actual file
797      if (paths.file) {
798        paths = paths.file;
799      }
800      this.file = paths;
801    }
802    // private _onended callback, set by the method: onended(callback)
803    this._onended = function () {
804    };
805    this._looping = false;
806    this._playing = false;
807    this._paused = false;
808    this._pauseTime = 0;
809    // cues for scheduling events with addCue() removeCue()
810    this._cues = [];
811    //  position of the most recently played sample
812    this._lastPos = 0;
813    this._counterNode;
814    this._scopeNode;
815    // array of sources so that they can all be stopped!
816    this.bufferSourceNodes = [];
817    // current source
818    this.bufferSourceNode = null;
819    this.buffer = null;
820    this.playbackRate = 1;
821    this.gain = 1;
822    this.input = p5sound.audiocontext.createGain();
823    this.output = p5sound.audiocontext.createGain();
824    this.reversed = false;
825    // start and end of playback / loop
826    this.startTime = 0;
827    this.endTime = null;
828    this.pauseTime = 0;
829    // "restart" would stop playback before retriggering
830    this.mode = 'sustain';
831    // time that playback was started, in millis
832    this.startMillis = null;
833    // stereo panning
834    this.panPosition = 0;
835    this.panner = new p5.Panner(this.output, p5sound.input, 2);
836    // it is possible to instantiate a soundfile with no path
837    if (this.url || this.file) {
838      this.load(onload, onerror);
839    }
840    // add this p5.SoundFile to the soundArray
841    p5sound.soundArray.push(this);
842    if (typeof whileLoading === 'function') {
843      this._whileLoading = whileLoading;
844    } else {
845      this._whileLoading = function () {
846      };
847    }
848  };
849  // register preload handling of loadSound
850  p5.prototype.registerPreloadMethod('loadSound', p5.prototype);
851  /**
852   *  loadSound() returns a new p5.SoundFile from a specified
853   *  path. If called during preload(), the p5.SoundFile will be ready
854   *  to play in time for setup() and draw(). If called outside of
855   *  preload, the p5.SoundFile will not be ready immediately, so
856   *  loadSound accepts a callback as the second parameter. Using a
857   *  <a href="https://github.com/processing/p5.js/wiki/Local-server">
858   *  local server</a> is recommended when loading external files.
859   *  
860   *  @method loadSound
861   *  @param  {String/Array}   path     Path to the sound file, or an array with
862   *                                    paths to soundfiles in multiple formats
863   *                                    i.e. ['sound.ogg', 'sound.mp3'].
864   *                                    Alternately, accepts an object: either
865   *                                    from the HTML5 File API, or a p5.File.
866   *  @param {Function} [successCallback]   Name of a function to call once file loads
867   *  @param {Function} [errorCallback]   Name of a function to call if there is
868   *                                      an error loading the file.
869   *  @param {Function} [whileLoading] Name of a function to call while file is loading.
870   *                                 This function will receive the percentage loaded
871   *                                 so far, from 0.0 to 1.0.
872   *  @return {SoundFile}            Returns a p5.SoundFile
873   *  @example 
874   *  <div><code>
875   *  function preload() {
876   *   mySound = loadSound('assets/doorbell.mp3');
877   *  }
878   *
879   *  function setup() {
880   *    mySound.setVolume(0.1);
881   *    mySound.play();
882   *  }
883   *  </code></div>
884   */
885  p5.prototype.loadSound = function (path, callback, onerror, whileLoading) {
886    // if loading locally without a server
887    if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') {
888      alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS');
889    }
890    var s = new p5.SoundFile(path, callback, onerror, whileLoading);
891    return s;
892  };
893  /**
894   * This is a helper function that the p5.SoundFile calls to load
895   * itself. Accepts a callback (the name of another function)
896   * as an optional parameter.
897   *
898   * @private
899   * @param {Function} [successCallback]   Name of a function to call once file loads
900   * @param {Function} [errorCallback]   Name of a function to call if there is an error
901   */
902  p5.SoundFile.prototype.load = function (callback, errorCallback) {
903    var loggedError = false;
904    var self = this;
905    var errorTrace = new Error().stack;
906    if (this.url != undefined && this.url != '') {
907      var request = new XMLHttpRequest();
908      request.addEventListener('progress', function (evt) {
909        self._updateProgress(evt);
910      }, false);
911      request.open('GET', this.url, true);
912      request.responseType = 'arraybuffer';
913      request.onload = function () {
914        if (request.status == 200) {
915          // on sucess loading file:
916          ac.decodeAudioData(request.response, // success decoding buffer:
917          function (buff) {
918            self.buffer = buff;
919            self.panner.inputChannels(buff.numberOfChannels);
920            if (callback) {
921              callback(self);
922            }
923          }, // error decoding buffer. "e" is undefined in Chrome 11/22/2015
924          function (e) {
925            var err = new CustomError('decodeAudioData', errorTrace, self.url);
926            var msg = 'AudioContext error at decodeAudioData for ' + self.url;
927            if (errorCallback) {
928              err.msg = msg;
929              errorCallback(err);
930            } else {
931              console.error(msg + '\n The error stack trace includes: \n' + err.stack);
932            }
933          });
934        } else {
935          var err = new CustomError('loadSound', errorTrace, self.url);
936          var msg = 'Unable to load ' + self.url + '. The request status was: ' + request.status + ' (' + request.statusText + ')';
937          if (errorCallback) {
938            err.message = msg;
939            errorCallback(err);
940          } else {
941            console.error(msg + '\n The error stack trace includes: \n' + err.stack);
942          }
943        }
944      };
945      // if there is another error, aside from 404...
946      request.onerror = function (e) {
947        var err = new CustomError('loadSound', errorTrace, self.url);
948        var msg = 'There was no response from the server at ' + self.url + '. Check the url and internet connectivity.';
949        if (errorCallback) {
950          err.message = msg;
951          errorCallback(err);
952        } else {
953          console.error(msg + '\n The error stack trace includes: \n' + err.stack);
954        }
955      };
956      request.send();
957    } else if (this.file != undefined) {
958      var reader = new FileReader();
959      var self = this;
960      reader.onload = function () {
961        ac.decodeAudioData(reader.result, function (buff) {
962          self.buffer = buff;
963          self.panner.inputChannels(buff.numberOfChannels);
964          if (callback) {
965            callback(self);
966          }
967        });
968      };
969      reader.onerror = function (e) {
970        if (onerror)
971          onerror(e);
972      };
973      reader.readAsArrayBuffer(this.file);
974    }
975  };
976  // TO DO: use this method to create a loading bar that shows progress during file upload/decode.
977  p5.SoundFile.prototype._updateProgress = function (evt) {
978    if (evt.lengthComputable) {
979      var percentComplete = Math.log(evt.loaded / evt.total * 9.9);
980      this._whileLoading(percentComplete);
981    } else {
982      // Unable to compute progress information since the total size is unknown
983      this._whileLoading('size unknown');
984    }
985  };
986  /**
987   *  Returns true if the sound file finished loading successfully.
988   *  
989   *  @method  isLoaded
990   *  @return {Boolean} 
991   */
992  p5.SoundFile.prototype.isLoaded = function () {
993    if (this.buffer) {
994      return true;
995    } else {
996      return false;
997    }
998  };
999  /**
1000   * Play the p5.SoundFile
1001   *
1002   * @method play
1003   * @param {Number} [startTime]            (optional) schedule playback to start (in seconds from now).
1004   * @param {Number} [rate]             (optional) playback rate
1005   * @param {Number} [amp]              (optional) amplitude (volume)
1006   *                                     of playback
1007   * @param {Number} [cueStart]        (optional) cue start time in seconds
1008   * @param {Number} [duration]          (optional) duration of playback in seconds
1009   */
1010  p5.SoundFile.prototype.play = function (time, rate, amp, _cueStart, duration) {
1011    var self = this;
1012    var now = p5sound.audiocontext.currentTime;
1013    var cueStart, cueEnd;
1014    var time = time || 0;
1015    if (time < 0) {
1016      time = 0;
1017    }
1018    time = time + now;
1019    // TO DO: if already playing, create array of buffers for easy stop()
1020    if (this.buffer) {
1021      // reset the pause time (if it was paused)
1022      this._pauseTime = 0;
1023      // handle restart playmode
1024      if (this.mode === 'restart' && this.buffer && this.bufferSourceNode) {
1025        var now = p5sound.audiocontext.currentTime;
1026        this.bufferSourceNode.stop(time);
1027        this._counterNode.stop(time);
1028      }
1029      // make a new source and counter. They are automatically assigned playbackRate and buffer
1030      this.bufferSourceNode = this._initSourceNode();
1031      // garbage collect counterNode and create a new one
1032      if (this._counterNode)
1033        this._counterNode = undefined;
1034      this._counterNode = this._initCounterNode();
1035      if (_cueStart) {
1036        if (_cueStart >= 0 && _cueStart < this.buffer.duration) {
1037          // this.startTime = cueStart;
1038          cueStart = _cueStart;
1039        } else {
1040          throw 'start time out of range';
1041        }
1042      } else {
1043        cueStart = 0;
1044      }
1045      if (duration) {
1046        // if duration is greater than buffer.duration, just play entire file anyway rather than throw an error
1047        duration = duration <= this.buffer.duration - cueStart ? duration : this.buffer.duration;
1048      } else {
1049        duration = this.buffer.duration - cueStart;
1050      }
1051      // TO DO: Fix this. It broke in Safari
1052      // 
1053      // method of controlling gain for individual bufferSourceNodes, without resetting overall soundfile volume
1054      // if (typeof(this.bufferSourceNode.gain === 'undefined' ) ) {
1055      //   this.bufferSourceNode.gain = p5sound.audiocontext.createGain();
1056      // }
1057      // this.bufferSourceNode.connect(this.bufferSourceNode.gain);
1058      // set local amp if provided, otherwise 1
1059      var a = amp || 1;
1060      // this.bufferSourceNode.gain.gain.setValueAtTime(a, p5sound.audiocontext.currentTime);
1061      // this.bufferSourceNode.gain.connect(this.output); 
1062      this.bufferSourceNode.connect(this.output);
1063      this.output.gain.value = a;
1064      // not necessary with _initBufferSource ?
1065      // this.bufferSourceNode.playbackRate.cancelScheduledValues(now);
1066      rate = rate || Math.abs(this.playbackRate);
1067      this.bufferSourceNode.playbackRate.setValueAtTime(rate, now);
1068      // if it was paused, play at the pause position
1069      if (this._paused) {
1070        this.bufferSourceNode.start(time, this.pauseTime, duration);
1071        this._counterNode.start(time, this.pauseTime, duration);
1072      } else {
1073        this.bufferSourceNode.start(time, cueStart, duration);
1074        this._counterNode.start(time, cueStart, duration);
1075      }
1076      this._playing = true;
1077      this._paused = false;
1078      // add source to sources array, which is used in stopAll()
1079      this.bufferSourceNodes.push(this.bufferSourceNode);
1080      this.bufferSourceNode._arrayIndex = this.bufferSourceNodes.length - 1;
1081      // delete this.bufferSourceNode from the sources array when it is done playing:
1082      var clearOnEnd = function (e) {
1083        this._playing = false;
1084        this.removeEventListener('ended', clearOnEnd, false);
1085        // call the onended callback
1086        self._onended(self);
1087        self.bufferSourceNodes.forEach(function (n, i) {
1088          if (n._playing === false) {
1089            self.bufferSourceNodes.splice(i);
1090          }
1091        });
1092        if (self.bufferSourceNodes.length === 0) {
1093          self._playing = false;
1094        }
1095      };
1096      this.bufferSourceNode.onended = clearOnEnd;
1097    } else {
1098      throw 'not ready to play file, buffer has yet to load. Try preload()';
1099    }
1100    // if looping, will restart at original time
1101    this.bufferSourceNode.loop = this._looping;
1102    this._counterNode.loop = this._looping;
1103    if (this._looping === true) {
1104      var cueEnd = cueStart + duration;
1105      this.bufferSourceNode.loopStart = cueStart;
1106      this.bufferSourceNode.loopEnd = cueEnd;
1107      this._counterNode.loopStart = cueStart;
1108      this._counterNode.loopEnd = cueEnd;
1109    }
1110  };
1111  /**
1112   *  p5.SoundFile has two play modes: <code>restart</code> and
1113   *  <code>sustain</code>. Play Mode determines what happens to a
1114   *  p5.SoundFile if it is triggered while in the middle of playback.
1115   *  In sustain mode, playback will continue simultaneous to the
1116   *  new playback. In restart mode, play() will stop playback
1117   *  and start over. Sustain is the default mode. 
1118   *  
1119   *  @method  playMode
1120   *  @param  {String} str 'restart' or 'sustain'
1121   *  @example
1122   *  <div><code>
1123   *  function setup(){
1124   *    mySound = loadSound('assets/Damscray_DancingTiger.mp3');
1125   *  }
1126   *  function mouseClicked() {
1127   *    mySound.playMode('sustain');
1128   *    mySound.play();
1129   *  }
1130   *  function keyPressed() {
1131   *    mySound.playMode('restart');
1132   *    mySound.play();
1133   *  }
1134   * 
1135   * </code></div>
1136   */
1137  p5.SoundFile.prototype.playMode = function (str) {
1138    var s = str.toLowerCase();
1139    // if restart, stop all other sounds from playing
1140    if (s === 'restart' && this.buffer && this.bufferSourceNode) {
1141      for (var i = 0; i < this.bufferSourceNodes.length - 1; i++) {
1142        var now = p5sound.audiocontext.currentTime;
1143        this.bufferSourceNodes[i].stop(now);
1144      }
1145    }
1146    // set play mode to effect future playback
1147    if (s === 'restart' || s === 'sustain') {
1148      this.mode = s;
1149    } else {
1150      throw 'Invalid play mode. Must be either "restart" or "sustain"';
1151    }
1152  };
1153  /**
1154   *  Pauses a file that is currently playing. If the file is not
1155   *  playing, then nothing will happen.
1156   *
1157   *  After pausing, .play() will resume from the paused
1158   *  position.
1159   *  If p5.SoundFile had been set to loop before it was paused,
1160   *  it will continue to loop after it is unpaused with .play().
1161   *
1162   *  @method pause
1163   *  @param {Number} [startTime] (optional) schedule event to occur
1164   *                               seconds from now
1165   *  @example
1166   *  <div><code>
1167   *  var soundFile;
1168   *  
1169   *  function preload() {
1170   *    soundFormats('ogg', 'mp3');
1171   *    soundFile = loadSound('assets/Damscray_-_Dancing_Tiger_02.mp3');
1172   *  }
1173   *  function setup() {
1174   *    background(0, 255, 0);
1175   *    soundFile.setVolume(0.1);
1176   *    soundFile.loop();
1177   *  }
1178   *  function keyTyped() {
1179   *    if (key == 'p') {
1180   *      soundFile.pause();
1181   *      background(255, 0, 0);
1182   *    }
1183   *  }
1184   *  
1185   *  function keyReleased() {
1186   *    if (key == 'p') {
1187   *      soundFile.play();
1188   *      background(0, 255, 0);
1189   *    }
1190   *  </code>
1191   *  </div>
1192   */
1193  p5.SoundFile.prototype.pause = function (time) {
1194    var now = p5sound.audiocontext.currentTime;
1195    var time = time || 0;
1196    var pTime = time + now;
1197    if (this.isPlaying() && this.buffer && this.bufferSourceNode) {
1198      this.pauseTime = this.currentTime();
1199      this.bufferSourceNode.stop(pTime);
1200      this._counterNode.stop(pTime);
1201      this._paused = true;
1202      this._playing = false;
1203      this._pauseTime = this.currentTime();
1204    } else {
1205      this._pauseTime = 0;
1206    }
1207  };
1208  /**
1209   * Loop the p5.SoundFile. Accepts optional parameters to set the
1210   * playback rate, playback volume, loopStart, loopEnd.
1211   *
1212   * @method loop
1213   * @param {Number} [startTime] (optional) schedule event to occur
1214   *                             seconds from now
1215   * @param {Number} [rate]        (optional) playback rate
1216   * @param {Number} [amp]         (optional) playback volume
1217   * @param {Number} [cueLoopStart](optional) startTime in seconds
1218   * @param {Number} [duration]  (optional) loop duration in seconds
1219   */
1220  p5.SoundFile.prototype.loop = function (startTime, rate, amp, loopStart, duration) {
1221    this._looping = true;
1222    this.play(startTime, rate, amp, loopStart, duration);
1223  };
1224  /**
1225   * Set a p5.SoundFile's looping flag to true or false. If the sound
1226   * is currently playing, this change will take effect when it
1227   * reaches the end of the current playback. 
1228   * 
1229   * @param {Boolean} Boolean   set looping to true or false
1230   */
1231  p5.SoundFile.prototype.setLoop = function (bool) {
1232    if (bool === true) {
1233      this._looping = true;
1234    } else if (bool === false) {
1235      this._looping = false;
1236    } else {
1237      throw 'Error: setLoop accepts either true or false';
1238    }
1239    if (this.bufferSourceNode) {
1240      this.bufferSourceNode.loop = this._looping;
1241      this._counterNode.loop = this._looping;
1242    }
1243  };
1244  /**
1245   * Returns 'true' if a p5.SoundFile is currently looping and playing, 'false' if not.
1246   *
1247   * @return {Boolean}
1248   */
1249  p5.SoundFile.prototype.isLooping = function () {
1250    if (!this.bufferSourceNode) {
1251      return false;
1252    }
1253    if (this._looping === true && this.isPlaying() === true) {
1254      return true;
1255    }
1256    return false;
1257  };
1258  /**
1259   *  Returns true if a p5.SoundFile is playing, false if not (i.e.
1260   *  paused or stopped).
1261   *
1262   *  @method isPlaying
1263   *  @return {Boolean}
1264   */
1265  p5.SoundFile.prototype.isPlaying = function () {
1266    return this._playing;
1267  };
1268  /**
1269   *  Returns true if a p5.SoundFile is paused, false if not (i.e.
1270   *  playing or stopped).
1271   *
1272   *  @method  isPaused
1273   *  @return {Boolean}
1274   */
1275  p5.SoundFile.prototype.isPaused = function () {
1276    return this._paused;
1277  };
1278  /**
1279   * Stop soundfile playback.
1280   *
1281   * @method stop
1282   * @param {Number} [startTime] (optional) schedule event to occur
1283   *                             in seconds from now
1284   */
1285  p5.SoundFile.prototype.stop = function (timeFromNow) {
1286    var time = timeFromNow || 0;
1287    if (this.mode == 'sustain') {
1288      this.stopAll(time);
1289      this._playing = false;
1290      this.pauseTime = 0;
1291      this._paused = false;
1292    } else if (this.buffer && this.bufferSourceNode) {
1293      var now = p5sound.audiocontext.currentTime;
1294      var t = time || 0;
1295      this.pauseTime = 0;
1296      this.bufferSourceNode.stop(now + t);
1297      this._counterNode.stop(now + t);
1298      this._playing = false;
1299      this._paused = false;
1300    }
1301  };
1302  /**
1303   *  Stop playback on all of this soundfile's sources.
1304   *  @private
1305   */
1306  p5.SoundFile.prototype.stopAll = function (_time) {
1307    var now = p5sound.audiocontext.currentTime;
1308    var time = _time || 0;
1309    if (this.buffer && this.bufferSourceNode) {
1310      for (var i = 0; i < this.bufferSourceNodes.length; i++) {
1311        if (typeof this.bufferSourceNodes[i] != undefined) {
1312          try {
1313            this.bufferSourceNodes[i].onended = function () {
1314            };
1315            this.bufferSourceNodes[i].stop(now + time);
1316          } catch (e) {
1317          }
1318        }
1319      }
1320      this._counterNode.stop(now + time);
1321      this._onended(this);
1322    }
1323  };
1324  /**
1325   *  Multiply the output volume (amplitude) of a sound file
1326   *  between 0.0 (silence) and 1.0 (full volume).
1327   *  1.0 is the maximum amplitude of a digital sound, so multiplying
1328   *  by greater than 1.0 may cause digital distortion. To
1329   *  fade, provide a <code>rampTime</code> parameter. For more
1330   *  complex fades, see the Env class.
1331   *
1332   *  Alternately, you can pass in a signal source such as an
1333   *  oscillator to modulate the amplitude with an audio signal.
1334   *
1335   *  @method  setVolume
1336   *  @param {Number|Object} volume  Volume (amplitude) between 0.0
1337   *                                     and 1.0 or modulating signal/oscillator
1338   *  @param {Number} [rampTime]  Fade for t seconds
1339   *  @param {Number} [timeFromNow]  Schedule this event to happen at
1340   *                                 t seconds in the future
1341   */
1342  p5.SoundFile.prototype.setVolume = function (vol, rampTime, tFromNow) {
1343    if (typeof vol === 'number') {
1344      var rampTime = rampTime || 0;
1345      var tFromNow = tFromNow || 0;
1346      var now = p5sound.audiocontext.currentTime;
1347      var currentVol = this.output.gain.value;
1348      this.output.gain.cancelScheduledValues(now + tFromNow);
1349      this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow);
1350      this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime);
1351    } else if (vol) {
1352      vol.connect(this.output.gain);
1353    } else {
1354      // return the Gain Node
1355      return this.output.gain;
1356    }
1357  };
1358  // same as setVolume, to match Processing Sound
1359  p5.SoundFile.prototype.amp = p5.SoundFile.prototype.setVolume;
1360  // these are the same thing
1361  p5.SoundFile.prototype.fade = p5.SoundFile.prototype.setVolume;
1362  p5.SoundFile.prototype.getVolume = function () {
1363    return this.output.gain.value;
1364  };
1365  /**
1366   * Set the stereo panning of a p5.sound object to
1367   * a floating point number between -1.0 (left) and 1.0 (right).
1368   * Default is 0.0 (center).
1369   *
1370   * @method pan
1371   * @param {Number} [panValue]     Set the stereo panner
1372   * @param  {Number} timeFromNow schedule this event to happen
1373   *                                seconds from now
1374   * @example
1375   * <div><code>
1376   *
1377   *  var ball = {};
1378   *  var soundFile;
1379   *
1380   *  function setup() {
1381   *    soundFormats('ogg', 'mp3');
1382   *    soundFile = loadSound('assets/beatbox.mp3');
1383   *  }
1384   *  
1385   *  function draw() {
1386   *    background(0);
1387   *    ball.x = constrain(mouseX, 0, width);
1388   *    ellipse(ball.x, height/2, 20, 20)
1389   *  }
1390   *  
1391   *  function mousePressed(){
1392   *    // map the ball's x location to a panning degree 
1393   *    // between -1.0 (left) and 1.0 (right)
1394   *    var panning = map(ball.x, 0., width,-1.0, 1.0);
1395   *    soundFile.pan(panning);
1396   *    soundFile.play();
1397   *  }
1398   *  </div></code>
1399   */
1400  p5.SoundFile.prototype.pan = function (pval, tFromNow) {
1401    this.panPosition = pval;
1402    this.panner.pan(pval, tFromNow);
1403  };
1404  /**
1405   * Returns the current stereo pan position (-1.0 to 1.0)
1406   *
1407   * @return {Number} Returns the stereo pan setting of the Oscillator
1408   *                          as a number between -1.0 (left) and 1.0 (right).
1409   *                          0.0 is center and default.
1410   */
1411  p5.SoundFile.prototype.getPan = function () {
1412    return this.panPosition;
1413  };
1414  /**
1415   *  Set the playback rate of a sound file. Will change the speed and the pitch.
1416   *  Values less than zero will reverse the audio buffer.
1417   *
1418   *  @method rate
1419   *  @param {Number} [playbackRate]     Set the playback rate. 1.0 is normal,
1420   *                                     .5 is half-speed, 2.0 is twice as fast.
1421   *                                     Must be greater than zero.
1422   *  @example
1423   *  <div><code>
1424   *  var song;
1425   *  
1426   *  function preload() {
1427   *    song = loadSound('assets/Damscray_DancingTiger.mp3');
1428   *  }
1429   *
1430   *  function setup() {
1431   *    song.loop();
1432   *  }
1433   *
1434   *  function draw() {
1435   *    background(200);
1436   *    
1437   *    // Set the rate to a range between 0.1 and 4
1438   *    // Changing the rate also alters the pitch
1439   *    var speed = map(mouseY, 0.1, height, 0, 2);
1440   *    speed = constrain(speed, 0.01, 4);
1441   *    song.rate(speed);
1442   *    
1443   *    // Draw a circle to show what is going on
1444   *    stroke(0);
1445   *    fill(51, 100);
1446   *    ellipse(mouseX, 100, 48, 48);
1447   *  }
1448   *  
1449   * </code>
1450   * </div>
1451   *  
1452   */
1453  p5.SoundFile.prototype.rate = function (playbackRate) {
1454    if (this.playbackRate === playbackRate && this.bufferSourceNode) {
1455      if (this.bufferSourceNode.playbackRate.value === playbackRate) {
1456        return;
1457      }
1458    }
1459    this.playbackRate = playbackRate;
1460    var rate = playbackRate;
1461    if (this.playbackRate === 0 && this._playing) {
1462      this.pause();
1463    }
1464    if (this.playbackRate < 0 && !this.reversed) {
1465      var cPos = this.currentTime();
1466      var cRate = this.bufferSourceNode.playbackRate.value;
1467      // this.pause();
1468      this.reverseBuffer();
1469      rate = Math.abs(playbackRate);
1470      var newPos = (cPos - this.duration()) / rate;
1471      this.pauseTime = newPos;
1472    } else if (this.playbackRate > 0 && this.reversed) {
1473      this.reverseBuffer();
1474    }
1475    if (this.bufferSourceNode) {
1476      var now = p5sound.audiocontext.currentTime;
1477      this.bufferSourceNode.playbackRate.cancelScheduledValues(now);
1478      this.bufferSourceNode.playbackRate.linearRampToValueAtTime(Math.abs(rate), now);
1479      this._counterNode.playbackRate.cancelScheduledValues(now);
1480      this._counterNode.playbackRate.linearRampToValueAtTime(Math.abs(rate), now);
1481    }
1482  };
1483  // TO DO: document this
1484  p5.SoundFile.prototype.setPitch = function (num) {
1485    var newPlaybackRate = midiToFreq(num) / midiToFreq(60);
1486    this.rate(newPlaybackRate);
1487  };
1488  p5.SoundFile.prototype.getPlaybackRate = function () {
1489    return this.playbackRate;
1490  };
1491  /**
1492   * Returns the duration of a sound file in seconds.
1493   *
1494   * @method duration
1495   * @return {Number} The duration of the soundFile in seconds.
1496   */
1497  p5.SoundFile.prototype.duration = function () {
1498    // Return Duration
1499    if (this.buffer) {
1500      return this.buffer.duration;
1501    } else {
1502      return 0;
1503    }
1504  };
1505  /**
1506   * Return the current position of the p5.SoundFile playhead, in seconds.
1507   * Note that if you change the playbackRate while the p5.SoundFile is
1508   * playing, the results may not be accurate.
1509   *
1510   * @method currentTime
1511   * @return {Number}   currentTime of the soundFile in seconds.
1512   */
1513  p5.SoundFile.prototype.currentTime = function () {
1514    // TO DO --> make reverse() flip these values appropriately
1515    if (this._pauseTime > 0) {
1516      return this._pauseTime;
1517    } else {
1518      return this._lastPos / ac.sampleRate;
1519    }
1520  };
1521  /**
1522   * Move the playhead of the song to a position, in seconds. Start
1523   * and Stop time. If none are given, will reset the file to play
1524   * entire duration from start to finish.
1525   *
1526   * @method jump
1527   * @param {Number} cueTime    cueTime of the soundFile in seconds.
1528   * @param {Number} uuration    duration in seconds.
1529   */
1530  p5.SoundFile.prototype.jump = function (cueTime, duration) {
1531    if (cueTime < 0 || cueTime > this.buffer.duration) {
1532      throw 'jump time out of range';
1533    }
1534    if (duration > this.buffer.duration - cueTime) {
1535      throw 'end time out of range';
1536    }
1537    var cTime = cueTime || 0;
1538    var eTime = duration || this.buffer.duration - cueTime;
1539    if (this.isPlaying()) {
1540      this.stop();
1541    }
1542    this.play(0, this.playbackRate, this.output.gain.value, cTime, eTime);
1543  };
1544  /**
1545  * Return the number of channels in a sound file.
1546  * For example, Mono = 1, Stereo = 2.
1547  *
1548  * @method channels
1549  * @return {Number} [channels]
1550  */
1551  p5.SoundFile.prototype.channels = function () {
1552    return this.buffer.numberOfChannels;
1553  };
1554  /**
1555  * Return the sample rate of the sound file.
1556  *
1557  * @method sampleRate
1558  * @return {Number} [sampleRate]
1559  */
1560  p5.SoundFile.prototype.sampleRate = function () {
1561    return this.buffer.sampleRate;
1562  };
1563  /**
1564  * Return the number of samples in a sound file.
1565  * Equal to sampleRate * duration.
1566  *
1567  * @method frames
1568  * @return {Number}
1568 [sampleCount]
1569  */
1570  p5.SoundFile.prototype.frames = function () {
1571    return this.buffer.length;
1572  };
1573  /**
1574   * Returns an array of amplitude peaks in a p5.SoundFile that can be
1575   * used to draw a static waveform. Scans through the p5.SoundFile's
1576   * audio buffer to find the greatest amplitudes. Accepts one
1577   * parameter, 'length', which determines size of the array.
1578   * Larger arrays result in more precise waveform visualizations.
1579   * 
1580   * Inspired by Wavesurfer.js.
1581   * 
1582   * @method  getPeaks
1583   * @params {Number} [length] length is the size of the returned array.
1584   *                          Larger length results in more precision.
1585   *                          Defaults to 5*width of the browser window.
1586   * @returns {Float32Array} Array of peaks.
1587   */
1588  p5.SoundFile.prototype.getPeaks = function (length) {
1589    if (this.buffer) {
1590      // set length to window's width if no length is provided
1591      if (!length) {
1592        length = window.width * 5;
1593      }
1594      if (this.buffer) {
1595        var buffer = this.buffer;
1596        var sampleSize = buffer.length / length;
1597        var sampleStep = ~~(sampleSize / 10) || 1;
1598        var channels = buffer.numberOfChannels;
1599        var peaks = new Float32Array(Math.round(length));
1600        for (var c = 0; c < channels; c++) {
1601          var chan = buffer.getChannelData(c);
1602          for (var i = 0; i < length; i++) {
1603            var start = ~~(i * sampleSize);
1604            var end = ~~(start + sampleSize);
1605            var max = 0;
1606            for (var j = start; j < end; j += sampleStep) {
1607              var value = chan[j];
1608              if (value > max) {
1609                max = value;
1610              } else if (-value > max) {
1611                max = value;
1612              }
1613            }
1614            if (c === 0 || Math.abs(max) > peaks[i]) {
1615              peaks[i] = max;
1616            }
1617          }
1618        }
1619        return peaks;
1620      }
1621    } else {
1622      throw 'Cannot load peaks yet, buffer is not loaded';
1623    }
1624  };
1625  /**
1626   *  Reverses the p5.SoundFile's buffer source.
1627   *  Playback must be handled separately (see example).
1628   *
1629   *  @method  reverseBuffer
1630   *  @example
1631   *  <div><code>
1632   *  var drum;
1633   *  
1634   *  function preload() {
1635   *    drum = loadSound('assets/drum.mp3');
1636   *  }
1637   *
1638   *  function setup() {
1639   *    drum.reverseBuffer();
1640   *    drum.play();
1641   *  }
1642   *  
1643   * </code>
1644   * </div>
1645   */
1646  p5.SoundFile.prototype.reverseBuffer = function () {
1647    var curVol = this.getVolume();
1648    this.setVolume(0, 0.01, 0);
1649    this.pause();
1650    if (this.buffer) {
1651      for (var i = 0; i < this.buffer.numberOfChannels; i++) {
1652        Array.prototype.reverse.call(this.buffer.getChannelData(i));
1653      }
1654      // set reversed flag
1655      this.reversed = !this.reversed;
1656    } else {
1657      throw 'SoundFile is not done loading';
1658    }
1659    this.setVolume(curVol, 0.01, 0.0101);
1660    this.play();
1661  };
1662  /**
1663   *  Schedule an event to be called when the soundfile
1664   *  reaches the end of a buffer. If the soundfile is
1665   *  playing through once, this will be called when it
1666   *  ends. If it is looping, it will be called when
1667   *  stop is called.
1668   *  
1669   *  @method  onended
1670   *  @param  {Function} callback function to call when the
1671   *                              soundfile has ended.
1672   */
1673  p5.SoundFile.prototype.onended = function (callback) {
1674    this._onended = callback;
1675    return this;
1676  };
1677  p5.SoundFile.prototype.add = function () {
1678  };
1679  p5.SoundFile.prototype.dispose = function () {
1680    var now = p5sound.audiocontext.currentTime;
1681    // remove reference to soundfile
1682    var index = p5sound.soundArray.indexOf(this);
1683    p5sound.soundArray.splice(index, 1);
1684    this.stop(now);
1685    if (this.buffer && this.bufferSourceNode) {
1686      for (var i = 0; i < this.bufferSourceNodes.length - 1; i++) {
1687        if (this.bufferSourceNodes[i] !== null) {
1688          this.bufferSourceNodes[i].disconnect();
1689          try {
1690            this.bufferSourceNodes[i].stop(now);
1691          } catch (e) {
1692          }
1693          this.bufferSourceNodes[i] = null;
1694        }
1695      }
1696      if (this.isPlaying()) {
1697        try {
1698          this._counterNode.stop(now);
1699        } catch (e) {
1700          console.log(e);
1701        }
1702        this._counterNode = null;
1703      }
1704    }
1705    if (this.output) {
1706      this.output.disconnect();
1707      this.output = null;
1708    }
1709    if (this.panner) {
1710      this.panner.disconnect();
1711      this.panner = null;
1712    }
1713  };
1714  /**
1715   * Connects the output of a p5sound object to input of another
1716   * p5.sound object. For example, you may connect a p5.SoundFile to an
1717   * FFT or an Effect. If no parameter is given, it will connect to
1718   * the master output. Most p5sound objects connect to the master
1719   * output when they are created.
1720   *
1721   * @method connect
1722   * @param {Object} [object] Audio object that accepts an input
1723   */
1724  p5.SoundFile.prototype.connect = function (unit) {
1725    if (!unit) {
1726      this.panner.connect(p5sound.input);
1727    } else {
1728      if (unit.hasOwnProperty('input')) {
1729        this.panner.connect(unit.input);
1730      } else {
1731        this.panner.connect(unit);
1732      }
1733    }
1734  };
1735  /**
1736   * Disconnects the output of this p5sound object.
1737   *
1738   * @method disconnect
1739   */
1740  p5.SoundFile.prototype.disconnect = function (unit) {
1741    this.panner.disconnect(unit);
1742  };
1743  /**
1744   */
1745  p5.SoundFile.prototype.getLevel = function (smoothing) {
1746    console.warn('p5.SoundFile.getLevel has been removed from the library. Use p5.Amplitude instead');
1747  };
1748  /**
1749   *  Reset the source for this SoundFile to a
1750   *  new path (URL).
1751   *
1752   *  @method  setPath
1753   *  @param {String}   path     path to audio file
1754   *  @param {Function} callback Callback
1755   */
1756  p5.SoundFile.prototype.setPath = function (p, callback) {
1757    var path = p5.prototype._checkFileFormats(p);
1758    this.url = path;
1759    this.load(callback);
1760  };
1761  /**
1762   *  Replace the current Audio Buffer with a new Buffer.
1763   *  
1764   *  @param {Array} buf Array of Float32 Array(s). 2 Float32 Arrays
1765   *                     will create a stereo source. 1 will create
1766   *                     a mono source.
1767   */
1768  p5.SoundFile.prototype.setBuffer = function (buf) {
1769    var numChannels = buf.length;
1770    var size = buf[0].length;
1771    var newBuffer = ac.createBuffer(numChannels, size, ac.sampleRate);
1772    if (!buf[0] instanceof Float32Array) {
1773      buf[0] = new Float32Array(buf[0]);
1774    }
1775    for (var channelNum = 0; channelNum < numChannels; channelNum++) {
1776      var channel = newBuffer.getChannelData(channelNum);
1777      channel.set(buf[channelNum]);
1778    }
1779    this.buffer = newBuffer;
1780    // set numbers of channels on input to the panner
1781    this.panner.inputChannels(numChannels);
1782  };
1783  //////////////////////////////////////////////////
1784  // script processor node with an empty buffer to help
1785  // keep a sample-accurate position in playback buffer.
1786  // Inspired by Chinmay Pendharkar's technique for Sonoport --> http://bit.ly/1HwdCsV
1787  // Copyright [2015] [Sonoport (Asia) Pte. Ltd.],
1788  // Licensed under the Apache License http://apache.org/licenses/LICENSE-2.0
1789  ////////////////////////////////////////////////////////////////////////////////////
1790  // initialize counterNode, set its initial buffer and playbackRate
1791  p5.SoundFile.prototype._initCounterNode = function () {
1792    var self = this;
1793    var now = ac.currentTime;
1794    var cNode = ac.createBufferSource();
1795    // dispose of scope node if it already exists
1796    if (self._scopeNode) {
1797      self._scopeNode.disconnect();
1798      self._scopeNode.onaudioprocess = undefined;
1799      self._scopeNode = null;
1800    }
1801    self._scopeNode = ac.createScriptProcessor(256, 1, 1);
1802    // create counter buffer of the same length as self.buffer
1803    cNode.buffer = _createCounterBuffer(self.buffer);
1804    cNode.playbackRate.setValueAtTime(self.playbackRate, now);
1805    cNode.connect(self._scopeNode);
1806    self._scopeNode.connect(p5.soundOut._silentNode);
1807    self._scopeNode.onaudioprocess = function (processEvent) {
1808      var inputBuffer = processEvent.inputBuffer.getChannelData(0);
1809      // update the lastPos
1810      self._lastPos = inputBuffer[inputBuffer.length - 1] || 0;
1811      // do any callbacks that have been scheduled
1812      self._onTimeUpdate(self._lastPos);
1813    };
1814    return cNode;
1815  };
1816  // initialize sourceNode, set its initial buffer and playbackRate
1817  p5.SoundFile.prototype._initSourceNode = function () {
1818    var self = this;
1819    var now = ac.currentTime;
1820    var bufferSourceNode = ac.createBufferSource();
1821    bufferSourceNode.buffer = self.buffer;
1822    bufferSourceNode.playbackRate.setValueAtTime(self.playbackRate, now);
1823    return bufferSourceNode;
1824  };
1825  var _createCounterBuffer = function (buffer) {
1826    var array = new Float32Array(buffer.length);
1827    var audioBuf = ac.createBuffer(1, buffer.length, 44100);
1828    for (var index = 0; index < buffer.length; index++) {
1829      array[index] = index;
1830    }
1831    audioBuf.getChannelData(0).set(array);
1832    return audioBuf;
1833  };
1834  /**
1835   *  processPeaks returns an array of timestamps where it thinks there is a beat.
1836   *
1837   *  This is an asynchronous function that processes the soundfile in an offline audio context,
1838   *  and sends the results to your callback function.
1839   *
1840   *  The process involves running the soundfile through a lowpass filter, and finding all of the
1841   *  peaks above the initial threshold. If the total number of peaks are below the minimum number of peaks,
1842   *  it decreases the threshold and re-runs the analysis until either minPeaks or minThreshold are reached.
1843   *  
1844   *  @method  processPeaks
1845   *  @param  {Function} callback       a function to call once this data is returned
1846   *  @param  {Number}   [initThreshold] initial threshold defaults to 0.9
1847   *  @param  {Number}   [minThreshold]   minimum threshold defaults to 0.22
1848   *  @param  {Number}   [minPeaks]       minimum number of peaks defaults to 200
1849   *  @return {Array}                  Array of timestamped peaks
1850   */
1851  p5.SoundFile.prototype.processPeaks = function (callback, _initThreshold, _minThreshold, _minPeaks) {
1852    var bufLen = this.buffer.length;
1853    var sampleRate = this.buffer.sampleRate;
1854    var buffer = this.buffer;
1855    var initialThreshold = _initThreshold || 0.9, threshold = initialThreshold, minThreshold = _minThreshold || 0.22, minPeaks = _minPeaks || 200;
1856    // Create offline context
1857    var offlineContext = new OfflineAudioContext(1, bufLen, sampleRate);
1858    // create buffer source
1859    var source = offlineContext.createBufferSource();
1860    source.buffer = buffer;
1861    // Create filter. TO DO: allow custom setting of filter
1862    var filter = offlineContext.createBiquadFilter();
1863    filter.type = 'lowpass';
1864    source.connect(filter);
1865    filter.connect(offlineContext.destination);
1866    // start playing at time:0
1867    source.start(0);
1868    offlineContext.startRendering();
1869    // Render the song
1870    // act on the result
1871    offlineContext.oncomplete = function (e) {
1872      var data = {};
1873      var filteredBuffer = e.renderedBuffer;
1874      var bufferData = filteredBuffer.getChannelData(0);
1875      // step 1: 
1876      // create Peak instances, add them to array, with strength and sampleIndex
1877      do {
1878        allPeaks = getPeaksAtThreshold(bufferData, threshold);
1879        threshold -= 0.005;
1880      } while (Object.keys(allPeaks).length < minPeaks && threshold >= minThreshold);
1881      // step 2:
1882      // find intervals for each peak in the sampleIndex, add tempos array
1883      var intervalCounts = countIntervalsBetweenNearbyPeaks(allPeaks);
1884      // step 3: find top tempos
1885      var groups = groupNeighborsByTempo(intervalCounts, filteredBuffer.sampleRate);
1886      // sort top intervals
1887      var topTempos = groups.sort(function (intA, intB) {
1888        return intB.count - intA.count;
1889      }).splice(0, 5);
1890      // set this SoundFile's tempo to the top tempo ??
1891      this.tempo = topTempos[0].tempo;
1892      // step 4:
1893      // new array of peaks at top tempo within a bpmVariance
1894      var bpmVariance = 5;
1895      var tempoPeaks = getPeaksAtTopTempo(allPeaks, topTempos[0].tempo, filteredBuffer.sampleRate, bpmVariance);
1896      callback(tempoPeaks);
1897    };
1898  };
1899  // process peaks
1900  var Peak = function (amp, i) {
1901    this.sampleIndex = i;
1902    this.amplitude = amp;
1903    this.tempos = [];
1904    this.intervals = [];
1905  };
1906  var allPeaks = [];
1907  // 1. for processPeaks() Function to identify peaks above a threshold
1908  // returns an array of peak indexes as frames (samples) of the original soundfile
1909  function getPeaksAtThreshold(data, threshold) {
1910    var peaksObj = {};
1911    var length = data.length;
1912    for (var i = 0; i < length; i++) {
1913      if (data[i] > threshold) {
1914        var amp = data[i];
1915        var peak = new Peak(amp, i);
1916        peaksObj[i] = peak;
1917        // Skip forward ~ 1/8s to get past this peak.
1918        i += 6000;
1919      }
1920      i++;
1921    }
1922    return peaksObj;
1923  }
1924  // 2. for processPeaks()
1925  function countIntervalsBetweenNearbyPeaks(peaksObj) {
1926    var intervalCounts = [];
1927    var peaksArray = Object.keys(peaksObj).sort();
1928    for (var index = 0; index < peaksArray.length; index++) {
1929      // find intervals in comparison to nearby peaks
1930      for (var i = 0; i < 10; i++) {
1931        var startPeak = peaksObj[peaksArray[index]];
1932        var endPeak = peaksObj[peaksArray[index + i]];
1933        if (startPeak && endPeak) {
1934          var startPos = startPeak.sampleIndex;
1935          var endPos = endPeak.sampleIndex;
1936          var interval = endPos - startPos;
1937          // add a sample interval to the startPeek in the allPeaks array
1938          if (interval > 0) {
1939            startPeak.intervals.push(interval);
1940          }
1941          // tally the intervals and return interval counts
1942          var foundInterval = intervalCounts.some(function (intervalCount, p) {
1943            if (intervalCount.interval === interval) {
1944              intervalCount.count++;
1945              return intervalCount;
1946            }
1947          });
1948          // store with JSON like formatting
1949          if (!foundInterval) {
1950            intervalCounts.push({
1951              interval: interval,
1952              count: 1
1953            });
1954          }
1955        }
1956      }
1957    }
1958    return intervalCounts;
1959  }
1960  // 3. for processPeaks --> find tempo
1961  function groupNeighborsByTempo(intervalCounts, sampleRate) {
1962    var tempoCounts = [];
1963    intervalCounts.forEach(function (intervalCount, i) {
1964      try {
1965        // Convert an interval to tempo
1966        var theoreticalTempo = Math.abs(60 / (intervalCount.interval / sampleRate));
1967        theoreticalTempo = mapTempo(theoreticalTempo);
1968        var foundTempo = tempoCounts.some(function (tempoCount) {
1969          if (tempoCount.tempo === theoreticalTempo)
1970            return tempoCount.count += intervalCount.count;
1971        });
1972        if (!foundTempo) {
1973          if (isNaN(theoreticalTempo)) {
1974            return;
1975          }
1976          tempoCounts.push({
1977            tempo: Math.round(theoreticalTempo),
1978            count: intervalCount.count
1979          });
1980        }
1981      } catch (e) {
1982        throw e;
1983      }
1984    });
1985    return tempoCounts;
1986  }
1987  // 4. for processPeaks - get peaks at top tempo
1988  function getPeaksAtTopTempo(peaksObj, tempo, sampleRate, bpmVariance) {
1989    var peaksAtTopTempo = [];
1990    var peaksArray = Object.keys(peaksObj).sort();
1991    // TO DO: filter out peaks that have the tempo and return
1992    for (var i = 0; i < peaksArray.length; i++) {
1993      var key = peaksArray[i];
1994      var peak = peaksObj[key];
1995      for (var j = 0; j < peak.intervals.length; j++) {
1996        var intervalBPM = Math.round(Math.abs(60 / (peak.intervals[j] / sampleRate)));
1997        intervalBPM = mapTempo(intervalBPM);
1998        var dif = intervalBPM - tempo;
1999        if (Math.abs(intervalBPM - tempo) < bpmVariance) {
2000          // convert sampleIndex to seconds
2001          peaksAtTopTempo.push(peak.sampleIndex / 44100);
2002        }
2003      }
2004    }
2005    // filter out peaks that are very close to each other
2006    peaksAtTopTempo = peaksAtTopTempo.filter(function (peakTime, index, arr) {
2007      var dif = arr[index + 1] - peakTime;
2008      if (dif > 0.01) {
2009        return true;
2010      }
2011    });
2012    return peaksAtTopTempo;
2013  }
2014  // helper function for processPeaks
2015  function mapTempo(theoreticalTempo) {
2016    // these scenarios create infinite while loop
2017    if (!isFinite(theoreticalTempo) || theoreticalTempo == 0) {
2018      return;
2019    }
2020    // Adjust the tempo to fit within the 90-180 BPM range
2021    while (theoreticalTempo < 90)
2022      theoreticalTempo *= 2;
2023    while (theoreticalTempo > 180 && theoreticalTempo > 90)
2024      theoreticalTempo /= 2;
2025    return theoreticalTempo;
2026  }
2027  /*** SCHEDULE EVENTS ***/
2028  /**
2029   *  Schedule events to trigger every time a MediaElement
2030   *  (audio/video) reaches a playback cue point.
2031   *
2032   *  Accepts a callback function, a time (in seconds) at which to trigger
2033   *  the callback, and an optional parameter for the callback.
2034   *
2035   *  Time will be passed as the first parameter to the callback function,
2036   *  and param will be the second parameter.
2037   *
2038   *
2039   *  @method  addCue
2040   *  @param {Number}   time     Time in seconds, relative to this media
2041   *                             element's playback. For example, to trigger
2042   *                             an event every time playback reaches two
2043   *                             seconds, pass in the number 2. This will be
2044   *                             passed as the first parameter to
2045   *                             the callback function.
2046   *  @param {Function} callback Name of a function that will be
2047   *                             called at the given time. The callback will
2048   *                             receive time and (optionally) param as its
2049   *                             two parameters.
2050   *  @param {Object} [value]    An object to be passed as the
2051   *                             second parameter to the
2052   *                             callback function.
2053   *  @return {Number} id ID of this cue,
2054   *                      useful for removeCue(id)
2055   *  @example
2056   *  <div><code>
2057   *  function setup() {
2058   *    background(0);
2059   *    noStroke();
2060   *    fill(255);
2061   *    textAlign(CENTER);
2062   *    text('click to play', width/2, height/2);
2063   *    
2064   *    mySound = loadSound('assets/beat.mp3');
2065   *
2066   *    // schedule calls to changeText
2067   *    mySound.addCue(0.50, changeText, "hello" );
2068   *    mySound.addCue(1.00, changeText, "p5" );
2069   *    mySound.addCue(1.50, changeText, "what" );
2070   *    mySound.addCue(2.00, changeText, "do" );
2071   *    mySound.addCue(2.50, changeText, "you" );
2072   *    mySound.addCue(3.00, changeText, "want" );
2073   *    mySound.addCue(4.00, changeText, "to" );
2074   *    mySound.addCue(5.00, changeText, "make" );
2075   *    mySound.addCue(6.00, changeText, "?" );
2076   *  }
2077   *
2078   *  function changeText(val) {
2079   *    background(0);
2080   *    text(val, width/2, height/2);
2081   *  }
2082   *
2083   *  function mouseClicked() {
2084   *    if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
2085   *      if (mySound.isPlaying() ) {
2086   *        mySound.stop();
2087   *      } else {
2088   *        mySound.play();
2089   *      }
2090   *    }
2091   *  }
2092   *  </code></div>
2093   */
2094  p5.SoundFile.prototype.addCue = function (time, callback, val) {
2095    var id = this._cueIDCounter++;
2096    var cue = new Cue(callback, time, id, val);
2097    this._cues.push(cue);
2098    // if (!this.elt.ontimeupdate) {
2099    //   this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
2100    // }
2101    return id;
2102  };
2103  /**
2104   *  Remove a callback based on its ID. The ID is returned by the
2105   *  addCue method.
2106   *
2107   *  @method removeCue
2108   *  @param  {Number} id ID of the cue, as returned by addCue
2109   */
2110  p5.SoundFile.prototype.removeCue = function (id) {
2111    var cueLength = this._cues.length;
2112    for (var i = 0; i < cueLength; i++) {
2113      var cue = this._cues[i];
2114      if (cue.id === id) {
2115        this.cues.splice(i, 1);
2116      }
2117    }
2118    if (this._cues.length === 0) {
2119    }
2120  };
2121  /**
2122   *  Remove all of the callbacks that had originally been scheduled
2123   *  via the addCue method.
2124   *
2125   *  @method  clearCues
2126   */
2127  p5.SoundFile.prototype.clearCues = function () {
2128    this._cues = [];
2129  };
2130  // private method that checks for cues to be fired if events
2131  // have been scheduled using addCue(callback, time).
2132  p5.SoundFile.prototype._onTimeUpdate = function (position) {
2133    var playbackTime = position / this.buffer.sampleRate;
2134    var cueLength = this._cues.length;
2135    for (var i = 0; i < cueLength; i++) {
2136      var cue = this._cues[i];
2137      var callbackTime = cue.time;
2138      var val = cue.val;
2139      if (this._prevTime < callbackTime && callbackTime <= playbackTime) {
2140        // pass the scheduled callbackTime as parameter to the callback
2141        cue.callback(val);
2142      }
2143    }
2144    this._prevTime = playbackTime;
2145  };
2146  // Cue inspired by JavaScript setTimeout, and the
2147  // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
2148  var Cue = function (callback, time, id, val) {
2149    this.callback = callback;
2150    this.time = time;
2151    this.id = id;
2152    this.val = val;
2153  };
2154}(sndcore, errorHandler, master);
2155var amplitude;
2156amplitude = function () {
2157  'use strict';
2158  var p5sound = master;
2159  /**
2160   *  Amplitude measures volume between 0.0 and 1.0.
2161   *  Listens to all p5sound by default, or use setInput()
2162   *  to listen to a specific sound source. Accepts an optional
2163   *  smoothing value, which defaults to 0. 
2164   *
2165   *  @class p5.Amplitude
2166   *  @constructor
2167   *  @param {Number} [smoothing] between 0.0 and .999 to smooth
2168   *                             amplitude readings (defaults to 0)
2169   *  @return {Object}    Amplitude Object
2170   *  @example
2171   *  <div><code>
2172   *  var sound, amplitude, cnv;
2173   *  
2174   *  function preload(){
2175   *    sound = loadSound('assets/beat.mp3');
2176   *  }
2177   *  function setup() {
2178   *    cnv = createCanvas(100,100);
2179   *    amplitude = new p5.Amplitude();
2180   *
2181   *    // start / stop the sound when canvas is clicked
2182   *    cnv.mouseClicked(function() {
2183   *      if (sound.isPlaying() ){
2184   *        sound.stop();
2185   *      } else {
2186   *        sound.play();
2187   *      }
2188   *    });
2189   *  }
2190   *  function draw() {
2191   *    background(0);
2192   *    fill(255);
2193   *    var level = amplitude.getLevel();
2194   *    var size = map(level, 0, 1, 0, 200);
2195   *    ellipse(width/2, height/2, size, size);
2196   *  }
2197   *
2198   *  </code></div>
2199   */
2200  p5.Amplitude = function (smoothing) {
2201    // Set to 2048 for now. In future iterations, this should be inherited or parsed from p5sound's default
2202    this.bufferSize = 2048;
2203    // set audio context
2204    this.audiocontext = p5sound.audiocontext;
2205    this.processor = this.audiocontext.createScriptProcessor(this.bufferSize, 2, 1);
2206    // for connections
2207    this.input = this.processor;
2208    this.output = this.audiocontext.createGain();
2209    // smoothing defaults to 0
2210    this.smoothing = smoothing || 0;
2211    // the variables to return
2212    this.volume = 0;
2213    this.average = 0;
2214    this.stereoVol = [
2215      0,
2216      0
2217    ];
2218    this.stereoAvg = [
2219      0,
2220      0
2221    ];
2222    this.stereoVolNorm = [
2223      0,
2224      0
2225    ];
2226    this.volMax = 0.001;
2227    this.normalize = false;
2228    this.processor.onaudioprocess = this._audioProcess.bind(this);
2229    this.processor.connect(this.output);
2230    this.output.gain.value = 0;
2231    // this may only be necessary because of a Chrome bug
2232    this.output.connect(this.audiocontext.destination);
2233    // connect to p5sound master output by default, unless set by input()
2234    p5sound.meter.connect(this.processor);
2235    // add this p5.SoundFile to the soundArray
2236    p5sound.soundArray.push(this);
2237  };
2238  /**
2239   *  Connects to the p5sound instance (master output) by default.
2240   *  Optionally, you can pass in a specific source (i.e. a soundfile).
2241   *
2242   *  @method setInput
2243   *  @param {soundObject|undefined} [snd] set the sound source
2244   *                                       (optional, defaults to
2245   *                                       master output)
2246   *  @param {Number|undefined} [smoothing] a range between 0.0 and 1.0
2247   *                                        to smooth amplitude readings
2248   *  @example
2249   *  <div><code>
2250   *  function preload(){
2251   *    sound1 = loadSound('assets/beat.mp3');
2252   *    sound2 = loadSound('assets/drum.mp3');
2253   *  }
2254   *  function setup(){
2255   *    amplitude = new p5.Amplitude();
2256   *    sound1.play();
2257   *    sound2.play();
2258   *    amplitude.setInput(sound2);
2259   *  }
2260   *  function draw() {
2261   *    background(0);
2262   *    fill(255);
2263   *    var level = amplitude.getLevel();
2264   *    var size = map(level, 0, 1, 0, 200);
2265   *    ellipse(width/2, height/2, size, size);
2266   *  }
2267   *  function mouseClicked(){
2268   *    sound1.stop();
2269   *    sound2.stop();
2270   *  }
2271   *  </code></div>
2272   */
2273  p5.Amplitude.prototype.setInput = function (source, smoothing) {
2274    p5sound.meter.disconnect();
2275    if (smoothing) {
2276      this.smoothing = smoothing;
2277    }
2278    // connect to the master out of p5s instance if no snd is provided
2279    if (source == null) {
2280      console.log('Amplitude input source is not ready! Connecting to master output instead');
2281      p5sound.meter.connect(this.processor);
2282    } else if (source instanceof p5.Signal) {
2283      source.output.connect(this.processor);
2284    } else if (source) {
2285      source.connect(this.processor);
2286      this.processor.disconnect();
2287      this.processor.connect(this.output);
2288    } else {
2289      p5sound.meter.connect(this.processor);
2290    }
2291  };
2292  p5.Amplitude.prototype.connect = function (unit) {
2293    if (unit) {
2294      if (unit.hasOwnProperty('input')) {
2295        this.output.connect(unit.input);
2296      } else {
2297        this.output.connect(unit);
2298      }
2299    } else {
2300      this.output.connect(this.panner.connect(p5sound.input));
2301    }
2302  };
2303  p5.Amplitude.prototype.disconnect = function (unit) {
2304    this.output.disconnect();
2305  };
2306  // TO DO make this stereo / dependent on # of audio channels
2307  p5.Amplitude.prototype._audioProcess = function (event) {
2308    for (var channel = 0; channel < event.inputBuffer.numberOfChannels; channel++) {
2309      var inputBuffer = event.inputBuffer.getChannelData(channel);
2310      var bufLength = inputBuffer.length;
2311      var total = 0;
2312      var sum = 0;
2313      var x;
2314      for (var i = 0; i < bufLength; i++) {
2315        x = inputBuffer[i];
2316        if (this.normalize) {
2317          total += Math.max(Math.min(x / this.volMax, 1), -1);
2318          sum += Math.max(Math.min(x / this.volMax, 1), -1) * Math.max(Math.min(x / this.volMax, 1), -1);
2319        } else {
2320          total += x;
2321          sum += x * x;
2322        }
2323      }
2324      var average = total / bufLength;
2325      // ... then take the square root of the sum.
2326      var rms = Math.sqrt(sum / bufLength);
2327      this.stereoVol[channel] = Math.max(rms, this.stereoVol[channel] * this.smoothing);
2328      this.stereoAvg[channel] = Math.max(average, this.stereoVol[channel] * this.smoothing);
2329      this.volMax = Math.max(this.stereoVol[channel], this.volMax);
2330    }
2331    // add volume from all channels together
2332    var self = this;
2333    var volSum = this.stereoVol.reduce(function (previousValue, currentValue, index) {
2334      self.stereoVolNorm[index - 1] = Math.max(Math.min(self.stereoVol[index - 1] / self.volMax, 1), 0);
2335      self.stereoVolNorm[index] = Math.max(Math.min(self.stereoVol[index] / self.volMax, 1), 0);
2336      return previousValue + currentValue;
2337    });
2338    // volume is average of channels
2339    this.volume = volSum / this.stereoVol.length;
2340    // normalized value
2341    this.volNorm = Math.max(Math.min(this.volume / this.volMax, 1), 0);
2342  };
2343  /**
2344   *  Returns a single Amplitude reading at the moment it is called.
2345   *  For continuous readings, run in the draw loop.
2346   *
2347   *  @method getLevel
2348   *  @param {Number} [channel] Optionally return only channel 0 (left) or 1 (right)
2349   *  @return {Number}       Amplitude as a number between 0.0 and 1.0
2350   *  @example
2351   *  <div><code>
2352   *  function preload(){
2353   *    sound = loadSound('assets/beat.mp3');
2354   *  }
2355   *  function setup() { 
2356   *    amplitude = new p5.Amplitude();
2357   *    sound.play();
2358   *  }
2359   *  function draw() {
2360   *    background(0);
2361   *    fill(255);
2362   *    var level = amplitude.getLevel();
2363   *    var size = map(level, 0, 1, 0, 200);
2364   *    ellipse(width/2, height/2, size, size);
2365   *  }
2366   *  function mouseClicked(){
2367   *    sound.stop();
2368   *  }
2369   *  </code></div>
2370   */
2371  p5.Amplitude.prototype.getLevel = function (channel) {
2372    if (typeof channel !== 'undefined') {
2373      if (this.normalize) {
2374        return this.stereoVolNorm[channel];
2375      } else {
2376        return this.stereoVol[channel];
2377      }
2378    } else if (this.normalize) {
2379      return this.volNorm;
2380    } else {
2381      return this.volume;
2382    }
2383  };
2384  /**
2385   * Determines whether the results of Amplitude.process() will be
2386   * Normalized. To normalize, Amplitude finds the difference the
2387   * loudest reading it has processed and the maximum amplitude of
2388   * 1.0. Amplitude adds this difference to all values to produce
2389   * results that will reliably map between 0.0 and 1.0. However,
2390   * if a louder moment occurs, the amount that Normalize adds to
2391   * all the values will change. Accepts an optional boolean parameter
2392   * (true or false). Normalizing is off by default.
2393   *
2394   * @method toggleNormalize
2395   * @param {boolean} [boolean] set normalize to true (1) or false (0)
2396   */
2397  p5.Amplitude.prototype.toggleNormalize = function (bool) {
2398    if (typeof bool === 'boolean') {
2399      this.normalize = bool;
2400    } else {
2401      this.normalize = !this.normalize;
2402    }
2403  };
2404  /**
2405   *  Smooth Amplitude analysis by averaging with the last analysis 
2406   *  frame. Off by default.
2407   *
2408   *  @method smooth
2409   *  @param {Number} set smoothing from 0.0 <= 1
2410   */
2411  p5.Amplitude.prototype.smooth = function (s) {
2412    if (s >= 0 && s < 1) {
2413      this.smoothing = s;
2414    } else {
2415      console.log('Error: smoothing must be between 0 and 1');
2416    }
2417  };
2418  p5.Amplitude.prototype.dispose = function () {
2419    // remove reference from soundArray
2420    var index = p5sound.soundArray.indexOf(this);
2421    p5sound.soundArray.splice(index, 1);
2422    this.input.disconnect();
2423    this.output.disconnect();
2424    this.input = this.processor = undefined;
2425    this.output = undefined;
2426  };
2427}(master);
2428var fft;
2429fft = function () {
2430  'use strict';
2431  var p5sound = master;
2432  /**
2433   *  <p>
2433FFT (Fast Fourier Transform) is an analysis algorithm that
2434   *  isolates individual
2435   *  <a href="https://en.wikipedia.org/wiki/Audio_frequency">
2436   *  audio frequencies</a> within a waveform.</p>
2437   *
2438   *  <p>Once instantiated, a p5.FFT object can return an array based on
2439   *  two types of analyses: <br> • <code>FFT.waveform()</code> computes
2440   *  amplitude values along the time domain. The array indices correspond
2441   *  to samples across a brief moment in time. Each value represents
2442   *  amplitude of the waveform at that sample of time.<br>
2443   *  • <code>FFT.analyze() </code> computes amplitude values along the
2444   *  frequency domain. The array indices correspond to frequencies (i.e.
2445   *  pitches), from the lowest to the highest that humans can hear. Each
2446   *  value represents amplitude at that slice of the frequency spectrum.
2447   *  Use with <code>getEnergy()</code> to measure amplitude at specific
2448   *  frequencies, or within a range of frequencies. </p>
2449   *
2450   *  <p>FFT analyzes a very short snapshot of sound called a sample
2451   *  buffer. It returns an array of amplitude measurements, referred
2452   *  to as <code>bins</code>. The array is 1024 bins long by default.
2453   *  You can change the bin array length, but it must be a power of 2
2454   *  between 16 and 1024 in order for the FFT algorithm to function
2455   *  correctly. The actual size of the FFT buffer is twice the 
2456   *  number of bins, so given a standard sample rate, the buffer is
2457   *  2048/44100 seconds long.</p>
2458   *  
2459   * 
2460   *  @class p5.FFT
2461   *  @constructor
2462   *  @param {Number} [smoothing]   Smooth results of Freq Spectrum.
2463   *                                0.0 < smoothing < 1.0.
2464   *                                Defaults to 0.8.
2465   *  @param {Number} [bins]    Length of resulting array.
2466   *                            Must be a power of two between
2467   *                            16 and 1024. Defaults to 1024.
2468   *  @return {Object}    FFT Object
2469   *  @example
2470   *  <div><code>
2471   *  function preload(){
2472   *    sound = loadSound('assets/Damscray_DancingTiger.mp3');
2473   *  }
2474   *  
2475   *  function setup(){
2476   *    var cnv = createCanvas(100,100);
2477   *    cnv.mouseClicked(togglePlay);
2478   *    fft = new p5.FFT();
2479   *    sound.amp(0.2);
2480   *  }
2481   *  
2482   *  function draw(){
2483   *    background(0);
2484   *  
2485   *    var spectrum = fft.analyze(); 
2486   *    noStroke();
2487   *    fill(0,255,0); // spectrum is green
2488   *    for (var i = 0; i< spectrum.length; i++){
2489   *      var x = map(i, 0, spectrum.length, 0, width);
2490   *      var h = -height + map(spectrum[i], 0, 255, height, 0);
2491   *      rect(x, height, width / spectrum.length, h )
2492   *    }
2493   *  
2494   *    var waveform = fft.waveform();
2495   *    noFill();
2496   *    beginShape();
2497   *    stroke(255,0,0); // waveform is red
2498   *    strokeWeight(1);
2499   *    for (var i = 0; i< waveform.length; i++){
2500   *      var x = map(i, 0, waveform.length, 0, width);
2501   *      var y = map( waveform[i], -1, 1, 0, height);
2502   *      vertex(x,y);
2503   *    }
2504   *    endShape();
2505   *  
2506   *    text('click to play/pause', 4, 10);
2507   *  }
2508   *  
2509   *  // fade sound if mouse is over canvas
2510   *  function togglePlay() {
2511   *    if (sound.isPlaying()) {
2512   *      sound.pause();
2513   *    } else {
2514   *      sound.loop();
2515   *    }
2516   *  }
2517   *  </code></div>
2518   */
2519  p5.FFT = function (smoothing, bins) {
2520    this.smoothing = smoothing || 0.8;
2521    this.bins = bins || 1024;
2522    var FFT_SIZE = bins * 2 || 2048;
2523    this.input = this.analyser = p5sound.audiocontext.createAnalyser();
2524    // default connections to p5sound fftMeter
2525    p5sound.fftMeter.connect(this.analyser);
2526    this.analyser.smoothingTimeConstant = this.smoothing;
2527    this.analyser.fftSize = FFT_SIZE;
2528    this.freqDomain = new Uint8Array(this.analyser.frequencyBinCount);
2529    this.timeDomain = new Uint8Array(this.analyser.frequencyBinCount);
2530    // predefined frequency ranages, these will be tweakable
2531    this.bass = [
2532      20,
2533      140
2534    ];
2535    this.lowMid = [
2536      140,
2537      400
2538    ];
2539    this.mid = [
2540      400,
2541      2600
2542    ];
2543    this.highMid = [
2544      2600,
2545      5200
2546    ];
2547    this.treble = [
2548      5200,
2549      14000
2550    ];
2551    // add this p5.SoundFile to the soundArray
2552    p5sound.soundArray.push(this);
2553  };
2554  /**
2555   *  Set the input source for the FFT analysis. If no source is
2556   *  provided, FFT will analyze all sound in the sketch.
2557   *
2558   *  @method  setInput
2559   *  @param {Object} [source] p5.sound object (or web audio API source node)
2560   */
2561  p5.FFT.prototype.setInput = function (source) {
2562    if (!source) {
2563      p5sound.fftMeter.connect(this.analyser);
2564    } else {
2565      if (source.output) {
2566        source.output.connect(this.analyser);
2567      } else if (source.connect) {
2568        source.connect(this.analyser);
2569      }
2570      p5sound.fftMeter.disconnect();
2571    }
2572  };
2573  /**
2574   *  Returns an array of amplitude values (between -1.0 and +1.0) that represent
2575   *  a snapshot of amplitude readings in a single buffer. Length will be
2576   *  equal to bins (defaults to 1024). Can be used to draw the waveform
2577   *  of a sound. 
2578   *  
2579   *  @method waveform
2580   *  @param {Number} [bins]    Must be a power of two between
2581   *                            16 and 1024. Defaults to 1024.
2582   *  @param {String} [precision] If any value is provided, will return results
2583   *                              in a Float32 Array which is more precise
2584   *                              than a regular array.
2585   *  @return {Array}  Array    Array of amplitude values (-1 to 1)
2586   *                            over time. Array length = bins.
2587   *
2588   */
2589  p5.FFT.prototype.waveform = function () {
2590    var bins, mode, normalArray;
2591    for (var i = 0; i < arguments.length; i++) {
2592      if (typeof arguments[i] === 'number') {
2593        bins = arguments[i];
2594        this.analyser.fftSize = bins * 2;
2595      }
2596      if (typeof arguments[i] === 'string') {
2597        mode = arguments[i];
2598      }
2599    }
2600    // getFloatFrequencyData doesnt work in Safari as of 5/2015
2601    if (mode && !p5.prototype._isSafari()) {
2602      timeToFloat(this, this.timeDomain);
2603      this.analyser.getFloatTimeDomainData(this.timeDomain);
2604      return this.timeDomain;
2605    } else {
2606      timeToInt(this, this.timeDomain);
2607      this.analyser.getByteTimeDomainData(this.timeDomain);
2608      var normalArray = new Array();
2609      for (var i = 0; i < this.timeDomain.length; i++) {
2610        var scaled = p5.prototype.map(this.timeDomain[i], 0, 255, -1, 1);
2611        normalArray.push(scaled);
2612      }
2613      return normalArray;
2614    }
2615  };
2616  /**
2617   *  Returns an array of amplitude values (between 0 and 255)
2618   *  across the frequency spectrum. Length is equal to FFT bins
2619   *  (1024 by default). The array indices correspond to frequencies
2620   *  (i.e. pitches), from the lowest to the highest that humans can
2621   *  hear. Each value represents amplitude at that slice of the
2622   *  frequency spectrum. Must be called prior to using
2623   *  <code>getEnergy()</code>.
2624   *
2625   *  @method analyze
2626   *  @param {Number} [bins]    Must be a power of two between
2627   *                             16 and 1024. Defaults to 1024.
2628   *  @param {Number} [scale]    If "dB," returns decibel
2629   *                             float measurements between
2630   *                             -140 and 0 (max).
2631   *                             Otherwise returns integers from 0-255.
2632   *  @return {Array} spectrum    Array of energy (amplitude/volume)
2633   *                              values across the frequency spectrum.
2634   *                              Lowest energy (silence) = 0, highest
2635   *                              possible is 255.
2636   *  @example
2637   *  <div><code>
2638   *  var osc;
2639   *  var fft;
2640   *
2641   *  function setup(){
2642   *    createCanvas(100,100);
2643   *    osc = new p5.Oscillator();
2644   *    osc.amp(0);
2645   *    osc.start();
2646   *    fft = new p5.FFT();
2647   *  }
2648   *
2649   *  function draw(){
2650   *    background(0);
2651   *
2652   *    var freq = map(mouseX, 0, 800, 20, 15000);
2653   *    freq = constrain(freq, 1, 20000);
2654   *    osc.freq(freq);
2655   *
2656   *    var spectrum = fft.analyze(); 
2657   *    noStroke();
2658   *    fill(0,255,0); // spectrum is green
2659   *    for (var i = 0; i< spectrum.length; i++){
2660   *      var x = map(i, 0, spectrum.length, 0, width);
2661   *      var h = -height + map(spectrum[i], 0, 255, height, 0);
2662   *      rect(x, height, width / spectrum.length, h );
2663   *    }
2664   *
2665   *    stroke(255);
2666   *    text('Freq: ' + round(freq)+'Hz', 10, 10); 
2667   *
2668   *    isMouseOverCanvas();
2669   *  }
2670   *
2671   *  // only play sound when mouse is over canvas
2672   *  function isMouseOverCanvas() {
2673   *    var mX = mouseX, mY = mouseY;
2674   *    if (mX > 0 && mX < width && mY < height && mY > 0) {
2675   *      osc.amp(0.5, 0.2);
2676   *    } else {
2677   *      osc.amp(0, 0.2);
2678   *    }
2679   *  }
2680   *  </code></div>
2681   *                                   
2682   *
2683   */
2684  p5.FFT.prototype.analyze = function () {
2685    var bins, mode;
2686    for (var i = 0; i < arguments.length; i++) {
2687      if (typeof arguments[i] === 'number') {
2688        bins = this.bins = arguments[i];
2689        this.analyser.fftSize = this.bins * 2;
2690      }
2691      if (typeof arguments[i] === 'string') {
2692        mode = arguments[i];
2693      }
2694    }
2695    if (mode && mode.toLowerCase() === 'db') {
2696      freqToFloat(this);
2697      this.analyser.getFloatFrequencyData(this.freqDomain);
2698      return this.freqDomain;
2699    } else {
2700      freqToInt(this, this.freqDomain);
2701      this.analyser.getByteFrequencyData(this.freqDomain);
2702      var normalArray = Array.apply([], this.freqDomain);
2703      normalArray.length === this.analyser.fftSize;
2704      normalArray.constructor === Array;
2705      return normalArray;
2706    }
2707  };
2708  /**
2709   *  Returns the amount of energy (volume) at a specific
2710   *  <a href="en.wikipedia.org/wiki/Audio_frequency" target="_blank">
2711   *  frequency</a>, or the average amount of energy between two
2712   *  frequencies. Accepts Number(s) corresponding
2713   *  to frequency (in Hz), or a String corresponding to predefined
2714   *  frequency ranges ("bass", "lowMid", "mid", "highMid", "treble").
2715   *  Returns a range between 0 (no energy/volume at that frequency) and
2716   *  255 (maximum energy). 
2717   *  <em>NOTE: analyze() must be called prior to getEnergy(). Analyze()
2718   *  tells the FFT to analyze frequency data, and getEnergy() uses
2719   *  the results determine the value at a specific frequency or
2720   *  range of frequencies.</em></p>
2721   *  
2722   *  @method  getEnergy
2723   *  @param  {Number|String} frequency1   Will return a value representing
2724   *                                energy at this frequency. Alternately,
2725   *                                the strings "bass", "lowMid" "mid",
2726   *                                "highMid", and "treble" will return
2727   *                                predefined frequency ranges.
2728   *  @param  {Number} [frequency2] If a second frequency is given,
2729   *                                will return average amount of
2730   *                                energy that exists between the
2731   *                                two frequencies.
2732   *  @return {Number}   Energy   Energy (volume/amplitude) from
2733   *                              0 and 255.
2734   *                                       
2735   */
2736  p5.FFT.prototype.getEnergy = function (frequency1, frequency2) {
2737    var nyquist = p5sound.audiocontext.sampleRate / 2;
2738    if (frequency1 === 'bass') {
2739      frequency1 = this.bass[0];
2740      frequency2 = this.bass[1];
2741    } else if (frequency1 === 'lowMid') {
2742      frequency1 = this.lowMid[0];
2743      frequency2 = this.lowMid[1];
2744    } else if (frequency1 === 'mid') {
2745      frequency1 = this.mid[0];
2746      frequency2 = this.mid[1];
2747    } else if (frequency1 === 'highMid') {
2748      frequency1 = this.highMid[0];
2749      frequency2 = this.highMid[1];
2750    } else if (frequency1 === 'treble') {
2751      frequency1 = this.treble[0];
2752      frequency2 = this.treble[1];
2753    }
2754    if (typeof frequency1 !== 'number') {
2755      throw 'invalid input for getEnergy()';
2756    } else if (!frequency2) {
2757      var index = Math.round(frequency1 / nyquist * this.freqDomain.length);
2758      return this.freqDomain[index];
2759    } else if (frequency1 && frequency2) {
2760      // if second is higher than first
2761      if (frequency1 > frequency2) {
2762        var swap = frequency2;
2763        frequency2 = frequency1;
2764        frequency1 = swap;
2765      }
2766      var lowIndex = Math.round(frequency1 / nyquist * this.freqDomain.length);
2767      var highIndex = Math.round(frequency2 / nyquist * this.freqDomain.length);
2768      var total = 0;
2769      var numFrequencies = 0;
2770      // add up all of the values for the frequencies
2771      for (var i = lowIndex; i <= highIndex; i++) {
2772        total += this.freqDomain[i];
2773        numFrequencies += 1;
2774      }
2775      // divide by total number of frequencies
2776      var toReturn = total / numFrequencies;
2777      return toReturn;
2778    } else {
2779      throw 'invalid input for getEnergy()';
2780    }
2781  };
2782  // compatability with v.012, changed to getEnergy in v.0121. Will be deprecated...
2783  p5.FFT.prototype.getFreq = function (freq1, freq2) {
2784    console.log('getFreq() is deprecated. Please use getEnergy() instead.');
2785    var x = this.getEnergy(freq1, freq2);
2786    return x;
2787  };
2788  /**
2789   *  Returns the 
2790   *  <a href="http://en.wikipedia.org/wiki/Spectral_centroid" target="_blank">
2791   *  spectral centroid</a> of the input signal.
2792   *  <em>NOTE: analyze() must be called prior to getCentroid(). Analyze()
2793   *  tells the FFT to analyze frequency data, and getCentroid() uses
2794   *  the results determine the spectral centroid.</em></p>
2795   *  
2796   *  @method  getCentroid
2797   *  @return {Number}   Spectral Centroid Frequency   Frequency of the spectral centroid in Hz.
2798   * 
2799   *
2800   * @example
2801   *  <div><code>
2802   *
2803   *
2804   *function setup(){
2805   *  cnv = createCanvas(800,400);
2806   *  sound = new p5.AudioIn();
2807   *  sound.start();
2808   *  fft = new p5.FFT();
2809   *  sound.connect(fft);
2810   *}
2811   *
2812   *
2813   *function draw(){
2814   *
2815   *  var centroidplot = 0.0;
2816   *  var spectralCentroid = 0;
2817   *  
2818   *  
2819   *  background(0);
2820   *  stroke(0,255,0);
2821   *  var spectrum = fft.analyze(); 
2822   *  fill(0,255,0); // spectrum is green
2823   *  
2824   *  //draw the spectrum
2825   *  
2826   *  for (var i = 0; i< spectrum.length; i++){
2827   *    var x = map(log(i), 0, log(spectrum.length), 0, width);
2828   *    var h = map(spectrum[i], 0, 255, 0, height);
2829   *    var rectangle_width = (log(i+1)-log(i))*(width/log(spectrum.length));
2830   *    rect(x, height, rectangle_width, -h )
2831   *  }
2832  
2833   *  var nyquist = 22050;
2834   *  
2835   *  // get the centroid
2836   *  spectralCentroid = fft.getCentroid();
2837   *  
2838   *  // the mean_freq_index calculation is for the display.
2839   *  var mean_freq_index = spectralCentroid/(nyquist/spectrum.length);
2840   *
2841   *  centroidplot = map(log(mean_freq_index), 0, log(spectrum.length), 0, width);
2842   *
2843   *
2844   *  stroke(255,0,0); // the line showing where the centroid is will be red
2845   *  
2846   *  rect(centroidplot, 0, width / spectrum.length, height)
2847   *  noStroke();
2848   *  fill(255,255,255);  // text is white
2849   *  textSize(40);
2850   *  text("centroid: "+round(spectralCentroid)+" Hz", 10, 40);
2851   *}
2852   * </code></div>
2853   */
2854  p5.FFT.prototype.getCentroid = function () {
2855    var nyquist = p5sound.audiocontext.sampleRate / 2;
2856    var cumulative_sum = 0;
2857    var centroid_normalization = 0;
2858    for (var i = 0; i < this.freqDomain.length; i++) {
2859      cumulative_sum += i * this.freqDomain[i];
2860      centroid_normalization += this.freqDomain[i];
2861    }
2862    var mean_freq_index = 0;
2863    if (centroid_normalization != 0) {
2864      mean_freq_index = cumulative_sum / centroid_normalization;
2865    }
2866    var spec_centroid_freq = mean_freq_index * (nyquist / this.freqDomain.length);
2867    return spec_centroid_freq;
2868  };
2869  /**
2870   *  Smooth FFT analysis by averaging with the last analysis frame.
2871   *  
2872   *  @method smooth
2873   *  @param {Number} smoothing    0.0 < smoothing < 1.0.
2874   *                               Defaults to 0.8.
2875   */
2876  p5.FFT.prototype.smooth = function (s) {
2877    if (s) {
2878      this.smoothing = s;
2879    }
2880    this.analyser.smoothingTimeConstant = s;
2881  };
2882  p5.FFT.prototype.dispose = function () {
2883    // remove reference from soundArray
2884    var index = p5sound.soundArray.indexOf(this);
2885    p5sound.soundArray.splice(index, 1);
2886    this.analyser.disconnect();
2887    this.analyser = undefined;
2888  };
2889  // helper methods to convert type from float (dB) to int (0-255)
2890  var freqToFloat = function (fft) {
2891    if (fft.freqDomain instanceof Float32Array === false) {
2892      fft.freqDomain = new Float32Array(fft.analyser.frequencyBinCount);
2893    }
2894  };
2895  var freqToInt = function (fft) {
2896    if (fft.freqDomain instanceof Uint8Array === false) {
2897      fft.freqDomain = new Uint8Array(fft.analyser.frequencyBinCount);
2898    }
2899  };
2900  var timeToFloat = function (fft) {
2901    if (fft.timeDomain instanceof Float32Array === false) {
2902      fft.timeDomain = new Float32Array(fft.analyser.frequencyBinCount);
2903    }
2904  };
2905  var timeToInt = function (fft) {
2906    if (fft.timeDomain instanceof Uint8Array === false) {
2907      fft.timeDomain = new Uint8Array(fft.analyser.frequencyBinCount);
2908    }
2909  };
2910}(master);
2911/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
2912var Tone_core_Tone;
2913Tone_core_Tone = function () {
2914  'use strict';
2915  function isUndef(val) {
2916    return val === void 0;
2917  }
2918  function isFunction(val) {
2919    return typeof val === 'function';
2920  }
2921  var audioContext;
2922  if (isUndef(window.AudioContext)) {
2923    window.AudioContext = window.webkitAudioContext;
2924  }
2925  if (isUndef(window.OfflineAudioContext)) {
2926    window.OfflineAudioContext = window.webkitOfflineAudioContext;
2927  }
2928  if (!isUndef(AudioContext)) {
2929    audioContext = new AudioContext();
2930  } else {
2931    throw new Error('Web Audio is not supported in this browser');
2932  }
2933  if (!isFunction(AudioContext.prototype.createGain)) {
2934    AudioContext.prototype.createGain = AudioContext.prototype.createGainNode;
2935  }
2936  if (!isFunction(AudioContext.prototype.createDelay)) {
2937    AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode;
2938  }
2939  if (!isFunction(AudioContext.prototype.createPeriodicWave)) {
2940    AudioContext.prototype.createPeriodicWave = AudioContext.prototype.createWaveTable;
2941  }
2942  if (!isFunction(AudioBufferSourceNode.prototype.start)) {
2943    AudioBufferSourceNode.prototype.start = AudioBufferSourceNode.prototype.noteGrainOn;
2944  }
2945  if (!isFunction(AudioBufferSourceNode.prototype.stop)) {
2946    AudioBufferSourceNode.prototype.stop = AudioBufferSourceNode.prototype.noteOff;
2947  }
2948  if (!isFunction(OscillatorNode.prototype.start)) {
2949    OscillatorNode.prototype.start = OscillatorNode.prototype.noteOn;
2950  }
2951  if (!isFunction(OscillatorNode.prototype.stop)) {
2952    OscillatorNode.prototype.stop = OscillatorNode.prototype.noteOff;
2953  }
2954  if (!isFunction(OscillatorNode.prototype.setPeriodicWave)) {
2955    OscillatorNode.prototype.setPeriodicWave = OscillatorNode.prototype.setWaveTable;
2956  }
2957  AudioNode.prototype._nativeConnect = AudioNode.prototype.connect;
2958  AudioNode.prototype.connect = function (B, outNum, inNum) {
2959    if (B.input) {
2960      if (Array.isArray(B.input)) {
2961        if (isUndef(inNum)) {
2962          inNum = 0;
2963        }
2964        this.connect(B.input[inNum]);
2965      } else {
2966        this.connect(B.input, outNum, inNum);
2967      }
2968    } else {
2969      try {
2970        if (B instanceof AudioNode) {
2971          this._nativeConnect(B, outNum, inNum);
2972        } else {
2973          this._nativeConnect(B, outNum);
2974        }
2975      } catch (e) {
2976        throw new Error('error connecting to node: ' + B);
2977      }
2978    }
2979  };
2980  var Tone = function (inputs, outputs) {
2981    if (isUndef(inputs) || inputs === 1) {
2982      this.input = this.context.createGain();
2983    } else if (inputs > 1) {
2984      this.input = new Array(inputs);
2985    }
2986    if (isUndef(outputs) || outputs === 1) {
2987      this.output = this.context.createGain();
2988    } else if (outputs > 1) {
2989      this.output = new Array(inputs);
2990    }
2991  };
2992  Tone.prototype.set = function (params, value, rampTime) {
2993    if (this.isObject(params)) {
2994      rampTime = value;
2995    } else if (this.isString(params)) {
2996      var tmpObj = {};
2997      tmpObj[params] = value;
2998      params = tmpObj;
2999    }
3000    for (var attr in params) {
3001      value = params[attr];
3002      var parent = this;
3003      if (attr.indexOf('.') !== -1) {
3004        var attrSplit = attr.split('.');
3005        for (var i = 0; i < attrSplit.length - 1; i++) {
3006          parent = parent[attrSplit[i]];
3007        }
3008        attr = attrSplit[attrSplit.length - 1];
3009      }
3010      var param = parent[attr];
3011      if (isUndef(param)) {
3012        continue;
3013      }
3014      if (Tone.Signal && param instanceof Tone.Signal || Tone.Param && param instanceof Tone.Param) {
3015        if (param.value !== value) {
3016          if (isUndef(rampTime)) {
3017            param.value = value;
3018          } else {
3019            param.rampTo(value, rampTime);
3020          }
3021        }
3022      } else if (param instanceof AudioParam) {
3023        if (param.value !== value) {
3024          param.value = value;
3025        }
3026      } else if (param instanceof Tone) {
3027        param.set(value);
3028      } else if (param !== value) {
3029        parent[attr] = value;
3030      }
3031    }
3032    return this;
3033  };
3034  Tone.prototype.get = function (params) {
3035    if (isUndef(params)) {
3036      params = this._collectDefaults(this.constructor);
3037    } else if (this.isString(params)) {
3038      params = [params];
3039    }
3040    var ret = {};
3041    for (var i = 0; i < params.length; i++) {
3042      var attr = params[i];
3043      var parent = this;
3044      var subRet = ret;
3045      if (attr.indexOf('.') !== -1) {
3046        var attrSplit = attr.split('.');
3047        for (var j = 0; j < attrSplit.length - 1; j++) {
3048          var subAttr = attrSplit[j];
3049          subRet[subAttr] = subRet[subAttr] || {};
3050          subRet = subRet[subAttr];
3051          parent = parent[subAttr];
3052        }
3053        attr = attrSplit[attrSplit.length - 1];
3054      }
3055      var param = parent[attr];
3056      if (this.isObject(params[attr])) {
3057        subRet[attr] = param.get();
3058      } else if (Tone.Signal && param instanceof Tone.Signal) {
3059        subRet[attr] = param.value;
3060      } else if (Tone.Param && param instanceof Tone.Param) {
3061        subRet[attr] = param.value;
3062      } else if (param instanceof AudioParam) {
3063        subRet[attr] = param.value;
3064      } else if (param instanceof Tone) {
3065        subRet[attr] = param.get();
3066      } else if (!isFunction(param) && !isUndef(param)) {
3067        subRet[attr] = param;
3068      }
3069    }
3070    return ret;
3071  };
3072  Tone.prototype._collectDefaults = function (constr) {
3073    var ret = [];
3074    if (!isUndef(constr.defaults)) {
3075      ret = Object.keys(constr.defaults);
3076    }
3077    if (!isUndef(constr._super)) {
3078      var superDefs = this._collectDefaults(constr._super);
3079      for (var i = 0; i < superDefs.length; i++) {
3080        if (ret.indexOf(superDefs[i]) === -1) {
3081          ret.push(superDefs[i]);
3082        }
3083      }
3084    }
3085    return ret;
3086  };
3087  Tone.prototype.toString = function () {
3088    for (var className in Tone) {
3089      var isLetter = className[0].match(/^[A-Z]$/);
3090      var sameConstructor = Tone[className] === this.constructor;
3091      if (isFunction(Tone[className]) && isLetter && sameConstructor) {
3092        return className;
3093      }
3094    }
3095    return 'Tone';
3096  };
3097  Tone.context = audioContext;
3098  Tone.prototype.context = Tone.context;
3099  Tone.prototype.bufferSize = 2048;
3100  Tone.prototype.blockTime = 128 / Tone.context.sampleRate;
3101  Tone.prototype.dispose = function () {
3102    if (!this.isUndef(this.input)) {
3103      if (this.input instanceof AudioNode) {
3104        this.input.disconnect();
3105      }
3106      this.input = null;
3107    }
3108    if (!this.isUndef(this.output)) {
3109      if (this.output instanceof AudioNode) {
3110        this.output.disconnect();
3111      }
3112      this.output = null;
3113    }
3114    return this;
3115  };
3116  var _silentNode = null;
3117  Tone.prototype.noGC = function () {
3118    this.output.connect(_silentNode);
3119    return this;
3120  };
3121  AudioNode.prototype.noGC = function () {
3122    this.connect(_silentNode);
3123    return this;
3124  };
3125  Tone.prototype.connect = function (unit, outputNum, inputNum) {
3126    if (Array.isArray(this.output)) {
3127      outputNum = this.defaultArg(outputNum, 0);
3128      this.output[outputNum].connect(unit, 0, inputNum);
3129    } else {
3130      this.output.connect(unit, outputNum, inputNum);
3131    }
3132    return this;
3133  };
3134  Tone.prototype.disconnect = function (outputNum) {
3135    if (Array.isArray(this.output)) {
3136      outputNum = this.defaultArg(outputNum, 0);
3137      this.output[outputNum].disconnect();
3138    } else {
3139      this.output.disconnect();
3140    }
3141    return this;
3142  };
3143  Tone.prototype.connectSeries = function () {
3144    if (arguments.length > 1) {
3145      var currentUnit = arguments[0];
3146      for (var i = 1; i < arguments.length; i++) {
3147        var toUnit = arguments[i];
3148        currentUnit.connect(toUnit);
3149        currentUnit = toUnit;
3150      }
3151    }
3152    return this;
3153  };
3154  Tone.prototype.connectParallel = function () {
3155    var connectFrom = arguments[0];
3156    if (arguments.length > 1) {
3157      for (var i = 1; i < arguments.length; i++) {
3158        var connectTo = arguments[i];
3159        connectFrom.connect(connectTo);
3160      }
3161    }
3162    return this;
3163  };
3164  Tone.prototype.chain = function () {
3165    if (arguments.length > 0) {
3166      var currentUnit = this;
3167      for (var i = 0; i < arguments.length; i++) {
3168        var toUnit = arguments[i];
3169        currentUnit.connect(toUnit);
3170        currentUnit = toUnit;
3171      }
3172    }
3173    return this;
3174  };
3175  Tone.prototype.fan = function () {
3176    if (arguments.length > 0) {
3177      for (var i = 0; i < arguments.length; i++) {
3178        this.connect(arguments[i]);
3179      }
3180    }
3181    return this;
3182  };
3183  AudioNode.prototype.chain = Tone.prototype.chain;
3184  AudioNode.prototype.fan = Tone.prototype.fan;
3185  Tone.prototype.defaultArg = function (given, fallback) {
3186    if (this.isObject(given) && this.isObject(fallback)) {
3187      var ret = {};
3188      for (var givenProp in given) {
3189        ret[givenProp] = this.defaultArg(fallback[givenProp], given[givenProp]);
3190      }
3191      for (var fallbackProp in fallback) {
3192        ret[fallbackProp] = this.defaultArg(given[fallbackProp], fallback[fallbackProp]);
3193      }
3194      return ret;
3195    } else {
3196      return isUndef(given) ? fallback : given;
3197    }
3198  };
3199  Tone.prototype.optionsObject = function (values, keys, defaults) {
3200    var options = {};
3201    if (values.length === 1 && this.isObject(values[0])) {
3202      options = values[0];
3203    } else {
3204      for (var i = 0; i < keys.length; i++) {
3205        options[keys[i]] = values[i];
3206      }
3207    }
3208    if (!this.isUndef(defaults)) {
3209      return this.defaultArg(options, defaults);
3210    } else {
3211      return options;
3212    }
3213  };
3214  Tone.prototype.isUndef = isUndef;
3215  Tone.prototype.isFunction = isFunction;
3216  Tone.prototype.isNumber = function (arg) {
3217    return typeof arg === 'number';
3218  };
3219  Tone.prototype.isObject = function (arg) {
3220    return Object.prototype.toString.call(arg) === '[object Object]' && arg.constructor === Object;
3221  };
3222  Tone.prototype.isBoolean = function (arg) {
3223    return typeof arg === 'boolean';
3224  };
3225  Tone.prototype.isArray = function (arg) {
3226    return Array.isArray(arg);
3227  };
3228  Tone.prototype.isString = function (arg) {
3229    return typeof arg === 'string';
3230  };
3231  Tone.noOp = function () {
3232  };
3233  Tone.prototype._readOnly = function (property) {
3234    if (Array.isArray(property)) {
3235      for (var i = 0; i < property.length; i++) {
3236        this._readOnly(property[i]);
3237      }
3238    } else {
3239      Object.defineProperty(this, property, {
3240        writable: false,
3241        enumerable: true
3242      });
3243    }
3244  };
3245  Tone.prototype._writable = function (property) {
3246    if (Array.isArray(property)) {
3247      for (var i = 0; i < property.length; i++) {
3248        this._writable(property[i]);
3249      }
3250    } else {
3251      Object.defineProperty(this, property, { writable: true });
3252    }
3253  };
3254  Tone.State = {
3255    Started: 'started',
3256    Stopped: 'stopped',
3257    Paused: 'paused'
3258  };
3259  Tone.prototype.equalPowerScale = function (percent) {
3260    var piFactor = 0.5 * Math.PI;
3261    return Math.sin(percent * piFactor);
3262  };
3263  Tone.prototype.dbToGain = function (db) {
3264    return Math.pow(2, db / 6);
3265  };
3266  Tone.prototype.gainToDb = function (gain) {
3267    return 20 * (Math.log(gain) / Math.LN10);
3268  };
3269  Tone.prototype.now = function () {
3270    return this.context.currentTime;
3271  };
3272  Tone.extend = function (child, parent) {
3273    if (isUndef(parent)) {
3274      parent = Tone;
3275    }
3276    function TempConstructor() {
3277    }
3278    TempConstructor.prototype = parent.prototype;
3279    child.prototype = new TempConstructor();
3280    child.prototype.constructor = child;
3281    child._super = parent;
3282  };
3283  var newContextCallbacks = [];
3284  Tone._initAudioContext = function (callback) {
3285    callback(Tone.context);
3286    newContextCallbacks.push(callback);
3287  };
3288  Tone.setContext = function (ctx) {
3289    Tone.prototype.context = ctx;
3290    Tone.context = ctx;
3291    for (var i = 0; i < newContextCallbacks.length; i++) {
3292      newContextCallbacks[i](ctx);
3293    }
3294  };
3295  Tone.startMobile = function () {
3296    var osc = Tone.context.createOscillator();
3297    var silent = Tone.context.createGain();
3298    silent.gain.value = 0;
3299    osc.connect(silent);
3300    silent.connect(Tone.context.destination);
3301    var now = Tone.context.currentTime;
3302    osc.start(now);
3303    osc.stop(now + 1);
3304  };
3305  Tone._initAudioContext(function (audioContext) {
3306    Tone.prototype.blockTime = 128 / audioContext.sampleRate;
3307    _silentNode = audioContext.createGain();
3308    _silentNode.gain.value = 0;
3309    _silentNode.connect(audioContext.destination);
3310  });
3311  Tone.version = 'r7-dev';
3312  return Tone;
3313}();
3314/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
3315var Tone_signal_SignalBase;
3316Tone_signal_SignalBase = function (Tone) {
3317  'use strict';
3318  Tone.SignalBase = function () {
3319  };
3320  Tone.extend(Tone.SignalBase);
3321  Tone.SignalBase.prototype.connect = function (node, outputNumber, inputNumber) {
3322    if (Tone.Signal && Tone.Signal === node.constructor || Tone.Param && Tone.Param === node.constructor || Tone.TimelineSignal && Tone.TimelineSignal === node.constructor) {
3323      node._param.cancelScheduledValues(0);
3324      node._param.value = 0;
3325      node.overridden = true;
3326    } else if (node instanceof AudioParam) {
3327      node.cancelScheduledValues(0);
3328      node.value = 0;
3329    }
3330    Tone.prototype.connect.call(this, node, outputNumber, inputNumber);
3331    return this;
3332  };
3333  return Tone.SignalBase;
3334}(Tone_core_Tone);
3335/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
3336var Tone_signal_WaveShaper;
3337Tone_signal_WaveShaper = function (Tone) {
3338  'use strict';
3339  Tone.WaveShaper = function (mapping, bufferLen) {
3340    this._shaper = this.input = this.output = this.context.createWaveShaper();
3341    this._curve = null;
3342    if (Array.isArray(mapping)) {
3343      this.curve = mapping;
3344    } else if (isFinite(mapping) || this.isUndef(mapping)) {
3345      this._curve = new Float32Array(this.defaultArg(mapping, 1024));
3346    } else if (this.isFunction(mapping)) {
3347      this._curve = new Float32Array(this.defaultArg(bufferLen, 1024));
3348      this.setMap(mapping);
3349    }
3350  };
3351  Tone.extend(Tone.WaveShaper, Tone.SignalBase);
3352  Tone.WaveShaper.prototype.setMap = function (mapping) {
3353    for (var i = 0, len = this._curve.length; i < len; i++) {
3354      var normalized = i / len * 2 - 1;
3355      this._curve[i] = mapping(normalized, i);
3356    }
3357    this._shaper.curve = this._curve;
3358    return this;
3359  };
3360  Object.defineProperty(Tone.WaveShaper.prototype, 'curve', {
3361    get: function () {
3362      return this._shaper.curve;
3363    },
3364    set: function (mapping) {
3365      this._curve = new Float32Array(mapping);
3366      this._shaper.curve = this._curve;
3367    }
3368  });
3369  Object.defineProperty(Tone.WaveShaper.prototype, 'oversample', {
3370    get: function () {
3371      return this._shaper.oversample;
3372    },
3373    set: function (oversampling) {
3374      if ([
3375          'none',
3376          '2x',
3377          '4x'
3378        ].indexOf(oversampling) !== -1) {
3379        this._shaper.oversample = oversampling;
3380      } else {
3381        throw new Error('invalid oversampling: ' + oversampling);
3382      }
3383    }
3384  });
3385  Tone.WaveShaper.prototype.dispose = function () {
3386    Tone.prototype.dispose.call(this);
3387    this._shaper.disconnect();
3388    this._shaper = null;
3389    this._curve = null;
3390    return this;
3391  };
3392  return Tone.WaveShaper;
3393}(Tone_core_Tone);
3394/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
3395var Tone_core_Type;
3396Tone_core_Type = function (Tone) {
3397  'use strict';
3398  Tone.Type = {
3399    Default: 'number',
3400    Time: 'time',
3401    Frequency: 'frequency',
3402    NormalRange: 'normalRange',
3403    AudioRange: 'audioRange',
3404    Decibels: 'db',
3405    Interval: 'interval',
3406    BPM: 'bpm',
3407    Positive: 'positive',
3408    Cents: 'cents',
3409    Degrees: 'degrees',
3410    MIDI: 'midi',
3411    TransportTime: 'transportTime',
3412    Ticks: 'tick',
3413    Note: 'note',
3414    Milliseconds: 'milliseconds',
3415    Notation: 'notation'
3416  };
3417  Tone.prototype.isNowRelative = function () {
3418    var nowRelative = new RegExp(/^\s*\+(.)+/i);
3419    return function (note) {
3420      return nowRelative.test(note);
3421    };
3422  }();
3423  Tone.prototype.isTicks = function () {
3424    var tickFormat = new RegExp(/^\d+i$/i);
3425    return function (note) {
3426      return tickFormat.test(note);
3427    };
3428  }();
3429  Tone.prototype.isNotation = function () {
3430    var notationFormat = new RegExp(/^[0-9]+[mnt]$/i);
3431    return function (note) {
3432      return notationFormat.test(note);
3433    };
3434  }();
3435  Tone.prototype.isTransportTime = function () {
3436    var transportTimeFormat = new RegExp(/^(\d+(\.\d+)?\:){1,2}(\d+(\.\d+)?)?$/i);
3437    return function (transportTime) {
3438      return transportTimeFormat.test(transportTime);
3439    };
3440  }();
3441  Tone.prototype.isNote = function () {
3442    var noteFormat = new RegExp(/^[a-g]{1}(b|#|x|bb)?-?[0-9]+$/i);
3443    return function (note) {
3444      return noteFormat.test(note);
3445    };
3446  }();
3447  Tone.prototype.isFrequency = function () {
3448    var freqFormat = new RegExp(/^\d*\.?\d+hz$/i);
3449    return function (freq) {
3450      return freqFormat.test(freq);
3451    };
3452  }();
3453  function getTransportBpm() {
3454    if (Tone.Transport && Tone.Transport.bpm) {
3455      return Tone.Transport.bpm.value;
3456    } else {
3457      return 120;
3458    }
3459  }
3460  function getTransportTimeSignature() {
3461    if (Tone.Transport && Tone.Transport.timeSignature) {
3462      return Tone.Transport.timeSignature;
3463    } else {
3464      return 4;
3465    }
3466  }
3467  Tone.prototype.notationToSeconds = function (notation, bpm, timeSignature) {
3468    bpm = this.defaultArg(bpm, getTransportBpm());
3469    timeSignature = this.defaultArg(timeSignature, getTransportTimeSignature());
3470    var beatTime = 60 / bpm;
3471    if (notation === '1n') {
3472      notation = '1m';
3473    }
3474    var subdivision = parseInt(notation, 10);
3475    var beats = 0;
3476    if (subdivision === 0) {
3477      beats = 0;
3478    }
3479    var lastLetter = notation.slice(-1);
3480    if (lastLetter === 't') {
3481      beats = 4 / subdivision * 2 / 3;
3482    } else if (lastLetter === 'n') {
3483      beats = 4 / subdivision;
3484    } else if (lastLetter === 'm') {
3485      beats = subdivision * timeSignature;
3486    } else {
3487      beats = 0;
3488    }
3489    return beatTime * beats;
3490  };
3491  Tone.prototype.transportTimeToSeconds = function (transportTime, bpm, timeSignature) {
3492    bpm = this.defaultArg(bpm, getTransportBpm());
3493    timeSignature = this.defaultArg(timeSignature, getTransportTimeSignature());
3494    var measures = 0;
3495    var quarters = 0;
3496    var sixteenths = 0;
3497    var split = transportTime.split(':');
3498    if (split.length === 2) {
3499      measures = parseFloat(split[0]);
3500      quarters = parseFloat(split[1]);
3501    } else if (split.length === 1) {
3502      quarters = parseFloat(split[0]);
3503    } else if (split.length === 3) {
3504      measures = parseFloat(split[0]);
3505      quarters = parseFloat(split[1]);
3506      sixteenths = parseFloat(split[2]);
3507    }
3508    var beats = measures * timeSignature + quarters + sixteenths / 4;
3509    return beats * (60 / bpm);
3510  };
3511  Tone.prototype.ticksToSeconds = function (ticks, bpm) {
3512    if (this.isUndef(Tone.Transport)) {
3513      return 0;
3514    }
3515    ticks = parseFloat(ticks);
3516    bpm = this.defaultArg(bpm, getTransportBpm());
3517    var tickTime = 60 / bpm / Tone.Transport.PPQ;
3518    return tickTime * ticks;
3519  };
3520  Tone.prototype.frequencyToSeconds = function (freq) {
3521    return 1 / parseFloat(freq);
3522  };
3523  Tone.prototype.samplesToSeconds = function (samples) {
3524    return samples / this.context.sampleRate;
3525  };
3526  Tone.prototype.secondsToSamples = function (seconds) {
3527    return seconds * this.context.sampleRate;
3528  };
3529  Tone.prototype.secondsToTransportTime = function (seconds, bpm, timeSignature) {
3530    bpm = this.defaultArg(bpm, getTransportBpm());
3531    timeSignature = this.defaultArg(timeSignature, getTransportTimeSignature());
3532    var quarterTime = 60 / bpm;
3533    var quarters = seconds / quarterTime;
3534    var measures = Math.floor(quarters / timeSignature);
3535    var sixteenths = quarters % 1 * 4;
3536    quarters = Math.floor(quarters) % timeSignature;
3537    var progress = [
3538      measures,
3539      quarters,
3540      sixteenths
3541    ];
3542    return progress.join(':');
3543  };
3544  Tone.prototype.secondsToFrequency = function (seconds) {
3545    return 1 / seconds;
3546  };
3547  Tone.prototype.toTransportTime = function (time, bpm, timeSignature) {
3548    var seconds = this.toSeconds(time);
3549    return this.secondsToTransportTime(seconds, bpm, timeSignature);
3550  };
3551  Tone.prototype.toFrequency = function (freq, now) {
3552    if (this.isFrequency(freq)) {
3553      return parseFloat(freq);
3554    } else if (this.isNotation(freq) || this.isTransportTime(freq)) {
3555      return this.secondsToFrequency(this.toSeconds(freq, now));
3556    } else if (this.isNote(freq)) {
3557      return this.noteToFrequency(freq);
3558    } else {
3559      return freq;
3560    }
3561  };
3562  Tone.prototype.toTicks = function (time) {
3563    if (this.isUndef(Tone.Transport)) {
3564      return 0;
3565    }
3566    var bpm = Tone.Transport.bpm.value;
3567    var plusNow = 0;
3568    if (this.isNowRelative(time)) {
3569      time = time.replace('+', '');
3570      plusNow = Tone.Transport.ticks;
3571    } else if (this.isUndef(time)) {
3572      return Tone.Transport.ticks;
3573    }
3574    var seconds = this.toSeconds(time);
3575    var quarter = 60 / bpm;
3576    var quarters = seconds / quarter;
3577    var tickNum = quarters * Tone.Transport.PPQ;
3578    return Math.round(tickNum + plusNow);
3579  };
3580  Tone.prototype.toSamples = function (time) {
3581    var seconds = this.toSeconds(time);
3582    return Math.round(seconds * this.context.sampleRate);
3583  };
3584  Tone.prototype.toSeconds = function (time, now) {
3585    now = this.defaultArg(now, this.now());
3586    if (this.isNumber(time)) {
3587      return time;
3588    } else if (this.isString(time)) {
3589      var plusTime = 0;
3590      if (this.isNowRelative(time)) {
3591        time = time.replace('+', '');
3592        plusTime = now;
3593      }
3594      var betweenParens = time.match(/\(([^)(]+)\)/g);
3595      if (betweenParens) {
3596        for (var j = 0; j < betweenParens.length; j++) {
3597          var symbol = betweenParens[j].replace(/[\(\)]/g, '');
3598          var symbolVal = this.toSeconds(symbol);
3599          time = time.replace(betweenParens[j], symbolVal);
3600        }
3601      }
3602      if (time.indexOf('@') !== -1) {
3603        var quantizationSplit = time.split('@');
3604        if (!this.isUndef(Tone.Transport)) {
3605          var toQuantize = quantizationSplit[0].trim();
3606          if (toQuantize === '') {
3607            toQuantize = undefined;
3608          }
3609          if (plusTime > 0) {
3610            toQuantize = '+' + toQuantize;
3611            plusTime = 0;
3612          }
3613          var subdivision = quantizationSplit[1].trim();
3614          time = Tone.Transport.quantize(toQuantize, subdivision);
3615        } else {
3616          throw new Error('quantization requires Tone.Transport');
3617        }
3618      } else {
3619        var components = time.split(/[\(\)\-\+\/\*]/);
3620        if (components.length > 1) {
3621          var originalTime = time;
3622          for (var i = 0; i < components.length; i++) {
3623            var symb = components[i].trim();
3624            if (symb !== '') {
3625              var val = this.toSeconds(symb);
3626              time = time.replace(symb, val);
3627            }
3628          }
3629          try {
3630            time = eval(time);
3631          } catch (e) {
3632            throw new EvalError('cannot evaluate Time: ' + originalTime);
3633          }
3634        } else if (this.isNotation(time)) {
3635          time = this.notationToSeconds(time);
3636        } else if (this.isTransportTime(time)) {
3637          time = this.transportTimeToSeconds(time);
3638        } else if (this.isFrequency(time)) {
3639          time = this.frequencyToSeconds(time);
3640        } else if (this.isTicks(time)) {
3641          time = this.ticksToSeconds(time);
3642        } else {
3643          time = parseFloat(time);
3644        }
3645      }
3646      return time + plusTime;
3647    } else {
3648      return now;
3649    }
3650  };
3651  Tone.prototype.toNotation = function (time, bpm, timeSignature) {
3652    var testNotations = [
3653      '1m',
3654      '2n',
3655      '4n',
3656      '8n',
3657      '16n',
3658      '32n',
3659      '64n',
3660      '128n'
3661    ];
3662    var retNotation = toNotationHelper.call(this, time, bpm, timeSignature, testNotations);
3663    var testTripletNotations = [
3664      '1m',
3665      '2n',
3666      '2t',
3667      '4n',
3668      '4t',
3669      '8n',
3670      '8t',
3671      '16n',
3672      '16t',
3673      '32n',
3674      '32t',
3675      '64n',
3676      '64t',
3677      '128n'
3678    ];
3679    var retTripletNotation = toNotationHelper.call(this, time, bpm, timeSignature, testTripletNotations);
3680    if (retTripletNotation.split('+').length < retNotation.split('+').length) {
3681      return retTripletNotation;
3682    } else {
3683      return retNotation;
3684    }
3685  };
3686  function toNotationHelper(time, bpm, timeSignature, testNotations) {
3687    var seconds = this.toSeconds(time);
3688    var threshold = this.notationToSeconds(testNotations[testNotations.length - 1], bpm, timeSignature);
3689    var retNotation = '';
3690    for (var i = 0; i < testNotations.length; i++) {
3691      var notationTime = this.notationToSeconds(testNotations[i], bpm, timeSignature);
3692      var multiple = seconds / notationTime;
3693      var floatingPointError = 0.000001;
3694      if (1 - multiple % 1 < floatingPointError) {
3695        multiple += floatingPointError;
3696      }
3697      multiple = Math.floor(multiple);
3698      if (multiple > 0) {
3699        if (multiple === 1) {
3700          retNotation += testNotations[i];
3701        } else {
3702          retNotation += multiple.toString() + '*' + testNotations[i];
3703        }
3704        seconds -= multiple * notationTime;
3705        if (seconds < threshold) {
3706          break;
3707        } else {
3708          retNotation += ' + ';
3709        }
3710      }
3711    }
3712    if (retNotation === '') {
3713      retNotation = '0';
3714    }
3715    return retNotation;
3716  }
3717  Tone.prototype.fromUnits = function (val, units) {
3718    if (this.convert || this.isUndef(this.convert)) {
3719      switch (units) {
3720      case Tone.Type.Time:
3721        return this.toSeconds(val);
3722      case Tone.Type.Frequency:
3723        return this.toFrequency(val);
3724      case Tone.Type.Decibels:
3725        return this.dbToGain(val);
3726      case Tone.Type.NormalRange:
3727        return Math.min(Math.max(val, 0), 1);
3728      case Tone.Type.AudioRange:
3729        return Math.min(Math.max(val, -1), 1);
3730      case Tone.Type.Positive:
3731        return Math.max(val, 0);
3732      default:
3733        return val;
3734      }
3735    } else {
3736      return val;
3737    }
3738  };
3739  Tone.prototype.toUnits = function (val, units) {
3740    if (this.convert || this.isUndef(this.convert)) {
3741      switch (units) {
3742      case Tone.Type.Decibels:
3743        return this.gainToDb(val);
3744      default:
3745        return val;
3746      }
3747    } else {
3748      return val;
3749    }
3750  };
3751  var noteToScaleIndex = {
3752    'cbb': -2,
3753    'cb': -1,
3754    'c': 0,
3755    'c#': 1,
3756    'cx': 2,
3757    'dbb': 0,
3758    'db': 1,
3759    'd': 2,
3760    'd#': 3,
3761    'dx': 4,
3762    'ebb': 2,
3763    'eb': 3,
3764    'e': 4,
3765    'e#': 5,
3766    'ex': 6,
3767    'fbb': 3,
3768    'fb': 4,
3769    'f': 5,
3770    'f#': 6,
3771    'fx': 7,
3772    'gbb': 5,
3773    'gb': 6,
3774    'g': 7,
3775    'g#': 8,
3776    'gx': 9,
3777    'abb': 7,
3778    'ab': 8,
3779    'a': 9,
3780    'a#': 10,
3781    'ax': 11,
3782    'bbb': 9,
3783    'bb': 10,
3784    'b': 11,
3785    'b#': 12,
3786    'bx': 13
3787  };
3788  var scaleIndexToNote = [
3789    'C',
3790    'C#',
3791    'D',
3792    'D#',
3793    'E',
3794    'F',
3795    'F#',
3796    'G',
3797    'G#',
3798    'A',
3799    'A#',
3800    'B'
3801  ];
3802  Tone.A4 = 440;
3803  Tone.prototype.noteToFrequency = function (note) {
3804    var parts = note.split(/(-?\d+)/);
3805    if (parts.length === 3) {
3806      var index = noteToScaleIndex[parts[0].toLowerCase()];
3807      var octave = parts[1];
3808      var noteNumber = index + (parseInt(octave, 10) + 1) * 12;
3809      return this.midiToFrequency(noteNumber);
3810    } else {
3811      return 0;
3812    }
3813  };
3814  Tone.prototype.frequencyToNote = function (freq) {
3815    var log = Math.log(freq / Tone.A4) / Math.LN2;
3816    var noteNumber = Math.round(12 * log) + 57;
3817    var octave = Math.floor(noteNumber / 12);
3818    if (octave < 0) {
3819      noteNumber += -12 * octave;
3820    }
3821    var noteName = scaleIndexToNote[noteNumber % 12];
3822    return noteName + octave.toString();
3823  };
3824  Tone.prototype.intervalToFrequencyRatio = function (interval) {
3825    return Math.pow(2, interval / 12);
3826  };
3827  Tone.prototype.midiToNote = function (midiNumber) {
3828    var octave = Math.floor(midiNumber / 12) - 1;
3829    var note = midiNumber % 12;
3830    return scaleIndexToNote[note] + octave;
3831  };
3832  Tone.prototype.noteToMidi = function (note) {
3833    var parts = note.split(/(\d+)/);
3834    if (parts.length === 3) {
3835      var index = noteToScaleIndex[parts[0].toLowerCase()];
3836      var octave = parts[1];
3837      return index + (parseInt(octave, 10) + 1) * 12;
3838    } else {
3839      return 0;
3840    }
3841  };
3842  Tone.prototype.midiToFrequency = function (midi) {
3843    return Tone.A4 * Math.pow(2, (midi - 69) / 12);
3844  };
3845  return Tone;
3846}(Tone_core_Tone);
3847/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
3848var Tone_core_Param;
3849Tone_core_Param = function (Tone) {
3850  'use strict';
3851  Tone.Param = function () {
3852    var options = this.optionsObject(arguments, [
3853      'param',
3854      'units',
3855      'convert'
3856    ], Tone.Param.defaults);
3857    this._param = this.input = options.param;
3858    this.units = options.units;
3859    this.convert = options.convert;
3860    this.overridden = false;
3861    if (!this.isUndef(options.value)) {
3862      this.value = options.value;
3863    }
3864  };
3865  Tone.extend(Tone.Param);
3866  Tone.Param.defaults = {
3867    'units': Tone.Type.Default,
3868    'convert': true,
3869    'param': undefined
3870  };
3871  Object.defineProperty(Tone.Param.prototype, 'value', {
3872    get: function () {
3873      return this._toUnits(this._param.value);
3874    },
3875    set: function (value) {
3876      var convertedVal = this._fromUnits(value);
3877      this._param.value = convertedVal;
3878    }
3879  });
3880  Tone.Param.prototype._fromUnits = function (val) {
3881    if (this.convert || this.isUndef(this.convert)) {
3882      switch (this.units) {
3883      case Tone.Type.Time:
3884        return this.toSeconds(val);
3885      case Tone.Type.Frequency:
3886        return this.toFrequency(val);
3887      case Tone.Type.Decibels:
3888        return this.dbToGain(val);
3889      case Tone.Type.NormalRange:
3890        return Math.min(Math.max(val, 0), 1);
3891      case Tone.Type.AudioRange:
3892        return Math.min(Math.max(val, -1), 1);
3893      case Tone.Type.Positive:
3894        return Math.max(val, 0);
3895      default:
3896        return val;
3897      }
3898    } else {
3899      return val;
3900    }
3901  };
3902  Tone.Param.prototype._toUnits = function (val) {
3903    if (this.convert || this.isUndef(this.convert)) {
3904      switch (this.units) {
3905      case Tone.Type.Decibels:
3906        return this.gainToDb(val);
3907      default:
3908        return val;
3909      }
3910    } else {
3911      return val;
3912    }
3913  };
3914  Tone.Param.prototype._minOutput = 0.00001;
3915  Tone.Param.prototype.setValueAtTime = function (value, time) {
3916    value = this._fromUnits(value);
3917    this._param.setValueAtTime(value, this.toSeconds(time));
3918    return this;
3919  };
3920  Tone.Param.prototype.setRampPoint = function (now) {
3921    now = this.defaultArg(now, this.now());
3922    var currentVal = this._param.value;
3923    this._param.setValueAtTime(currentVal, now);
3924    return this;
3925  };
3926  Tone.Param.prototype.linearRampToValueAtTime = function (value, endTime) {
3927    value = this._fromUnits(value);
3928    this._param.linearRampToValueAtTime(value, this.toSeconds(endTime));
3929    return this;
3930  };
3931  Tone.Param.prototype.exponentialRampToValueAtTime = function (value, endTime) {
3932    value = this._fromUnits(value);
3933    value = Math.max(this._minOutput, value);
3934    this._param.exponentialRampToValueAtTime(value, this.toSeconds(endTime));
3935    return this;
3936  };
3937  Tone.Param.prototype.exponentialRampToValue = function (value, rampTime) {
3938    var now = this.now();
3939    var currentVal = this.value;
3940    this.setValueAtTime(Math.max(currentVal, this._minOutput), now);
3941    this.exponentialRampToValueAtTime(value, now + this.toSeconds(rampTime));
3942    return this;
3943  };
3944  Tone.Param.prototype.linearRampToValue = function (value, rampTime) {
3945    var now = this.now();
3946    this.setRampPoint(now);
3947    this.linearRampToValueAtTime(value, now + this.toSeconds(rampTime));
3948    return this;
3949  };
3950  Tone.Param.prototype.setTargetAtTime = function (value, startTime, timeConstant) {
3951    value = this._fromUnits(value);
3952    value = Math.max(this._minOutput, value);
3953    timeConstant = Math.max(this._minOutput, timeConstant);
3954    this._param.setTargetAtTime(value, this.toSeconds(startTime), timeConstant);
3955    return this;
3956  };
3957  Tone.Param.prototype.setValueCurveAtTime = function (values, startTime, duration) {
3958    for (var i = 0; i < values.length; i++) {
3959      values[i] = this._fromUnits(values[i]);
3960    }
3961    this._param.setValueCurveAtTime(values, this.toSeconds(startTime), this.toSeconds(duration));
3962    return this;
3963  };
3964  Tone.Param.prototype.cancelScheduledValues = function (startTime) {
3965    this._param.cancelScheduledValues(this.toSeconds(startTime));
3966    return this;
3967  };
3968  Tone.Param.prototype.rampTo = function (value, rampTime) {
3969    rampTime = this.defaultArg(rampTime, 0);
3970    if (this.units === Tone.Type.Frequency || this.units === Tone.Type.BPM) {
3971      this.exponentialRampToValue(value, rampTime);
3972    } else {
3973      this.linearRampToValue(value, rampTime);
3974    }
3975    return this;
3976  };
3977  Tone.Param.prototype.dispose = function () {
3978    Tone.prototype.dispose.call(this);
3979    this._param = null;
3980    return this;
3981  };
3982  return Tone.Param;
3983}(Tone_core_Tone);
3984/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
3985var Tone_core_Gain;
3986Tone_core_Gain = function (Tone) {
3987  'use strict';
3988  Tone.Gain = function () {
3989    var options = this.optionsObject(arguments, [
3990      'gain',
3991      'units'
3992    ], Tone.Gain.defaults);
3993    this.input = this.output = this._gainNode = this.context.createGain();
3994    this.gain = new Tone.Param({
3995      'param': this._gainNode.gain,
3996      'units': options.units,
3997      'value': options.gain,
3998      'convert': options.convert
3999    });
4000    this._readOnly('gain');
4001  };
4002  Tone.extend(Tone.Gain);
4003  Tone.Gain.defaults = {
4004    'gain': 1,
4005    'convert': true
4006  };
4007  Tone.Gain.prototype.dispose = function () {
4008    Tone.Param.prototype.dispose.call(this);
4009    this._gainNode.disconnect();
4010    this._gainNode = null;
4011    this._writable('gain');
4012    this.gain.dispose();
4013    this.gain = null;
4014  };
4015  return Tone.Gain;
4016}(Tone_core_Tone, Tone_core_Param);
4017/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
4018var Tone_signal_Signal;
4019Tone_signal_Signal = function (Tone) {
4020  'use strict';
4021  Tone.Signal = function () {
4022    var options = this.optionsObject(arguments, [
4023      'value',
4024      'units'
4025    ], Tone.Signal.defaults);
4026    this.output = this._gain = this.context.createGain();
4027    options.param = this._gain.gain;
4028    Tone.Param.call(this, options);
4029    this.input = this._param = this._gain.gain;
4030    Tone.Signal._constant.chain(this._gain);
4031  };
4032  Tone.extend(Tone.Signal, Tone.Param);
4033  Tone.Signal.defaults = {
4034    'value': 0,
4035    'units': Tone.Type.Default,
4036    'convert': true
4037  };
4038  Tone.Signal.prototype.connect = Tone.SignalBase.prototype.connect;
4039  Tone.Signal.prototype.dispose = function () {
4040    Tone.Param.prototype.dispose.call(this);
4041    this._param = null;
4042    this._gain.disconnect();
4043    this._gain = null;
4044    return this;
4045  };
4046  Tone.Signal._constant = null;
4047  Tone._initAudioContext(function (audioContext) {
4048    var buffer = audioContext.createBuffer(1, 128, audioContext.sampleRate);
4049    var arr = buffer.getChannelData(0);
4050    for (var i = 0; i < arr.length; i++) {
4051      arr[i] = 1;
4052    }
4053    Tone.Signal._constant = audioContext.createBufferSource();
4054    Tone.Signal._constant.channelCount = 1;
4055    Tone.Signal._constant.channelCountMode = 'explicit';
4056    Tone.Signal._constant.buffer = buffer;
4057    Tone.Signal._constant.loop = true;
4058    Tone.Signal._constant.start(0);
4059    Tone.Signal._constant.noGC();
4060  });
4061  return Tone.Signal;
4062}(Tone_core_Tone, Tone_signal_WaveShaper, Tone_core_Type, Tone_core_Param);
4063/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
4064var Tone_signal_Add;
4065Tone_signal_Add = function (Tone) {
4066  'use strict';
4067  Tone.Add = function (value) {
4068    Tone.call(this, 2, 0);
4069    this._sum = this.input[0] = this.input[1] = this.output = this.context.createGain();
4070    this._param = this.input[1] = new Tone.Signal(value);
4071    this._param.connect(this._sum);
4072  };
4073  Tone.extend(Tone.Add, Tone.Signal);
4074  Tone.Add.prototype.dispose = function () {
4075    Tone.prototype.dispose.call(this);
4076    this._sum.disconnect();
4077    this._sum = null;
4078    this._param.dispose();
4079    this._param = null;
4080    return this;
4081  };
4082  return Tone.Add;
4083}(Tone_core_Tone);
4084/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
4085var Tone_signal_Multiply;
4086Tone_signal_Multiply = function (Tone) {
4087  'use strict';
4088  Tone.Multiply = function (value) {
4089    Tone.call(this, 2, 0);
4090    this._mult = this.input[0] = this.output = this.context.createGain();
4091    this._param = this.input[1] = this.output.gain;
4092    this._param.value = this.defaultArg(value, 0);
4093  };
4094  Tone.extend(Tone.Multiply, Tone.Signal);
4095  Tone.Multiply.prototype.dispose = function () {
4096    Tone.prototype.dispose.call(this);
4097    this._mult.disconnect();
4098    this._mult = null;
4099    this._param = null;
4100    return this;
4101  };
4102  return Tone.Multiply;
4103}(Tone_core_Tone);
4104/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
4105var Tone_signal_Scale;
4106Tone_signal_Scale = function (Tone) {
4107  'use strict';
4108  Tone.Scale = function (outputMin, outputMax) {
4109    this._outputMin = this.defaultArg(outputMin, 0);
4110    this._outputMax = this.defaultArg(outputMax, 1);
4111    this._scale = this.input = new Tone.Multiply(1);
4112    this._add = this.output = new Tone.Add(0);
4113    this._scale.connect(this._add);
4114    this._setRange();
4115  };
4116  Tone.extend(Tone.Scale, Tone.SignalBase);
4117  Object.defineProperty(Tone.Scale.prototype, 'min', {
4118    get: function () {
4119      return this._outputMin;
4120    },
4121    set: function (min) {
4122      this._outputMin = min;
4123      this._setRange();
4124    }
4125  });
4126  Object.defineProperty(Tone.Scale.prototype, 'max', {
4127    get: function () {
4128      return this._outputMax;
4129    },
4130    set: function (max) {
4131      this._outputMax = max;
4132      this._setRange();
4133    }
4134  });
4135  Tone.Scale.prototype._setRange = function () {
4136    this._add.value = this._outputMin;
4137    this._scale.value = this._outputMax - this._outputMin;
4138  };
4139  Tone.Scale.prototype.dispose = function () {
4140    Tone.prototype.dispose.call(this);
4141    this._add.dispose();
4142    this._add = null;
4143    this._scale.dispose();
4144    this._scale = null;
4145    return this;
4146  };
4147  return Tone.Scale;
4148}(Tone_core_Tone, Tone_signal_Add, Tone_signal_Multiply);
4149var signal;
4150signal = function () {
4151  'use strict';
4152  // Signal is built with the Tone.js signal by Yotam Mann
4153  // https://github.com/TONEnoTONE/Tone.js/
4154  var Signal = Tone_signal_Signal;
4155  var Add = Tone_signal_Add;
4156  var Mult = Tone_signal_Multiply;
4157  var Scale = Tone_signal_Scale;
4158  var Tone = Tone_core_Tone;
4159  var p5sound = master;
4160  Tone.setContext(p5sound.audiocontext);
4161  /**
4162   *  <p>p5.Signal is a constant audio-rate signal used by p5.Oscillator
4163   *  and p5.Envelope for modulation math.</p>
4164   *
4165   *  <p>This is necessary because Web Audio is processed on a seprate clock.
4166   *  For example, the p5 draw loop runs about 60 times per second. But
4167   *  the audio clock must process samples 44100 times per second. If we
4168   *  want to add a value to each of those samples, we can't do it in the
4169   *  draw loop, but we can do it by adding a constant-rate audio signal.</p.
4170   *  
4171   *  <p>This class mostly functions behind the scenes in p5.sound, and returns
4172   *  a Tone.Signal from the Tone.js library by Yotam Mann.
4173   *  If you want to work directly with audio signals for modular
4174   *  synthesis, check out
4175   *  <a href='http://bit.ly/1oIoEng' target=_'blank'>tone.js.</a></p>
4176   *
4177   *  @class  p5.Signal
4178   *  @constructor
4179   *  @return {Tone.Signal} A Signal object from the Tone.js library
4180   *  @example
4181   *  <div><code>
4182   *  function setup() {
4183   *    carrier = new p5.Oscillator('sine');
4184   *    carrier.amp(1); // set amplitude
4185   *    carrier.freq(220); // set frequency
4186   *    carrier.start(); // start oscillating
4187   *    
4188   *    modulator = new p5.Oscillator('sawtooth');
4189   *    modulator.disconnect();
4190   *    modulator.amp(1);
4191   *    modulator.freq(4);
4192   *    modulator.start();
4193   *
4194   *    // Modulator's default amplitude range is -1 to 1.
4195   *    // Multiply it by -200, so the range is -200 to 200
4196   *    // then add 220 so the range is 20 to 420
4197   *    carrier.freq( modulator.mult(-200).add(220) );
4198   *  }
4199   *  </code></div>
4200   */
4201  p5.Signal = function (value) {
4202    var s = new Signal(value);
4203    // p5sound.soundArray.push(s);
4204    return s;
4205  };
4206  /**
4207   *  Fade to value, for smooth transitions
4208   *
4209   *  @method  fade
4210   *  @param  {Number} value          Value to set this signal
4211   *  @param  {[Number]} secondsFromNow Length of fade, in seconds from now
4212   */
4213  Signal.prototype.fade = Signal.prototype.linearRampToValueAtTime;
4214  Mult.prototype.fade = Signal.prototype.fade;
4215  Add.prototype.fade = Signal.prototype.fade;
4216  Scale.prototype.fade = Signal.prototype.fade;
4217  /**
4218   *  Connect a p5.sound object or Web Audio node to this
4219   *  p5.Signal so that its amplitude values can be scaled.
4220   *  
4221   *  @param {Object} input
4222   */
4223  Signal.prototype.setInput = function (_input) {
4224    _input.connect(this);
4225  };
4226  Mult.prototype.setInput = Signal.prototype.setInput;
4227  Add.prototype.setInput = Signal.prototype.setInput;
4228  Scale.prototype.setInput = Signal.prototype.setInput;
4229  // signals can add / mult / scale themselves
4230  /**
4231   *  Add a constant value to this audio signal,
4232   *  and return the resulting audio signal. Does
4233   *  not change the value of the original signal,
4234   *  instead it returns a new p5.SignalAdd.
4235   *  
4236   *  @method  add
4237   *  @param {Number} number
4238   *  @return {p5.SignalAdd} object
4239   */
4240  Signal.prototype.add = function (num) {
4241    var add = new Add(num);
4242    // add.setInput(this);
4243    this.connect(add);
4244    return add;
4245  };
4246  Mult.prototype.add = Signal.prototype.add;
4247  Add.prototype.add = Signal.prototype.add;
4248  Scale.prototype.add = Signal.prototype.add;
4249  /**
4250   *  Multiply this signal by a constant value,
4251   *  and return the resulting audio signal. Does
4252   *  not change the value of the original signal,
4253   *  instead it returns a new p5.SignalMult.
4254   *  
4255   *  @method  mult
4256   *  @param {Number} number to multiply
4257   *  @return {Tone.Multiply} object
4258   */
4259  Signal.prototype.mult = function (num) {
4260    var mult = new Mult(num);
4261    // mult.setInput(this);
4262    this.connect(mult);
4263    return mult;
4264  };
4265  Mult.prototype.mult = Signal.prototype.mult;
4266  Add.prototype.mult = Signal.prototype.mult;
4267  Scale.prototype.mult = Signal.prototype.mult;
4268  /**
4269   *  Scale this signal value to a given range,
4270   *  and return the result as an audio signal. Does
4271   *  not change the value of the original signal,
4272   *  instead it returns a new p5.SignalScale.
4273   *  
4274   *  @method  scale
4275   *  @param {Number} number to multiply
4276   *  @param  {Number} inMin  input range minumum
4277   *  @param  {Number} inMax  input range maximum
4278   *  @param  {Number} outMin input range minumum
4279   *  @param  {Number} outMax input range maximum
4280   *  @return {p5.SignalScale} object
4281   */
4282  Signal.prototype.scale = function (inMin, inMax, outMin, outMax) {
4283    var mapOutMin, mapOutMax;
4284    if (arguments.length === 4) {
4285      mapOutMin = p5.prototype.map(outMin, inMin, inMax, 0, 1) - 0.5;
4286      mapOutMax = p5.prototype.map(outMax, inMin, inMax, 0, 1) - 0.5;
4287    } else {
4288      mapOutMin = arguments[0];
4289      mapOutMax = arguments[1];
4290    }
4291    var scale = new Scale(mapOutMin, mapOutMax);
4292    this.connect(scale);
4293    return scale;
4294  };
4295  Mult.prototype.scale = Signal.prototype.scale;
4296  Add.prototype.scale = Signal.prototype.scale;
4297  Scale.prototype.scale = Signal.prototype.scale;
4298}(Tone_signal_Signal, Tone_signal_Add, Tone_signal_Multiply, Tone_signal_Scale, Tone_core_Tone, master);
4299var oscillator;
4300oscillator = function () {
4301  'use strict';
4302  var p5sound = master;
4303  var Signal = Tone_signal_Signal;
4304  var Add = Tone_signal_Add;
4305  var Mult = Tone_signal_Multiply;
4306  var Scale = Tone_signal_Scale;
4307  /**
4308   *  <p>Creates a signal that oscillates between -1.0 and 1.0.
4309   *  By default, the oscillation takes the form of a sinusoidal
4310   *  shape ('sine'). Additional types include 'triangle',
4311   *  'sawtooth' and 'square'. The frequency defaults to
4312   *  440 oscillations per second (440Hz, equal to the pitch of an
4313   *  'A' note).</p> 
4314   *
4315   *  <p>Set the type of oscillation with setType(), or by creating a
4316   *  specific oscillator.</p> For example:
4317   *  <code>new p5.SinOsc(freq)</code>
4318   *  <code>new p5.TriOsc(freq)</code>
4319   *  <code>new p5.SqrOsc(freq)</code>
4320   *  <code>new p5.SawOsc(freq)</code>.
4321   *  </p>
4322   *  
4323   *  @class p5.Oscillator
4324   *  @constructor
4325   *  @param {Number} [freq] frequency defaults to 440Hz
4326   *  @param {String} [type] type of oscillator. Options:
4327   *                         'sine' (default), 'triangle',
4328   *                         'sawtooth', 'square'
4329   *  @return {Object}    Oscillator object
4330   *  @example
4331   *  <div><code>
4332   *  var osc;
4333   *  var playing = false;
4334   *  
4335   *  function setup() {
4336   *    backgroundColor = color(255,0,255);
4337   *    textAlign(CENTER);
4338   *    
4339   *    osc = new p5.Oscillator();
4340   *    osc.setType('sine');
4341   *    osc.freq(240);
4342   *    osc.amp(0);
4343   *    osc.start();
4344   *  }
4345   *
4346   *  function draw() {
4347   *    background(backgroundColor)
4348   *    text('click to play', width/2, height/2);
4349   *  }
4350   *
4351   *  function mouseClicked() {
4352   *    if (mouseX > 0 && mouseX < width && mouseY < height && mouseY > 0) {
4353   *      if (!playing) {
4354   *        // ramp amplitude to 0.5 over 0.1 seconds
4355   *        osc.amp(0.5, 0.05);
4356   *        playing = true;
4357   *        backgroundColor = color(0,255,255);
4358   *      } else {
4359   *        // ramp amplitude to 0 over 0.5 seconds
4360   *        osc.amp(0, 0.5);
4361   *        playing = false;
4362   *        backgroundColor = color(255,0,255);
4363   *      }
4364   *    }
4365   *  }
4366   *  </code> </div>
4367   */
4368  p5.Oscillator = function (freq, type) {
4369    if (typeof freq === 'string') {
4370      var f = type;
4371      type = freq;
4372      freq = f;
4373    }
4374    if (typeof type === 'number') {
4375      var f = type;
4376      type = freq;
4377      freq = f;
4378    }
4379    this.started = false;
4380    // components
4381    this.phaseAmount = undefined;
4382    this.oscillator = p5sound.audiocontext.createOscillator();
4383    this.f = freq || 440;
4384    // frequency
4385    this.oscillator.frequency.setValueAtTime(this.f, p5sound.audiocontext.currentTime);
4386    this.oscillator.type = type || 'sine';
4387    var o = this.oscillator;
4388    // connections
4389    this.input = p5sound.audiocontext.createGain();
4390    this.output = p5sound.audiocontext.createGain();
4391    this._freqMods = [];
4392    // modulators connected to this oscillator's frequency
4393    // set default output gain to 0.5
4394    this.output.gain.value = 0.5;
4395    this.output.gain.setValueAtTime(0.5, p5sound.audiocontext.currentTime);
4396    this.oscillator.connect(this.output);
4397    // stereo panning
4398    this.panPosition = 0;
4399    this.connection = p5sound.input;
4400    // connect to p5sound by default
4401    this.panner = new p5.Panner(this.output, this.connection, 1);
4402    //array of math operation signal chaining
4403    this.mathOps = [this.output];
4404    // add to the soundArray so we can dispose of the osc later
4405    p5sound.soundArray.push(this);
4406  };
4407  /**
4408   *  Start an oscillator. Accepts an optional parameter to
4409   *  determine how long (in seconds from now) until the
4410   *  oscillator starts.
4411   *
4412   *  @method  start
4413   *  @param  {Number} [time] startTime in seconds from now.
4414   *  @param  {Number} [frequency] frequency in Hz.
4415   */
4416  p5.Oscillator.prototype.start = function (time, f) {
4417    if (this.started) {
4418      var now = p5sound.audiocontext.currentTime;
4419      this.stop(now);
4420    }
4421    if (!this.started) {
4422      var freq = f || this.f;
4423      var type = this.oscillator.type;
4424      // var detune = this.oscillator.frequency.value;
4425      this.oscillator = p5sound.audiocontext.createOscillator();
4426      this.oscillator.frequency.exponentialRampToValueAtTime(Math.abs(freq), p5sound.audiocontext.currentTime);
4427      this.oscillator.type = type;
4428      // this.oscillator.detune.value = detune;
4429      this.oscillator.connect(this.output);
4430      time = time || 0;
4431      this.oscillator.start(time + p5sound.audiocontext.currentTime);
4432      this.freqNode = this.oscillator.frequency;
4433      // if other oscillators are already connected to this osc's freq
4434      for (var i in this._freqMods) {
4435        if (typeof this._freqMods[i].connect !== 'undefined') {
4436          this._freqMods[i].connect(this.oscillator.frequency);
4437        }
4438      }
4439      this.started = true;
4440    }
4441  };
4442  /**
4443   *  Stop an oscillator. Accepts an optional parameter
4444   *  to determine how long (in seconds from now) until the
4445   *  oscillator stops.
4446   *
4447   *  @method  stop
4448   *  @param  {Number} secondsFromNow Time, in seconds from now.
4449   */
4450  p5.Oscillator.prototype.stop = function (time) {
4451    if (this.started) {
4452      var t = time || 0;
4453      var now = p5sound.audiocontext.currentTime;
4454      this.oscillator.stop(t + now);
4455      this.started = false;
4456    }
4457  };
4458  /**
4459   *  Set the amplitude between 0 and 1.0. Or, pass in an object
4460   *  such as an oscillator to modulate amplitude with an audio signal.
4461   *
4462   *  @method  amp
4463   *  @param  {Number|Object} vol between 0 and 1.0
4464   *                              or a modulating signal/oscillator
4465   *  @param {Number} [rampTime] create a fade that lasts rampTime 
4466   *  @param {Number} [timeFromNow] schedule this event to happen
4467   *                                seconds from now
4468   *  @return  {AudioParam} gain  If no value is provided,
4469   *                              returns the Web Audio API
4470   *                              AudioParam that controls
4471   *                              this oscillator's
4472   *                              gain/amplitude/volume)
4473   */
4474  p5.Oscillator.prototype.amp = function (vol, rampTime, tFromNow) {
4475    var self = this;
4476    if (typeof vol === 'number') {
4477      var rampTime = rampTime || 0;
4478      var tFromNow = tFromNow || 0;
4479      var now = p5sound.audiocontext.currentTime;
4480      var currentVol = this.output.gain.value;
4481      this.output.gain.cancelScheduledValues(now);
4482      this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow);
4483      this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime);
4484    } else if (vol) {
4485      vol.connect(self.output.gain);
4486    } else {
4487      // return the Gain Node
4488      return this.output.gain;
4489    }
4490  };
4491  // these are now the same thing
4492  p5.Oscillator.prototype.fade = p5.Oscillator.prototype.amp;
4493  p5.Oscillator.prototype.getAmp = function () {
4494    return this.output.gain.value;
4495  };
4496  /**
4497   *  Set frequency of an oscillator to a value. Or, pass in an object
4498   *  such as an oscillator to modulate the frequency with an audio signal.
4499   *
4500   *  @method  freq
4501   *  @param  {Number|Object} Frequency Frequency in Hz
4502   *                                        or modulating signal/oscillator
4503   *  @param  {Number} [rampTime] Ramp time (in seconds)
4504   *  @param  {Number} [timeFromNow] Schedule this event to happen
4505   *                                   at x seconds from now
4506   *  @return  {AudioParam} Frequency If no value is provided,
4507   *                                  returns the Web Audio API
4508   *                                  AudioParam that controls
4509   *                                  this oscillator's frequency
4510   *  @example
4511   *  <div><code>
4512   *  var osc = new p5.Oscillator(300);
4513   *  osc.start();
4514   *  osc.freq(40, 10);
4515   *  </code></div>
4516   */
4517  p5.Oscillator.prototype.freq = function (val, rampTime, tFromNow) {
4518    if (typeof val === 'number' && !isNaN(val)) {
4519      this.f = val;
4520      var now = p5sound.audiocontext.currentTime;
4521      var rampTime = rampTime || 0;
4522      var tFromNow = tFromNow || 0;
4523      // var currentFreq = this.oscillator.frequency.value;
4524      // this.oscillator.frequency.cancelScheduledValues(now);
4525      if (rampTime == 0) {
4526        this.oscillator.frequency.cancelScheduledValues(now);
4527        this.oscillator.frequency.setValueAtTime(val, tFromNow + now);
4528      } else {
4529        if (val > 0) {
4530          this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now);
4531        } else {
4532          this.oscillator.frequency.linearRampToValueAtTime(val, tFromNow + rampTime + now);
4533        }
4534      }
4535      // reset phase if oscillator has a phase
4536      if (this.phaseAmount) {
4537        this.phase(this.phaseAmount);
4538      }
4539    } else if (val) {
4540      if (val.output) {
4541        val = val.output;
4542      }
4543      val.connect(this.oscillator.frequency);
4544      // keep track of what is modulating this param
4545      // so it can be re-connected if 
4546      this._freqMods.push(val);
4547    } else {
4548      // return the Frequency Node
4549      return this.oscillator.frequency;
4550    }
4551  };
4552  p5.Oscillator.prototype.getFreq = function () {
4553    return this.oscillator.frequency.value;
4554  };
4555  /**
4556   *  Set type to 'sine', 'triangle', 'sawtooth' or 'square'.
4557   *
4558   *  @method  setType
4559   *  @param {String} type 'sine', 'triangle', 'sawtooth' or 'square'.
4560   */
4561  p5.Oscillator.prototype.setType = function (type) {
4562    this.oscillator.type = type;
4563  };
4564  p5.Oscillator.prototype.getType = function () {
4565    return this.oscillator.type;
4566  };
4567  /**
4568   *  Connect to a p5.sound / Web Audio object.
4569   *
4570   *  @method  connect
4571   *  @param  {Object} unit A p5.sound or Web Audio object
4572   */
4573  p5.Oscillator.prototype.connect = function (unit) {
4574    if (!unit) {
4575      this.panner.connect(p5sound.input);
4576    } else if (unit.hasOwnProperty('input')) {
4577      this.panner.connect(unit.input);
4578      this.connection = unit.input;
4579    } else {
4580      this.panner.connect(unit);
4581      this.connection = unit;
4582    }
4583  };
4584  /**
4585   *  Disconnect all outputs
4586   *
4587   *  @method  disconnect
4588   */
4589  p5.Oscillator.prototype.disconnect = function (unit) {
4590    this.output.disconnect();
4591    this.panner.disconnect();
4592    this.output.connect(this.panner);
4593    this.oscMods = [];
4594  };
4595  /**
4596   *  Pan between Left (-1) and Right (1)
4597   *
4598   *  @method  pan
4599   *  @param  {Number} panning Number between -1 and 1
4600   *  @param  {Number} timeFromNow schedule this event to happen
4601   *                                seconds from now
4602   */
4603  p5.Oscillator.prototype.pan = function (pval, tFromNow) {
4604    this.panPosition = pval;
4605    this.panner.pan(pval, tFromNow);
4606  };
4607  p5.Oscillator.prototype.getPan = function () {
4608    return this.panPosition;
4609  };
4610  // get rid of the oscillator
4611  p5.Oscillator.prototype.dispose = function () {
4612    // remove reference from soundArray
4613    var index = p5sound.soundArray.indexOf(this);
4614    p5sound.soundArray.splice(index, 1);
4615    if (this.oscillator) {
4616      var now = p5sound.audiocontext.currentTime;
4617      this.stop(now);
4618      this.disconnect();
4619      this.oscillator.disconnect();
4620      this.panner = null;
4621      this.oscillator = null;
4622    }
4623    // if it is a Pulse
4624    if (this.osc2) {
4625      this.osc2.dispose();
4626    }
4627  };
4628  /**
4629   *  Set the phase of an oscillator between 0.0 and 1.0.
4630   *  In this implementation, phase is a delay time
4631   *  based on the oscillator's current frequency.
4632   *  
4633   *  @method  phase
4634   *  @param  {Number} phase float between 0.0 and 1.0
4635   */
4636  p5.Oscillator.prototype.phase = function (p) {
4637    var delayAmt = p5.prototype.map(p, 0, 1, 0, 1 / this.f);
4638    var now = p5sound.audiocontext.currentTime;
4639    this.phaseAmount = p;
4640    if (!this.dNode) {
4641      // create a delay node
4642      this.dNode = p5sound.audiocontext.createDelay();
4643      // put the delay node in between output and panner
4644      this.oscillator.disconnect();
4645      this.oscillator.connect(this.dNode);
4646      this.dNode.connect(this.output);
4647    }
4648    // set delay time to match phase:
4649    this.dNode.delayTime.setValueAtTime(delayAmt, now);
4650  };
4651  // ========================== //
4652  // SIGNAL MATH FOR MODULATION //
4653  // ========================== //
4654  // return sigChain(this, scale, thisChain, nextChain, Scale);
4655  var sigChain = function (o, mathObj, thisChain, nextChain, type) {
4656    var chainSource = o.oscillator;
4657    // if this type of math already exists in the chain, replace it
4658    for (var i in o.mathOps) {
4659      if (o.mathOps[i] instanceof type) {
4660        chainSource.disconnect();
4661        o.mathOps[i].dispose();
4662        thisChain = i;
4663        // assume nextChain is output gain node unless...
4664        if (thisChain < o.mathOps.length - 2) {
4665          nextChain = o.mathOps[i + 1];
4666        }
4667      }
4668    }
4669    if (thisChain == o.mathOps.length - 1) {
4670      o.mathOps.push(nextChain);
4671    }
4672    // assume source is the oscillator unless i > 0
4673    if (i > 0) {
4674      chainSource = o.mathOps[i - 1];
4675    }
4676    chainSource.disconnect();
4677    chainSource.connect(mathObj);
4678    mathObj.connect(nextChain);
4679    o.mathOps[thisChain] = mathObj;
4680    return o;
4681  };
4682  /**
4683   *  Add a value to the p5.Oscillator's output amplitude,
4684   *  and return the oscillator. Calling this method again
4685   *  will override the initial add() with a new value.
4686   *  
4687   *  @method  add
4688   *  @param {Number} number Constant number to add
4689   *  @return {p5.Oscillator} Oscillator Returns this oscillator
4690   *                                     with scaled output
4691   *  
4692   */
4693  p5.Oscillator.prototype.add = function (num) {
4694    var add = new Add(num);
4695    var thisChain = this.mathOps.length - 1;
4696    var nextChain = this.output;
4697    return sigChain(this, add, thisChain, nextChain, Add);
4698  };
4699  /**
4700   *  Multiply the p5.Oscillator's output amplitude
4701   *  by a fixed value (i.e. turn it up!). Calling this method
4702   *  again will override the initial mult() with a new value.
4703   *  
4704   *  @method  mult
4705   *  @param {Number}
4705 number Constant number to multiply
4706   *  @return {p5.Oscillator} Oscillator Returns this oscillator
4707   *                                     with multiplied output
4708   */
4709  p5.Oscillator.prototype.mult = function (num) {
4710    var mult = new Mult(num);
4711    var thisChain = this.mathOps.length - 1;
4712    var nextChain = this.output;
4713    return sigChain(this, mult, thisChain, nextChain, Mult);
4714  };
4715  /**
4716   *  Scale this oscillator's amplitude values to a given
4717   *  range, and return the oscillator. Calling this method
4718   *  again will override the initial scale() with new values.
4719   *  
4720   *  @method  scale
4721   *  @param  {Number} inMin  input range minumum
4722   *  @param  {Number} inMax  input range maximum
4723   *  @param  {Number} outMin input range minumum
4724   *  @param  {Number} outMax input range maximum
4725   *  @return {p5.Oscillator} Oscillator Returns this oscillator
4726   *                                     with scaled output
4727   */
4728  p5.Oscillator.prototype.scale = function (inMin, inMax, outMin, outMax) {
4729    var mapOutMin, mapOutMax;
4730    if (arguments.length === 4) {
4731      mapOutMin = p5.prototype.map(outMin, inMin, inMax, 0, 1) - 0.5;
4732      mapOutMax = p5.prototype.map(outMax, inMin, inMax, 0, 1) - 0.5;
4733    } else {
4734      mapOutMin = arguments[0];
4735      mapOutMax = arguments[1];
4736    }
4737    var scale = new Scale(mapOutMin, mapOutMax);
4738    var thisChain = this.mathOps.length - 1;
4739    var nextChain = this.output;
4740    return sigChain(this, scale, thisChain, nextChain, Scale);
4741  };
4742  // ============================== //
4743  // SinOsc, TriOsc, SqrOsc, SawOsc //
4744  // ============================== //
4745  /**
4746   *  Constructor: <code>new p5.SinOsc()</code>.
4747   *  This creates a Sine Wave Oscillator and is
4748   *  equivalent to <code> new p5.Oscillator('sine')
4749   *  </code> or creating a p5.Oscillator and then calling
4750   *  its method <code>setType('sine')</code>.
4751   *  See p5.Oscillator for methods.
4752   *
4753   *  @method  p5.SinOsc
4754   *  @param {[Number]} freq Set the frequency
4755   */
4756  p5.SinOsc = function (freq) {
4757    p5.Oscillator.call(this, freq, 'sine');
4758  };
4759  p5.SinOsc.prototype = Object.create(p5.Oscillator.prototype);
4760  /**
4761   *  Constructor: <code>new p5.TriOsc()</code>.
4762   *  This creates a Triangle Wave Oscillator and is
4763   *  equivalent to <code>new p5.Oscillator('triangle')
4764   *  </code> or creating a p5.Oscillator and then calling
4765   *  its method <code>setType('triangle')</code>.
4766   *  See p5.Oscillator for methods.
4767   *
4768   *  @method  p5.TriOsc
4769   *  @param {[Number]} freq Set the frequency
4770   */
4771  p5.TriOsc = function (freq) {
4772    p5.Oscillator.call(this, freq, 'triangle');
4773  };
4774  p5.TriOsc.prototype = Object.create(p5.Oscillator.prototype);
4775  /**
4776   *  Constructor: <code>new p5.SawOsc()</code>.
4777   *  This creates a SawTooth Wave Oscillator and is
4778   *  equivalent to <code> new p5.Oscillator('sawtooth')
4779   *  </code> or creating a p5.Oscillator and then calling
4780   *  its method <code>setType('sawtooth')</code>.
4781   *  See p5.Oscillator for methods.
4782   *
4783   *  @method  p5.SawOsc
4784   *  @param {[Number]} freq Set the frequency
4785   */
4786  p5.SawOsc = function (freq) {
4787    p5.Oscillator.call(this, freq, 'sawtooth');
4788  };
4789  p5.SawOsc.prototype = Object.create(p5.Oscillator.prototype);
4790  /**
4791   *  Constructor: <code>new p5.SqrOsc()</code>.
4792   *  This creates a Square Wave Oscillator and is
4793   *  equivalent to <code> new p5.Oscillator('square')
4794   *  </code> or creating a p5.Oscillator and then calling
4795   *  its method <code>setType('square')</code>.
4796   *  See p5.Oscillator for methods.
4797   *
4798   *  @method  p5.SqrOsc
4799   *  @param {[Number]} freq Set the frequency
4800   */
4801  p5.SqrOsc = function (freq) {
4802    p5.Oscillator.call(this, freq, 'square');
4803  };
4804  p5.SqrOsc.prototype = Object.create(p5.Oscillator.prototype);
4805}(master, Tone_signal_Signal, Tone_signal_Add, Tone_signal_Multiply, Tone_signal_Scale);
4806/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
4807var Tone_core_Timeline;
4808Tone_core_Timeline = function (Tone) {
4809  'use strict';
4810  Tone.Timeline = function () {
4811    var options = this.optionsObject(arguments, ['memory'], Tone.Timeline.defaults);
4812    this._timeline = [];
4813    this._toRemove = [];
4814    this._iterating = false;
4815    this.memory = options.memory;
4816  };
4817  Tone.extend(Tone.Timeline);
4818  Tone.Timeline.defaults = { 'memory': Infinity };
4819  Object.defineProperty(Tone.Timeline.prototype, 'length', {
4820    get: function () {
4821      return this._timeline.length;
4822    }
4823  });
4824  Tone.Timeline.prototype.addEvent = function (event) {
4825    if (this.isUndef(event.time)) {
4826      throw new Error('events must have a time attribute');
4827    }
4828    event.time = this.toSeconds(event.time);
4829    if (this._timeline.length) {
4830      var index = this._search(event.time);
4831      this._timeline.splice(index + 1, 0, event);
4832    } else {
4833      this._timeline.push(event);
4834    }
4835    if (this.length > this.memory) {
4836      var diff = this.length - this.memory;
4837      this._timeline.splice(0, diff);
4838    }
4839    return this;
4840  };
4841  Tone.Timeline.prototype.removeEvent = function (event) {
4842    if (this._iterating) {
4843      this._toRemove.push(event);
4844    } else {
4845      var index = this._timeline.indexOf(event);
4846      if (index !== -1) {
4847        this._timeline.splice(index, 1);
4848      }
4849    }
4850    return this;
4851  };
4852  Tone.Timeline.prototype.getEvent = function (time) {
4853    time = this.toSeconds(time);
4854    var index = this._search(time);
4855    if (index !== -1) {
4856      return this._timeline[index];
4857    } else {
4858      return null;
4859    }
4860  };
4861  Tone.Timeline.prototype.getEventAfter = function (time) {
4862    time = this.toSeconds(time);
4863    var index = this._search(time);
4864    if (index + 1 < this._timeline.length) {
4865      return this._timeline[index + 1];
4866    } else {
4867      return null;
4868    }
4869  };
4870  Tone.Timeline.prototype.getEventBefore = function (time) {
4871    time = this.toSeconds(time);
4872    var index = this._search(time);
4873    if (index - 1 >= 0) {
4874      return this._timeline[index - 1];
4875    } else {
4876      return null;
4877    }
4878  };
4879  Tone.Timeline.prototype.cancel = function (after) {
4880    if (this._timeline.length > 1) {
4881      after = this.toSeconds(after);
4882      var index = this._search(after);
4883      if (index >= 0) {
4884        this._timeline = this._timeline.slice(0, index);
4885      } else {
4886        this._timeline = [];
4887      }
4888    } else if (this._timeline.length === 1) {
4889      if (this._timeline[0].time >= after) {
4890        this._timeline = [];
4891      }
4892    }
4893    return this;
4894  };
4895  Tone.Timeline.prototype.cancelBefore = function (time) {
4896    if (this._timeline.length) {
4897      time = this.toSeconds(time);
4898      var index = this._search(time);
4899      if (index >= 0) {
4900        this._timeline = this._timeline.slice(index + 1);
4901      }
4902    }
4903    return this;
4904  };
4905  Tone.Timeline.prototype._search = function (time) {
4906    var beginning = 0;
4907    var len = this._timeline.length;
4908    var end = len;
4909    while (beginning <= end && beginning < len) {
4910      var midPoint = Math.floor(beginning + (end - beginning) / 2);
4911      var event = this._timeline[midPoint];
4912      if (event.time === time) {
4913        for (var i = midPoint; i < this._timeline.length; i++) {
4914          var testEvent = this._timeline[i];
4915          if (testEvent.time === time) {
4916            midPoint = i;
4917          }
4918        }
4919        return midPoint;
4920      } else if (event.time > time) {
4921        end = midPoint - 1;
4922      } else if (event.time < time) {
4923        beginning = midPoint + 1;
4924      }
4925    }
4926    return beginning - 1;
4927  };
4928  Tone.Timeline.prototype._iterate = function (callback, lowerBound, upperBound) {
4929    this._iterating = true;
4930    lowerBound = this.defaultArg(lowerBound, 0);
4931    upperBound = this.defaultArg(upperBound, this._timeline.length - 1);
4932    for (var i = lowerBound; i <= upperBound; i++) {
4933      callback(this._timeline[i]);
4934    }
4935    this._iterating = false;
4936    if (this._toRemove.length > 0) {
4937      for (var j = 0; j < this._toRemove.length; j++) {
4938        var index = this._timeline.indexOf(this._toRemove[j]);
4939        if (index !== -1) {
4940          this._timeline.splice(index, 1);
4941        }
4942      }
4943      this._toRemove = [];
4944    }
4945  };
4946  Tone.Timeline.prototype.forEach = function (callback) {
4947    this._iterate(callback);
4948    return this;
4949  };
4950  Tone.Timeline.prototype.forEachBefore = function (time, callback) {
4951    time = this.toSeconds(time);
4952    var upperBound = this._search(time);
4953    if (upperBound !== -1) {
4954      this._iterate(callback, 0, upperBound);
4955    }
4956    return this;
4957  };
4958  Tone.Timeline.prototype.forEachAfter = function (time, callback) {
4959    time = this.toSeconds(time);
4960    var lowerBound = this._search(time);
4961    this._iterate(callback, lowerBound + 1);
4962    return this;
4963  };
4964  Tone.Timeline.prototype.forEachFrom = function (time, callback) {
4965    time = this.toSeconds(time);
4966    var lowerBound = this._search(time);
4967    while (lowerBound >= 0 && this._timeline[lowerBound].time >= time) {
4968      lowerBound--;
4969    }
4970    this._iterate(callback, lowerBound + 1);
4971    return this;
4972  };
4973  Tone.Timeline.prototype.forEachAtTime = function (time, callback) {
4974    time = this.toSeconds(time);
4975    var upperBound = this._search(time);
4976    if (upperBound !== -1) {
4977      this._iterate(function (event) {
4978        if (event.time === time) {
4979          callback(event);
4980        }
4981      }, 0, upperBound);
4982    }
4983    return this;
4984  };
4985  Tone.Timeline.prototype.dispose = function () {
4986    Tone.prototype.dispose.call(this);
4987    this._timeline = null;
4988    this._toRemove = null;
4989  };
4990  return Tone.Timeline;
4991}(Tone_core_Tone);
4992/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
4993var Tone_signal_TimelineSignal;
4994Tone_signal_TimelineSignal = function (Tone) {
4995  'use strict';
4996  Tone.TimelineSignal = function () {
4997    var options = this.optionsObject(arguments, [
4998      'value',
4999      'units'
5000    ], Tone.Signal.defaults);
5001    Tone.Signal.apply(this, options);
5002    options.param = this._param;
5003    Tone.Param.call(this, options);
5004    this._events = new Tone.Timeline(10);
5005    this._initial = this._fromUnits(this._param.value);
5006  };
5007  Tone.extend(Tone.TimelineSignal, Tone.Param);
5008  Tone.TimelineSignal.Type = {
5009    Linear: 'linear',
5010    Exponential: 'exponential',
5011    Target: 'target',
5012    Set: 'set'
5013  };
5014  Object.defineProperty(Tone.TimelineSignal.prototype, 'value', {
5015    get: function () {
5016      return this._toUnits(this._param.value);
5017    },
5018    set: function (value) {
5019      var convertedVal = this._fromUnits(value);
5020      this._initial = convertedVal;
5021      this._param.value = convertedVal;
5022    }
5023  });
5024  Tone.TimelineSignal.prototype.setValueAtTime = function (value, startTime) {
5025    value = this._fromUnits(value);
5026    startTime = this.toSeconds(startTime);
5027    this._events.addEvent({
5028      'type': Tone.TimelineSignal.Type.Set,
5029      'value': value,
5030      'time': startTime
5031    });
5032    this._param.setValueAtTime(value, startTime);
5033    return this;
5034  };
5035  Tone.TimelineSignal.prototype.linearRampToValueAtTime = function (value, endTime) {
5036    value = this._fromUnits(value);
5037    endTime = this.toSeconds(endTime);
5038    this._events.addEvent({
5039      'type': Tone.TimelineSignal.Type.Linear,
5040      'value': value,
5041      'time': endTime
5042    });
5043    this._param.linearRampToValueAtTime(value, endTime);
5044    return this;
5045  };
5046  Tone.TimelineSignal.prototype.exponentialRampToValueAtTime = function (value, endTime) {
5047    value = this._fromUnits(value);
5048    value = Math.max(this._minOutput, value);
5049    endTime = this.toSeconds(endTime);
5050    this._events.addEvent({
5051      'type': Tone.TimelineSignal.Type.Exponential,
5052      'value': value,
5053      'time': endTime
5054    });
5055    this._param.exponentialRampToValueAtTime(value, endTime);
5056    return this;
5057  };
5058  Tone.TimelineSignal.prototype.setTargetAtTime = function (value, startTime, timeConstant) {
5059    value = this._fromUnits(value);
5060    value = Math.max(this._minOutput, value);
5061    timeConstant = Math.max(this._minOutput, timeConstant);
5062    startTime = this.toSeconds(startTime);
5063    this._events.addEvent({
5064      'type': Tone.TimelineSignal.Type.Target,
5065      'value': value,
5066      'time': startTime,
5067      'constant': timeConstant
5068    });
5069    this._param.setTargetAtTime(value, startTime, timeConstant);
5070    return this;
5071  };
5072  Tone.TimelineSignal.prototype.cancelScheduledValues = function (after) {
5073    this._events.cancel(after);
5074    this._param.cancelScheduledValues(this.toSeconds(after));
5075    return this;
5076  };
5077  Tone.TimelineSignal.prototype.setRampPoint = function (time) {
5078    time = this.toSeconds(time);
5079    var val = this.getValueAtTime(time);
5080    var after = this._searchAfter(time);
5081    if (after) {
5082      this.cancelScheduledValues(time);
5083      if (after.type === Tone.TimelineSignal.Type.Linear) {
5084        this.linearRampToValueAtTime(val, time);
5085      } else if (after.type === Tone.TimelineSignal.Type.Exponential) {
5086        this.exponentialRampToValueAtTime(val, time);
5087      }
5088    }
5089    this.setValueAtTime(val, time);
5090    return this;
5091  };
5092  Tone.TimelineSignal.prototype.linearRampToValueBetween = function (value, start, finish) {
5093    this.setRampPoint(start);
5094    this.linearRampToValueAtTime(value, finish);
5095    return this;
5096  };
5097  Tone.TimelineSignal.prototype.exponentialRampToValueBetween = function (value, start, finish) {
5098    this.setRampPoint(start);
5099    this.exponentialRampToValueAtTime(value, finish);
5100    return this;
5101  };
5102  Tone.TimelineSignal.prototype._searchBefore = function (time) {
5103    return this._events.getEvent(time);
5104  };
5105  Tone.TimelineSignal.prototype._searchAfter = function (time) {
5106    return this._events.getEventAfter(time);
5107  };
5108  Tone.TimelineSignal.prototype.getValueAtTime = function (time) {
5109    var after = this._searchAfter(time);
5110    var before = this._searchBefore(time);
5111    var value = this._initial;
5112    if (before === null) {
5113      value = this._initial;
5114    } else if (before.type === Tone.TimelineSignal.Type.Target) {
5115      var previous = this._events.getEventBefore(before.time);
5116      var previouVal;
5117      if (previous === null) {
5118        previouVal = this._initial;
5119      } else {
5120        previouVal = previous.value;
5121      }
5122      value = this._exponentialApproach(before.time, previouVal, before.value, before.constant, time);
5123    } else if (after === null) {
5124      value = before.value;
5125    } else if (after.type === Tone.TimelineSignal.Type.Linear) {
5126      value = this._linearInterpolate(before.time, before.value, after.time, after.value, time);
5127    } else if (after.type === Tone.TimelineSignal.Type.Exponential) {
5128      value = this._exponentialInterpolate(before.time, before.value, after.time, after.value, time);
5129    } else {
5130      value = before.value;
5131    }
5132    return value;
5133  };
5134  Tone.TimelineSignal.prototype.connect = Tone.SignalBase.prototype.connect;
5135  Tone.TimelineSignal.prototype._exponentialApproach = function (t0, v0, v1, timeConstant, t) {
5136    return v1 + (v0 - v1) * Math.exp(-(t - t0) / timeConstant);
5137  };
5138  Tone.TimelineSignal.prototype._linearInterpolate = function (t0, v0, t1, v1, t) {
5139    return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
5140  };
5141  Tone.TimelineSignal.prototype._exponentialInterpolate = function (t0, v0, t1, v1, t) {
5142    v0 = Math.max(this._minOutput, v0);
5143    return v0 * Math.pow(v1 / v0, (t - t0) / (t1 - t0));
5144  };
5145  Tone.TimelineSignal.prototype.dispose = function () {
5146    Tone.Signal.prototype.dispose.call(this);
5147    Tone.Param.prototype.dispose.call(this);
5148    this._events.dispose();
5149    this._events = null;
5150  };
5151  return Tone.TimelineSignal;
5152}(Tone_core_Tone, Tone_signal_Signal);
5153var env;
5154env = function () {
5155  'use strict';
5156  var p5sound = master;
5157  var Add = Tone_signal_Add;
5158  var Mult = Tone_signal_Multiply;
5159  var Scale = Tone_signal_Scale;
5160  var TimelineSignal = Tone_signal_TimelineSignal;
5161  var Tone = Tone_core_Tone;
5162  Tone.setContext(p5sound.audiocontext);
5163  /**
5164   *  <p>Envelopes are pre-defined amplitude distribution over time.
5165   *  Typically, envelopes are used to control the output volume
5166   *  of an object, a series of fades referred to as Attack, Decay,
5167   *  Sustain and Release (
5168   *  <a href="https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg">ADSR</a>
5169   *  ). Envelopes can also control other Web Audio Parameters—for example, a p5.Env can 
5170   *  control an Oscillator's frequency like this: <code>osc.freq(env)</code>.</p>
5171   *  <p>Use <code><a href="#/p5.Env/setRange">setRange</a></code> to change the attack/release level.
5172   *  Use <code><a href="#/p5.Env/setADSR">setADSR</a></code> to change attackTime, decayTime, sustainPercent and releaseTime.</p>
5173   *  <p>Use the <code><a href="#/p5.Env/play">play</a></code> method to play the entire envelope,
5174   *  the <code><a href="#/p5.Env/ramp">ramp</a></code> method for a pingable trigger,
5175   *  or <code><a href="#/p5.Env/triggerAttack">triggerAttack</a></code>/
5176   *  <code><a href="#/p5.Env/triggerRelease">triggerRelease</a></code> to trigger noteOn/noteOff.</p>
5177   *  
5178   *  @class p5.Env
5179   *  @constructor
5180   *  @example
5181   *  <div><code>
5182   *  var attackLevel = 1.0;
5183   *  var releaseLevel = 0;
5184   *
5185   *  var attackTime = 0.001
5186   *  var decayTime = 0.2;
5187   *  var susPercent = 0.2;
5188   *  var releaseTime = 0.5;
5189   *
5190   *  var env, triOsc;
5191   *
5192   *  function setup() {
5193   *    var cnv = createCanvas(100, 100);
5194   *
5195   *    textAlign(CENTER);
5196   *    text('click to play', width/2, height/2);
5197   *
5198   *    env = new p5.Env();
5199   *    env.setADSR(attackTime, decayTime, susPercent, releaseTime);
5200   *    env.setRange(attackLevel, releaseLevel);
5201   *
5202   *    triOsc = new p5.Oscillator('triangle');
5203   *    triOsc.amp(env);
5204   *    triOsc.start();
5205   *    triOsc.freq(220);
5206   *
5207   *    cnv.mousePressed(playEnv);
5208   *  }
5209   *
5210   *  function playEnv(){
5211   *    env.play();
5212   *  }
5213   *  </code></div>
5214   */
5215  p5.Env = function (t1, l1, t2, l2, t3, l3) {
5216    var now = p5sound.audiocontext.currentTime;
5217    /**
5218     * Time until envelope reaches attackLevel
5219     * @property attackTime
5220     */
5221    this.aTime = t1 || 0.1;
5222    /**
5223     * Level once attack is complete.
5224     * @property attackLevel
5225     */
5226    this.aLevel = l1 || 1;
5227    /**
5228     * Time until envelope reaches decayLevel.
5229     * @property decayTime
5230     */
5231    this.dTime = t2 || 0.5;
5232    /**
5233     * Level after decay. The envelope will sustain here until it is released.
5234     * @property decayLevel
5235     */
5236    this.dLevel = l2 || 0;
5237    /**
5238     * Duration of the release portion of the envelope.
5239     * @property releaseTime
5240     */
5241    this.rTime = t3 || 0;
5242    /**
5243     * Level at the end of the release.
5244     * @property releaseLevel
5245     */
5246    this.rLevel = l3 || 0;
5247    this._rampHighPercentage = 0.98;
5248    this._rampLowPercentage = 0.02;
5249    this.output = p5sound.audiocontext.createGain();
5250    this.control = new TimelineSignal();
5251    this._init();
5252    // this makes sure the envelope starts at zero
5253    this.control.connect(this.output);
5254    // connect to the output
5255    this.connection = null;
5256    // store connection
5257    //array of math operation signal chaining
5258    this.mathOps = [this.control];
5259    //whether envelope should be linear or exponential curve
5260    this.isExponential = false;
5261    // oscillator or buffer source to clear on env complete
5262    // to save resources if/when it is retriggered
5263    this.sourceToClear = null;
5264    // set to true if attack is set, then false on release
5265    this.wasTriggered = false;
5266    // add to the soundArray so we can dispose of the env later
5267    p5sound.soundArray.push(this);
5268  };
5269  // this init function just smooths the starting value to zero and gives a start point for the timeline
5270  // - it was necessary to remove glitches at the beginning.
5271  p5.Env.prototype._init = function () {
5272    var now = p5sound.audiocontext.currentTime;
5273    var t = now;
5274    this.control.setTargetAtTime(0.00001, t, 0.001);
5275    //also, compute the correct time constants
5276    this._setRampAD(this.aTime, this.dTime);
5277  };
5278  /**
5279   *  Reset the envelope with a series of time/value pairs.
5280   *
5281   *  @method  set
5282   *  @param {Number} attackTime     Time (in seconds) before level
5283   *                                 reaches attackLevel
5284   *  @param {Number} attackLevel    Typically an amplitude between
5285   *                                 0.0 and 1.0
5286   *  @param {Number} decayTime      Time
5287   *  @param {Number} decayLevel   Amplitude (In a standard ADSR envelope,
5288   *                                 decayLevel = sustainLevel)
5289   *  @param {Number} releaseTime   Release Time (in seconds)
5290   *  @param {Number} releaseLevel  Amplitude
5291   */
5292  p5.Env.prototype.set = function (t1, l1, t2, l2, t3, l3) {
5293    this.aTime = t1;
5294    this.aLevel = l1;
5295    this.dTime = t2 || 0;
5296    this.dLevel = l2 || 0;
5297    this.rTime = t4 || 0;
5298    this.rLevel = l4 || 0;
5299    // set time constants for ramp
5300    this._setRampAD(t1, t2);
5301  };
5302  /**
5303   *  Set values like a traditional
5304   *  <a href="https://en.wikipedia.org/wiki/Synthesizer#/media/File:ADSR_parameter.svg">
5305   *  ADSR envelope
5306   *  </a>.
5307   *  
5308   *  @method  setADSR
5309   *  @param {Number} attackTime    Time (in seconds before envelope
5310   *                                reaches Attack Level
5311   *  @param {Number} [decayTime]    Time (in seconds) before envelope
5312   *                                reaches Decay/Sustain Level
5313   *  @param {Number} [susRatio]    Ratio between attackLevel and releaseLevel, on a scale from 0 to 1,
5314   *                                where 1.0 = attackLevel, 0.0 = releaseLevel.
5315   *                                The susRatio determines the decayLevel and the level at which the
5316   *                                sustain portion of the envelope will sustain.
5317   *                                For example, if attackLevel is 0.4, releaseLevel is 0,
5318   *                                and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is
5319   *                                increased to 1.0 (using <code>setRange</code>),
5320   *                                then decayLevel would increase proportionally, to become 0.5.
5321   *  @param {Number} [releaseTime]   Time in seconds from now (defaults to 0)
5322   *  @example
5323   *  <div><code>
5324   *  var attackLevel = 1.0;
5325   *  var releaseLevel = 0;
5326   *
5327   *  var attackTime = 0.001
5328   *  var decayTime = 0.2;
5329   *  var susPercent = 0.2;
5330   *  var releaseTime = 0.5;
5331   *
5332   *  var env, triOsc;
5333   *
5334   *  function setup() {
5335   *    var cnv = createCanvas(100, 100);
5336   *
5337   *    textAlign(CENTER);
5338   *    text('click to play', width/2, height/2);
5339   *
5340   *    env = new p5.Env();
5341   *    env.setADSR(attackTime, decayTime, susPercent, releaseTime);
5342   *    env.setRange(attackLevel, releaseLevel);
5343   *
5344   *    triOsc = new p5.Oscillator('triangle');
5345   *    triOsc.amp(env);
5346   *    triOsc.start();
5347   *    triOsc.freq(220);
5348   *
5349   *    cnv.mousePressed(playEnv);
5350   *  }
5351   *
5352   *  function playEnv(){
5353   *    env.play();
5354   *  }
5355   *  </code></div>
5356   */
5357  p5.Env.prototype.setADSR = function (aTime, dTime, sPercent, rTime) {
5358    this.aTime = aTime;
5359    this.dTime = dTime || 0;
5360    // lerp
5361    this.sPercent = sPercent || 0;
5362    this.dLevel = typeof sPercent !== 'undefined' ? sPercent * (this.aLevel - this.rLevel) + this.rLevel : 0;
5363    this.rTime = rTime || 0;
5364    // also set time constants for ramp
5365    this._setRampAD(aTime, dTime);
5366  };
5367  /**
5368   *  Set max (attackLevel) and min (releaseLevel) of envelope.
5369   *  
5370   *  @method  setRange
5371   *  @param {Number} aLevel attack level (defaults to 1)
5372   *  @param {Number} rLevel release level (defaults to 0)
5373   *  @example
5374   *  <div><code>
5375   *  var attackLevel = 1.0;
5376   *  var releaseLevel = 0;
5377   *
5378   *  var attackTime = 0.001
5379   *  var decayTime = 0.2;
5380   *  var susPercent = 0.2;
5381   *  var releaseTime = 0.5;
5382   *
5383   *  var env, triOsc;
5384   *
5385   *  function setup() {
5386   *    var cnv = createCanvas(100, 100);
5387   *
5388   *    textAlign(CENTER);
5389   *    text('click to play', width/2, height/2);
5390   *
5391   *    env = new p5.Env();
5392   *    env.setADSR(attackTime, decayTime, susPercent, releaseTime);
5393   *    env.setRange(attackLevel, releaseLevel);
5394   *
5395   *    triOsc = new p5.Oscillator('triangle');
5396   *    triOsc.amp(env);
5397   *    triOsc.start();
5398   *    triOsc.freq(220);
5399   *
5400   *    cnv.mousePressed(playEnv);
5401   *  }
5402   *
5403   *  function playEnv(){
5404   *    env.play();
5405   *  }
5406   *  </code></div>
5407   */
5408  p5.Env.prototype.setRange = function (aLevel, rLevel) {
5409    this.aLevel = aLevel || 1;
5410    this.rLevel = rLevel || 0;
5411  };
5412  //  private (undocumented) method called when ADSR is set to set time constants for ramp
5413  //
5414  //  Set the <a href="https://en.wikipedia.org/wiki/RC_time_constant">
5415  //  time constants</a> for simple exponential ramps.
5416  //  The larger the time constant value, the slower the
5417  //  transition will be.
5418  //
5419  //  method  _setRampAD
5420  //  param {Number}
5420 attackTimeConstant  attack time constant
5421  //  param {Number} decayTimeConstant   decay time constant
5422  //
5423  p5.Env.prototype._setRampAD = function (t1, t2) {
5424    this._rampAttackTime = this.checkExpInput(t1);
5425    this._rampDecayTime = this.checkExpInput(t2);
5426    var TCDenominator = 1;
5427    /// Aatish Bhatia's calculation for time constant for rise(to adjust 1/1-e calculation to any percentage)
5428    TCDenominator = Math.log(1 / this.checkExpInput(1 - this._rampHighPercentage));
5429    this._rampAttackTC = t1 / this.checkExpInput(TCDenominator);
5430    TCDenominator = Math.log(1 / this._rampLowPercentage);
5431    this._rampDecayTC = t2 / this.checkExpInput(TCDenominator);
5432  };
5433  // private method
5434  p5.Env.prototype.setRampPercentages = function (p1, p2) {
5435    //set the percentages that the simple exponential ramps go to
5436    this._rampHighPercentage = this.checkExpInput(p1);
5437    this._rampLowPercentage = this.checkExpInput(p2);
5438    var TCDenominator = 1;
5439    //now re-compute the time constants based on those percentages
5440    /// Aatish Bhatia's calculation for time constant for rise(to adjust 1/1-e calculation to any percentage)
5441    TCDenominator = Math.log(1 / this.checkExpInput(1 - this._rampHighPercentage));
5442    this._rampAttackTC = this._rampAttackTime / this.checkExpInput(TCDenominator);
5443    TCDenominator = Math.log(1 / this._rampLowPercentage);
5444    this._rampDecayTC = this._rampDecayTime / this.checkExpInput(TCDenominator);
5445  };
5446  /**
5447   *  Assign a parameter to be controlled by this envelope.
5448   *  If a p5.Sound object is given, then the p5.Env will control its
5449   *  output gain. If multiple inputs are provided, the env will
5450   *  control all of them.
5451   *  
5452   *  @method  setInput
5453   *  @param  {Object} unit         A p5.sound object or
5454   *                                Web Audio Param.
5455   */
5456  p5.Env.prototype.setInput = function (unit) {
5457    for (var i = 0; i < arguments.length; i++) {
5458      this.connect(arguments[i]);
5459    }
5460  };
5461  /**
5462   *  Set whether the envelope ramp is linear (default) or exponential.
5463   *  Exponential ramps can be useful because we perceive amplitude
5464   *  and frequency logarithmically.
5465   *  
5466   *  @method  setExp
5467   *  @param {Boolean} isExp true is exponential, false is linear
5468   */
5469  p5.Env.prototype.setExp = function (isExp) {
5470    this.isExponential = isExp;
5471  };
5472  //helper method to protect against zero values being sent to exponential functions
5473  p5.Env.prototype.checkExpInput = function (value) {
5474    if (value <= 0) {
5475      value = 0.0001;
5476    }
5477    return value;
5478  };
5479  /**
5480   *  Play tells the envelope to start acting on a given input.
5481   *  If the input is a p5.sound object (i.e. AudioIn, Oscillator,
5482   *  SoundFile), then Env will control its output volume.
5483   *  Envelopes can also be used to control any <a href="
5484   *  http://docs.webplatform.org/wiki/apis/webaudio/AudioParam">
5485   *  Web Audio Audio Param.</a>
5486   *
5487   *  @method  play
5488   *  @param  {Object} unit         A p5.sound object or
5489   *                                Web Audio Param.
5490   *  @param  {Number} [startTime]  time from now (in seconds) at which to play
5491   *  @param  {Number} [sustainTime] time to sustain before releasing the envelope
5492   *  @example
5493   *  <div><code>
5494   *  var attackLevel = 1.0;
5495   *  var releaseLevel = 0;
5496   *
5497   *  var attackTime = 0.001
5498   *  var decayTime = 0.2;
5499   *  var susPercent = 0.2;
5500   *  var releaseTime = 0.5;
5501   *
5502   *  var env, triOsc;
5503   *
5504   *  function setup() {
5505   *    var cnv = createCanvas(100, 100);
5506   *
5507   *    textAlign(CENTER);
5508   *    text('click to play', width/2, height/2);
5509   *
5510   *    env = new p5.Env();
5511   *    env.setADSR(attackTime, decayTime, susPercent, releaseTime);
5512   *    env.setRange(attackLevel, releaseLevel);
5513   *
5514   *    triOsc = new p5.Oscillator('triangle');
5515   *    triOsc.amp(env);
5516   *    triOsc.start();
5517   *    triOsc.freq(220);
5518   *
5519   *    cnv.mousePressed(playEnv);
5520   *  }
5521   *
5522   *  function playEnv(){
5523   *    // trigger env on triOsc, 0 seconds from now
5524   *    // After decay, sustain for 0.2 seconds before release
5525   *    env.play(triOsc, 0, 0.2);
5526   *  }
5527   *  </code></div>
5528   */
5529  p5.Env.prototype.play = function (unit, secondsFromNow, susTime) {
5530    var now = p5sound.audiocontext.currentTime;
5531    var tFromNow = secondsFromNow || 0;
5532    var susTime = susTime || 0;
5533    if (unit) {
5534      if (this.connection !== unit) {
5535        this.connect(unit);
5536      }
5537    }
5538    this.triggerAttack(unit, tFromNow);
5539    this.triggerRelease(unit, tFromNow + this.aTime + this.dTime + susTime);
5540  };
5541  /**
5542   *  Trigger the Attack, and Decay portion of the Envelope.
5543   *  Similar to holding down a key on a piano, but it will
5544   *  hold the sustain level until you let go. Input can be
5545   *  any p5.sound object, or a <a href="
5546   *  http://docs.webplatform.org/wiki/apis/webaudio/AudioParam">
5547   *  Web Audio Param</a>.
5548   *
5549   *  @method  triggerAttack
5550   *  @param  {Object} unit p5.sound Object or Web Audio Param
5551   *  @param  {Number} secondsFromNow time from now (in seconds)
5552   *  @example
5553   *  <div><code>
5554   *  
5555   *  var attackLevel = 1.0;
5556   *  var releaseLevel = 0;
5557   *  
5558   *  var attackTime = 0.001
5559   *  var decayTime = 0.3;
5560   *  var susPercent = 0.4;
5561   *  var releaseTime = 0.5;
5562   *  
5563   *  var env, triOsc;
5564   *  
5565   *  function setup() {
5566   *    var cnv = createCanvas(100, 100);
5567   *    background(200);
5568   *    textAlign(CENTER);
5569   *    text('click to play', width/2, height/2);
5570   *  
5571   *    env = new p5.Env();
5572   *    env.setADSR(attackTime, decayTime, susPercent, releaseTime);
5573   *    env.setRange(attackLevel, releaseLevel);
5574   *  
5575   *    triOsc = new p5.Oscillator('triangle');
5576   *    triOsc.amp(env);
5577   *    triOsc.start();
5578   *    triOsc.freq(220);
5579   *  
5580   *    cnv.mousePressed(envAttack);
5581   *  }
5582   *  
5583   *  function envAttack(){
5584   *    console.log('trigger attack');
5585   *    env.triggerAttack();
5586   *  
5587   *    background(0,255,0);
5588   *    text('attack!', width/2, height/2);
5589   *  }
5590   *  
5591   *  function mouseReleased() {
5592   *    env.triggerRelease();
5593   *  
5594   *    background(200);
5595   *    text('click to play', width/2, height/2);
5596   *  }
5597   *  </code></div>
5598   */
5599  p5.Env.prototype.triggerAttack = function (unit, secondsFromNow) {
5600    var now = p5sound.audiocontext.currentTime;
5601    var tFromNow = secondsFromNow || 0;
5602    var t = now + tFromNow;
5603    this.lastAttack = t;
5604    this.wasTriggered = true;
5605    if (unit) {
5606      if (this.connection !== unit) {
5607        this.connect(unit);
5608      }
5609    }
5610    // get and set value (with linear ramp) to anchor automation
5611    var valToSet = this.control.getValueAtTime(t);
5612    this.control.cancelScheduledValues(t);
5613    // not sure if this is necessary
5614    if (this.isExponential == true) {
5615      this.control.exponentialRampToValueAtTime(this.checkExpInput(valToSet), t);
5616    } else {
5617      this.control.linearRampToValueAtTime(valToSet, t);
5618    }
5619    // after each ramp completes, cancel scheduled values
5620    // (so they can be overridden in case env has been re-triggered)
5621    // then, set current value (with linearRamp to avoid click)
5622    // then, schedule the next automation...
5623    // attack
5624    t += this.aTime;
5625    if (this.isExponential == true) {
5626      this.control.exponentialRampToValueAtTime(this.checkExpInput(this.aLevel), t);
5627      valToSet = this.checkExpInput(this.control.getValueAtTime(t));
5628      this.control.cancelScheduledValues(t);
5629      this.control.exponentialRampToValueAtTime(valToSet, t);
5630    } else {
5631      this.control.linearRampToValueAtTime(this.aLevel, t);
5632      valToSet = this.control.getValueAtTime(t);
5633      this.control.cancelScheduledValues(t);
5634      this.control.linearRampToValueAtTime(valToSet, t);
5635    }
5636    // decay to decay level (if using ADSR, then decay level == sustain level)
5637    t += this.dTime;
5638    if (this.isExponential == true) {
5639      this.control.exponentialRampToValueAtTime(this.checkExpInput(this.dLevel), t);
5640      valToSet = this.checkExpInput(this.control.getValueAtTime(t));
5641      this.control.cancelScheduledValues(t);
5642      this.control.exponentialRampToValueAtTime(valToSet, t);
5643    } else {
5644      this.control.linearRampToValueAtTime(this.dLevel, t);
5645      valToSet = this.control.getValueAtTime(t);
5646      this.control.cancelScheduledValues(t);
5647      this.control.linearRampToValueAtTime(valToSet, t);
5648    }
5649  };
5650  /**
5651   *  Trigger the Release of the Envelope. This is similar to releasing
5652   *  the key on a piano and letting the sound fade according to the
5653   *  release level and release time.
5654   *
5655   *  @method  triggerRelease
5656   *  @param  {Object} unit p5.sound Object or Web Audio Param
5657   *  @param  {Number} secondsFromNow time to trigger the release
5658   *  @example
5659   *  <div><code>
5660   *  
5661   *  var attackLevel = 1.0;
5662   *  var releaseLevel = 0;
5663   *  
5664   *  var attackTime = 0.001
5665   *  var decayTime = 0.3;
5666   *  var susPercent = 0.4;
5667   *  var releaseTime = 0.5;
5668   *  
5669   *  var env, triOsc;
5670   *  
5671   *  function setup() {
5672   *    var cnv = createCanvas(100, 100);
5673   *    background(200);
5674   *    textAlign(CENTER);
5675   *    text('click to play', width/2, height/2);
5676   *  
5677   *    env = new p5.Env();
5678   *    env.setADSR(attackTime, decayTime, susPercent, releaseTime);
5679   *    env.setRange(attackLevel, releaseLevel);
5680   *  
5681   *    triOsc = new p5.Oscillator('triangle');
5682   *    triOsc.amp(env);
5683   *    triOsc.start();
5684   *    triOsc.freq(220);
5685   *  
5686   *    cnv.mousePressed(envAttack);
5687   *  }
5688   *  
5689   *  function envAttack(){
5690   *    console.log('trigger attack');
5691   *    env.triggerAttack();
5692   *  
5693   *    background(0,255,0);
5694   *    text('attack!', width/2, height/2);
5695   *  }
5696   *  
5697   *  function mouseReleased() {
5698   *    env.triggerRelease();
5699   *  
5700   *    background(200);
5701   *    text('click to play', width/2, height/2);
5702   *  }
5703   *  </code></div>
5704   */
5705  p5.Env.prototype.triggerRelease = function (unit, secondsFromNow) {
5706    // only trigger a release if an attack was triggered
5707    if (!this.wasTriggered) {
5708      // this currently causes a bit of trouble:
5709      // if a later release has been scheduled (via the play function)
5710      // a new earlier release won't interrupt it, because 
5711      // this.wasTriggered has already been set to false.
5712      // If we want new earlier releases to override, then we need to 
5713      // keep track of the last release time, and if the new release time is 
5714      // earlier, then use it.
5715      return;
5716    }
5717    var now = p5sound.audiocontext.currentTime;
5718    var tFromNow = secondsFromNow || 0;
5719    var t = now + tFromNow;
5720    if (unit) {
5721      if (this.connection !== unit) {
5722        this.connect(unit);
5723      }
5724    }
5725    // get and set value (with linear or exponential ramp) to anchor automation
5726    var valToSet = this.control.getValueAtTime(t);
5727    this.control.cancelScheduledValues(t);
5728    // not sure if this is necessary
5729    if (this.isExponential == true) {
5730      this.control.exponentialRampToValueAtTime(this.checkExpInput(valToSet), t);
5731    } else {
5732      this.control.linearRampToValueAtTime(valToSet, t);
5733    }
5734    // release
5735    t += this.rTime;
5736    if (this.isExponential == true) {
5737      this.control.exponentialRampToValueAtTime(this.checkExpInput(this.rLevel), t);
5738      valToSet = this.checkExpInput(this.control.getValueAtTime(t));
5739      this.control.cancelScheduledValues(t);
5740      this.control.exponentialRampToValueAtTime(valToSet, t);
5741    } else {
5742      this.control.linearRampToValueAtTime(this.rLevel, t);
5743      valToSet = this.control.getValueAtTime(t);
5744      this.control.cancelScheduledValues(t);
5745      this.control.linearRampToValueAtTime(valToSet, t);
5746    }
5747    this.wasTriggered = false;
5748  };
5749  /**
5750   *  Exponentially ramp to a value using the first two
5751   *  values from <code><a href="#/p5.Env/setADSR">setADSR(attackTime, decayTime)</a></code>
5752   *  as <a href="https://en.wikipedia.org/wiki/RC_time_constant">
5753   *  time constants</a> for simple exponential ramps.
5754   *  If the value is higher than current value, it uses attackTime,
5755   *  while a decrease uses decayTime.
5756   *
5757   *  @method  ramp
5758   *  @param  {Object} unit           p5.sound Object or Web Audio Param
5759   *  @param  {Number} secondsFromNow When to trigger the ramp
5760   *  @param  {Number} v              Target value
5761   *  @param  {Number} [v2]           Second target value (optional)
5762   *  @example
5763   *  <div><code>
5764   *  var env, osc, amp, cnv;
5765   *  
5766   *  var attackTime = 0.001;
5767   *  var decayTime = 0.2;
5768   *  var attackLevel = 1;
5769   *  var decayLevel = 0;
5770   *  
5771   *  function setup() {
5772   *    cnv = createCanvas(100, 100);
5773   *    fill(0,255,0);
5774   *    noStroke();
5775   *  
5776   *    env = new p5.Env();
5777   *    env.setADSR(attackTime, decayTime);
5778   *  
5779   *    osc = new p5.Oscillator();
5780   *    osc.amp(env);
5781   *    osc.start();
5782   *  
5783   *    amp = new p5.Amplitude();
5784   *  
5785   *    cnv.mousePressed(triggerRamp);
5786   *  }
5787   *  
5788   *  function triggerRamp() {
5789   *    env.ramp(osc, 0, attackLevel, decayLevel);
5790   *  }
5791   *  
5792   *  function draw() {
5793   *    background(20,20,20);
5794   *    text('click me', 10, 20);
5795   *    var h = map(amp.getLevel(), 0, 0.4, 0, height);;
5796   *  
5797   *    rect(0, height, width, -h);
5798   *  }
5799   *  </code></div>
5800   */
5801  p5.Env.prototype.ramp = function (unit, secondsFromNow, v1, v2) {
5802    var now = p5sound.audiocontext.currentTime;
5803    var tFromNow = secondsFromNow || 0;
5804    var t = now + tFromNow;
5805    var destination1 = this.checkExpInput(v1);
5806    var destination2 = typeof v2 !== 'undefined' ? this.checkExpInput(v2) : undefined;
5807    // connect env to unit if not already connected
5808    if (unit) {
5809      if (this.connection !== unit) {
5810        this.connect(unit);
5811      }
5812    }
5813    //get current value
5814    var currentVal = this.checkExpInput(this.control.getValueAtTime(t));
5815    this.control.cancelScheduledValues(t);
5816    //if it's going up
5817    if (destination1 > currentVal) {
5818      this.control.setTargetAtTime(destination1, t, this._rampAttackTC);
5819      t += this._rampAttackTime;
5820    } else if (destination1 < currentVal) {
5821      this.control.setTargetAtTime(destination1, t, this._rampDecayTC);
5822      t += this._rampDecayTime;
5823    }
5824    // Now the second part of envelope begins
5825    if (destination2 === undefined)
5826      return;
5827    //if it's going up
5828    if (destination2 > destination1) {
5829      this.control.setTargetAtTime(destination2, t, this._rampAttackTC);
5830    } else if (destination2 < destination1) {
5831      this.control.setTargetAtTime(destination2, t, this._rampDecayTC);
5832    }
5833  };
5834  p5.Env.prototype.connect = function (unit) {
5835    this.connection = unit;
5836    // assume we're talking about output gain
5837    // unless given a different audio param
5838    if (unit instanceof p5.Oscillator || unit instanceof p5.SoundFile || unit instanceof p5.AudioIn || unit instanceof p5.Reverb || unit instanceof p5.Noise || unit instanceof p5.Filter || unit instanceof p5.Delay) {
5839      unit = unit.output.gain;
5840    }
5841    if (unit instanceof AudioParam) {
5842      //set the initial value
5843      unit.setValueAtTime(0, p5sound.audiocontext.currentTime);
5844    }
5845    if (unit instanceof p5.Signal) {
5846      unit.setValue(0);
5847    }
5848    this.output.connect(unit);
5849  };
5850  p5.Env.prototype.disconnect = function (unit) {
5851    this.output.disconnect();
5852  };
5853  // Signal Math
5854  /**
5855   *  Add a value to the p5.Oscillator's output amplitude,
5856   *  and return the oscillator. Calling this method
5857   *  again will override the initial add() with new values.
5858   *  
5859   *  @method  add
5860   *  @param {Number} number Constant number to add
5861   *  @return {p5.Env} Envelope Returns this envelope
5862   *                                     with scaled output
5863   */
5864  p5.Env.prototype.add = function (num) {
5865    var add = new Add(num);
5866    var thisChain = this.mathOps.length;
5867    var nextChain = this.output;
5868    return p5.prototype._mathChain(this, add, thisChain, nextChain, Add);
5869  };
5870  /**
5871   *  Multiply the p5.Env's output amplitude
5872   *  by a fixed value. Calling this method
5873   *  again will override the initial mult() with new values.
5874   *  
5875   *  @method  mult
5876   *  @param {Number}
5876 number Constant number to multiply
5877   *  @return {p5.Env} Envelope Returns this envelope
5878   *                                     with scaled output
5879   */
5880  p5.Env.prototype.mult = function (num) {
5881    var mult = new Mult(num);
5882    var thisChain = this.mathOps.length;
5883    var nextChain = this.output;
5884    return p5.prototype._mathChain(this, mult, thisChain, nextChain, Mult);
5885  };
5886  /**
5887   *  Scale this envelope's amplitude values to a given
5888   *  range, and return the envelope. Calling this method
5889   *  again will override the initial scale() with new values.
5890   *  
5891   *  @method  scale
5892   *  @param  {Number} inMin  input range minumum
5893   *  @param  {Number} inMax  input range maximum
5894   *  @param  {Number} outMin input range minumum
5895   *  @param  {Number} outMax input range maximum
5896   *  @return {p5.Env} Envelope Returns this envelope
5897   *                                     with scaled output
5898   */
5899  p5.Env.prototype.scale = function (inMin, inMax, outMin, outMax) {
5900    var scale = new Scale(inMin, inMax, outMin, outMax);
5901    var thisChain = this.mathOps.length;
5902    var nextChain = this.output;
5903    return p5.prototype._mathChain(this, scale, thisChain, nextChain, Scale);
5904  };
5905  // get rid of the oscillator
5906  p5.Env.prototype.dispose = function () {
5907    // remove reference from soundArray
5908    var index = p5sound.soundArray.indexOf(this);
5909    p5sound.soundArray.splice(index, 1);
5910    var now = p5sound.audiocontext.currentTime;
5911    this.disconnect();
5912    try {
5913      this.control.dispose();
5914      this.control = null;
5915    } catch (e) {
5916    }
5917    for (var i = 1; i < this.mathOps.length; i++) {
5918      mathOps[i].dispose();
5919    }
5920  };
5921}(master, Tone_signal_Add, Tone_signal_Multiply, Tone_signal_Scale, Tone_signal_TimelineSignal, Tone_core_Tone);
5922var pulse;
5923pulse = function () {
5924  'use strict';
5925  var p5sound = master;
5926  /**
5927   *  Creates a Pulse object, an oscillator that implements
5928   *  Pulse Width Modulation.
5929   *  The pulse is created with two oscillators.
5930   *  Accepts a parameter for frequency, and to set the
5931   *  width between the pulses. See <a href="
5932   *  http://p5js.org/reference/#/p5.Oscillator">
5933   *  <code>p5.Oscillator</code> for a full list of methods.
5934   *  
5935   *  @class p5.Pulse
5936   *  @constructor
5937   *  @param {Number} [freq] Frequency in oscillations per second (Hz)
5938   *  @param {Number} [w]    Width between the pulses (0 to 1.0,
5939   *                         defaults to 0)
5940   *  @example
5941   *  <div><code>
5942   *  var pulse;
5943   *  function setup() {
5944   *    background(0);
5945   *    
5946   *    // Create and start the pulse wave oscillator
5947   *    pulse = new p5.Pulse();
5948   *    pulse.amp(0.5);
5949   *    pulse.freq(220);
5950   *    pulse.start();
5951   *  }
5952   *
5953   *  function draw() {
5954   *    var w = map(mouseX, 0, width, 0, 1);
5955   *    w = constrain(w, 0, 1);
5956   *    pulse.width(w)
5957   *  }
5958   *  </code></div>
5959   */
5960  p5.Pulse = function (freq, w) {
5961    p5.Oscillator.call(this, freq, 'sawtooth');
5962    // width of PWM, should be betw 0 to 1.0
5963    this.w = w || 0;
5964    // create a second oscillator with inverse frequency
5965    this.osc2 = new p5.SawOsc(freq);
5966    // create a delay node
5967    this.dNode = p5sound.audiocontext.createDelay();
5968    // dc offset
5969    this.dcOffset = createDCOffset();
5970    this.dcGain = p5sound.audiocontext.createGain();
5971    this.dcOffset.connect(this.dcGain);
5972    this.dcGain.connect(this.output);
5973    // set delay time based on PWM width
5974    this.f = freq || 440;
5975    var mW = this.w / this.oscillator.frequency.value;
5976    this.dNode.delayTime.value = mW;
5977    this.dcGain.gain.value = 1.7 * (0.5 - this.w);
5978    // disconnect osc2 and connect it to delay, which is connected to output
5979    this.osc2.disconnect();
5980    this.osc2.panner.disconnect();
5981    this.osc2.amp(-1);
5982    // inverted amplitude
5983    this.osc2.output.connect(this.dNode);
5984    this.dNode.connect(this.output);
5985    this.output.gain.value = 1;
5986    this.output.connect(this.panner);
5987  };
5988  p5.Pulse.prototype = Object.create(p5.Oscillator.prototype);
5989  /**
5990   *  Set the width of a Pulse object (an oscillator that implements
5991   *  Pulse Width Modulation).
5992   *
5993   *  @method  width
5994   *  @param {Number} [width]    Width between the pulses (0 to 1.0,
5995   *                         defaults to 0)
5996   */
5997  p5.Pulse.prototype.width = function (w) {
5998    if (typeof w === 'number') {
5999      if (w <= 1 && w >= 0) {
6000        this.w = w;
6001        // set delay time based on PWM width
6002        // var mW = map(this.w, 0, 1.0, 0, 1/this.f);
6003        var mW = this.w / this.oscillator.frequency.value;
6004        this.dNode.delayTime.value = mW;
6005      }
6006      this.dcGain.gain.value = 1.7 * (0.5 - this.w);
6007    } else {
6008      w.connect(this.dNode.delayTime);
6009      var sig = new p5.SignalAdd(-0.5);
6010      sig.setInput(w);
6011      sig = sig.mult(-1);
6012      sig = sig.mult(1.7);
6013      sig.connect(this.dcGain.gain);
6014    }
6015  };
6016  p5.Pulse.prototype.start = function (f, time) {
6017    var now = p5sound.audiocontext.currentTime;
6018    var t = time || 0;
6019    if (!this.started) {
6020      var freq = f || this.f;
6021      var type = this.oscillator.type;
6022      this.oscillator = p5sound.audiocontext.createOscillator();
6023      this.oscillator.frequency.setValueAtTime(freq, now);
6024      this.oscillator.type = type;
6025      this.oscillator.connect(this.output);
6026      this.oscillator.start(t + now);
6027      // set up osc2
6028      this.osc2.oscillator = p5sound.audiocontext.createOscillator();
6029      this.osc2.oscillator.frequency.setValueAtTime(freq, t + now);
6030      this.osc2.oscillator.type = type;
6031      this.osc2.oscillator.connect(this.osc2.output);
6032      this.osc2.start(t + now);
6033      this.freqNode = [
6034        this.oscillator.frequency,
6035        this.osc2.oscillator.frequency
6036      ];
6037      // start dcOffset, too
6038      this.dcOffset = createDCOffset();
6039      this.dcOffset.connect(this.dcGain);
6040      this.dcOffset.start(t + now);
6041      // if LFO connections depend on these oscillators
6042      if (this.mods !== undefined && this.mods.frequency !== undefined) {
6043        this.mods.frequency.connect(this.freqNode[0]);
6044        this.mods.frequency.connect(this.freqNode[1]);
6045      }
6046      this.started = true;
6047      this.osc2.started = true;
6048    }
6049  };
6050  p5.Pulse.prototype.stop = function (time) {
6051    if (this.started) {
6052      var t = time || 0;
6053      var now = p5sound.audiocontext.currentTime;
6054      this.oscillator.stop(t + now);
6055      this.osc2.oscillator.stop(t + now);
6056      this.dcOffset.stop(t + now);
6057      this.started = false;
6058      this.osc2.started = false;
6059    }
6060  };
6061  p5.Pulse.prototype.freq = function (val, rampTime, tFromNow) {
6062    if (typeof val === 'number') {
6063      this.f = val;
6064      var now = p5sound.audiocontext.currentTime;
6065      var rampTime = rampTime || 0;
6066      var tFromNow = tFromNow || 0;
6067      var currentFreq = this.oscillator.frequency.value;
6068      this.oscillator.frequency.cancelScheduledValues(now);
6069      this.oscillator.frequency.setValueAtTime(currentFreq, now + tFromNow);
6070      this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now);
6071      this.osc2.oscillator.frequency.cancelScheduledValues(now);
6072      this.osc2.oscillator.frequency.setValueAtTime(currentFreq, now + tFromNow);
6073      this.osc2.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now);
6074      if (this.freqMod) {
6075        this.freqMod.output.disconnect();
6076        this.freqMod = null;
6077      }
6078    } else if (val.output) {
6079      val.output.disconnect();
6080      val.output.connect(this.oscillator.frequency);
6081      val.output.connect(this.osc2.oscillator.frequency);
6082      this.freqMod = val;
6083    }
6084  };
6085  // inspiration: http://webaudiodemos.appspot.com/oscilloscope/
6086  function createDCOffset() {
6087    var ac = p5sound.audiocontext;
6088    var buffer = ac.createBuffer(1, 2048, ac.sampleRate);
6089    var data = buffer.getChannelData(0);
6090    for (var i = 0; i < 2048; i++)
6091      data[i] = 1;
6092    var bufferSource = ac.createBufferSource();
6093    bufferSource.buffer = buffer;
6094    bufferSource.loop = true;
6095    return bufferSource;
6096  }
6097}(master, oscillator);
6098var noise;
6099noise = function () {
6100  'use strict';
6101  var p5sound = master;
6102  /**
6103   *  Noise is a type of oscillator that generates a buffer with random values.
6104   *
6105   *  @class p5.Noise
6106   *  @constructor
6107   *  @param {String} type Type of noise can be 'white' (default),
6108   *                       'brown' or 'pink'.
6109   *  @return {Object}    Noise Object
6110   */
6111  p5.Noise = function (type) {
6112    p5.Oscillator.call(this);
6113    delete this.f;
6114    delete this.freq;
6115    delete this.oscillator;
6116    this.buffer = _whiteNoise;
6117  };
6118  p5.Noise.prototype = Object.create(p5.Oscillator.prototype);
6119  // generate noise buffers
6120  var _whiteNoise = function () {
6121    var bufferSize = 2 * p5sound.audiocontext.sampleRate;
6122    var whiteBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate);
6123    var noiseData = whiteBuffer.getChannelData(0);
6124    for (var i = 0; i < bufferSize; i++) {
6125      noiseData[i] = Math.random() * 2 - 1;
6126    }
6127    whiteBuffer.type = 'white';
6128    return whiteBuffer;
6129  }();
6130  var _pinkNoise = function () {
6131    var bufferSize = 2 * p5sound.audiocontext.sampleRate;
6132    var pinkBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate);
6133    var noiseData = pinkBuffer.getChannelData(0);
6134    var b0, b1, b2, b3, b4, b5, b6;
6135    b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0;
6136    for (var i = 0; i < bufferSize; i++) {
6137      var white = Math.random() * 2 - 1;
6138      b0 = 0.99886 * b0 + white * 0.0555179;
6139      b1 = 0.99332 * b1 + white * 0.0750759;
6140      b2 = 0.969 * b2 + white * 0.153852;
6141      b3 = 0.8665 * b3 + white * 0.3104856;
6142      b4 = 0.55 * b4 + white * 0.5329522;
6143      b5 = -0.7616 * b5 - white * 0.016898;
6144      noiseData[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
6145      noiseData[i] *= 0.11;
6146      // (roughly) compensate for gain
6147      b6 = white * 0.115926;
6148    }
6149    pinkBuffer.type = 'pink';
6150    return pinkBuffer;
6151  }();
6152  var _brownNoise = function () {
6153    var bufferSize = 2 * p5sound.audiocontext.sampleRate;
6154    var brownBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate);
6155    var noiseData = brownBuffer.getChannelData(0);
6156    var lastOut = 0;
6157    for (var i = 0; i < bufferSize; i++) {
6158      var white = Math.random() * 2 - 1;
6159      noiseData[i] = (lastOut + 0.02 * white) / 1.02;
6160      lastOut = noiseData[i];
6161      noiseData[i] *= 3.5;
6162    }
6163    brownBuffer.type = 'brown';
6164    return brownBuffer;
6165  }();
6166  /**
6167   *  Set type of noise to 'white', 'pink' or 'brown'.
6168   *  White is the default.
6169   *
6170   *  @method setType
6171   *  @param {String} [type] 'white', 'pink' or 'brown'
6172   */
6173  p5.Noise.prototype.setType = function (type) {
6174    switch (type) {
6175    case 'white':
6176      this.buffer = _whiteNoise;
6177      break;
6178    case 'pink':
6179      this.buffer = _pinkNoise;
6180      break;
6181    case 'brown':
6182      this.buffer = _brownNoise;
6183      break;
6184    default:
6185      this.buffer = _whiteNoise;
6186    }
6187    if (this.started) {
6188      var now = p5sound.audiocontext.currentTime;
6189      this.stop(now);
6190      this.start(now + 0.01);
6191    }
6192  };
6193  p5.Noise.prototype.getType = function () {
6194    return this.buffer.type;
6195  };
6196  /**
6197   *  Start the noise
6198   *
6199   *  @method start
6200   */
6201  p5.Noise.prototype.start = function () {
6202    if (this.started) {
6203      this.stop();
6204    }
6205    this.noise = p5sound.audiocontext.createBufferSource();
6206    this.noise.buffer = this.buffer;
6207    this.noise.loop = true;
6208    this.noise.connect(this.output);
6209    var now = p5sound.audiocontext.currentTime;
6210    this.noise.start(now);
6211    this.started = true;
6212  };
6213  /**
6214   *  Stop the noise.
6215   *
6216   *  @method  stop
6217   */
6218  p5.Noise.prototype.stop = function () {
6219    var now = p5sound.audiocontext.currentTime;
6220    if (this.noise) {
6221      this.noise.stop(now);
6222      this.started = false;
6223    }
6224  };
6225  /**
6226   *  Pan the noise.
6227   *
6228   *  @method  pan
6229   *  @param  {Number} panning Number between -1 (left)
6230   *                           and 1 (right)
6231   *  @param  {Number} timeFromNow schedule this event to happen
6232   *                                seconds from now
6233   */
6234  /**
6235   *  Set the amplitude of the noise between 0 and 1.0. Or,
6236   *  modulate amplitude with an audio signal such as an oscillator.
6237   *  
6238   *  @param  {Number|Object} volume amplitude between 0 and 1.0
6239   *                                     or modulating signal/oscillator
6240   *  @param {Number} [rampTime] create a fade that lasts rampTime 
6241   *  @param {Number} [timeFromNow] schedule this event to happen
6242   *                                seconds from now
6243   */
6244  /**
6245   *  Send output to a p5.sound or web audio object
6246   *  
6247   *  @method  connect
6248   *  @param  {Object} unit
6249   */
6250  /**
6251   *  Disconnect all output.
6252   *  
6253   *  @method disconnect
6254   */
6255  p5.Noise.prototype.dispose = function () {
6256    var now = p5sound.audiocontext.currentTime;
6257    // remove reference from soundArray
6258    var index = p5sound.soundArray.indexOf(this);
6259    p5sound.soundArray.splice(index, 1);
6260    if (this.noise) {
6261      this.noise.disconnect();
6262      this.stop(now);
6263    }
6264    if (this.output) {
6265      this.output.disconnect();
6266    }
6267    if (this.panner) {
6268      this.panner.disconnect();
6269    }
6270    this.output = null;
6271    this.panner = null;
6272    this.buffer = null;
6273    this.noise = null;
6274  };
6275}(master);
6276var audioin;
6277audioin = function () {
6278  'use strict';
6279  var p5sound = master;
6280  var CustomError = errorHandler;
6281  /**
6282   *  <p>Get audio from an input, i.e. your computer's microphone.</p>
6283   *
6284   *  <p>Turn the mic on/off with the start() and stop() methods. When the mic
6285   *  is on, its volume can be measured with getLevel or by connecting an
6286   *  FFT object.</p>
6287   *  
6288   *  <p>If you want to hear the AudioIn, use the .connect() method. 
6289   *  AudioIn does not connect to p5.sound output by default to prevent
6290   *  feedback.</p> 
6291   *
6292   *  <p><em>Note: This uses the <a href="http://caniuse.com/stream">getUserMedia/
6293   *  Stream</a> API, which is not supported by certain browsers.</em></p>
6294   *
6295   *  @class p5.AudioIn
6296   *  @constructor
6297   *  @return {Object} AudioIn
6298   *  @example
6299   *  <div><code>
6300   *  var mic;
6301   *  function setup(){
6302   *    mic = new p5.AudioIn()
6303   *    mic.start();
6304   *  }
6305   *  function draw(){
6306   *    background(0);
6307   *    micLevel = mic.getLevel();
6308   *    ellipse(width/2, constrain(height-micLevel*height*5, 0, height), 10, 10);
6309   *  }
6310   *  </code></div>
6311   */
6312  p5.AudioIn = function () {
6313    // set up audio input
6314    this.input = p5sound.audiocontext.createGain();
6315    this.output = p5sound.audiocontext.createGain();
6316    this.stream = null;
6317    this.mediaStream = null;
6318    this.currentSource = 0;
6319    /**
6320     *  Client must allow browser to access their microphone / audioin source.
6321     *  Default: false. Will become true when the client enables acces.
6322     *
6323     *  @property {Boolean} enabled
6324     */
6325    this.enabled = false;
6326    // create an amplitude, connect to it by default but not to master out
6327    this.amplitude = new p5.Amplitude();
6328    this.output.connect(this.amplitude.input);
6329    // Some browsers let developer determine their input sources
6330    if (typeof window.MediaStreamTrack === 'undefined') {
6331      window.alert('This browser does not support MediaStreamTrack');
6332    } else if (typeof window.MediaStreamTrack.getSources === 'function') {
6333      // Chrome supports getSources to list inputs. Dev picks default
6334      window.MediaStreamTrack.getSources(this._gotSources);
6335    } else {
6336    }
6337    // add to soundArray so we can dispose on close
6338    p5sound.soundArray.push(this);
6339  };
6340  /**
6341   *  Start processing audio input. This enables the use of other
6342   *  AudioIn methods like getLevel(). Note that by default, AudioIn
6343   *  is not connected to p5.sound's output. So you won't hear
6344   *  anything unless you use the connect() method.<br/>
6345   *
6346   *  @method start
6347   *  @param {Function} successCallback Name of a function to call on
6348   *                                    success.
6349   *  @param {Function} errorCallback Name of a function to call if
6350   *                                    there was an error. For example,
6351   *                                    some browsers do not support
6352   *                                    getUserMedia.
6353   */
6354  p5.AudioIn.prototype.start = function (successCallback, errorCallback) {
6355    var self = this;
6356    // if _gotSources() i.e. developers determine which source to use
6357    if (p5sound.inputSources[self.currentSource]) {
6358      // set the audio source
6359      var audioSource = p5sound.inputSources[self.currentSource].id;
6360      var constraints = { audio: { optional: [{ sourceId: audioSource }] } };
6361      window.navigator.getUserMedia(constraints, this._onStream = function (stream) {
6362        self.stream = stream;
6363        self.enabled = true;
6364        // Wrap a MediaStreamSourceNode around the live input
6365        self.mediaStream = p5sound.audiocontext.createMediaStreamSource(stream);
6366        self.mediaStream.connect(self.output);
6367        if (successCallback)
6368          successCallback();
6369        // only send to the Amplitude reader, so we can see it but not hear it.
6370        self.amplitude.setInput(self.output);
6371      }, this._onStreamError = function (e) {
6372        if (errorCallback)
6373          errorCallback(e);
6374        else
6375          console.error(e);
6376      });
6377    } else {
6378      // if Firefox where users select their source via browser
6379      // if (typeof MediaStreamTrack.getSources === 'undefined') {
6380      // Only get the audio stream.
6381      window.navigator.getUserMedia({ 'audio': true }, this._onStream = function (stream) {
6382        self.stream = stream;
6383        self.enabled = true;
6384        // Wrap a MediaStreamSourceNode around the live input
6385        self.mediaStream = p5sound.audiocontext.createMediaStreamSource(stream);
6386        self.mediaStream.connect(self.output);
6387        // only send to the Amplitude reader, so we can see it but not hear it.
6388        self.amplitude.setInput(self.output);
6389        if (successCallback)
6390          successCallback();
6391      }, this._onStreamError = function (e) {
6392        if (errorCallback)
6393          errorCallback(e);
6394        else
6395          console.error(e);
6396      });
6397    }
6398  };
6399  /**
6400   *  Turn the AudioIn off. If the AudioIn is stopped, it cannot getLevel().<br/>
6401   *
6402   *  @method stop
6403   */
6404  p5.AudioIn.prototype.stop = function () {
6405    if (this.stream) {
6406      this.stream.stop();
6407    }
6408  };
6409  /**
6410   *  Connect to an audio unit. If no parameter is provided, will
6411   *  connect to the master output (i.e. your speakers).<br/>
6412   *  
6413   *  @method  connect
6414   *  @param  {Object} [unit] An object that accepts audio input,
6415   *                          such as an FFT
6416   */
6417  p5.AudioIn.prototype.connect = function (unit) {
6418    if (unit) {
6419      if (unit.hasOwnProperty('input')) {
6420        this.output.connect(unit.input);
6421      } else if (unit.hasOwnProperty('analyser')) {
6422        this.output.connect(unit.analyser);
6423      } else {
6424        this.output.connect(unit);
6425      }
6426    } else {
6427      this.output.connect(p5sound.input);
6428    }
6429  };
6430  /**
6431   *  Disconnect the AudioIn from all audio units. For example, if
6432   *  connect() had been called, disconnect() will stop sending 
6433   *  signal to your speakers.<br/>
6434   *
6435   *  @method  disconnect
6436   */
6437  p5.AudioIn.prototype.disconnect = function (unit) {
6438    this.output.disconnect(unit);
6439    // stay connected to amplitude even if not outputting to p5
6440    this.output.connect(this.amplitude.input);
6441  };
6442  /**
6443   *  Read the Amplitude (volume level) of an AudioIn. The AudioIn
6444   *  class contains its own instance of the Amplitude class to help
6445   *  make it easy to get a microphone's volume level. Accepts an
6446   *  optional smoothing value (0.0 < 1.0). <em>NOTE: AudioIn must
6447   *  .start() before using .getLevel().</em><br/>
6448   *  
6449   *  @method  getLevel
6450   *  @param  {Number} [smoothing] Smoothing is 0.0 by default.
6451   *                               Smooths values based on previous values.
6452   *  @return {Number}           Volume level (between 0.0 and 1.0)
6453   */
6454  p5.AudioIn.prototype.getLevel = function (smoothing) {
6455    if (smoothing) {
6456      this.amplitude.smoothing = smoothing;
6457    }
6458    return this.amplitude.getLevel();
6459  };
6460  /**
6461   *  Add input sources to the list of available sources.
6462   *  
6463   *  @private
6464   */
6465  p5.AudioIn.prototype._gotSources = function (sourceInfos) {
6466    for (var i = 0; i < sourceInfos.length; i++) {
6467      var sourceInfo = sourceInfos[i];
6468      if (sourceInfo.kind === 'audio') {
6469        // add the inputs to inputSources
6470        //p5sound.inputSources.push(sourceInfo);
6471        return sourceInfo;
6472      }
6473    }
6474  };
6475  /**
6476   *  Set amplitude (volume) of a mic input between 0 and 1.0. <br/>
6477   *
6478   *  @method  amp
6479   *  @param  {Number} vol between 0 and 1.0
6480   *  @param {Number} [time] ramp time (optional)
6481   */
6482  p5.AudioIn.prototype.amp = function (vol, t) {
6483    if (t) {
6484      var rampTime = t || 0;
6485      var currentVol = this.output.gain.value;
6486      this.output.gain.cancelScheduledValues(p5sound.audiocontext.currentTime);
6487      this.output.gain.setValueAtTime(currentVol, p5sound.audiocontext.currentTime);
6488      this.output.gain.linearRampToValueAtTime(vol, rampTime + p5sound.audiocontext.currentTime);
6489    } else {
6490      this.output.gain.cancelScheduledValues(p5sound.audiocontext.currentTime);
6491      this.output.gain.setValueAtTime(vol, p5sound.audiocontext.currentTime);
6492    }
6493  };
6494  p5.AudioIn.prototype.listSources = function () {
6495    console.log('listSources is deprecated - please use AudioIn.getSources');
6496    console.log('input sources: ');
6497    if (p5sound.inputSources.length > 0) {
6498      return p5sound.inputSources;
6499    } else {
6500      return 'This browser does not support MediaStreamTrack.getSources()';
6501    }
6502  };
6503  /**
6504   * Chrome only. Returns a list of available input sources 
6505   * and allows the user to set the media source. Firefox allows 
6506   * the user to choose from input sources in the permissions dialogue
6507   * instead of enumerating available sources and selecting one.
6508   * Note: in order to have descriptive media names your page must be 
6509   * served over a secure (HTTPS) connection and the page should 
6510   * request user media before enumerating devices. Otherwise device 
6511   * ID will be a long device ID number and does not specify device 
6512   * type. For example see 
6513   * https://simpl.info/getusermedia/sources/index.html vs.
6514   * http://simpl.info/getusermedia/sources/index.html
6515   *
6516   * @method  getSources
6517   * @param  {Function} callback a callback to handle the sources 
6518   *                               when they have been enumerated
6519   * @example
6520   *  <div><code>
6521   *  var audiograb;
6522   *      
6523   *  function setup(){
6524   *    //new audioIn
6525   *    audioGrab = new p5.AudioIn();
6526   *    
6527   *    audioGrab.getSources(function(sourceList) {
6528   *      //print out the array of available sources
6529   *      console.log(sourceList);
6530   *      //set the source to the first item in the inputSources array
6531   *      audioGrab.setSource(0);
6532   *    });
6533   *  }
6534   *  </code></div>
6535   */
6536  p5.AudioIn.prototype.getSources = function (callback) {
6537    if (typeof window.MediaStreamTrack.getSources === 'function') {
6538      window.MediaStreamTrack.getSources(function (data) {
6539        for (var i = 0, max = data.length; i < max; i++) {
6540          var sourceInfo = data[i];
6541          if (sourceInfo.kind === 'audio') {
6542            // add the inputs to inputSources
6543            p5sound.inputSources.push(sourceInfo);
6544          }
6545        }
6546        callback(p5sound.inputSources);
6547      });
6548    } else {
6549      console.log('This browser does not support MediaStreamTrack.getSources()');
6550    }
6551  };
6552  /**
6553   *  Set the input source. Accepts a number representing a
6554   *  position in the array returned by listSources().
6555   *  This is only available in browsers that support 
6556   *  MediaStreamTrack.getSources(). Instead, some browsers
6557   *  give users the option to set their own media source.<br/>
6558   *  
6559   *  @method setSource
6560   *  @param {number} num position of input source in the array
6561   */
6562  p5.AudioIn.prototype.setSource = function (num) {
6563    // TO DO - set input by string or # (array position)
6564    var self = this;
6565    if (p5sound.inputSources.length > 0 && num < p5sound.inputSources.length) {
6566      // set the current source
6567      self.currentSource = num;
6568      console.log('set source to ' + p5sound.inputSources[self.currentSource].id);
6569    } else {
6570      console.log('unable to set input source');
6571    }
6572  };
6573  // private method
6574  p5.AudioIn.prototype.dispose = function () {
6575    // remove reference from soundArray
6576    var index = p5sound.soundArray.indexOf(this);
6577    p5sound.soundArray.splice(index, 1);
6578    this.stop();
6579    if (this.output) {
6580      this.output.disconnect();
6581    }
6582    if (this.amplitude) {
6583      this.amplitude.disconnect();
6584    }
6585    this.amplitude = null;
6586    this.output = null;
6587  };
6588}(master, errorHandler);
6589var filter;
6590filter = function () {
6591  'use strict';
6592  var p5sound = master;
6593  /**
6594   *  A p5.Filter uses a Web Audio Biquad Filter to filter
6595   *  the frequency response of an input source. Inheriting
6596   *  classes include:<br/>
6597   *  * <code>p5.LowPass</code> - allows frequencies below
6598   *  the cutoff frequency to pass through, and attenuates
6599   *  frequencies above the cutoff.<br/>
6600   *  * <code>p5.HighPass</code> - the opposite of a lowpass
6601   *  filter. <br/>
6602   *  * <code>p5.BandPass</code> -  allows a range of
6603   *  frequencies to pass through and attenuates the frequencies
6604   *  below and above this frequency range.<br/>
6605   *
6606   *  The <code>.res()</code> method controls either width of the
6607   *  bandpass, or resonance of the low/highpass cutoff frequency.
6608   *
6609   *  @class p5.Filter
6610   *  @constructor
6611   *  @param {[String]} type 'lowpass' (default), 'highpass', 'bandpass'
6612   *  @return {Object} p5.Filter
6613   *  @example
6614   *  <div><code>
6615   *  var fft, noise, filter;
6616   *
6617   *  function setup() {
6618   *    fill(255, 40, 255);
6619   *
6620   *    filter = new p5.BandPass();
6621   *
6622   *    noise = new p5.Noise();
6623   *    // disconnect unfiltered noise,
6624   *    // and connect to filter
6625   *    noise.disconnect();
6626   *    noise.connect(filter);
6627   *    noise.start();
6628   *
6629   *    fft = new p5.FFT();
6630   *  }
6631   *
6632   *  function draw() {
6633   *    background(30);
6634   *
6635   *    // set the BandPass frequency based on mouseX
6636   *    var freq = map(mouseX, 0, width, 20, 10000);
6637   *    filter.freq(freq);
6638   *    // give the filter a narrow band (lower res = wider bandpass)
6639   *    filter.res(50);
6640   *
6641   *    // draw filtered spectrum
6642   *    var spectrum = fft.analyze();
6643   *    noStroke();
6644   *    for (var i = 0; i < spectrum.length; i++) {
6645   *      var x = map(i, 0, spectrum.length, 0, width);
6646   *      var h = -height + map(spectrum[i], 0, 255, height, 0);
6647   *      rect(x, height, width/spectrum.length, h);
6648   *    }
6649   *    
6650   *    isMouseOverCanvas();
6651   *  }
6652   *
6653   *  function isMouseOverCanvas() {
6654   *    var mX = mouseX, mY = mouseY;
6655   *    if (mX > 0 && mX < width && mY < height && mY > 0) {
6656   *      noise.amp(0.5, 0.2);
6657   *    } else {
6658   *      noise.amp(0, 0.2);
6659   *    }
6660   *  }
6661   *  </code></div>
6662   */
6663  p5.Filter = function (type) {
6664    this.ac = p5sound.audiocontext;
6665    this.input = this.ac.createGain();
6666    this.output = this.ac.createGain();
6667    /**
6668     *  The p5.Filter is built with a
6669     *  <a href="http://www.w3.org/TR/webaudio/#BiquadFilterNode">
6670     *  Web Audio BiquadFilter Node</a>.
6671     *  
6672     *  @property biquadFilter
6673     *  @type {Object}  Web Audio Delay Node
6674     */
6675    this.biquad = this.ac.createBiquadFilter();
6676    this.input.connect(this.biquad);
6677    this.biquad.connect(this.output);
6678    this.connect();
6679    if (type) {
6680      this.setType(type);
6681    }
6682    // add to the soundArray
6683    p5sound.soundArray.push(this);
6684  };
6685  /**
6686   *  Filter an audio signal according to a set
6687   *  of filter parameters.
6688   *  
6689   *  @method  process
6690   *  @param  {Object} Signal  An object that outputs audio
6691   *  @param {[Number]} freq Frequency in Hz, from 10 to 22050
6692   *  @param {[Number]} res Resonance/Width of the filter frequency
6693   *                        from 0.001 to 1000
6694   */
6695  p5.Filter.prototype.process = function (src, freq, res) {
6696    src.connect(this.input);
6697    this.set(freq, res);
6698  };
6699  /**
6700   *  Set the frequency and the resonance of the filter.
6701   *
6702   *  @method  set
6703   *  @param {Number} freq Frequency in Hz, from 10 to 22050
6704   *  @param {Number} res  Resonance (Q) from 0.001 to 1000
6705   *  @param {Number} [timeFromNow] schedule this event to happen
6706   *                                seconds from now
6707   */
6708  p5.Filter.prototype.set = function (freq, res, time) {
6709    if (freq) {
6710      this.freq(freq, time);
6711    }
6712    if (res) {
6713      this.res(res, time);
6714    }
6715  };
6716  /**
6717   *  Set the filter frequency, in Hz, from 10 to 22050 (the range of
6718   *  human hearing, although in reality most people hear in a narrower
6719   *  range).
6720   *
6721   *  @method  freq
6722   *  @param  {Number} freq Filter Frequency
6723   *  @param {Number} [timeFromNow] schedule this event to happen
6724   *                                seconds from now
6725   *  @return {Number} value  Returns the current frequency value
6726   */
6727  p5.Filter.prototype.freq = function (freq, time) {
6728    var self = this;
6729    var t = time || 0;
6730    if (freq <= 0) {
6731      freq = 1;
6732    }
6733    if (typeof freq === 'number') {
6734      self.biquad.frequency.value = freq;
6735      self.biquad.frequency.cancelScheduledValues(this.ac.currentTime + 0.01 + t);
6736      self.biquad.frequency.exponentialRampToValueAtTime(freq, this.ac.currentTime + 0.02 + t);
6737    } else if (freq) {
6738      freq.connect(this.biquad.frequency);
6739    }
6740    return self.biquad.frequency.value;
6741  };
6742  /**
6743   *  Controls either width of a bandpass frequency,
6744   *  or the resonance of a low/highpass cutoff frequency.
6745   *
6746   *  @method  res
6747   *  @param {Number} res  Resonance/Width of filter freq
6748   *                       from 0.001 to 1000
6749   *  @param {Number} [timeFromNow] schedule this event to happen
6750   *                                seconds from now
6751   *  @return {Number} value Returns the current res value
6752   */
6753  p5.Filter.prototype.res = function (res, time) {
6754    var self = this;
6755    var t = time || 0;
6756    if (typeof res == 'number') {
6757      self.biquad.Q.value = res;
6758      self.biquad.Q.cancelScheduledValues(self.ac.currentTime + 0.01 + t);
6759      self.biquad.Q.linearRampToValueAtTime(res, self.ac.currentTime + 0.02 + t);
6760    } else if (res) {
6761      freq.connect(this.biquad.Q);
6762    }
6763    return self.biquad.Q.value;
6764  };
6765  /**
6766   *  Set the type of a p5.Filter. Possible types include: 
6767   *  "lowpass" (default), "highpass", "bandpass", 
6768   *  "lowshelf", "highshelf", "peaking", "notch",
6769   *  "allpass". 
6770   *  
6771   *  @method  setType
6772   *  @param {String}
6773   */
6774  p5.Filter.prototype.setType = function (t) {
6775    this.biquad.type = t;
6776  };
6777  /**
6778   *  Set the output level of the filter.
6779   *  
6780   *  @method  amp
6781   *  @param {Number} volume amplitude between 0 and 1.0
6782   *  @param {Number} [rampTime] create a fade that lasts rampTime 
6783   *  @param {Number} [timeFromNow] schedule this event to happen
6784   *                                seconds from now
6785   */
6786  p5.Filter.prototype.amp = function (vol, rampTime, tFromNow) {
6787    var rampTime = rampTime || 0;
6788    var tFromNow = tFromNow || 0;
6789    var now = p5sound.audiocontext.currentTime;
6790    var currentVol = this.output.gain.value;
6791    this.output.gain.cancelScheduledValues(now);
6792    this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow + 0.001);
6793    this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime + 0.001);
6794  };
6795  /**
6796   *  Send output to a p5.sound or web audio object
6797   *  
6798   *  @method connect
6799   *  @param  {Object} unit
6800   */
6801  p5.Filter.prototype.connect = function (unit) {
6802    var u = unit || p5.soundOut.input;
6803    this.output.connect(u);
6804  };
6805  /**
6806   *  Disconnect all output.
6807   *  
6808   *  @method disconnect
6809   */
6810  p5.Filter.prototype.disconnect = function () {
6811    this.output.disconnect();
6812  };
6813  p5.Filter.prototype.dispose = function () {
6814    // remove reference from soundArray
6815    var index = p5sound.soundArray.indexOf(this);
6816    p5sound.soundArray.splice(index, 1);
6817    this.input.disconnect();
6818    this.input = undefined;
6819    this.output.disconnect();
6820    this.output = undefined;
6821    this.biquad.disconnect();
6822    this.biquad = undefined;
6823  };
6824  /**
6825   *  Constructor: <code>new p5.LowPass()</code> Filter.
6826   *  This is the same as creating a p5.Filter and then calling
6827   *  its method <code>setType('lowpass')</code>.
6828   *  See p5.Filter for methods.
6829   *  
6830   *  @method p5.LowPass
6831   */
6832  p5.LowPass = function () {
6833    p5.Filter.call(this, 'lowpass');
6834  };
6835  p5.LowPass.prototype = Object.create(p5.Filter.prototype);
6836  /**
6837   *  Constructor: <code>new p5.HighPass()</code> Filter.
6838   *  This is the same as creating a p5.Filter and then calling
6839   *  its method <code>setType('highpass')</code>.
6840   *  See p5.Filter for methods.
6841   *  
6842   *  @method p5.HighPass
6843   */
6844  p5.HighPass = function () {
6845    p5.Filter.call(this, 'highpass');
6846  };
6847  p5.HighPass.prototype = Object.create(p5.Filter.prototype);
6848  /**
6849   *  Constructor: <code>new p5.BandPass()</code> Filter.
6850   *  This is the same as creating a p5.Filter and then calling
6851   *  its method <code>setType('bandpass')</code>.
6852   *  See p5.Filter for methods. 
6853   *  
6854   *  @method p5.BandPass
6855   */
6856  p5.BandPass = function () {
6857    p5.Filter.call(this, 'bandpass');
6858  };
6859  p5.BandPass.prototype = Object.create(p5.Filter.prototype);
6860}(master);
6861var delay;
6862delay = function () {
6863  'use strict';
6864  var p5sound = master;
6865  var Filter = filter;
6866  /**
6867   *  Delay is an echo effect. It processes an existing sound source,
6868   *  and outputs a delayed version of that sound. The p5.Delay can
6869   *  produce different effects depending on the delayTime, feedback,
6870   *  filter, and type. In the example below, a feedback of 0.5 will
6871   *  produce a looping delay that decreases in volume by
6872   *  50% each repeat. A filter will cut out the high frequencies so
6873   *  that the delay does not sound as piercing as the original source.
6874   *  
6875   *  @class p5.Delay
6876   *  @constructor
6877   *  @return {Object} Returns a p5.Delay object
6878   *  @example
6879   *  <div><code>
6880   *  var noise, env, delay;
6881   *  
6882   *  function setup() {
6883   *    background(0);
6884   *    noStroke();
6885   *    fill(255);
6886   *    textAlign(CENTER);
6887   *    text('click to play', width/2, height/2);
6888   *    
6889   *    noise = new p5.Noise('brown');
6890   *    noise.amp(0);
6891   *    noise.start();
6892   *    
6893   *    delay = new p5.Delay();
6894   *
6895   *    // delay.process() accepts 4 parameters:
6896   *    // source, delayTime, feedback, filter frequency
6897   *    // play with these numbers!!
6898   *    delay.process(noise, .12, .7, 2300);
6899   *    
6900   *    // play the noise with an envelope,
6901   *    // a series of fades ( time / value pairs )
6902   *    env = new p5.Env(.01, 0.2, .2, .1);
6903   *  }
6904   *
6905   *  // mouseClick triggers envelope
6906   *  function mouseClicked() {
6907   *    // is mouse over canvas?
6908   *    if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
6909   *      env.play(noise);
6910   *    }
6911   *  }
6912   *  </code></div>
6913   */
6914  p5.Delay = function () {
6915    this.ac = p5sound.audiocontext;
6916    this.input = this.ac.createGain();
6917    this.output = this.ac.createGain();
6918    this._split = this.ac.createChannelSplitter(2);
6919    this._merge = this.ac.createChannelMerger(2);
6920    this._leftGain = this.ac.createGain();
6921    this._rightGain = this.ac.createGain();
6922    /**
6923     *  The p5.Delay is built with two
6924     *  <a href="http://www.w3.org/TR/webaudio/#DelayNode">
6925     *  Web Audio Delay Nodes</a>, one for each stereo channel.
6926     *  
6927     *  @property leftDelay
6928     *  @type {Object}  Web Audio Delay Node
6929     */
6930    this.leftDelay = this.ac.createDelay();
6931    /**
6932     *  The p5.Delay is built with two
6933     *  <a href="http://www.w3.org/TR/webaudio/#DelayNode">
6934     *  Web Audio Delay Nodes</a>, one for each stereo channel.
6935     *  
6936     *  @property rightDelay
6937     *  @type {Object}  Web Audio Delay Node
6938     */
6939    this.rightDelay = this.ac.createDelay();
6940    this._leftFilter = new p5.Filter();
6941    this._rightFilter = new p5.Filter();
6942    this._leftFilter.disconnect();
6943    this._rightFilter.disconnect();
6944    this._leftFilter.biquad.frequency.setValueAtTime(1200, this.ac.currentTime);
6945    this._rightFilter.biquad.frequency.setValueAtTime(1200, this.ac.currentTime);
6946    this._leftFilter.biquad.Q.setValueAtTime(0.3, this.ac.currentTime);
6947    this._rightFilter.biquad.Q.setValueAtTime(0.3, this.ac.currentTime);
6948    // graph routing
6949    this.input.connect(this._split);
6950    this.leftDelay.connect(this._leftGain);
6951    this.rightDelay.connect(this._rightGain);
6952    this._leftGain.connect(this._leftFilter.input);
6953    this._rightGain.connect(this._rightFilter.input);
6954    this._merge.connect(this.output);
6955    this.output.connect(p5.soundOut.input);
6956    this._leftFilter.biquad.gain.setValueAtTime(1, this.ac.currentTime);
6957    this._rightFilter.biquad.gain.setValueAtTime(1, this.ac.currentTime);
6958    // default routing
6959    this.setType(0);
6960    this._maxDelay = this.leftDelay.delayTime.maxValue;
6961    // add this p5.SoundFile to the soundArray
6962    p5sound.soundArray.push(this);
6963  };
6964  /**
6965   *  Add delay to an audio signal according to a set
6966   *  of delay parameters.
6967   *  
6968   *  @method  process
6969   *  @param  {Object} Signal  An object that outputs audio
6970   *  @param  {Number} [delayTime] Time (in seconds) of the delay/echo.
6971   *                               Some browsers limit delayTime to
6972   *                               1 second.
6973   *  @param  {Number} [feedback]  sends the delay back through itself
6974   *                               in a loop that decreases in volume
6975   *                               each time.
6976   *  @param  {Number} [lowPass]   Cutoff frequency. Only frequencies
6977   *                               below the lowPass will be part of the
6978   *                               delay.
6979   */
6980  p5.Delay.prototype.process = function (src, _delayTime, _feedback, _filter) {
6981    var feedback = _feedback || 0;
6982    var delayTime = _delayTime || 0;
6983    if (feedback >= 1) {
6984      throw new Error('Feedback value will force a positive feedback loop.');
6985    }
6986    if (delayTime >= this._maxDelay) {
6987      throw new Error('Delay Time exceeds maximum delay time of ' + this._maxDelay + ' second.');
6988    }
6989    src.connect(this.input);
6990    this.leftDelay.delayTime.setValueAtTime(delayTime, this.ac.currentTime);
6991    this.rightDelay.delayTime.setValueAtTime(delayTime, this.ac.currentTime);
6992    this._leftGain.gain.setValueAtTime(feedback, this.ac.currentTime);
6993    this._rightGain.gain.setValueAtTime(feedback, this.ac.currentTime);
6994    if (_filter) {
6995      this._leftFilter.freq(_filter);
6996      this._rightFilter.freq(_filter);
6997    }
6998  };
6999  /**
7000   *  Set the delay (echo) time, in seconds. Usually this value will be
7001   *  a floating point number between 0.0 and 1.0.
7002   *
7003   *  @method  delayTime
7004   *  @param {Number} delayTime Time (in seconds) of the delay
7005   */
7006  p5.Delay.prototype.delayTime = function (t) {
7007    // if t is an audio node...
7008    if (typeof t !== 'number') {
7009      t.connect(this.leftDelay.delayTime);
7010      t.connect(this.rightDelay.delayTime);
7011    } else {
7012      this.leftDelay.delayTime.cancelScheduledValues(this.ac.currentTime);
7013      this.rightDelay.delayTime.cancelScheduledValues(this.ac.currentTime);
7014      this.leftDelay.delayTime.linearRampToValueAtTime(t, this.ac.currentTime);
7015      this.rightDelay.delayTime.linearRampToValueAtTime(t, this.ac.currentTime);
7016    }
7017  };
7018  /**
7019   *  Feedback occurs when Delay sends its signal back through its input
7020   *  in a loop. The feedback amount determines how much signal to send each
7021   *  time through the loop. A feedback greater than 1.0 is not desirable because
7022   *  it will increase the overall output each time through the loop,
7023   *  creating an infinite feedback loop.
7024   *  
7025   *  @method  feedback
7026   *  @param {Number|Object} feedback 0.0 to 1.0, or an object such as an
7027   *                                  Oscillator that can be used to
7028   *                                  modulate this param
7029   */
7030  p5.Delay.prototype.feedback = function (f) {
7031    // if f is an audio node...
7032    if (typeof f !== 'number') {
7033      f.connect(this._leftGain.gain);
7034      f.connect(this._rightGain.gain);
7035    } else if (f >= 1) {
7036      throw new Error('Feedback value will force a positive feedback loop.');
7037    } else {
7038      this._leftGain.gain.exponentialRampToValueAtTime(f, this.ac.currentTime);
7039      this._rightGain.gain.exponentialRampToValueAtTime(f, this.ac.currentTime);
7040    }
7041  };
7042  /**
7043   *  Set a lowpass filter frequency for the delay. A lowpass filter
7044   *  will cut off any frequencies higher than the filter frequency.
7045   *   
7046   *  @method  filter
7047   *  @param {Number|Object} cutoffFreq  A lowpass filter will cut off any 
7048   *                              frequencies higher than the filter frequency.
7049   *  @param {Number|Object} res  Resonance of the filter frequency
7050   *                              cutoff, or an object (i.e. a p5.Oscillator)
7051   *                              that can be used to modulate this parameter.
7052   *                              High numbers (i.e. 15) will produce a resonance,
7053   *                              low numbers (i.e. .2) will produce a slope.
7054   */
7055  p5.Delay.prototype.filter = function (freq, q) {
7056    this._leftFilter.set(freq, q);
7057    this._rightFilter.set(freq, q);
7058  };
7059  /**
7060   *  Choose a preset type of delay. 'pingPong' bounces the signal
7061   *  from the left to the right channel to produce a stereo effect.
7062   *  Any other parameter will revert to the default delay setting.
7063   *  
7064   *  @method  setType
7065   *  @param {String|Number} type 'pingPong' (1) or 'default' (0)
7066   */
7067  p5.Delay.prototype.setType = function (t) {
7068    if (t === 1) {
7069      t = 'pingPong';
7070    }
7071    this._split.disconnect();
7072    this._leftFilter.disconnect();
7073    this._rightFilter.disconnect();
7074    this._split.connect(this.leftDelay, 0);
7075    this._split.connect(this.rightDelay, 1);
7076    switch (t) {
7077    case 'pingPong':
7078      this._rightFilter.setType(this._leftFilter.biquad.type);
7079      this._leftFilter.output.connect(this._merge, 0, 0);
7080      this._rightFilter.output.connect(this._merge, 0, 1);
7081      this._leftFilter.output.connect(this.rightDelay);
7082      this._rightFilter.output.connect(this.leftDelay);
7083      break;
7084    default:
7085      this._leftFilter.output.connect(this._merge, 0, 0);
7086      this._leftFilter.output.connect(this._merge, 0, 1);
7087      this._leftFilter.output.connect(this.leftDelay);
7088      this._leftFilter.output.connect(this.rightDelay);
7089    }
7090  };
7091  /**
7092   *  Set the output level of the delay effect.
7093   *  
7094   *  @method  amp
7095   *  @param  {Number} volume amplitude between 0 and 1.0
7096   *  @param {Number} [rampTime] create a fade that lasts rampTime 
7097   *  @param {Number} [timeFromNow] schedule this event to happen
7098   *                                seconds from now
7099   */
7100  p5.Delay.prototype.amp = function (vol, rampTime, tFromNow) {
7101    var rampTime = rampTime || 0;
7102    var tFromNow = tFromNow || 0;
7103    var now = p5sound.audiocontext.currentTime;
7104    var currentVol = this.output.gain.value;
7105    this.output.gain.cancelScheduledValues(now);
7106    this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow + 0.001);
7107    this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime + 0.001);
7108  };
7109  /**
7110   *  Send output to a p5.sound or web audio object
7111   *  
7112   *  @method  connect
7113   *  @param  {Object} unit
7114   */
7115  p5.Delay.prototype.connect = function (unit) {
7116    var u = unit || p5.soundOut.input;
7117    this.output.connect(u);
7118  };
7119  /**
7120   *  Disconnect all output.
7121   *  
7122   *  @method disconnect
7123   */
7124  p5.Delay.prototype.disconnect = function () {
7125    this.output.disconnect();
7126  };
7127  p5.Delay.prototype.dispose = function () {
7128    // remove reference from soundArray
7129    var index = p5sound.soundArray.indexOf(this);
7130    p5sound.soundArray.splice(index, 1);
7131    this.input.disconnect();
7132    this.output.disconnect();
7133    this._split.disconnect();
7134    this._leftFilter.disconnect();
7135    this._rightFilter.disconnect();
7136    this._merge.disconnect();
7137    this._leftGain.disconnect();
7138    this._rightGain.disconnect();
7139    this.leftDelay.disconnect();
7140    this.rightDelay.disconnect();
7141    this.input = undefined;
7142    this.output = undefined;
7143    this._split = undefined;
7144    this._leftFilter = undefined;
7145    this._rightFilter = undefined;
7146    this._merge = undefined;
7147    this._leftGain = undefined;
7148    this._rightGain = undefined;
7149    this.leftDelay = undefined;
7150    this.rightDelay = undefined;
7151  };
7152}(master, filter);
7153var reverb;
7154reverb = function () {
7155  'use strict';
7156  var p5sound = master;
7157  var CustomError = errorHandler;
7158  /**
7159   *  Reverb adds depth to a sound through a large number of decaying
7160   *  echoes. It creates the perception that sound is occurring in a
7161   *  physical space. The p5.Reverb has paramters for Time (how long does the
7162   *  reverb last) and decayRate (how much the sound decays with each echo)
7163   *  that can be set with the .set() or .process() methods. The p5.Convolver
7164   *  extends p5.Reverb allowing you to recreate the sound of actual physical
7165   *  spaces through convolution.
7166   *  
7167   *  @class p5.Reverb
7168   *  @constructor
7169   *  @example
7170   *  <div><code>
7171   *  var soundFile, reverb;
7172   *  function preload() {
7173   *    soundFile = loadSound('assets/Damscray_DancingTiger.mp3');
7174   *  }
7175   *
7176   *  function setup() {
7177   *    reverb = new p5.Reverb();
7178   *    soundFile.disconnect(); // so we'll only hear reverb...
7179   *
7180   *    // connect soundFile to reverb, process w/
7181   *    // 3 second reverbTime, decayRate of 2%
7182   *    reverb.process(soundFile, 3, 2);
7183   *    soundFile.play();
7184   *  }
7185   *  </code></div>
7186   */
7187  p5.Reverb = function () {
7188    this.ac = p5sound.audiocontext;
7189    this.convolverNode = this.ac.createConvolver();
7190    this.input = this.ac.createGain();
7191    this.output = this.ac.createGain();
7192    // otherwise, Safari distorts
7193    this.input.gain.value = 0.5;
7194    this.input.connect(this.convolverNode);
7195    this.convolverNode.connect(this.output);
7196    // default params
7197    this._seconds = 3;
7198    this._decay = 2;
7199    this._reverse = false;
7200    this._buildImpulse();
7201    this.connect();
7202    p5sound.soundArray.push(this);
7203  };
7204  /**
7205   *  Connect a source to the reverb, and assign reverb parameters.
7206   *  
7207   *  @method  process
7208   *  @param  {Object} src     p5.sound / Web Audio object with a sound
7209   *                           output.
7210   *  @param  {Number} [seconds] Duration of the reverb, in seconds.
7211   *                           Min: 0, Max: 10. Defaults to 3.
7212   *  @param  {Number} [decayRate] Percentage of decay with each echo.
7213   *                            Min: 0, Max: 100. Defaults to 2.
7214   *  @param  {Boolean} [reverse] Play the reverb backwards or forwards.
7215   */
7216  p5.Reverb.prototype.process = function (src, seconds, decayRate, reverse) {
7217    src.connect(this.input);
7218    var rebuild = false;
7219    if (seconds) {
7220      this._seconds = seconds;
7221      rebuild = true;
7222    }
7223    if (decayRate) {
7224      this._decay = decayRate;
7225    }
7226    if (reverse) {
7227      this._reverse = reverse;
7228    }
7229    if (rebuild) {
7230      this._buildImpulse();
7231    }
7232  };
7233  /**
7234   *  Set the reverb settings. Similar to .process(), but without
7235   *  assigning a new input.
7236   *  
7237   *  @method  set
7238   *  @param  {Number} [seconds] Duration of the reverb, in seconds.
7239   *                           Min: 0, Max: 10. Defaults to 3.
7240   *  @param  {Number} [decayRate] Percentage of decay with each echo.
7241   *                            Min: 0, Max: 100. Defaults to 2.
7242   *  @param  {Boolean} [reverse] Play the reverb backwards or forwards.
7243   */
7244  p5.Reverb.prototype.set = function (seconds, decayRate, reverse) {
7245    var rebuild = false;
7246    if (seconds) {
7247      this._seconds = seconds;
7248      rebuild = true;
7249    }
7250    if (decayRate) {
7251      this._decay = decayRate;
7252    }
7253    if (reverse) {
7254      this._reverse = reverse;
7255    }
7256    if (rebuild) {
7257      this._buildImpulse();
7258    }
7259  };
7260  /**
7261   *  Set the output level of the delay effect.
7262   *  
7263   *  @method  amp
7264   *  @param  {Number} volume amplitude between 0 and 1.0
7265   *  @param  {Number} [rampTime] create a fade that lasts rampTime 
7266   *  @param  {Number} [timeFromNow] schedule this event to happen
7267   *                                seconds from now
7268   */
7269  p5.Reverb.prototype.amp = function (vol, rampTime, tFromNow) {
7270    var rampTime = rampTime || 0;
7271    var tFromNow = tFromNow || 0;
7272    var now = p5sound.audiocontext.currentTime;
7273    var currentVol = this.output.gain.value;
7274    this.output.gain.cancelScheduledValues(now);
7275    this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow + 0.001);
7276    this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime + 0.001);
7277  };
7278  /**
7279   *  Send output to a p5.sound or web audio object
7280   *  
7281   *  @method  connect
7282   *  @param  {Object} unit
7283   */
7284  p5.Reverb.prototype.connect = function (unit) {
7285    var u = unit || p5.soundOut.input;
7286    this.output.connect(u.input ? u.input : u);
7287  };
7288  /**
7289   *  Disconnect all output.
7290   *  
7291   *  @method disconnect
7292   */
7293  p5.Reverb.prototype.disconnect = function () {
7294    this.output.disconnect();
7295  };
7296  /**
7297   *  Inspired by Simple Reverb by Jordan Santell
7298   *  https://github.com/web-audio-components/simple-reverb/blob/master/index.js
7299   * 
7300   *  Utility function for building an impulse response
7301   *  based on the module parameters.
7302   *
7303   *  @private
7304   */
7305  p5.Reverb.prototype._buildImpulse = function () {
7306    var rate = this.ac.sampleRate;
7307    var length = rate * this._seconds;
7308    var decay = this._decay;
7309    var impulse = this.ac.createBuffer(2, length, rate);
7310    var impulseL = impulse.getChannelData(0);
7311    var impulseR = impulse.getChannelData(1);
7312    var n, i;
7313    for (i = 0; i < length; i++) {
7314      n = this.reverse ? length - i : i;
7315      impulseL[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, decay);
7316      impulseR[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, decay);
7317    }
7318    this.convolverNode.buffer = impulse;
7319  };
7320  p5.Reverb.prototype.dispose = function () {
7321    // remove reference from soundArray
7322    var index = p5sound.soundArray.indexOf(this);
7323    p5sound.soundArray.splice(index, 1);
7324    if (this.convolverNode) {
7325      this.convolverNode.buffer = null;
7326      this.convolverNode = null;
7327    }
7328    if (typeof this.output !== 'undefined') {
7329      this.output.disconnect();
7330      this.output = null;
7331    }
7332    if (typeof this.panner !== 'undefined') {
7333      this.panner.disconnect();
7334      this.panner = null;
7335    }
7336  };
7337  // =======================================================================
7338  //                          *** p5.Convolver ***
7339  // =======================================================================
7340  /**
7341   *  <p>p5.Convolver extends p5.Reverb. It can emulate the sound of real
7342   *  physical spaces through a process called <a href="
7343   *  https://en.wikipedia.org/wiki/Convolution_reverb#Real_space_simulation">
7344   *  convolution</a>.</p>
7345   *  
7346   *  <p>Convolution multiplies any audio input by an "impulse response"
7347   *  to simulate the dispersion of sound over time. The impulse response is
7348   *  generated from an audio file that you provide. One way to
7349   *  generate an impulse response is to pop a balloon in a reverberant space
7350   *  and record the echo. Convolution can also be used to experiment with
7351   *  sound.</p>
7352   *
7353   *  <p>Use the method <code>createConvolution(path)</code> to instantiate a
7354   *  p5.Convolver with a path to your impulse response audio file.</p>
7355   *  
7356   *  @class p5.Convolver
7357   *  @constructor
7358   *  @param  {String}   path     path to a sound file
7359   *  @param  {Function} [callback] function to call when loading succeeds
7360   *  @param  {Function} [errorCallback] function to call if loading fails.
7361   *                                     This function will receive an error or
7362   *                                     XMLHttpRequest object with information
7363   *                                     about what went wrong.
7364   *  @example
7365   *  <div><code>
7366   *  var cVerb, sound;
7367   *  function preload() {
7368   *    // We have both MP3 and OGG versions of all sound assets
7369   *    soundFormats('ogg', 'mp3');
7370   *    
7371   *    // Try replacing 'bx-spring' with other soundfiles like
7372   *    // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox'
7373   *    cVerb = createConvolver('assets/bx-spring.mp3');
7374   *
7375   *    // Try replacing 'Damscray_DancingTiger' with
7376   *    // 'beat', 'doorbell', lucky_dragons_-_power_melody'
7377   *    sound = loadSound('assets/Damscray_DancingTiger.mp3');
7378   *  }
7379   *  
7380   *  function setup() {
7381   *    // disconnect from master output...
7382   *    sound.disconnect();
7383   *    
7384   *    // ...and process with cVerb
7385   *    // so that we only hear the convolution
7386   *    cVerb.process(sound);
7387   *    
7388   *    sound.play();
7389   *  }
7390   *  </code></div>
7391   */
7392  p5.Convolver = function (path, callback, errorCallback) {
7393    this.ac = p5sound.audiocontext;
7394    /**
7395     *  Internally, the p5.Convolver uses the a
7396     *  <a href="http://www.w3.org/TR/webaudio/#ConvolverNode">
7397     *  Web Audio Convolver Node</a>.
7398     *  
7399     *  @property convolverNode
7400     *  @type {Object}  Web Audio Convolver Node
7401     */
7402    this.convolverNode = this.ac.createConvolver();
7403    this.input = this.ac.createGain();
7404    this.output = this.ac.createGain();
7405    // otherwise, Safari distorts
7406    this.input.gain.value = 0.5;
7407    this.input.connect(this.convolverNode);
7408    this.convolverNode.connect(this.output);
7409    if (path) {
7410      this.impulses = [];
7411      this._loadBuffer(path, callback, errorCallback);
7412    } else {
7413      // parameters
7414      this._seconds = 3;
7415      this._decay = 2;
7416      this._reverse = false;
7417      this._buildImpulse();
7418    }
7419    this.connect();
7420    p5sound.soundArray.push(this);
7421  };
7422  p5.Convolver.prototype = Object.create(p5.Reverb.prototype);
7423  p5.prototype.registerPreloadMethod('createConvolver', p5.prototype);
7424  /**
7425   *  Create a p5.Convolver. Accepts a path to a soundfile 
7426   *  that will be used to generate an impulse response.
7427   *
7428   *  @method  createConvolver
7429   *  @param  {String}   path     path to a sound file
7430   *  @param  {Function} [callback] function to call if loading is successful.
7431   *                                The object will be passed in as the argument
7432   *                                to the callback function.
7433   *  @param  {Function} [errorCallback] function to call if loading is not successful.
7434   *                                A custom error will be passed in as the argument
7435   *                                to the callback function.
7436   *  @return {p5.Convolver}
7437   *  @example
7438   *  <div><code>
7439   *  var cVerb, sound;
7440   *  function preload() {
7441   *    // We have both MP3 and OGG versions of all sound assets
7442   *    soundFormats('ogg', 'mp3');
7443   *    
7444   *    // Try replacing 'bx-spring' with other soundfiles like
7445   *    // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox'
7446   *    cVerb = createConvolver('assets/bx-spring.mp3');
7447   *
7448   *    // Try replacing 'Damscray_DancingTiger' with
7449   *    // 'beat', 'doorbell', lucky_dragons_-_power_melody'
7450   *    sound = loadSound('assets/Damscray_DancingTiger.mp3');
7451   *  }
7452   *  
7453   *  function setup() {
7454   *    // disconnect from master output...
7455   *    sound.disconnect();
7456   *    
7457   *    // ...and process with cVerb
7458   *    // so that we only hear the convolution
7459   *    cVerb.process(sound);
7460   *    
7461   *    sound.play();
7462   *  }
7463   *  </code></div>
7464   */
7465  p5.prototype.createConvolver = function (path, callback, errorCallback) {
7466    // if loading locally without a server
7467    if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') {
7468      alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS');
7469    }
7470    var cReverb = new p5.Convolver(path, callback, errorCallback);
7471    cReverb.impulses = [];
7472    return cReverb;
7473  };
7474  /**
7475   *  Private method to load a buffer as an Impulse Response,
7476   *  assign it to the convolverNode, and add to the Array of .impulses.
7477   *  
7478   *  @param   {String}   path
7479   *  @param   {Function} callback
7480   *  @param   {Function} errorCallback
7481   *  @private
7482   */
7483  p5.Convolver.prototype._loadBuffer = function (path, callback, errorCallback) {
7484    var path = p5.prototype._checkFileFormats(path);
7485    var self = this;
7486    var errorTrace = new Error().stack;
7487    var ac = p5.prototype.getAudioContext();
7488    var request = new XMLHttpRequest();
7489    request.open('GET', path, true);
7490    request.responseType = 'arraybuffer';
7491    request.onload = function () {
7492      if (request.status == 200) {
7493        // on success loading file:
7494        ac.decodeAudioData(request.response, function (buff) {
7495          var buffer = {};
7496          var chunks = path.split('/');
7497          buffer.name = chunks[chunks.length - 1];
7498          buffer.audioBuffer = buff;
7499          self.impulses.push(buffer);
7500          self.convolverNode.buffer = buffer.audioBuffer;
7501          if (callback) {
7502            callback(buffer);
7503          }
7504        }, // error decoding buffer. "e" is undefined in Chrome 11/22/2015
7505        function (e) {
7506          var err = new CustomError('decodeAudioData', errorTrace, self.url);
7507          var msg = 'AudioContext error at decodeAudioData for ' + self.url;
7508          if (errorCallback) {
7509            err.msg = msg;
7510            errorCallback(err);
7511          } else {
7512            console.error(msg + '\n The error stack trace includes: \n' + err.stack);
7513          }
7514        });
7515      } else {
7516        var err = new CustomError('loadConvolver', errorTrace, self.url);
7517        var msg = 'Unable to load ' + self.url + '. The request status was: ' + request.status + ' (' + request.statusText + ')';
7518        if (errorCallback) {
7519          err.message = msg;
7520          errorCallback(err);
7521        } else {
7522          console.error(msg + '\n The error stack trace includes: \n' + err.stack);
7523        }
7524      }
7525    };
7526    // if there is another error, aside from 404...
7527    request.onerror = function (e) {
7528      var err = new CustomError('loadConvolver', errorTrace, self.url);
7529      var msg = 'There was no response from the server at ' + self.url + '. Check the url and internet connectivity.';
7530      if (errorCallback) {
7531        err.message = msg;
7532        errorCallback(err);
7533      } else {
7534        console.error(msg + '\n The error stack trace includes: \n' + err.stack);
7535      }
7536    };
7537    request.send();
7538  };
7539  p5.Convolver.prototype.set = null;
7540  /**
7541   *  Connect a source to the reverb, and assign reverb parameters.
7542   *  
7543   *  @method  process
7544   *  @param  {Object} src     p5.sound / Web Audio object with a sound
7545   *                           output.
7546   *  @example
7547   *  <div><code>
7548   *  var cVerb, sound;
7549   *  function preload() {
7550   *    soundFormats('ogg', 'mp3');
7551   *    
7552   *    cVerb = createConvolver('assets/concrete-tunnel.mp3');
7553   *
7554   *    sound = loadSound('assets/beat.mp3');
7555   *  }
7556   *  
7557   *  function setup() {
7558   *    // disconnect from master output...
7559   *    sound.disconnect();
7560   *    
7561   *    // ...and process with (i.e. connect to) cVerb
7562   *    // so that we only hear the convolution
7563   *    cVerb.process(sound);
7564   *    
7565   *    sound.play();
7566   *  }
7567   *  </code></div>
7568   */
7569  p5.Convolver.prototype.process = function (src) {
7570    src.connect(this.input);
7571  };
7572  /**
7573   *  If you load multiple impulse files using the .addImpulse method,
7574   *  they will be stored as Objects in this Array. Toggle between them
7575   *  with the <code>toggleImpulse(id)</code> method.
7576   *  
7577   *  @property impulses
7578   *  @type {Array} Array of Web Audio Buffers
7579   */
7580  p5.Convolver.prototype.impulses = [];
7581  /**
7582   *  Load and assign a new Impulse Response to the p5.Convolver.
7583   *  The impulse is added to the <code>.impulses</code> array. Previous
7584   *  impulses can be accessed with the <code>.toggleImpulse(id)</code>
7585   *  method.
7586   *  
7587   *  @method  addImpulse
7588   *  @param  {String}   path     path to a sound file
7589   *  @param  {Function} callback function (optional)
7590   *  @param  {Function} errorCallback function (optional)
7591   */
7592  p5.Convolver.prototype.addImpulse = function (path, callback, errorCallback) {
7593    // if loading locally without a server
7594    if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') {
7595      alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS');
7596    }
7597    this._loadBuffer(path, callback, errorCallback);
7598  };
7599  /**
7600   *  Similar to .addImpulse, except that the <code>.impulses</code>
7601   *  Array is reset to save memory. A new <code>.impulses</code>
7602   *  array is created with this impulse as the only item. 
7603   *
7604   *  @method  resetImpulse
7605   *  @param  {String}   path     path to a sound file
7606   *  @param  {Function} callback function (optional)
7607   *  @param  {Function} errorCallback function (optional)
7608   */
7609  p5.Convolver.prototype.resetImpulse = function (path, callback, errorCallback) {
7610    // if loading locally without a server
7611    if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') {
7612      alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS');
7613    }
7614    this.impulses = [];
7615    this._loadBuffer(path, callback, errorCallback);
7616  };
7617  /**
7618   *  If you have used <code>.addImpulse()</code> to add multiple impulses
7619   *  to a p5.Convolver, then you can use this method to toggle between
7620   *  the items in the <code>.impulses</code> Array. Accepts a parameter
7621   *  to identify which impulse you wish to use, identified either by its
7622   *  original filename (String) or by its position in the <code>.impulses
7623   *  </code> Array (Number).<br/>
7624   *  You can access the objects in the .impulses Array directly. Each
7625   *  Object has two attributes: an <code>.audioBuffer</code> (type:
7626   *  Web Audio <a href="
7627   *  http://webaudio.github.io/web-audio-api/#the-audiobuffer-interface">
7628   *  AudioBuffer)</a> and a <code>.name</code>, a String that corresponds
7629   *  with the original filename. 
7630   *  
7631   *  @method toggleImpulse
7632   *  @param {String|Number} id Identify the impulse by its original filename
7633   *                            (String), or by its position in the
7634   *                            <code>.impulses</code> Array (Number).
7635   */
7636  p5.Convolver.prototype.toggleImpulse = function (id) {
7637    if (typeof id === 'number' && id < this.impulses.length) {
7638      this.convolverNode.buffer = this.impulses[id].audioBuffer;
7639    }
7640    if (typeof id === 'string') {
7641      for (var i = 0; i < this.impulses.length; i++) {
7642        if (this.impulses[i].name === id) {
7643          this.convolverNode.buffer = this.impulses[i].audioBuffer;
7644          break;
7645        }
7646      }
7647    }
7648  };
7649  p5.Convolver.prototype.dispose = function () {
7650    // remove all the Impulse Response buffers
7651    for (var i in this.impulses) {
7652      this.impulses[i] = null;
7653    }
7654    this.convolverNode.disconnect();
7655    this.concolverNode = null;
7656    if (typeof this.output !== 'undefined') {
7657      this.output.disconnect();
7658      this.output = null;
7659    }
7660    if (typeof this.panner !== 'undefined') {
7661      this.panner.disconnect();
7662      this.panner = null;
7663    }
7664  };
7665}(master, errorHandler, sndcore);
7666/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
7667var Tone_core_TimelineState;
7668Tone_core_TimelineState = function (Tone) {
7669  'use strict';
7670  Tone.TimelineState = function (initial) {
7671    Tone.Timeline.call(this);
7672    this._initial = initial;
7673  };
7674  Tone.extend(Tone.TimelineState, Tone.Timeline);
7675  Tone.TimelineState.prototype.getStateAtTime = function (time) {
7676    var event = this.getEvent(time);
7677    if (event !== null) {
7678      return event.state;
7679    } else {
7680      return this._initial;
7681    }
7682  };
7683  Tone.TimelineState.prototype.setStateAtTime = function (state, time) {
7684    this.addEvent({
7685      'state': state,
7686      'time': this.toSeconds(time)
7687    });
7688  };
7689  return Tone.TimelineState;
7690}(Tone_core_Tone, Tone_core_Timeline);
7691/** Tone.js module by Yotam Mann, MIT License 2016  http://opensource.org/licenses/MIT **/
7692var Tone_core_Clock;
7693Tone_core_Clock = function (Tone) {
7694  'use strict';
7695  Tone.Clock = function () {
7696    var options = this.optionsObject(arguments, [
7697      'callback',
7698      'frequency'
7699    ], Tone.Clock.defaults);
7700    this.callback = options.callback;
7701    this._lookAhead = 'auto';
7702    this._computedLookAhead = 1 / 60;
7703    this._threshold = 0.5;
7704    this._nextTick = -1;
7705    this._lastUpdate = 0;
7706    this._loopID = -1;
7707    this.frequency = new Tone.TimelineSignal(options.frequency, Tone.Type.Frequency);
7708    this.ticks = 0;
7709    this._state = new Tone.TimelineState(Tone.State.Stopped);
7710    this._boundLoop = this._loop.bind(this);
7711    this._readOnly('frequency');
7712    this._loop();
7713  };
7714  Tone.extend(Tone.Clock);
7715  Tone.Clock.defaults = {
7716    'callback': Tone.noOp,
7717    'frequency': 1,
7718    'lookAhead': 'auto'
7719  };
7720  Object.defineProperty(Tone.Clock.prototype, 'state', {
7721    get: function () {
7722      return this._state.getStateAtTime(this.now());
7723    }
7724  });
7725  Object.defineProperty(Tone.Clock.prototype, 'lookAhead', {
7726    get: function () {
7727      return this._lookAhead;
7728    },
7729    set: function (val) {
7730      if (val === 'auto') {
7731        this._lookAhead = 'auto';
7732      } else {
7733        this._lookAhead = this.toSeconds(val);
7734      }
7735    }
7736  });
7737  Tone.Clock.prototype.start = function (time, offset) {
7738    time = this.toSeconds(time);
7739    if (this._state.getStateAtTime(time) !== Tone.State.Started) {
7740      this._state.addEvent({
7741        'state': Tone.State.Started,
7742        'time': time,
7743        'offset': offset
7744      });
7745    }
7746    return this;
7747  };
7748  Tone.Clock.prototype.stop = function (time) {
7749    time = this.toSeconds(time);
7750    if (this._state.getStateAtTime(time) !== Tone.State.Stopped) {
7751      this._state.setStateAtTime(Tone.State.Stopped, time);
7752    }
7753    return this;
7754  };
7755  Tone.Clock.prototype.pause = function (time) {
7756    time = this.toSeconds(time);
7757    if (this._state.getStateAtTime(time) === Tone.State.Started) {
7758      this._state.setStateAtTime(Tone.State.Paused, time);
7759    }
7760    return this;
7761  };
7762  Tone.Clock.prototype._loop = function (time) {
7763    this._loopID = requestAnimationFrame(this._boundLoop);
7764    if (this._lookAhead === 'auto') {
7765      if (!this.isUndef(time)) {
7766        var diff = (time - this._lastUpdate) / 1000;
7767        this._lastUpdate = time;
7768        if (diff < this._threshold) {
7769          this._computedLookAhead = (9 * this._computedLookAhead + diff) / 10;
7770        }
7771      }
7772    } else {
7773      this._computedLookAhead = this._lookAhead;
7774    }
7775    var now = this.now();
7776    var lookAhead = this._computedLookAhead * 2;
7777    var event = this._state.getEvent(now + lookAhead);
7778    var state = Tone.State.Stopped;
7779    if (event) {
7780      state = event.state;
7781      if (this._nextTick === -1 && state === Tone.State.Started) {
7782        this._nextTick = event.time;
7783        if (!this.isUndef(event.offset)) {
7784          this.ticks = event.offset;
7785        }
7786      }
7787    }
7788    if (state === Tone.State.Started) {
7789      while (now + lookAhead > this._nextTick) {
7790        if (now > this._nextTick + this._threshold) {
7791          this._nextTick = now;
7792        }
7793        var tickTime = this._nextTick;
7794        this._nextTick += 1 / this.frequency.getValueAtTime(this._nextTick);
7795        this.callback(tickTime);
7796        this.ticks++;
7797      }
7798    } else if (state === Tone.State.Stopped) {
7799      this._nextTick = -1;
7800      this.ticks = 0;
7801    }
7802  };
7803  Tone.Clock.prototype.getStateAtTime = function (time) {
7804    return this._state.getStateAtTime(time);
7805  };
7806  Tone.Clock.prototype.dispose = function () {
7807    cancelAnimationFrame(this._loopID);
7808    Tone.TimelineState.prototype.dispose.call(this);
7809    this._writable('frequency');
7810    this.frequency.dispose();
7811    this.frequency = null;
7812    this._boundLoop = Tone.noOp;
7813    this._nextTick = Infinity;
7814    this.callback = null;
7815    this._state.dispose();
7816    this._state = null;
7817  };
7818  return Tone.Clock;
7819}(Tone_core_Tone, Tone_signal_TimelineSignal);
7820var metro;
7821metro = function () {
7822  'use strict';
7823  var p5sound = master;
7824  // requires the Tone.js library's Clock (MIT license, Yotam Mann)
7825  // https://github.com/TONEnoTONE/Tone.js/
7826  var Clock = Tone_core_Clock;
7827  var ac = p5sound.audiocontext;
7828  // var upTick = false;
7829  p5.Metro = function () {
7830    this.clock = new Clock({ 'callback': this.ontick.bind(this) });
7831    this.syncedParts = [];
7832    this.bpm = 120;
7833    // gets overridden by p5.Part
7834    this._init();
7835    this.tickCallback = function () {
7836    };
7837  };
7838  var prevTick = 0;
7839  var tatumTime = 0;
7840  p5.Metro.prototype.ontick = function (tickTime) {
7841    var elapsedTime = tickTime - prevTick;
7842    var secondsFromNow = tickTime - p5sound.audiocontext.currentTime;
7843    if (elapsedTime - tatumTime <= -0.02) {
7844      return;
7845    } else {
7846      prevTick = tickTime;
7847      // for all of the active things on the metro:
7848      for (var i in this.syncedParts) {
7849        var thisPart = this.syncedParts[i];
7850        thisPart.incrementStep(secondsFromNow);
7851        // each synced source keeps track of its own beat number
7852        for (var j in thisPart.phrases) {
7853          var thisPhrase = thisPart.phrases[j];
7854          var phraseArray = thisPhrase.sequence;
7855          var bNum = this.metroTicks % phraseArray.length;
7856          if (phraseArray[bNum] !== 0 && (this.metroTicks < phraseArray.length || !thisPhrase.looping)) {
7857            thisPhrase.callback(secondsFromNow, phraseArray[bNum]);
7858          }
7859        }
7860      }
7861      this.metroTicks += 1;
7862      this.tickCallback(secondsFromNow);
7863    }
7864  };
7865  p5.Metro.prototype.setBPM = function (bpm, rampTime) {
7866    var beatTime = 60 / (bpm * this.tatums);
7867    var now = p5sound.audiocontext.currentTime;
7868    tatumTime = beatTime;
7869    var rampTime = rampTime || 0;
7870    this.clock.frequency.setValueAtTime(this.clock.frequency.value, now);
7871    this.clock.frequency.linearRampToValueAtTime(bpm, now + rampTime);
7872    this.bpm = bpm;
7873  };
7874  p5.Metro.prototype.getBPM = function (tempo) {
7875    return this.clock.getRate() / this.tatums * 60;
7876  };
7877  p5.Metro.prototype._init = function () {
7878    this.metroTicks = 0;
7879  };
7880  // clear existing synced parts, add only this one
7881  p5.Metro.prototype.resetSync = function (part) {
7882    this.syncedParts = [part];
7883  };
7884  // push a new synced part to the array
7885  p5.Metro.prototype.pushSync = function (part) {
7886    this.syncedParts.push(part);
7887  };
7888  p5.Metro.prototype.start = function (timeFromNow) {
7889    var t = timeFromNow || 0;
7890    var now = p5sound.audiocontext.currentTime;
7891    this.clock.start(now + t);
7892    this.setBPM(this.bpm);
7893  };
7894  p5.Metro.prototype.stop = function (timeFromNow) {
7895    var t = timeFromNow || 0;
7896    var now = p5sound.audiocontext.currentTime;
7897    if (this.clock._oscillator) {
7898      this.clock.stop(now + t);
7899    }
7900  };
7901  p5.Metro.prototype.beatLength = function (tatums) {
7902    this.tatums = 1 / tatums / 4;
7903  };
7904}(master, Tone_core_Clock);
7905var looper;
7906looper = function () {
7907  'use strict';
7908  var p5sound = master;
7909  var bpm = 120;
7910  /**
7911   *  Set the global tempo, in beats per minute, for all
7912   *  p5.Parts. This method will impact all active p5.Parts.
7913   *  
7914   *  @param {Number} BPM      Beats Per Minute
7915   *  @param {Number} rampTime Seconds from now
7916   */
7917  p5.prototype.setBPM = function (BPM, rampTime) {
7918    bpm = BPM;
7919    for (var i in p5sound.parts) {
7920      p5sound.parts[i].setBPM(bpm, rampTime);
7921    }
7922  };
7923  /**
7924   *  <p>A phrase is a pattern of musical events over time, i.e.
7925   *  a series of notes and rests.</p>
7926   *  
7927   *  <p>Phrases must be added to a p5.Part for playback, and
7928   *  each part can play multiple phrases at the same time.
7929   *  For example, one Phrase might be a kick drum, another
7930   *  could be a snare, and another could be the bassline.</p>
7931   *  
7932   *  <p>The first parameter is a name so that the phrase can be
7933   *  modified or deleted later. The callback is a a function that
7934   *  this phrase will call at every step—for example it might be
7935   *  called <code>playNote(value){}</code>. The array determines
7936   *  which value is passed into the callback at each step of the
7937   *  phrase. It can be numbers, an object with multiple numbers,
7938   *  or a zero (0) indicates a rest so the callback won't be called).</p>
7939   * 
7940   *  @class p5.Phrase
7941   *  @constructor
7942   *  @param {String}   name     Name so that you can access the Phrase.
7943   *  @param {Function} callback The name of a function that this phrase
7944   *                             will call. Typically it will play a sound,
7945   *                             and accept two parameters: a time at which
7946   *                             to play the sound (in seconds from now),
7947   *                             and a value from the sequence array. The
7948   *                             time should be passed into the play() or
7949   *                             start() method to ensure precision.
7950   *  @param {Array}   sequence    Array of values to pass into the callback
7951   *                            at each step of the phrase.
7952   *  @example
7953   *  <div><code>
7954   *  var mySound, myPhrase, myPart;
7955   *  var pattern = [1,0,0,2,0,2,0,0];
7956   *  var msg = 'click to play';
7957   *  
7958   *  function preload() {
7959   *    mySound = loadSound('assets/beatbox.mp3');
7960   *  }
7961   *  
7962   *  function setup() {
7963   *    noStroke();
7964   *    fill(255);
7965   *    textAlign(CENTER);
7966   *    masterVolume(0.1);
7967   *    
7968   *    myPhrase = new p5.Phrase('bbox', makeSound, pattern);
7969   *    myPart = new p5.Part();
7970   *    myPart.addPhrase(myPhrase);
7971   *    myPart.setBPM(60);
7972   *  }
7973   *
7974   *  function draw() {
7975   *    background(0);
7976   *    text(msg, width/2, height/2);
7977   *  }
7978   *
7979   *  function makeSound(time, playbackRate) {
7980   *    mySound.rate(playbackRate);
7981   *    mySound.play(time);
7982   *  }
7983   *  
7984   *  function mouseClicked() {
7985   *    if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
7986   *      myPart.start();
7987   *      msg = 'playing pattern';
7988   *    }
7989   *  }
7990   *
7991   *  </code></div>
7992   */
7993  p5.Phrase = function (name, callback, sequence) {
7994    this.phraseStep = 0;
7995    this.name = name;
7996    this.callback = callback;
7997    /**
7998     * Array of values to pass into the callback
7999     * at each step of the phrase. Depending on the callback
8000     * function's requirements, these values may be numbers,
8001     * strings, or an object with multiple parameters.
8002     * Zero (0) indicates a rest.
8003     * 
8004     * @property sequence
8005     * @type {Array}
8006     */
8007    this.sequence = sequence;
8008  };
8009  /**
8010   *  <p>A p5.Part plays back one or more p5.Phrases. Instantiate a part
8011   *  with steps and tatums. By default, each step represents 1/16th note.</p>
8012   *
8013   *  <p>See p5.Phrase for more about musical timing.</p>
8014   *  
8015   *  @class p5.Part
8016   *  @constructor
8017   *  @param {Number} [steps]   Steps in the part
8018   *  @param {Number} [tatums] Divisions of a beat (default is 1/16, a quarter note)
8019   *  @example
8020   *  <div><code>
8021   *  var box, drum, myPart;
8022   *  var boxPat = [1,0,0,2,0,2,0,0];
8023   *  var drumPat = [0,1,1,0,2,0,1,0];
8024   *  var msg = 'click to play';
8025   *  
8026   *  function preload() {
8027   *    box = loadSound('assets/beatbox.mp3');
8028   *    drum = loadSound('assets/drum.mp3');
8029   *  }
8030   *  
8031   *  function setup() {
8032   *    noStroke();
8033   *    fill(255);
8034   *    textAlign(CENTER);
8035   *    masterVolume(0.1);
8036   *
8037   *    var boxPhrase = new p5.Phrase('box', playBox, boxPat);
8038   *    var drumPhrase = new p5.Phrase('drum', playDrum, drumPat);
8039   *    myPart = new p5.Part();
8040   *    myPart.addPhrase(boxPhrase);
8041   *    myPart.addPhrase(drumPhrase);
8042   *    myPart.setBPM(60);
8043   *    masterVolume(0.1);
8044   *  }
8045   *
8046   *  function draw() {
8047   *    background(0);
8048   *    text(msg, width/2, height/2);
8049   *  }
8050   *
8051   *  function playBox(time, playbackRate) {
8052   *    box.rate(playbackRate);
8053   *    box.play(time);
8054   *  }
8055   *  
8056   *  function playDrum(time, playbackRate) {
8057   *    drum.rate(playbackRate);
8058   *    drum.play(time);
8059   *  }
8060   *  
8061   *  function mouseClicked() {
8062   *    if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
8063   *      myPart.start();
8064   *      msg = 'playing part';
8065   *    }
8066   *  }
8067   *  </code></div>
8068   */
8069  p5.Part = function (steps, bLength) {
8070    this.length = steps || 0;
8071    // how many beats
8072    this.partStep = 0;
8073    this.phrases = [];
8074    this.looping = false;
8075    this.isPlaying = false;
8076    // what does this looper do when it gets to the last step?
8077    this.onended = function () {
8078      this.stop();
8079    };
8080    this.tatums = bLength || 0.0625;
8081    // defaults to quarter note
8082    this.metro = new p5.Metro();
8083    this.metro._init();
8084    this.metro.beatLength(this.tatums);
8085    this.metro.setBPM(bpm);
8086    p5sound.parts.push(this);
8087    this.callback = function () {
8088    };
8089  };
8090  /**
8091   *  Set the tempo of this part, in Beats Per Minute. 
8092   *  
8093   *  @method  setBPM
8094   *  @param {Number} BPM      Beats Per Minute
8095   *  @param {Number} [rampTime] Seconds from now
8096   */
8097  p5.Part.prototype.setBPM = function (tempo, rampTime) {
8098    this.metro.setBPM(tempo, rampTime);
8099  };
8100  /**
8101   *  Returns the Beats Per Minute of this currently part.
8102   *  
8103   *  @method getBPM
8104   *  @return {Number} 
8105   */
8106  p5.Part.prototype.getBPM = function () {
8107    return this.metro.getBPM();
8108  };
8109  /**
8110   *  Start playback of this part. It will play
8111   *  through all of its phrases at a speed
8112   *  determined by setBPM.
8113   *  
8114   *  @method  start
8115   *  @param  {Number} [time] seconds from now
8116   */
8117  p5.Part.prototype.start = function (time) {
8118    if (!this.isPlaying) {
8119      this.isPlaying = true;
8120      this.metro.resetSync(this);
8121      var t = time || 0;
8122      this.metro.start(t);
8123    }
8124  };
8125  /**
8126   *  Loop playback of this part. It will begin
8127   *  looping through all of its phrases at a speed
8128   *  determined by setBPM.
8129   *  
8130   *  @method  loop
8131   *  @param  {Number} [time] seconds from now
8132   */
8133  p5.Part.prototype.loop = function (time) {
8134    this.looping = true;
8135    // rest onended function
8136    this.onended = function () {
8137      this.partStep = 0;
8138    };
8139    var t = time || 0;
8140    this.start(t);
8141  };
8142  /**
8143   *  Tell the part to stop looping.
8144   *
8145   *  @method  noLoop
8146   */
8147  p5.Part.prototype.noLoop = function () {
8148    this.looping = false;
8149    // rest onended function
8150    this.onended = function () {
8151      this.stop();
8152    };
8153  };
8154  /**
8155   *  Stop the part and cue it to step 0.
8156   *  
8157   *  @method  stop
8158   *  @param  {Number} [time] seconds from now
8159   */
8160  p5.Part.prototype.stop = function (time) {
8161    this.partStep = 0;
8162    this.pause(time);
8163  };
8164  /**
8165   *  Pause the part. Playback will resume
8166   *  from the current step.
8167   *  
8168   *  @method  pause
8169   *  @param  {Number} time seconds from now
8170   */
8171  p5.Part.prototype.pause = function (time) {
8172    this.isPlaying = false;
8173    var t = time || 0;
8174    this.metro.stop(t);
8175  };
8176  /**
8177   *  Add a p5.Phrase to this Part.
8178   *
8179   *  @method  addPhrase
8180   *  @param {p5.Phrase}   phrase   reference to a p5.Phrase
8181   */
8182  p5.Part.prototype.addPhrase = function (name, callback, array) {
8183    var p;
8184    if (arguments.length === 3) {
8185      p = new p5.Phrase(name, callback, array);
8186    } else if (arguments[0] instanceof p5.Phrase) {
8187      p = arguments[0];
8188    } else {
8189      throw 'invalid input. addPhrase accepts name, callback, array or a p5.Phrase';
8190    }
8191    this.phrases.push(p);
8192    // reset the length if phrase is longer than part's existing length
8193    if (p.sequence.length > this.length) {
8194      this.length = p.sequence.length;
8195    }
8196  };
8197  /**
8198   *  Remove a phrase from this part, based on the name it was
8199   *  given when it was created.
8200   *  
8201   *  @method  removePhrase
8202   *  @param  {String} phraseName
8203   */
8204  p5.Part.prototype.removePhrase = function (name) {
8205    for (var i in this.phrases) {
8206      if (this.phrases[i].name === name) {
8207        this.phrases.split(i, 1);
8208      }
8209    }
8210  };
8211  /**
8212   *  Get a phrase from this part, based on the name it was
8213   *  given when it was created. Now you can modify its array.
8214   *  
8215   *  @method  getPhrase
8216   *  @param  {String} phraseName
8217   */
8218  p5.Part.prototype.getPhrase = function (name) {
8219    for (var i in this.phrases) {
8220      if (this.phrases[i].name === name) {
8221        return this.phrases[i];
8222      }
8223    }
8224  };
8225  /**
8226   *  Get a phrase from this part, based on the name it was
8227   *  given when it was created. Now you can modify its array.
8228   *  
8229   *  @method  replaceSequence
8230   *  @param  {String} phraseName
8231   *  @param  {Array} sequence  Array of values to pass into the callback
8232   *                            at each step of the phrase.
8233   */
8234  p5.Part.prototype.replaceSequence = function (name, array) {
8235    for (var i in this.phrases) {
8236      if (this.phrases[i].name === name) {
8237        this.phrases[i].sequence = array;
8238      }
8239    }
8240  };
8241  p5.Part.prototype.incrementStep = function (time) {
8242    if (this.partStep < this.length - 1) {
8243      this.callback(time);
8244      this.partStep += 1;
8245    } else {
8246      if (this.looping) {
8247        this.callback(time);
8248      }
8249      this.onended();
8250      this.partStep = 0;
8251    }
8252  };
8253  /**
8254   *  Fire a callback function at every step.
8255   *
8256   *  @method onStep
8257   *  @param  {Function} callback The name of the callback
8258   *                              you want to fire
8259   *                              on every beat/tatum.
8260   */
8261  p5.Part.prototype.onStep = function (callback) {
8262    this.callback = callback;
8263  };
8264  // ===============
8265  // p5.Score
8266  // ===============
8267  /**
8268   *  A Score consists of a series of Parts. The parts will
8269   *  be played back in order. For example, you could have an
8270   *  A part, a B part, and a C part, and play them back in this order
8271   *  <code>new p5.Score(a, a, b, a, c)</code>
8272   *
8273   *  @class p5.Score
8274   *  @constructor
8275   *  @param {p5.Part} part(s) One or multiple parts, to be played in sequence.
8276   *  @return {p5.Score}
8277   */
8278  p5.Score = function () {
8279    // for all of the arguments
8280    this.parts = [];
8281    this.currentPart = 0;
8282    var thisScore = this;
8283    for (var i in arguments) {
8284      this.parts[i] = arguments[i];
8285      this.parts[i].nextPart = this.parts[i + 1];
8286      this.parts[i].onended = function () {
8287        thisScore.resetPart(i);
8288        playNextPart(thisScore);
8289      };
8290    }
8291    this.looping = false;
8292  };
8293  p5.Score.prototype.onended = function () {
8294    if (this.looping) {
8295      // this.resetParts();
8296      this.parts[0].start();
8297    } else {
8298      this.parts[this.parts.length - 1].onended = function () {
8299        this.stop();
8300        this.resetParts();
8301      };
8302    }
8303    this.currentPart = 0;
8304  };
8305  /**
8306   *  Start playback of the score.
8307   *  
8308   *  @method  start
8309   */
8310  p5.Score.prototype.start = function () {
8311    this.parts[this.currentPart].start();
8312    this.scoreStep = 0;
8313  };
8314  /**
8315   *  Stop playback of the score.
8316   *  
8317   *  @method  stop
8318   */
8319  p5.Score.prototype.stop = function () {
8320    this.parts[this.currentPart].stop();
8321    this.currentPart = 0;
8322    this.scoreStep = 0;
8323  };
8324  /**
8325   *  Pause playback of the score.
8326   *  
8327   *  @method  pause
8328   */
8329  p5.Score.prototype.pause = function () {
8330    this.parts[this.currentPart].stop();
8331  };
8332  /**
8333   *  Loop playback of the score.
8334   *  
8335   *  @method  loop
8336   */
8337  p5.Score.prototype.loop = function () {
8338    this.looping = true;
8339    this.start();
8340  };
8341  /**
8342   *  Stop looping playback of the score. If it
8343   *  is currently playing, this will go into effect
8344   *  after the current round of playback completes.
8345   *  
8346   *  @method  noLoop
8347   */
8348  p5.Score.prototype.noLoop = function () {
8349    this.looping = false;
8350  };
8351  p5.Score.prototype.resetParts = function () {
8352    for (var i in this.parts) {
8353      this.resetPart(i);
8354    }
8355  };
8356  p5.Score.prototype.resetPart = function (i) {
8357    this.parts[i].stop();
8358    this.parts[i].partStep = 0;
8359    for (var p in this.parts[i].phrases) {
8360      this.parts[i].phrases[p].phraseStep = 0;
8361    }
8362  };
8363  /**
8364   *  Set the tempo for all parts in the score
8365   *  
8366   *  @param {Number} BPM      Beats Per Minute
8367   *  @param {Number} rampTime Seconds from now
8368   */
8369  p5.Score.prototype.setBPM = function (bpm, rampTime) {
8370    for (var i in this.parts) {
8371      this.parts[i].setBPM(bpm, rampTime);
8372    }
8373  };
8374  function playNextPart(aScore) {
8375    aScore.currentPart++;
8376    if (aScore.currentPart >= aScore.parts.length) {
8377      aScore.scoreStep = 0;
8378      aScore.onended();
8379    } else {
8380      aScore.scoreStep = 0;
8381      aScore.parts[aScore.currentPart - 1].stop();
8382      aScore.parts[aScore.currentPart].start();
8383    }
8384  }
8385}(master);
8386var soundRecorder;
8387soundRecorder = function () {
8388  'use strict';
8389  var p5sound = master;
8390  var ac = p5sound.audiocontext;
8391  /**
8392   *  <p>
8392Record sounds for playback and/or to save as a .wav file.
8393   *  The p5.SoundRecorder records all sound output from your sketch,
8394   *  or can be assigned a specific source with setInput().</p>
8395   *  <p>The record() method accepts a p5.SoundFile as a parameter.
8396   *  When playback is stopped (either after the given amount of time,
8397   *  or with the stop() method), the p5.SoundRecorder will send its
8398   *  recording to that p5.SoundFile for playback.</p>
8399   *  
8400   *  @class p5.SoundRecorder
8401   *  @constructor
8402   *  @example
8403   *  <div><code>
8404   *  var mic, recorder, soundFile;
8405   *  var state = 0;
8406   *  
8407   *  function setup() {
8408   *    background(200);
8409   *    // create an audio in
8410   *    mic = new p5.AudioIn();
8411   *    
8412   *    // prompts user to enable their browser mic
8413   *    mic.start();
8414   *    
8415   *    // create a sound recorder
8416   *    recorder = new p5.SoundRecorder();
8417   *    
8418   *    // connect the mic to the recorder
8419   *    recorder.setInput(mic);
8420   *    
8421   *    // this sound file will be used to
8422   *    // playback & save the recording
8423   *    soundFile = new p5.SoundFile();
8424   *
8425   *    text('keyPress to record', 20, 20);
8426   *  }
8427   *
8428   *  function keyPressed() {
8429   *    // make sure user enabled the mic
8430   *    if (state === 0 && mic.enabled) {
8431   *    
8432   *      // record to our p5.SoundFile
8433   *      recorder.record(soundFile);
8434   *      
8435   *      background(255,0,0);
8436   *      text('Recording!', 20, 20);
8437   *      state++;
8438   *    }
8439   *    else if (state === 1) {
8440   *      background(0,255,0);
8441   *
8442   *      // stop recorder and
8443   *      // send result to soundFile
8444   *      recorder.stop(); 
8445   *      
8446   *      text('Stopped', 20, 20);
8447   *      state++;
8448   *    }
8449   *    
8450   *    else if (state === 2) {
8451   *      soundFile.play(); // play the result!
8452   *      save(soundFile, 'mySound.wav');
8453   *      state++;
8454   *    }
8455   *  }
8456   *  </div></code>
8457   */
8458  p5.SoundRecorder = function () {
8459    this.input = ac.createGain();
8460    this.output = ac.createGain();
8461    this.recording = false;
8462    this.bufferSize = 1024;
8463    this._channels = 2;
8464    // stereo (default)
8465    this._clear();
8466    // initialize variables
8467    this._jsNode = ac.createScriptProcessor(this.bufferSize, this._channels, 2);
8468    this._jsNode.onaudioprocess = this._audioprocess.bind(this);
8469    /** 
8470     *  callback invoked when the recording is over
8471     *  @private
8472     *  @type {function(Float32Array)}
8473     */
8474    this._callback = function () {
8475    };
8476    // connections
8477    this._jsNode.connect(p5.soundOut._silentNode);
8478    this.setInput();
8479    // add this p5.SoundFile to the soundArray
8480    p5sound.soundArray.push(this);
8481  };
8482  /**
8483   *  Connect a specific device to the p5.SoundRecorder.
8484   *  If no parameter is given, p5.SoundRecorer will record
8485   *  all audible p5.sound from your sketch.
8486   *  
8487   *  @method  setInput
8488   *  @param {Object} [unit] p5.sound object or a web audio unit
8489   *                         that outputs sound
8490   */
8491  p5.SoundRecorder.prototype.setInput = function (unit) {
8492    this.input.disconnect();
8493    this.input = null;
8494    this.input = ac.createGain();
8495    this.input.connect(this._jsNode);
8496    this.input.connect(this.output);
8497    if (unit) {
8498      unit.connect(this.input);
8499    } else {
8500      p5.soundOut.output.connect(this.input);
8501    }
8502  };
8503  /**
8504   *  Start recording. To access the recording, provide
8505   *  a p5.SoundFile as the first parameter. The p5.SoundRecorder
8506   *  will send its recording to that p5.SoundFile for playback once
8507   *  recording is complete. Optional parameters include duration
8508   *  (in seconds) of the recording, and a callback function that
8509   *  will be called once the complete recording has been
8510   *  transfered to the p5.SoundFile.
8511   *  
8512   *  @method  record
8513   *  @param  {p5.SoundFile}   soundFile    p5.SoundFile
8514   *  @param  {Number}   [duration] Time (in seconds)
8515   *  @param  {Function} [callback] The name of a function that will be
8516   *                                called once the recording completes
8517   */
8518  p5.SoundRecorder.prototype.record = function (sFile, duration, callback) {
8519    this.recording = true;
8520    if (duration) {
8521      this.sampleLimit = Math.round(duration * ac.sampleRate);
8522    }
8523    if (sFile && callback) {
8524      this._callback = function () {
8525        this.buffer = this._getBuffer();
8526        sFile.setBuffer(this.buffer);
8527        callback();
8528      };
8529    } else if (sFile) {
8530      this._callback = function () {
8531        this.buffer = this._getBuffer();
8532        sFile.setBuffer(this.buffer);
8533      };
8534    }
8535  };
8536  /**
8537   *  Stop the recording. Once the recording is stopped,
8538   *  the results will be sent to the p5.SoundFile that
8539   *  was given on .record(), and if a callback function
8540   *  was provided on record, that function will be called.
8541   *  
8542   *  @method  stop
8543   */
8544  p5.SoundRecorder.prototype.stop = function () {
8545    this.recording = false;
8546    this._callback();
8547    this._clear();
8548  };
8549  p5.SoundRecorder.prototype._clear = function () {
8550    this._leftBuffers = [];
8551    this._rightBuffers = [];
8552    this.recordedSamples = 0;
8553    this.sampleLimit = null;
8554  };
8555  /**
8556   *  internal method called on audio process
8557   *  
8558   *  @private
8559   *  @param   {AudioProcessorEvent} event 
8560   */
8561  p5.SoundRecorder.prototype._audioprocess = function (event) {
8562    if (this.recording === false) {
8563      return;
8564    } else if (this.recording === true) {
8565      // if we are past the duration, then stop... else:
8566      if (this.sampleLimit && this.recordedSamples >= this.sampleLimit) {
8567        this.stop();
8568      } else {
8569        // get channel data
8570        var left = event.inputBuffer.getChannelData(0);
8571        var right = event.inputBuffer.getChannelData(1);
8572        // clone the samples
8573        this._leftBuffers.push(new Float32Array(left));
8574        this._rightBuffers.push(new Float32Array(right));
8575        this.recordedSamples += this.bufferSize;
8576      }
8577    }
8578  };
8579  p5.SoundRecorder.prototype._getBuffer = function () {
8580    var buffers = [];
8581    buffers.push(this._mergeBuffers(this._leftBuffers));
8582    buffers.push(this._mergeBuffers(this._rightBuffers));
8583    return buffers;
8584  };
8585  p5.SoundRecorder.prototype._mergeBuffers = function (channelBuffer) {
8586    var result = new Float32Array(this.recordedSamples);
8587    var offset = 0;
8588    var lng = channelBuffer.length;
8589    for (var i = 0; i < lng; i++) {
8590      var buffer = channelBuffer[i];
8591      result.set(buffer, offset);
8592      offset += buffer.length;
8593    }
8594    return result;
8595  };
8596  p5.SoundRecorder.prototype.dispose = function () {
8597    this._clear();
8598    // remove reference from soundArray
8599    var index = p5sound.soundArray.indexOf(this);
8600    p5sound.soundArray.splice(index, 1);
8601    this._callback = function () {
8602    };
8603    if (this.input) {
8604      this.input.disconnect();
8605    }
8606    this.input = null;
8607    this._jsNode = null;
8608  };
8609  /**
8610   *  Save a p5.SoundFile as a .wav audio file.
8611   *  
8612   *  @method saveSound
8613   *  @param  {p5.SoundFile} soundFile p5.SoundFile that you wish to save
8614   *  @param  {String} name      name of the resulting .wav file.
8615   */
8616  p5.prototype.saveSound = function (soundFile, name) {
8617    var leftChannel = soundFile.buffer.getChannelData(0);
8618    var rightChannel = soundFile.buffer.getChannelData(1);
8619    var interleaved = interleave(leftChannel, rightChannel);
8620    // create the buffer and view to create the .WAV file
8621    var buffer = new ArrayBuffer(44 + interleaved.length * 2);
8622    var view = new DataView(buffer);
8623    // write the WAV container,
8624    // check spec at: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
8625    // RIFF chunk descriptor
8626    writeUTFBytes(view, 0, 'RIFF');
8627    view.setUint32(4, 44 + interleaved.length * 2, true);
8628    writeUTFBytes(view, 8, 'WAVE');
8629    // FMT sub-chunk
8630    writeUTFBytes(view, 12, 'fmt ');
8631    view.setUint32(16, 16, true);
8632    view.setUint16(20, 1, true);
8633    // stereo (2 channels)
8634    view.setUint16(22, 2, true);
8635    view.setUint32(24, 44100, true);
8636    view.setUint32(28, 44100 * 4, true);
8637    view.setUint16(32, 4, true);
8638    view.setUint16(34, 16, true);
8639    // data sub-chunk
8640    writeUTFBytes(view, 36, 'data');
8641    view.setUint32(40, interleaved.length * 2, true);
8642    // write the PCM samples
8643    var lng = interleaved.length;
8644    var index = 44;
8645    var volume = 1;
8646    for (var i = 0; i < lng; i++) {
8647      view.setInt16(index, interleaved[i] * (32767 * volume), true);
8648      index += 2;
8649    }
8650    p5.prototype.writeFile([view], name, 'wav');
8651  };
8652  // helper methods to save waves
8653  function interleave(leftChannel, rightChannel) {
8654    var length = leftChannel.length + rightChannel.length;
8655    var result = new Float32Array(length);
8656    var inputIndex = 0;
8657    for (var index = 0; index < length;) {
8658      result[index++] = leftChannel[inputIndex];
8659      result[index++] = rightChannel[inputIndex];
8660      inputIndex++;
8661    }
8662    return result;
8663  }
8664  function writeUTFBytes(view, offset, string) {
8665    var lng = string.length;
8666    for (var i = 0; i < lng; i++) {
8667      view.setUint8(offset + i, string.charCodeAt(i));
8668    }
8669  }
8670}(sndcore, master);
8671var peakdetect;
8672peakdetect = function () {
8673  'use strict';
8674  var p5sound = master;
8675  /**
8676   *  <p>PeakDetect works in conjunction with p5.FFT to
8677   *  look for onsets in some or all of the frequency spectrum.
8678   *  </p>
8679   *  <p>
8680   *  To use p5.PeakDetect, call <code>update</code> in the draw loop
8681   *  and pass in a p5.FFT object.
8682   *  </p>
8683   *  <p>
8684   *  You can listen for a specific part of the frequency spectrum by
8685   *  setting the range between <code>freq1</code> and <code>freq2</code>.
8686   *  </p>
8687   *
8688   *  <p><code>threshold</code> is the threshold for detecting a peak,
8689   *  scaled between 0 and 1. It is logarithmic, so 0.1 is half as loud
8690   *  as 1.0.</p>
8691   *
8692   *  <p>
8693   *  The update method is meant to be run in the draw loop, and
8694   *  <b>frames</b> determines how many loops must pass before
8695   *  another peak can be detected.
8696   *  For example, if the frameRate() = 60, you could detect the beat of a
8697   *  120 beat-per-minute song with this equation:
8698   *  <code> framesPerPeak = 60 / (estimatedBPM / 60 );</code>
8699   *  </p>
8700   *
8701   *  <p>
8702   *  Based on example contribtued by @b2renger, and a simple beat detection
8703   *  explanation by <a
8704   *  href="http://www.airtightinteractive.com/2013/10/making-audio-reactive-visuals/"
8705   *  target="_blank">Felix Turner</a>.
8706   *  </p>
8707   *  
8708   *  @class  p5.PeakDetect
8709   *  @constructor
8710   *  @param {Number} [freq1]     lowFrequency - defaults to 20Hz
8711   *  @param {Number} [freq2]     highFrequency - defaults to 20000 Hz
8712   *  @param {Number} [threshold] Threshold for detecting a beat between 0 and 1
8713   *                            scaled logarithmically where 0.1 is 1/2 the loudness
8714   *                            of 1.0. Defaults to 0.35.
8715   *  @param {Number} [framesPerPeak]     Defaults to 20.
8716   *  @example
8717   *  <div><code>
8718   *  
8719   *  var cnv, soundFile, fft, peakDetect;
8720   *  var ellipseWidth = 10;
8721   *
8722   *  function setup() {
8723   *    background(0);
8724   *    noStroke();
8725   *    fill(255);
8726   *    textAlign(CENTER);
8727   *
8728   *    soundFile = loadSound('assets/beat.mp3');
8729   *
8730   *    // p5.PeakDetect requires a p5.FFT
8731   *    fft = new p5.FFT();
8732   *    peakDetect = new p5.PeakDetect();
8733   *
8734   *  }
8735   *
8736   *  function draw() {
8737   *    background(0);
8738   *    text('click to play/pause', width/2, height/2);
8739   *
8740   *    // peakDetect accepts an fft post-analysis
8741   *    fft.analyze();
8742   *    peakDetect.update(fft);
8743   *
8744   *    if ( peakDetect.isDetected ) {
8745   *      ellipseWidth = 50;
8746   *    } else {
8747   *      ellipseWidth *= 0.95;
8748   *    }
8749   *
8750   *    ellipse(width/2, height/2, ellipseWidth, ellipseWidth);
8751   *  }
8752   *
8753   *  // toggle play/stop when canvas is clicked
8754   *  function mouseClicked() {
8755   *    if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
8756   *      if (soundFile.isPlaying() ) {
8757   *        soundFile.stop();
8758   *      } else {
8759   *        soundFile.play();
8760   *      }
8761   *    }
8762   *  }
8763   *  </code></div>
8764   */
8765  p5.PeakDetect = function (freq1, freq2, threshold, _framesPerPeak) {
8766    var framesPerPeak;
8767    // framesPerPeak determines how often to look for a beat.
8768    // If a beat is provided, try to look for a beat based on bpm
8769    this.framesPerPeak = _framesPerPeak || 20;
8770    this.framesSinceLastPeak = 0;
8771    this.decayRate = 0.95;
8772    this.threshold = threshold || 0.35;
8773    this.cutoff = 0;
8774    // how much to increase the cutoff 
8775    // TO DO: document this / figure out how to make it accessible
8776    this.cutoffMult = 1.5;
8777    this.energy = 0;
8778    this.penergy = 0;
8779    // TO DO: document this property / figure out how to make it accessible
8780    this.currentValue = 0;
8781    /**
8782     *  isDetected is set to true when a peak is detected.
8783     *  
8784     *  @attribute isDetected
8785     *  @type {Boolean}
8786     *  @default  false
8787     */
8788    this.isDetected = false;
8789    this.f1 = freq1 || 40;
8790    this.f2 = freq2 || 20000;
8791    // function to call when a peak is detected
8792    this._onPeak = function () {
8793    };
8794  };
8795  /**
8796   *  The update method is run in the draw loop.
8797   *
8798   *  Accepts an FFT object. You must call .analyze()
8799   *  on the FFT object prior to updating the peakDetect
8800   *  because it relies on a completed FFT analysis.
8801   *
8802   *  @method  update
8803   *  @param  {p5.FFT} fftObject A p5.FFT object
8804   */
8805  p5.PeakDetect.prototype.update = function (fftObject) {
8806    var nrg = this.energy = fftObject.getEnergy(this.f1, this.f2) / 255;
8807    if (nrg > this.cutoff && nrg > this.threshold && nrg - this.penergy > 0) {
8808      // trigger callback
8809      this._onPeak();
8810      this.isDetected = true;
8811      // debounce
8812      this.cutoff = nrg * this.cutoffMult;
8813      this.framesSinceLastPeak = 0;
8814    } else {
8815      this.isDetected = false;
8816      if (this.framesSinceLastPeak <= this.framesPerPeak) {
8817        this.framesSinceLastPeak++;
8818      } else {
8819        this.cutoff *= this.decayRate;
8820        this.cutoff = Math.max(this.cutoff, this.threshold);
8821      }
8822    }
8823    this.currentValue = nrg;
8824    this.penergy = nrg;
8825  };
8826  /**
8827   *  onPeak accepts two arguments: a function to call when
8828   *  a peak is detected. The value of the peak,
8829   *  between 0.0 and 1.0, is passed to the callback.
8830   *   
8831   *  @method  onPeak
8832   *  @param  {Function} callback Name of a function that will
8833   *                              be called when a peak is
8834   *                              detected.
8835   *  @param  {Object}   [val]    Optional value to pass
8836   *                              into the function when
8837   *                              a peak is detected.
8838   *  @example
8839   *  <div><code>
8840   *  var cnv, soundFile, fft, peakDetect;
8841   *  var ellipseWidth = 0;
8842   *  
8843   *  function setup() {
8844   *    cnv = createCanvas(100,100);
8845   *    textAlign(CENTER);
8846   *  
8847   *    soundFile = loadSound('assets/beat.mp3');
8848   *    fft = new p5.FFT();
8849   *    peakDetect = new p5.PeakDetect();
8850   *  
8851   *    setupSound();
8852   *  
8853   *    // when a beat is detected, call triggerBeat()
8854   *    peakDetect.onPeak(triggerBeat);
8855   *  }
8856   *  
8857   *  function draw() {
8858   *    background(0);
8859   *    fill(255);
8860   *    text('click to play', width/2, height/2);
8861   *  
8862   *    fft.analyze();
8863   *    peakDetect.update(fft);
8864   *  
8865   *    ellipseWidth *= 0.95;
8866   *    ellipse(width/2, height/2, ellipseWidth, ellipseWidth);
8867   *  }
8868   *  
8869   *  // this function is called by peakDetect.onPeak
8870   *  function triggerBeat() {
8871   *    ellipseWidth = 50;
8872   *  }
8873   *  
8874   *  // mouseclick starts/stops sound
8875   *  function setupSound() {
8876   *    cnv.mouseClicked( function() {
8877   *      if (soundFile.isPlaying() ) {
8878   *        soundFile.stop();
8879   *      } else {
8880   *        soundFile.play();
8881   *      }
8882   *    });
8883   *  }
8884   *  </code></div>
8885   */
8886  p5.PeakDetect.prototype.onPeak = function (callback, val) {
8887    var self = this;
8888    self._onPeak = function () {
8889      callback(self.energy, val);
8890    };
8891  };
8892}(master);
8893var gain;
8894gain = function () {
8895  'use strict';
8896  var p5sound = master;
8897  /**
8898  *  A gain node is usefull to set the relative volume of sound.
8899  *  It's typically used to build mixers.   
8900  *
8901  *  @class p5.Gain
8902  *  @constructor
8903  *  @example
8904  *  <div><code>
8905  *
8906  * // load two soundfile and crossfade beetween them
8907  * var sound1,sound2;
8908  * var gain1, gain2, gain3;
8909  * 
8910  * function preload(){
8911  *   soundFormats('ogg', 'mp3');
8912  *   sound1 = loadSound('../_files/Damscray_-_Dancing_Tiger_01');
8913  *   sound2 = loadSound('../_files/beat.mp3');
8914  * }
8915  *
8916  * function setup() {
8917  *   createCanvas(400,200);
8918  *
8919  *   // create a 'master' gain to which we will connect both soundfiles
8920  *   gain3 = new p5.Gain();
8921  *   gain3.connect();
8922  *
8923  *   // setup first sound for playing
8924  *   sound1.rate(1);
8925  *   sound1.loop();
8926  *   sound1.disconnect(); // diconnect from p5 output
8927  *
8928  *   gain1 = new p5.Gain(); // setup a gain node
8929  *   gain1.setInput(sound1); // connect the first sound to its input
8930  *   gain1.connect(gain3); // connect its output to the 'master'
8931  *
8932  *   sound2.rate(1);
8933  *   sound2.disconnect();
8934  *   sound2.loop();
8935  *
8936  *   gain2 = new p5.Gain();
8937  *   gain2.setInput(sound2);
8938  *   gain2.connect(gain3);
8939  *
8940  * }
8941  *
8942  * function draw(){
8943  *   background(180);
8944  *  
8945  *   // calculate the horizontal distance beetween the mouse and the right of the screen
8946  *   var d = dist(mouseX,0,width,0);
8947  *
8948  *   // map the horizontal position of the mouse to values useable for volume control of sound1
8949  *   var vol1 = map(mouseX,0,width,0,1); 
8950  *   var vol2 = 1-vol1; // when sound1 is loud, sound2 is quiet and vice versa
8951  *
8952  *   gain1.amp(vol1,0.5,0);
8953  *   gain2.amp(vol2,0.5,0);
8954  *
8955  *   // map the vertical position of the mouse to values useable for 'master volume control'
8956  *   var vol3 = map(mouseY,0,height,0,1); 
8957  *   gain3.amp(vol3,0.5,0);
8958  * }
8959  *</code></div>
8960  *
8961  */
8962  p5.Gain = function () {
8963    this.ac = p5sound.audiocontext;
8964    this.input = this.ac.createGain();
8965    this.output = this.ac.createGain();
8966    // otherwise, Safari distorts
8967    this.input.gain.value = 0.5;
8968    this.input.connect(this.output);
8969    // add  to the soundArray
8970    p5sound.soundArray.push(this);
8971  };
8972  /**
8973   *  Connect a source to the gain node.
8974   *  
8975   *  @method  setInput
8976   *  @param  {Object} src     p5.sound / Web Audio object with a sound
8977   *                           output.
8978   */
8979  p5.Gain.prototype.setInput = function (src) {
8980    src.connect(this.input);
8981  };
8982  /**
8983   *  Send output to a p5.sound or web audio object
8984   *  
8985   *  @method  connect
8986   *  @param  {Object} unit
8987   */
8988  p5.Gain.prototype.connect = function (unit) {
8989    var u = unit || p5.soundOut.input;
8990    this.output.connect(u.input ? u.input : u);
8991  };
8992  /**
8993   *  Disconnect all output.
8994   *  
8995   *  @method disconnect
8996   */
8997  p5.Gain.prototype.disconnect = function () {
8998    this.output.disconnect();
8999  };
9000  /**
9001   *  Set the output level of the gain node.
9002   *  
9003   *  @method  amp
9004   *  @param  {Number} volume amplitude between 0 and 1.0
9005   *  @param  {Number} [rampTime] create a fade that lasts rampTime 
9006   *  @param  {Number} [timeFromNow] schedule this event to happen
9007   *                                seconds from now
9008   */
9009  p5.Gain.prototype.amp = function (vol, rampTime, tFromNow) {
9010    var rampTime = rampTime || 0;
9011    var tFromNow = tFromNow || 0;
9012    var now = p5sound.audiocontext.currentTime;
9013    var currentVol = this.output.gain.value;
9014    this.output.gain.cancelScheduledValues(now);
9015    this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow);
9016    this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime);
9017  };
9018  p5.Gain.prototype.dispose = function () {
9019    // remove reference from soundArray
9020    var index = p5sound.soundArray.indexOf(this);
9021    p5sound.soundArray.splice(index, 1);
9022    this.output.disconnect();
9023    this.input.disconnect();
9024    this.output = undefined;
9025    this.input = undefined;
9026  };
9027}(master, sndcore);
9028var src_app;
9029src_app = function () {
9030  'use strict';
9031  var p5SOUND = sndcore;
9032  return p5SOUND;
9033}(sndcore, master, helpers, errorHandler, panner, soundfile, amplitude, fft, signal, oscillator, env, pulse, noise, audioin, filter, delay, reverb, metro, looper, soundRecorder, peakdetect, gain);
9034}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.