Skip to content

Instantly share code, notes, and snippets.

@therewasaguy
Last active December 19, 2015 18:38
Show Gist options
  • Save therewasaguy/0ad4bf964551aaf0bab7 to your computer and use it in GitHub Desktop.
Save therewasaguy/0ad4bf964551aaf0bab7 to your computer and use it in GitHub Desktop.
update
// shims
var requestAnimationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame;
var cancelAnimationFrame = window.cancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelRequestAnimationFrame || window.mozCancelAnimationFrame ||
window.oCancelRequestAnimationFrame || window.oCancelAnimationFrame ||
window.msCancelRequestAnimationFrame || window.msCancelAnimationFrame;
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
// two canvases / contexts
var cnv1, ctx1, cnv2, ctx2;
var video;
var numRows = 8;
var numCols = 2;
var counter = 0;
var curMatrixIndex, prevMatrixIndex;
var curColor = [0, 0, 0];
var w, h;
var pixelScaling = 12;
// event listeners
window.addEventListener('load', init);
function init() {
w = window.innerWidth/pixelScaling;
h = window.innerHeight/pixelScaling;
cnv1 = document.createElement('canvas');
cnv1.width = w;
cnv1.height = h;
ctx1 = cnv1.getContext('2d');
// flip canvas
ctx1.translate(cnv1.width, 0);
ctx1.scale(-1, 1);
cnv2 = document.createElement('canvas');
cnv2.width = w*pixelScaling;
cnv2.height = h*pixelScaling;
ctx2 = cnv2.getContext('2d');
ctx2.scale(pixelScaling,pixelScaling);
var container = document.getElementById('container');
container.appendChild(cnv2);
video = document.createElement('video');
video.width = w;
video.height = h;
video.hidden = true;
document.body.appendChild(video);
startCam();
draw();
}
function startCam() {
if (navigator.getUserMedia){
navigator.getUserMedia({video: true}, function(stream) {
video.src = window.URL.createObjectURL(stream) || stream;
video.play();
}, function(error) {alert("Your browser doesnt allow access to webcam. Try Chrome ");});
}
};
function draw() {
var rowWidth = Math.round(w/numRows);
var colHeight = Math.round(h/numCols);
// draw video to graphics context 1 (which is hidden)
ctx1.drawImage(video, 0, 0, cnv1.width, cnv1.height);
// keep track of which box we're in
var indexCounter = 0;
// split into rows and colums
for (var col = 0; col < (h - colHeight); col+= colHeight) {
for (var row = 0; row < (w - rowWidth); row+= rowWidth) {
ctx2.globalAlpha=0.9;
// get a rectangle of image data (pixels)
var imgData = ctx1.getImageData(row, col, rowWidth, colHeight);
// find average rgb value in this rectangle
var avgRGB = getAverageRGB(imgData.data);
// draw a rectangle on graphics context 2 (visible)
var c = rgbToHex(avgRGB);
ctx2.fillStyle=c;
ctx2.fillRect(row, col, rowWidth, colHeight);
// show which item we're on. curMatrixIndex is set by tone.loop in app-audio.js
if (curMatrixIndex === indexCounter) {
ctx2.globalAlpha=0.07;
ctx2.fillStyle='#fffff0';
ctx2.fillRect(row, col, rowWidth, colHeight);
curColor = rgbToHsl(avgRGB);
}
indexCounter++;
}
}
// call this function again in 50 ms
setTimeout(draw,50);
}
// via https://jsfiddle.net/xLF38/
function getAverageRGB(pxls) {
var blockSize = 5, // only visit every 5 pixels
rgb = {r: 0, g: 0, b: 0},
i = -4,
length,
count = 0;
var length = pxls.length;
while ( (i += blockSize * 4) < length ) {
++count;
rgb.r += pxls[i];
rgb.g += pxls[i+1];
rgb.b += pxls[i+2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r/count);
rgb.g = ~~(rgb.g/count);
rgb.b = ~~(rgb.b/count);
return rgb;
}
// via http://stackoverflow.com/a/5624139
function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function rgbToHex(c) {
return "#" + componentToHex(c.r) + componentToHex(c.g) + componentToHex(c.b);
}
/**
* via http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and l in the set [0, 1].
*
* @param Number r The red color value
* @param Number g The green color value
* @param Number b The blue color value
* @return Array The HSL representation
*/
function rgbToHsl(c){
var r = c.r/255, g = c.g/255, b = c.b/= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
function map(value, low1, high1, low2, high2) {
return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
}
<!DOCTYPE html>
<head>
<script src="tone.js"></script>
<script src="cam.js"></script>
<script src="sketch.js"></script>
<style>
body {
background:#222;
}
#container {
width:100%;
height:100%;
}
canvas {
position: absolute;
top: 0px;
left: 0px;
right:0px;
bottom:0px;
}
</style>
</head>
<body>
<div id="container">
</div>
</body>
/*! p5.dom.js v0.2.2 May 30, 2015 */
/**
* <p>The web is much more than just canvas and p5.dom makes it easy to interact
* with other HTML5 objects, including text, hyperlink, image, input, video,
* audio, and webcam.</p>
* <p>There is a set of creation methods, DOM manipulation methods, and
* an extended p5.Element that supports a range of HTML elements. See the
* <a href="https://github.com/processing/p5.js/wiki/Beyond-the-canvas">
* beyond the canvas tutorial</a> for a full overview of how this addon works.
*
* <p>Methods and properties shown in black are part of the p5.js core, items in
* blue are part of the p5.dom library. You will need to include an extra file
* in order to access the blue functions. See the
* <a href="http://p5js.org/libraries/#using-a-library">using a library</a>
* section for information on how to include this library. p5.dom comes with
* <a href="http://p5js.org/download">p5 complete</a> or you can download the single file
* <a href="https://raw.githubusercontent.com/lmccart/p5.js/master/lib/addons/p5.dom.js">
* here</a>.</p>
* <p>See <a href="https://github.com/processing/p5.js/wiki/Beyond-the-canvas">tutorial: beyond the canvas]</a>
* for more info on how to use this libary.</a>
*
* @module p5.dom
* @submodule p5.dom
* @for p5.dom
* @main
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd)
define('p5.dom', ['p5'], function (p5) { (factory(p5));});
else if (typeof exports === 'object')
factory(require('../p5'));
else
factory(root['p5']);
}(this, function (p5) {
// =============================================================================
// p5 additions
// =============================================================================
/**
* Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'
* prefixes to specify an ID or class respectively, and none for a tag) and returns it as
* a p5.Element. If a class or tag name is given with more than 1 element,
* only the first element will be returned.
* The DOM node itself can be accessed with .elt.
* Returns null if none found.
*
* @method select
* @param {String} name id, class, or tag name of element to search for
* @return {Object/p5.Element|Null} p5.Element containing node found
*/
p5.prototype.select = function (e) {
var res;
var str;
if (e[0] === '.'){
str = e.slice(1);
res = document.getElementsByClassName(str);
if (res) {
return wrapElement(res[0]);
}else {
return null;
}
}else if (e[0] === '#'){
str = e.slice(1);
res = document.getElementById(str);
if (res) {
return wrapElement(res);
}else {
return null;
}
}else{
res = document.getElementsByTagName(e);
if (res) {
return wrapElement(res[0]);
}else {
return null;
}
}
};
/**
* Searches the page for elements with the given class or tag name (using the '.' prefix
* to specify a class and no prefix for a tag) and returns them as p5.Elements
* in an array.
* The DOM node itself can be accessed with .elt.
* Returns null if none found.
*
* @method selectAll
* @param {String} name class or tag name of elements to search for
* @return {Array} Array of p5.Elements containing nodes found
*/
p5.prototype.selectAll = function (e) {
var arr = [];
var res;
var str;
if (e[0] === '.'){
str = e.slice(1);
res = document.getElementsByClassName(str);
}else {
res = document.getElementsByTagName(e);
}
if (res) {
for (var j = 0; j < res.length; j++) {
var obj = wrapElement(res[j]);
arr.push(obj);
}
}
return arr;
};
/**
* Helper function for getElement and getElements.
*/
function wrapElement(elt) {
if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") {
return new p5.MediaElement(elt);
} else {
return new p5.Element(elt);
}
}
/**
* Removes all elements created by p5, except any canvas / graphics
* elements created by createCanvas or createGraphics.
* Event handlers are removed, and element is removed from the DOM.
* @method removeElements
* @example
* <div class='norender'><code>
* function setup() {
* createCanvas(100, 100);
* createDiv('this is some text');
* createP('this is a paragraph');
* }
* function mousePressed() {
* removeElements(); // this will remove the div and p, not canvas
* }
* </code></div>
*
*/
p5.prototype.removeElements = function (e) {
for (var i=0; i<this._elements.length; i++) {
if (!(this._elements[i].elt instanceof HTMLCanvasElement)) {
this._elements[i].remove();
}
}
};
/**
* Helpers for create methods.
*/
function addElement(elt, pInst, media) {
var node = pInst._userNode ? pInst._userNode : document.body;
node.appendChild(elt);
var c = media ? new p5.MediaElement(elt) : new p5.Element(elt);
pInst._elements.push(c);
return c;
}
/**
* Creates a &lt;div&gt;&lt;/div&gt; element in the DOM with given inner HTML.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createDiv
* @param {String} html inner HTML for element created
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
/**
* Creates a &lt;p&gt;&lt;/p&gt; element in the DOM with given inner HTML. Used
* for paragraph length text.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createP
* @param {String} html inner HTML for element created
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
/**
* Creates a &lt;span&gt;&lt;/span&gt; element in the DOM with given inner HTML.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createSpan
* @param {String} html inner HTML for element created
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
var tags = ['div', 'p', 'span'];
tags.forEach(function(tag) {
var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1);
p5.prototype[method] = function(html) {
var elt = document.createElement(tag);
elt.innerHTML = typeof html === undefined ? "" : html;
return addElement(elt, this);
}
});
/**
* Creates an &lt;img /&gt; element in the DOM with given src and
* alternate text.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createImg
* @param {String} src src path or url for image
* @param {String} [alt] alternate text to be used if image does not load
* @param {Function} [successCallback] callback to be called once image data is loaded
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
p5.prototype.createImg = function() {
var elt = document.createElement('img');
var args = arguments;
var self = {};
var setAttrs = function(){
self.width = elt.width;
self.height = elt.height;
if (args.length === 3 && typeof args[2] === 'function'){
self.fn = args[2];
self.fn();
}
};
elt.src = args[0];
if (args.length > 1 && typeof args[1] === 'string'){
elt.alt = args[1];
}
if (elt.complete){
setAttrs();
}else{
elt.onload = function(){
setAttrs();
}
}
self = addElement(elt, this);
return self;
};
/**
* Creates an &lt;a&gt;&lt;/a&gt; element in the DOM for including a hyperlink.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createA
* @param {String} href url of page to link to
* @param {String} html inner html of link element to display
* @param {String} [target] target where new link should open,
* could be _blank, _self, _parent, _top.
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
p5.prototype.createA = function(href, html, target) {
var elt = document.createElement('a');
elt.href = href;
elt.innerHTML = html;
if (target) elt.target = target;
return addElement(elt, this);
};
/** INPUT **/
/**
* Creates a slider &lt;input&gt;&lt;/input&gt; element in the DOM.
* Use .size() to set the display length of the slider.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createSlider
* @param {Number} min minimum value of the slider
* @param {Number} max maximum value of the slider
* @param {Number} [value] default value of the slider
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
p5.prototype.createSlider = function(min, max, value, step) {
var elt = document.createElement('input');
elt.type = 'range';
elt.min = min;
elt.max = max;
if (step) elt.step = step;
if (value) elt.value = value;
return addElement(elt, this);
};
/**
* Creates a &lt;button&gt;&lt;/button&gt; element in the DOM.
* Use .size() to set the display size of the button.
* Use .mousePressed() to specify behavior on press.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createButton
* @param {String} label label displayed on the button
* @param {String} [value] value of the button
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
p5.prototype.createButton = function(label, value) {
var elt = document.createElement('button');
elt.innerHTML = label;
elt.value = value;
if (value) elt.value = value;
return addElement(elt, this);
};
/**
* Creates a checkbox &lt;input&gt;&lt;/input&gt; element in the DOM.
*
* @method createCheckbox
* @param {String} [label] label displayed after checkbox
* @param {boolean} [value] value of the checkbox; checked is true, unchecked is false. Unchecked if no value given
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
p5.prototype.createCheckbox = function() {
var elt = document.createElement('input');
elt.type = 'checkbox';
//checkbox must be wrapped in p5.Element before label so that label appears after
var self = addElement(elt, this);
self.checked = function(){
if (arguments.length === 0){
return self.elt.checked;
}else if(arguments[0]){
self.elt.checked = true;
}else{
self.elt.checked = false;
}
return self;
};
this.value = function(val){
self.value = val;
return this;
};
if (arguments[0]){
var ran = Math.random().toString(36).slice(2);
var label = document.createElement('label');
elt.setAttribute('id', ran);
label.htmlFor = ran;
self.value(arguments[0]);
label.appendChild(document.createTextNode(arguments[0]));
addElement(label, this);
}
if (arguments[1]){
elt.checked = true;
}
return self;
};
/**
* Creates a dropdown menu &lt;select&gt;&lt;/select&gt; element in the DOM.
* @method createSelect
* @param {boolean} [multiple] [true if dropdown should support multiple selections]
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
p5.prototype.createSelect = function(mult) {
var elt = document.createElement('select');
if (mult){
elt.setAttribute('multiple', 'true');
}
var self = addElement(elt, this);
self.option = function(name, value){
var opt = document.createElement('option');
opt.innerHTML = name;
if (arguments.length > 1)
opt.value = value;
else
opt.value = name;
elt.appendChild(opt);
};
self.selected = function(value){
var arr = [];
if (arguments.length > 0){
for (var i = 0; i < this.elt.length; i++){
if (value.toString() === this.elt[i].value){
this.elt.selectedIndex = i;
}
}
return this;
}else{
if (mult){
for (var i = 0; i < this.elt.selectedOptions.length; i++){
arr.push(this.elt.selectedOptions[i].value);
}
return arr;
}else{
return this.elt.value;
}
}
};
return self;
};
/**
* Creates an &lt;input&gt;&lt;/input&gt; element in the DOM for text input.
* Use .size() to set the display length of the box.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createInput
* @param {Number} [value] default value of the input box
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
p5.prototype.createInput = function(value) {
var elt = document.createElement('input');
elt.type = 'text';
if (value) elt.value = value;
return addElement(elt, this);
};
/**
* Creates an &lt;input&gt;&lt;/input&gt; element in the DOM of type 'file'.
* This allows users to select local files for use in a sketch.
*
* @method createFileInput
* @param {Function} [callback] callback function for when a file loaded
* @param {String} [multiple] optional to allow multiple files selected
* @return {Object/p5.Element} pointer to p5.Element holding created DOM element
*/
p5.prototype.createFileInput = function(callback, multiple) {
// Is the file stuff supported?
if (window.File && window.FileReader && window.FileList && window.Blob) {
// Yup, we're ok and make an input file selector
var elt = document.createElement('input');
elt.type = 'file';
// If we get a second argument that evaluates to true
// then we are looking for multiple files
if (multiple) {
// Anything gets the job done
elt.multiple = 'multiple';
}
// Now let's handle when a file was selected
elt.addEventListener('change', handleFileSelect, false);
// Function to handle when a file is selected
// We're simplifying life and assuming that we always
// want to load every selected file
function handleFileSelect(evt) {
// These are the files
var files = evt.target.files;
// Load each one and trigger a callback
for (var i = 0; i < files.length; i++) {
var f = files[i];
var reader = new FileReader();
reader.onload = makeLoader(f);
function makeLoader(theFile) {
// Making a p5.File object
var p5file = new p5.File(theFile);
return function(e) {
p5file.data = e.target.result;
callback(p5file);
};
};
// Text of data?
// This should likely be improved
if (f.type === 'text') {
reader.readAsText(f);
} else {
reader.readAsDataURL(f);
}
}
}
return addElement(elt, this);
} else {
console.log('The File APIs are not fully supported in this browser. Cannot create element.');
}
};
/** VIDEO STUFF **/
function createMedia(pInst, type, src, callback) {
var elt = document.createElement(type);
if (typeof src === 'string') {
src = [src];
}
for (var i=0; i<src.length; i++) {
var source = document.createElement('source');
source.src = src[i];
elt.appendChild(source);
}
if (typeof callback !== 'undefined') {
elt.addEventListener('canplaythrough', function() {
callback();
});
}
var c = addElement(elt, pInst, true);
c.loadedmetadata = false;
// set width and height onload metadata
elt.addEventListener('loadedmetadata', function() {
c.width = elt.videoWidth;
c.height = elt.videoHeight;
c.loadedmetadata = true;
});
return c;
}
/**
* Creates an HTML5 &lt;video&gt; element in the DOM for simple playback
* of audio/video. Shown by default, can be hidden with .hide()
* and drawn into canvas using video(). Appends to the container
* node if one is specified, otherwise appends to body. The first parameter
* can be either a single string path to a video file, or an array of string
* paths to different formats of the same video. This is useful for ensuring
* that your video can play across different browsers, as each supports
* different formats. See <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats">this
* page for further information about supported formats.
*
* @method createVideo
* @param {String|Array} src path to a video file, or array of paths for
* supporting different browsers
* @param {Object} [callback] callback function to be called upon
* 'canplaythrough' event fire, that is, when the
* browser can play the media, and estimates that
* enough data has been loaded to play the media
* up to its end without having to stop for
* further buffering of content
* @return {Object/p5.Element} pointer to video p5.Element
*/
p5.prototype.createVideo = function(src, callback) {
return createMedia(this, 'video', src, callback);
};
/** AUDIO STUFF **/
/**
* Creates a hidden HTML5 &lt;audio&gt; element in the DOM for simple audio
* playback. Appends to the container node if one is specified,
* otherwise appends to body. The first parameter
* can be either a single string path to a audio file, or an array of string
* paths to different formats of the same audio. This is useful for ensuring
* that your audio can play across different browsers, as each supports
* different formats. See <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats">this
* page for further information about supported formats.
*
* @method createAudio
* @param {String|Array} src path to an audio file, or array of paths for
* supporting different browsers
* @param {Object} [callback] callback function to be called upon
* 'canplaythrough' event fire, that is, when the
* browser can play the media, and estimates that
* enough data has been loaded to play the media
* up to its end without having to stop for
* further buffering of content
* @return {Object/p5.Element} pointer to audio p5.Element
*/
p5.prototype.createAudio = function(src, callback) {
return createMedia(this, 'audio', src, callback);
};
/** CAMERA STUFF **/
p5.prototype.VIDEO = 'video';
p5.prototype.AUDIO = 'audio';
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
/**
* Creates a new &lt;video&gt; element that contains the audio/video feed
* from a webcam. This can be drawn onto the canvas using video(). More
* specific properties of the stream can be passing in a Constraints object.
* See the
* <a href="http://w3c.github.io/mediacapture-main/getusermedia.html">W3C
* spec</a> for possible properties. Note that not all of these are supported
* by all browsers.
*
* @method createCapture
* @param {String|Constant|Object} type type of capture, either VIDEO or
* AUDIO if none specified, default both,
* or a Constraints boject
* @param {Function} callback function to be called once
* stream has loaded
* @return {Object/p5.Element} capture video p5.Element
* @example
* <div><class='norender'><code>
* var capture;
*
* function setup() {
* createCanvas(480, 120);
* capture = createCapture(VIDEO);
* }
*
* function draw() {
* image(capture, 0, 0, width, width*capture.height/capture.width);
* filter(INVERT);
* }
* </code></div>
* <div><class='norender'><code>
* function setup() {
* createCanvas(480, 120);
* var constraints = {
* video: {
* mandatory: {
* minWidth: 1280,
* minHeight: 720
* },
* optional: [
* { maxFrameRate: 10 }
* ]
* },
* audio: true
* };
* createCapture(constraints, function(stream) {
* console.log(stream);
* });
* }
* </code></div>
*/
p5.prototype.createCapture = function() {
var useVideo = true;
var useAudio = true;
var constraints;
var cb;
for (var i=0; i<arguments.length; i++) {
if (arguments[i] === p5.prototype.VIDEO) {
useAudio = false;
} else if (arguments[i] === p5.prototype.AUDIO) {
useVideo = false;
} else if (typeof arguments[i] === 'object') {
constraints = arguments[i];
} else if (typeof arguments[i] === 'function') {
cb = arguments[i];
}
}
if (navigator.getUserMedia) {
var elt = document.createElement('video');
if (!constraints) {
constraints = {video: useVideo, audio: useAudio};
}
navigator.getUserMedia(constraints, function(stream) {
elt.src = window.URL.createObjectURL(stream);
elt.play();
if (cb) {
cb(stream);
}
}, function(e) { console.log(e); });
} else {
throw 'getUserMedia not supported in this browser';
}
var c = addElement(elt, this, true);
c.loadedmetadata = false;
// set width and height onload metadata
elt.addEventListener('loadedmetadata', function() {
c.width = elt.videoWidth;
c.height = elt.videoHeight;
c.loadedmetadata = true;
});
return c;
};
/**
* Creates element with given tag in the DOM with given content.
* Appends to the container node if one is specified, otherwise
* appends to body.
*
* @method createElement
* @param {String} tag tag for the new element
* @param {String} [content] html content to be inserted into the element
* @return {Object/p5.Element} pointer to p5.Element holding created node
*/
p5.prototype.createElement = function(tag, content) {
var elt = document.createElement(tag);
if (typeof content !== 'undefined') {
elt.innerHTML = content;
}
return addElement(elt, this);
};
// =============================================================================
// p5.Element additions
// =============================================================================
/**
*
* Adds specified class to the element.
*
* @for p5.Element
* @method addClass
* @param {String} class name of class to add
* @return {Object/p5.Element}
*/
p5.Element.prototype.addClass = function(c) {
if (this.elt.className) {
// PEND don't add class more than once
//var regex = new RegExp('[^a-zA-Z\d:]?'+c+'[^a-zA-Z\d:]?');
//if (this.elt.className.search(/[^a-zA-Z\d:]?hi[^a-zA-Z\d:]?/) === -1) {
this.elt.className = this.elt.className+' '+c;
//}
} else {
this.elt.className = c;
}
return this;
}
/**
*
* Removes specified class from the element.
*
* @method removeClass
* @param {String} class name of class to remove
* @return {Object/p5.Element}
*/
p5.Element.prototype.removeClass = function(c) {
var regex = new RegExp('(?:^|\\s)'+c+'(?!\\S)');
this.elt.className = this.elt.className.replace(regex, '');
this.elt.className = this.elt.className.replace(/^\s+|\s+$/g, ""); //prettify (optional)
return this;
}
/**
*
* Attaches the element as a child to the parent specified.
* Accepts either a string ID, DOM node, or p5.Element
*
* @method child
* @param {String|Object/p5.Element} child the ID, DOM node, or p5.Element
* to add to the current element
* @return {p5.Element}
* @example
* <div class='norender'><code>
* var div0 = createDiv('this is the parent');
* var div1 = createDiv('this is the child');
* div0.child(div1); // use p5.Element
* </code></div>
* <div class='norender'><code>
* var div0 = createDiv('this is the parent');
* var div1 = createDiv('this is the child');
* div1.id('apples');
* div0.child('apples'); // use id
* </code></div>
* <div class='norender'><code>
* var div0 = createDiv('this is the parent');
* var elt = document.getElementById('myChildDiv');
* div0.child(elt); // use element from page
* </code></div>
*/
p5.Element.prototype.child = function(c) {
if (typeof c === 'string') {
c = document.getElementById(c);
} else if (c instanceof p5.Element) {
c = c.elt;
}
this.elt.appendChild(c);
return this;
};
/**
*
* If an argument is given, sets the inner HTML of the element,
* replacing any existing html. If no arguments are given, returns
* the inner HTML of the element.
*
* @for p5.Element
* @method html
* @param {String} [html] the HTML to be placed inside the element
* @return {Object/p5.Element|String}
*/
p5.Element.prototype.html = function(html) {
if (typeof html !== 'undefined') {
this.elt.innerHTML = html;
return this;
} else {
return this.elt.innerHTML;
}
};
/**
*
* Sets the position of the element relative to (0, 0) of the
* window. Essentially, sets position:absolute and left and top
* properties of style. If no arguments given returns the x and y position
* of the element in an object.
*
* @method position
* @param {Number} [x] x-position relative to upper left of window
* @param {Number} [y] y-position relative to upper left of window
* @return {Object/p5.Element}
* @example
* <div><code class='norender'>
* function setup() {
* var cnv = createCanvas(100, 100);
* // positions canvas 50px to the right and 100px
* // below upper left corner of the window
* cnv.position(50, 100);
* }
* </code></div>
*/
p5.Element.prototype.position = function() {
if (arguments.length === 0){
return { 'x' : this.elt.offsetLeft , 'y' : this.elt.offsetTop };
}else{
this.elt.style.position = 'absolute';
this.elt.style.left = arguments[0]+'px';
this.elt.style.top = arguments[1]+'px';
this.x = arguments[0];
this.y = arguments[1];
return this;
}
};
/**
* Translates an element with css transforms in either 2d (if 2 arguments given)
* or 3d (if 3 arguments given) space.
* @method translate
* @param {Number} x x-position in px
* @param {Number} y y-position in px
* @param {Number} [z] z-position in px
* @param {Number} [perspective] sets the perspective of the parent element in px,
* default value set to 1000px
* @return {Object/p5.Element}
* @example
* <div><code>
* function setup() {
* createCanvas(100,100);
* //translates canvas 50px down
* select('canvas').translate(0,50);
* }
* </code></div>
*/
p5.Element.prototype.translate = function(){
this.elt.style.position = 'absolute';
if (arguments.length === 2){
var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
style = style.replace(/translate[X-Z]?\(.*\)/g, '');
this.elt.style.transform = 'translate('+arguments[0]+'px, '+arguments[1]+'px)';
this.elt.style.transform += style;
}else if (arguments.length === 3){
var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
style = style.replace(/translate[X-Z]?\(.*\)/g, '');
this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
this.elt.style.transform += style;
this.elt.parentElement.style.perspective = '1000px';
}else if (arguments.length === 4){
var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
style = style.replace(/translate[X-Z]?\(.*\)/g, '');
this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
this.elt.style.transform += style;
this.elt.parentElement.style.perspective = arguments[3]+'px';
}
return this;
};
/**
* Rotates an element with css transforms in either 2d (if 2 arguments given)
* or 3d (if 3 arguments given) space.
* @method rotate
* @param {Number} x amount of degrees to rotate the element along the x-axis in deg
* @param {Number} [y] amount of degrees to rotate the element along the y-axis in deg
* @param {Number} [z] amount of degrees to rotate the element along the z-axis in deg
* @return {Object/p5.Element}
* @example
* <div><code>
* var x = 0,
* y = 0,
* z = 0;
* function setup(){
* createCanvas(100,100);
* }
* function draw(){
* x+=.5 % 360;
* y+=.5 % 360;
* z+=.5 % 360;
* //rotates the canvas .5deg (degrees) on every axis each frame.
* select('canvas').rotate(x,y,z);
* }
* </code></div>
*/
p5.Element.prototype.rotate = function(){
if (arguments.length === 1){
var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
this.elt.style.transform = 'rotate('+arguments[0]+'deg)';
this.elt.style.transform += style;
}else if (arguments.length === 2){
var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
this.elt.style.transform = 'rotate('+arguments[0]+'deg, '+arguments[1]+'deg)';
this.elt.style.transform += style;
}else if (arguments.length === 3){
var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
this.elt.style.transform = 'rotateX('+arguments[0]+'deg)';
this.elt.style.transform += 'rotateY('+arguments[1]+'deg)';
this.elt.style.transform += 'rotateZ('+arguments[2]+'deg)';
this.elt.style.transform += style;
}
return this;
};
/**
* Sets the given style (css) property of the element with the given value.
* If no value is specified, returns the value of the given property,
* or undefined if the property is not.
*
* @method style
* @param {String} property property to be set
* @param {String} [value] value to assign to property
* @return {String|Object/p5.Element} value of property, if no value is specified
* or p5.Element
* @example
* <div><code class="norender">
* var myDiv = createDiv("I like pandas.");
* myDiv.style("color", "#ff0000");
* myDiv.style("font-size", "18px");
* </code></div>
*/
p5.Element.prototype.style = function(prop, val) {
if (typeof val === 'undefined') {
var attrs = prop.split(';');
for (var i=0; i<attrs.length; i++) {
var parts = attrs[i].split(':');
if (parts[0] && parts[1]) {
this.elt.style[parts[0].trim()] = parts[1].trim();
}
}
} else {
this.elt.style[prop] = val;
if (prop === 'width' || prop === 'height' || prop === 'left' || prop === 'top'){
var numVal = val.replace(/\D+/g,'');
this[prop] = parseInt(numVal);
}
}
return this;
};
/**
*
* Adds a new attribute or changes the value of an existing attribute
* on the specified element. If no value is specified, returns the
* value of the given attribute, or null if attribute is not set.
*
* @method attribute
* @param {String} attr attribute to set
* @param {String} [value] value to assign to attribute
* @return {String|Object/p5.Element} value of attribute, if no value is
* specified or p5.Element
* @example
* <div class="norender"><code>
* var myDiv = createDiv("I like pandas.");
*myDiv.attribute("align", "center");
* </code></div>
*/
p5.Element.prototype.attribute = function(attr, value) {
if (typeof value === 'undefined') {
return this.elt.getAttribute(attr);
} else {
this.elt.setAttribute(attr, value);
return this;
}
};
/**
* Either returns the value of the element if no arguments
* given, or sets the value of the element.
*
* @method value
* @param {String|Number} [value]
* @return {String|Object/p5.Element} value of element if no value is specified or p5.Element
*/
p5.Element.prototype.value = function() {
if (arguments.length > 0) {
this.elt.value = arguments[0];
return this;
} else {
if (this.elt.type === 'range') {
return parseFloat(this.elt.value);
}
else return this.elt.value;
}
};
/**
*
* Shows the current element. Essentially, setting display:block for the style.
*
* @method show
* @return {Object/p5.Element}
*/
p5.Element.prototype.show = function() {
this.elt.style.display = 'block';
return this;
};
/**
* Hides the current element. Essentially, setting display:none for the style.
*
* @method hide
* @return {Object/p5.Element}
*/
p5.Element.prototype.hide = function() {
this.elt.style.display = 'none';
return this;
};
/**
*
* Sets the width and height of the element. AUTO can be used to
* only adjust one dimension. If no arguments given returns the width and height
* of the element in an object.
*
* @method size
* @param {Number} [w] width of the element
* @param {Number} [h] height of the element
* @return {Object/p5.Element}
*/
p5.Element.prototype.size = function(w, h) {
if (arguments.length === 0){
return { 'width' : this.elt.offsetWidth , 'height' : this.elt.offsetHeight };
}else{
var aW = w;
var aH = h;
var AUTO = p5.prototype.AUTO;
if (aW !== AUTO || aH !== AUTO) {
if (aW === AUTO) {
aW = h * this.width / this.height;
} else if (aH === AUTO) {
aH = w * this.height / this.width;
}
// set diff for cnv vs normal div
if (this.elt instanceof HTMLCanvasElement) {
var j = {};
var k = this.elt.getContext('2d');
for (var prop in k) {
j[prop] = k[prop];
}
this.elt.setAttribute('width', aW * this._pInst._pixelDensity);
this.elt.setAttribute('height', aH * this._pInst._pixelDensity);
this.elt.setAttribute('style', 'width:' + aW + 'px; height:' + aH + 'px');
this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity);
for (var prop in j) {
this.elt.getContext('2d')[prop] = j[prop];
}
} else {
this.elt.style.width = aW+'px';
this.elt.style.height = aH+'px';
this.elt.width = aW;
this.elt.height = aH;
this.width = aW;
this.height = aH;
}
this.elt.style.overflow = 'hidden';
this.width = this.elt.offsetWidth;
this.height = this.elt.offsetHeight;
if (this._pInst) { // main canvas associated with p5 instance
if (this._pInst._curElement.elt === this.elt) {
this._pInst._setProperty('width', this.elt.offsetWidth);
this._pInst._setProperty('height', this.elt.offsetHeight);
}
}
}
return this;
}
};
/**
* Removes the element and deregisters all listeners.
* @method remove
* @example
* <div class='norender'><code>
* var myDiv = createDiv('this is some text');
* myDiv.remove();
* </code></div>
*/
p5.Element.prototype.remove = function() {
// deregister events
for (var ev in this._events) {
this.elt.removeEventListener(ev, this._events[ev]);
}
if (this.elt.parentNode) {
this.elt.parentNode.removeChild(this.elt);
}
delete(this);
};
// =============================================================================
// p5.MediaElement additions
// =============================================================================
/**
* Extends p5.Element to handle audio and video. In addition to the methods
* of p5.Element, it also contains methods for controlling media. It is not
* called directly, but p5.MediaElements are created by calling createVideo,
* createAudio, and createCapture.
*
* @class p5.MediaElement
* @constructor
* @param {String} elt DOM node that is wrapped
* @param {Object} [pInst] pointer to p5 instance
*/
p5.MediaElement = function(elt, pInst) {
p5.Element.call(this, elt, pInst);
this._prevTime = 0;
this._cueIDCounter = 0;
this._cues = [];
this.pixelDensity = 1;
};
p5.MediaElement.prototype = Object.create(p5.Element.prototype);
/**
* Play an HTML5 media element.
*
* @method play
* @return {Object/p5.Element}
*/
p5.MediaElement.prototype.play = function() {
if (this.elt.currentTime === this.elt.duration) {
this.elt.currentTime = 0;
}
if (this.elt.readyState > 1) {
this.elt.play();
} else {
// in Chrome, playback cannot resume after being stopped and must reload
this.elt.load();
this.elt.play();
}
return this;
};
/**
* Stops an HTML5 media element (sets current time to zero).
*
* @method stop
* @return {Object/p5.Element}
*/
p5.MediaElement.prototype.stop = function() {
this.elt.pause();
this.elt.currentTime = 0;
return this;
};
/**
* Pauses an HTML5 media element.
*
* @method pause
* @return {Object/p5.Element}
*/
p5.MediaElement.prototype.pause = function() {
this.elt.pause();
return this;
};
/**
* Set 'loop' to true for an HTML5 media element, and starts playing.
*
* @method loop
* @return {Object/p5.Element}
*/
p5.MediaElement.prototype.loop = function() {
this.elt.setAttribute('loop', true);
this.play();
return this;
};
/**
* Set 'loop' to false for an HTML5 media element. Element will stop
* when it reaches the end.
*
* @method noLoop
* @return {Object/p5.Element}
*/
p5.MediaElement.prototype.noLoop = function() {
this.elt.setAttribute('loop', false);
return this;
};
/**
* Set HTML5 media element to autoplay or not.
*
* @method autoplay
* @param {Boolean} autoplay whether the element should autoplay
* @return {Object/p5.Element}
*/
p5.MediaElement.prototype.autoplay = function(val) {
this.elt.setAttribute('autoplay', val);
return this;
};
/**
* Sets volume for this HTML5 media element. If no argument is given,
* returns the current volume.
*
* @param {Number} [val] volume between 0.0 and 1.0
* @return {Number|p5.MediaElement} current volume or p5.MediaElement
* @method volume
*/
p5.MediaElement.prototype.volume = function(val) {
if (typeof val === 'undefined') {
return this.elt.volume;
} else {
this.elt.volume = val;
}
};
/**
* If no arguments are given, returns the current time of the elmeent.
* If an argument is given the current time of the element is set to it.
*
* @method time
* @param {Number} [time] time to jump to (in seconds)
* @return {Number|Object/p5.MediaElement} current time (in seconds)
* or p5.MediaElement
*/
p5.MediaElement.prototype.time = function(val) {
if (typeof val === 'undefined') {
return this.elt.currentTime;
} else {
this.elt.currentTime = val;
}
};
/**
* Returns the duration of the HTML5 media element.
*
* @method duration
* @return {Number} duration
*/
p5.MediaElement.prototype.duration = function() {
return this.elt.duration;
};
p5.MediaElement.prototype.pixels = [];
p5.MediaElement.prototype.loadPixels = function() {
if (this.loadedmetadata) { // wait for metadata for w/h
if (!this.canvas) {
this.canvas = document.createElement('canvas');
this.canvas.width = this.width;
this.canvas.height = this.height;
this.drawingContext = this.canvas.getContext('2d');
}
this.drawingContext.drawImage(this.elt, 0, 0, this.width, this.height);
p5.Renderer2D.prototype.loadPixels.call(this);
}
return this;
}
p5.MediaElement.prototype.updatePixels = function(x, y, w, h){
if (this.loadedmetadata) { // wait for metadata
p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
}
return this;
}
p5.MediaElement.prototype.get = function(x, y, w, h){
if (this.loadedmetadata) { // wait for metadata
return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
} else return [0, 0, 0, 255];
};
p5.MediaElement.prototype.set = function(x, y, imgOrCol){
if (this.loadedmetadata) { // wait for metadata
p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
}
};
/*** CONNECT TO WEB AUDIO API / p5.sound.js ***/
/**
* Send the audio output of this element to a specified audioNode or
* p5.sound object. If no element is provided, connects to p5's master
* output. That connection is established when this method is first called.
* All connections are removed by the .disconnect() method.
*
* This method is meant to be used with the p5.sound.js addon library.
*
* @method connect
* @param {AudioNode|p5.sound object} audioNode AudioNode from the Web Audio API,
* or an object from the p5.sound library
*/
p5.MediaElement.prototype.connect = function(obj) {
var audioContext, masterOutput;
// if p5.sound exists, same audio context
if (typeof p5.prototype.getAudioContext === 'function') {
audioContext = p5.prototype.getAudioContext();
masterOutput = p5.soundOut.input;
} else {
try {
audioContext = obj.context;
masterOutput = audioContext.destination
} catch(e) {
throw 'connect() is meant to be used with Web Audio API or p5.sound.js'
}
}
// create a Web Audio MediaElementAudioSourceNode if none already exists
if (!this.audioSourceNode) {
this.audioSourceNode = audioContext.createMediaElementSource(this.elt);
// connect to master output when this method is first called
this.audioSourceNode.connect(masterOutput);
}
// connect to object if provided
if (obj) {
if (obj.input) {
this.audioSourceNode.connect(obj.input);
} else {
this.audioSourceNode.connect(obj);
}
}
// otherwise connect to master output of p5.sound / AudioContext
else {
this.audioSourceNode.connect(masterOutput);
}
};
/**
* Disconnect all Web Audio routing, including to master output.
* This is useful if you want to re-route the output through
* audio effects, for example.
*
* @method disconnect
*/
p5.MediaElement.prototype.disconnect = function() {
if (this.audioSourceNode) {
this.audioSourceNode.disconnect();
} else {
throw 'nothing to disconnect';
}
};
/*** SHOW / HIDE CONTROLS ***/
/**
* Show the default MediaElement controls, as determined by the web browser.
*
* @method showControls
*/
p5.MediaElement.prototype.showControls = function() {
// must set style for the element to show on the page
this.elt.style['text-align'] = 'inherit';
this.elt.controls = true;
};
/**
* Hide the default mediaElement controls.
*
* @method hideControls
*/
p5.MediaElement.prototype.hideControls = function() {
this.elt.controls = false;
};
/*** SCHEDULE EVENTS ***/
/**
* Schedule events to trigger every time a MediaElement
* (audio/video) reaches a playback cue point.
*
* Accepts a callback function, a time (in seconds) at which to trigger
* the callback, and an optional parameter for the callback.
*
* Time will be passed as the first parameter to the callback function,
* and param will be the second parameter.
*
*
* @method addCue
* @param {Number} time Time in seconds, relative to this media
* element's playback. For example, to trigger
* an event every time playback reaches two
* seconds, pass in the number 2. This will be
* passed as the first parameter to
* the callback function.
* @param {Function} callback Name of a function that will be
* called at the given time. The callback will
* receive time and (optionally) param as its
* two parameters.
* @param {Object} [value] An object to be passed as the
* second parameter to the
* callback function.
* @return {Number} id ID of this cue,
* useful for removeCue(id)
* @example
* <div><code>
* function setup() {
* background(255,255,255);
*
* audioEl = createAudio('assets/beat.mp3');
* audioEl.showControls();
*
* // schedule three calls to changeBackground
* audioEl.addCue(0.5, changeBackground, color(255,0,0) );
* audioEl.addCue(1.0, changeBackground, color(0,255,0) );
* audioEl.addCue(2.5, changeBackground, color(0,0,255) );
* audioEl.addCue(3.0, changeBackground, color(0,255,255) );
* audioEl.addCue(4.2, changeBackground, color(255,255,0) );
* audioEl.addCue(5.0, changeBackground, color(255,255,0) );
* }
*
* function changeBackground(val) {
* background(val);
* }
* </code></div>
*/
p5.MediaElement.prototype.addCue = function(time, callback, val) {
var id = this._cueIDCounter++;
var cue = new Cue(callback, time, id, val);
this._cues.push(cue);
if (!this.elt.ontimeupdate) {
this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
}
return id;
};
/**
* Remove a callback based on its ID. The ID is returned by the
* addCue method.
*
* @method removeCue
* @param {Number} id ID of the cue, as returned by addCue
*/
p5.MediaElement.prototype.removeCue = function(id) {
for (var i = 0; i < this._cues.length; i++) {
var cue = this._cues[i];
if (cue.id === id) {
this.cues.splice(i, 1);
}
}
if (this._cues.length === 0) {
this.elt.ontimeupdate = null
}
};
/**
* Remove all of the callbacks that had originally been scheduled
* via the addCue method.
*
* @method clearCues
*/
p5.MediaElement.prototype.clearCues = function() {
this._cues = [];
this.elt.ontimeupdate = null;
};
// private method that checks for cues to be fired if events
// have been scheduled using addCue(callback, time).
p5.MediaElement.prototype._onTimeUpdate = function() {
var playbackTime = this.time();
for (var i = 0 ; i < this._cues.length; i++) {
var callbackTime = this._cues[i].time;
var val = this._cues[i].val;
if (this._prevTime < callbackTime && callbackTime <= playbackTime) {
// pass the scheduled callbackTime as parameter to the callback
this._cues[i].callback(val);
}
}
this._prevTime = playbackTime;
};
// Cue inspired by JavaScript setTimeout, and the
// Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
var Cue = function(callback, time, id, val) {
this.callback = callback;
this.time = time;
this.id = id;
this.val = val;
};
// =============================================================================
// p5.File
// =============================================================================
/**
* Base class for a file
* Using this for createFileInput
*
* @class p5.File
* @constructor
* @param {File} file File that is wrapped
* @param {Object} [pInst] pointer to p5 instance
*/
p5.File = function(file, pInst) {
/**
* Underlying File object. All normal File methods can be called on this.
*
* @property file
*/
this.file = file;
this._pInst = pInst;
// Splitting out the file type into two components
// This makes determining if image or text etc simpler
var typeList = file.type.split('/');
/**
* File type (image, text, etc.)
*
* @property type
*/
this.type = typeList[0];
/**
* File subtype (usually the file extension jpg, png, xml, etc.)
*
* @property subtype
*/
this.subtype = typeList[1];
/**
* File name
*
* @property name
*/
this.name = file.name;
/**
* File size
*
* @property size
*/
this.size = file.size;
// Data not loaded yet
this.data = undefined;
};
}));
/*! p5.js v0.4.9 September 03, 2015 */ !function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.p5=a()}}(function(){var define,module,exports;return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){},{}],2:[function(a,b,c){"use strict";c.argument=function(a,b){if(!a)throw new Error(b)},c.assert=c.argument},{}],3:[function(a,b,c){"use strict";function d(a,b,c,d,e){a.beginPath(),a.moveTo(b,c),a.lineTo(d,e),a.stroke()}c.line=d},{}],4:[function(a,b,c){"use strict";function d(a){this.font=a}function e(a){this.cmap=a}function f(a,b){this.encoding=a,this.charset=b}function g(a){var b;switch(a.version){case 1:this.names=c.standardNames.slice();break;case 2:for(this.names=new Array(a.numberOfGlyphs),b=0;b<a.numberOfGlyphs;b++)a.glyphNameIndex[b]<c.standardNames.length?this.names[b]=c.standardNames[a.glyphNameIndex[b]]:this.names[b]=a.names[a.glyphNameIndex[b]-c.standardNames.length];break;case 2.5:for(this.names=new Array(a.numberOfGlyphs),b=0;b<a.numberOfGlyphs;b++)this.names[b]=c.standardNames[b+a.glyphNameIndex[b]];break;case 3:this.names=[]}}function h(a){for(var b,c=a.tables.cmap.glyphIndexMap,d=Object.keys(c),e=0;e<d.length;e+=1){var f=d[e],g=c[f];b=a.glyphs.get(g),b.addUnicode(parseInt(f))}for(e=0;e<a.glyphs.length;e+=1)b=a.glyphs.get(e),a.cffEncoding?b.name=a.cffEncoding.charset[e]:b.name=a.glyphNames.glyphIndexToName(e)}var i=[".notdef","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","exclamdown","cent","sterling","fraction","yen","florin","section","currency","quotesingle","quotedblleft","guillemotleft","guilsinglleft","guilsinglright","fi","fl","endash","dagger","daggerdbl","periodcentered","paragraph","bullet","quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis","perthousand","questiondown","grave","acute","circumflex","tilde","macron","breve","dotaccent","dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash","AE","ordfeminine","Lslash","Oslash","OE","ordmasculine","ae","dotlessi","lslash","oslash","oe","germandbls","onesuperior","logicalnot","mu","trademark","Eth","onehalf","plusminus","Thorn","onequarter","divide","brokenbar","degree","thorn","threequarters","twosuperior","registered","minus","eth","multiply","threesuperior","copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring","Atilde","Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute","Ocircumflex","Odieresis","Ograve","Otilde","Scaron","Uacute","Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron","aacute","acircumflex","adieresis","agrave","aring","atilde","ccedilla","eacute","ecircumflex","edieresis","egrave","iacute","icircumflex","idieresis","igrave","ntilde","oacute","ocircumflex","odieresis","ograve","otilde","scaron","uacute","ucircumflex","udieresis","ugrave","yacute","ydieresis","zcaron","exclamsmall","Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior","266 ff","onedotenleader","zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior","threequartersemdash","periodsuperior","questionsmall","asuperior","bsuperior","centsuperior","dsuperior","esuperior","isuperior","lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior","tsuperior","ff","ffi","ffl","parenleftinferior","parenrightinferior","Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall","Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall","Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","exclamdownsmall","centoldstyle","Lslashsmall","Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall","Dotaccentsmall","Macronsmall","figuredash","hypheninferior","Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall","oneeighth","threeeighths","fiveeighths","seveneighths","onethird","twothirds","zerosuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","eightsuperior","ninesuperior","zeroinferior","oneinferior","twoinferior","threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior","eightinferior","nineinferior","centinferior","dollarinferior","periodinferior","commainferior","Agravesmall","Aacutesmall","Acircumflexsmall","Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall","Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall","Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall","Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall","Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall","Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall","Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003","Black","Bold","Book","Light","Medium","Regular","Roman","Semibold"],j=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","exclamdown","cent","sterling","fraction","yen","florin","section","currency","quotesingle","quotedblleft","guillemotleft","guilsinglleft","guilsinglright","fi","fl","","endash","dagger","daggerdbl","periodcentered","","paragraph","bullet","quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis","perthousand","","questiondown","","grave","acute","circumflex","tilde","macron","breve","dotaccent","dieresis","","ring","cedilla","","hungarumlaut","ogonek","caron","emdash","","","","","","","","","","","","","","","","","AE","","ordfeminine","","","","","Lslash","Oslash","OE","ordmasculine","","","","","","ae","","","","dotlessi","","","lslash","oslash","oe","germandbls"],k=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","exclamsmall","Hungarumlautsmall","","dollaroldstyle","dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period","fraction","zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","colon","semicolon","commasuperior","threequartersemdash","periodsuperior","questionsmall","","asuperior","bsuperior","centsuperior","dsuperior","esuperior","","","isuperior","","","lsuperior","msuperior","nsuperior","osuperior","","","rsuperior","ssuperior","tsuperior","","ff","fi","fl","ffi","ffl","parenleftinferior","","parenrightinferior","Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall","Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall","Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","exclamdownsmall","centoldstyle","Lslashsmall","","","Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall","","Dotaccentsmall","","","Macronsmall","","","figuredash","hypheninferior","","","Ogoneksmall","Ringsmall","Cedillasmall","","","","onequarter","onehalf","threequarters","questiondownsmall","oneeighth","threeeighths","fiveeighths","seveneighths","onethird","twothirds","","","zerosuperior","onesuperior","twosuperior","threesuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","eightsuperior","ninesuperior","zeroinferior","oneinferior","twoinferior","threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior","eightinferior","nineinferior","centinferior","dollarinferior","periodinferior","commainferior","Agravesmall","Aacutesmall","Acircumflexsmall","Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall","Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall","Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall","Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall","Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall","Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall","Thornsmall","Ydieresissmall"],l=[".notdef",".null","nonmarkingreturn","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","grave","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","Adieresis","Aring","Ccedilla","Eacute","Ntilde","Odieresis","Udieresis","aacute","agrave","acircumflex","adieresis","atilde","aring","ccedilla","eacute","egrave","ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis","ntilde","oacute","ograve","ocircumflex","odieresis","otilde","uacute","ugrave","ucircumflex","udieresis","dagger","degree","cent","sterling","section","bullet","paragraph","germandbls","registered","copyright","trademark","acute","dieresis","notequal","AE","Oslash","infinity","plusminus","lessequal","greaterequal","yen","mu","partialdiff","summation","product","pi","integral","ordfeminine","ordmasculine","Omega","ae","oslash","questiondown","exclamdown","logicalnot","radical","florin","approxequal","Delta","guillemotleft","guillemotright","ellipsis","nonbreakingspace","Agrave","Atilde","Otilde","OE","oe","endash","emdash","quotedblleft","quotedblright","quoteleft","quoteright","divide","lozenge","ydieresis","Ydieresis","fraction","currency","guilsinglleft","guilsinglright","fi","fl","daggerdbl","periodcentered","quotesinglbase","quotedblbase","perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex","apple","Ograve","Uacute","Ucircumflex","Ugrave","dotlessi","circumflex","tilde","macron","breve","dotaccent","ring","cedilla","hungarumlaut","ogonek","caron","Lslash","lslash","Scaron","scaron","Zcaron","zcaron","brokenbar","Eth","eth","Yacute","yacute","Thorn","thorn","minus","multiply","onesuperior","twosuperior","threesuperior","onehalf","onequarter","threequarters","franc","Gbreve","gbreve","Idotaccent","Scedilla","scedilla","Cacute","cacute","Ccaron","ccaron","dcroat"];d.prototype.charToGlyphIndex=function(a){var b=a.charCodeAt(0),c=this.font.glyphs;if(!c)return null;for(var d=0;d<c.length;d+=1)for(var e=c.get(d),f=0;f<e.unicodes.length;f+=1)if(e.unicodes[f]===b)return d},e.prototype.charToGlyphIndex=function(a){return this.cmap.glyphIndexMap[a.charCodeAt(0)]||0},f.prototype.charToGlyphIndex=function(a){var b=a.charCodeAt(0),c=this.encoding[b];return this.charset.indexOf(c)},g.prototype.nameToGlyphIndex=function(a){return this.names.indexOf(a)},g.prototype.glyphIndexToName=function(a){return this.names[a]},c.cffStandardStrings=i,c.cffStandardEncoding=j,c.cffExpertEncoding=k,c.standardNames=l,c.DefaultEncoding=d,c.CmapEncoding=e,c.CffEncoding=f,c.GlyphNames=g,c.addGlyphNames=h},{}],5:[function(a,b,c){"use strict";function d(a){a=a||{},this.names={fontFamily:{en:a.familyName||" "},fontSubfamily:{en:a.styleName||" "},designer:{en:a.designer||" "},designerURL:{en:a.designerURL||" "},manufacturer:{en:a.manufacturer||" "},manufacturerURL:{en:a.manufacturerURL||" "},license:{en:a.license||" "},licenseURL:{en:a.licenseURL||" "},version:{en:a.version||"Version 0.1"},description:{en:a.description||" "},copyright:{en:a.copyright||" "},trademark:{en:a.trademark||" "}},this.unitsPerEm=a.unitsPerEm||1e3,this.ascender=a.ascender,this.descender=a.descender,this.supported=!0,this.glyphs=new h.GlyphSet(this,a.glyphs||[]),this.encoding=new g.DefaultEncoding(this),this.tables={}}var e=a("./path"),f=a("./tables/sfnt"),g=a("./encoding"),h=a("./glyphset");d.prototype.hasChar=function(a){return null!==this.encoding.charToGlyphIndex(a)},d.prototype.charToGlyphIndex=function(a){return this.encoding.charToGlyphIndex(a)},d.prototype.charToGlyph=function(a){var b=this.charToGlyphIndex(a),c=this.glyphs.get(b);return c||(c=this.glyphs.get(0)),c},d.prototype.stringToGlyphs=function(a){for(var b=[],c=0;c<a.length;c+=1){var d=a[c];b.push(this.charToGlyph(d))}return b},d.prototype.nameToGlyphIndex=function(a){return this.glyphNames.nameToGlyphIndex(a)},d.prototype.nameToGlyph=function(a){var b=this.nametoGlyphIndex(a),c=this.glyphs.get(b);return c||(c=this.glyphs.get(0)),c},d.prototype.glyphIndexToName=function(a){return this.glyphNames.glyphIndexToName?this.glyphNames.glyphIndexToName(a):""},d.prototype.getKerningValue=function(a,b){a=a.index||a,b=b.index||b;var c=this.getGposKerningValue;return c?c(a,b):this.kerningPairs[a+","+b]||0},d.prototype.forEachGlyph=function(a,b,c,d,e,f){b=void 0!==b?b:0,c=void 0!==c?c:0,d=void 0!==d?d:72,e=e||{};for(var g=void 0===e.kerning?!0:e.kerning,h=1/this.unitsPerEm*d,i=this.stringToGlyphs(a),j=0;j<i.length;j+=1){var k=i[j];if(f(k,b,c,d,e),k.advanceWidth&&(b+=k.advanceWidth*h),g&&j<i.length-1){var l=this.getKerningValue(k,i[j+1]);b+=l*h}}},d.prototype.getPath=function(a,b,c,d,f){var g=new e.Path;return this.forEachGlyph(a,b,c,d,f,function(a,b,c,d){var e=a.getPath(b,c,d);g.extend(e)}),g},d.prototype.draw=function(a,b,c,d,e,f){this.getPath(b,c,d,e,f).draw(a)},d.prototype.drawPoints=function(a,b,c,d,e,f){this.forEachGlyph(b,c,d,e,f,function(b,c,d,e){b.drawPoints(a,c,d,e)})},d.prototype.drawMetrics=function(a,b,c,d,e,f){this.forEachGlyph(b,c,d,e,f,function(b,c,d,e){b.drawMetrics(a,c,d,e)})},d.prototype.getEnglishName=function(a){var b=this.names[a];return b?b.en:void 0},d.prototype.validate=function(){function a(a,b){a||c.push(b)}function b(b){var c=d.getEnglishName(b);a(c&&c.trim().length>0,"No English "+b+" specified.")}var c=[],d=this;b("fontFamily"),b("weightName"),b("manufacturer"),b("copyright"),b("version"),a(this.unitsPerEm>0,"No unitsPerEm specified.")},d.prototype.toTables=function(){return f.fontToTable(this)},d.prototype.toBuffer=function(){for(var a=this.toTables(),b=a.encode(),c=new ArrayBuffer(b.length),d=new Uint8Array(c),e=0;e<b.length;e++)d[e]=b[e];return c},d.prototype.download=function(){var a=this.getEnglishName("fontFamily"),b=this.getEnglishName("fontSubfamily"),c=a.replace(/\s/g,"")+"-"+b+".otf",d=this.toBuffer();window.requestFileSystem=window.requestFileSystem||window.webkitRequestFileSystem,window.requestFileSystem(window.TEMPORARY,d.byteLength,function(a){a.root.getFile(c,{create:!0},function(a){a.createWriter(function(b){var c=new DataView(d),e=new Blob([c],{type:"font/opentype"});b.write(e),b.addEventListener("writeend",function(){location.href=a.toURL()},!1)})})},function(a){throw a})},c.Font=d},{"./encoding":4,"./glyphset":7,"./path":10,"./tables/sfnt":27}],6:[function(a,b,c){"use strict";function d(a,b){var c=b||{commands:[]};return{configurable:!0,get:function(){return"function"==typeof c&&(c=c()),c},set:function(a){c=a}}}function e(a){this.bindConstructorValues(a)}var f=a("./check"),g=a("./draw"),h=a("./path");e.prototype.bindConstructorValues=function(a){this.index=a.index||0,this.name=a.name||null,this.unicode=a.unicode||void 0,this.unicodes=a.unicodes||void 0!==a.unicode?[a.unicode]:[],a.xMin&&(this.xMin=a.xMin),a.yMin&&(this.yMin=a.yMin),a.xMax&&(this.xMax=a.xMax),a.yMax&&(this.yMax=a.yMax),a.advanceWidth&&(this.advanceWidth=a.advanceWidth),Object.defineProperty(this,"path",d(this,a.path))},e.prototype.addUnicode=function(a){0===this.unicodes.length&&(this.unicode=a),this.unicodes.push(a)},e.prototype.getPath=function(a,b,c){a=void 0!==a?a:0,b=void 0!==b?b:0,c=void 0!==c?c:72;for(var d=1/this.path.unitsPerEm*c,e=new h.Path,f=this.path.commands,g=0;g<f.length;g+=1){var i=f[g];"M"===i.type?e.moveTo(a+i.x*d,b+-i.y*d):"L"===i.type?e.lineTo(a+i.x*d,b+-i.y*d):"Q"===i.type?e.quadraticCurveTo(a+i.x1*d,b+-i.y1*d,a+i.x*d,b+-i.y*d):"C"===i.type?e.curveTo(a+i.x1*d,b+-i.y1*d,a+i.x2*d,b+-i.y2*d,a+i.x*d,b+-i.y*d):"Z"===i.type&&e.closePath()}return e},e.prototype.getContours=function(){if(void 0===this.points)return[];for(var a=[],b=[],c=0;c<this.points.length;c+=1){var d=this.points[c];b.push(d),d.lastPointOfContour&&(a.push(b),b=[])}return f.argument(0===b.length,"There are still points left in the current contour."),a},e.prototype.getMetrics=function(){for(var a=this.path.commands,b=[],c=[],d=0;d<a.length;d+=1){var e=a[d];"Z"!==e.type&&(b.push(e.x),c.push(e.y)),("Q"===e.type||"C"===e.type)&&(b.push(e.x1),c.push(e.y1)),"C"===e.type&&(b.push(e.x2),c.push(e.y2))}var f={xMin:Math.min.apply(null,b),yMin:Math.min.apply(null,c),xMax:Math.max.apply(null,b),yMax:Math.max.apply(null,c),leftSideBearing:0};return f.rightSideBearing=this.advanceWidth-f.leftSideBearing-(f.xMax-f.xMin),f},e.prototype.draw=function(a,b,c,d){this.getPath(b,c,d).draw(a)},e.prototype.drawPoints=function(a,b,c,d){function e(b,c,d,e){var f=2*Math.PI;a.beginPath();for(var g=0;g<b.length;g+=1)a.moveTo(c+b[g].x*e,d+b[g].y*e),a.arc(c+b[g].x*e,d+b[g].y*e,2,0,f,!1);a.closePath(),a.fill()}b=void 0!==b?b:0,c=void 0!==c?c:0,d=void 0!==d?d:24;for(var f=1/this.path.unitsPerEm*d,g=[],h=[],i=this.path,j=0;j<i.commands.length;j+=1){var k=i.commands[j];void 0!==k.x&&g.push({x:k.x,y:-k.y}),void 0!==k.x1&&h.push({x:k.x1,y:-k.y1}),void 0!==k.x2&&h.push({x:k.x2,y:-k.y2})}a.fillStyle="blue",e(g,b,c,f),a.fillStyle="red",e(h,b,c,f)},e.prototype.drawMetrics=function(a,b,c,d){var e;b=void 0!==b?b:0,c=void 0!==c?c:0,d=void 0!==d?d:24,e=1/this.path.unitsPerEm*d,a.lineWidth=1,a.strokeStyle="black",g.line(a,b,-1e4,b,1e4),g.line(a,-1e4,c,1e4,c);var f=this.xMin||0,h=this.yMin||0,i=this.xMax||0,j=this.yMax||0,k=this.advanceWidth||0;a.strokeStyle="blue",g.line(a,b+f*e,-1e4,b+f*e,1e4),g.line(a,b+i*e,-1e4,b+i*e,1e4),g.line(a,-1e4,c+-h*e,1e4,c+-h*e),g.line(a,-1e4,c+-j*e,1e4,c+-j*e),a.strokeStyle="green",g.line(a,b+k*e,-1e4,b+k*e,1e4)},c.Glyph=e},{"./check":2,"./draw":3,"./path":10}],7:[function(a,b,c){"use strict";function d(a,b){if(this.font=a,this.glyphs={},Array.isArray(b))for(var c=0;c<b.length;c++)this.glyphs[c]=b[c];this.length=b&&b.length||0}function e(a,b){return new h.Glyph({index:b,font:a})}function f(a,b,c,d,e,f){return function(){var g=new h.Glyph({index:b,font:a});return g.path=function(){c(g,d,e);var b=f(a.glyphs,g);return b.unitsPerEm=a.unitsPerEm,b},g}}function g(a,b,c,d){return function(){var e=new h.Glyph({index:b,font:a});return e.path=function(){var b=c(a,e,d);return b.unitsPerEm=a.unitsPerEm,b},e}}var h=a("./glyph");d.prototype.get=function(a){return"function"==typeof this.glyphs[a]&&(this.glyphs[a]=this.glyphs[a]()),this.glyphs[a]},d.prototype.push=function(a,b){this.glyphs[a]=b,this.length++},c.GlyphSet=d,c.glyphLoader=e,c.ttfGlyphLoader=f,c.cffGlyphLoader=g},{"./glyph":6}],8:[function(a,b,c){"use strict";function d(a){for(var b=new ArrayBuffer(a.length),c=new Uint8Array(b),d=0;d<a.length;d+=1)c[d]=a[d];return b}function e(b,c){var e=a("fs");e.readFile(b,function(a,b){return a?c(a.message):void c(null,d(b))})}function f(a,b){var c=new XMLHttpRequest;c.open("get",a,!0),c.responseType="arraybuffer",c.onload=function(){return 200!==c.status?b("Font could not be loaded: "+c.statusText):b(null,c.response)},c.send()}function g(a){var b,c,d,e,f,g,h,i,l,n,D=new k.Font,E=new DataView(a,0),F=m.getFixed(E,0);if(1===F)D.outlinesFormat="truetype";else{if(F=m.getTag(E,0),"OTTO"!==F)throw new Error("Unsupported OpenType version "+F);D.outlinesFormat="cff"}for(var G=m.getUShort(E,4),H=12,I=0;G>I;I+=1){var J=m.getTag(E,H),K=m.getULong(E,H+8);switch(J){case"cmap":D.tables.cmap=o.parse(E,K),D.encoding=new j.CmapEncoding(D.tables.cmap);break;case"fvar":e=K;break;case"head":D.tables.head=t.parse(E,K),D.unitsPerEm=D.tables.head.unitsPerEm,b=D.tables.head.indexToLocFormat;break;case"hhea":D.tables.hhea=u.parse(E,K),D.ascender=D.tables.hhea.ascender,D.descender=D.tables.hhea.descender,D.numberOfHMetrics=D.tables.hhea.numberOfHMetrics;break;case"hmtx":h=K;break;case"ltag":c=x.parse(E,K);break;case"maxp":D.tables.maxp=z.parse(E,K),D.numGlyphs=D.tables.maxp.numGlyphs;break;case"name":n=K;break;case"OS/2":D.tables.os2=B.parse(E,K);break;case"post":D.tables.post=C.parse(E,K),D.glyphNames=new j.GlyphNames(D.tables.post);break;case"glyf":f=K;break;case"loca":l=K;break;case"CFF ":d=K;break;case"kern":i=K;break;case"GPOS":g=K}H+=16}if(D.tables.name=A.parse(E,n,c),D.names=D.tables.name,f&&l){var L=0===b,M=y.parse(E,l,D.numGlyphs,L);D.glyphs=r.parse(E,f,M,D),v.parse(E,h,D.numberOfHMetrics,D.numGlyphs,D.glyphs),j.addGlyphNames(D)}else{if(!d)throw new Error("Font doesn't contain TrueType or CFF outlines.");p.parse(E,d,D),j.addGlyphNames(D)}return i?D.kerningPairs=w.parse(E,i):D.kerningPairs={},g&&s.parse(E,g,D),e&&(D.tables.fvar=q.parse(E,e,D.names)),D}function h(a,b){var c="undefined"==typeof window,d=c?e:f;d(a,function(a,c){if(a)return b(a);var d=g(c);return b(null,d)})}function i(b){var c=a("fs"),e=c.readFileSync(b);return g(d(e))}var j=a("./encoding"),k=a("./font"),l=a("./glyph"),m=a("./parse"),n=a("./path"),o=a("./tables/cmap"),p=a("./tables/cff"),q=a("./tables/fvar"),r=a("./tables/glyf"),s=a("./tables/gpos"),t=a("./tables/head"),u=a("./tables/hhea"),v=a("./tables/hmtx"),w=a("./tables/kern"),x=a("./tables/ltag"),y=a("./tables/loca"),z=a("./tables/maxp"),A=a("./tables/name"),B=a("./tables/os2"),C=a("./tables/post");c._parse=m,c.Font=k.Font,c.Glyph=l.Glyph,c.Path=n.Path,c.parse=g,c.load=h,c.loadSync=i},{"./encoding":4,"./font":5,"./glyph":6,"./parse":9,"./path":10,"./tables/cff":12,"./tables/cmap":13,"./tables/fvar":14,"./tables/glyf":15,"./tables/gpos":16,"./tables/head":17,"./tables/hhea":18,"./tables/hmtx":19,"./tables/kern":20,"./tables/loca":21,"./tables/ltag":22,"./tables/maxp":23,"./tables/name":24,"./tables/os2":25,"./tables/post":26,fs:1}],9:[function(a,b,c){"use strict";function d(a,b){this.data=a,this.offset=b,this.relativeOffset=0}c.getByte=function(a,b){return a.getUint8(b)},c.getCard8=c.getByte,c.getUShort=function(a,b){return a.getUint16(b,!1)},c.getCard16=c.getUShort,c.getShort=function(a,b){return a.getInt16(b,!1)},c.getULong=function(a,b){return a.getUint32(b,!1)},c.getFixed=function(a,b){var c=a.getInt16(b,!1),d=a.getUint16(b+2,!1);return c+d/65535},c.getTag=function(a,b){for(var c="",d=b;b+4>d;d+=1)c+=String.fromCharCode(a.getInt8(d));return c},c.getOffset=function(a,b,c){for(var d=0,e=0;c>e;e+=1)d<<=8,d+=a.getUint8(b+e);return d},c.getBytes=function(a,b,c){for(var d=[],e=b;c>e;e+=1)d.push(a.getUint8(e));return d},c.bytesToString=function(a){for(var b="",c=0;c<a.length;c+=1)b+=String.fromCharCode(a[c]);return b};var e={"byte":1,uShort:2,"short":2,uLong:4,fixed:4,longDateTime:8,tag:4};d.prototype.parseByte=function(){var a=this.data.getUint8(this.offset+this.relativeOffset);return this.relativeOffset+=1,a},d.prototype.parseChar=function(){var a=this.data.getInt8(this.offset+this.relativeOffset);return this.relativeOffset+=1,a},d.prototype.parseCard8=d.prototype.parseByte,d.prototype.parseUShort=function(){var a=this.data.getUint16(this.offset+this.relativeOffset);return this.relativeOffset+=2,a},d.prototype.parseCard16=d.prototype.parseUShort,d.prototype.parseSID=d.prototype.parseUShort,d.prototype.parseOffset16=d.prototype.parseUShort,d.prototype.parseShort=function(){var a=this.data.getInt16(this.offset+this.relativeOffset);return this.relativeOffset+=2,a},d.prototype.parseF2Dot14=function(){var a=this.data.getInt16(this.offset+this.relativeOffset)/16384;return this.relativeOffset+=2,a},d.prototype.parseULong=function(){var a=c.getULong(this.data,this.offset+this.relativeOffset);return this.relativeOffset+=4,a},d.prototype.parseFixed=function(){var a=c.getFixed(this.data,this.offset+this.relativeOffset);return this.relativeOffset+=4,a},d.prototype.parseOffset16List=d.prototype.parseUShortList=function(a){for(var b=new Array(a),d=this.data,e=this.offset+this.relativeOffset,f=0;a>f;f++)b[f]=c.getUShort(d,e),e+=2;return this.relativeOffset+=2*a,b},d.prototype.parseString=function(a){var b=this.data,c=this.offset+this.relativeOffset,d="";this.relativeOffset+=a;for(var e=0;a>e;e++)d+=String.fromCharCode(b.getUint8(c+e));return d},d.prototype.parseTag=function(){return this.parseString(4)},d.prototype.parseLongDateTime=function(){var a=c.getULong(this.data,this.offset+this.relativeOffset+4);return this.relativeOffset+=8,a},d.prototype.parseFixed=function(){var a=c.getULong(this.data,this.offset+this.relativeOffset);return this.relativeOffset+=4,a/65536},d.prototype.parseVersion=function(){var a=c.getUShort(this.data,this.offset+this.relativeOffset),b=c.getUShort(this.data,this.offset+this.relativeOffset+2);return this.relativeOffset+=4,a+b/4096/10},d.prototype.skip=function(a,b){void 0===b&&(b=1),this.relativeOffset+=e[a]*b},c.Parser=d},{}],10:[function(a,b,c){"use strict";function d(){this.commands=[],this.fill="black",this.stroke=null,this.strokeWidth=1}d.prototype.moveTo=function(a,b){this.commands.push({type:"M",x:a,y:b})},d.prototype.lineTo=function(a,b){this.commands.push({type:"L",x:a,y:b})},d.prototype.curveTo=d.prototype.bezierCurveTo=function(a,b,c,d,e,f){this.commands.push({type:"C",x1:a,y1:b,x2:c,y2:d,x:e,y:f})},d.prototype.quadTo=d.prototype.quadraticCurveTo=function(a,b,c,d){this.commands.push({type:"Q",x1:a,y1:b,x:c,y:d})},d.prototype.close=d.prototype.closePath=function(){this.commands.push({type:"Z"})},d.prototype.extend=function(a){a.commands&&(a=a.commands),Array.prototype.push.apply(this.commands,a)},d.prototype.draw=function(a){a.beginPath();for(var b=0;b<this.commands.length;b+=1){var c=this.commands[b];"M"===c.type?a.moveTo(c.x,c.y):"L"===c.type?a.lineTo(c.x,c.y):"C"===c.type?a.bezierCurveTo(c.x1,c.y1,c.x2,c.y2,c.x,c.y):"Q"===c.type?a.quadraticCurveTo(c.x1,c.y1,c.x,c.y):"Z"===c.type&&a.closePath()}this.fill&&(a.fillStyle=this.fill,a.fill()),this.stroke&&(a.strokeStyle=this.stroke,a.lineWidth=this.strokeWidth,a.stroke())},d.prototype.toPathData=function(a){function b(b){return Math.round(b)===b?""+Math.round(b):b.toFixed(a)}function c(){for(var a="",c=0;c<arguments.length;c+=1){var d=arguments[c];d>=0&&c>0&&(a+=" "),a+=b(d)}return a}a=void 0!==a?a:2;for(var d="",e=0;e<this.commands.length;e+=1){var f=this.commands[e];"M"===f.type?d+="M"+c(f.x,f.y):"L"===f.type?d+="L"+c(f.x,f.y):"C"===f.type?d+="C"+c(f.x1,f.y1,f.x2,f.y2,f.x,f.y):"Q"===f.type?d+="Q"+c(f.x1,f.y1,f.x,f.y):"Z"===f.type&&(d+="Z")}return d},d.prototype.toSVG=function(a){var b='<path d="';return b+=this.toPathData(a),b+='"',this.fill&"black"!==this.fill&&(b+=null===this.fill?' fill="none"':' fill="'+this.fill+'"'),this.stroke&&(b+=' stroke="'+this.stroke+'" stroke-width="'+this.strokeWidth+'"'),b+="/>"},c.Path=d},{}],11:[function(a,b,c){"use strict";function d(a,b,c){var d;for(d=0;d<b.length;d+=1){var e=b[d];this[e.name]=e.value}if(this.tableName=a,this.fields=b,c){var f=Object.keys(c);for(d=0;d<f.length;d+=1){var g=f[d],h=c[g];void 0!==this[g]&&(this[g]=h)}}}var e=a("./check"),f=a("./types").encode,g=a("./types").sizeOf;d.prototype.sizeOf=function(){for(var a=0,b=0;b<this.fields.length;b+=1){var c=this.fields[b],d=this[c.name];if(void 0===d&&(d=c.value),"function"==typeof d.sizeOf)a+=d.sizeOf();else{var f=g[c.type];e.assert("function"==typeof f,"Could not find sizeOf function for field"+c.name),a+=f(d)}}return a},d.prototype.encode=function(){return f.TABLE(this)},c.Table=d},{"./check":2,"./types":28}],12:[function(a,b,c){"use strict";function d(a,b){if(a===b)return!0;if(Array.isArray(a)&&Array.isArray(b)){if(a.length!==b.length)return!1;for(var c=0;c<a.length;c+=1)if(!d(a[c],b[c]))return!1;return!0}return!1}function e(a,b,c){var d,e,f,g=[],h=[],i=J.getCard16(a,b);if(0!==i){var j=J.getByte(a,b+2);e=b+(i+1)*j+2;var k=b+3;for(d=0;i+1>d;d+=1)g.push(J.getOffset(a,k,j)),k+=j;f=e+g[i]}else f=b+2;for(d=0;d<g.length-1;d+=1){var l=J.getBytes(a,e+g[d],e+g[d+1]);c&&(l=c(l)),h.push(l)}return{objects:h,startOffset:b,endOffset:f}}function f(a){for(var b="",c=15,d=["0","1","2","3","4","5","6","7","8","9",".","E","E-",null,"-"];;){var e=a.parseByte(),f=e>>4,g=15&e;if(f===c)break;if(b+=d[f],g===c)break;b+=d[g]}return parseFloat(b)}function g(a,b){var c,d,e,g;if(28===b)return c=a.parseByte(),d=a.parseByte(),c<<8|d;if(29===b)return c=a.parseByte(),d=a.parseByte(),e=a.parseByte(),g=a.parseByte(),c<<24|d<<16|e<<8|g;if(30===b)return f(a);if(b>=32&&246>=b)return b-139;if(b>=247&&250>=b)return c=a.parseByte(),256*(b-247)+c+108;if(b>=251&&254>=b)return c=a.parseByte(),256*-(b-251)-c-108;throw new Error("Invalid b0 "+b)}function h(a){for(var b={},c=0;c<a.length;c+=1){var d,e=a[c][0],f=a[c][1];if(d=1===f.length?f[0]:f,b.hasOwnProperty(e))throw new Error("Object "+b+" already has key "+e);b[e]=d}return b}function i(a,b,c){b=void 0!==b?b:0;var d=new J.Parser(a,b),e=[],f=[];for(c=void 0!==c?c:a.length;d.relativeOffset<c;){var i=d.parseByte();21>=i?(12===i&&(i=1200+d.parseByte()),e.push([i,f]),f=[]):f.push(g(d,i))}return h(e)}function j(a,b){return b=390>=b?H.cffStandardStrings[b]:a[b-391]}function k(a,b,c){for(var d={},e=0;e<b.length;e+=1){var f=b[e],g=a[f.op];void 0===g&&(g=void 0!==f.value?f.value:null),"SID"===f.type&&(g=j(c,g)),d[f.name]=g}return d}function l(a,b){var c={};return c.formatMajor=J.getCard8(a,b),c.formatMinor=J.getCard8(a,b+1),c.size=J.getCard8(a,b+2),c.offsetSize=J.getCard8(a,b+3),c.startOffset=b,c.endOffset=b+4,c}function m(a,b){var c=i(a,0,a.byteLength);return k(c,M,b)}function n(a,b,c,d){var e=i(a,b,c);return k(e,N,d)}function o(a,b,c,d){var e,f,g,h=new J.Parser(a,b);c-=1;var i=[".notdef"],k=h.parseCard8();if(0===k)for(e=0;c>e;e+=1)f=h.parseSID(),i.push(j(d,f));else if(1===k)for(;i.length<=c;)for(f=h.parseSID(),g=h.parseCard8(),e=0;g>=e;e+=1)i.push(j(d,f)),f+=1;else{if(2!==k)throw new Error("Unknown charset format "+k);for(;i.length<=c;)for(f=h.parseSID(),g=h.parseCard16(),e=0;g>=e;e+=1)i.push(j(d,f)),f+=1}return i}function p(a,b,c){var d,e,f={},g=new J.Parser(a,b),h=g.parseCard8();if(0===h){var i=g.parseCard8();for(d=0;i>d;d+=1)e=g.parseCard8(),
f[e]=d}else{if(1!==h)throw new Error("Unknown encoding format "+h);var j=g.parseCard8();for(e=1,d=0;j>d;d+=1)for(var k=g.parseCard8(),l=g.parseCard8(),m=k;k+l>=m;m+=1)f[m]=e,e+=1}return new H.CffEncoding(f,c)}function q(a,b,c){function d(a,b){p&&k.closePath(),k.moveTo(a,b),p=!0}function e(){var b;b=l.length%2!==0,b&&!n&&(o=l.shift()+a.nominalWidthX),m+=l.length>>1,l.length=0,n=!0}function f(c){for(var s,t,u,v,w,x,y,z,A,B,C,D,E=0;E<c.length;){var F=c[E];switch(E+=1,F){case 1:e();break;case 3:e();break;case 4:l.length>1&&!n&&(o=l.shift()+a.nominalWidthX,n=!0),r+=l.pop(),d(q,r);break;case 5:for(;l.length>0;)q+=l.shift(),r+=l.shift(),k.lineTo(q,r);break;case 6:for(;l.length>0&&(q+=l.shift(),k.lineTo(q,r),0!==l.length);)r+=l.shift(),k.lineTo(q,r);break;case 7:for(;l.length>0&&(r+=l.shift(),k.lineTo(q,r),0!==l.length);)q+=l.shift(),k.lineTo(q,r);break;case 8:for(;l.length>0;)g=q+l.shift(),h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),q=i+l.shift(),r=j+l.shift(),k.curveTo(g,h,i,j,q,r);break;case 10:w=l.pop()+a.subrsBias,x=a.subrs[w],x&&f(x);break;case 11:return;case 12:switch(F=c[E],E+=1,F){case 35:g=q+l.shift(),h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),y=i+l.shift(),z=j+l.shift(),A=y+l.shift(),B=z+l.shift(),C=A+l.shift(),D=B+l.shift(),q=C+l.shift(),r=D+l.shift(),l.shift(),k.curveTo(g,h,i,j,y,z),k.curveTo(A,B,C,D,q,r);break;case 34:g=q+l.shift(),h=r,i=g+l.shift(),j=h+l.shift(),y=i+l.shift(),z=j,A=y+l.shift(),B=j,C=A+l.shift(),D=r,q=C+l.shift(),k.curveTo(g,h,i,j,y,z),k.curveTo(A,B,C,D,q,r);break;case 36:g=q+l.shift(),h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),y=i+l.shift(),z=j,A=y+l.shift(),B=j,C=A+l.shift(),D=B+l.shift(),q=C+l.shift(),k.curveTo(g,h,i,j,y,z),k.curveTo(A,B,C,D,q,r);break;case 37:g=q+l.shift(),h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),y=i+l.shift(),z=j+l.shift(),A=y+l.shift(),B=z+l.shift(),C=A+l.shift(),D=B+l.shift(),Math.abs(C-q)>Math.abs(D-r)?q=C+l.shift():r=D+l.shift(),k.curveTo(g,h,i,j,y,z),k.curveTo(A,B,C,D,q,r);break;default:console.log("Glyph "+b.index+": unknown operator 1200"+F),l.length=0}break;case 14:l.length>0&&!n&&(o=l.shift()+a.nominalWidthX,n=!0),p&&(k.closePath(),p=!1);break;case 18:e();break;case 19:case 20:e(),E+=m+7>>3;break;case 21:l.length>2&&!n&&(o=l.shift()+a.nominalWidthX,n=!0),r+=l.pop(),q+=l.pop(),d(q,r);break;case 22:l.length>1&&!n&&(o=l.shift()+a.nominalWidthX,n=!0),q+=l.pop(),d(q,r);break;case 23:e();break;case 24:for(;l.length>2;)g=q+l.shift(),h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),q=i+l.shift(),r=j+l.shift(),k.curveTo(g,h,i,j,q,r);q+=l.shift(),r+=l.shift(),k.lineTo(q,r);break;case 25:for(;l.length>6;)q+=l.shift(),r+=l.shift(),k.lineTo(q,r);g=q+l.shift(),h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),q=i+l.shift(),r=j+l.shift(),k.curveTo(g,h,i,j,q,r);break;case 26:for(l.length%2&&(q+=l.shift());l.length>0;)g=q,h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),q=i,r=j+l.shift(),k.curveTo(g,h,i,j,q,r);break;case 27:for(l.length%2&&(r+=l.shift());l.length>0;)g=q+l.shift(),h=r,i=g+l.shift(),j=h+l.shift(),q=i+l.shift(),r=j,k.curveTo(g,h,i,j,q,r);break;case 28:s=c[E],t=c[E+1],l.push((s<<24|t<<16)>>16),E+=2;break;case 29:w=l.pop()+a.gsubrsBias,x=a.gsubrs[w],x&&f(x);break;case 30:for(;l.length>0&&(g=q,h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),q=i+l.shift(),r=j+(1===l.length?l.shift():0),k.curveTo(g,h,i,j,q,r),0!==l.length);)g=q+l.shift(),h=r,i=g+l.shift(),j=h+l.shift(),r=j+l.shift(),q=i+(1===l.length?l.shift():0),k.curveTo(g,h,i,j,q,r);break;case 31:for(;l.length>0&&(g=q+l.shift(),h=r,i=g+l.shift(),j=h+l.shift(),r=j+l.shift(),q=i+(1===l.length?l.shift():0),k.curveTo(g,h,i,j,q,r),0!==l.length);)g=q,h=r+l.shift(),i=g+l.shift(),j=h+l.shift(),q=i+l.shift(),r=j+(1===l.length?l.shift():0),k.curveTo(g,h,i,j,q,r);break;default:32>F?console.log("Glyph "+b.index+": unknown operator "+F):247>F?l.push(F-139):251>F?(s=c[E],E+=1,l.push(256*(F-247)+s+108)):255>F?(s=c[E],E+=1,l.push(256*-(F-251)-s-108)):(s=c[E],t=c[E+1],u=c[E+2],v=c[E+3],E+=4,l.push((s<<24|t<<16|u<<8|v)/65536))}}}var g,h,i,j,k=new K.Path,l=[],m=0,n=!1,o=a.defaultWidthX,p=!1,q=0,r=0;return f(c),b.advanceWidth=o,k}function r(a){var b;return b=a.length<1240?107:a.length<33900?1131:32768}function s(a,b,c){c.tables.cff={};var d=l(a,b),f=e(a,d.endOffset,J.bytesToString),g=e(a,f.endOffset),h=e(a,g.endOffset,J.bytesToString),i=e(a,h.endOffset);c.gsubrs=i.objects,c.gsubrsBias=r(c.gsubrs);var j=new DataView(new Uint8Array(g.objects[0]).buffer),k=m(j,h.objects);c.tables.cff.topDict=k;var s=b+k["private"][1],t=n(a,s,k["private"][0],h.objects);if(c.defaultWidthX=t.defaultWidthX,c.nominalWidthX=t.nominalWidthX,0!==t.subrs){var u=s+t.subrs,v=e(a,u);c.subrs=v.objects,c.subrsBias=r(c.subrs)}else c.subrs=[],c.subrsBias=0;var w=e(a,b+k.charStrings);c.nGlyphs=w.objects.length;var x=o(a,b+k.charset,c.nGlyphs,h.objects);0===k.encoding?c.cffEncoding=new H.CffEncoding(H.cffStandardEncoding,x):1===k.encoding?c.cffEncoding=new H.CffEncoding(H.cffExpertEncoding,x):c.cffEncoding=p(a,b+k.encoding,x),c.encoding=c.encoding||c.cffEncoding,c.glyphs=new I.GlyphSet(c);for(var y=0;y<c.nGlyphs;y+=1){var z=w.objects[y];c.glyphs.push(y,I.cffGlyphLoader(c,y,q,z))}}function t(a,b){var c,d=H.cffStandardStrings.indexOf(a);return d>=0&&(c=d),d=b.indexOf(a),d>=0?c=d+H.cffStandardStrings.length:(c=H.cffStandardStrings.length+b.length,b.push(a)),c}function u(){return new L.Table("Header",[{name:"major",type:"Card8",value:1},{name:"minor",type:"Card8",value:0},{name:"hdrSize",type:"Card8",value:4},{name:"major",type:"Card8",value:1}])}function v(a){var b=new L.Table("Name INDEX",[{name:"names",type:"INDEX",value:[]}]);b.names=[];for(var c=0;c<a.length;c+=1)b.names.push({name:"name_"+c,type:"NAME",value:a[c]});return b}function w(a,b,c){for(var e={},f=0;f<a.length;f+=1){var g=a[f],h=b[g.name];void 0===h||d(h,g.value)||("SID"===g.type&&(h=t(h,c)),e[g.op]={name:g.name,type:g.type,value:h})}return e}function x(a,b){var c=new L.Table("Top DICT",[{name:"dict",type:"DICT",value:{}}]);return c.dict=w(M,a,b),c}function y(a){var b=new L.Table("Top DICT INDEX",[{name:"topDicts",type:"INDEX",value:[]}]);return b.topDicts=[{name:"topDict_0",type:"TABLE",value:a}],b}function z(a){var b=new L.Table("String INDEX",[{name:"strings",type:"INDEX",value:[]}]);b.strings=[];for(var c=0;c<a.length;c+=1)b.strings.push({name:"string_"+c,type:"STRING",value:a[c]});return b}function A(){return new L.Table("Global Subr INDEX",[{name:"subrs",type:"INDEX",value:[]}])}function B(a,b){for(var c=new L.Table("Charsets",[{name:"format",type:"Card8",value:0}]),d=0;d<a.length;d+=1){var e=a[d],f=t(e,b);c.fields.push({name:"glyph_"+d,type:"SID",value:f})}return c}function C(a){var b=[],c=a.path;b.push({name:"width",type:"NUMBER",value:a.advanceWidth});for(var d=0,e=0,f=0;f<c.commands.length;f+=1){var g,h,i=c.commands[f];if("Q"===i.type){var j=1/3,k=2/3;i={type:"C",x:i.x,y:i.y,x1:j*d+k*i.x1,y1:j*e+k*i.y1,x2:j*i.x+k*i.x1,y2:j*i.y+k*i.y1}}if("M"===i.type)g=Math.round(i.x-d),h=Math.round(i.y-e),b.push({name:"dx",type:"NUMBER",value:g}),b.push({name:"dy",type:"NUMBER",value:h}),b.push({name:"rmoveto",type:"OP",value:21}),d=Math.round(i.x),e=Math.round(i.y);else if("L"===i.type)g=Math.round(i.x-d),h=Math.round(i.y-e),b.push({name:"dx",type:"NUMBER",value:g}),b.push({name:"dy",type:"NUMBER",value:h}),b.push({name:"rlineto",type:"OP",value:5}),d=Math.round(i.x),e=Math.round(i.y);else if("C"===i.type){var l=Math.round(i.x1-d),m=Math.round(i.y1-e),n=Math.round(i.x2-i.x1),o=Math.round(i.y2-i.y1);g=Math.round(i.x-i.x2),h=Math.round(i.y-i.y2),b.push({name:"dx1",type:"NUMBER",value:l}),b.push({name:"dy1",type:"NUMBER",value:m}),b.push({name:"dx2",type:"NUMBER",value:n}),b.push({name:"dy2",type:"NUMBER",value:o}),b.push({name:"dx",type:"NUMBER",value:g}),b.push({name:"dy",type:"NUMBER",value:h}),b.push({name:"rrcurveto",type:"OP",value:8}),d=Math.round(i.x),e=Math.round(i.y)}}return b.push({name:"endchar",type:"OP",value:14}),b}function D(a){for(var b=new L.Table("CharStrings INDEX",[{name:"charStrings",type:"INDEX",value:[]}]),c=0;c<a.length;c+=1){var d=a.get(c),e=C(d);b.charStrings.push({name:d.name,type:"CHARSTRING",value:e})}return b}function E(a,b){var c=new L.Table("Private DICT",[{name:"dict",type:"DICT",value:{}}]);return c.dict=w(N,a,b),c}function F(a){var b=new L.Table("Private DICT INDEX",[{name:"privateDicts",type:"INDEX",value:[]}]);return b.privateDicts=[{name:"privateDict_0",type:"TABLE",value:a}],b}function G(a,b){for(var c,d=new L.Table("CFF ",[{name:"header",type:"TABLE"},{name:"nameIndex",type:"TABLE"},{name:"topDictIndex",type:"TABLE"},{name:"stringIndex",type:"TABLE"},{name:"globalSubrIndex",type:"TABLE"},{name:"charsets",type:"TABLE"},{name:"charStringsIndex",type:"TABLE"},{name:"privateDictIndex",type:"TABLE"}]),e=1/b.unitsPerEm,f={version:b.version,fullName:b.fullName,familyName:b.familyName,weight:b.weightName,fontMatrix:[e,0,0,e,0,0],charset:999,encoding:0,charStrings:999,"private":[0,999]},g={},h=[],i=1;i<a.length;i+=1)c=a.get(i),h.push(c.name);var j=[];d.header=u(),d.nameIndex=v([b.postScriptName]);var k=x(f,j);d.topDictIndex=y(k),d.globalSubrIndex=A(),d.charsets=B(h,j),d.charStringsIndex=D(a);var l=E(g,j);d.privateDictIndex=F(l),d.stringIndex=z(j);var m=d.header.sizeOf()+d.nameIndex.sizeOf()+d.topDictIndex.sizeOf()+d.stringIndex.sizeOf()+d.globalSubrIndex.sizeOf();return f.charset=m,f.encoding=0,f.charStrings=f.charset+d.charsets.sizeOf(),f["private"][1]=f.charStrings+d.charStringsIndex.sizeOf(),k=x(f,j),d.topDictIndex=y(k),d}var H=a("../encoding"),I=a("../glyphset"),J=a("../parse"),K=a("../path"),L=a("../table"),M=[{name:"version",op:0,type:"SID"},{name:"notice",op:1,type:"SID"},{name:"copyright",op:1200,type:"SID"},{name:"fullName",op:2,type:"SID"},{name:"familyName",op:3,type:"SID"},{name:"weight",op:4,type:"SID"},{name:"isFixedPitch",op:1201,type:"number",value:0},{name:"italicAngle",op:1202,type:"number",value:0},{name:"underlinePosition",op:1203,type:"number",value:-100},{name:"underlineThickness",op:1204,type:"number",value:50},{name:"paintType",op:1205,type:"number",value:0},{name:"charstringType",op:1206,type:"number",value:2},{name:"fontMatrix",op:1207,type:["real","real","real","real","real","real"],value:[.001,0,0,.001,0,0]},{name:"uniqueId",op:13,type:"number"},{name:"fontBBox",op:5,type:["number","number","number","number"],value:[0,0,0,0]},{name:"strokeWidth",op:1208,type:"number",value:0},{name:"xuid",op:14,type:[],value:null},{name:"charset",op:15,type:"offset",value:0},{name:"encoding",op:16,type:"offset",value:0},{name:"charStrings",op:17,type:"offset",value:0},{name:"private",op:18,type:["number","offset"],value:[0,0]}],N=[{name:"subrs",op:19,type:"offset",value:0},{name:"defaultWidthX",op:20,type:"number",value:0},{name:"nominalWidthX",op:21,type:"number",value:0}];c.parse=s,c.make=G},{"../encoding":4,"../glyphset":7,"../parse":9,"../path":10,"../table":11}],13:[function(a,b,c){"use strict";function d(a,b){var c,d={};d.version=i.getUShort(a,b),h.argument(0===d.version,"cmap table version should be 0."),d.numTables=i.getUShort(a,b+2);var e=-1;for(c=0;c<d.numTables;c+=1){var f=i.getUShort(a,b+4+8*c),g=i.getUShort(a,b+4+8*c+2);if(3===f&&(1===g||0===g)){e=i.getULong(a,b+4+8*c+4);break}}if(-1===e)return null;var j=new i.Parser(a,b+e);d.format=j.parseUShort(),h.argument(4===d.format,"Only format 4 cmap tables are supported."),d.length=j.parseUShort(),d.language=j.parseUShort();var k;d.segCount=k=j.parseUShort()>>1,j.skip("uShort",3),d.glyphIndexMap={};var l=new i.Parser(a,b+e+14),m=new i.Parser(a,b+e+16+2*k),n=new i.Parser(a,b+e+16+4*k),o=new i.Parser(a,b+e+16+6*k),p=b+e+16+8*k;for(c=0;k-1>c;c+=1)for(var q,r=l.parseUShort(),s=m.parseUShort(),t=n.parseShort(),u=o.parseUShort(),v=s;r>=v;v+=1)0!==u?(p=o.offset+o.relativeOffset-2,p+=u,p+=2*(v-s),q=i.getUShort(a,p),0!==q&&(q=q+t&65535)):q=v+t&65535,d.glyphIndexMap[v]=q;return d}function e(a,b,c){a.segments.push({end:b,start:b,delta:-(b-c),offset:0})}function f(a){a.segments.push({end:65535,start:65535,delta:1,offset:0})}function g(a){var b,c=new j.Table("cmap",[{name:"version",type:"USHORT",value:0},{name:"numTables",type:"USHORT",value:1},{name:"platformID",type:"USHORT",value:3},{name:"encodingID",type:"USHORT",value:1},{name:"offset",type:"ULONG",value:12},{name:"format",type:"USHORT",value:4},{name:"length",type:"USHORT",value:0},{name:"language",type:"USHORT",value:0},{name:"segCountX2",type:"USHORT",value:0},{name:"searchRange",type:"USHORT",value:0},{name:"entrySelector",type:"USHORT",value:0},{name:"rangeShift",type:"USHORT",value:0}]);for(c.segments=[],b=0;b<a.length;b+=1){for(var d=a.get(b),g=0;g<d.unicodes.length;g+=1)e(c,d.unicodes[g],b);c.segments=c.segments.sort(function(a,b){return a.start-b.start})}f(c);var h;h=c.segments.length,c.segCountX2=2*h,c.searchRange=2*Math.pow(2,Math.floor(Math.log(h)/Math.log(2))),c.entrySelector=Math.log(c.searchRange/2)/Math.log(2),c.rangeShift=c.segCountX2-c.searchRange;var i=[],k=[],l=[],m=[],n=[];for(b=0;h>b;b+=1){var o=c.segments[b];i=i.concat({name:"end_"+b,type:"USHORT",value:o.end}),k=k.concat({name:"start_"+b,type:"USHORT",value:o.start}),l=l.concat({name:"idDelta_"+b,type:"SHORT",value:o.delta}),m=m.concat({name:"idRangeOffset_"+b,type:"USHORT",value:o.offset}),void 0!==o.glyphId&&(n=n.concat({name:"glyph_"+b,type:"USHORT",value:o.glyphId}))}return c.fields=c.fields.concat(i),c.fields.push({name:"reservedPad",type:"USHORT",value:0}),c.fields=c.fields.concat(k),c.fields=c.fields.concat(l),c.fields=c.fields.concat(m),c.fields=c.fields.concat(n),c.length=14+2*i.length+2+2*k.length+2*l.length+2*m.length+2*n.length,c}var h=a("../check"),i=a("../parse"),j=a("../table");c.parse=d,c.make=g},{"../check":2,"../parse":9,"../table":11}],14:[function(a,b,c){"use strict";function d(a,b){var c=JSON.stringify(a),d=256;for(var e in b){var f=parseInt(e);if(f&&!(256>f)){if(JSON.stringify(b[e])===c)return f;f>=d&&(d=f+1)}}return b[d]=a,d}function e(a,b){var c=d(a.name,b);return new m.Table("fvarAxis",[{name:"tag",type:"TAG",value:a.tag},{name:"minValue",type:"FIXED",value:a.minValue<<16},{name:"defaultValue",type:"FIXED",value:a.defaultValue<<16},{name:"maxValue",type:"FIXED",value:a.maxValue<<16},{name:"flags",type:"USHORT",value:0},{name:"nameID",type:"USHORT",value:c}])}function f(a,b,c){var d={},e=new l.Parser(a,b);return d.tag=e.parseTag(),d.minValue=e.parseFixed(),d.defaultValue=e.parseFixed(),d.maxValue=e.parseFixed(),e.skip("uShort",1),d.name=c[e.parseUShort()]||{},d}function g(a,b,c){for(var e=d(a.name,c),f=[{name:"nameID",type:"USHORT",value:e},{name:"flags",type:"USHORT",value:0}],g=0;g<b.length;++g){var h=b[g].tag;f.push({name:"axis "+h,type:"FIXED",value:a.coordinates[h]<<16})}return new m.Table("fvarInstance",f)}function h(a,b,c,d){var e={},f=new l.Parser(a,b);e.name=d[f.parseUShort()]||{},f.skip("uShort",1),e.coordinates={};for(var g=0;g<c.length;++g)e.coordinates[c[g].tag]=f.parseFixed();return e}function i(a,b){var c=new m.Table("fvar",[{name:"version",type:"ULONG",value:65536},{name:"offsetToData",type:"USHORT",value:0},{name:"countSizePairs",type:"USHORT",value:2},{name:"axisCount",type:"USHORT",value:a.axes.length},{name:"axisSize",type:"USHORT",value:20},{name:"instanceCount",type:"USHORT",value:a.instances.length},{name:"instanceSize",type:"USHORT",value:4+4*a.axes.length}]);c.offsetToData=c.sizeOf();for(var d=0;d<a.axes.length;d++)c.fields.push({name:"axis "+d,type:"TABLE",value:e(a.axes[d],b)});for(var f=0;f<a.instances.length;f++)c.fields.push({name:"instance "+f,type:"TABLE",value:g(a.instances[f],a.axes,b)});return c}function j(a,b,c){var d=new l.Parser(a,b),e=d.parseULong();k.argument(65536===e,"Unsupported fvar table version.");var g=d.parseOffset16();d.skip("uShort",1);for(var i=d.parseUShort(),j=d.parseUShort(),m=d.parseUShort(),n=d.parseUShort(),o=[],p=0;i>p;p++)o.push(f(a,b+g+p*j,c));for(var q=[],r=b+g+i*j,s=0;m>s;s++)q.push(h(a,r+s*n,o,c));return{axes:o,instances:q}}var k=a("../check"),l=a("../parse"),m=a("../table");c.make=i,c.parse=j},{"../check":2,"../parse":9,"../table":11}],15:[function(a,b,c){"use strict";function d(a,b,c,d,e){var f;return(b&d)>0?(f=a.parseByte(),0===(b&e)&&(f=-f),f=c+f):f=(b&e)>0?c:c+a.parseShort(),f}function e(a,b,c){var e=new m.Parser(b,c);a.numberOfContours=e.parseShort(),a.xMin=e.parseShort(),a.yMin=e.parseShort(),a.xMax=e.parseShort(),a.yMax=e.parseShort();var f,g;if(a.numberOfContours>0){var h,i=a.endPointIndices=[];for(h=0;h<a.numberOfContours;h+=1)i.push(e.parseUShort());for(a.instructionLength=e.parseUShort(),a.instructions=[],h=0;h<a.instructionLength;h+=1)a.instructions.push(e.parseByte());var j=i[i.length-1]+1;for(f=[],h=0;j>h;h+=1)if(g=e.parseByte(),f.push(g),(8&g)>0)for(var l=e.parseByte(),n=0;l>n;n+=1)f.push(g),h+=1;if(k.argument(f.length===j,"Bad flags."),i.length>0){var o,p=[];if(j>0){for(h=0;j>h;h+=1)g=f[h],o={},o.onCurve=!!(1&g),o.lastPointOfContour=i.indexOf(h)>=0,p.push(o);var q=0;for(h=0;j>h;h+=1)g=f[h],o=p[h],o.x=d(e,g,q,2,16),q=o.x;var r=0;for(h=0;j>h;h+=1)g=f[h],o=p[h],o.y=d(e,g,r,4,32),r=o.y}a.points=p}else a.points=[]}else if(0===a.numberOfContours)a.points=[];else{a.isComposite=!0,a.points=[],a.components=[];for(var s=!0;s;){f=e.parseUShort();var t={glyphIndex:e.parseUShort(),xScale:1,scale01:0,scale10:0,yScale:1,dx:0,dy:0};(1&f)>0?(t.dx=e.parseShort(),t.dy=e.parseShort()):(t.dx=e.parseChar(),t.dy=e.parseChar()),(8&f)>0?t.xScale=t.yScale=e.parseF2Dot14():(64&f)>0?(t.xScale=e.parseF2Dot14(),t.yScale=e.parseF2Dot14()):(128&f)>0&&(t.xScale=e.parseF2Dot14(),t.scale01=e.parseF2Dot14(),t.scale10=e.parseF2Dot14(),t.yScale=e.parseF2Dot14()),a.components.push(t),s=!!(32&f)}}}function f(a,b){for(var c=[],d=0;d<a.length;d+=1){var e=a[d],f={x:b.xScale*e.x+b.scale01*e.y+b.dx,y:b.scale10*e.x+b.yScale*e.y+b.dy,onCurve:e.onCurve,lastPointOfContour:e.lastPointOfContour};c.push(f)}return c}function g(a){for(var b=[],c=[],d=0;d<a.length;d+=1){var e=a[d];c.push(e),e.lastPointOfContour&&(b.push(c),c=[])}return k.argument(0===c.length,"There are still points left in the current contour."),b}function h(a){var b=new n.Path;if(!a)return b;for(var c=g(a),d=0;d<c.length;d+=1){var e,f,h=c[d],i=h[0],j=h[h.length-1];i.onCurve?(e=null,f=!0):(i=j.onCurve?j:{x:(i.x+j.x)/2,y:(i.y+j.y)/2},e=i,f=!1),b.moveTo(i.x,i.y);for(var k=f?1:0;k<h.length;k+=1){var l=h[k],m=0===k?i:h[k-1];if(m.onCurve&&l.onCurve)b.lineTo(l.x,l.y);else if(m.onCurve&&!l.onCurve)e=l;else if(m.onCurve||l.onCurve){if(m.onCurve||!l.onCurve)throw new Error("Invalid state.");b.quadraticCurveTo(e.x,e.y,l.x,l.y),e=null}else{var o={x:(m.x+l.x)/2,y:(m.y+l.y)/2};b.quadraticCurveTo(m.x,m.y,o.x,o.y),e=l}}i!==j&&(e?b.quadraticCurveTo(e.x,e.y,i.x,i.y):b.lineTo(i.x,i.y))}return b.closePath(),b}function i(a,b){if(b.isComposite)for(var c=0;c<b.components.length;c+=1){var d=b.components[c],e=a.get(d.glyphIndex);if(e.points){var g=f(e.points,d);b.points=b.points.concat(g)}}return h(b.points)}function j(a,b,c,d){var f,g=new l.GlyphSet(d);for(f=0;f<c.length-1;f+=1){var h=c[f],j=c[f+1];h!==j?g.push(f,l.ttfGlyphLoader(d,f,e,a,b+h,i)):g.push(f,l.glyphLoader(d,f))}return g}var k=a("../check"),l=a("../glyphset"),m=a("../parse"),n=a("../path");c.parse=j},{"../check":2,"../glyphset":7,"../parse":9,"../path":10}],16:[function(a,b,c){"use strict";function d(a,b){for(var c=new k.Parser(a,b),d=c.parseUShort(),e=[],f=0;d>f;f++)e[c.parseTag()]={offset:c.parseUShort()};return e}function e(a,b){var c=new k.Parser(a,b),d=c.parseUShort(),e=c.parseUShort();if(1===d)return c.parseUShortList(e);if(2===d){for(var f=[];e--;)for(var g=c.parseUShort(),h=c.parseUShort(),i=c.parseUShort(),j=g;h>=j;j++)f[i++]=j;return f}}function f(a,b){var c=new k.Parser(a,b),d=c.parseUShort();if(1===d){var e=c.parseUShort(),f=c.parseUShort(),g=c.parseUShortList(f);return function(a){return g[a-e]||0}}if(2===d){for(var h=c.parseUShort(),i=[],j=[],l=[],m=0;h>m;m++)i[m]=c.parseUShort(),j[m]=c.parseUShort(),l[m]=c.parseUShort();return function(a){for(var b=0,c=i.length-1;c>b;){var d=b+c+1>>1;a<i[d]?c=d-1:b=d}return i[b]<=a&&a<=j[b]?l[b]||0:0}}}function g(a,b){var c,d,g=new k.Parser(a,b),h=g.parseUShort(),i=g.parseUShort(),j=e(a,b+i),l=g.parseUShort(),m=g.parseUShort();if(4===l&&0===m){var n={};if(1===h){for(var o=g.parseUShort(),p=[],q=g.parseOffset16List(o),r=0;o>r;r++){var s=q[r],t=n[s];if(!t){t={},g.relativeOffset=s;for(var u=g.parseUShort();u--;){var v=g.parseUShort();l&&(c=g.parseShort()),m&&(d=g.parseShort()),t[v]=c}}p[j[r]]=t}return function(a,b){var c=p[a];return c?c[b]:void 0}}if(2===h){for(var w=g.parseUShort(),x=g.parseUShort(),y=g.parseUShort(),z=g.parseUShort(),A=f(a,b+w),B=f(a,b+x),C=[],D=0;y>D;D++)for(var E=C[D]=[],F=0;z>F;F++)l&&(c=g.parseShort()),m&&(d=g.parseShort()),E[F]=c;var G={};for(D=0;D<j.length;D++)G[j[D]]=1;return function(a,b){if(G[a]){var c=A(a),d=B(b),e=C[c];return e?e[d]:void 0}}}}}function h(a,b){var c=new k.Parser(a,b),d=c.parseUShort(),e=c.parseUShort(),f=16&e,h=c.parseUShort(),i=c.parseOffset16List(h),j={lookupType:d,lookupFlag:e,markFilteringSet:f?c.parseUShort():-1};if(2===d){for(var l=[],m=0;h>m;m++)l.push(g(a,b+i[m]));j.getKerningValue=function(a,b){for(var c=l.length;c--;){var d=l[c](a,b);if(void 0!==d)return d}return 0}}return j}function i(a,b,c){var e=new k.Parser(a,b),f=e.parseFixed();j.argument(1===f,"Unsupported GPOS table version."),d(a,b+e.parseUShort()),d(a,b+e.parseUShort());var g=e.parseUShort();e.relativeOffset=g;for(var i=e.parseUShort(),l=e.parseOffset16List(i),m=b+g,n=0;i>n;n++){var o=h(a,m+l[n]);2!==o.lookupType||c.getGposKerningValue||(c.getGposKerningValue=o.getKerningValue)}}var j=a("../check"),k=a("../parse");c.parse=i},{"../check":2,"../parse":9}],17:[function(a,b,c){"use strict";function d(a,b){var c={},d=new g.Parser(a,b);return c.version=d.parseVersion(),c.fontRevision=Math.round(1e3*d.parseFixed())/1e3,c.checkSumAdjustment=d.parseULong(),c.magicNumber=d.parseULong(),f.argument(1594834165===c.magicNumber,"Font header has wrong magic number."),c.flags=d.parseUShort(),c.unitsPerEm=d.parseUShort(),c.created=d.parseLongDateTime(),c.modified=d.parseLongDateTime(),c.xMin=d.parseShort(),c.yMin=d.parseShort(),c.xMax=d.parseShort(),c.yMax=d.parseShort(),c.macStyle=d.parseUShort(),c.lowestRecPPEM=d.parseUShort(),c.fontDirectionHint=d.parseShort(),c.indexToLocFormat=d.parseShort(),c.glyphDataFormat=d.parseShort(),c}function e(a){return new h.Table("head",[{name:"version",type:"FIXED",value:65536},{name:"fontRevision",type:"FIXED",value:65536},{name:"checkSumAdjustment",type:"ULONG",value:0},{name:"magicNumber",type:"ULONG",value:1594834165},{name:"flags",type:"USHORT",value:0},{name:"unitsPerEm",type:"USHORT",value:1e3},{name:"created",type:"LONGDATETIME",value:0},{name:"modified",type:"LONGDATETIME",value:0},{name:"xMin",type:"SHORT",value:0},{name:"yMin",type:"SHORT",value:0},{name:"xMax",type:"SHORT",value:0},{name:"yMax",type:"SHORT",value:0},{name:"macStyle",type:"USHORT",value:0},{name:"lowestRecPPEM",type:"USHORT",value:0},{name:"fontDirectionHint",type:"SHORT",value:2},{name:"indexToLocFormat",type:"SHORT",value:0},{name:"glyphDataFormat",type:"SHORT",value:0}],a)}var f=a("../check"),g=a("../parse"),h=a("../table");c.parse=d,c.make=e},{"../check":2,"../parse":9,"../table":11}],18:[function(a,b,c){"use strict";function d(a,b){var c={},d=new f.Parser(a,b);return c.version=d.parseVersion(),c.ascender=d.parseShort(),c.descender=d.parseShort(),c.lineGap=d.parseShort(),c.advanceWidthMax=d.parseUShort(),c.minLeftSideBearing=d.parseShort(),c.minRightSideBearing=d.parseShort(),c.xMaxExtent=d.parseShort(),c.caretSlopeRise=d.parseShort(),c.caretSlopeRun=d.parseShort(),c.caretOffset=d.parseShort(),d.relativeOffset+=8,c.metricDataFormat=d.parseShort(),c.numberOfHMetrics=d.parseUShort(),c}function e(a){return new g.Table("hhea",[{name:"version",type:"FIXED",value:65536},{name:"ascender",type:"FWORD",value:0},{name:"descender",type:"FWORD",value:0},{name:"lineGap",type:"FWORD",value:0},{name:"advanceWidthMax",type:"UFWORD",value:0},{name:"minLeftSideBearing",type:"FWORD",value:0},{name:"minRightSideBearing",type:"FWORD",value:0},{name:"xMaxExtent",type:"FWORD",value:0},{name:"caretSlopeRise",type:"SHORT",value:1},{name:"caretSlopeRun",type:"SHORT",value:0},{name:"caretOffset",type:"SHORT",value:0},{name:"reserved1",type:"SHORT",value:0},{name:"reserved2",type:"SHORT",value:0},{name:"reserved3",type:"SHORT",value:0},{name:"reserved4",type:"SHORT",value:0},{name:"metricDataFormat",type:"SHORT",value:0},{name:"numberOfHMetrics",type:"USHORT",value:0}],a)}var f=a("../parse"),g=a("../table");c.parse=d,c.make=e},{"../parse":9,"../table":11}],19:[function(a,b,c){"use strict";function d(a,b,c,d,e){for(var g,h,i=new f.Parser(a,b),j=0;d>j;j+=1){c>j&&(g=i.parseUShort(),h=i.parseShort());var k=e.get(j);k.advanceWidth=g,k.leftSideBearing=h}}function e(a){for(var b=new g.Table("hmtx",[]),c=0;c<a.length;c+=1){var d=a.get(c),e=d.advanceWidth||0,f=d.leftSideBearing||0;b.fields.push({name:"advanceWidth_"+c,type:"USHORT",value:e}),b.fields.push({name:"leftSideBearing_"+c,type:"SHORT",value:f})}return b}var f=a("../parse"),g=a("../table");c.parse=d,c.make=e},{"../parse":9,"../table":11}],20:[function(a,b,c){"use strict";function d(a,b){var c={},d=new f.Parser(a,b),g=d.parseUShort();e.argument(0===g,"Unsupported kern table version."),d.skip("uShort",1);var h=d.parseUShort();e.argument(0===h,"Unsupported kern sub-table version."),d.skip("uShort",2);var i=d.parseUShort();d.skip("uShort",3);for(var j=0;i>j;j+=1){var k=d.parseUShort(),l=d.parseUShort(),m=d.parseShort();c[k+","+l]=m}return c}var e=a("../check"),f=a("../parse");c.parse=d},{"../check":2,"../parse":9}],21:[function(a,b,c){"use strict";function d(a,b,c,d){for(var f=new e.Parser(a,b),g=d?f.parseUShort:f.parseULong,h=[],i=0;c+1>i;i+=1){var j=g.call(f);d&&(j*=2),h.push(j)}return h}var e=a("../parse");c.parse=d},{"../parse":9}],22:[function(a,b,c){"use strict";function d(a){for(var b=new h.Table("ltag",[{name:"version",type:"ULONG",value:1},{name:"flags",type:"ULONG",value:0},{name:"numTags",type:"ULONG",value:a.length}]),c="",d=12+4*a.length,e=0;e<a.length;++e){var f=c.indexOf(a[e]);0>f&&(f=c.length,c+=a[e]),b.fields.push({name:"offset "+e,type:"USHORT",value:d+f}),b.fields.push({name:"length "+e,type:"USHORT",value:a[e].length})}return b.fields.push({name:"stringPool",type:"CHARARRAY",value:c}),b}function e(a,b){var c=new g.Parser(a,b),d=c.parseULong();f.argument(1===d,"Unsupported ltag table version."),c.skip("uLong",1);for(var e=c.parseULong(),h=[],i=0;e>i;i++){for(var j="",k=b+c.parseUShort(),l=c.parseUShort(),m=k;k+l>m;++m)j+=String.fromCharCode(a.getInt8(m));h.push(j)}return h}var f=a("../check"),g=a("../parse"),h=a("../table");c.make=d,c.parse=e},{"../check":2,"../parse":9,"../table":11}],23:[function(a,b,c){"use strict";function d(a,b){var c={},d=new f.Parser(a,b);return c.version=d.parseVersion(),c.numGlyphs=d.parseUShort(),1===c.version&&(c.maxPoints=d.parseUShort(),c.maxContours=d.parseUShort(),c.maxCompositePoints=d.parseUShort(),c.maxCompositeContours=d.parseUShort(),c.maxZones=d.parseUShort(),c.maxTwilightPoints=d.parseUShort(),c.maxStorage=d.parseUShort(),c.maxFunctionDefs=d.parseUShort(),c.maxInstructionDefs=d.parseUShort(),c.maxStackElements=d.parseUShort(),c.maxSizeOfInstructions=d.parseUShort(),c.maxComponentElements=d.parseUShort(),c.maxComponentDepth=d.parseUShort()),c}function e(a){return new g.Table("maxp",[{name:"version",type:"FIXED",value:20480},{name:"numGlyphs",type:"USHORT",value:a}])}var f=a("../parse"),g=a("../table");c.parse=d,c.make=e},{"../parse":9,"../table":11}],24:[function(a,b,c){"use strict";function d(a,b,c){switch(a){case 0:if(65535===b)return"und";if(c)return c[b];break;case 1:return r[b];case 3:return t[b]}return void 0}function e(a,b,c){switch(a){case 0:return u;case 1:return w[c]||v[b];case 3:if(1===b||10===b)return u}return void 0}function f(a,b,c){for(var f={},g=new o.Parser(a,b),h=g.parseUShort(),i=g.parseUShort(),j=g.offset+g.parseUShort(),k=0;i>k;k++){var l=g.parseUShort(),n=g.parseUShort(),p=g.parseUShort(),r=g.parseUShort(),s=q[r]||r,t=g.parseUShort(),v=g.parseUShort(),w=d(l,p,c),x=e(l,n,p);if(void 0!==x&&void 0!==w){var y;if(y=x===u?m.UTF16(a,j+v,t):m.MACSTRING(a,j+v,t,x)){var z=f[s];void 0===z&&(z=f[s]={}),z[w]=y}}}var A=0;return 1===h&&(A=g.parseUShort()),f}function g(a){var b={};for(var c in a)b[a[c]]=parseInt(c);return b}function h(a,b,c,d,e,f){return new p.Table("NameRecord",[{name:"platformID",type:"USHORT",value:a},{name:"encodingID",type:"USHORT",value:b},{name:"languageID",type:"USHORT",value:c},{name:"nameID",type:"USHORT",value:d},{name:"length",type:"USHORT",value:e},{name:"offset",type:"USHORT",value:f}])}function i(a,b){var c=a.length,d=b.length-c+1;a:for(var e=0;d>e;e++)for(;d>e;e++){for(var f=0;c>f;f++)if(b[e+f]!==a[f])continue a;return e}return-1}function j(a,b){var c=i(a,b);if(0>c){c=b.length;for(var d=0,e=a.length;e>d;++d)b.push(a[d])}return c}function k(a,b){var c,d=[],f={},i=g(q);for(var k in a){var l=i[k];void 0===l&&(l=k),c=parseInt(l),f[c]=a[k],d.push(c)}for(var m=g(r),o=g(t),u=[],v=[],w=0;w<d.length;w++){c=d[w];var x=f[c];for(var y in x){var z=x[y],A=1,B=m[y],C=s[B],D=e(A,C,B),E=n.MACSTRING(z,D);void 0===E&&(A=0,B=b.indexOf(y),0>B&&(B=b.length,b.push(y)),C=4,E=n.UTF16(z));var F=j(E,v);u.push(h(A,C,B,c,E.length,F));var G=o[y];if(void 0!==G){var H=n.UTF16(z),I=j(H,v);u.push(h(3,1,G,c,H.length,I))}}}u.sort(function(a,b){return a.platformID-b.platformID||a.encodingID-b.encodingID||a.languageID-b.languageID||a.nameID-b.nameID});for(var J=new p.Table("name",[{name:"format",type:"USHORT",value:0},{name:"count",type:"USHORT",value:u.length},{name:"stringOffset",type:"USHORT",value:6+12*u.length}]),K=0;K<u.length;K++)J.fields.push({name:"record_"+K,type:"TABLE",value:u[K]});return J.fields.push({name:"strings",type:"LITERAL",value:v}),J}var l=a("../types"),m=l.decode,n=l.encode,o=a("../parse"),p=a("../table"),q=["copyright","fontFamily","fontSubfamily","uniqueID","fullName","version","postScriptName","trademark","manufacturer","designer","description","manufacturerURL","designerURL","licence","licenceURL","reserved","preferredFamily","preferredSubfamily","compatibleFullName","sampleText","postScriptFindFontName","wwsFamily","wwsSubfamily"],r={0:"en",1:"fr",2:"de",3:"it",4:"nl",5:"sv",6:"es",7:"da",8:"pt",9:"no",10:"he",11:"ja",12:"ar",13:"fi",14:"el",15:"is",16:"mt",17:"tr",18:"hr",19:"zh-Hant",20:"ur",21:"hi",22:"th",23:"ko",24:"lt",25:"pl",26:"hu",27:"es",28:"lv",29:"se",30:"fo",31:"fa",32:"ru",33:"zh",34:"nl-BE",35:"ga",36:"sq",37:"ro",38:"cz",39:"sk",40:"si",41:"yi",42:"sr",43:"mk",44:"bg",45:"uk",46:"be",47:"uz",48:"kk",49:"az-Cyrl",50:"az-Arab",51:"hy",52:"ka",53:"mo",54:"ky",55:"tg",56:"tk",57:"mn-CN",58:"mn",59:"ps",60:"ks",61:"ku",62:"sd",63:"bo",64:"ne",65:"sa",66:"mr",67:"bn",68:"as",69:"gu",70:"pa",71:"or",72:"ml",73:"kn",74:"ta",75:"te",76:"si",77:"my",78:"km",79:"lo",80:"vi",81:"id",82:"tl",83:"ms",84:"ms-Arab",85:"am",86:"ti",87:"om",88:"so",89:"sw",90:"rw",91:"rn",92:"ny",93:"mg",94:"eo",128:"cy",129:"eu",130:"ca",131:"la",132:"qu",133:"gn",134:"ay",135:"tt",136:"ug",137:"dz",138:"jv",139:"su",140:"gl",141:"af",142:"br",143:"iu",144:"gd",145:"gv",146:"ga",147:"to",148:"el-polyton",149:"kl",150:"az",151:"nn"},s={0:0,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:5,11:1,12:4,13:0,14:6,15:0,16:0,17:0,18:0,19:2,20:4,21:9,22:21,23:3,24:29,25:29,26:29,27:29,28:29,29:0,30:0,31:4,32:7,33:25,34:0,35:0,36:0,37:0,38:29,39:29,40:0,41:5,42:7,43:7,44:7,45:7,46:7,47:7,48:7,49:7,50:4,51:24,52:23,53:7,54:7,55:7,56:7,57:27,58:7,59:4,60:4,61:4,62:4,63:26,64:9,65:9,66:9,67:13,68:13,69:11,70:10,71:12,72:17,73:16,74:14,75:15,76:18,77:19,78:20,79:22,80:30,81:0,82:0,83:0,84:4,85:28,86:28,87:28,88:0,89:0,90:0,91:0,92:0,93:0,94:0,128:0,129:0,130:0,131:0,132:0,133:0,134:0,135:7,136:4,137:26,138:0,139:0,140:0,141:0,142:0,143:28,144:0,145:0,146:0,147:0,148:6,149:0,150:0,151:0},t={1078:"af",1052:"sq",1156:"gsw",1118:"am",5121:"ar-DZ",15361:"ar-BH",3073:"ar",2049:"ar-IQ",11265:"ar-JO",13313:"ar-KW",12289:"ar-LB",4097:"ar-LY",6145:"ary",8193:"ar-OM",16385:"ar-QA",1025:"ar-SA",10241:"ar-SY",7169:"aeb",14337:"ar-AE",9217:"ar-YE",1067:"hy",1101:"as",2092:"az-Cyrl",1068:"az",1133:"ba",1069:"eu",1059:"be",2117:"bn",1093:"bn-IN",
8218:"bs-Cyrl",5146:"bs",1150:"br",1026:"bg",1027:"ca",3076:"zh-HK",5124:"zh-MO",2052:"zh",4100:"zh-SG",1028:"zh-TW",1155:"co",1050:"hr",4122:"hr-BA",1029:"cs",1030:"da",1164:"prs",1125:"dv",2067:"nl-BE",1043:"nl",3081:"en-AU",10249:"en-BZ",4105:"en-CA",9225:"en-029",16393:"en-IN",6153:"en-IE",8201:"en-JM",17417:"en-MY",5129:"en-NZ",13321:"en-PH",18441:"en-SG",7177:"en-ZA",11273:"en-TT",2057:"en-GB",1033:"en",12297:"en-ZW",1061:"et",1080:"fo",1124:"fil",1035:"fi",2060:"fr-BE",3084:"fr-CA",1036:"fr",5132:"fr-LU",6156:"fr-MC",4108:"fr-CH",1122:"fy",1110:"gl",1079:"ka",3079:"de-AT",1031:"de",5127:"de-LI",4103:"de-LU",2055:"de-CH",1032:"el",1135:"kl",1095:"gu",1128:"ha",1037:"he",1081:"hi",1038:"hu",1039:"is",1136:"ig",1057:"id",1117:"iu",2141:"iu-Latn",2108:"ga",1076:"xh",1077:"zu",1040:"it",2064:"it-CH",1041:"ja",1099:"kn",1087:"kk",1107:"km",1158:"quc",1159:"rw",1089:"sw",1111:"kok",1042:"ko",1088:"ky",1108:"lo",1062:"lv",1063:"lt",2094:"dsb",1134:"lb",1071:"mk",2110:"ms-BN",1086:"ms",1100:"ml",1082:"mt",1153:"mi",1146:"arn",1102:"mr",1148:"moh",1104:"mn",2128:"mn-CN",1121:"ne",1044:"nb",2068:"nn",1154:"oc",1096:"or",1123:"ps",1045:"pl",1046:"pt",2070:"pt-PT",1094:"pa",1131:"qu-BO",2155:"qu-EC",3179:"qu",1048:"ro",1047:"rm",1049:"ru",9275:"smn",4155:"smj-NO",5179:"smj",3131:"se-FI",1083:"se",2107:"se-SE",8251:"sms",6203:"sma-NO",7227:"sms",1103:"sa",7194:"sr-Cyrl-BA",3098:"sr",6170:"sr-Latn-BA",2074:"sr-Latn",1132:"nso",1074:"tn",1115:"si",1051:"sk",1060:"sl",11274:"es-AR",16394:"es-BO",13322:"es-CL",9226:"es-CO",5130:"es-CR",7178:"es-DO",12298:"es-EC",17418:"es-SV",4106:"es-GT",18442:"es-HN",2058:"es-MX",19466:"es-NI",6154:"es-PA",15370:"es-PY",10250:"es-PE",20490:"es-PR",3082:"es",1034:"es",21514:"es-US",14346:"es-UY",8202:"es-VE",2077:"sv-FI",1053:"sv",1114:"syr",1064:"tg",2143:"tzm",1097:"ta",1092:"tt",1098:"te",1054:"th",1105:"bo",1055:"tr",1090:"tk",1152:"ug",1058:"uk",1070:"hsb",1056:"ur",2115:"uz-Cyrl",1091:"uz",1066:"vi",1106:"cy",1160:"wo",1157:"sah",1144:"ii",1130:"yo"},u="utf-16",v={0:"macintosh",1:"x-mac-japanese",2:"x-mac-chinesetrad",3:"x-mac-korean",6:"x-mac-greek",7:"x-mac-cyrillic",9:"x-mac-devanagai",10:"x-mac-gurmukhi",11:"x-mac-gujarati",12:"x-mac-oriya",13:"x-mac-bengali",14:"x-mac-tamil",15:"x-mac-telugu",16:"x-mac-kannada",17:"x-mac-malayalam",18:"x-mac-sinhalese",19:"x-mac-burmese",20:"x-mac-khmer",21:"x-mac-thai",22:"x-mac-lao",23:"x-mac-georgian",24:"x-mac-armenian",25:"x-mac-chinesesimp",26:"x-mac-tibetan",27:"x-mac-mongolian",28:"x-mac-ethiopic",29:"x-mac-ce",30:"x-mac-vietnamese",31:"x-mac-extarabic"},w={15:"x-mac-icelandic",17:"x-mac-turkish",18:"x-mac-croatian",24:"x-mac-ce",25:"x-mac-ce",26:"x-mac-ce",27:"x-mac-ce",28:"x-mac-ce",30:"x-mac-icelandic",37:"x-mac-romanian",38:"x-mac-ce",39:"x-mac-ce",40:"x-mac-ce",143:"x-mac-inuit",146:"x-mac-gaelic"};c.parse=f,c.make=k},{"../parse":9,"../table":11,"../types":28}],25:[function(a,b,c){"use strict";function d(a){for(var b=0;b<i.length;b+=1){var c=i[b];if(a>=c.begin&&a<c.end)return b}return-1}function e(a,b){var c={},d=new g.Parser(a,b);c.version=d.parseUShort(),c.xAvgCharWidth=d.parseShort(),c.usWeightClass=d.parseUShort(),c.usWidthClass=d.parseUShort(),c.fsType=d.parseUShort(),c.ySubscriptXSize=d.parseShort(),c.ySubscriptYSize=d.parseShort(),c.ySubscriptXOffset=d.parseShort(),c.ySubscriptYOffset=d.parseShort(),c.ySuperscriptXSize=d.parseShort(),c.ySuperscriptYSize=d.parseShort(),c.ySuperscriptXOffset=d.parseShort(),c.ySuperscriptYOffset=d.parseShort(),c.yStrikeoutSize=d.parseShort(),c.yStrikeoutPosition=d.parseShort(),c.sFamilyClass=d.parseShort(),c.panose=[];for(var e=0;10>e;e++)c.panose[e]=d.parseByte();return c.ulUnicodeRange1=d.parseULong(),c.ulUnicodeRange2=d.parseULong(),c.ulUnicodeRange3=d.parseULong(),c.ulUnicodeRange4=d.parseULong(),c.achVendID=String.fromCharCode(d.parseByte(),d.parseByte(),d.parseByte(),d.parseByte()),c.fsSelection=d.parseUShort(),c.usFirstCharIndex=d.parseUShort(),c.usLastCharIndex=d.parseUShort(),c.sTypoAscender=d.parseShort(),c.sTypoDescender=d.parseShort(),c.sTypoLineGap=d.parseShort(),c.usWinAscent=d.parseUShort(),c.usWinDescent=d.parseUShort(),c.version>=1&&(c.ulCodePageRange1=d.parseULong(),c.ulCodePageRange2=d.parseULong()),c.version>=2&&(c.sxHeight=d.parseShort(),c.sCapHeight=d.parseShort(),c.usDefaultChar=d.parseUShort(),c.usBreakChar=d.parseUShort(),c.usMaxContent=d.parseUShort()),c}function f(a){return new h.Table("OS/2",[{name:"version",type:"USHORT",value:3},{name:"xAvgCharWidth",type:"SHORT",value:0},{name:"usWeightClass",type:"USHORT",value:0},{name:"usWidthClass",type:"USHORT",value:0},{name:"fsType",type:"USHORT",value:0},{name:"ySubscriptXSize",type:"SHORT",value:650},{name:"ySubscriptYSize",type:"SHORT",value:699},{name:"ySubscriptXOffset",type:"SHORT",value:0},{name:"ySubscriptYOffset",type:"SHORT",value:140},{name:"ySuperscriptXSize",type:"SHORT",value:650},{name:"ySuperscriptYSize",type:"SHORT",value:699},{name:"ySuperscriptXOffset",type:"SHORT",value:0},{name:"ySuperscriptYOffset",type:"SHORT",value:479},{name:"yStrikeoutSize",type:"SHORT",value:49},{name:"yStrikeoutPosition",type:"SHORT",value:258},{name:"sFamilyClass",type:"SHORT",value:0},{name:"bFamilyType",type:"BYTE",value:0},{name:"bSerifStyle",type:"BYTE",value:0},{name:"bWeight",type:"BYTE",value:0},{name:"bProportion",type:"BYTE",value:0},{name:"bContrast",type:"BYTE",value:0},{name:"bStrokeVariation",type:"BYTE",value:0},{name:"bArmStyle",type:"BYTE",value:0},{name:"bLetterform",type:"BYTE",value:0},{name:"bMidline",type:"BYTE",value:0},{name:"bXHeight",type:"BYTE",value:0},{name:"ulUnicodeRange1",type:"ULONG",value:0},{name:"ulUnicodeRange2",type:"ULONG",value:0},{name:"ulUnicodeRange3",type:"ULONG",value:0},{name:"ulUnicodeRange4",type:"ULONG",value:0},{name:"achVendID",type:"CHARARRAY",value:"XXXX"},{name:"fsSelection",type:"USHORT",value:0},{name:"usFirstCharIndex",type:"USHORT",value:0},{name:"usLastCharIndex",type:"USHORT",value:0},{name:"sTypoAscender",type:"SHORT",value:0},{name:"sTypoDescender",type:"SHORT",value:0},{name:"sTypoLineGap",type:"SHORT",value:0},{name:"usWinAscent",type:"USHORT",value:0},{name:"usWinDescent",type:"USHORT",value:0},{name:"ulCodePageRange1",type:"ULONG",value:0},{name:"ulCodePageRange2",type:"ULONG",value:0},{name:"sxHeight",type:"SHORT",value:0},{name:"sCapHeight",type:"SHORT",value:0},{name:"usDefaultChar",type:"USHORT",value:0},{name:"usBreakChar",type:"USHORT",value:0},{name:"usMaxContext",type:"USHORT",value:0}],a)}var g=a("../parse"),h=a("../table"),i=[{begin:0,end:127},{begin:128,end:255},{begin:256,end:383},{begin:384,end:591},{begin:592,end:687},{begin:688,end:767},{begin:768,end:879},{begin:880,end:1023},{begin:11392,end:11519},{begin:1024,end:1279},{begin:1328,end:1423},{begin:1424,end:1535},{begin:42240,end:42559},{begin:1536,end:1791},{begin:1984,end:2047},{begin:2304,end:2431},{begin:2432,end:2559},{begin:2560,end:2687},{begin:2688,end:2815},{begin:2816,end:2943},{begin:2944,end:3071},{begin:3072,end:3199},{begin:3200,end:3327},{begin:3328,end:3455},{begin:3584,end:3711},{begin:3712,end:3839},{begin:4256,end:4351},{begin:6912,end:7039},{begin:4352,end:4607},{begin:7680,end:7935},{begin:7936,end:8191},{begin:8192,end:8303},{begin:8304,end:8351},{begin:8352,end:8399},{begin:8400,end:8447},{begin:8448,end:8527},{begin:8528,end:8591},{begin:8592,end:8703},{begin:8704,end:8959},{begin:8960,end:9215},{begin:9216,end:9279},{begin:9280,end:9311},{begin:9312,end:9471},{begin:9472,end:9599},{begin:9600,end:9631},{begin:9632,end:9727},{begin:9728,end:9983},{begin:9984,end:10175},{begin:12288,end:12351},{begin:12352,end:12447},{begin:12448,end:12543},{begin:12544,end:12591},{begin:12592,end:12687},{begin:43072,end:43135},{begin:12800,end:13055},{begin:13056,end:13311},{begin:44032,end:55215},{begin:55296,end:57343},{begin:67840,end:67871},{begin:19968,end:40959},{begin:57344,end:63743},{begin:12736,end:12783},{begin:64256,end:64335},{begin:64336,end:65023},{begin:65056,end:65071},{begin:65040,end:65055},{begin:65104,end:65135},{begin:65136,end:65279},{begin:65280,end:65519},{begin:65520,end:65535},{begin:3840,end:4095},{begin:1792,end:1871},{begin:1920,end:1983},{begin:3456,end:3583},{begin:4096,end:4255},{begin:4608,end:4991},{begin:5024,end:5119},{begin:5120,end:5759},{begin:5760,end:5791},{begin:5792,end:5887},{begin:6016,end:6143},{begin:6144,end:6319},{begin:10240,end:10495},{begin:40960,end:42127},{begin:5888,end:5919},{begin:66304,end:66351},{begin:66352,end:66383},{begin:66560,end:66639},{begin:118784,end:119039},{begin:119808,end:120831},{begin:1044480,end:1048573},{begin:65024,end:65039},{begin:917504,end:917631},{begin:6400,end:6479},{begin:6480,end:6527},{begin:6528,end:6623},{begin:6656,end:6687},{begin:11264,end:11359},{begin:11568,end:11647},{begin:19904,end:19967},{begin:43008,end:43055},{begin:65536,end:65663},{begin:65856,end:65935},{begin:66432,end:66463},{begin:66464,end:66527},{begin:66640,end:66687},{begin:66688,end:66735},{begin:67584,end:67647},{begin:68096,end:68191},{begin:119552,end:119647},{begin:73728,end:74751},{begin:119648,end:119679},{begin:7040,end:7103},{begin:7168,end:7247},{begin:7248,end:7295},{begin:43136,end:43231},{begin:43264,end:43311},{begin:43312,end:43359},{begin:43520,end:43615},{begin:65936,end:65999},{begin:66e3,end:66047},{begin:66208,end:66271},{begin:127024,end:127135}];c.unicodeRanges=i,c.getUnicodeRange=d,c.parse=e,c.make=f},{"../parse":9,"../table":11}],26:[function(a,b,c){"use strict";function d(a,b){var c,d={},e=new g.Parser(a,b);switch(d.version=e.parseVersion(),d.italicAngle=e.parseFixed(),d.underlinePosition=e.parseShort(),d.underlineThickness=e.parseShort(),d.isFixedPitch=e.parseULong(),d.minMemType42=e.parseULong(),d.maxMemType42=e.parseULong(),d.minMemType1=e.parseULong(),d.maxMemType1=e.parseULong(),d.version){case 1:d.names=f.standardNames.slice();break;case 2:for(d.numberOfGlyphs=e.parseUShort(),d.glyphNameIndex=new Array(d.numberOfGlyphs),c=0;c<d.numberOfGlyphs;c++)d.glyphNameIndex[c]=e.parseUShort();for(d.names=[],c=0;c<d.numberOfGlyphs;c++)if(d.glyphNameIndex[c]>=f.standardNames.length){var h=e.parseChar();d.names.push(e.parseString(h))}break;case 2.5:for(d.numberOfGlyphs=e.parseUShort(),d.offset=new Array(d.numberOfGlyphs),c=0;c<d.numberOfGlyphs;c++)d.offset[c]=e.parseChar()}return d}function e(){return new h.Table("post",[{name:"version",type:"FIXED",value:196608},{name:"italicAngle",type:"FIXED",value:0},{name:"underlinePosition",type:"FWORD",value:0},{name:"underlineThickness",type:"FWORD",value:0},{name:"isFixedPitch",type:"ULONG",value:0},{name:"minMemType42",type:"ULONG",value:0},{name:"maxMemType42",type:"ULONG",value:0},{name:"minMemType1",type:"ULONG",value:0},{name:"maxMemType1",type:"ULONG",value:0}])}var f=a("../encoding"),g=a("../parse"),h=a("../table");c.parse=d,c.make=e},{"../encoding":4,"../parse":9,"../table":11}],27:[function(a,b,c){"use strict";function d(a){return Math.log(a)/Math.log(2)|0}function e(a){for(;a.length%4!==0;)a.push(0);for(var b=0,c=0;c<a.length;c+=4)b+=(a[c]<<24)+(a[c+1]<<16)+(a[c+2]<<8)+a[c+3];return b%=Math.pow(2,32)}function f(a,b,c,d){return new l.Table("Table Record",[{name:"tag",type:"TAG",value:void 0!==a?a:""},{name:"checkSum",type:"ULONG",value:void 0!==b?b:0},{name:"offset",type:"ULONG",value:void 0!==c?c:0},{name:"length",type:"ULONG",value:void 0!==d?d:0}])}function g(a){var b=new l.Table("sfnt",[{name:"version",type:"TAG",value:"OTTO"},{name:"numTables",type:"USHORT",value:0},{name:"searchRange",type:"USHORT",value:0},{name:"entrySelector",type:"USHORT",value:0},{name:"rangeShift",type:"USHORT",value:0}]);b.tables=a,b.numTables=a.length;var c=Math.pow(2,d(b.numTables));b.searchRange=16*c,b.entrySelector=d(c),b.rangeShift=16*b.numTables-b.searchRange;for(var g=[],h=[],i=b.sizeOf()+f().sizeOf()*b.numTables;i%4!==0;)i+=1,h.push({name:"padding",type:"BYTE",value:0});for(var j=0;j<a.length;j+=1){var m=a[j];k.argument(4===m.tableName.length,"Table name"+m.tableName+" is invalid.");var n=m.sizeOf(),o=f(m.tableName,e(m.encode()),i,n);for(g.push({name:o.tag+" Table Record",type:"TABLE",value:o}),h.push({name:m.tableName+" table",type:"TABLE",value:m}),i+=n,k.argument(!isNaN(i),"Something went wrong calculating the offset.");i%4!==0;)i+=1,h.push({name:"padding",type:"BYTE",value:0})}return g.sort(function(a,b){return a.value.tag>b.value.tag?1:-1}),b.fields=b.fields.concat(g),b.fields=b.fields.concat(h),b}function h(a,b,c){for(var d=0;d<b.length;d+=1){var e=a.charToGlyphIndex(b[d]);if(e>0){var f=a.glyphs.get(e);return f.getMetrics()}}return c}function i(a){for(var b=0,c=0;c<a.length;c+=1)b+=a[c];return b/a.length}function j(a){for(var b,c=[],d=[],f=[],j=[],k=[],l=[],w=[],x=0,y=0,z=0,A=0,B=0,C=0;C<a.glyphs.length;C+=1){var D=a.glyphs.get(C),E=0|D.unicode;(b>E||null===b)&&(b=E),E>x&&(x=E);var F=u.getUnicodeRange(E);if(32>F)y|=1<<F;else if(64>F)z|=1<<F-32;else if(96>F)A|=1<<F-64;else{if(!(123>F))throw new Error("Unicode ranges bits > 123 are reserved for internal usage");B|=1<<F-96}if(".notdef"!==D.name){var G=D.getMetrics();c.push(G.xMin),d.push(G.yMin),f.push(G.xMax),j.push(G.yMax),l.push(G.leftSideBearing),w.push(G.rightSideBearing),k.push(D.advanceWidth)}}var H={xMin:Math.min.apply(null,c),yMin:Math.min.apply(null,d),xMax:Math.max.apply(null,f),yMax:Math.max.apply(null,j),advanceWidthMax:Math.max.apply(null,k),advanceWidthAvg:i(k),minLeftSideBearing:Math.min.apply(null,l),maxLeftSideBearing:Math.max.apply(null,l),minRightSideBearing:Math.min.apply(null,w)};H.ascender=void 0!==a.ascender?a.ascender:H.yMax,H.descender=void 0!==a.descender?a.descender:H.yMin;var I=o.make({unitsPerEm:a.unitsPerEm,xMin:H.xMin,yMin:H.yMin,xMax:H.xMax,yMax:H.yMax}),J=p.make({ascender:H.ascender,descender:H.descender,advanceWidthMax:H.advanceWidthMax,minLeftSideBearing:H.minLeftSideBearing,minRightSideBearing:H.minRightSideBearing,xMaxExtent:H.maxLeftSideBearing+(H.xMax-H.xMin),numberOfHMetrics:a.glyphs.length}),K=s.make(a.glyphs.length),L=u.make({xAvgCharWidth:Math.round(H.advanceWidthAvg),usWeightClass:500,usWidthClass:5,usFirstCharIndex:b,usLastCharIndex:x,ulUnicodeRange1:y,ulUnicodeRange2:z,ulUnicodeRange3:A,ulUnicodeRange4:B,sTypoAscender:H.ascender,sTypoDescender:H.descender,sTypoLineGap:0,usWinAscent:H.ascender,usWinDescent:-H.descender,sxHeight:h(a,"xyvw",{yMax:0}).yMax,sCapHeight:h(a,"HIKLEFJMNTZBDPRAGOQSUVWXY",H).yMax,usBreakChar:a.hasChar(" ")?32:0}),M=q.make(a.glyphs),N=m.make(a.glyphs),O=a.getEnglishName("fontFamily"),P=a.getEnglishName("fontSubfamily"),Q=O+" "+P,R=a.getEnglishName("postScriptName");R||(R=O.replace(/\s/g,"")+"-"+P);var S={};for(var T in a.names)S[T]=a.names[T];S.uniqueID||(S.uniqueID={en:a.getEnglishName("manufacturer")+":"+Q}),S.postScriptName||(S.postScriptName={en:R}),S.preferredFamily||(S.preferredFamily=a.names.fontFamily),S.preferredSubfamily||(S.preferredSubfamily=a.names.fontSubfamily);var U=[],V=t.make(S,U),W=U.length>0?r.make(U):void 0,X=v.make(),Y=n.make(a.glyphs,{version:a.getEnglishName("version"),fullName:Q,familyName:O,weightName:P,postScriptName:R,unitsPerEm:a.unitsPerEm}),Z=[I,J,K,L,V,N,X,Y,M];W&&Z.push(W);var $=g(Z),_=$.encode(),aa=e(_),ba=$.fields,ca=!1;for(C=0;C<ba.length;C+=1)if("head table"===ba[C].name){ba[C].value.checkSumAdjustment=2981146554-aa,ca=!0;break}if(!ca)throw new Error("Could not find head table with checkSum to adjust.");return $}var k=a("../check"),l=a("../table"),m=a("./cmap"),n=a("./cff"),o=a("./head"),p=a("./hhea"),q=a("./hmtx"),r=a("./ltag"),s=a("./maxp"),t=a("./name"),u=a("./os2"),v=a("./post");c.computeCheckSum=e,c.make=g,c.fontToTable=j},{"../check":2,"../table":11,"./cff":12,"./cmap":13,"./head":17,"./hhea":18,"./hmtx":19,"./ltag":22,"./maxp":23,"./name":24,"./os2":25,"./post":26}],28:[function(a,b,c){"use strict";function d(a){return function(){return a}}var e=a("./check"),f=32768,g=2147483648,h={},i={},j={};i.BYTE=function(a){return e.argument(a>=0&&255>=a,"Byte value should be between 0 and 255."),[a]},j.BYTE=d(1),i.CHAR=function(a){return[a.charCodeAt(0)]},j.CHAR=d(1),i.CHARARRAY=function(a){for(var b=[],c=0;c<a.length;c+=1)b.push(a.charCodeAt(c));return b},j.CHARARRAY=function(a){return a.length},i.USHORT=function(a){return[a>>8&255,255&a]},j.USHORT=d(2),i.SHORT=function(a){return a>=f&&(a=-(2*f-a)),[a>>8&255,255&a]},j.SHORT=d(2),i.UINT24=function(a){return[a>>16&255,a>>8&255,255&a]},j.UINT24=d(3),i.ULONG=function(a){return[a>>24&255,a>>16&255,a>>8&255,255&a]},j.ULONG=d(4),i.LONG=function(a){return a>=g&&(a=-(2*g-a)),[a>>24&255,a>>16&255,a>>8&255,255&a]},j.LONG=d(4),i.FIXED=i.ULONG,j.FIXED=j.ULONG,i.FWORD=i.SHORT,j.FWORD=j.SHORT,i.UFWORD=i.USHORT,j.UFWORD=j.USHORT,i.LONGDATETIME=function(){return[0,0,0,0,0,0,0,0]},j.LONGDATETIME=d(8),i.TAG=function(a){return e.argument(4===a.length,"Tag should be exactly 4 ASCII characters."),[a.charCodeAt(0),a.charCodeAt(1),a.charCodeAt(2),a.charCodeAt(3)]},j.TAG=d(4),i.Card8=i.BYTE,j.Card8=j.BYTE,i.Card16=i.USHORT,j.Card16=j.USHORT,i.OffSize=i.BYTE,j.OffSize=j.BYTE,i.SID=i.USHORT,j.SID=j.USHORT,i.NUMBER=function(a){return a>=-107&&107>=a?[a+139]:a>=108&&1131>=a?(a-=108,[(a>>8)+247,255&a]):a>=-1131&&-108>=a?(a=-a-108,[(a>>8)+251,255&a]):a>=-32768&&32767>=a?i.NUMBER16(a):i.NUMBER32(a)},j.NUMBER=function(a){return i.NUMBER(a).length},i.NUMBER16=function(a){return[28,a>>8&255,255&a]},j.NUMBER16=d(3),i.NUMBER32=function(a){return[29,a>>24&255,a>>16&255,a>>8&255,255&a]},j.NUMBER32=d(5),i.REAL=function(a){var b=a.toString(),c=/\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(b);if(c){var d=parseFloat("1e"+((c[2]?+c[2]:0)+c[1].length));b=(Math.round(a*d)/d).toString()}var e,f,g="";for(e=0,f=b.length;f>e;e+=1){var h=b[e];g+="e"===h?"-"===b[++e]?"c":"b":"."===h?"a":"-"===h?"e":h}g+=1&g.length?"f":"ff";var i=[30];for(e=0,f=g.length;f>e;e+=2)i.push(parseInt(g.substr(e,2),16));return i},j.REAL=function(a){return i.REAL(a).length},i.NAME=i.CHARARRAY,j.NAME=j.CHARARRAY,i.STRING=i.CHARARRAY,j.STRING=j.CHARARRAY,h.UTF16=function(a,b,c){for(var d=[],e=c/2,f=0;e>f;f++,b+=2)d[f]=a.getUint16(b);return String.fromCharCode.apply(null,d)},i.UTF16=function(a){for(var b=[],c=0;c<a.length;c+=1){var d=a.charCodeAt(c);b.push(d>>8&255),b.push(255&d)}return b},j.UTF16=function(a){return 2*a.length};var k={"x-mac-croatian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈ƫȅ ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ","x-mac-cyrillic":"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю","x-mac-gaelic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØḂ±≤≥ḃĊċḊḋḞḟĠġṀæøṁṖṗɼƒſṠ«»… ÀÃÕŒœ–—“”‘’ṡẛÿŸṪ€‹›Ŷŷṫ·Ỳỳ⁊ÂÊÁËÈÍÎÏÌÓÔ♣ÒÚÛÙıÝýŴŵẄẅẀẁẂẃ","x-mac-greek":"Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦€ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ­","x-mac-icelandic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüݰ¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-inuit":"ᐃᐄᐅᐆᐊᐋᐱᐲᐳᐴᐸᐹᑉᑎᑏᑐᑑᑕᑖᑦᑭᑮᑯᑰᑲᑳᒃᒋᒌᒍᒎᒐᒑ°ᒡᒥᒦ•¶ᒧ®©™ᒨᒪᒫᒻᓂᓃᓄᓅᓇᓈᓐᓯᓰᓱᓲᓴᓵᔅᓕᓖᓗᓘᓚᓛᓪᔨᔩᔪᔫᔭ… ᔮᔾᕕᕖᕗ–—“”‘’ᕘᕙᕚᕝᕆᕇᕈᕉᕋᕌᕐᕿᖀᖁᖂᖃᖄᖅᖏᖐᖑᖒᖓᖔᖕᙱᙲᙳᙴᙵᙶᖖᖠᖡᖢᖣᖤᖥᖦᕼŁł","x-mac-ce":"ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ",macintosh:"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-romanian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂȘ∞±≤≥¥µ∂∑∏π∫ªºΩăș¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›Țț‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-turkish":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙˆ˜¯˘˙˚¸˝˛ˇ"};h.MACSTRING=function(a,b,c,d){var e=k[d];if(void 0===e)return void 0;for(var f="",g=0;c>g;g++){var h=a.getUint8(b+g);f+=127>=h?String.fromCharCode(h):e[127&h]}return f};var l,m="function"==typeof WeakMap&&new WeakMap,n=function(a){if(!l){l={};for(var b in k)l[b]=new String(b)}var c=l[a];if(void 0===c)return void 0;if(m){var d=m.get(c);if(void 0!==d)return d}var e=k[a];if(void 0===e)return void 0;for(var f={},g=0;g<e.length;g++)f[e.charCodeAt(g)]=g+128;return m&&m.set(c,f),f};i.MACSTRING=function(a,b){var c=n(b);if(void 0===c)return void 0;for(var d=[],e=0;e<a.length;e++){var f=a.charCodeAt(e);if(f>=128&&(f=c[f],void 0===f))return void 0;d.push(f)}return d},j.MACSTRING=function(a,b){var c=i.MACSTRING(a,b);return void 0!==c?c.length:0},i.INDEX=function(a){var b,c=1,d=[c],e=[],f=0;for(b=0;b<a.length;b+=1){var g=i.OBJECT(a[b]);Array.prototype.push.apply(e,g),f+=g.length,c+=g.length,d.push(c)}if(0===e.length)return[0,0];var h=[],j=1+Math.floor(Math.log(f)/Math.log(2))/8|0,k=[void 0,i.BYTE,i.USHORT,i.UINT24,i.ULONG][j];for(b=0;b<d.length;b+=1){var l=k(d[b]);Array.prototype.push.apply(h,l)}return Array.prototype.concat(i.Card16(a.length),i.OffSize(j),h,e)},j.INDEX=function(a){return i.INDEX(a).length},i.DICT=function(a){for(var b=[],c=Object.keys(a),d=c.length,e=0;d>e;e+=1){var f=parseInt(c[e],0),g=a[f];b=b.concat(i.OPERAND(g.value,g.type)),b=b.concat(i.OPERATOR(f))}return b},j.DICT=function(a){return i.DICT(a).length},i.OPERATOR=function(a){return 1200>a?[a]:[12,a-1200]},i.OPERAND=function(a,b){var c=[];if(Array.isArray(b))for(var d=0;d<b.length;d+=1)e.argument(a.length===b.length,"Not enough arguments given for type"+b),c=c.concat(i.OPERAND(a[d],b[d]));else if("SID"===b)c=c.concat(i.NUMBER(a));else if("offset"===b)c=c.concat(i.NUMBER32(a));else if("number"===b)c=c.concat(i.NUMBER(a));else{if("real"!==b)throw new Error("Unknown operand type "+b);c=c.concat(i.REAL(a))}return c},i.OP=i.BYTE,j.OP=j.BYTE;var o="function"==typeof WeakMap&&new WeakMap;i.CHARSTRING=function(a){if(o){var b=o.get(a);if(void 0!==b)return b}for(var c=[],d=a.length,e=0;d>e;e+=1){var f=a[e];c=c.concat(i[f.type](f.value))}return o&&o.set(a,c),c},j.CHARSTRING=function(a){return i.CHARSTRING(a).length},i.OBJECT=function(a){var b=i[a.type];return e.argument(void 0!==b,"No encoding function for type "+a.type),b(a.value)},j.OBJECT=function(a){var b=j[a.type];return e.argument(void 0!==b,"No sizeOf function for type "+a.type),b(a.value)},i.TABLE=function(a){for(var b=[],c=a.fields.length,d=0;c>d;d+=1){var f=a.fields[d],g=i[f.type];e.argument(void 0!==g,"No encoding function for field type "+f.type);var h=a[f.name];void 0===h&&(h=f.value);var j=g(h);b=b.concat(j)}return b},j.TABLE=function(a){for(var b=0,c=a.fields.length,d=0;c>d;d+=1){var f=a.fields[d],g=j[f.type];e.argument(void 0!==g,"No sizeOf function for field type "+f.type);var h=a[f.name];void 0===h&&(h=f.value),b+=g(h)}return b},i.LITERAL=function(a){return a},j.LITERAL=function(a){return a.length},c.decode=h,c.encode=i,c.sizeOf=j},{"./check":2}],29:[function(_dereq_,module,exports){!function(a,b,c){"undefined"!=typeof module&&module.exports?module.exports=c():"function"==typeof define&&define.amd?define(c):b[a]=c()}("reqwest",this,function(){function succeed(a){var b=protocolRe.exec(a.url);return b=b&&b[1]||window.location.protocol,httpsRe.test(b)?twoHundo.test(a.request.status):!!a.request.response}function handleReadyState(a,b,c){return function(){return a._aborted?c(a.request):a._timedOut?c(a.request,"Request is aborted: timeout"):void(a.request&&4==a.request[readyState]&&(a.request.onreadystatechange=noop,succeed(a)?b(a.request):c(a.request)))}}function setHeaders(a,b){var c,d=b.headers||{};d.Accept=d.Accept||defaultHeaders.accept[b.type]||defaultHeaders.accept["*"];var e="function"==typeof FormData&&b.data instanceof FormData;b.crossOrigin||d[requestedWith]||(d[requestedWith]=defaultHeaders.requestedWith),d[contentType]||e||(d[contentType]=b.contentType||defaultHeaders.contentType);for(c in d)d.hasOwnProperty(c)&&"setRequestHeader"in a&&a.setRequestHeader(c,d[c])}function setCredentials(a,b){"undefined"!=typeof b.withCredentials&&"undefined"!=typeof a.withCredentials&&(a.withCredentials=!!b.withCredentials)}function generalCallback(a){lastValue=a}function urlappend(a,b){return a+(/\?/.test(a)?"&":"?")+b}function handleJsonp(a,b,c,d){var e=uniqid++,f=a.jsonpCallback||"callback",g=a.jsonpCallbackName||reqwest.getcallbackPrefix(e),h=new RegExp("((^|\\?|&)"+f+")=([^&]+)"),i=d.match(h),j=doc.createElement("script"),k=0,l=-1!==navigator.userAgent.indexOf("MSIE 10.0");return i?"?"===i[3]?d=d.replace(h,"$1="+g):g=i[3]:d=urlappend(d,f+"="+g),win[g]=generalCallback,j.type="text/javascript",j.src=d,j.async=!0,"undefined"==typeof j.onreadystatechange||l||(j.htmlFor=j.id="_reqwest_"+e),j.onload=j.onreadystatechange=function(){return j[readyState]&&"complete"!==j[readyState]&&"loaded"!==j[readyState]||k?!1:(j.onload=j.onreadystatechange=null,j.onclick&&j.onclick(),b(lastValue),lastValue=void 0,head.removeChild(j),void(k=1))},head.appendChild(j),{abort:function(){j.onload=j.onreadystatechange=null,c({},"Request is aborted: timeout",{}),lastValue=void 0,head.removeChild(j),k=1}}}function getRequest(a,b){var c,d=this.o,e=(d.method||"GET").toUpperCase(),f="string"==typeof d?d:d.url,g=d.processData!==!1&&d.data&&"string"!=typeof d.data?reqwest.toQueryString(d.data):d.data||null,h=!1;return"jsonp"!=d.type&&"GET"!=e||!g||(f=urlappend(f,g),g=null),"jsonp"==d.type?handleJsonp(d,a,b,f):(c=d.xhr&&d.xhr(d)||xhr(d),c.open(e,f,d.async===!1?!1:!0),setHeaders(c,d),setCredentials(c,d),win[xDomainRequest]&&c instanceof win[xDomainRequest]?(c.onload=a,c.onerror=b,c.onprogress=function(){},h=!0):c.onreadystatechange=handleReadyState(this,a,b),d.before&&d.before(c),h?setTimeout(function(){c.send(g)},200):c.send(g),c)}function Reqwest(a,b){this.o=a,this.fn=b,init.apply(this,arguments)}function setType(a){return a.match("json")?"json":a.match("javascript")?"js":a.match("text")?"html":a.match("xml")?"xml":void 0}function init(o,fn){function complete(a){for(o.timeout&&clearTimeout(self.timeout),self.timeout=null;self._completeHandlers.length>0;)self._completeHandlers.shift()(a)}function success(resp){var type=o.type||resp&&setType(resp.getResponseHeader("Content-Type"));resp="jsonp"!==type?self.request:resp;var filteredResponse=globalSetupOptions.dataFilter(resp.responseText,type),r=filteredResponse;try{resp.responseText=r}catch(e){}if(r)switch(type){case"json":try{resp=win.JSON?win.JSON.parse(r):eval("("+r+")")}catch(err){return error(resp,"Could not parse JSON in response",err)}break;case"js":resp=eval(r);break;case"html":resp=r;break;case"xml":resp=resp.responseXML&&resp.responseXML.parseError&&resp.responseXML.parseError.errorCode&&resp.responseXML.parseError.reason?null:resp.responseXML}for(self._responseArgs.resp=resp,self._fulfilled=!0,fn(resp),self._successHandler(resp);self._fulfillmentHandlers.length>0;)resp=self._fulfillmentHandlers.shift()(resp);complete(resp)}function timedOut(){self._timedOut=!0,self.request.abort()}function error(a,b,c){for(a=self.request,self._responseArgs.resp=a,self._responseArgs.msg=b,self._responseArgs.t=c,self._erred=!0;self._errorHandlers.length>0;)self._errorHandlers.shift()(a,b,c);complete(a)}this.url="string"==typeof o?o:o.url,this.timeout=null,this._fulfilled=!1,this._successHandler=function(){},this._fulfillmentHandlers=[],this._errorHandlers=[],this._completeHandlers=[],this._erred=!1,this._responseArgs={};var self=this;fn=fn||function(){},o.timeout&&(this.timeout=setTimeout(function(){timedOut()},o.timeout)),o.success&&(this._successHandler=function(){o.success.apply(o,arguments)}),o.error&&this._errorHandlers.push(function(){o.error.apply(o,arguments)}),o.complete&&this._completeHandlers.push(function(){o.complete.apply(o,arguments)}),this.request=getRequest.call(this,success,error)}function reqwest(a,b){return new Reqwest(a,b)}function normalize(a){return a?a.replace(/\r?\n/g,"\r\n"):""}function serial(a,b){var c,d,e,f,g=a.name,h=a.tagName.toLowerCase(),i=function(a){a&&!a.disabled&&b(g,normalize(a.attributes.value&&a.attributes.value.specified?a.value:a.text))};if(!a.disabled&&g)switch(h){case"input":/reset|button|image|file/i.test(a.type)||(c=/checkbox/i.test(a.type),d=/radio/i.test(a.type),e=a.value,(!(c||d)||a.checked)&&b(g,normalize(c&&""===e?"on":e)));break;case"textarea":b(g,normalize(a.value));break;case"select":if("select-one"===a.type.toLowerCase())i(a.selectedIndex>=0?a.options[a.selectedIndex]:null);else for(f=0;a.length&&f<a.length;f++)a.options[f].selected&&i(a.options[f])}}function eachFormElement(){var a,b,c=this,d=function(a,b){var d,e,f;for(d=0;d<b.length;d++)for(f=a[byTag](b[d]),e=0;e<f.length;e++)serial(f[e],c)};for(b=0;b<arguments.length;b++)a=arguments[b],/input|select|textarea/i.test(a.tagName)&&serial(a,c),d(a,["input","select","textarea"])}function serializeQueryString(){return reqwest.toQueryString(reqwest.serializeArray.apply(null,arguments))}function serializeHash(){var a={};return eachFormElement.apply(function(b,c){b in a?(a[b]&&!isArray(a[b])&&(a[b]=[a[b]]),a[b].push(c)):a[b]=c},arguments),a}function buildParams(a,b,c,d){var e,f,g,h=/\[\]$/;if(isArray(b))for(f=0;b&&f<b.length;f++)g=b[f],c||h.test(a)?d(a,g):buildParams(a+"["+("object"==typeof g?f:"")+"]",g,c,d);else if(b&&"[object Object]"===b.toString())for(e in b)buildParams(a+"["+e+"]",b[e],c,d);else d(a,b)}var win=window,doc=document,httpsRe=/^http/,protocolRe=/(^\w+):\/\//,twoHundo=/^(20\d|1223)$/,byTag="getElementsByTagName",readyState="readyState",contentType="Content-Type",requestedWith="X-Requested-With",head=doc[byTag]("head")[0],uniqid=0,callbackPrefix="reqwest_"+ +new Date,lastValue,xmlHttpRequest="XMLHttpRequest",xDomainRequest="XDomainRequest",noop=function(){},isArray="function"==typeof Array.isArray?Array.isArray:function(a){return a instanceof Array},defaultHeaders={contentType:"application/x-www-form-urlencoded",requestedWith:xmlHttpRequest,accept:{"*":"text/javascript, text/html, application/xml, text/xml, */*",xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript",js:"application/javascript, text/javascript"}},xhr=function(a){if(a.crossOrigin===!0){var b=win[xmlHttpRequest]?new XMLHttpRequest:null;if(b&&"withCredentials"in b)return b;if(win[xDomainRequest])return new XDomainRequest;throw new Error("Browser does not support cross-origin requests")}return win[xmlHttpRequest]?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP")},globalSetupOptions={dataFilter:function(a){return a}};return Reqwest.prototype={abort:function(){this._aborted=!0,this.request.abort()},retry:function(){init.call(this,this.o,this.fn)},then:function(a,b){return a=a||function(){},b=b||function(){},this._fulfilled?this._responseArgs.resp=a(this._responseArgs.resp):this._erred?b(this._responseArgs.resp,this._responseArgs.msg,this._responseArgs.t):(this._fulfillmentHandlers.push(a),this._errorHandlers.push(b)),this},always:function(a){return this._fulfilled||this._erred?a(this._responseArgs.resp):this._completeHandlers.push(a),this},fail:function(a){return this._erred?a(this._responseArgs.resp,this._responseArgs.msg,this._responseArgs.t):this._errorHandlers.push(a),this},"catch":function(a){return this.fail(a)}},reqwest.serializeArray=function(){var a=[];return eachFormElement.apply(function(b,c){a.push({name:b,value:c})},arguments),a},reqwest.serialize=function(){if(0===arguments.length)return"";var a,b,c=Array.prototype.slice.call(arguments,0);return a=c.pop(),a&&a.nodeType&&c.push(a)&&(a=null),a&&(a=a.type),b="map"==a?serializeHash:"array"==a?reqwest.serializeArray:serializeQueryString,b.apply(null,c)},reqwest.toQueryString=function(a,b){var c,d,e=b||!1,f=[],g=encodeURIComponent,h=function(a,b){b="function"==typeof b?b():null==b?"":b,f[f.length]=g(a)+"="+g(b)};if(isArray(a))for(d=0;a&&d<a.length;d++)h(a[d].name,a[d].value);else for(c in a)a.hasOwnProperty(c)&&buildParams(c,a[c],e,h);return f.join("&").replace(/%20/g,"+")},reqwest.getcallbackPrefix=function(){return callbackPrefix},reqwest.compat=function(a,b){return a&&(a.type&&(a.method=a.type)&&delete a.type,a.dataType&&(a.type=a.dataType),a.jsonpCallback&&(a.jsonpCallbackName=a.jsonpCallback)&&delete a.jsonpCallback,a.jsonp&&(a.jsonpCallback=a.jsonp)),new Reqwest(a,b)},reqwest.ajaxSetup=function(a){a=a||{};for(var b in a)globalSetupOptions[b]=a[b];
},reqwest})},{}],30:[function(a,b,c){"use strict";var d=a("../core/core");a("./p5.Geometry3D"),d.prototype.plane=function(a,b,c,e){a=a||1,b=b||1,c=c||1,e=e||1;var f="plane|"+a+"|"+b+"|"+c+"|"+e;if(!this._graphics.geometryInHash(f)){var g=new d.Geometry3D,h=function(c,e){var f=2*a*c-a,g=2*b*e-b,h=0;return new d.Vector(f,g,h)};g.parametricGeometry(h,c,e);var i=g.generateObj();this._graphics.initBuffer(f,i)}this._graphics.drawBuffer(f)},d.prototype.sphere=function(a,b,c){a=a||50,b=b||12,c=c||8;var e="sphere|"+a+"|"+b+"|"+c;if(!this._graphics.geometryInHash(e)){var f=new d.Geometry3D,g=function(b,c){var e=2*Math.PI*b,f=Math.PI*c-Math.PI/2,g=a*Math.cos(f)*Math.sin(e),h=a*Math.sin(f),i=a*Math.cos(f)*Math.cos(e);return new d.Vector(g,h,i)};f.parametricGeometry(g,b,c);var h=f.generateObj();this._graphics.initBuffer(e,h)}return this._graphics.drawBuffer(e),this},d.prototype.cylinder=function(a,b,c,e){a=a||50,b=b||50,c=c||12,e=e||8;var f="cylinder|"+a+"|"+b+"|"+c+"|"+e;if(!this._graphics.geometryInHash(f)){var g=new d.Geometry3D,h=function(c,e){var f=2*Math.PI*c,g=a*Math.sin(f),h=2*b*e-b,i=a*Math.cos(f);return new d.Vector(g,h,i)};g.parametricGeometry(h,c,e),g.mergeVertices();var i=function(c,e){var f=2*Math.PI*c,g=a*Math.sin(-f),h=b,i=a*Math.cos(f);return 0===e?new d.Vector(0,b,0):new d.Vector(g,h,i)};g.parametricGeometry(i,c,1,g.vertices.length);var j=function(c,e){var f=2*Math.PI*c,g=a*Math.sin(f),h=-b,i=a*Math.cos(f);return 0===e?new d.Vector(0,-b,0):new d.Vector(g,h,i)};g.parametricGeometry(j,c,1,g.vertices.length);var k=g.generateObj(!0);this._graphics.initBuffer(f,k)}return this._graphics.drawBuffer(f),this},d.prototype.cone=function(a,b,c,e){a=a||50,b=b||50,c=c||12,e=e||8;var f="cone|"+a+"|"+b+"|"+c+"|"+e;if(!this._graphics.geometryInHash(f)){var g=new d.Geometry3D,h=function(c,e){var f=2*Math.PI*c,g=a*(1-e)*Math.sin(f),h=2*b*e-b,i=a*(1-e)*Math.cos(f);return new d.Vector(g,h,i)};g.parametricGeometry(h,c,e),g.mergeVertices();var i=function(c,e){var f=2*Math.PI*c,g=a*(1-e)*Math.sin(-f),h=-b,i=a*(1-e)*Math.cos(f);return new d.Vector(g,h,i)};g.parametricGeometry(i,c,1,g.vertices.length);var j=g.generateObj(!0);this._graphics.initBuffer(f,j)}return this._graphics.drawBuffer(f),this},d.prototype.torus=function(a,b,c,e){a=a||50,b=b||20,c=c||12,e=e||8;var f="torus|"+a+"|"+b+"|"+c+"|"+e;if(!this._graphics.geometryInHash(f)){var g=new d.Geometry3D,h=function(c,e){var f=2*Math.PI*c,g=2*Math.PI*e,h=(a+b*Math.cos(g))*Math.cos(f),i=(a+b*Math.cos(g))*Math.sin(f),j=b*Math.sin(g);return new d.Vector(h,i,j)};g.parametricGeometry(h,c,e);var i=g.generateObj();this._graphics.initBuffer(f,i)}return this._graphics.drawBuffer(f),this},d.prototype.box=function(a,b,c){a=a||10,b=b||a,c=c||a;var e=typeof arguments[3]===Number?arguments[3]:1,f=typeof arguments[4]===Number?arguments[4]:1,g="cube|"+a+"|"+b+"|"+c+"|"+e+"|"+f;if(!this._graphics.geometryInHash(g)){var h=new d.Geometry3D,i=function(e,f){var g=2*a*e-a,h=2*b*f-b,i=c;return new d.Vector(g,h,i)},j=function(e,f){var g=2*a*(1-e)-a,h=2*b*f-b,i=-c;return new d.Vector(g,h,i)},k=function(e,f){var g=2*a*(1-e)-a,h=b,i=2*c*f-c;return new d.Vector(g,h,i)},l=function(e,f){var g=2*a*e-a,h=-b,i=2*c*f-c;return new d.Vector(g,h,i)},m=function(e,f){var g=a,h=2*b*e-b,i=2*c*f-c;return new d.Vector(g,h,i)},n=function(e,f){var g=-a,h=2*b*(1-e)-b,i=2*c*f-c;return new d.Vector(g,h,i)};h.parametricGeometry(i,e,f,h.vertices.length),h.parametricGeometry(j,e,f,h.vertices.length),h.parametricGeometry(k,e,f,h.vertices.length),h.parametricGeometry(l,e,f,h.vertices.length),h.parametricGeometry(m,e,f,h.vertices.length),h.parametricGeometry(n,e,f,h.vertices.length);var o=h.generateObj(!0);this._graphics.initBuffer(g,o)}return this._graphics.drawBuffer(g),this},b.exports=d},{"../core/core":49,"./p5.Geometry3D":35}],31:[function(a,b,c){"use strict";function d(a){var b=[];return a.forEach(function(a){b.push(a/255)}),b}var e=a("../core/core");e.Renderer3D.prototype.primitives2D=function(a){var b=this.GL,c=this.getColorVertexShader(),d=this.verticeBuffer;b.bindBuffer(b.ARRAY_BUFFER,d),b.bufferData(b.ARRAY_BUFFER,new Float32Array(a),b.STATIC_DRAW),b.vertexAttribPointer(c.vertexPositionAttribute,3,b.FLOAT,!1,0,0);var e=this.colorBuffer;b.bindBuffer(b.ARRAY_BUFFER,e);for(var f=this.getCurColor(),g=[],h=0;h<a.length/3;h++)g=g.concat(f);b.bufferData(b.ARRAY_BUFFER,new Float32Array(g),b.STATIC_DRAW),b.vertexAttribPointer(c.vertexColorAttribute,4,b.FLOAT,!1,0,0);var i="vertexColorVert|vertexColorFrag";this.setMatrixUniforms(i)},e.Renderer3D.prototype.point=function(a,b,c){var d=this.GL;return this.primitives2D([a,b,c]),d.drawArrays(d.POINTS,0,1),this},e.Renderer3D.prototype.line=function(a,b,c,d,e,f){var g=this.GL;return this.primitives2D([a,b,c,d,e,f]),g.drawArrays(g.LINES,0,2),this},e.Renderer3D.prototype.triangle=function(a,b,c,d,e,f,g,h,i){var j=this.GL;return this.primitives2D([a,b,c,d,e,f,g,h,i]),this._strokeCheck(),j.drawArrays(j.TRIANGLES,0,3),this},e.Renderer3D.prototype.quad=function(a,b,c,d,e,f,g,h,i,j,k,l){var m=this.GL;return this.primitives2D([a,b,c,d,e,f,g,h,i,j,k,l]),this._strokeCheck(),m.drawArrays(m.TRIANGLE_STRIP,0,4),this},e.Renderer3D.prototype.beginShape=function(a){return this.modeStack.push(a),this.verticeStack=[],this},e.Renderer3D.prototype.vertex=function(a,b,c){return this.verticeStack.push(a,b,c),this},e.Renderer3D.prototype.endShape=function(){var a=this.GL;this.primitives2D(this.verticeStack),this.verticeStack=[];var b=this.modeStack.pop();switch(b){case"POINTS":a.drawArrays(a.POINTS,0,1);break;case"LINES":a.drawArrays(a.LINES,0,2);break;case"TRIANGLES":this._strokeCheck(),a.drawArrays(a.TRIANGLES,0,3);break;case"TRIANGLE_STRIP":this._strokeCheck(),a.drawArrays(a.TRIANGLE_STRIP,0,4);break;default:this._strokeCheck(),a.drawArrays(a.TRIANGLES,0,3)}return this},e.Renderer3D.prototype._strokeCheck=function(){var a=this.drawModeStack[this.drawModeStack.length-1];if("stroke"===a)throw new Error("stroke for shapes in 3D not yet implemented, use fill for now :(")},e.Renderer3D.prototype.fill=function(a,b,c,e){var f=this._pInst.color.apply(this._pInst,arguments),g=d(f.rgba);return g!==this.getCurColor()&&this.colorStack.push(g),this.drawModeStack.push("fill"),this},e.Renderer3D.prototype.stroke=function(a,b,c,e){var f=this._pInst.color.apply(this._pInst,arguments),g=d(f.rgba);return g!==this.getCurColor()&&this.colorStack.push(g),this.drawModeStack.push("stroke"),this},e.Renderer3D.prototype.getColorVertexShader=function(){var a,b=this.GL,c="vertexColorVert|vertexColorFrag";return this.materialInHash(c)?a=this.mHash[c]:(a=this.initShaders("vertexColorVert","vertexColorFrag",!0),a.vertexColorAttribute=b.getAttribLocation(a,"aVertexColor"),b.enableVertexAttribArray(a.vertexColorAttribute)),a},b.exports=e.Renderer3D},{"../core/core":49}],32:[function(a,b,c){"use strict";var d=a("../core/core");d.prototype.orbitControl=function(){return this.mouseIsPressed&&(this.rotateX((this.mouseX-this.width/2)/(this.width/2)),this.rotateY((this.mouseY-this.height/2)/(this.width/2))),this},b.exports=d},{"../core/core":49}],33:[function(a,b,c){"use strict";function d(a){var b=[];return a.forEach(function(a){b.push(a/255)}),b}var e=a("../core/core");e.prototype.ambientLight=function(a,b,c,e){var f=this._graphics.GL,g=this._graphics.getShader("directionalLightVert","lightFrag");f.useProgram(g),g.uAmbientColor=f.getUniformLocation(g,"uAmbientColor");var h=this._graphics._pInst.color.apply(this._graphics._pInst,arguments),i=d(h.rgba);return f.uniform3f(g.uAmbientColor,i[0],i[1],i[2]),g.uMaterialColor=f.getUniformLocation(g,"uMaterialColor"),f.uniform4f(g.uMaterialColor,1,1,1,1),this},e.prototype.directionalLight=function(a,b,c,e,f,g,h){var i=this._graphics.GL,j=this._graphics.getShader("directionalLightVert","lightFrag");i.useProgram(j),j.uDirectionalColor=i.getUniformLocation(j,"uDirectionalColor");var k=this._graphics._pInst.color.apply(this._graphics._pInst,[a,b,c]),l=d(k.rgba);return i.uniform3f(j.uDirectionalColor,l[0],l[1],l[2]),j.uLightingDirection=i.getUniformLocation(j,"uLightingDirection"),i.uniform3f(j.uLightingDirection,arguments[arguments.length-3],arguments[arguments.length-2],arguments[arguments.length-1]),j.uMaterialColor=i.getUniformLocation(j,"uMaterialColor"),i.uniform4f(j.uMaterialColor,1,1,1,1),this},e.prototype.pointLight=function(){},b.exports=e},{"../core/core":49}],34:[function(a,b,c){"use strict";function d(a){return 0===(a&a-1)}function e(a){var b=[];return a.forEach(function(a){b.push(a/255)}),b}var f=a("../core/core");f.prototype.normalMaterial=function(){return this._graphics.getShader("normalVert","normalFrag"),this},f.prototype.texture=function(a){var b=this._graphics.GL,c=this._graphics.getShader("normalVert","textureFrag");b.useProgram(c);var e=b.createTexture();if(b.bindTexture(b.TEXTURE_2D,e),a instanceof f.Image){a.loadPixels();var g=new Uint8Array(a.pixels);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,a.width,a.height,0,b.RGBA,b.UNSIGNED_BYTE,g)}return d(a.width)&&d(a.height)?b.generateMipmap(b.TEXTURE_2D):(b.texParameteri(b.TETXURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TETXURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TETXURE_2D,b.TEXTURE_MIN_FILTER,b.LINEAR)),b.bindTexture(b.TEXTURE_2D,e),b.uniform1i(b.getUniformLocation(c,"uSampler"),0),this},f.prototype.basicMaterial=function(){var a=this._graphics.GL,b=this._graphics.getShader("normalVert","basicFrag");a.useProgram(b),b.uMaterialColor=a.getUniformLocation(b,"uMaterialColor");var c=this._graphics._pInst.color.apply(this._graphics._pInst,arguments),d=e(c.rgba);return a.uniform4f(b.uMaterialColor,d[0],d[1],d[2],d[3]),this},f.prototype.ambientMaterial=function(){var a=this._graphics.GL,b=this._graphics.getCurShaderId(),c=this._graphics.mHash[b];a.useProgram(c),c.uMaterialColor=a.getUniformLocation(c,"uMaterialColor");var d=this._graphics._pInst.color.apply(this._graphics._pInst,arguments),f=e(d.rgba);return a.uniform4f(c.uMaterialColor,f[0],f[1],f[2],f[3]),this},f.prototype.specularMaterial=function(){return this},b.exports=f},{"../core/core":49}],35:[function(a,b,c){"use strict";function d(a){return a.reduce(function(a,b){return a.concat(b)})}function e(a){return d(a.map(function(a){return[a.x,a.y,a.z]}))}var f=a("../core/core");f.Geometry3D=function(){this.vertices=[],this.vertexNormals=[],this.faces=[],this.faceNormals=[],this.uvs=[]},f.Geometry3D.prototype.parametricGeometry=function(a,b,c,d){var e,f,g,h,i;d=d||0;var j=b+1;for(e=0;c>=e;e++)for(i=e/c,f=0;b>=f;f++)h=f/b,g=a(h,i),this.vertices.push(g);var k,l,m,n,o,p,q,r;for(e=0;c>e;e++)for(f=0;b>f;f++)k=e*j+f+d,l=e*j+f+1+d,m=(e+1)*j+f+1+d,n=(e+1)*j+f+d,o=[f/b,e/c],p=[(f+1)/b,e/c],q=[(f+1)/b,(e+1)/c],r=[f/b,(e+1)/c],this.faces.push([k,l,n]),this.uvs.push([o,p,r]),this.faces.push([l,m,n]),this.uvs.push([p,q,r])},f.Geometry3D.prototype.mergeVertices=function(){var a,b,c,d,e,f={},g=[],h=[],i=4,j=Math.pow(10,i);for(c=0;c<this.vertices.length;c++)a=this.vertices[c],b=Math.round(a.x*j)+"_"+Math.round(a.y*j)+"_"+Math.round(a.z*j),void 0===f[b]?(f[b]=c,g.push(this.vertices[c]),h[c]=g.length-1):h[c]=h[f[b]];var k=[];for(c=0;c<this.faces.length;c++){d=this.faces[c],d[0]=h[d[0]],d[1]=h[d[1]],d[2]=h[d[2]],e=[d[0],d[1],d[2]];for(var l=-1,m=0;3>m;m++)if(e[m]===e[(m+1)%3]){l=m,k.push(c);break}}for(c=k.length-1;c>=0;c--){var n=k[c];this.faces.splice(n,1)}var o=this.vertices.length-g.length;return this.vertices=g,o},f.Geometry3D.prototype.computeFaceNormals=function(){for(var a=new f.Vector,b=new f.Vector,c=0;c<this.faces.length;c++){var d=this.faces[c],e=this.vertices[d[0]],g=this.vertices[d[1]],h=this.vertices[d[2]];f.Vector.sub(h,g,a),f.Vector.sub(e,g,b);var i=f.Vector.cross(b,a);i.normalize(),i.mult(-1),this.faceNormals[c]=i}},f.Geometry3D.prototype.computeVertexNormals=function(){var a,b,c,d,e,g=[];for(e=new Array(this.vertices.length),a=0;a<this.vertices.length;a++)e[a]=new f.Vector;for(b=0;b<this.faces.length;b++)c=this.faces[b],d=this.faceNormals[b],e[c[0]].add(d),e[c[1]].add(d),e[c[2]].add(d);for(a=0;a<this.vertices.length;a++)e[a].normalize();for(b=0;b<this.faces.length;b++)c=this.faces[b],g[b]=[],g[b][0]=e[c[0]].copy(),g[b][1]=e[c[1]].copy(),g[b][2]=e[c[2]].copy();for(b=0;b<this.faces.length;b++)c=this.faces[b],d=this.faceNormals[b],this.vertexNormals[c[0]]=g[b][0],this.vertexNormals[c[1]]=g[b][1],this.vertexNormals[c[2]]=g[b][2]},f.Geometry3D.prototype.generateUV=function(a,b){a=d(a),b=d(b);var c=[];return a.forEach(function(a,d){c[a]=b[d]}),d(c)},f.Geometry3D.prototype.generateObj=function(a){a||this.mergeVertices(),this.computeFaceNormals(),this.computeVertexNormals();var b={vertices:e(this.vertices),vertexNormals:e(this.vertexNormals),uvs:this.generateUV(this.faces,this.uvs),faces:d(this.faces),len:3*this.faces.length};return b},b.exports=f.Geometry3D},{"../core/core":49}],36:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("../math/polargeometry"),f=a("../core/constants"),g="undefined"!=typeof Float32Array?Float32Array:Array;d.Matrix=function(){return arguments[0]instanceof d?(this.p5=arguments[0],this.mat4=arguments[1]||new g([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1])):this.mat4=arguments[0]||new g([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]),this},d.Matrix.prototype.set=function(a){return a instanceof d.Matrix?(this.mat4=a.mat4,this):a instanceof g?(this.mat4=a,this):this},d.Matrix.prototype.get=function(){return new d.Matrix(this.mat4)},d.Matrix.prototype.copy=function(){var a=new d.Matrix;return a.mat4[0]=this.mat4[0],a.mat4[1]=this.mat4[1],a.mat4[2]=this.mat4[2],a.mat4[3]=this.mat4[3],a.mat4[4]=this.mat4[4],a.mat4[5]=this.mat4[5],a.mat4[6]=this.mat4[6],a.mat4[7]=this.mat4[7],a.mat4[8]=this.mat4[8],a.mat4[9]=this.mat4[9],a.mat4[10]=this.mat4[10],a.mat4[11]=this.mat4[11],a.mat4[12]=this.mat4[12],a.mat4[13]=this.mat4[13],a.mat4[14]=this.mat4[14],a.mat4[15]=this.mat4[15],a},d.Matrix.identity=function(){return new d.Matrix},d.Matrix.prototype.transpose=function(a){var b,c,e,f,h,i;return a instanceof d.Matrix?(b=a.mat4[1],c=a.mat4[2],e=a.mat4[3],f=a.mat4[6],h=a.mat4[7],i=a.mat4[11],this.mat4[0]=a.mat4[0],this.mat4[1]=a.mat4[4],this.mat4[2]=a.mat4[8],this.mat4[3]=a.mat4[12],this.mat4[4]=b,this.mat4[5]=a.mat4[5],this.mat4[6]=a.mat4[9],this.mat4[7]=a.mat4[13],this.mat4[8]=c,this.mat4[9]=f,this.mat4[10]=a.mat4[10],this.mat4[11]=a.mat4[14],this.mat4[12]=e,this.mat4[13]=h,this.mat4[14]=i,this.mat4[15]=a.mat4[15]):a instanceof g&&(b=a[1],c=a[2],e=a[3],f=a[6],h=a[7],i=a[11],this.mat4[0]=a[0],this.mat4[1]=a[4],this.mat4[2]=a[8],this.mat4[3]=a[12],this.mat4[4]=b,this.mat4[5]=a[5],this.mat4[6]=a[9],this.mat4[7]=a[13],this.mat4[8]=c,this.mat4[9]=f,this.mat4[10]=a[10],this.mat4[11]=a[14],this.mat4[12]=e,this.mat4[13]=h,this.mat4[14]=i,this.mat4[15]=a[15]),this},d.Matrix.prototype.invert=function(a){var b,c,e,f,h,i,j,k,l,m,n,o,p,q,r,s;a instanceof d.Matrix?(b=a.mat4[0],c=a.mat4[1],e=a.mat4[2],f=a.mat4[3],h=a.mat4[4],i=a.mat4[5],j=a.mat4[6],k=a.mat4[7],l=a.mat4[8],m=a.mat4[9],n=a.mat4[10],o=a.mat4[11],p=a.mat4[12],q=a.mat4[13],r=a.mat4[14],s=a.mat4[15]):a instanceof g&&(b=a[0],c=a[1],e=a[2],f=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=a[9],n=a[10],o=a[11],p=a[12],q=a[13],r=a[14],s=a[15]);var t=b*i-c*h,u=b*j-e*h,v=b*k-f*h,w=c*j-e*i,x=c*k-f*i,y=e*k-f*j,z=l*q-m*p,A=l*r-n*p,B=l*s-o*p,C=m*r-n*q,D=m*s-o*q,E=n*s-o*r,F=t*E-u*D+v*C+w*B-x*A+y*z;return F?(F=1/F,this.mat4[0]=(i*E-j*D+k*C)*F,this.mat4[1]=(e*D-c*E-f*C)*F,this.mat4[2]=(q*y-r*x+s*w)*F,this.mat4[3]=(n*x-m*y-o*w)*F,this.mat4[4]=(j*B-h*E-k*A)*F,this.mat4[5]=(b*E-e*B+f*A)*F,this.mat4[6]=(r*v-p*y-s*u)*F,this.mat4[7]=(l*y-n*v+o*u)*F,this.mat4[8]=(h*D-i*B+k*z)*F,this.mat4[9]=(c*B-b*D-f*z)*F,this.mat4[10]=(p*x-q*v+s*t)*F,this.mat4[11]=(m*v-l*x-o*t)*F,this.mat4[12]=(i*A-h*C-j*z)*F,this.mat4[13]=(b*C-c*A+e*z)*F,this.mat4[14]=(q*u-p*w-r*t)*F,this.mat4[15]=(l*w-m*u+n*t)*F,this):null},d.Matrix.prototype.determinant=function(){var a=this.mat4[0]*this.mat4[5]-this.mat4[1]*this.mat4[4],b=this.mat4[0]*this.mat4[6]-this.mat4[2]*this.mat4[4],c=this.mat4[0]*this.mat4[7]-this.mat4[3]*this.mat4[4],d=this.mat4[1]*this.mat4[6]-this.mat4[2]*this.mat4[5],e=this.mat4[1]*this.mat4[7]-this.mat4[3]*this.mat4[5],f=this.mat4[2]*this.mat4[7]-this.mat4[3]*this.mat4[6],g=this.mat4[8]*this.mat4[13]-this.mat4[9]*this.mat4[12],h=this.mat4[8]*this.mat4[14]-this.mat4[10]*this.mat4[12],i=this.mat4[8]*this.mat4[15]-this.mat4[11]*this.mat4[12],j=this.mat4[9]*this.mat4[14]-this.mat4[10]*this.mat4[13],k=this.mat4[9]*this.mat4[15]-this.mat4[11]*this.mat4[13],l=this.mat4[10]*this.mat4[15]-this.mat4[11]*this.mat4[14];return a*l-b*k+c*j+d*i-e*h+f*g},d.Matrix.prototype.mult=function(a){var b=new g(16),c=new g(16);a instanceof d.Matrix?c=a.mat4:a instanceof g&&(c=a);var e=this.mat4[0],f=this.mat4[1],h=this.mat4[2],i=this.mat4[3];return b[0]=e*c[0]+f*c[4]+h*c[8]+i*c[12],b[1]=e*c[1]+f*c[5]+h*c[9]+i*c[13],b[2]=e*c[2]+f*c[6]+h*c[10]+i*c[14],b[3]=e*c[3]+f*c[7]+h*c[11]+i*c[15],e=this.mat4[4],f=this.mat4[5],h=this.mat4[6],i=this.mat4[7],b[4]=e*c[0]+f*c[4]+h*c[8]+i*c[12],b[5]=e*c[1]+f*c[5]+h*c[9]+i*c[13],b[6]=e*c[2]+f*c[6]+h*c[10]+i*c[14],b[7]=e*c[3]+f*c[7]+h*c[11]+i*c[15],e=this.mat4[8],f=this.mat4[9],h=this.mat4[10],i=this.mat4[11],b[8]=e*c[0]+f*c[4]+h*c[8]+i*c[12],b[9]=e*c[1]+f*c[5]+h*c[9]+i*c[13],b[10]=e*c[2]+f*c[6]+h*c[10]+i*c[14],b[11]=e*c[3]+f*c[7]+h*c[11]+i*c[15],e=this.mat4[12],f=this.mat4[13],h=this.mat4[14],i=this.mat4[15],b[12]=e*c[0]+f*c[4]+h*c[8]+i*c[12],b[13]=e*c[1]+f*c[5]+h*c[9]+i*c[13],b[14]=e*c[2]+f*c[6]+h*c[10]+i*c[14],b[15]=e*c[3]+f*c[7]+h*c[11]+i*c[15],this.mat4=b,this},d.Matrix.prototype.scale=function(){var a,b,c;arguments[0]instanceof d.Vector?(a=arguments[0].x,b=arguments[0].y,c=arguments[0].z):arguments[0]instanceof Array?(a=arguments[0][0],b=arguments[0][1],c=arguments[0][2]):(a=arguments[0]||1,b=arguments[1]||1,c=arguments[2]||1);for(var e=new g(16),f=0;f<this.mat4.length;f++){var h=f%4;switch(h){case 0:e[f]=this.mat4[f]*a;break;case 1:e[f]=this.mat4[f]*b;break;case 2:e[f]=this.mat4[f]*c;break;case 3:e[f]=this.mat4[f]}}return this.mat4=e,this},d.Matrix.prototype.rotate=function(a,b){var c,g,h,i,j;this.p5?this.p5._angleMode===f.DEGREES&&(i=e.degreesToRadians(a)):i=a,b instanceof d.Vector?(c=b.x,g=b.y,h=b.z):b instanceof Array&&(c=b[0],g=b[1],h=b[2]),j=Math.sqrt(c*c+g*g+h*h),c*=1/j,g*=1/j,h*=1/j;var k=this.mat4[0],l=this.mat4[1],m=this.mat4[2],n=this.mat4[3],o=this.mat4[4],p=this.mat4[5],q=this.mat4[6],r=this.mat4[7],s=this.mat4[8],t=this.mat4[9],u=this.mat4[10],v=this.mat4[11],w=Math.sin(i),x=Math.cos(i),y=1-x,z=c*c*y+x,A=g*c*y+h*w,B=h*c*y-g*w,C=c*g*y-h*w,D=g*g*y+x,E=h*g*y+c*w,F=c*h*y+g*w,G=g*h*y-c*w,H=h*h*y+x;return this.mat4[0]=k*z+o*A+s*B,this.mat4[1]=l*z+p*A+t*B,this.mat4[2]=m*z+q*A+u*B,this.mat4[3]=n*z+r*A+v*B,this.mat4[4]=k*C+o*D+s*E,this.mat4[5]=l*C+p*D+t*E,this.mat4[6]=m*C+q*D+u*E,this.mat4[7]=n*C+r*D+v*E,this.mat4[8]=k*F+o*G+s*H,this.mat4[9]=l*F+p*G+t*H,this.mat4[10]=m*F+q*G+u*H,this.mat4[11]=n*F+r*G+v*H,this},d.Matrix.prototype.translate=function(a){var b=a[0],c=a[1],d=a[2];this.mat4[12]=this.mat4[0]*b+this.mat4[4]*c+this.mat4[8]*d+this.mat4[12],this.mat4[13]=this.mat4[1]*b+this.mat4[5]*c+this.mat4[9]*d+this.mat4[13],this.mat4[14]=this.mat4[2]*b+this.mat4[6]*c+this.mat4[10]*d+this.mat4[14],this.mat4[15]=this.mat4[3]*b+this.mat4[7]*c+this.mat4[11]*d+this.mat4[15]},d.Matrix.prototype.rotateX=function(a){this.rotate(a,[1,0,0])},d.Matrix.prototype.rotateY=function(a){this.rotate(a,[0,1,0])},d.Matrix.prototype.rotateZ=function(a){this.rotate(a,[0,0,1])},d.Matrix.prototype.perspective=function(a,b,c,d){var e=1/Math.tan(a/2),f=1/(c-d);return this.mat4[0]=e/b,this.mat4[1]=0,this.mat4[2]=0,this.mat4[3]=0,this.mat4[4]=0,this.mat4[5]=e,this.mat4[6]=0,this.mat4[7]=0,this.mat4[8]=0,this.mat4[9]=0,this.mat4[10]=(d+c)*f,this.mat4[11]=-1,this.mat4[12]=0,this.mat4[13]=0,this.mat4[14]=2*d*c*f,this.mat4[15]=0,this},d.Matrix.prototype.ortho=function(a,b,c,d,e,f){var g=1/(a-b),h=1/(c-d),i=1/(e-f);return this.mat4[0]=-2*g,this.mat4[1]=0,this.mat4[2]=0,this.mat4[3]=0,this.mat4[4]=0,this.mat4[5]=-2*h,this.mat4[6]=0,this.mat4[7]=0,this.mat4[8]=0,this.mat4[9]=0,this.mat4[10]=2*i,this.mat4[11]=0,this.mat4[12]=(a+b)*g,this.mat4[13]=(d+c)*h,this.mat4[14]=(f+e)*i,this.mat4[15]=1,this},b.exports=d.Matrix},{"../core/constants":48,"../core/core":49,"../math/polargeometry":78}],37:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("./shader");a("../core/p5.Renderer"),a("./p5.Matrix");var f=[],g=[],h=1e3,i={alpha:!1,depth:!0,stencil:!0,antialias:!1,premultipliedAlpha:!1,preserveDrawingBuffer:!1};d.Renderer3D=function(a,b,c){d.Renderer.call(this,a,b,c);try{if(this.drawingContext=this.canvas.getContext("webgl",i)||this.canvas.getContext("experimental-webgl",i),null===this.drawingContext)throw new Error("Error creating webgl context");console.log("p5.Renderer3D: enabled webgl context")}catch(e){throw new Error(e)}this.isP3D=!0,this.GL=this.drawingContext;var f=this.GL;return f.clearColor(1,1,1,1),f.clearDepth(1),f.enable(f.DEPTH_TEST),f.depthFunc(f.LEQUAL),f.clear(f.COLOR_BUFFER_BIT|f.DEPTH_BUFFER_BIT),f.viewport(0,0,f.drawingBufferWidth,f.drawingBufferHeight),this.initMatrix(),this.initHash(),this.resetStack(),this.verticeBuffer=f.createBuffer(),this.colorBuffer=f.createBuffer(),this},d.Renderer3D.prototype=Object.create(d.Renderer.prototype),d.Renderer3D.prototype._applyDefaults=function(){return this},d.Renderer3D.prototype.resize=function(a,b){var c=this.GL;d.Renderer.prototype.resize.call(this,a,b),c.viewport(0,0,c.drawingBufferWidth,c.drawingBufferHeight)},d.Renderer3D.prototype.background=function(){var a=this.GL,b=this._pInst.color.apply(this._pInst,arguments),c=b.rgba[0]/255,d=b.rgba[1]/255,e=b.rgba[2]/255,f=b.rgba[3]/255;a.clearColor(c,d,e,f),a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT),this.resetMatrix(),this.resetStack()},d.Renderer3D.prototype.initShaders=function(a,b,c){var d=this.GL,f=d.createShader(d.VERTEX_SHADER);if(d.shaderSource(f,e[a]),d.compileShader(f),!d.getShaderParameter(f,d.COMPILE_STATUS))return alert("Yikes! An error occurred compiling the shaders:"+d.getShaderInfoLog(f)),null;var g=d.createShader(d.FRAGMENT_SHADER);if(d.shaderSource(g,e[b]),d.compileShader(g),!d.getShaderParameter(g,d.COMPILE_STATUS))return alert("Darn! An error occurred compiling the shaders:"+d.getShaderInfoLog(g)),null;var i=d.createProgram();return d.attachShader(i,f),d.attachShader(i,g),d.linkProgram(i),d.getProgramParameter(i,d.LINK_STATUS)||alert("Snap! Error linking shader program"),d.useProgram(i),i.uResolution=d.getUniformLocation(i,"uResolution"),d.uniform1f(i.uResolution,h),i.vertexPositionAttribute=d.getAttribLocation(i,"aPosition"),d.enableVertexAttribArray(i.vertexPositionAttribute),void 0===c&&(i.vertexNormalAttribute=d.getAttribLocation(i,"aNormal"),d.enableVertexAttribArray(i.vertexNormalAttribute),i.uNMatrixUniform=d.getUniformLocation(i,"uNormalMatrix"),i.textureCoordAttribute=d.getAttribLocation(i,"aTexCoord"),d.enableVertexAttribArray(i.textureCoordAttribute),i.samplerUniform=d.getUniformLocation(i,"uSampler")),i.uPMatrixUniform=d.getUniformLocation(i,"uTransformMatrix"),i.uMVMatrixUniform=d.getUniformLocation(i,"uModelviewMatrix"),this.mHash[a+"|"+b]=i,i},d.Renderer3D.prototype.getShader=function(a,b){var c=a+"|"+b;return this.materialInHash(c)||this.initShaders(a,b),c!==this.getCurShaderId()&&this.saveShaders(c),this.mHash[c]},d.Renderer3D.prototype.setMatrixUniforms=function(a){var b=this.GL,c=this.mHash[a];b.useProgram(c),b.uniformMatrix4fv(c.uPMatrixUniform,!1,this.uPMatrix.mat4),b.uniformMatrix4fv(c.uMVMatrixUniform,!1,this.uMVMatrix.mat4),this.uNMatrix=new d.Matrix,this.uNMatrix.invert(this.uMVMatrix),this.uNMatrix.transpose(this.uNMatrix),b.uniformMatrix4fv(c.uNMatrixUniform,!1,this.uNMatrix.mat4)},d.Renderer3D.prototype.saveShaders=function(a){g.push(a)},d.Renderer3D.prototype.getCurColor=function(){return this.colorStack[this.colorStack.length-1]||[.5,.5,.5,1]},d.Renderer3D.prototype.getCurShaderId=function(){var a=g[g.length-1];if(void 0===a){a="normalVert|basicFrag";var b=this.GL,c=this.initShaders("normalVert","basicFrag");c.uMaterialColor=b.getUniformLocation(c,"uMaterialColor");var d=this.getCurColor();b.uniform4f(c.uMaterialColor,d[0],d[1],d[2],d[3]),this.saveShaders(a)}return a},d.Renderer3D.prototype.resetStack=function(){g=[],this.colorStack=[],this.modeStack=[],this.drawModeStack=[],this.verticeStack=[],this.lightStack=[]},d.Renderer3D.prototype.initHash=function(){this.gHash={},this.mHash={}},d.Renderer3D.prototype.geometryInHash=function(a){return void 0!==this.gHash[a]},d.Renderer3D.prototype.materialInHash=function(a){return void 0!==this.mHash[a]},d.Renderer3D.prototype.initMatrix=function(){this.uMVMatrix=new d.Matrix,this.uPMatrix=new d.Matrix,this.uNMatrix=new d.Matrix;var a=this.width,b=this.height;this.uPMatrix.perspective(60/180*Math.PI,a/b,.1,100)},d.Renderer3D.prototype.resetMatrix=function(){this.uMVMatrix=d.Matrix.identity()},d.Renderer3D.prototype.translate=function(a,b,c){return a/=h,b=-b/h,c/=h,this.uMVMatrix.translate([a,b,c]),this},d.Renderer3D.prototype.scale=function(a,b,c){return this.uMVMatrix.scale([a,b,c]),this},d.Renderer3D.prototype.rotateX=function(a){return this.uMVMatrix.rotateX(a),this},d.Renderer3D.prototype.rotateY=function(a){return this.uMVMatrix.rotateY(a),this},d.Renderer3D.prototype.rotateZ=function(a){return this.uMVMatrix.rotateZ(a),this},d.Renderer3D.prototype.push=function(){f.push(this.uMVMatrix.copy())},d.Renderer3D.prototype.pop=function(){if(0===f.length)throw"Invalid popMatrix!";this.uMVMatrix=f.pop()},b.exports=d.Renderer3D},{"../core/core":49,"../core/p5.Renderer":55,"./p5.Matrix":36,"./shader":39}],38:[function(a,b,c){"use strict";var d=a("../core/core");d.Renderer3D.prototype.createBuffer=function(a,b){var c=this.GL;this.gHash[a]={},this.gHash[a].len=b.len,this.gHash[a].vertexBuffer=c.createBuffer(),this.gHash[a].normalBuffer=c.createBuffer(),this.gHash[a].uvBuffer=c.createBuffer(),this.gHash[a].indexBuffer=c.createBuffer()},d.Renderer3D.prototype.initBuffer=function(a,b){var c=this.GL;this.createBuffer(a,b);var d=this.mHash[this.getCurShaderId()];c.bindBuffer(c.ARRAY_BUFFER,this.gHash[a].vertexBuffer),c.bufferData(c.ARRAY_BUFFER,new Float32Array(b.vertices),c.STATIC_DRAW),c.vertexAttribPointer(d.vertexPositionAttribute,3,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,this.gHash[a].normalBuffer),c.bufferData(c.ARRAY_BUFFER,new Float32Array(b.vertexNormals),c.STATIC_DRAW),c.vertexAttribPointer(d.vertexNormalAttribute,3,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,this.gHash[a].uvBuffer),c.bufferData(c.ARRAY_BUFFER,new Float32Array(b.uvs),c.STATIC_DRAW),c.vertexAttribPointer(d.textureCoordAttribute,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,this.gHash[a].indexBuffer),c.bufferData(c.ELEMENT_ARRAY_BUFFER,new Uint16Array(b.faces),c.STATIC_DRAW)},d.Renderer3D.prototype.drawBuffer=function(a){var b=this.GL,c=this.getCurShaderId(),d=this.mHash[c];b.bindBuffer(b.ARRAY_BUFFER,this.gHash[a].vertexBuffer),b.vertexAttribPointer(d.vertexPositionAttribute,3,b.FLOAT,!1,0,0),b.bindBuffer(b.ARRAY_BUFFER,this.gHash[a].normalBuffer),b.vertexAttribPointer(d.vertexNormalAttribute,3,b.FLOAT,!1,0,0),b.bindBuffer(b.ARRAY_BUFFER,this.gHash[a].uvBuffer),b.vertexAttribPointer(d.textureCoordAttribute,2,b.FLOAT,!1,0,0),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,this.gHash[a].indexBuffer),this.setMatrixUniforms(c),b.drawElements(b.TRIANGLES,this.gHash[a].len,b.UNSIGNED_SHORT,0)},b.exports=d.Renderer3D},{"../core/core":49}],39:[function(a,b,c){b.exports={vertexColorVert:"attribute vec3 aPosition;\nattribute vec4 aVertexColor;\n\nuniform mat4 uModelviewMatrix;\nuniform mat4 uTransformMatrix;\n\nvarying vec4 vColor;\n\nvoid main(void) {\n vec3 zeroToOne = aPosition / 1000.0;\n vec4 positionVec4 = vec4(zeroToOne * vec3(1., -1., 1.), 1.);\n gl_Position = uTransformMatrix * uModelviewMatrix * positionVec4;\n vColor = aVertexColor;\n}",vertexColorFrag:"precision mediump float;\nvarying vec4 vColor;\nvoid main(void) {\n gl_FragColor = vColor;\n}",normalVert:"attribute vec3 aPosition;\nattribute vec3 aNormal;\nattribute vec2 aTexCoord;\n\nuniform mat4 uModelviewMatrix;\nuniform mat4 uTransformMatrix;\nuniform mat4 uNormalMatrix;\nuniform float uResolution;\n\nvarying vec3 vVertexNormal;\nvarying highp vec2 vVertTexCoord;\n\nvoid main(void) {\n vec3 zeroToOne = aPosition / uResolution;\n vec4 positionVec4 = vec4(zeroToOne, 1.);\n gl_Position = uTransformMatrix * uModelviewMatrix * positionVec4;\n vVertexNormal = vec3( uNormalMatrix * vec4( aNormal, 1.0 ) );\n vVertTexCoord = aTexCoord;\n}",normalFrag:"precision mediump float;\nvarying vec3 vVertexNormal;\nvoid main(void) {\n gl_FragColor = vec4(vVertexNormal, 1.0);\n}",basicFrag:"precision mediump float;\nvarying vec3 vVertexNormal;\nuniform vec4 uMaterialColor;\nvoid main(void) {\n gl_FragColor = uMaterialColor;\n}",textureFrag:"precision mediump float;\nvarying highp vec2 vVertTexCoord;\nuniform sampler2D uSampler;\nvoid main(void) {\n gl_FragColor = texture2D(uSampler, vec2(vVertTexCoord.s,vVertTexCoord.t));\n}",lightFrag:"precision mediump float;\n//varying vec2 vTextureCoord;\nvarying vec3 vLightWeighting;\n//uniform sampler2D uSampler;\nuniform vec4 uMaterialColor;\nvoid main(void) {\n //vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));\n gl_FragColor = vec4(vec3(uMaterialColor.rgb * vLightWeighting), uMaterialColor.a);\n}",directionalLightVert:"attribute vec3 position;\nattribute vec3 normal;\nattribute vec2 texCoord;\n\nuniform mat4 modelviewMatrix;\nuniform mat4 transformMatrix;\nuniform mat4 normalMatrix;\nuniform float uResolution;\n\nuniform vec3 uAmbientColor;\nuniform vec3 uLightingDirection;\nuniform vec3 uDirectionalColor;\n\nvarying vec2 vertTexCoord;\nvarying vec3 vLightWeighting;\n\nvoid main(void) {\n vec3 zeroToOne = position / uResolution;\n vec4 positionVec4 = vec4(zeroToOne, 1.);\n gl_Position = transformMatrix * modelviewMatrix * positionVec4;\n vec3 vertexNormal = vec3( normalMatrix * vec4( normal, 1.0 ) );\n vertTexCoord = texCoord;\n\n float directionalLightWeighting = max(dot(vertexNormal, uLightingDirection), 0.0);\n vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;\n}",spotLightVert:"attribute vec3 position;\nattribute vec3 normal;\nattribute vec2 texCoord;\n\nuniform mat4 modelviewMatrix;\nuniform mat4 transformMatrix;\nuniform mat4 normalMatrix;\nuniform float uResolution;\n\nuniform vec4 uAmbientColor;\nuniform vec3 uPointLightingLocation;\nuniform vec4 uPointLightingColor;\n\nvarying vec3 vertexNormal;\nvarying vec2 vertTexCoord;\nvarying vec4 vLightWeighting;\n\nvoid main(void) {\n vec3 zeroToOne = position / uResolution;\n vec4 positionVec4 = vec4(zeroToOne, 1.);\n gl_Position = transformMatrix * modelviewMatrix * positionVec4;\n vertTexCoord = texCoord;\n\n vec3 lightDirection = normalize(uPointLightingLocation - mvPosition.xyz);\n vec3 transformedNormal = normalMatrix * vertexNormal;\n float directionalLightWeighting = max(dot(transformedNormal, lightDirection), 0.0);\n vLightWeighting = uAmbientColor + uPointLightingColor * directionalLightWeighting;\n}"}},{}],40:[function(a,b,c){"use strict";var d=a("./core/core");a("./color/p5.Color"),a("./core/p5.Element"),a("./typography/p5.Font"),a("./core/p5.Graphics"),a("./core/p5.Renderer2D"),a("./image/p5.Image"),a("./math/p5.Vector"),a("./io/p5.TableRow"),a("./io/p5.Table"),a("./color/creating_reading"),a("./color/setting"),a("./core/constants"),a("./utilities/conversion"),a("./utilities/array_functions"),a("./utilities/string_functions"),a("./core/environment"),a("./image/image"),a("./image/loading_displaying"),a("./image/pixels"),a("./io/files"),a("./events/keyboard"),a("./events/acceleration"),a("./events/mouse"),a("./utilities/time_date"),a("./events/touch"),a("./math/math"),a("./math/calculation"),a("./math/random"),a("./math/noise"),a("./math/trigonometry"),a("./core/rendering"),a("./core/2d_primitives"),a("./core/attributes"),a("./core/curves"),a("./core/vertex"),a("./core/structure"),a("./core/transform"),a("./typography/attributes"),a("./typography/loading_displaying"),a("./3d/p5.Renderer3D"),
a("./3d/p5.Geometry3D"),a("./3d/retainedMode3D"),a("./3d/immediateMode3D"),a("./3d/3d_primitives"),a("./3d/p5.Matrix"),a("./3d/material"),a("./3d/light"),a("./3d/shader"),a("./3d/interaction");var e=function(){window.PHANTOMJS||window.mocha||(window.setup&&"function"==typeof window.setup||window.draw&&"function"==typeof window.draw)&&new d};"complete"===document.readyState?e():window.addEventListener("load",e,!1),b.exports=d},{"./3d/3d_primitives":30,"./3d/immediateMode3D":31,"./3d/interaction":32,"./3d/light":33,"./3d/material":34,"./3d/p5.Geometry3D":35,"./3d/p5.Matrix":36,"./3d/p5.Renderer3D":37,"./3d/retainedMode3D":38,"./3d/shader":39,"./color/creating_reading":42,"./color/p5.Color":43,"./color/setting":44,"./core/2d_primitives":45,"./core/attributes":46,"./core/constants":48,"./core/core":49,"./core/curves":50,"./core/environment":51,"./core/p5.Element":53,"./core/p5.Graphics":54,"./core/p5.Renderer2D":56,"./core/rendering":57,"./core/structure":59,"./core/transform":60,"./core/vertex":61,"./events/acceleration":62,"./events/keyboard":63,"./events/mouse":64,"./events/touch":65,"./image/image":67,"./image/loading_displaying":68,"./image/p5.Image":69,"./image/pixels":70,"./io/files":71,"./io/p5.Table":72,"./io/p5.TableRow":73,"./math/calculation":74,"./math/math":75,"./math/noise":76,"./math/p5.Vector":77,"./math/random":79,"./math/trigonometry":80,"./typography/attributes":81,"./typography/loading_displaying":82,"./typography/p5.Font":83,"./utilities/array_functions":84,"./utilities/conversion":85,"./utilities/string_functions":86,"./utilities/time_date":87}],41:[function(a,b,c){var d=a("../core/core");d.ColorUtils={},d.ColorUtils.hsbaToRGBA=function(a){var b=a[0],c=a[1],d=a[2],e=a[3]||1,f=[];if(0===c)f=[d,d,d,e];else{var g=6*b;6===g&&(g=0);var h,i,j,k=Math.floor(g),l=d*(1-c),m=d*(1-c*(g-k)),n=d*(1-c*(1-(g-k)));0===k?(h=d,i=n,j=l):1===k?(h=m,i=d,j=l):2===k?(h=l,i=d,j=n):3===k?(h=l,i=m,j=d):4===k?(h=n,i=l,j=d):(h=d,i=l,j=m),f=[h,i,j,e]}return f},d.ColorUtils.rgbaToHSBA=function(a){var b,c,d=a[0],e=a[1],f=a[2],g=a[3]||1,h=Math.min(d,e,f),i=Math.max(d,e,f),j=i-h,k=i;if(0===j)b=0,c=0;else{c=j/i;var l=((i-d)/6+j/2)/j,m=((i-e)/6+j/2)/j,n=((i-f)/6+j/2)/j;d===i?b=n-m:e===i?b=1/3+l-n:f===i&&(b=2/3+m-l),0>b&&(b+=1),b>1&&(b-=1)}return[b,c,k,g]},d.ColorUtils.hslaToRGBA=function(a){var b=a[0],c=a[1],d=a[2],e=a[3]||1,f=[];if(0===c)f=[d,d,d,e];else{var g,h,i,j,k;h=.5>d?d*(1+c):d+c-c*d,g=2*d-h;var l=function(a,b,c){return 0>c?c+=1:c>1&&(c-=1),1>6*c?a+6*(b-a)*c:1>2*c?b:2>3*c?a+(b-a)*(2/3-c)*6:a};i=l(g,h,b+1/3),j=l(g,h,b),k=l(g,h,b-1/3),f=[i,j,k,e]}return f},d.ColorUtils.rgbaToHSLA=function(a){var b,c,d,e,f,g=a[0],h=a[1],i=a[2],j=a[3]||1,k=Math.min(g,h,i),l=Math.max(g,h,i),m=l-k,n=(l+k)/2;return 0===m?(b=0,c=0):(d=((l-g)/6+m/2)/m,e=((l-h)/6+m/2)/m,f=((l-i)/6+m/2)/m,g===l?b=f-e:h===l?b=1/3+d-f:i===l&&(b=2/3+e-d),0>b&&(b+=1),b>1&&(b-=1),c=.5>n?m/(l+k):m/(2-l-k)),[b,c,n,j]},d.ColorUtils.hslaToHSBA=function(a){var b,c=a[0],d=a[1],e=a[2],f=a[3]||1;return d*=.5>e?e:1-e,b=e+d,d=2*d/(e+d),[c,d,b,f]},d.ColorUtils.hsbaToHSLA=function(a){var b=a[0],c=a[1],d=a[2],e=a[3]||1,f=(2-c)*d/2;return 0!==f&&(1===f?c=0:.5>f?c/=2-c:c=c*d/(2-2*f)),[b,c,f,e]},b.exports=d.ColorUtils},{"../core/core":49}],42:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("../core/constants");a("./p5.Color"),d.prototype.alpha=function(a){if(a instanceof d.Color||a instanceof Array)return this.color(a).getAlpha();throw new Error("Needs p5.Color or pixel array as argument.")},d.prototype.blue=function(a){if(a instanceof d.Color||a instanceof Array)return this.color(a).getBlue();throw new Error("Needs p5.Color or pixel array as argument.")},d.prototype.brightness=function(a){if(a instanceof d.Color||a instanceof Array)return this.color(a).getBrightness();throw new Error("Needs p5.Color or pixel array as argument.")},d.prototype.color=function(){if(arguments[0]instanceof d.Color)return arguments[0];if(arguments[0]instanceof Array)return new d.Color(this,arguments[0]);var a=Array.prototype.slice.call(arguments);return new d.Color(this,a)},d.prototype.green=function(a){if(a instanceof d.Color||a instanceof Array)return this.color(a).getGreen();throw new Error("Needs p5.Color or pixel array as argument.")},d.prototype.hue=function(a){if(!(a instanceof d.Color))throw new Error("Needs p5.Color as argument.");return a.getHue()},d.prototype.lerpColor=function(a,b,c){var d,f,g,h,i,j;if(this._colorMode===e.RGB)i=this.color(a).rgba,j=this.color(b).rgba;else if(this._colorMode===e.HSB)i=this.color(a).hsba,j=this.color(b).hsba;else{if(this._colorMode!==e.HSL)return;i=this.color(a).hsla,j=this.color(b).hsla}return d=this.lerp(i[0],j[0],c),f=this.lerp(i[1],j[1],c),g=this.lerp(i[2],j[2],c),h=this.lerp(i[3],j[3],c),this.color(d,f,g,h)},d.prototype.lightness=function(a){if(a instanceof d.Color||a instanceof Array)return this.color(a).getLightness();throw new Error("Needs p5.Color or pixel array as argument.")},d.prototype.red=function(a){if(a instanceof d.Color||a instanceof Array)return this.color(a).getRed();throw new Error("Needs p5.Color or pixel array as argument.")},d.prototype.saturation=function(a){if(!(a instanceof d.Color))throw new Error("Needs p5.Color as argument.");return a.getSaturation()},b.exports=d},{"../core/constants":48,"../core/core":49,"./p5.Color":43}],43:[function(a,b,c){var d=a("../core/core"),e=a("./color_utils"),f=a("../core/constants");d.Color=function(a,b){this.mode=a._colorMode,this.maxes=a._colorMaxes;var c=this.mode===f.HSB,g=this.mode===f.RGB,h=this.mode===f.HSL;if(g)this._array=d.Color._getFormattedColor.apply(a,b);else if(c)this.hsba=d.Color._getFormattedColor.apply(a,b),this._array=e.hsbaToRGBA(this.hsba);else{if(!h)throw new Error(a._colorMode+" is an invalid colorMode.");this.hsla=d.Color._getFormattedColor.apply(a,b),this._array=e.hslaToRGBA(this.hsla)}return this.rgba=[Math.round(255*this._array[0]),Math.round(255*this._array[1]),Math.round(255*this._array[2]),Math.round(255*this._array[3])],this},d.Color.prototype.getHue=function(){return this.hsla?this.hsla[0]*this.maxes[f.HSL][0]:this.hsba?this.hsba[0]*this.maxes[f.HSB][0]:(this.hsla=e.rgbaToHSLA(this._array),this.hsla[0]*this.maxes[f.HSL][0])},d.Color.prototype.getSaturation=function(){return this.hsba&&this.mode===f.HSB?this.hsba[1]*this.maxes[f.HSB][1]:(this.hsla||(this.hsla=e.rgbaToHSLA(this._array)),this.hsla[1]*this.maxes[f.HSL][1])},d.Color.prototype.getBrightness=function(){return this.hsba?this.hsba[2]*this.maxes[f.HSB][2]:(this.hsba=e.rgbaToHSBA(this._array),this.hsba[2]*this.maxes[f.HSB][2])},d.Color.prototype.getLightness=function(){return this.hsla?this.hsla[2]*this.maxes[f.HSL][2]:(this.hsla=e.rgbaToHSLA(this._array),this.hsla[2]*this.maxes[f.HSL][2])},d.Color.prototype.getRed=function(){return this._array[0]*this.maxes[f.RGB][0]},d.Color.prototype.getGreen=function(){return this._array[1]*this.maxes[f.RGB][1]},d.Color.prototype.getBlue=function(){return this._array[2]*this.maxes[f.RGB][2]},d.Color.prototype.getAlpha=function(){return this._array[3]*this.maxes[this.mode][3]},d.Color.prototype.toString=function(){var a=this.rgba;return a[3]=this._array[3],"rgba("+a[0]+","+a[1]+","+a[2]+","+a[3]+")"};var g=/\s*/,h=/(\d{1,3})/,i=/((?:\d+(?:\.\d+)?)|(?:\.\d+))/,j=new RegExp(i.source+"%"),k={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},l={HEX3:/^#([a-f0-9])([a-f0-9])([a-f0-9])$/i,HEX6:/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i,RGB:new RegExp(["^rgb\\(",h.source,",",h.source,",",h.source,"\\)$"].join(g.source),"i"),RGB_PERCENT:new RegExp(["^rgb\\(",j.source,",",j.source,",",j.source,"\\)$"].join(g.source),"i"),RGBA:new RegExp(["^rgba\\(",h.source,",",h.source,",",h.source,",",i.source,"\\)$"].join(g.source),"i"),RGBA_PERCENT:new RegExp(["^rgba\\(",j.source,",",j.source,",",j.source,",",i.source,"\\)$"].join(g.source),"i"),HSL:new RegExp(["^hsl\\(",h.source,",",j.source,",",j.source,"\\)$"].join(g.source),"i"),HSLA:new RegExp(["^hsla\\(",h.source,",",j.source,",",j.source,",",i.source,"\\)$"].join(g.source),"i"),HSB:new RegExp(["^hsb\\(",h.source,",",j.source,",",j.source,"\\)$"].join(g.source),"i"),HSBA:new RegExp(["^hsba\\(",h.source,",",j.source,",",j.source,",",i.source,"\\)$"].join(g.source),"i")};d.Color._getFormattedColor=function(){var a=arguments.length,b=this._colorMode,c=this._colorMaxes[this._colorMode],g=[];if(a>=3)g[0]=arguments[0]/c[0],g[1]=arguments[1]/c[1],g[2]=arguments[2]/c[2],g[3]="number"==typeof arguments[3]?arguments[3]/c[3]:1;else if(1===a&&"string"==typeof arguments[0]){var h=arguments[0].trim().toLowerCase();if(k[h])return d.Color._getFormattedColor.apply(this,[k[h]]);if(l.HEX3.test(h)?(g=l.HEX3.exec(h).slice(1).map(function(a){return parseInt(a+a,16)/255}),g[3]=1):l.HEX6.test(h)?(g=l.HEX6.exec(h).slice(1).map(function(a){return parseInt(a,16)/255}),g[3]=1):l.RGB.test(h)?(g=l.RGB.exec(h).slice(1).map(function(a){return a/255}),g[3]=1):l.RGB_PERCENT.test(h)?(g=l.RGB_PERCENT.exec(h).slice(1).map(function(a){return parseFloat(a)/100}),g[3]=1):l.RGBA.test(h)?g=l.RGBA.exec(h).slice(1).map(function(a,b){return 3===b?parseFloat(a):a/255}):l.RGBA_PERCENT.test(h)&&(g=l.RGBA_PERCENT.exec(h).slice(1).map(function(a,b){return 3===b?parseFloat(a):parseFloat(a)/100})),g.length){if(b===f.RGB)return g;if(b===f.HSL)return e.rgbaToHSLA(g);if(b===f.HSB)return e.rgbaToHSBA(g)}if(l.HSL.test(h)?(g=l.HSL.exec(h).slice(1).map(function(a,b){return 0===b?parseInt(a,10)/360:parseInt(a,10)/100}),g[3]=1):l.HSLA.test(h)&&(g=l.HSLA.exec(h).slice(1).map(function(a,b){return 0===b?parseInt(a,10)/360:3===b?parseFloat(a):parseInt(a,10)/100})),g.length){if(b===f.RGB)return e.hslaToRGBA(g);if(b===f.HSL)return g;if(b===f.HSB)return e.hslaToHSBA(g)}if(l.HSB.test(h)?(g=l.HSB.exec(h).slice(1).map(function(a,b){return 0===b?parseInt(a,10)/360:parseInt(a,10)/100}),g[3]=1):l.HSBA.test(h)&&(g=l.HSBA.exec(h).slice(1).map(function(a,b){return 0===b?parseInt(a,10)/360:3===b?parseFloat(a):parseInt(a,10)/100})),g.length){if(b===f.RGB)return e.hsbaToRGBA(g);if(b===f.HSB)return g;if(b===f.HSL)return e.hsbaToHSLA(g)}g=[1,1,1,1]}else{if(1!==a&&2!==a||"number"!=typeof arguments[0])throw new Error(arguments+"is not a valid color representation.");b===f.RGB?(g[0]=arguments[0]/c[0],g[1]=arguments[0]/c[1],g[2]=arguments[0]/c[2],g[3]="number"==typeof arguments[1]?arguments[1]/c[3]:1):(g[0]=arguments[0],g[1]=arguments[0],g[2]=arguments[0]/c[2],g[3]="number"==typeof arguments[1]?arguments[1]/c[3]:1)}return g},b.exports=d.Color},{"../core/constants":48,"../core/core":49,"./color_utils":41}],44:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("../core/constants");a("./p5.Color"),d.prototype._doStroke=!0,d.prototype._doFill=!0,d.prototype._strokeSet=!1,d.prototype._fillSet=!1,d.prototype._colorMode=e.RGB,d.prototype._colorMaxes={rgb:[255,255,255,255],hsb:[360,100,100,1],hsl:[360,100,100,1]},d.prototype.background=function(){return arguments[0]instanceof d.Image?this.image(arguments[0],0,0,this.width,this.height):this._graphics.background.apply(this._graphics,arguments),this},d.prototype.clear=function(){return this._graphics.clear(),this},d.prototype.colorMode=function(){if(arguments[0]===e.RGB||arguments[0]===e.HSB||arguments[0]===e.HSL){this._colorMode=arguments[0];var a=this._colorMaxes[this._colorMode];2===arguments.length?(a[0]=arguments[1],a[1]=arguments[1],a[2]=arguments[1],a[3]=arguments[1]):4===arguments.length&&(a[0]=arguments[1],a[1]=arguments[2],a[2]=arguments[3]),5===arguments.length&&(a[0]=arguments[1],a[1]=arguments[2],a[2]=arguments[3],a[3]=arguments[4])}return this},d.prototype.fill=function(){return this._setProperty("_fillSet",!0),this._setProperty("_doFill",!0),this._graphics.fill.apply(this._graphics,arguments),this},d.prototype.noFill=function(){return this._setProperty("_doFill",!1),this},d.prototype.noStroke=function(){return this._setProperty("_doStroke",!1),this},d.prototype.stroke=function(){return this._setProperty("_strokeSet",!0),this._setProperty("_doStroke",!0),this._graphics.stroke.apply(this._graphics,arguments),this},b.exports=d},{"../core/constants":48,"../core/core":49,"./p5.Color":43}],45:[function(a,b,c){"use strict";var d=a("./core"),e=a("./constants");a("./error_helpers"),d.prototype.arc=function(a,b,c,d,f,g,h){if(this._validateParameters("arc",arguments,[["Number","Number","Number","Number","Number","Number"],["Number","Number","Number","Number","Number","Number","String"]]),!this._doStroke&&!this._doFill)return this;for(this._angleMode===e.DEGREES&&(f=this.radians(f),g=this.radians(g));0>f;)f+=e.TWO_PI;for(;0>g;)g+=e.TWO_PI;return f%=e.TWO_PI,g%=e.TWO_PI,f=f<=e.HALF_PI?Math.atan(c/d*Math.tan(f)):f>e.HALF_PI&&f<=3*e.HALF_PI?Math.atan(c/d*Math.tan(f))+e.PI:Math.atan(c/d*Math.tan(f))+e.TWO_PI,g=g<=e.HALF_PI?Math.atan(c/d*Math.tan(g)):g>e.HALF_PI&&g<=3*e.HALF_PI?Math.atan(c/d*Math.tan(g))+e.PI:Math.atan(c/d*Math.tan(g))+e.TWO_PI,f>g&&(g+=e.TWO_PI),c=Math.abs(c),d=Math.abs(d),this._graphics.arc(a,b,c,d,f,g,h),this},d.prototype.ellipse=function(a,b,c,d){return this._validateParameters("ellipse",arguments,["Number","Number","Number","Number"]),this._doStroke||this._doFill?(c=Math.abs(c),d=Math.abs(d),this._graphics.ellipse(a,b,c,d),this):this},d.prototype.line=function(){return this._validateParameters("line",arguments,[["Number","Number","Number","Number"],["Number","Number","Number","Number","Number","Number"]]),this._doStroke?(this._graphics.isP3D?this._graphics.line(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]):this._graphics.line(arguments[0],arguments[1],arguments[2],arguments[3]),this):this},d.prototype.point=function(){return this._validateParameters("point",arguments,[["Number","Number"],["Number","Number","Number"]]),this._doStroke?(this._graphics.isP3D?this._graphics.point(arguments[0],arguments[1],arguments[2]):this._graphics.point(arguments[0],arguments[1]),this):this},d.prototype.quad=function(){return this._validateParameters("quad",arguments,[["Number","Number","Number","Number","Number","Number","Number","Number"],["Number","Number","Number","Number","Number","Number","Number","Number","Number","Number","Number","Number"]]),this._doStroke||this._doFill?(this._graphics.isP3D?this._graphics.quad(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7],arguments[8],arguments[9],arguments[10],arguments[11]):this._graphics.quad(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7]),this):this},d.prototype.rect=function(a,b,c,d,e,f,g,h){return this._validateParameters("rect",arguments,[["Number","Number","Number","Number"],["Number","Number","Number","Number","Number"],["Number","Number","Number","Number","Number","Number","Number","Number"]]),this._doStroke||this._doFill?(this._graphics.rect(a,b,c,d,e,f,g,h),this):void 0},d.prototype.triangle=function(){return this._validateParameters("triangle",arguments,[["Number","Number","Number","Number","Number","Number"],["Number","Number","Number","Number","Number","Number","Number","Number","Number"]]),this._doStroke||this._doFill?(this._graphics.isP3D?this._graphics.triangle(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7],arguments[8]):this._graphics.triangle(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]),this):this},b.exports=d},{"./constants":48,"./core":49,"./error_helpers":52}],46:[function(a,b,c){"use strict";var d=a("./core"),e=a("./constants");d.prototype._rectMode=e.CORNER,d.prototype._ellipseMode=e.CENTER,d.prototype.ellipseMode=function(a){return(a===e.CORNER||a===e.CORNERS||a===e.RADIUS||a===e.CENTER)&&(this._ellipseMode=a),this},d.prototype.noSmooth=function(){return this._graphics.noSmooth(),this},d.prototype.rectMode=function(a){return(a===e.CORNER||a===e.CORNERS||a===e.RADIUS||a===e.CENTER)&&(this._rectMode=a),this},d.prototype.smooth=function(){return this._graphics.smooth(),this},d.prototype.strokeCap=function(a){return(a===e.ROUND||a===e.SQUARE||a===e.PROJECT)&&this._graphics.strokeCap(a),this},d.prototype.strokeJoin=function(a){return(a===e.ROUND||a===e.BEVEL||a===e.MITER)&&this._graphics.strokeJoin(a),this},d.prototype.strokeWeight=function(a){return this._graphics.strokeWeight(a),this},b.exports=d},{"./constants":48,"./core":49}],47:[function(a,b,c){var d=a("./constants");b.exports={modeAdjust:function(a,b,c,e,f){return f===d.CORNER?{x:a,y:b,w:c,h:e}:f===d.CORNERS?{x:a,y:b,w:c-a,h:e-b}:f===d.RADIUS?{x:a-c,y:b-e,w:2*c,h:2*e}:f===d.CENTER?{x:a-.5*c,y:b-.5*e,w:c,h:e}:void 0},arcModeAdjust:function(a,b,c,e,f){return f===d.CORNER?{x:a+.5*c,y:b+.5*e,w:c,h:e}:f===d.CORNERS?{x:a,y:b,w:c+a,h:e+b}:f===d.RADIUS?{x:a,y:b,w:2*c,h:2*e}:f===d.CENTER?{x:a,y:b,w:c,h:e}:void 0}}},{"./constants":48}],48:[function(a,b,c){var d=Math.PI;b.exports={P2D:"p2d",WEBGL:"webgl",ARROW:"default",CROSS:"crosshair",HAND:"pointer",MOVE:"move",TEXT:"text",WAIT:"wait",HALF_PI:d/2,PI:d,QUARTER_PI:d/4,TAU:2*d,TWO_PI:2*d,DEGREES:"degrees",RADIANS:"radians",CORNER:"corner",CORNERS:"corners",RADIUS:"radius",RIGHT:"right",LEFT:"left",CENTER:"center",TOP:"top",BOTTOM:"bottom",BASELINE:"alphabetic",POINTS:"points",LINES:"lines",TRIANGLES:"triangles",TRIANGLE_FAN:"triangles_fan",TRIANGLE_STRIP:"triangles_strip",QUADS:"quads",QUAD_STRIP:"quad_strip",CLOSE:"close",OPEN:"open",CHORD:"chord",PIE:"pie",PROJECT:"square",SQUARE:"butt",ROUND:"round",BEVEL:"bevel",MITER:"miter",RGB:"rgb",HSB:"hsb",HSL:"hsl",AUTO:"auto",ALT:18,BACKSPACE:8,CONTROL:17,DELETE:46,DOWN_ARROW:40,ENTER:13,ESCAPE:27,LEFT_ARROW:37,OPTION:18,RETURN:13,RIGHT_ARROW:39,SHIFT:16,TAB:9,UP_ARROW:38,BLEND:"normal",ADD:"lighter",DARKEST:"darken",LIGHTEST:"lighten",DIFFERENCE:"difference",EXCLUSION:"exclusion",MULTIPLY:"multiply",SCREEN:"screen",REPLACE:"source-over",OVERLAY:"overlay",HARD_LIGHT:"hard-light",SOFT_LIGHT:"soft-light",DODGE:"color-dodge",BURN:"color-burn",THRESHOLD:"threshold",GRAY:"gray",OPAQUE:"opaque",INVERT:"invert",POSTERIZE:"posterize",DILATE:"dilate",ERODE:"erode",BLUR:"blur",NORMAL:"normal",ITALIC:"italic",BOLD:"bold",_DEFAULT_TEXT_FILL:"#000000",_DEFAULT_LEADMULT:1.25,_CTX_MIDDLE:"middle",LINEAR:"linear",QUADRATIC:"quadratic",BEZIER:"bezier",CURVE:"curve",_DEFAULT_STROKE:"#000000",_DEFAULT_FILL:"#FFFFFF"}},{}],49:[function(a,b,c){"use strict";a("./shim");var d=a("./constants"),e=function(a,b,c){2===arguments.length&&"boolean"==typeof b&&(c=b,b=void 0),this._setupDone=!1,this.pixelDensity=window.devicePixelRatio||1,this._userNode=b,this._curElement=null,this._elements=[],this._requestAnimId=0,this._preloadCount=0,this._isGlobal=!1,this._loop=!0,this._styles=[],this._defaultCanvasSize={width:100,height:100},this._events={mousemove:null,mousedown:null,mouseup:null,click:null,mouseover:null,mouseout:null,keydown:null,keyup:null,keypress:null,touchstart:null,touchmove:null,touchend:null,resize:null,blur:null},window.DeviceOrientationEvent?this._events.deviceorientation=null:window.DeviceMotionEvent?this._events.devicemotion=null:this._events.MozOrientation=null,/Firefox/i.test(navigator.userAgent)?this._events.DOMMouseScroll=null:this._events.mousewheel=null,this._loadingScreenId="p5_loading",this._start=function(){this._userNode&&"string"==typeof this._userNode&&(this._userNode=document.getElementById(this._userNode)),this.createCanvas(this._defaultCanvasSize.width,this._defaultCanvasSize.height,"p2d",!0);var a=this.preload||window.preload;if(a){var b=document.getElementById(this._loadingScreenId);if(!b){b=document.createElement("div"),b.innerHTML="Loading...",b.style.position="absolute",b.id=this._loadingScreenId;var c=this._userNode||document.body;c.appendChild(b)}for(var d in this._preloadMethods){this._preloadMethods[d]=this._preloadMethods[d]||e;var f=this._preloadMethods[d];(f===e.prototype||f===e)&&(f=this._isGlobal?window:this),this._registeredPreloadMethods[d]=f[d],f[d]=this._wrapPreload(f,d)}a()}else this._setup(),this._runFrames(),this._draw()}.bind(this),this._decrementPreload=function(){var a=this._isGlobal?window:this;if(a._setProperty("_preloadCount",a._preloadCount-1),0===a._preloadCount){var b=document.getElementById(a._loadingScreenId);b&&b.parentNode.removeChild(b),a._setup(),a._runFrames(),a._draw()}},this._wrapPreload=function(a,b){return function(){this._incrementPreload();var c=Array.prototype.slice.call(arguments);return c.push(this._decrementPreload.bind(this)),this._registeredPreloadMethods[b].apply(a,c)}.bind(this)},this._incrementPreload=function(){var a=this._isGlobal?window:this;a._setProperty("_preloadCount",a._preloadCount+1)},this._setup=function(){var a=this._isGlobal?window:this;if("function"==typeof a.preload)for(var b in this._preloadMethods)a[b]=this._preloadMethods[b][b];"function"==typeof a.setup&&a.setup();for(var c=new RegExp(/(^|\s)p5_hidden(?!\S)/g),d=document.getElementsByClassName("p5_hidden"),e=0;e<d.length;e++){var f=d[e];f.style.visibility="",f.className=f.className.replace(c,"")}this._setupDone=!0}.bind(this),this._draw=function(){var a=window.performance.now(),b=a-this._lastFrameTime,c=1e3/this._targetFrameRate,d=5;(!this.loop||b>=c-d)&&(this._setProperty("frameCount",this.frameCount+1),this.redraw(),this._updatePAccelerations(),this._updatePMouseCoords(),this._updatePTouchCoords(),this._frameRate=1e3/(a-this._lastFrameTime),this._lastFrameTime=a),this._loop&&(this._requestAnimId=window.requestAnimationFrame(this._draw))}.bind(this),this._runFrames=function(){this._updateInterval&&clearInterval(this._updateInterval)}.bind(this),this._setProperty=function(a,b){this[a]=b,this._isGlobal&&(window[a]=b)}.bind(this),this.remove=function(){if(this._curElement){this._loop=!1,this._requestAnimId&&window.cancelAnimationFrame(this._requestAnimId);for(var a in this._events)window.removeEventListener(a,this._events[a]);for(var b=0;b<this._elements.length;b++){var c=this._elements[b];c.elt.parentNode&&c.elt.parentNode.removeChild(c.elt);for(var d in c._events)c.elt.removeEventListener(d,c._events[d])}var f=this;if(this._registeredMethods.remove.forEach(function(a){"undefined"!=typeof a&&a.call(f)}),this._isGlobal){for(var g in e.prototype)try{delete window[g]}catch(h){window[g]=void 0}for(var i in this)if(this.hasOwnProperty(i))try{delete window[i]}catch(h){window[i]=void 0}}}}.bind(this);for(var f in d)e.prototype[f]=d[f];if(a)a(this);else{this._isGlobal=!0;for(var g in e.prototype)if("function"==typeof e.prototype[g]){var h=g.substring(2);this._events.hasOwnProperty(h)||(window[g]=e.prototype[g].bind(this))}else window[g]=e.prototype[g];for(var i in this)this.hasOwnProperty(i)&&(window[i]=this[i])}for(var j in this._events){var k=this["_on"+j];if(k){var l=k.bind(this);window.addEventListener(j,l),this._events[j]=l}}var m=this;window.addEventListener("focus",function(){m._setProperty("focused",!0)}),window.addEventListener("blur",function(){m._setProperty("focused",!1)}),c?this._start():"complete"===document.readyState?this._start():window.addEventListener("load",this._start.bind(this),!1)};e.prototype._preloadMethods={loadJSON:e.prototype,loadImage:e.prototype,loadStrings:e.prototype,loadXML:e.prototype,loadShape:e.prototype,loadTable:e.prototype,loadFont:e.prototype},e.prototype._registeredMethods={pre:[],post:[],remove:[]},e.prototype._registeredPreloadMethods={},e.prototype.registerPreloadMethod=function(a,b){e.prototype._preloadMethods.hasOwnProperty(a)||(e.prototype._preloadMethods[a]=b)},e.prototype.registerMethod=function(a,b){e.prototype._registeredMethods.hasOwnProperty(a)||(e.prototype._registeredMethods[a]=[]),e.prototype._registeredMethods[a].push(b)},b.exports=e},{"./constants":48,"./shim":58}],50:[function(a,b,c){"use strict";var d=a("./core");a("./error_helpers");var e=20,f=20;d.prototype._curveTightness=0,d.prototype.bezier=function(a,b,c,d,e,f,g,h){return this._validateParameters("bezier",arguments,["Number","Number","Number","Number","Number","Number","Number","Number"]),this._doStroke?(this._graphics.bezier(a,b,c,d,e,f,g,h),this):this},d.prototype.bezierDetail=function(a){return e=a,this},d.prototype.bezierPoint=function(a,b,c,d,e){var f=1-e;return Math.pow(f,3)*a+3*Math.pow(f,2)*e*b+3*f*Math.pow(e,2)*c+Math.pow(e,3)*d},d.prototype.bezierTangent=function(a,b,c,d,e){var f=1-e;return 3*d*Math.pow(e,2)-3*c*Math.pow(e,2)+6*c*f*e-6*b*f*e+3*b*Math.pow(f,2)-3*a*Math.pow(f,2)},d.prototype.curve=function(a,b,c,d,e,f,g,h){return this._validateParameters("curve",arguments,["Number","Number","Number","Number","Number","Number","Number","Number"]),this._doStroke?(this._graphics.curve(a,b,c,d,e,f,g,h),this):void 0},d.prototype.curveDetail=function(a){return f=a,this},d.prototype.curveTightness=function(a){this._setProperty("_curveTightness",a)},d.prototype.curvePoint=function(a,b,c,d,e){var f=e*e*e,g=e*e,h=-.5*f+g-.5*e,i=1.5*f-2.5*g+1,j=-1.5*f+2*g+.5*e,k=.5*f-.5*g;return a*h+b*i+c*j+d*k},d.prototype.curveTangent=function(a,b,c,d,e){var f=e*e,g=-3*f/2+2*e-.5,h=9*f/2-5*e,i=-9*f/2+4*e+.5,j=3*f/2-e;return a*g+b*h+c*i+d*j},b.exports=d},{"./core":49,"./error_helpers":52}],51:[function(a,b,c){"use strict";function d(a){var b=document.fullscreenEnabled||document.webkitFullscreenEnabled||document.mozFullScreenEnabled||document.msFullscreenEnabled;if(!b)throw new Error("Fullscreen not enabled in this browser.");a.requestFullscreen?a.requestFullscreen():a.mozRequestFullScreen?a.mozRequestFullScreen():a.webkitRequestFullscreen?a.webkitRequestFullscreen():a.msRequestFullscreen&&a.msRequestFullscreen()}function e(){document.exitFullscreen?document.exitFullscreen():document.mozCancelFullScreen?document.mozCancelFullScreen():document.webkitExitFullscreen?document.webkitExitFullscreen():document.msExitFullscreen&&document.msExitFullscreen()}var f=a("./core"),g=a("./constants"),h=[g.ARROW,g.CROSS,g.HAND,g.MOVE,g.TEXT,g.WAIT];f.prototype._frameRate=0,f.prototype._lastFrameTime=window.performance.now(),f.prototype._targetFrameRate=60,window.console&&console.log?f.prototype.print=function(a){try{var b=JSON.parse(JSON.stringify(a));console.log(b)}catch(c){console.log(a)}}:f.prototype.print=function(){},f.prototype.println=f.prototype.print,f.prototype.frameCount=0,f.prototype.focused=document.hasFocus(),f.prototype.cursor=function(a,b,c){var d="auto",e=this._curElement.elt;if(h.indexOf(a)>-1)d=a;else if("string"==typeof a){var f="";b&&c&&"number"==typeof b&&"number"==typeof c&&(f=b+" "+c),d="http://"!==a.substring(0,6)?"url("+a+") "+f+", auto":/\.(cur|jpg|jpeg|gif|png|CUR|JPG|JPEG|GIF|PNG)$/.test(a)?"url("+a+") "+f+", auto":a}e.style.cursor=d},f.prototype.frameRate=function(a){return"undefined"==typeof a?this._frameRate:(this._setProperty("_targetFrameRate",a),this._runFrames(),this)},f.prototype.getFrameRate=function(){return this.frameRate()},f.prototype.setFrameRate=function(a){return this.frameRate(a)},f.prototype.noCursor=function(){this._curElement.elt.style.cursor="none"},f.prototype.displayWidth=screen.width,f.prototype.displayHeight=screen.height,f.prototype.windowWidth=window.innerWidth,f.prototype.windowHeight=window.innerHeight,f.prototype._onresize=function(a){this._setProperty("windowWidth",window.innerWidth),this._setProperty("windowHeight",window.innerHeight);var b,c=this._isGlobal?window:this;"function"==typeof c.windowResized&&(b=c.windowResized(a),void 0===b||b||a.preventDefault())},f.prototype.width=0,f.prototype.height=0,f.prototype.fullScreen=function(a){return"undefined"==typeof a?document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement:void(a?d(document.documentElement):e())},f.prototype.devicePixelScaling=function(a){a?"number"==typeof a?this.pixelDensity=a:this.pixelDensity=window.devicePixelRatio||1:this.pixelDensity=1,this.resizeCanvas(this.width,this.height,!0)},f.prototype.getURL=function(){return location.href},f.prototype.getURLPath=function(){return location.pathname.split("/").filter(function(a){return""!==a})},f.prototype.getURLParams=function(){for(var a,b=/[?&]([^&=]+)(?:[&=])([^&=]+)/gim,c={};null!=(a=b.exec(location.search));)a.index===b.lastIndex&&b.lastIndex++,c[a[1]]=a[2];return c},b.exports=f},{"./constants":48,"./core":49}],52:[function(a,b,c){"use strict";function d(a,b,c){if(a.match(/^p5\./)){var d=a.split(".");return c instanceof g[d[1]]}return"Boolean"===a||a.toLowerCase()===b||p.indexOf(a)>-1&&o(c)}function e(a,b,c){h&&(f(),h=!1),"undefined"===m(c)?c="#B40033":"number"===m(c)&&(c=u[c]),"load"===b.substring(0,4)?console.log("%c> p5.js says: "+a+"%c[https://github.com/processing/p5.js/wiki/Local-server]","background-color:"+c+";color:#FFF;","background-color:transparent;color:"+c+";","background-color:"+c+";color:#FFF;","background-color:transparent;color:"+c+";"):console.log("%c> p5.js says: "+a+"%c [http://p5js.org/reference/#p5/"+b+"]","background-color:"+c+";color:#FFF;","background-color:transparent;color:"+c+";")}function f(){var a="transparent",b="#ED225D",c="#ED225D",d="white";console.log("%c _ \n /\\| |/\\ \n \\ ` ' / \n / , . \\ \n \\/|_|\\/ \n\n%c> p5.js says: Welcome! This is your friendly debugger. To turn me off switch to using “p5.min.js”.","background-color:"+a+";color:"+b+";","background-color:"+c+";color:"+d+";")}for(var g=a("./core"),h=!0,i={},j=i.toString,k=["Boolean","Number","String","Function","Array","Date","RegExp","Object","Error"],l=0;l<k.length;l++)i["[object "+k[l]+"]"]=k[l].toLowerCase();
var m=function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},n=Array.isArray||function(a){return"array"===m(a)},o=function(a){return!n(a)&&a-parseFloat(a)+1>=0},p=["Number","Integer","Number/Constant"],q=0,r=1,s=2,t=3,u=["#2D7BB6","#EE9900","#4DB200","#C83C00"];g.prototype._validateParameters=function(a,b,c){n(c[0])||(c=[c]);for(var f,g=Math.abs(b.length-c[0].length),h=0,i=1,j=c.length;j>i;i++){var k=Math.abs(b.length-c[i].length);g>=k&&(h=i,g=k)}var l="X";g>0&&(f="You wrote "+a+"(",b.length>0&&(f+=l+Array(b.length).join(","+l)),f+="). "+a+" was expecting "+c[h].length+" parameters. Try "+a+"(",c[h].length>0&&(f+=l+Array(c[h].length).join(","+l)),f+=").",c.length>1&&(f+=" "+a+" takes different numbers of parameters depending on what you want to do. Click this link to learn more: "),e(f,a,q));for(var o=0;o<c.length;o++)for(var p=0;p<c[o].length&&p<b.length;p++){var t=c[o][p],u=m(b[p]);"undefined"===u||null===u?e("It looks like "+a+" received an empty variable in spot #"+(p+1)+". If not intentional, this is often a problem with scope: [link to scope].",a,r):"*"===t||d(t,u,b[p])||(f=a+" was expecting a "+t.toLowerCase()+" for parameter #"+(p+1)+", received ",f+="string"===u?'"'+b[p]+'"':b[p],f+=" instead.",c.length>1&&(f+=" "+a+" takes different numbers of parameters depending on what you want to do. Click this link to learn more:"),e(f,a,s))}};var v={0:{fileType:"image",method:"loadImage",message:" hosting the image online,"},1:{fileType:"XML file",method:"loadXML"},2:{fileType:"table file",method:"loadTable"},3:{fileType:"text file",method:"loadStrings"}};g._friendlyFileLoadError=function(a,b){var c=v[a],d="It looks like there was a problem loading your "+c.fileType+". Try checking if the file path%c ["+b+"] %cis correct,"+(c.message||"")+" or running a local server.";e(d,c.method,t)},b.exports=g},{"./core":49}],53:[function(a,b,c){function d(a,b,c){var d=b.bind(c);c.elt.addEventListener(a,d,!1),c._events[a]=d}var e=a("./core");e.Element=function(a,b){this.elt=a,this._pInst=b,this._events={},this.width=this.elt.offsetWidth,this.height=this.elt.offsetHeight},e.Element.prototype.parent=function(a){return"string"==typeof a?a=document.getElementById(a):a instanceof e.Element&&(a=a.elt),a.appendChild(this.elt),this},e.Element.prototype.id=function(a){return this.elt.id=a,this},e.Element.prototype["class"]=function(a){return this.elt.className+=" "+a,this},e.Element.prototype.mousePressed=function(a){return d("mousedown",a,this),d("touchstart",a,this),this},e.Element.prototype.mouseWheel=function(a){return d("mousewheel",a,this),this},e.Element.prototype.mouseReleased=function(a){return d("mouseup",a,this),d("touchend",a,this),this},e.Element.prototype.mouseClicked=function(a){return d("click",a,this),this},e.Element.prototype.mouseMoved=function(a){return d("mousemove",a,this),d("touchmove",a,this),this},e.Element.prototype.mouseOver=function(a){return d("mouseover",a,this),this},e.Element.prototype.changed=function(a){return d("change",a,this),this},e.Element.prototype.mouseOut=function(a){return d("mouseout",a,this),this},e.Element.prototype.touchStarted=function(a){return d("touchstart",a,this),d("mousedown",a,this),this},e.Element.prototype.touchMoved=function(a){return d("touchmove",a,this),d("mousemove",a,this),this},e.Element.prototype.touchEnded=function(a){return d("touchend",a,this),d("mouseup",a,this),this},e.Element.prototype.dragOver=function(a){return d("dragover",a,this),this},e.Element.prototype.dragLeave=function(a){return d("dragleave",a,this),this},e.Element.prototype.drop=function(a,b){function c(b){var c=new e.File(b);return function(b){c.data=b.target.result,a(c)}}return window.File&&window.FileReader&&window.FileList&&window.Blob?(d("dragover",function(a){a.stopPropagation(),a.preventDefault()},this),d("dragleave",function(a){a.stopPropagation(),a.preventDefault()},this),arguments.length>1&&d("drop",b,this),d("drop",function(a){a.stopPropagation(),a.preventDefault();for(var b=a.dataTransfer.files,d=0;d<b.length;d++){var e=b[d],f=new FileReader;f.onload=c(e),"text"===e.type?f.readAsText(e):f.readAsDataURL(e)}},this)):console.log("The File APIs are not fully supported in this browser."),this},e.Element.prototype._setProperty=function(a,b){this[a]=b},b.exports=e.Element},{"./core":49}],54:[function(a,b,c){var d=a("./core"),e=a("./constants");d.Graphics=function(a,b,c,f){var g=c||e.P2D,h=document.createElement("canvas"),i=this._userNode||document.body;i.appendChild(h),d.Element.call(this,h,f,!1),this._styles=[],this.width=a,this.height=b,this.pixelDensity=f.pixelDensity,g===e.WEBGL?this._graphics=new d.Renderer3D(h,f,!1):this._graphics=new d.Renderer2D(h,f,!1),this._graphics.resize(a,b),this._graphics._applyDefaults(),f._elements.push(this);for(var j in d.prototype)this[j]||("function"==typeof d.prototype[j]?this[j]=d.prototype[j].bind(this):this[j]=d.prototype[j]);return this},d.Graphics.prototype=Object.create(d.Element.prototype),b.exports=d.Graphics},{"./constants":48,"./core":49}],55:[function(a,b,c){var d=a("./core");d.Renderer=function(a,b,c){d.Element.call(this,a,b),this.canvas=a,this._pInst=b,c?(this._isMainCanvas=!0,this._pInst._setProperty("_curElement",this),this._pInst._setProperty("canvas",this.canvas),this._pInst._setProperty("width",this.width),this._pInst._setProperty("height",this.height)):(this.canvas.style.display="none",this._styles=[])},d.Renderer.prototype=Object.create(d.Element.prototype),d.Renderer.prototype.resize=function(a,b){this.width=a,this.height=b,this.elt.width=a*this._pInst.pixelDensity,this.elt.height=b*this._pInst.pixelDensity,this.elt.style.width=a+"px",this.elt.style.height=b+"px",this._isMainCanvas&&(this._pInst._setProperty("width",this.width),this._pInst._setProperty("height",this.height))},b.exports=d.Renderer},{"./core":49}],56:[function(a,b,c){var d=a("./core"),e=a("./canvas"),f=a("./constants"),g=a("../image/filters");a("./p5.Renderer");var h="rgba(0,0,0,0)";d.Renderer2D=function(a,b,c){return d.Renderer.call(this,a,b,c),this.drawingContext=this.canvas.getContext("2d"),this._pInst._setProperty("drawingContext",this.drawingContext),this},d.Renderer2D.prototype=Object.create(d.Renderer.prototype),d.Renderer2D.prototype._applyDefaults=function(){this.drawingContext.fillStyle=f._DEFAULT_FILL,this.drawingContext.strokeStyle=f._DEFAULT_STROKE,this.drawingContext.lineCap=f.ROUND,this.drawingContext.font="normal 12px sans-serif"},d.Renderer2D.prototype.resize=function(a,b){d.Renderer.prototype.resize.call(this,a,b),this.drawingContext.scale(this._pInst.pixelDensity,this._pInst.pixelDensity)},d.Renderer2D.prototype.background=function(){if(this.drawingContext.save(),this.drawingContext.setTransform(1,0,0,1,0,0),this.drawingContext.scale(this._pInst.pixelDensity,this._pInst.pixelDensity),arguments[0]instanceof d.Image)this._pInst.image(arguments[0],0,0,this.width,this.height);else{var a=this.drawingContext.fillStyle,b=this._pInst.color.apply(this._pInst,arguments),c=b.toString();this.drawingContext.fillStyle=c,this.drawingContext.fillRect(0,0,this.width,this.height),this.drawingContext.fillStyle=a}this.drawingContext.restore()},d.Renderer2D.prototype.clear=function(){this.drawingContext.clearRect(0,0,this.width,this.height)},d.Renderer2D.prototype.fill=function(){var a=this.drawingContext,b=this._pInst.color.apply(this._pInst,arguments);a.fillStyle=b.toString()},d.Renderer2D.prototype.stroke=function(){var a=this.drawingContext,b=this._pInst.color.apply(this._pInst,arguments);a.strokeStyle=b.toString()},d.Renderer2D.prototype.image=function(a,b,c,d,e){var f=a.canvas||a.elt;try{this._pInst._tint&&a.canvas?this.drawingContext.drawImage(this._getTintedImageCanvas(a),b,c,d,e):this.drawingContext.drawImage(f,b,c,d,e)}catch(g){if("NS_ERROR_NOT_AVAILABLE"!==g.name)throw g}},d.Renderer2D.prototype._getTintedImageCanvas=function(a){if(!a.canvas)return a;var b=g._toPixels(a.canvas),c=document.createElement("canvas");c.width=a.canvas.width,c.height=a.canvas.height;for(var d=c.getContext("2d"),e=d.createImageData(a.canvas.width,a.canvas.height),f=e.data,h=0;h<b.length;h+=4){var i=b[h],j=b[h+1],k=b[h+2],l=b[h+3];f[h]=i*this._pInst._tint[0]/255,f[h+1]=j*this._pInst._tint[1]/255,f[h+2]=k*this._pInst._tint[2]/255,f[h+3]=l*this._pInst._tint[3]/255}return d.putImageData(e,0,0),c},d.Renderer2D.prototype.blendMode=function(a){this.drawingContext.globalCompositeOperation=a},d.Renderer2D.prototype.blend=function(){var a=this.drawingContext.globalCompositeOperation,b=arguments[arguments.length-1],c=Array.prototype.slice.call(arguments,0,arguments.length-1);this.drawingContext.globalCompositeOperation=b,this._pInst.copy.apply(this._pInst,c),this.drawingContext.globalCompositeOperation=a},d.Renderer2D.prototype.copy=function(){var a,b,c,e,f,g,h,i,j;if(9===arguments.length)a=arguments[0],b=arguments[1],c=arguments[2],e=arguments[3],f=arguments[4],g=arguments[5],h=arguments[6],i=arguments[7],j=arguments[8];else{if(8!==arguments.length)throw new Error("Signature not supported");a=this._pInst,b=arguments[0],c=arguments[1],e=arguments[2],f=arguments[3],g=arguments[4],h=arguments[5],i=arguments[6],j=arguments[7]}d.Renderer2D._copyHelper(a,b,c,e,f,g,h,i,j)},d.Renderer2D._copyHelper=function(a,b,c,d,e,f,g,h,i){var j=a.canvas.width/a.width;this.drawingContext.drawImage(a.canvas,j*b,j*c,j*d,j*e,f,g,h,i)},d.Renderer2D.prototype.get=function(a,b,c,e){if(void 0===a&&void 0===b&&void 0===c&&void 0===e?(a=0,b=0,c=this.width,e=this.height):void 0===c&&void 0===e&&(c=1,e=1),a>this.width||b>this.height||0>a||0>b)return[0,0,0,255];var f=this.pixelDensity||this._pInst.pixelDensity;if(1===c&&1===e)return[this.pixels[4*f*(b*this.width+a)],this.pixels[f*(4*(b*this.width+a)+1)],this.pixels[f*(4*(b*this.width+a)+2)],this.pixels[f*(4*(b*this.width+a)+3)]];var g=a*f,h=b*f,i=Math.min(c,this.width),j=Math.min(e,this.height),k=i*f,l=j*f,m=new d.Image(i,j);return m.canvas.getContext("2d").drawImage(this.canvas,g,h,k,l,0,0,i,j),m},d.Renderer2D.prototype.loadPixels=function(){var a=this.pixelDensity||this._pInst.pixelDensity,b=this.width*a,c=this.height*a,d=this.drawingContext.getImageData(0,0,b,c);this._pInst?(this._pInst._setProperty("imageData",d),this._pInst._setProperty("pixels",d.data)):(this._setProperty("imageData",d),this._setProperty("pixels",d.data))},d.Renderer2D.prototype.set=function(a,b,c){if(c instanceof d.Image)this.drawingContext.save(),this.drawingContext.setTransform(1,0,0,1,0,0),this.drawingContext.scale(this._pInst.pixelDensity,this._pInst.pixelDensity),this.drawingContext.drawImage(c.canvas,a,b),this.loadPixels.call(this._pInst),this.drawingContext.restore();else{var e=this._pInst||this,f=0,g=0,h=0,i=0,j=4*(b*e.pixelDensity*this.width*e.pixelDensity+a*e.pixelDensity);if(e.imageData||e.loadPixels.call(e),"number"==typeof c)j<e.pixels.length&&(f=c,g=c,h=c,i=255);else if(c instanceof Array){if(c.length<4)throw new Error("pixel array must be of the form [R, G, B, A]");j<e.pixels.length&&(f=c[0],g=c[1],h=c[2],i=c[3])}else c instanceof d.Color&&j<e.pixels.length&&(f=c.rgba[0],g=c.rgba[1],h=c.rgba[2],i=c.rgba[3]);for(var k=0;k<e.pixelDensity;k++)for(var l=0;l<e.pixelDensity;l++)j=4*((b*e.pixelDensity+l)*this.width*e.pixelDensity+(a*e.pixelDensity+k)),e.pixels[j]=f,e.pixels[j+1]=g,e.pixels[j+2]=h,e.pixels[j+3]=i}},d.Renderer2D.prototype.updatePixels=function(a,b,c,d){var e=this.pixelDensity||this._pInst.pixelDensity;void 0===a&&void 0===b&&void 0===c&&void 0===d&&(a=0,b=0,c=this.width,d=this.height),c*=e,d*=e,this._pInst?this.drawingContext.putImageData(this._pInst.imageData,a,b,0,0,c,d):this.drawingContext.putImageData(this.imageData,a,b,0,0,c,d)},d.Renderer2D.prototype._acuteArcToBezier=function(a,b){var c=b/2,d=Math.cos(c),e=Math.sin(c),f=1/Math.tan(c),g=a+c,h=Math.cos(g),i=Math.sin(g),j=(4-d)/3,k=e+(d-j)*f;return{ax:Math.cos(a),ay:Math.sin(a),bx:j*h+k*i,by:j*i-k*h,cx:j*h-k*i,cy:j*i+k*h,dx:Math.cos(a+b),dy:Math.sin(a+b)}},d.Renderer2D.prototype.arc=function(a,b,c,d,g,h,i){for(var j=this.drawingContext,k=e.arcModeAdjust(a,b,c,d,this._pInst._ellipseMode),l=k.w/2,m=k.h/2,n=1e-5,o=0,p=[];h-g>n;)o=Math.min(h-g,f.HALF_PI),p.push(this._acuteArcToBezier(g,o)),g+=o;return this._pInst._doFill&&(j.beginPath(),p.forEach(function(a,b){0===b&&j.moveTo(k.x+a.ax*l,k.y+a.ay*m),j.bezierCurveTo(k.x+a.bx*l,k.y+a.by*m,k.x+a.cx*l,k.y+a.cy*m,k.x+a.dx*l,k.y+a.dy*m)}),(i===f.PIE||null==i)&&j.lineTo(k.x,k.y),j.closePath(),j.fill()),this._pInst._doStroke&&(j.beginPath(),p.forEach(function(a,b){0===b&&j.moveTo(k.x+a.ax*l,k.y+a.ay*m),j.bezierCurveTo(k.x+a.bx*l,k.y+a.by*m,k.x+a.cx*l,k.y+a.cy*m,k.x+a.dx*l,k.y+a.dy*m)}),i===f.PIE?(j.lineTo(k.x,k.y),j.closePath()):i===f.CHORD&&j.closePath(),j.stroke()),this},d.Renderer2D.prototype.ellipse=function(a,b,c,d){var f=this.drawingContext,g=this._pInst._doFill,i=this._pInst._doStroke;if(g&&!i){if(f.fillStyle===h)return this}else if(!g&&i&&f.strokeStyle===h)return this;var j=e.modeAdjust(a,b,c,d,this._pInst._ellipseMode),k=.5522847498,l=j.w/2*k,m=j.h/2*k,n=j.x+j.w,o=j.y+j.h,p=j.x+j.w/2,q=j.y+j.h/2;f.beginPath(),f.moveTo(j.x,q),f.bezierCurveTo(j.x,q-m,p-l,j.y,p,j.y),f.bezierCurveTo(p+l,j.y,n,q-m,n,q),f.bezierCurveTo(n,q+m,p+l,o,p,o),f.bezierCurveTo(p-l,o,j.x,q+m,j.x,q),f.closePath(),g&&f.fill(),i&&f.stroke()},d.Renderer2D.prototype.line=function(a,b,c,d){var e=this.drawingContext;return this._pInst._doStroke?e.strokeStyle===h?this:(e.lineWidth%2===1&&e.translate(.5,.5),e.beginPath(),e.moveTo(a,b),e.lineTo(c,d),e.stroke(),e.lineWidth%2===1&&e.translate(-.5,-.5),this):this},d.Renderer2D.prototype.point=function(a,b){var c=this.drawingContext,d=c.strokeStyle,e=c.fillStyle;return this._pInst._doStroke?c.strokeStyle===h?this:(a=Math.round(a),b=Math.round(b),c.fillStyle=d,c.lineWidth>1?(c.beginPath(),c.arc(a,b,c.lineWidth/2,0,f.TWO_PI,!1),c.fill()):c.fillRect(a,b,1,1),void(c.fillStyle=e)):this},d.Renderer2D.prototype.quad=function(a,b,c,d,e,f,g,i){var j=this.drawingContext,k=this._pInst._doFill,l=this._pInst._doStroke;if(k&&!l){if(j.fillStyle===h)return this}else if(!k&&l&&j.strokeStyle===h)return this;return j.beginPath(),j.moveTo(a,b),j.lineTo(c,d),j.lineTo(e,f),j.lineTo(g,i),j.closePath(),k&&j.fill(),l&&j.stroke(),this},d.Renderer2D.prototype.rect=function(a,b,c,d,f,g,i,j){var k=this.drawingContext,l=this._pInst._doFill,m=this._pInst._doStroke;if(l&&!m){if(k.fillStyle===h)return this}else if(!l&&m&&k.strokeStyle===h)return this;var n=e.modeAdjust(a,b,c,d,this._pInst._rectMode);if(this._pInst._doStroke&&k.lineWidth%2===1&&k.translate(.5,.5),k.beginPath(),"undefined"==typeof f)k.rect(n.x,n.y,n.w,n.h);else{"undefined"==typeof g&&(g=f),"undefined"==typeof i&&(i=g),"undefined"==typeof j&&(j=i);var o=n.x,p=n.y,q=n.w,r=n.h,s=q/2,t=r/2;2*f>q&&(f=s),2*f>r&&(f=t),2*g>q&&(g=s),2*g>r&&(g=t),2*i>q&&(i=s),2*i>r&&(i=t),2*j>q&&(j=s),2*j>r&&(j=t),k.beginPath(),k.moveTo(o+f,p),k.arcTo(o+q,p,o+q,p+r,g),k.arcTo(o+q,p+r,o,p+r,i),k.arcTo(o,p+r,o,p,j),k.arcTo(o,p,o+q,p,f),k.closePath()}return this._pInst._doFill&&k.fill(),this._pInst._doStroke&&k.stroke(),this._pInst._doStroke&&k.lineWidth%2===1&&k.translate(-.5,-.5),this},d.Renderer2D.prototype.triangle=function(a,b,c,d,e,f){var g=this.drawingContext,i=this._pInst._doFill,j=this._pInst._doStroke;if(i&&!j){if(g.fillStyle===h)return this}else if(!i&&j&&g.strokeStyle===h)return this;g.beginPath(),g.moveTo(a,b),g.lineTo(c,d),g.lineTo(e,f),g.closePath(),i&&g.fill(),j&&g.stroke()},d.Renderer2D.prototype.endShape=function(a,b,c,d,e,g,h){if(0===b.length)return this;if(!this._pInst._doStroke&&!this._pInst._doFill)return this;var i,j=a===f.CLOSE;j&&!g&&b.push(b[0]);var k,l,m=b.length;if(!c||h!==f.POLYGON&&null!==h)if(!d||h!==f.POLYGON&&null!==h)if(!e||h!==f.POLYGON&&null!==h)if(h===f.POINTS)for(k=0;m>k;k++)i=b[k],this._pInst._doStroke&&this._pInst.stroke(i[6]),this._pInst.point(i[0],i[1]);else if(h===f.LINES)for(k=0;m>k+1;k+=2)i=b[k],this._pInst._doStroke&&this._pInst.stroke(b[k+1][6]),this._pInst.line(i[0],i[1],b[k+1][0],b[k+1][1]);else if(h===f.TRIANGLES)for(k=0;m>k+2;k+=3)i=b[k],this.drawingContext.beginPath(),this.drawingContext.moveTo(i[0],i[1]),this.drawingContext.lineTo(b[k+1][0],b[k+1][1]),this.drawingContext.lineTo(b[k+2][0],b[k+2][1]),this.drawingContext.lineTo(i[0],i[1]),this._pInst._doFill&&(this._pInst.fill(b[k+2][5]),this.drawingContext.fill()),this._pInst._doStroke&&(this._pInst.stroke(b[k+2][6]),this.drawingContext.stroke()),this.drawingContext.closePath();else if(h===f.TRIANGLE_STRIP)for(k=0;m>k+1;k++)i=b[k],this.drawingContext.beginPath(),this.drawingContext.moveTo(b[k+1][0],b[k+1][1]),this.drawingContext.lineTo(i[0],i[1]),this._pInst._doStroke&&this._pInst.stroke(b[k+1][6]),this._pInst._doFill&&this._pInst.fill(b[k+1][5]),m>k+2&&(this.drawingContext.lineTo(b[k+2][0],b[k+2][1]),this._pInst._doStroke&&this._pInst.stroke(b[k+2][6]),this._pInst._doFill&&this._pInst.fill(b[k+2][5])),this._doFillStrokeClose();else if(h===f.TRIANGLE_FAN){if(m>2)for(this.drawingContext.beginPath(),this.drawingContext.moveTo(b[0][0],b[0][1]),this.drawingContext.lineTo(b[1][0],b[1][1]),this.drawingContext.lineTo(b[2][0],b[2][1]),this._pInst._doFill&&this._pInst.fill(b[2][5]),this._pInst._doStroke&&this._pInst.stroke(b[2][6]),this._doFillStrokeClose(),k=3;m>k;k++)i=b[k],this.drawingContext.beginPath(),this.drawingContext.moveTo(b[0][0],b[0][1]),this.drawingContext.lineTo(b[k-1][0],b[k-1][1]),this.drawingContext.lineTo(i[0],i[1]),this._pInst._doFill&&this._pInst.fill(i[5]),this._pInst._doStroke&&this._pInst.stroke(i[6]),this._doFillStrokeClose()}else if(h===f.QUADS)for(k=0;m>k+3;k+=4){for(i=b[k],this.drawingContext.beginPath(),this.drawingContext.moveTo(i[0],i[1]),l=1;4>l;l++)this.drawingContext.lineTo(b[k+l][0],b[k+l][1]);this.drawingContext.lineTo(i[0],i[1]),this._pInst._doFill&&this._pInst.fill(b[k+3][5]),this._pInst._doStroke&&this._pInst.stroke(b[k+3][6]),this._doFillStrokeClose()}else if(h===f.QUAD_STRIP){if(m>3)for(k=0;m>k+1;k+=2)i=b[k],this.drawingContext.beginPath(),m>k+3?(this.drawingContext.moveTo(b[k+2][0],b[k+2][1]),this.drawingContext.lineTo(i[0],i[1]),this.drawingContext.lineTo(b[k+1][0],b[k+1][1]),this.drawingContext.lineTo(b[k+3][0],b[k+3][1]),this._pInst._doFill&&this._pInst.fill(b[k+3][5]),this._pInst._doStroke&&this._pInst.stroke(b[k+3][6])):(this.drawingContext.moveTo(i[0],i[1]),this.drawingContext.lineTo(b[k+1][0],b[k+1][1])),this._doFillStrokeClose()}else{for(this.drawingContext.beginPath(),this.drawingContext.moveTo(b[0][0],b[0][1]),k=1;m>k;k++)i=b[k],i.isVert&&(i.moveTo?this.drawingContext.moveTo(i[0],i[1]):this.drawingContext.lineTo(i[0],i[1]));this._doFillStrokeClose()}else{for(this.drawingContext.beginPath(),k=0;m>k;k++)b[k].isVert?b[k].moveTo?this.drawingContext.moveTo([0],b[k][1]):this.drawingContext.lineTo(b[k][0],b[k][1]):this.drawingContext.quadraticCurveTo(b[k][0],b[k][1],b[k][2],b[k][3]);this._doFillStrokeClose()}else{for(this.drawingContext.beginPath(),k=0;m>k;k++)b[k].isVert?b[k].moveTo?this.drawingContext.moveTo(b[k][0],b[k][1]):this.drawingContext.lineTo(b[k][0],b[k][1]):this.drawingContext.bezierCurveTo(b[k][0],b[k][1],b[k][2],b[k][3],b[k][4],b[k][5]);this._doFillStrokeClose()}else if(m>3){var n=[],o=1-this._pInst._curveTightness;for(this.drawingContext.beginPath(),this.drawingContext.moveTo(b[1][0],b[1][1]),k=1;m>k+2;k++)i=b[k],n[0]=[i[0],i[1]],n[1]=[i[0]+(o*b[k+1][0]-o*b[k-1][0])/6,i[1]+(o*b[k+1][1]-o*b[k-1][1])/6],n[2]=[b[k+1][0]+(o*b[k][0]-o*b[k+2][0])/6,b[k+1][1]+(o*b[k][1]-o*b[k+2][1])/6],n[3]=[b[k+1][0],b[k+1][1]],this.drawingContext.bezierCurveTo(n[1][0],n[1][1],n[2][0],n[2][1],n[3][0],n[3][1]);j&&this.drawingContext.lineTo(b[k+1][0],b[k+1][1]),this._doFillStrokeClose()}return c=!1,d=!1,e=!1,g=!1,j&&b.pop(),this},d.Renderer2D.prototype.noSmooth=function(){return"imageSmoothingEnabled"in this.drawingContext?this.drawingContext.imageSmoothingEnabled=!1:"mozImageSmoothingEnabled"in this.drawingContext?this.drawingContext.mozImageSmoothingEnabled=!1:"webkitImageSmoothingEnabled"in this.drawingContext?this.drawingContext.webkitImageSmoothingEnabled=!1:"msImageSmoothingEnabled"in this.drawingContext&&(this.drawingContext.msImageSmoothingEnabled=!1),this},d.Renderer2D.prototype.smooth=function(){return"imageSmoothingEnabled"in this.drawingContext?this.drawingContext.imageSmoothingEnabled=!0:"mozImageSmoothingEnabled"in this.drawingContext?this.drawingContext.mozImageSmoothingEnabled=!0:"webkitImageSmoothingEnabled"in this.drawingContext?this.drawingContext.webkitImageSmoothingEnabled=!0:"msImageSmoothingEnabled"in this.drawingContext&&(this.drawingContext.msImageSmoothingEnabled=!0),this},d.Renderer2D.prototype.strokeCap=function(a){return(a===f.ROUND||a===f.SQUARE||a===f.PROJECT)&&(this.drawingContext.lineCap=a),this},d.Renderer2D.prototype.strokeJoin=function(a){return(a===f.ROUND||a===f.BEVEL||a===f.MITER)&&(this.drawingContext.lineJoin=a),this},d.Renderer2D.prototype.strokeWeight=function(a){return"undefined"==typeof a||0===a?this.drawingContext.lineWidth=1e-4:this.drawingContext.lineWidth=a,this},d.Renderer2D.prototype._getFill=function(){return this.drawingContext.fillStyle},d.Renderer2D.prototype._getStroke=function(){return this.drawingContext.strokeStyle},d.Renderer2D.prototype.bezier=function(a,b,c,d,e,f,g,h){return this._pInst.beginShape(),this._pInst.vertex(a,b),this._pInst.bezierVertex(c,d,e,f,g,h),this._pInst.endShape(),this},d.Renderer2D.prototype.curve=function(a,b,c,d,e,f,g,h){return this._pInst.beginShape(),this._pInst.curveVertex(a,b),this._pInst.curveVertex(c,d),this._pInst.curveVertex(e,f),this._pInst.curveVertex(g,h),this._pInst.endShape(),this},d.Renderer2D.prototype._doFillStrokeClose=function(){this._pInst._doFill&&this.drawingContext.fill(),this._pInst._doStroke&&this.drawingContext.stroke(),this.drawingContext.closePath()},d.Renderer2D.prototype.applyMatrix=function(a,b,c,d,e,f){this.drawingContext.transform(a,b,c,d,e,f)},d.Renderer2D.prototype.resetMatrix=function(){return this.drawingContext.setTransform(1,0,0,1,0,0),this.drawingContext.scale(this._pInst.pixelDensity,this._pInst.pixelDensity),this},d.Renderer2D.prototype.rotate=function(a){this.drawingContext.rotate(a)},d.Renderer2D.prototype.scale=function(){var a=1,b=1;return 1===arguments.length?a=b=arguments[0]:(a=arguments[0],b=arguments[1]),this.drawingContext.scale(a,b),this},d.Renderer2D.prototype.shearX=function(a){return this._pInst._angleMode===f.DEGREES&&(a=this._pInst.radians(a)),this.drawingContext.transform(1,0,this._pInst.tan(a),1,0,0),this},d.Renderer2D.prototype.shearY=function(a){return this._pInst._angleMode===f.DEGREES&&(a=this._pInst.radians(a)),this.drawingContext.transform(1,this._pInst.tan(a),0,1,0,0),this},d.Renderer2D.prototype.translate=function(a,b){return this.drawingContext.translate(a,b),this},d.Renderer2D.prototype.text=function(a,b,c,d,e){var g,h,i,j,k,l,m,n,o,p,q=this._pInst;if(q._doFill||q._doStroke){if("string"!=typeof a&&(a=a.toString()),a=a.replace(/(\t)/g," "),g=a.split("\n"),"undefined"!=typeof d){for(o=0,i=0;i<g.length;i++)for(k="",n=g[i].split(" "),h=0;h<n.length;h++)l=k+n[h]+" ",m=this.textWidth(l),m>d?(k=n[h]+" ",o+=q.textLeading()):k=l;switch(this._pInst._rectMode===f.CENTER&&(b-=d/2,c-=e/2),this.drawingContext.textAlign){case f.CENTER:b+=d/2;break;case f.RIGHT:b+=d}if("undefined"!=typeof e)switch(this.drawingContext.textBaseline){case f.BOTTOM:c+=e-o;break;case f._CTX_MIDDLE:c+=(e-o)/2;break;case f.BASELINE:p=!0,this.drawingContext.textBaseline=f.TOP}for(i=0;i<g.length;i++){for(k="",n=g[i].split(" "),h=0;h<n.length;h++)l=k+n[h]+" ",m=this.textWidth(l),m>d&&k.length>0?(this._renderText(q,k,b,c),k=n[h]+" ",c+=q.textLeading()):k=l;this._renderText(q,k,b,c),c+=q.textLeading()}}else for(j=0;j<g.length;j++)this._renderText(q,g[j],b,c),c+=q.textLeading();return p&&(this.drawingContext.textBaseline=f.BASELINE),q}},d.Renderer2D.prototype._renderText=function(a,b,c,d){return a.push(),a._isOpenType()?a._textFont._renderPath(b,c,d):(a._doStroke&&a._strokeSet&&this.drawingContext.strokeText(b,c,d),a._doFill&&(this.drawingContext.fillStyle=a._fillSet?this.drawingContext.fillStyle:f._DEFAULT_TEXT_FILL,this.drawingContext.fillText(b,c,d))),a.pop(),a},d.Renderer2D.prototype.textWidth=function(a){return this._pInst._isOpenType()?this._pInst._textFont._textWidth(a):this.drawingContext.measureText(a).width},d.Renderer2D.prototype.textAlign=function(a,b){if(arguments.length)return(a===f.LEFT||a===f.RIGHT||a===f.CENTER)&&(this.drawingContext.textAlign=a),(b===f.TOP||b===f.BOTTOM||b===f.CENTER||b===f.BASELINE)&&(b===f.CENTER?this.drawingContext.textBaseline=f._CTX_MIDDLE:this.drawingContext.textBaseline=b),this._pInst;var c=this.drawingContext.textBaseline;return c===f._CTX_MIDDLE&&(c=f.CENTER),{horizontal:this.drawingContext.textAlign,vertical:c}},d.Renderer2D.prototype._applyTextProperties=function(){var a,b=this._pInst;return b._setProperty("_textAscent",null),b._setProperty("_textDescent",null),a=b._textFont,b._isOpenType()&&(a=b._textFont.font.familyName,b._setProperty("_textStyle",b._textFont.font.styleName)),this.drawingContext.font=b._textStyle+" "+b._textSize+"px "+a,b},d.Renderer2D.prototype.push=function(){this.drawingContext.save()},d.Renderer2D.prototype.pop=function(){this.drawingContext.restore()},b.exports=d.Renderer2D},{"../image/filters":66,"./canvas":47,"./constants":48,"./core":49,"./p5.Renderer":55}],57:[function(a,b,c){var d=a("./core"),e=a("./constants");a("./p5.Graphics"),a("./p5.Renderer2D"),a("../3d/p5.Renderer3D"),d.prototype.createCanvas=function(a,b,c){var f,g,h=c||e.P2D;return arguments[3]&&(f="boolean"==typeof arguments[3]?arguments[3]:!1),h===e.WEBGL?(g=document.getElementById("defaultCanvas"),g&&g.parentNode.removeChild(g),g=document.createElement("canvas"),g.id="defaultCanvas"):f?(g=document.createElement("canvas"),g.id="defaultCanvas"):g=this.canvas,this._setupDone||(g.className+=" p5_hidden",g.style.visibility="hidden"),this._userNode?this._userNode.appendChild(g):document.body.appendChild(g),h===e.WEBGL?(this._setProperty("_graphics",new d.Renderer3D(g,this,!0)),this._isdefaultGraphics=!0):this._isdefaultGraphics||(this._setProperty("_graphics",new d.Renderer2D(g,this,!0)),this._isdefaultGraphics=!0),this._graphics.resize(a,b),this._graphics._applyDefaults(),f&&this._elements.push(this._graphics),this._graphics},d.prototype.resizeCanvas=function(a,b,c){this._graphics&&(this._graphics.resize(a,b),this._graphics._applyDefaults(),c||this.redraw())},d.prototype.noCanvas=function(){this.canvas&&this.canvas.parentNode.removeChild(this.canvas)},d.prototype.createGraphics=function(a,b,c){return new d.Graphics(a,b,c,this)},d.prototype.blendMode=function(a){if(a!==e.BLEND&&a!==e.DARKEST&&a!==e.LIGHTEST&&a!==e.DIFFERENCE&&a!==e.MULTIPLY&&a!==e.EXCLUSION&&a!==e.SCREEN&&a!==e.REPLACE&&a!==e.OVERLAY&&a!==e.HARD_LIGHT&&a!==e.SOFT_LIGHT&&a!==e.DODGE&&a!==e.BURN&&a!==e.ADD&&a!==e.NORMAL)throw new Error("Mode "+a+" not recognized.");this._graphics.blendMode(a)},b.exports=d},{"../3d/p5.Renderer3D":37,"./constants":48,"./core":49,"./p5.Graphics":54,"./p5.Renderer2D":56}],58:[function(a,b,c){window.requestAnimationFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a,b){window.setTimeout(a,1e3/60)}}(),window.performance=window.performance||{},window.performance.now=function(){var a=Date.now();return window.performance.now||window.performance.mozNow||window.performance.msNow||window.performance.oNow||window.performance.webkitNow||function(){return Date.now()-a}}(),function(){"use strict";"undefined"!=typeof Uint8ClampedArray&&(Uint8ClampedArray.prototype.slice=Array.prototype.slice)}()},{}],59:[function(a,b,c){"use strict";var d=a("./core");d.prototype.exit=function(){throw"exit() not implemented, see remove()"},d.prototype.noLoop=function(){this._loop=!1},d.prototype.loop=function(){this._loop=!0,this._draw()},d.prototype.push=function(){this._graphics.push(),this._styles.push({doStroke:this._doStroke,doFill:this._doFill,tint:this._tint,imageMode:this._imageMode,rectMode:this._rectMode,ellipseMode:this._ellipseMode,colorMode:this._colorMode,textFont:this.textFont,textLeading:this.textLeading,textSize:this.textSize,textStyle:this.textStyle})},d.prototype.pop=function(){this._graphics.pop();var a=this._styles.pop();this._doStroke=a.doStroke,this._doFill=a.doFill,this._tint=a.tint,this._imageMode=a.imageMode,this._rectMode=a.rectMode,this._ellipseMode=a.ellipseMode,this._colorMode=a.colorMode,this.textFont=a.textFont,this.textLeading=a.textLeading,this.textSize=a.textSize,this.textStyle=a.textStyle},d.prototype.pushStyle=function(){throw new Error("pushStyle() not used, see push()")},d.prototype.popStyle=function(){throw new Error("popStyle() not used, see pop()")},d.prototype.redraw=function(){var a=this.setup||window.setup,b=this.draw||window.draw;if("function"==typeof b){this.push(),"undefined"==typeof a&&this.scale(this.pixelDensity,this.pixelDensity);var c=this;this._registeredMethods.pre.forEach(function(a){a.call(c)}),b(),this._registeredMethods.post.forEach(function(a){a.call(c)}),this.pop()}},d.prototype.size=function(){var a="size() is not a valid p5 function, to set the size of the ";throw a+="drawing canvas, please use createCanvas() instead"},b.exports=d},{"./core":49}],60:[function(a,b,c){"use strict";var d=a("./core"),e=a("./constants");d.prototype.applyMatrix=function(a,b,c,d,e,f){return this._graphics.applyMatrix(a,b,c,d,e,f),this},d.prototype.popMatrix=function(){throw new Error("popMatrix() not used, see pop()")},d.prototype.printMatrix=function(){throw new Error("printMatrix() not implemented")},d.prototype.pushMatrix=function(){throw new Error("pushMatrix() not used, see push()")},d.prototype.resetMatrix=function(){return this._graphics.resetMatrix(),this},d.prototype.rotate=function(a){return this._angleMode===e.DEGREES&&(a=this.radians(a)),this._graphics.rotate(a),this},d.prototype.rotateX=function(a){if(!this._graphics.isP3D)throw"not yet implemented.";return this._graphics.rotateX(a),this},d.prototype.rotateY=function(a){if(!this._graphics.isP3D)throw"not yet implemented.";return this._graphics.rotateY(a),this},d.prototype.rotateZ=function(a){if(!this._graphics.isP3D)throw"not supported in p2d. Please use webgl mode";return this._graphics.rotateZ(a),this},d.prototype.scale=function(){return this._graphics.isP3D?this._graphics.scale(arguments[0],arguments[1],arguments[2]):this._graphics.scale.apply(this._graphics,arguments),this},d.prototype.shearX=function(a){return this._angleMode===e.DEGREES&&(a=this.radians(a)),this._graphics.shearX(a),this},d.prototype.shearY=function(a){return this._angleMode===e.DEGREES&&(a=this.radians(a)),this._graphics.shearY(a),this},d.prototype.translate=function(a,b,c){return this._graphics.isP3D?this._graphics.translate(a,b,c):this._graphics.translate(a,b),this},b.exports=d},{"./constants":48,"./core":49}],61:[function(a,b,c){"use strict";var d=a("./core"),e=a("./constants"),f=null,g=[],h=[],i=!1,j=!1,k=!1,l=!1;d.prototype.beginContour=function(){return h=[],l=!0,this},d.prototype.beginShape=function(a){return this._graphics.isP3D?this._graphics.beginShape(a):(f=a===e.POINTS||a===e.LINES||a===e.TRIANGLES||a===e.TRIANGLE_FAN||a===e.TRIANGLE_STRIP||a===e.QUADS||a===e.QUAD_STRIP?a:null,g=[],h=[]),this},d.prototype.bezierVertex=function(a,b,c,d,e,f){if(0===g.length)throw"vertex() must be used once before calling bezierVertex()";i=!0;for(var j=[],k=0;k<arguments.length;k++)j[k]=arguments[k];return j.isVert=!1,l?h.push(j):g.push(j),this},d.prototype.curveVertex=function(a,b){return j=!0,this.vertex(a,b),this},d.prototype.endContour=function(){var a=h[0].slice();a.isVert=h[0].isVert,a.moveTo=!1,h.push(a),g.push(g[0]);for(var b=0;b<h.length;b++)g.push(h[b]);return this},d.prototype.endShape=function(a){if(this._graphics.isP3D)this._graphics.endShape();else{if(0===g.length)return this;if(!this._doStroke&&!this._doFill)return this;var b=a===e.CLOSE;b&&!l&&g.push(g[0]),this._graphics.endShape(a,g,j,i,k,l,f),j=!1,i=!1,k=!1,l=!1,b&&g.pop()}return this},d.prototype.quadraticVertex=function(a,b,c,d){
if(this._contourInited){var f={};return f.x=a,f.y=b,f.x3=c,f.y3=d,f.type=e.QUADRATIC,this._contourVertices.push(f),this}if(!(g.length>0))throw"vertex() must be used once before calling quadraticVertex()";k=!0;for(var i=[],j=0;j<arguments.length;j++)i[j]=arguments[j];return i.isVert=!1,l?h.push(i):g.push(i),this},d.prototype.vertex=function(a,b,c){if(this._graphics.isP3D)this._graphics.vertex(arguments[0],arguments[1],arguments[2]);else{var d=[];d.isVert=!0,d[0]=a,d[1]=b,d[2]=0,d[3]=0,d[4]=0,d[5]=this._graphics._getFill(),d[6]=this._graphics._getStroke(),c&&(d.moveTo=c),l?(0===h.length&&(d.moveTo=!0),h.push(d)):g.push(d)}return this},b.exports=d},{"./constants":48,"./core":49}],62:[function(a,b,c){"use strict";var d=a("../core/core");d.prototype.deviceOrientation=void 0,d.prototype.accelerationX=0,d.prototype.accelerationY=0,d.prototype.accelerationZ=0,d.prototype.pAccelerationX=0,d.prototype.pAccelerationY=0,d.prototype.pAccelerationZ=0,d.prototype._updatePAccelerations=function(){this._setProperty("pAccelerationX",this.accelerationX),this._setProperty("pAccelerationY",this.accelerationY),this._setProperty("pAccelerationZ",this.accelerationZ)};var e=.5,f=30;d.prototype.setMoveThreshold=function(a){"number"==typeof a&&(e=a)},d.prototype.setShakeThreshold=function(a){"number"==typeof a&&(f=a)};var g="",h="";d.prototype._ondeviceorientation=function(a){this._setProperty("accelerationX",a.beta),this._setProperty("accelerationY",a.gamma),this._setProperty("accelerationZ",a.alpha),this._handleMotion()},d.prototype._ondevicemotion=function(a){this._setProperty("accelerationX",2*a.acceleration.x),this._setProperty("accelerationY",2*a.acceleration.y),this._setProperty("accelerationZ",2*a.acceleration.z),this._handleMotion()},d.prototype._onMozOrientation=function(a){this._setProperty("accelerationX",a.x),this._setProperty("accelerationY",a.y),this._setProperty("accelerationZ",a.z),this._handleMotion()},d.prototype._handleMotion=function(){90===window.orientation||-90===window.orientation?this._setProperty("deviceOrientation","landscape"):0===window.orientation?this._setProperty("deviceOrientation","portrait"):void 0===window.orientation&&this._setProperty("deviceOrientation","undefined");var a=this.deviceMoved||window.deviceMoved;"function"==typeof a&&(Math.abs(this.accelerationX-this.pAccelerationX)>e||Math.abs(this.accelerationY-this.pAccelerationY)>e||Math.abs(this.accelerationZ-this.pAccelerationZ)>e)&&a();var b=this.deviceTurned||window.deviceTurned;if("function"==typeof b){var c=0;Math.abs(this.accelerationX)>c&&(c=this.accelerationX,h="x"),Math.abs(this.accelerationY)>c&&(c=this.accelerationY,h="y"),Math.abs(this.accelerationZ)>c&&(h="z"),""!==g&&g!==h&&b(h),g=h}var d=this.deviceShaken||window.deviceShaken;if("function"==typeof d){var i,j;null!==this.pAccelerationX&&(i=Math.abs(this.accelerationX-this.pAccelerationX),j=Math.abs(this.accelerationY-this.pAccelerationY)),i+j>f&&d()}},b.exports=d},{"../core/core":49}],63:[function(a,b,c){"use strict";var d=a("../core/core"),e={};d.prototype.isKeyPressed=!1,d.prototype.keyIsPressed=!1,d.prototype.key="",d.prototype.keyCode=0,d.prototype._onkeydown=function(a){this._setProperty("isKeyPressed",!0),this._setProperty("keyIsPressed",!0),this._setProperty("keyCode",a.which),e[a.which]=!0;var b=String.fromCharCode(a.which);b||(b=a.which),this._setProperty("key",b);var c=this.keyPressed||window.keyPressed;if("function"==typeof c&&!a.charCode){var d=c(a);d===!1&&a.preventDefault()}},d.prototype._onkeyup=function(a){var b=this.keyReleased||window.keyReleased;this._setProperty("isKeyPressed",!1),this._setProperty("keyIsPressed",!1),e[a.which]=!1;var c=String.fromCharCode(a.which);if(c||(c=a.which),this._setProperty("key",c),this._setProperty("keyCode",a.which),"function"==typeof b){var d=b(a);d===!1&&a.preventDefault()}},d.prototype._onkeypress=function(a){this._setProperty("keyCode",a.which),this._setProperty("key",String.fromCharCode(a.which));var b=this.keyTyped||window.keyTyped;if("function"==typeof b){var c=b(a);c===!1&&a.preventDefault()}},d.prototype._onblur=function(a){e={}},d.prototype.keyIsDown=function(a){return e[a]},b.exports=d},{"../core/core":49}],64:[function(a,b,c){"use strict";function d(a,b){var c=a.getBoundingClientRect();return{x:b.clientX-c.left,y:b.clientY-c.top}}var e=a("../core/core"),f=a("../core/constants");e.prototype.mouseX=0,e.prototype.mouseY=0,e.prototype.pmouseX=0,e.prototype.pmouseY=0,e.prototype.winMouseX=0,e.prototype.winMouseY=0,e.prototype.pwinMouseX=0,e.prototype.pwinMouseY=0,e.prototype.mouseButton=0,e.prototype.mouseIsPressed=!1,e.prototype.isMousePressed=!1,e.prototype._updateMouseCoords=function(a){if("touchstart"===a.type||"touchmove"===a.type||"touchend"===a.type)this._setProperty("mouseX",this.touchX),this._setProperty("mouseY",this.touchY);else if(null!==this._curElement){var b=d(this._curElement.elt,a);this._setProperty("mouseX",b.x),this._setProperty("mouseY",b.y)}this._setProperty("winMouseX",a.pageX),this._setProperty("winMouseY",a.pageY)},e.prototype._updatePMouseCoords=function(a){this._setProperty("pmouseX",this.mouseX),this._setProperty("pmouseY",this.mouseY),this._setProperty("pwinMouseX",this.winMouseX),this._setProperty("pwinMouseY",this.winMouseY)},e.prototype._setMouseButton=function(a){1===a.button?this._setProperty("mouseButton",f.CENTER):2===a.button?this._setProperty("mouseButton",f.RIGHT):(this._setProperty("mouseButton",f.LEFT),("touchstart"===a.type||"touchmove"===a.type)&&(this._setProperty("mouseX",this.touchX),this._setProperty("mouseY",this.touchY)))},e.prototype._onmousemove=function(a){var b,c=this._isGlobal?window:this;this._updateMouseCoords(a),this.isMousePressed?"function"==typeof c.mouseDragged?(b=c.mouseDragged(a),b===!1&&a.preventDefault()):"function"==typeof c.touchMoved&&(b=c.touchMoved(a),b===!1&&a.preventDefault(),this._updateTouchCoords(a)):"function"==typeof c.mouseMoved&&(b=c.mouseMoved(a),b===!1&&a.preventDefault())},e.prototype._onmousedown=function(a){var b,c=this._isGlobal?window:this;this._setProperty("isMousePressed",!0),this._setProperty("mouseIsPressed",!0),this._setMouseButton(a),this._updateMouseCoords(a),"function"==typeof c.mousePressed?(b=c.mousePressed(a),b===!1&&a.preventDefault()):"function"==typeof c.touchStarted&&(b=c.touchStarted(a),b===!1&&a.preventDefault(),this._updateTouchCoords(a))},e.prototype._onmouseup=function(a){var b,c=this._isGlobal?window:this;this._setProperty("isMousePressed",!1),this._setProperty("mouseIsPressed",!1),"function"==typeof c.mouseReleased?(b=c.mouseReleased(a),b===!1&&a.preventDefault()):"function"==typeof c.touchEnded&&(b=c.touchEnded(a),b===!1&&a.preventDefault(),this._updateTouchCoords(a))},e.prototype._onclick=function(a){var b=this._isGlobal?window:this;if("function"==typeof b.mouseClicked){var c=b.mouseClicked(a);c===!1&&a.preventDefault()}},e.prototype._onmousewheel=e.prototype._onDOMMouseScroll=function(a){var b=this._isGlobal?window:this;if("function"==typeof b.mouseWheel){a.delta=Math.max(-1,Math.min(1,a.wheelDelta||-a.detail));var c=b.mouseWheel(a);c===!1&&a.preventDefault()}},b.exports=e},{"../core/constants":48,"../core/core":49}],65:[function(a,b,c){"use strict";function d(a,b,c){c=c||0;var d=a.getBoundingClientRect(),e=b.touches[c]||b.changedTouches[c];return{x:e.clientX-d.left,y:e.clientY-d.top}}var e=a("../core/core");e.prototype.touchX=0,e.prototype.touchY=0,e.prototype.ptouchX=0,e.prototype.ptouchY=0,e.prototype.touches=[],e.prototype.touchIsDown=!1,e.prototype._updateTouchCoords=function(a){if("mousedown"===a.type||"mousemove"===a.type||"mouseup"===a.type)this._setProperty("touchX",this.mouseX),this._setProperty("touchY",this.mouseY);else{var b=d(this._curElement.elt,a,0);this._setProperty("touchX",b.x),this._setProperty("touchY",b.y);for(var c=[],e=0;e<a.touches.length;e++){var f=d(this._curElement.elt,a,e);c[e]={x:f.x,y:f.y}}this._setProperty("touches",c)}},e.prototype._updatePTouchCoords=function(){this._setProperty("ptouchX",this.touchX),this._setProperty("ptouchY",this.touchY)},e.prototype._ontouchstart=function(a){var b,c=this._isGlobal?window:this;this._updateTouchCoords(a),this._setProperty("touchIsDown",!0),"function"==typeof c.touchStarted?(b=c.touchStarted(a),b===!1&&a.preventDefault()):"function"==typeof c.mousePressed&&(b=c.mousePressed(a),b===!1&&a.preventDefault())},e.prototype._ontouchmove=function(a){var b,c=this._isGlobal?window:this;this._updateTouchCoords(a),"function"==typeof c.touchMoved?(b=c.touchMoved(a),b===!1&&a.preventDefault()):"function"==typeof c.mouseDragged&&(b=c.mouseDragged(a),b===!1&&a.preventDefault(),this._updateMouseCoords(a))},e.prototype._ontouchend=function(a){this._updateTouchCoords(a),0===this.touches.length&&this._setProperty("touchIsDown",!1);var b,c=this._isGlobal?window:this;"function"==typeof c.touchEnded?(b=c.touchEnded(a),b===!1&&a.preventDefault()):"function"==typeof c.mouseReleased&&(b=c.mouseReleased(a),b===!1&&a.preventDefault(),this._updateMouseCoords(a))},b.exports=e},{"../core/core":49}],66:[function(a,b,c){"use strict";function d(a){var b=3.5*a|0;if(b=1>b?1:248>b?b:248,g!==b){g=b,h=1+g<<1,i=new Int32Array(h),j=new Array(h);for(var c=0;h>c;c++)j[c]=new Int32Array(256);for(var d,e,f,k,l=1,m=b-1;b>l;l++){i[b+l]=i[m]=e=m*m,f=j[b+l],k=j[m--];for(var n=0;256>n;n++)f[n]=k[n]=e*n}d=i[b]=b*b,f=j[b];for(var o=0;256>o;o++)f[o]=d*o}}function e(a,b){for(var c=f._toPixels(a),e=a.width,k=a.height,l=e*k,m=new Int32Array(l),n=0;l>n;n++)m[n]=f._getARGB(c,n);var o,p,q,r,s,t,u,v,w,x,y=new Int32Array(l),z=new Int32Array(l),A=new Int32Array(l),B=new Int32Array(l),C=0;d(b);var D,E,F,G;for(E=0;k>E;E++){for(D=0;e>D;D++){if(r=q=p=s=o=0,t=D-g,0>t)x=-t,t=0;else{if(t>=e)break;x=0}for(F=x;h>F&&!(t>=e);F++){var H=m[t+C];G=j[F],s+=G[(-16777216&H)>>>24],p+=G[(16711680&H)>>16],q+=G[(65280&H)>>8],r+=G[255&H],o+=i[F],t++}u=C+D,y[u]=s/o,z[u]=p/o,A[u]=q/o,B[u]=r/o}C+=e}for(C=0,v=-g,w=v*e,E=0;k>E;E++){for(D=0;e>D;D++){if(r=q=p=s=o=0,0>v)x=u=-v,t=D;else{if(v>=k)break;x=0,u=v,t=D+w}for(F=x;h>F&&!(u>=k);F++)G=j[F],s+=G[y[t]],p+=G[z[t]],q+=G[A[t]],r+=G[B[t]],o+=i[F],u++,t+=e;m[D+C]=s/o<<24|p/o<<16|q/o<<8|r/o}C+=e,w+=e,v++}f._setPixels(c,m)}var f={};f._toPixels=function(a){return a instanceof ImageData?a.data:a.getContext("2d").getImageData(0,0,a.width,a.height).data},f._getARGB=function(a,b){var c=4*b;return a[c+3]<<24&4278190080|a[c]<<16&16711680|a[c+1]<<8&65280|255&a[c+2]},f._setPixels=function(a,b){for(var c=0,d=0,e=a.length;e>d;d++)c=4*d,a[c+0]=(16711680&b[d])>>>16,a[c+1]=(65280&b[d])>>>8,a[c+2]=255&b[d],a[c+3]=(4278190080&b[d])>>>24},f._toImageData=function(a){return a instanceof ImageData?a:a.getContext("2d").getImageData(0,0,a.width,a.height)},f._createImageData=function(a,b){return f._tmpCanvas=document.createElement("canvas"),f._tmpCtx=f._tmpCanvas.getContext("2d"),this._tmpCtx.createImageData(a,b)},f.apply=function(a,b,c){var d=a.getContext("2d"),e=d.getImageData(0,0,a.width,a.height),f=b(e,c);f instanceof ImageData?d.putImageData(f,0,0,0,0,a.width,a.height):d.putImageData(e,0,0,0,0,a.width,a.height)},f.threshold=function(a,b){var c=f._toPixels(a);void 0===b&&(b=.5);for(var d=Math.floor(255*b),e=0;e<c.length;e+=4){var g,h=c[e],i=c[e+1],j=c[e+2],k=.2126*h+.7152*i+.0722*j;g=k>=d?255:0,c[e]=c[e+1]=c[e+2]=g}},f.gray=function(a){for(var b=f._toPixels(a),c=0;c<b.length;c+=4){var d=b[c],e=b[c+1],g=b[c+2],h=.2126*d+.7152*e+.0722*g;b[c]=b[c+1]=b[c+2]=h}},f.opaque=function(a){for(var b=f._toPixels(a),c=0;c<b.length;c+=4)b[c+3]=255;return b},f.invert=function(a){for(var b=f._toPixels(a),c=0;c<b.length;c+=4)b[c]=255-b[c],b[c+1]=255-b[c+1],b[c+2]=255-b[c+2]},f.posterize=function(a,b){var c=f._toPixels(a);if(2>b||b>255)throw new Error("Level must be greater than 2 and less than 255 for posterize");for(var d=b-1,e=0;e<c.length;e+=4){var g=c[e],h=c[e+1],i=c[e+2];c[e]=255*(g*b>>8)/d,c[e+1]=255*(h*b>>8)/d,c[e+2]=255*(i*b>>8)/d}},f.dilate=function(a){for(var b,c,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t=f._toPixels(a),u=0,v=t.length?t.length/4:0,w=new Int32Array(v);v>u;)for(b=u,c=u+a.width;c>u;)d=e=f._getARGB(t,u),i=u-1,h=u+1,j=u-a.width,k=u+a.width,b>i&&(i=u),h>=c&&(h=u),0>j&&(j=0),k>=v&&(k=u),n=f._getARGB(t,j),m=f._getARGB(t,i),o=f._getARGB(t,k),l=f._getARGB(t,h),g=77*(d>>16&255)+151*(d>>8&255)+28*(255&d),q=77*(m>>16&255)+151*(m>>8&255)+28*(255&m),p=77*(l>>16&255)+151*(l>>8&255)+28*(255&l),r=77*(n>>16&255)+151*(n>>8&255)+28*(255&n),s=77*(o>>16&255)+151*(o>>8&255)+28*(255&o),q>g&&(e=m,g=q),p>g&&(e=l,g=p),r>g&&(e=n,g=r),s>g&&(e=o,g=s),w[u++]=e;f._setPixels(t,w)},f.erode=function(a){for(var b,c,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t=f._toPixels(a),u=0,v=t.length?t.length/4:0,w=new Int32Array(v);v>u;)for(b=u,c=u+a.width;c>u;)d=e=f._getARGB(t,u),i=u-1,h=u+1,j=u-a.width,k=u+a.width,b>i&&(i=u),h>=c&&(h=u),0>j&&(j=0),k>=v&&(k=u),n=f._getARGB(t,j),m=f._getARGB(t,i),o=f._getARGB(t,k),l=f._getARGB(t,h),g=77*(d>>16&255)+151*(d>>8&255)+28*(255&d),q=77*(m>>16&255)+151*(m>>8&255)+28*(255&m),p=77*(l>>16&255)+151*(l>>8&255)+28*(255&l),r=77*(n>>16&255)+151*(n>>8&255)+28*(255&n),s=77*(o>>16&255)+151*(o>>8&255)+28*(255&o),g>q&&(e=m,g=q),g>p&&(e=l,g=p),g>r&&(e=n,g=r),g>s&&(e=o,g=s),w[u++]=e;f._setPixels(t,w)};var g,h,i,j;f.blur=function(a,b){e(a,b)},b.exports=f},{}],67:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("../core/constants"),f=[];d.prototype._imageMode=e.CORNER,d.prototype._tint=null,d.prototype.createImage=function(a,b){return new d.Image(a,b)},d.prototype.saveCanvas=function(){var a,b,c;if(3===arguments.length?(a=arguments[0],b=arguments[1],c=arguments[2]):2===arguments.length?"object"==typeof arguments[0]?(a=arguments[0],b=arguments[1]):(b=arguments[0],c=arguments[1]):1===arguments.length&&("object"==typeof arguments[0]?a=arguments[0]:b=arguments[0]),a instanceof d.Element&&(a=a.elt),a instanceof HTMLCanvasElement||(a=null),c||(c=d.prototype._checkFileExtension(b,c)[1],""===c&&(c="png")),a||this._curElement&&this._curElement.elt&&(a=this._curElement.elt),d.prototype._isSafari()){var e="Hello, Safari user!\n";e+="Now capturing a screenshot...\n",e+="To save this image,\n",e+="go to File --> Save As.\n",alert(e),window.location.href=a.toDataURL()}else{var f;if("undefined"==typeof c)c="png",f="image/png";else switch(c){case"png":f="image/png";break;case"jpeg":f="image/jpeg";break;case"jpg":f="image/jpeg";break;default:f="image/png"}var g="image/octet-stream",h=a.toDataURL(f);h=h.replace(f,g),d.prototype.downloadFile(h,b,c)}},d.prototype.saveFrames=function(a,b,c,e,g){var h=c||3;h=d.prototype.constrain(h,0,15),h=1e3*h;var i=e||15;i=d.prototype.constrain(i,0,22);var j=0,k=d.prototype._makeFrame,l=this._curElement.elt,m=setInterval(function(){k(a+j,b,l),j++},1e3/i);setTimeout(function(){if(clearInterval(m),g)g(f);else for(var a=0;a<f.length;a++){var b=f[a];d.prototype.downloadFile(b.imageData,b.filename,b.ext)}f=[]},h+.01)},d.prototype._makeFrame=function(a,b,c){var d;d=this?this._curElement.elt:c;var e;if(b)switch(b.toLowerCase()){case"png":e="image/png";break;case"jpeg":e="image/jpeg";break;case"jpg":e="image/jpeg";break;default:e="image/png"}else b="png",e="image/png";var g="image/octet-stream",h=d.toDataURL(e);h=h.replace(e,g);var i={};i.imageData=h,i.filename=a,i.ext=b,f.push(i)},b.exports=d},{"../core/constants":48,"../core/core":49}],68:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("./filters"),f=a("../core/canvas"),g=a("../core/constants");a("../core/error_helpers"),d.prototype.loadImage=function(a,b,c){var e=new Image,f=new d.Image(1,1,this);return e.onload=function(){f.width=f.canvas.width=e.width,f.height=f.canvas.height=e.height,f.drawingContext.drawImage(e,0,0),"function"==typeof b&&b(f)},e.onerror=function(a){d._friendlyFileLoadError(0,e.src),"function"==typeof c&&c(a)},0!==a.indexOf("data:image/")&&(e.crossOrigin="Anonymous"),e.src=a,f},d.prototype.image=function(a,b,c,d,e){b=b||0,c=c||0,d=d||a.width,e=e||a.height;var g=f.modeAdjust(b,c,d,e,this._imageMode);this._graphics.image(a,g.x,g.y,g.w,g.h)},d.prototype.tint=function(){var a=this.color.apply(this,arguments);this._tint=a.rgba},d.prototype.noTint=function(){this._tint=null},d.prototype._getTintedImageCanvas=function(a){if(!a.canvas)return a;var b=e._toPixels(a.canvas),c=document.createElement("canvas");c.width=a.canvas.width,c.height=a.canvas.height;for(var d=c.getContext("2d"),f=d.createImageData(a.canvas.width,a.canvas.height),g=f.data,h=0;h<b.length;h+=4){var i=b[h],j=b[h+1],k=b[h+2],l=b[h+3];g[h]=i*this._tint[0]/255,g[h+1]=j*this._tint[1]/255,g[h+2]=k*this._tint[2]/255,g[h+3]=l*this._tint[3]/255}return d.putImageData(f,0,0),c},d.prototype.imageMode=function(a){(a===g.CORNER||a===g.CORNERS||a===g.CENTER)&&(this._imageMode=a)},b.exports=d},{"../core/canvas":47,"../core/constants":48,"../core/core":49,"../core/error_helpers":52,"./filters":66}],69:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("./filters");d.Image=function(a,b){this.width=a,this.height=b,this.canvas=document.createElement("canvas"),this.canvas.width=this.width,this.canvas.height=this.height,this.drawingContext=this.canvas.getContext("2d"),this.pixelDensity=1,this.pixels=[]},d.Image.prototype._setProperty=function(a,b){this[a]=b},d.Image.prototype.loadPixels=function(){d.Renderer2D.prototype.loadPixels.call(this)},d.Image.prototype.updatePixels=function(a,b,c,e){d.Renderer2D.prototype.updatePixels.call(this,a,b,c,e)},d.Image.prototype.get=function(a,b,c,e){return d.Renderer2D.prototype.get.call(this,a,b,c,e)},d.Image.prototype.set=function(a,b,c){d.Renderer2D.prototype.set.call(this,a,b,c)},d.Image.prototype.resize=function(a,b){a=a||this.canvas.width,b=b||this.canvas.height;var c=document.createElement("canvas");c.width=a,c.height=b,c.getContext("2d").drawImage(this.canvas,0,0,this.canvas.width,this.canvas.height,0,0,c.width,c.height),this.canvas.width=this.width=a,this.canvas.height=this.height=b,this.drawingContext.drawImage(c,0,0,a,b,0,0,a,b),this.pixels.length>0&&this.loadPixels()},d.Image.prototype.copy=function(){d.prototype.copy.apply(this,arguments)},d.Image.prototype.mask=function(a){void 0===a&&(a=this);var b=this.drawingContext.globalCompositeOperation,c=1;a instanceof d.Renderer&&(c=a._pInst.pixelDensity);var e=[a,0,0,c*a.width,c*a.height,0,0,this.width,this.height];this.drawingContext.globalCompositeOperation="destination-in",this.copy.apply(this,e),this.drawingContext.globalCompositeOperation=b},d.Image.prototype.filter=function(a,b){e.apply(this.canvas,e[a.toLowerCase()],b)},d.Image.prototype.blend=function(){d.prototype.blend.apply(this,arguments)},d.Image.prototype.save=function(a,b){var c;if(b)switch(b.toLowerCase()){case"png":c="image/png";break;case"jpeg":c="image/jpeg";break;case"jpg":c="image/jpeg";break;default:c="image/png"}else b="png",c="image/png";var e="image/octet-stream",f=this.canvas.toDataURL(c);f=f.replace(c,e),d.prototype.downloadFile(f,a,b)},b.exports=d.Image},{"../core/core":49,"./filters":66}],70:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("./filters");a("../color/p5.Color"),d.prototype.pixels=[],d.prototype.blend=function(){this._graphics.blend.apply(this._graphics,arguments)},d.prototype.copy=function(){d.Renderer2D._copyHelper.apply(this,arguments)},d.prototype.filter=function(a,b){e.apply(this.canvas,e[a.toLowerCase()],b)},d.prototype.get=function(a,b,c,d){return this._graphics.get(a,b,c,d)},d.prototype.loadPixels=function(){this._graphics.loadPixels()},d.prototype.set=function(a,b,c){this._graphics.set(a,b,c)},d.prototype.updatePixels=function(a,b,c,d){this._graphics.updatePixels(a,b,c,d)},b.exports=d},{"../color/p5.Color":43,"../core/core":49,"./filters":66}],71:[function(a,b,c){"use strict";function d(a,b){var c={};if(b=b||[],"undefined"==typeof b)for(var d=0;d<a.length;d++)b[d.toString()]=d;for(var e=0;e<b.length;e++){var f=b[e],g=a[e];c[f]=g}return c}function e(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function f(a,b){b&&b!==!0&&"true"!==b||(b=""),a||(a="untitled");var c="";return a&&a.indexOf(".")>-1&&(c=a.split(".").pop()),b&&c!==b&&(c=b,a=a+"."+c),[a,c]}function g(a){document.body.removeChild(a.target)}var h=a("../core/core"),i=a("reqwest"),j=a("opentype.js");a("../core/error_helpers"),h.prototype.loadFont=function(a,b,c){var d=new h.Font(this);return j.load(a,function(a,e){if(a){if("undefined"!=typeof c)return c(a);throw a}d.font=e,"undefined"!=typeof b&&b(d)}),d},h.prototype.createInput=function(){throw"not yet implemented"},h.prototype.createReader=function(){throw"not yet implemented"},h.prototype.loadBytes=function(){throw"not yet implemented"},h.prototype.loadJSON=function(){var a=arguments[0],b=arguments[1],c=[],d="json";return"string"==typeof arguments[2]&&("jsonp"===arguments[2]||"json"===arguments[2])&&(d=arguments[2]),i({url:a,type:d,crossOrigin:!0}).then(function(a){for(var d in a)c[d]=a[d];"undefined"!=typeof b&&b(a)}),c},h.prototype.loadStrings=function(a,b){var c=[],d=new XMLHttpRequest;return d.open("GET",a,!0),d.onreadystatechange=function(){if(4===d.readyState&&200===d.status){var e=d.responseText.match(/[^\r\n]+/g);for(var f in e)c[f]=e[f];"undefined"!=typeof b&&b(c)}else h._friendlyFileLoadError(3,a)},d.send(null),c},h.prototype.loadTable=function(a){for(var b=null,c=[],e=!1,f=",",g=!1,j=1;j<arguments.length;j++)if("function"==typeof arguments[j])b=arguments[j];else if("string"==typeof arguments[j])if(c.push(arguments[j]),"header"===arguments[j]&&(e=!0),"csv"===arguments[j]){if(g)throw new Error("Cannot set multiple separator types.");f=",",g=!0}else if("tsv"===arguments[j]){if(g)throw new Error("Cannot set multiple separator types.");f=" ",g=!0}var k=new h.Table;return i({url:a,crossOrigin:!0,type:"csv"}).then(function(a){a=a.responseText;for(var c,g={},i=0,l=1,m=2,n=4,o='"',p="\r",q="\n",r=[],s=0,t=null,u=function(){g.escaped=!1,t=[],w()},v=function(){g.currentState=n,r.push(t),t=null},w=function(){g.currentState=i,g.token=""},x=function(){t.push(g.token),w()};;){if(c=a[s++],null==c){if(g.escaped)throw new Error("Unclosed quote in file.");if(t){x(),v();break}}if(null===t&&u(),g.currentState===i){if(c===o){g.escaped=!0,g.currentState=l;continue}g.currentState=l}g.currentState===l&&g.escaped?c===o?a[s]===o?(g.token+=o,s++):(g.escaped=!1,g.currentState=m):g.token+=c:c===p?(a[s]===q&&s++,x(),v()):c===q?(x(),v()):c===f?x():g.currentState===l&&(g.token+=c)}if(e)k.columns=r.shift();else for(j=0;j<r.length;j++)k.columns[j]=j.toString();var y;for(j=0;j<r.length&&(j!==r.length-1||1!==r[j].length||"undefined"!==r[j][0]);j++)y=new h.TableRow,y.arr=r[j],y.obj=d(r[j],k.columns),k.addRow(y);null!==b&&b(k)}).fail(function(c,d){h._friendlyFileLoadError(2,a),"undefined"!=typeof b&&b(!1)}),k},h.prototype.loadXML=function(a,b){var c=document.implementation.createDocument(null,null);return i({url:a,type:"xml",crossOrigin:!0,error:function(b){h._friendlyFileLoadError(1,a)}}).then(function(a){var d=a.documentElement;c.appendChild(d),"undefined"!=typeof b&&b(a)}),c},h.prototype.parseXML=function(){throw"not yet implemented"},h.prototype.selectFolder=function(){throw"not yet implemented"},h.prototype.selectInput=function(){throw"not yet implemented"},h.prototype.httpGet=function(){var a=Array.prototype.slice.call(arguments);a.push("GET"),h.prototype.httpDo.apply(this,a)},h.prototype.httpPost=function(){var a=Array.prototype.slice.call(arguments);a.push("POST"),h.prototype.httpDo.apply(this,a)},h.prototype.httpDo=function(){for(var a,b="GET",c=arguments[0],d={},e="",f=1;f<arguments.length;f++){var g=arguments[f];"string"==typeof g?"GET"===g||"POST"===g||"PUT"===g?b=g:e=g:"object"==typeof g?d=g:"function"==typeof g&&(a=g)}""===e&&(e=-1!==c.indexOf("json")?"json":-1!==c.indexOf("xml")?"xml":"text"),i({url:c,method:b,data:d,type:e,crossOrigin:!0,success:function(b){"undefined"!=typeof a&&a("text"===e?b.response:b)}})},window.URL=window.URL||window.webkitURL,h.prototype._pWriters=[],h.prototype.beginRaw=function(){throw"not yet implemented"},h.prototype.beginRecord=function(){throw"not yet implemented"},h.prototype.createOutput=function(){throw"not yet implemented"},h.prototype.createWriter=function(a,b){var c;for(var d in h.prototype._pWriters)if(h.prototype._pWriters[d].name===a)return c=new h.PrintWriter(a+window.millis(),b),h.prototype._pWriters.push(c),c;return c=new h.PrintWriter(a,b),h.prototype._pWriters.push(c),c},h.prototype.endRaw=function(){throw"not yet implemented"},h.prototype.endRecord=function(){throw"not yet implemented"},h.PrintWriter=function(a,b){var c=this;this.name=a,this.content="",this.print=function(a){this.content+=a},this.println=function(a){this.content+=a+"\n"},this.flush=function(){this.content=""},this.close=function(){var d=[];d.push(this.content),h.prototype.writeFile(d,a,b);for(var e in h.prototype._pWriters)h.prototype._pWriters[e].name===this.name&&h.prototype._pWriters.splice(e,1);c.flush(),c={}}},h.prototype.saveBytes=function(){throw"not yet implemented"},h.prototype.save=function(a,b,c){var d=arguments,e=this._curElement.elt;if(0===d.length)return void h.prototype.saveCanvas(e);if(d[0]instanceof h.Renderer||d[0]instanceof h.Graphics)return void h.prototype.saveCanvas(d[0].elt,d[1],d[2]);if(1===d.length&&"string"==typeof d[0])h.prototype.saveCanvas(e,d[0]);else{var g=f(d[1],d[2])[1];switch(g){case"json":return void h.prototype.saveJSON(d[0],d[1],d[2]);case"txt":return void h.prototype.saveStrings(d[0],d[1],d[2]);default:d[0]instanceof Array?h.prototype.saveStrings(d[0],d[1],d[2]):d[0]instanceof h.Table?h.prototype.saveTable(d[0],d[1],d[2],d[3]):d[0]instanceof h.Image?h.prototype.saveCanvas(d[0].canvas,d[1]):d[0]instanceof h.SoundFile&&h.prototype.saveSound(d[0],d[1],d[2],d[3])}}},h.prototype.saveJSON=function(a,b,c){var d;d=c?JSON.stringify(a):JSON.stringify(a,void 0,2),console.log(d),this.saveStrings(d.split("\n"),b,"json")},h.prototype.saveJSONObject=h.prototype.saveJSON,h.prototype.saveJSONArray=h.prototype.saveJSON,h.prototype.saveStream=function(){throw"not yet implemented"},h.prototype.saveStrings=function(a,b,c){var d=c||"txt",e=this.createWriter(b,d);for(var f in a)f<a.length-1?e.println(a[f]):e.print(a[f]);e.close(),e.flush()},h.prototype.saveXML=function(){throw"not yet implemented"},h.prototype.selectOutput=function(){throw"not yet implemented"},h.prototype.saveTable=function(a,b,c){var d=this.createWriter(b,c),f=a.columns,g=",";if("tsv"===c&&(g=" "),"html"!==c){if("0"!==f[0])for(var h=0;h<f.length;h++)h<f.length-1?d.print(f[h]+g):d.println(f[h]);for(var i=0;i<a.rows.length;i++){var j;for(j=0;j<a.rows[i].arr.length;j++)j<a.rows[i].arr.length-1?d.print(a.rows[i].arr[j]+g):i<a.rows.length-1?d.println(a.rows[i].arr[j]):d.print(a.rows[i].arr[j])}}else{d.println("<html>"),d.println("<head>");var k=' <meta http-equiv="content-type" content';if(k+='="text/html;charset=utf-8" />',d.println(k),d.println("</head>"),d.println("<body>"),d.println(" <table>"),"0"!==f[0]){d.println(" <tr>");for(var l=0;l<f.length;l++){var m=e(f[l]);d.println(" <td>"+m),d.println(" </td>")}d.println(" </tr>")}for(var n=0;n<a.rows.length;n++){d.println(" <tr>");for(var o=0;o<a.columns.length;o++){var p=a.rows[n].getString(o),q=e(p);d.println(" <td>"+q),d.println(" </td>")}d.println(" </tr>")}d.println(" </table>"),d.println("</body>"),d.print("</html>")}d.close(),d.flush()},h.prototype.writeFile=function(a,b,c){var d="application/octet-stream";h.prototype._isSafari()&&(d="text/plain");var e=new Blob(a,{type:d}),f=window.URL.createObjectURL(e);h.prototype.downloadFile(f,b,c)},h.prototype.downloadFile=function(a,b,c){var d=f(b,c),e=d[0],i=d[1],j=document.createElement("a");if(j.href=a,j.download=e,j.onclick=g,j.style.display="none",document.body.appendChild(j),h.prototype._isSafari()){var k="Hello, Safari user! To download this file...\n";k+="1. Go to File --> Save As.\n",k+='2. Choose "Page Source" as the Format.\n',k+='3. Name it with this extension: ."'+i+'"',alert(k)}j.click(),a=null},h.prototype._checkFileExtension=f,h.prototype._isSafari=function(){var a=Object.prototype.toString.call(window.HTMLElement);return a.indexOf("Constructor")>0},b.exports=h},{"../core/core":49,"../core/error_helpers":52,"opentype.js":8,reqwest:29}],72:[function(a,b,c){"use strict";var d=a("../core/core");d.Table=function(a){this.columns=[],this.rows=[]},d.Table.prototype.addRow=function(a){var b=a||new d.TableRow;if("undefined"==typeof b.arr||"undefined"==typeof b.obj)throw"invalid TableRow: "+b;return b.table=this,this.rows.push(b),b},d.Table.prototype.removeRow=function(a){this.rows[a].table=null;var b=this.rows.splice(a+1,this.rows.length);this.rows.pop(),this.rows=this.rows.concat(b)},d.Table.prototype.getRow=function(a){return this.rows[a]},d.Table.prototype.getRows=function(){return this.rows},d.Table.prototype.findRow=function(a,b){if("string"==typeof b){for(var c=0;c<this.rows.length;c++)if(this.rows[c].obj[b]===a)return this.rows[c]}else for(var d=0;d<this.rows.length;d++)if(this.rows[d].arr[b]===a)return this.rows[d];return null},d.Table.prototype.findRows=function(a,b){var c=[];if("string"==typeof b)for(var d=0;d<this.rows.length;d++)this.rows[d].obj[b]===a&&c.push(this.rows[d]);else for(var e=0;e<this.rows.length;e++)this.rows[e].arr[b]===a&&c.push(this.rows[e]);return c},d.Table.prototype.matchRow=function(a,b){if("number"==typeof b){for(var c=0;c<this.rows.length;c++)if(this.rows[c].arr[b].match(a))return this.rows[c]}else for(var d=0;d<this.rows.length;d++)if(this.rows[d].obj[b].match(a))return this.rows[d];return null},d.Table.prototype.matchRows=function(a,b){var c=[];if("number"==typeof b)for(var d=0;d<this.rows.length;d++)this.rows[d].arr[b].match(a)&&c.push(this.rows[d]);else for(var e=0;e<this.rows.length;e++)this.rows[e].obj[b].match(a)&&c.push(this.rows[e]);return c},d.Table.prototype.getColumn=function(a){var b=[];if("string"==typeof a)for(var c=0;c<this.rows.length;c++)b.push(this.rows[c].obj[a]);else for(var d=0;d<this.rows.length;d++)b.push(this.rows[d].arr[a]);return b},d.Table.prototype.clearRows=function(){delete this.rows,this.rows=[]},d.Table.prototype.addColumn=function(a){var b=a||null;this.columns.push(b)},d.Table.prototype.getColumnCount=function(){return this.columns.length},d.Table.prototype.getRowCount=function(){return this.rows.length},d.Table.prototype.removeTokens=function(a,b){for(var c=function(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")},d=[],e=0;e<a.length;e++)d.push(c(a.charAt(e)));var f=new RegExp(d.join("|"),"g");if("undefined"==typeof b)for(var g=0;g<this.columns.length;g++)for(var h=0;h<this.rows.length;h++){var i=this.rows[h].arr[g];i=i.replace(f,""),this.rows[h].arr[g]=i,this.rows[h].obj[this.columns[g]]=i}else if("string"==typeof b)for(var j=0;j<this.rows.length;j++){var k=this.rows[j].obj[b];k=k.replace(f,""),this.rows[j].obj[b]=k;var l=this.columns.indexOf(b);this.rows[j].arr[l]=k}else for(var m=0;m<this.rows.length;m++){var n=this.rows[m].arr[b];n=n.replace(f,""),this.rows[m].arr[b]=n,this.rows[m].obj[this.columns[b]]=n}},d.Table.prototype.trim=function(a){var b=new RegExp(" ","g");if("undefined"==typeof a)for(var c=0;c<this.columns.length;c++)for(var d=0;d<this.rows.length;d++){var e=this.rows[d].arr[c];e=e.replace(b,""),this.rows[d].arr[c]=e,this.rows[d].obj[this.columns[c]]=e}else if("string"==typeof a)for(var f=0;f<this.rows.length;f++){var g=this.rows[f].obj[a];g=g.replace(b,""),this.rows[f].obj[a]=g;var h=this.columns.indexOf(a);this.rows[f].arr[h]=g}else for(var i=0;i<this.rows.length;i++){var j=this.rows[i].arr[a];j=j.replace(b,""),this.rows[i].arr[a]=j,this.rows[i].obj[this.columns[a]]=j}},d.Table.prototype.removeColumn=function(a){var b,c;"string"==typeof a?(b=a,c=this.columns.indexOf(a),console.log("string")):(c=a,b=this.columns[a]);var d=this.columns.splice(c+1,this.columns.length);this.columns.pop(),this.columns=this.columns.concat(d);for(var e=0;e<this.rows.length;e++){var f=this.rows[e].arr,g=f.splice(c+1,f.length);f.pop(),this.rows[e].arr=f.concat(g),delete this.rows[e].obj[b]}},d.Table.prototype.set=function(a,b,c){this.rows[a].set(b,c)},d.Table.prototype.setNum=function(a,b,c){this.rows[a].set(b,c);
},d.Table.prototype.setString=function(a,b,c){this.rows[a].set(b,c)},d.Table.prototype.get=function(a,b){return this.rows[a].get(b)},d.Table.prototype.getNum=function(a,b){return this.rows[a].getNum(b)},d.Table.prototype.getString=function(a,b){return this.rows[a].getString(b)},d.Table.prototype.getObject=function(a){for(var b,c,d,e={},f=0;f<this.rows.length;f++)if(b=this.rows[f].obj,"string"==typeof a){if(c=this.columns.indexOf(a),!(c>=0))throw'This table has no column named "'+a+'"';d=b[a],e[d]=b}else e[f]=this.rows[f].obj;return e},d.Table.prototype.getArray=function(){for(var a=[],b=0;b<this.rows.length;b++)a.push(this.rows[b].arr);return a},b.exports=d.Table},{"../core/core":49}],73:[function(a,b,c){"use strict";var d=a("../core/core");d.TableRow=function(a,b){var c=[],d={};a&&(b=b||",",c=a.split(b));for(var e=0;e<c.length;e++){var f=e,g=c[e];d[f]=g}this.arr=c,this.obj=d,this.table=null},d.TableRow.prototype.set=function(a,b){if("string"==typeof a){var c=this.table.columns.indexOf(a);if(!(c>=0))throw'This table has no column named "'+a+'"';this.obj[a]=b,this.arr[c]=b}else{if(!(a<this.table.columns.length))throw"Column #"+a+" is out of the range of this table";this.arr[a]=b;var d=this.table.columns[a];this.obj[d]=b}},d.TableRow.prototype.setNum=function(a,b){var c=parseFloat(b,10);this.set(a,c)},d.TableRow.prototype.setString=function(a,b){var c=b.toString();this.set(a,c)},d.TableRow.prototype.get=function(a){return"string"==typeof a?this.obj[a]:this.arr[a]},d.TableRow.prototype.getNum=function(a){var b;if(b="string"==typeof a?parseFloat(this.obj[a],10):parseFloat(this.arr[a],10),"NaN"===b.toString())throw"Error: "+this.obj[a]+" is NaN (Not a Number)";return b},d.TableRow.prototype.getString=function(a){return"string"==typeof a?this.obj[a].toString():this.arr[a].toString()},b.exports=d.TableRow},{"../core/core":49}],74:[function(a,b,c){"use strict";var d=a("../core/core");d.prototype.abs=Math.abs,d.prototype.ceil=Math.ceil,d.prototype.constrain=function(a,b,c){return Math.max(Math.min(a,c),b)},d.prototype.dist=function(a,b,c,d){return Math.sqrt((c-a)*(c-a)+(d-b)*(d-b))},d.prototype.exp=Math.exp,d.prototype.floor=Math.floor,d.prototype.lerp=function(a,b,c){return c*(b-a)+a},d.prototype.log=Math.log,d.prototype.mag=function(a,b){return Math.sqrt(a*a+b*b)},d.prototype.map=function(a,b,c,d,e){return(a-b)/(c-b)*(e-d)+d},d.prototype.max=function(){return arguments[0]instanceof Array?Math.max.apply(null,arguments[0]):Math.max.apply(null,arguments)},d.prototype.min=function(){return arguments[0]instanceof Array?Math.min.apply(null,arguments[0]):Math.min.apply(null,arguments)},d.prototype.norm=function(a,b,c){return this.map(a,b,c,0,1)},d.prototype.pow=Math.pow,d.prototype.round=Math.round,d.prototype.sq=function(a){return a*a},d.prototype.sqrt=Math.sqrt,b.exports=d},{"../core/core":49}],75:[function(a,b,c){"use strict";var d=a("../core/core");d.prototype.createVector=function(a,b,c){return this instanceof d?new d.Vector(this,arguments):new d.Vector(a,b,c)},b.exports=d},{"../core/core":49}],76:[function(a,b,c){"use strict";var d,e=a("../core/core"),f=4,g=1<<f,h=8,i=1<<h,j=4095,k=4,l=.5,m=function(a){return.5*(1-Math.cos(a*Math.PI))};e.prototype.noise=function(a,b,c){if(b=b||0,c=c||0,null==d){d=new Array(j+1);for(var e=0;j+1>e;e++)d[e]=Math.random()}0>a&&(a=-a),0>b&&(b=-b),0>c&&(c=-c);for(var n,o,p,q,r,s=Math.floor(a),t=Math.floor(b),u=Math.floor(c),v=a-s,w=b-t,x=c-u,y=0,z=.5,A=0;k>A;A++){var B=s+(t<<f)+(u<<h);n=m(v),o=m(w),p=d[B&j],p+=n*(d[B+1&j]-p),q=d[B+g&j],q+=n*(d[B+g+1&j]-q),p+=o*(q-p),B+=i,q=d[B&j],q+=n*(d[B+1&j]-q),r=d[B+g&j],r+=n*(d[B+g+1&j]-r),q+=o*(r-q),p+=m(x)*(q-p),y+=p*z,z*=l,s<<=1,v*=2,t<<=1,w*=2,u<<=1,x*=2,v>=1&&(s++,v--),w>=1&&(t++,w--),x>=1&&(u++,x--)}return y},e.prototype.noiseDetail=function(a,b){a>0&&(k=a),b>0&&(l=b)},e.prototype.noiseSeed=function(a){var b=function(){var a,b,c=4294967296,d=1664525,e=1013904223;return{setSeed:function(d){b=a=(null==d?Math.random()*c:d)>>>0},getSeed:function(){return a},rand:function(){return b=(d*b+e)%c,b/c}}}();b.setSeed(a),d=new Array(j+1);for(var c=0;j+1>c;c++)d[c]=b.rand()},b.exports=e},{"../core/core":49}],77:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("./polargeometry"),f=a("../core/constants");d.Vector=function(){var a,b,c;arguments[0]instanceof d?(this.p5=arguments[0],a=arguments[1][0]||0,b=arguments[1][1]||0,c=arguments[1][2]||0):(a=arguments[0]||0,b=arguments[1]||0,c=arguments[2]||0),this.x=a,this.y=b,this.z=c},d.Vector.prototype.toString=function(){return"p5.Vector Object : ["+this.x+", "+this.y+", "+this.z+"]"},d.Vector.prototype.set=function(a,b,c){return a instanceof d.Vector?(this.x=a.x||0,this.y=a.y||0,this.z=a.z||0,this):a instanceof Array?(this.x=a[0]||0,this.y=a[1]||0,this.z=a[2]||0,this):(this.x=a||0,this.y=b||0,this.z=c||0,this)},d.Vector.prototype.copy=function(){return this.p5?new d.Vector(this.p5,[this.x,this.y,this.z]):new d.Vector(this.x,this.y,this.z)},d.Vector.prototype.add=function(a,b,c){return a instanceof d.Vector?(this.x+=a.x||0,this.y+=a.y||0,this.z+=a.z||0,this):a instanceof Array?(this.x+=a[0]||0,this.y+=a[1]||0,this.z+=a[2]||0,this):(this.x+=a||0,this.y+=b||0,this.z+=c||0,this)},d.Vector.prototype.sub=function(a,b,c){return a instanceof d.Vector?(this.x-=a.x||0,this.y-=a.y||0,this.z-=a.z||0,this):a instanceof Array?(this.x-=a[0]||0,this.y-=a[1]||0,this.z-=a[2]||0,this):(this.x-=a||0,this.y-=b||0,this.z-=c||0,this)},d.Vector.prototype.mult=function(a){return this.x*=a||0,this.y*=a||0,this.z*=a||0,this},d.Vector.prototype.div=function(a){return this.x/=a,this.y/=a,this.z/=a,this},d.Vector.prototype.mag=function(){return Math.sqrt(this.magSq())},d.Vector.prototype.magSq=function(){var a=this.x,b=this.y,c=this.z;return a*a+b*b+c*c},d.Vector.prototype.dot=function(a,b,c){return a instanceof d.Vector?this.dot(a.x,a.y,a.z):this.x*(a||0)+this.y*(b||0)+this.z*(c||0)},d.Vector.prototype.cross=function(a){var b=this.y*a.z-this.z*a.y,c=this.z*a.x-this.x*a.z,e=this.x*a.y-this.y*a.x;return this.p5?new d.Vector(this.p5,[b,c,e]):new d.Vector(b,c,e)},d.Vector.prototype.dist=function(a){var b=a.copy().sub(this);return b.mag()},d.Vector.prototype.normalize=function(){return this.div(this.mag())},d.Vector.prototype.limit=function(a){var b=this.magSq();return b>a*a&&(this.div(Math.sqrt(b)),this.mult(a)),this},d.Vector.prototype.setMag=function(a){return this.normalize().mult(a)},d.Vector.prototype.heading=function(){var a=Math.atan2(this.y,this.x);return this.p5?this.p5._angleMode===f.RADIANS?a:e.radiansToDegrees(a):a},d.Vector.prototype.rotate=function(a){this.p5&&this.p5._angleMode===f.DEGREES&&(a=e.degreesToRadians(a));var b=this.heading()+a,c=this.mag();return this.x=Math.cos(b)*c,this.y=Math.sin(b)*c,this},d.Vector.prototype.lerp=function(a,b,c,e){return a instanceof d.Vector?this.lerp(a.x,a.y,a.z,b):(this.x+=(a-this.x)*e||0,this.y+=(b-this.y)*e||0,this.z+=(c-this.z)*e||0,this)},d.Vector.prototype.array=function(){return[this.x||0,this.y||0,this.z||0]},d.Vector.prototype.equals=function(a,b,c){var e,f,g;return a instanceof d.Vector?(e=a.x||0,f=a.y||0,g=a.z||0):a instanceof Array?(e=a[0]||0,f=a[1]||0,g=a[2]||0):(e=a||0,f=b||0,g=c||0),this.x===e&&this.y===f&&this.z===g},d.Vector.fromAngle=function(a){return this.p5&&this.p5._angleMode===f.DEGREES&&(a=e.degreesToRadians(a)),this.p5?new d.Vector(this.p5,[Math.cos(a),Math.sin(a),0]):new d.Vector(Math.cos(a),Math.sin(a),0)},d.Vector.random2D=function(){var a;return a=this.p5?this.p5._angleMode===f.DEGREES?this.p5.random(360):this.p5.random(f.TWO_PI):Math.random()*Math.PI*2,this.fromAngle(a)},d.Vector.random3D=function(){var a,b;this.p5?(a=this.p5.random(0,f.TWO_PI),b=this.p5.random(-1,1)):(a=Math.random()*Math.PI*2,b=2*Math.random()-1);var c=Math.sqrt(1-b*b)*Math.cos(a),e=Math.sqrt(1-b*b)*Math.sin(a);return this.p5?new d.Vector(this.p5,[c,e,b]):new d.Vector(c,e,b)},d.Vector.add=function(a,b,c){return c?c.set(a):c=a.copy(),c.add(b),c},d.Vector.sub=function(a,b,c){return c?c.set(a):c=a.copy(),c.sub(b),c},d.Vector.mult=function(a,b,c){return c?c.set(a):c=a.copy(),c.mult(b),c},d.Vector.div=function(a,b,c){return c?c.set(a):c=a.copy(),c.div(b),c},d.Vector.dot=function(a,b){return a.dot(b)},d.Vector.cross=function(a,b){return a.cross(b)},d.Vector.dist=function(a,b){return a.dist(b)},d.Vector.lerp=function(a,b,c,d){return d?d.set(a):d=a.copy(),d.lerp(b,c),d},d.Vector.angleBetween=function(a,b){var c=Math.acos(a.dot(b)/(a.mag()*b.mag()));return this.p5&&this.p5._angleMode===f.DEGREES&&(c=e.radiansToDegrees(c)),c},b.exports=d.Vector},{"../core/constants":48,"../core/core":49,"./polargeometry":78}],78:[function(a,b,c){b.exports={degreesToRadians:function(a){return 2*Math.PI*a/360},radiansToDegrees:function(a){return 360*a/(2*Math.PI)}}},{}],79:[function(a,b,c){"use strict";var d=a("../core/core"),e=!1,f=function(){var a,b,c=4294967296,d=1664525,e=1013904223;return{setSeed:function(d){b=a=(null==d?Math.random()*c:d)>>>0},getSeed:function(){return a},rand:function(){return b=(d*b+e)%c,b/c}}}();d.prototype.randomSeed=function(a){f.setSeed(a),e=!0},d.prototype.random=function(a,b){var c;if(c=e?f.rand():Math.random(),0===arguments.length)return c;if(1===arguments.length)return c*a;if(a>b){var d=a;a=b,b=d}return c*(b-a)+a};var g,h=!1;d.prototype.randomGaussian=function(a,b){var c,d,e,f;if(h)c=g,h=!1;else{do d=this.random(2)-1,e=this.random(2)-1,f=d*d+e*e;while(f>=1);f=Math.sqrt(-2*Math.log(f)/f),c=d*f,g=e*f,h=!0}var i=a||0,j=b||1;return c*j+i},b.exports=d},{"../core/core":49}],80:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("./polargeometry"),f=a("../core/constants");d.prototype._angleMode=f.RADIANS,d.prototype.acos=function(a){return this._angleMode===f.RADIANS?Math.acos(a):e.radiansToDegrees(Math.acos(a))},d.prototype.asin=function(a){return this._angleMode===f.RADIANS?Math.asin(a):e.radiansToDegrees(Math.asin(a))},d.prototype.atan=function(a){return this._angleMode===f.RADIANS?Math.atan(a):e.radiansToDegrees(Math.atan(a))},d.prototype.atan2=function(a,b){return this._angleMode===f.RADIANS?Math.atan2(a,b):e.radiansToDegrees(Math.atan2(a,b))},d.prototype.cos=function(a){return this._angleMode===f.RADIANS?Math.cos(a):Math.cos(this.radians(a))},d.prototype.sin=function(a){return this._angleMode===f.RADIANS?Math.sin(a):Math.sin(this.radians(a))},d.prototype.tan=function(a){return this._angleMode===f.RADIANS?Math.tan(a):Math.tan(this.radians(a))},d.prototype.degrees=function(a){return e.radiansToDegrees(a)},d.prototype.radians=function(a){return e.degreesToRadians(a)},d.prototype.angleMode=function(a){(a===f.DEGREES||a===f.RADIANS)&&(this._angleMode=a)},b.exports=d},{"../core/constants":48,"../core/core":49,"./polargeometry":78}],81:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("../core/constants");d.prototype._textSize=12,d.prototype._textLeading=15,d.prototype._textFont="sans-serif",d.prototype._textStyle=e.NORMAL,d.prototype._textAscent=null,d.prototype._textDescent=null,d.prototype.textAlign=function(a,b){return this._graphics.textAlign(a,b)},d.prototype.textLeading=function(a){return arguments.length?(this._setProperty("_textLeading",a),this):this._textLeading},d.prototype.textSize=function(a){return arguments.length?(this._setProperty("_textSize",a),this._setProperty("_textLeading",a*e._DEFAULT_LEADMULT),this._graphics._applyTextProperties()):this._textSize},d.prototype.textStyle=function(a){return arguments.length?((a===e.NORMAL||a===e.ITALIC||a===e.BOLD)&&this._setProperty("_textStyle",a),this._graphics._applyTextProperties()):this._textStyle},d.prototype.textWidth=function(a){return this._graphics.textWidth(a)},d.prototype.textAscent=function(){return null===this._textAscent&&this._updateTextMetrics(),this._textAscent},d.prototype.textDescent=function(){return null===this._textDescent&&this._updateTextMetrics(),this._textDescent},d.prototype._isOpenType=function(a){return a=a||this._textFont,"object"==typeof a&&a.font&&a.font.supported},d.prototype._updateTextMetrics=function(){if(this._isOpenType())return this._setProperty("_textAscent",this._textFont._textAscent()),this._setProperty("_textDescent",this._textFont._textDescent()),this;var a=document.createElement("span");a.style.fontFamily=this._textFont,a.style.fontSize=this._textSize+"px",a.innerHTML="ABCjgq|";var b=document.createElement("div");b.style.display="inline-block",b.style.width="1px",b.style.height="0px";var c=document.createElement("div");c.appendChild(a),c.appendChild(b),c.style.height="0px",c.style.overflow="hidden",document.body.appendChild(c),b.style.verticalAlign="baseline";var d=this._calculateOffset(b),e=this._calculateOffset(a),f=d[1]-e[1];b.style.verticalAlign="bottom",d=this._calculateOffset(b),e=this._calculateOffset(a);var g=d[1]-e[1],h=g-f;return document.body.removeChild(c),this._setProperty("_textAscent",f),this._setProperty("_textDescent",h),this},d.prototype._calculateOffset=function(a){var b=0,c=0;if(a.offsetParent){do b+=a.offsetLeft,c+=a.offsetTop;while(a=a.offsetParent)}else b+=a.offsetLeft,c+=a.offsetTop;return[b,c]},b.exports=d},{"../core/constants":48,"../core/core":49}],82:[function(a,b,c){"use strict";var d=a("../core/core"),e=a("../core/constants");a("../core/error_helpers"),d.prototype.text=function(a,b,c,d,e){return this._validateParameters("text",arguments,[["*","Number","Number"],["*","Number","Number","Number","Number"]]),this._doFill||this._doStroke?this._graphics.text.apply(this._graphics,arguments):this},d.prototype.textFont=function(a,b){if(arguments.length){if(!a)throw Error("null font passed to textFont");return this._setProperty("_textFont",a),b&&(this._setProperty("_textSize",b),this._setProperty("_textLeading",b*e._DEFAULT_LEADMULT)),this._graphics._applyTextProperties()}return this},b.exports=d},{"../core/constants":48,"../core/core":49,"../core/error_helpers":52}],83:[function(a,b,c){"use strict";function d(){for(var a=Array.prototype.slice.call(arguments),b=a.length,c="";b--;)c+=a[b]===Object(a[b])?JSON.stringify(a[b]):a[b];return c}var e=a("../core/core"),f=a("../core/constants");e.Font=function(a){this.parent=a,this.cache={},this.font=void 0},e.Font.prototype.list=function(){throw"not yet implemented"},e.Font.prototype.textBounds=function(a,b,c,e,f){b=void 0!==b?b:0,c=void 0!==c?c:0,e=e||this.parent._textSize;var g=this.cache[d("textBounds",a,b,c,e)];if(!g){var h,i,j,k,l=[],m=[],n=this,o=this._scale(e);this.font.forEachGlyph(a,b,c,e,f,function(a,b,c,d){if(l.push(b),m.push(c),"space"!==a.name){var f=a.getMetrics();l.push(b+f.xMax*o),m.push(c+-f.yMin*o),m.push(c+-f.yMax*o)}else l.push(b+n.font.charToGlyph(" ").advanceWidth*n._scale(e))}),h=Math.max(0,Math.min.apply(null,l)),i=Math.max(0,Math.min.apply(null,m)),j=Math.max(0,Math.max.apply(null,l)),k=Math.max(0,Math.max.apply(null,m)),g={x:h,y:i,h:k-i,w:j-h,advance:h-b},this.cache[d("textBounds",a,b,c,e)]=g}return g},e.Font.prototype._getGlyphs=function(a){return this.font.stringToGlyphs(a)},e.Font.prototype._getPath=function(a,b,c,d){var e=this.parent,f=e._graphics.drawingContext,g=this._handleAlignment(e,f,a,b,c);return this.font.getPath(a,g.x,g.y,e._textSize,d)},e.Font.prototype._getPathData=function(a,b,c,d){var e=3;return"string"==typeof a&&arguments.length>2?a=this._getPath(a,b,c,d):"object"==typeof b&&(d=b),d&&"number"==typeof d.decimals&&(e=d.decimals),a.toPathData(e)},e.Font.prototype._getSVG=function(a,b,c,d){var e=3;return"string"==typeof a&&arguments.length>2?a=this._getPath(a,b,c,d):"object"==typeof b&&(d=b),d&&("number"==typeof d.decimals&&(e=d.decimals),"number"==typeof d.strokeWidth&&(a.strokeWidth=d.strokeWidth),"undefined"!=typeof d.fill&&(a.fill=d.fill),"undefined"!=typeof d.stroke&&(a.stroke=d.stroke)),a.toSVG(e)},e.Font.prototype._renderPath=function(a,b,c,d){var e,g=this.parent,h=g._graphics,i=h.drawingContext;e="object"==typeof a&&a.commands?a.commands:this._getPath(a,b,c,g._textSize,d).commands,i.beginPath();for(var j=0;j<e.length;j+=1){var k=e[j];"M"===k.type?i.moveTo(k.x,k.y):"L"===k.type?i.lineTo(k.x,k.y):"C"===k.type?i.bezierCurveTo(k.x1,k.y1,k.x2,k.y2,k.x,k.y):"Q"===k.type?i.quadraticCurveTo(k.x1,k.y1,k.x,k.y):"Z"===k.type&&i.closePath()}return g._doStroke&&g._strokeSet&&i.stroke(),g._doFill&&(i.fillStyle=g._fillSet?i.fillStyle:f._DEFAULT_TEXT_FILL,i.fill()),this},e.Font.prototype._textWidth=function(a,b){if(" "===a)return this.font.charToGlyph(" ").advanceWidth*this._scale(b);var c=this.textBounds(a,0,0,b);return c.w+c.advance},e.Font.prototype._textAscent=function(a){return this.font.ascender*this._scale(a)},e.Font.prototype._textDescent=function(a){return-this.font.descender*this._scale(a)},e.Font.prototype._scale=function(a){return 1/this.font.unitsPerEm*(a||this.parent._textSize)},e.Font.prototype._handleAlignment=function(a,b,c,d,e){var g=this._textWidth(c),h=this._textAscent(),i=this._textDescent(),j=h+i;return b.textAlign===f.CENTER?d-=g/2:b.textAlign===f.RIGHT&&(d-=g),b.textBaseline===f.TOP?e+=j:b.textBaseline===f._CTX_MIDDLE?e+=j/2-i:b.textBaseline===f.BOTTOM&&(e-=i),{x:d,y:e}},b.exports=e.Font},{"../core/constants":48,"../core/core":49}],84:[function(a,b,c){"use strict";var d=a("../core/core");d.prototype.append=function(a,b){return a.push(b),a},d.prototype.arrayCopy=function(a,b,c,d,e){var f,g;"undefined"!=typeof e?(g=Math.min(e,a.length),f=d,a=a.slice(b,g+b)):("undefined"!=typeof c?(g=c,g=Math.min(g,a.length)):g=a.length,f=0,c=b,a=a.slice(0,g)),Array.prototype.splice.apply(c,[f,g].concat(a))},d.prototype.concat=function(a,b){return a.concat(b)},d.prototype.reverse=function(a){return a.reverse()},d.prototype.shorten=function(a){return a.pop(),a},d.prototype.shuffle=function(a,b){a=b||ArrayBuffer.isView(a)?a:a.slice();for(var c,d,e=a.length;e>1;)c=Math.random()*e|0,d=a[--e],a[e]=a[c],a[c]=d;return a},d.prototype.sort=function(a,b){var c=b?a.slice(0,Math.min(b,a.length)):a,d=b?a.slice(Math.min(b,a.length)):[];return c="string"==typeof c[0]?c.sort():c.sort(function(a,b){return a-b}),c.concat(d)},d.prototype.splice=function(a,b,c){return Array.prototype.splice.apply(a,[c,0].concat(b)),a},d.prototype.subset=function(a,b,c){return"undefined"!=typeof c?a.slice(b,b+c):a.slice(b,a.length)},b.exports=d},{"../core/core":49}],85:[function(a,b,c){"use strict";var d=a("../core/core");d.prototype["float"]=function(a){return parseFloat(a)},d.prototype["int"]=function(a,b){return"string"==typeof a?(b=b||10,parseInt(a,b)):"number"==typeof a?0|a:"boolean"==typeof a?a?1:0:a instanceof Array?a.map(function(a){return d.prototype["int"](a,b)}):void 0},d.prototype.str=function(a){return a instanceof Array?a.map(d.prototype.str):String(a)},d.prototype["boolean"]=function(a){return"number"==typeof a?0!==a:"string"==typeof a?"true"===a.toLowerCase():"boolean"==typeof a?a:a instanceof Array?a.map(d.prototype["boolean"]):void 0},d.prototype["byte"]=function(a){var b=d.prototype["int"](a,10);return"number"==typeof b?(b+128)%256-128:b instanceof Array?b.map(d.prototype["byte"]):void 0},d.prototype["char"]=function(a){return"number"!=typeof a||isNaN(a)?a instanceof Array?a.map(d.prototype["char"]):"string"==typeof a?d.prototype["char"](parseInt(a,10)):void 0:String.fromCharCode(a)},d.prototype.unchar=function(a){return"string"==typeof a&&1===a.length?a.charCodeAt(0):a instanceof Array?a.map(d.prototype.unchar):void 0},d.prototype.hex=function(a,b){if(b=void 0===b||null===b?b=8:b,a instanceof Array)return a.map(function(a){return d.prototype.hex(a,b)});if("number"==typeof a){0>a&&(a=4294967295+a+1);for(var c=Number(a).toString(16).toUpperCase();c.length<b;)c="0"+c;return c.length>=b&&(c=c.substring(c.length-b,c.length)),c}},d.prototype.unhex=function(a){return a instanceof Array?a.map(d.prototype.unhex):parseInt("0x"+a,16)},b.exports=d},{"../core/core":49}],86:[function(a,b,c){"use strict";function d(){var a=arguments[0],b=0>a,c=b?a.toString().substring(1):a.toString(),d=c.indexOf("."),e=-1!==d?c.substring(0,d):c,f=-1!==d?c.substring(d+1):"",g=b?"-":"";if(3===arguments.length){var h="";(-1!==d||arguments[2]-f.length>0)&&(h="."),f.length>arguments[2]&&(f=f.substring(0,arguments[2]));for(var i=0;i<arguments[1]-e.length;i++)g+="0";g+=e,g+=h,g+=f;for(var j=0;j<arguments[2]-f.length;j++)g+="0";return g}for(var k=0;k<Math.max(arguments[1]-e.length,0);k++)g+="0";return g+=c}function e(){var a=arguments[0].toString(),b=a.indexOf("."),c=-1!==b?a.substring(b):"",d=-1!==b?a.substring(0,b):a;if(d=d.toString().replace(/\B(?=(\d{3})+(?!\d))/g,","),0===arguments[1])c="";else if(void 0!==arguments[1])if(arguments[1]>c.length){c+=-1===b?".":"";for(var e=arguments[1]-c.length+1,f=0;e>f;f++)c+="0"}else c=c.substring(0,arguments[1]+1);return d+c}function f(){return parseFloat(arguments[0])>0?"+"+arguments[0].toString():arguments[0].toString()}function g(){return parseFloat(arguments[0])>0?" "+arguments[0].toString():arguments[0].toString()}var h=a("../core/core");h.prototype.join=function(a,b){return a.join(b)},h.prototype.match=function(a,b){return a.match(b)},h.prototype.matchAll=function(a,b){for(var c=new RegExp(b,"g"),d=c.exec(a),e=[];null!==d;)e.push(d),d=c.exec(a);return e},h.prototype.nf=function(){if(arguments[0]instanceof Array){var a=arguments[1],b=arguments[2];return arguments[0].map(function(c){return d(c,a,b)})}var c=Object.prototype.toString.call(arguments[0]);return"[object Arguments]"===c?3===arguments[0].length?this.nf(arguments[0][0],arguments[0][1],arguments[0][2]):2===arguments[0].length?this.nf(arguments[0][0],arguments[0][1]):this.nf(arguments[0][0]):d.apply(this,arguments)},h.prototype.nfc=function(){if(arguments[0]instanceof Array){var a=arguments[1];return arguments[0].map(function(b){return e(b,a)})}return e.apply(this,arguments)},h.prototype.nfp=function(){var a=this.nf.apply(this,arguments);return a instanceof Array?a.map(f):f(a)},h.prototype.nfs=function(){var a=this.nf.apply(this,arguments);return a instanceof Array?a.map(g):g(a)},h.prototype.split=function(a,b){return a.split(b)},h.prototype.splitTokens=function(){var a=arguments.length>0?arguments[1]:/\s/g;return arguments[0].split(a).filter(function(a){return a})},h.prototype.trim=function(a){return a instanceof Array?a.map(this.trim):a.trim()},b.exports=h},{"../core/core":49}],87:[function(a,b,c){"use strict";var d=a("../core/core");d.prototype.day=function(){return(new Date).getDate()},d.prototype.hour=function(){return(new Date).getHours()},d.prototype.minute=function(){return(new Date).getMinutes()},d.prototype.millis=function(){return window.performance.now()},d.prototype.month=function(){return(new Date).getMonth()+1},d.prototype.second=function(){return(new Date).getSeconds()},d.prototype.year=function(){return(new Date).getFullYear()},b.exports=d},{"../core/core":49}]},{},[40])(40)});p5.prototype._validateParameters = function() {};p5.prototype._friendlyFileLoadError = function() {};
/*! p5.sound.min.js v0.2.13 2015-07-17 */
!function(t,e){"function"==typeof define&&define.amd?define("p5.sound",["p5"],function(t){e(t)}):e("object"==typeof exports?require("../p5"):t.p5)}(this,function(t){var e;e=function(){"use strict";window.AudioContext=window.AudioContext||window.webkitAudioContext;var e=new window.AudioContext;t.prototype.getAudioContext=function(){return e},"function"!=typeof e.createGain&&(window.audioContext.createGain=window.audioContext.createGainNode),"function"!=typeof e.createDelay&&(window.audioContext.createDelay=window.audioContext.createDelayNode),"function"!=typeof window.AudioBufferSourceNode.prototype.start&&(window.AudioBufferSourceNode.prototype.start=window.AudioBufferSourceNode.prototype.noteGrainOn),"function"!=typeof window.AudioBufferSourceNode.prototype.stop&&(window.AudioBufferSourceNode.prototype.stop=window.AudioBufferSourceNode.prototype.noteOff),"function"!=typeof window.OscillatorNode.prototype.start&&(window.OscillatorNode.prototype.start=window.OscillatorNode.prototype.noteOn),"function"!=typeof window.OscillatorNode.prototype.stop&&(window.OscillatorNode.prototype.stop=window.OscillatorNode.prototype.noteOff),window.AudioContext.prototype.hasOwnProperty("createScriptProcessor")||(window.AudioContext.prototype.createScriptProcessor=window.AudioContext.prototype.createJavaScriptNode),navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia;var i=document.createElement("audio");t.prototype.isSupported=function(){return!!i.canPlayType};var o=function(){return!!i.canPlayType&&i.canPlayType('audio/ogg; codecs="vorbis"')},n=function(){return!!i.canPlayType&&i.canPlayType("audio/mpeg;")},s=function(){return!!i.canPlayType&&i.canPlayType('audio/wav; codecs="1"')},r=function(){return!!i.canPlayType&&(i.canPlayType("audio/x-m4a;")||i.canPlayType("audio/aac;"))},a=function(){return!!i.canPlayType&&i.canPlayType("audio/x-aiff;")};t.prototype.isFileSupported=function(t){switch(t.toLowerCase()){case"mp3":return n();case"wav":return s();case"ogg":return o();case"mp4":return r();case"aiff":return a();default:return!1}};var u=navigator.userAgent.match(/(iPad|iPhone|iPod)/g)?!0:!1;u&&window.addEventListener("touchstart",function(){var t=e.createBuffer(1,1,22050),i=e.createBufferSource();i.buffer=t,i.connect(e.destination),i.start(0)},!1)}();var i;i=function(){"use strict";var e=function(){var e=t.prototype.getAudioContext();this.input=e.createGain(),this.output=e.createGain(),this.limiter=e.createDynamicsCompressor(),this.limiter.threshold.value=0,this.limiter.ratio.value=100,this.audiocontext=e,this.output.disconnect(),this.inputSources=[],this.input.connect(this.limiter),this.limiter.connect(this.output),this.meter=e.createGain(),this.fftMeter=e.createGain(),this.output.connect(this.meter),this.output.connect(this.fftMeter),this.output.connect(this.audiocontext.destination),this.soundArray=[],this.parts=[],this.extensions=[]},i=new e;return t.prototype.getMasterVolume=function(){return i.output.gain.value},t.prototype.masterVolume=function(t,e,o){if("number"==typeof t){var e=e||0,o=o||0,n=i.audiocontext.currentTime,s=i.output.gain.value;i.output.gain.cancelScheduledValues(n+o),i.output.gain.linearRampToValueAtTime(s,n+o),i.output.gain.linearRampToValueAtTime(t,n+o+e)}else{if(!t)return i.output.gain;t.connect(i.output.gain)}},t.soundOut=i,t.soundOut._silentNode=i.audiocontext.createGain(),t.soundOut._silentNode.gain.value=0,t.soundOut._silentNode.connect(i.audiocontext.destination),i}(e);var o;o=function(){"use strict";var e=i;t.prototype.sampleRate=function(){return e.audiocontext.sampleRate},t.prototype.freqToMidi=function(t){var e=Math.log(t/440)/Math.log(2),i=Math.round(12*e)+57;return i},t.prototype.midiToFreq=function(t){return 440*Math.pow(2,(t-69)/12)},t.prototype.soundFormats=function(){e.extensions=[];for(var t=0;t<arguments.length;t++){if(arguments[t]=arguments[t].toLowerCase(),!(["mp3","wav","ogg","m4a","aac"].indexOf(arguments[t])>-1))throw arguments[t]+" is not a valid sound format!";e.extensions.push(arguments[t])}},t.prototype.disposeSound=function(){for(var t=0;t<e.soundArray.length;t++)e.soundArray[t].dispose()},t.prototype.registerMethod("remove",t.prototype.disposeSound),t.prototype._checkFileFormats=function(i){var o;if("string"==typeof i){o=i;var n=o.split(".").pop();if(["mp3","wav","ogg","m4a","aac"].indexOf(n)>-1){var s=t.prototype.isFileSupported(n);if(s)o=o;else for(var r=o.split("."),a=r[r.length-1],u=0;u<e.extensions.length;u++){var c=e.extensions[u],s=t.prototype.isFileSupported(c);if(s){a="",2===r.length&&(a+=r[0]);for(var u=1;u<=r.length-2;u++){var h=r[u];a+="."+h}o=a+=".",o=o+=c;break}}}else for(var u=0;u<e.extensions.length;u++){var c=e.extensions[u],s=t.prototype.isFileSupported(c);if(s){o=o+"."+c;break}}}else if("object"==typeof i)for(var u=0;u<i.length;u++){var c=i[u].split(".").pop(),s=t.prototype.isFileSupported(c);if(s){o=i[u];break}}return o},t.prototype._mathChain=function(t,e,i,o,n){for(var s in t.mathOps)t.mathOps[s]instanceof n&&(t.mathOps[s].dispose(),i=s,i<t.mathOps.length-1&&(o=t.mathOps[s+1]));return t.mathOps[i-1].disconnect(),t.mathOps[i-1].connect(e),e.connect(o),t.mathOps[i]=e,t}}(i);var n;n=function(){"use strict";var e=i,o=e.audiocontext;"undefined"!=typeof o.createStereoPanner?(t.Panner=function(t,e){this.stereoPanner=this.input=o.createStereoPanner(),t.connect(this.stereoPanner),this.stereoPanner.connect(e)},t.Panner.prototype.pan=function(t,e){var i=e||0,n=o.currentTime+i;this.stereoPanner.pan.linearRampToValueAtTime(t,n)},t.Panner.prototype.inputChannels=function(){},t.Panner.prototype.connect=function(t){this.stereoPanner.connect(t)},t.Panner.prototype.disconnect=function(){this.stereoPanner.disconnect()}):(t.Panner=function(t,e,i){this.input=o.createGain(),t.connect(this.input),this.left=o.createGain(),this.right=o.createGain(),this.left.channelInterpretation="discrete",this.right.channelInterpretation="discrete",i>1?(this.splitter=o.createChannelSplitter(2),this.input.connect(this.splitter),this.splitter.connect(this.left,1),this.splitter.connect(this.right,0)):(this.input.connect(this.left),this.input.connect(this.right)),this.output=o.createChannelMerger(2),this.left.connect(this.output,0,1),this.right.connect(this.output,0,0),this.output.connect(e)},t.Panner.prototype.pan=function(t,e){var i=e||0,n=o.currentTime+i,s=(t+1)/2,r=Math.cos(s*Math.PI/2),a=Math.sin(s*Math.PI/2);this.left.gain.linearRampToValueAtTime(a,n),this.right.gain.linearRampToValueAtTime(r,n)},t.Panner.prototype.inputChannels=function(t){1===t?(this.input.disconnect(),this.input.connect(this.left),this.input.connect(this.right)):2===t&&(this.splitter=o.createChannelSplitter(2),this.input.disconnect(),this.input.connect(this.splitter),this.splitter.connect(this.left,1),this.splitter.connect(this.right,0))},t.Panner.prototype.connect=function(t){this.output.connect(t)},t.Panner.prototype.disconnect=function(){this.output.disconnect()}),t.Panner3D=function(t,e){var i=o.createPanner();return i.panningModel="HRTF",i.distanceModel="linear",i.setPosition(0,0,0),t.connect(i),i.connect(e),i.pan=function(t,e,o){i.setPosition(t,e,o)},i}}(i);var s;s=function(){"use strict";function e(t,e){for(var i={},o=t.length,n=0;o>n;n++){if(t[n]>e){var s=t[n],r=new h(s,n);i[n]=r,n+=6e3}n++}return i}function o(t){for(var e=[],i=Object.keys(t).sort(),o=0;o<i.length;o++)for(var n=0;10>n;n++){var s=t[i[o]],r=t[i[o+n]];if(s&&r){var a=s.sampleIndex,u=r.sampleIndex,c=u-a;c>0&&s.intervals.push(c);var h=e.some(function(t){return t.interval===c?(t.count++,t):void 0});h||e.push({interval:c,count:1})}}return e}function n(t,e){var i=[];return t.forEach(function(t){try{var o=Math.abs(60/(t.interval/e));o=r(o);var n=i.some(function(e){return e.tempo===o?e.count+=t.count:void 0});if(!n){if(isNaN(o))return;i.push({tempo:Math.round(o),count:t.count})}}catch(s){throw s}}),i}function s(t,e,i,o){for(var n=[],s=Object.keys(t).sort(),a=0;a<s.length;a++)for(var u=s[a],c=t[u],h=0;h<c.intervals.length;h++){var p=Math.round(Math.abs(60/(c.intervals[h]/i)));p=r(p);Math.abs(p-e)<o&&n.push(c.sampleIndex/44100)}return n=n.filter(function(t,e,i){var o=i[e+1]-t;return o>.01?!0:void 0})}function r(t){if(isFinite(t)&&0!=t){for(;90>t;)t*=2;for(;t>180&&t>90;)t/=2;return t}}var a=i,u=a.audiocontext;t.SoundFile=function(e,i,o){if("undefined"!=typeof e){if("string"==typeof e||"string"==typeof e[0]){var n=t.prototype._checkFileFormats(e);this.url=n}else if("object"==typeof e&&!(window.File&&window.FileReader&&window.FileList&&window.Blob))throw"Unable to load file because the File API is not supported";e.file&&(e=e.file),this.file=e}this._looping=!1,this._playing=!1,this._paused=!1,this._pauseTime=0,this._cues=[],this._lastPos=0,this._counterNode,this._scopeNode,this.bufferSourceNodes=[],this.bufferSourceNode=null,this.buffer=null,this.playbackRate=1,this.gain=1,this.input=a.audiocontext.createGain(),this.output=a.audiocontext.createGain(),this.reversed=!1,this.startTime=0,this.endTime=null,this.pauseTime=0,this.mode="sustain",this.startMillis=null,this.amplitude=new t.Amplitude,this.output.connect(this.amplitude.input),this.panPosition=0,this.panner=new t.Panner(this.output,a.input,2),(this.url||this.file)&&this.load(i),a.soundArray.push(this),this.whileLoading="function"==typeof o?o:function(){}},t.prototype.registerPreloadMethod("loadSound"),t.prototype.loadSound=function(e,i,o){window.location.origin.indexOf("file://")>-1&&"undefined"===window.cordova&&alert("This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS");var n=new t.SoundFile(e,i,o);return n},t.SoundFile.prototype.load=function(t){if(void 0!=this.url&&""!=this.url){var e=this,i=new XMLHttpRequest;i.addEventListener("progress",function(t){e._updateProgress(t)},!1),i.open("GET",this.url,!0),i.responseType="arraybuffer";var o=this;i.onload=function(){u.decodeAudioData(i.response,function(e){o.buffer=e,o.panner.inputChannels(e.numberOfChannels),t&&t(o)})},i.send()}else if(void 0!=this.file){var n=new FileReader,o=this;n.onload=function(){u.decodeAudioData(n.result,function(e){o.buffer=e,o.panner.inputChannels(e.numberOfChannels),t&&t(o)})},n.readAsArrayBuffer(this.file)}},t.SoundFile.prototype._updateProgress=function(t){if(t.lengthComputable){var e=Math.log(t.loaded/t.total*9.9);this.whileLoading(e)}else console.log("size unknown")},t.SoundFile.prototype.isLoaded=function(){return this.buffer?!0:!1},t.SoundFile.prototype.play=function(t,e,i,o,n){var s,r,u=this,c=a.audiocontext.currentTime,t=t||0;if(0>t&&(t=0),t+=c,!this.buffer)throw"not ready to play file, buffer has yet to load. Try preload()";if(this._pauseTime=0,"restart"===this.mode&&this.buffer&&this.bufferSourceNode){var c=a.audiocontext.currentTime;this.bufferSourceNode.stop(t),this._counterNode.stop(t)}if(this.bufferSourceNode=this._initSourceNode(),this._counterNode=this._initCounterNode(),o){if(!(o>=0&&o<this.buffer.duration))throw"start time out of range";s=o}else s=0;n=n?n<=this.buffer.duration-s?n:this.buffer.duration:this.buffer.duration-s;var h=i||1;if(this.bufferSourceNode.connect(this.output),this.output.gain.value=h,e=e||Math.abs(this.playbackRate),this.bufferSourceNode.playbackRate.setValueAtTime(e,c),this._paused?(this.bufferSourceNode.start(t,this.pauseTime,n),this._counterNode.start(t,this.pauseTime,n)):(this.bufferSourceNode.start(t,s,n),this._counterNode.start(t,s,n)),this._playing=!0,this._paused=!1,this.bufferSourceNodes.push(this.bufferSourceNode),this.bufferSourceNode._arrayIndex=this.bufferSourceNodes.length-1,this.bufferSourceNode.onended=function(){var t=this;this._playing=!1,setTimeout(function(){u.bufferSourceNodes.splice(t._arrayIndex,1),0===u.bufferSourceNodes.length&&(u._playing=!1)},1)},this.bufferSourceNode.loop=this._looping,this._counterNode.loop=this._looping,this._looping===!0){var r=s+n;this.bufferSourceNode.loopStart=s,this.bufferSourceNode.loopEnd=r,this._counterNode.loopStart=s,this._counterNode.loopEnd=r}},t.SoundFile.prototype.playMode=function(t){var e=t.toLowerCase();if("restart"===e&&this.buffer&&this.bufferSourceNode)for(var i=0;i<this.bufferSourceNodes.length-1;i++){var o=a.audiocontext.currentTime;this.bufferSourceNodes[i].stop(o)}if("restart"!==e&&"sustain"!==e)throw'Invalid play mode. Must be either "restart" or "sustain"';this.mode=e},t.SoundFile.prototype.pause=function(t){var e=a.audiocontext.currentTime,t=t||0,i=t+e;this.isPlaying()&&this.buffer&&this.bufferSourceNode?(this.pauseTime=this.currentTime(),this.bufferSourceNode.stop(i),this._counterNode.stop(i),this._paused=!0,this._playing=!1,this._pauseTime=this.currentTime()):this._pauseTime=0},t.SoundFile.prototype.loop=function(t,e,i,o,n){this._looping=!0,this.play(t,e,i,o,n)},t.SoundFile.prototype.setLoop=function(t){if(t===!0)this._looping=!0;else{if(t!==!1)throw"Error: setLoop accepts either true or false";this._looping=!1}this.bufferSourceNode&&(this.bufferSourceNode.loop=this._looping,this._counterNode.loop=this._looping)},t.SoundFile.prototype.isLooping=function(){return this.bufferSourceNode&&this._looping===!0&&this.isPlaying()===!0?!0:!1},t.SoundFile.prototype.isPlaying=function(){return this._playing},t.SoundFile.prototype.isPaused=function(){return this._paused},t.SoundFile.prototype.stop=function(t){var e=t||0;if("sustain"==this.mode)this.stopAll(e),this._playing=!1,this.pauseTime=0,this._paused=!1;else if(this.buffer&&this.bufferSourceNode){var i=a.audiocontext.currentTime,o=e||0;this.pauseTime=0,this.bufferSourceNode.stop(i+o),this._counterNode.stop(i+o),this._playing=!1,this._paused=!1}},t.SoundFile.prototype.stopAll=function(t){var e=a.audiocontext.currentTime,i=t||0;if(this.buffer&&this.bufferSourceNode){for(var o=0;o<this.bufferSourceNodes.length;o++)if(void 0!=typeof this.bufferSourceNodes[o])try{this.bufferSourceNodes[o].stop(e+i)}catch(n){}this._counterNode.stop(e+i)}},t.SoundFile.prototype.setVolume=function(t,e,i){if("number"==typeof t){var e=e||0,i=i||0,o=a.audiocontext.currentTime,n=this.output.gain.value;this.output.gain.cancelScheduledValues(o+i),this.output.gain.linearRampToValueAtTime(n,o+i),this.output.gain.linearRampToValueAtTime(t,o+i+e)}else{if(!t)return this.output.gain;t.connect(this.output.gain)}},t.SoundFile.prototype.amp=t.SoundFile.prototype.setVolume,t.SoundFile.prototype.fade=t.SoundFile.prototype.setVolume,t.SoundFile.prototype.getVolume=function(){return this.output.gain.value},t.SoundFile.prototype.pan=function(t,e){this.panPosition=t,this.panner.pan(t,e)},t.SoundFile.prototype.getPan=function(){return this.panPosition},t.SoundFile.prototype.rate=function(t){if(this.playbackRate!==t||!this.bufferSourceNode||this.bufferSourceNode.playbackRate.value!==t){this.playbackRate=t;var e=t;if(0===this.playbackRate&&this._playing&&this.pause(),this.playbackRate<0&&!this.reversed){{var i=this.currentTime();this.bufferSourceNode.playbackRate.value}this.reverseBuffer(),e=Math.abs(t);var o=(i-this.duration())/e;this.pauseTime=o}else this.playbackRate>0&&this.reversed&&this.reverseBuffer();if(this.bufferSourceNode){var n=a.audiocontext.currentTime;this.bufferSourceNode.playbackRate.cancelScheduledValues(n),this.bufferSourceNode.playbackRate.linearRampToValueAtTime(Math.abs(e),n),this._counterNode.playbackRate.cancelScheduledValues(n),this._counterNode.playbackRate.linearRampToValueAtTime(Math.abs(e),n)}}},t.SoundFile.prototype.setPitch=function(t){var e=midiToFreq(t)/midiToFreq(60);this.rate(e)},t.SoundFile.prototype.getPlaybackRate=function(){return this.playbackRate},t.SoundFile.prototype.duration=function(){return this.buffer?this.buffer.duration:0},t.SoundFile.prototype.currentTime=function(){return this._pauseTime>0?this._pauseTime:this._lastPos/u.sampleRate},t.SoundFile.prototype.jump=function(t,e){if(0>t||t>this.buffer.duration)throw"jump time out of range";if(e>this.buffer.duration-t)throw"end time out of range";var i=t||0,o=e||this.buffer.duration-t;this.isPlaying()&&this.stop(),this.play(0,this.playbackRate,this.output.gain.value,i,o)},t.SoundFile.prototype.channels=function(){return this.buffer.numberOfChannels},t.SoundFile.prototype.sampleRate=function(){return this.buffer.sampleRate},t.SoundFile.prototype.frames=function(){return this.buffer.length},t.SoundFile.prototype.getPeaks=function(t){if(!this.buffer)throw"Cannot load peaks yet, buffer is not loaded";if(t||(t=5*window.width),this.buffer){for(var e=this.buffer,i=e.length/t,o=~~(i/10)||1,n=e.numberOfChannels,s=new Float32Array(Math.round(t)),r=0;n>r;r++)for(var a=e.getChannelData(r),u=0;t>u;u++){for(var c=~~(u*i),h=~~(c+i),p=0,l=c;h>l;l+=o){var f=a[l];f>p?p=f:-f>p&&(p=f)}(0===r||Math.abs(p)>s[u])&&(s[u]=p)}return s}},t.SoundFile.prototype.reverseBuffer=function(){var t=this.getVolume();if(this.setVolume(0,.01,0),this.pause(),!this.buffer)throw"SoundFile is not done loading";for(var e=0;e<this.buffer.numberOfChannels;e++)Array.prototype.reverse.call(this.buffer.getChannelData(e));this.reversed=!this.reversed,this.setVolume(t,.01,.0101),this.play()},t.SoundFile.prototype._onEnded=function(t){t.onended=function(t){var e=a.audiocontext.currentTime;t.stop(e)}},t.SoundFile.prototype.add=function(){},t.SoundFile.prototype.dispose=function(){var t=a.audiocontext.currentTime;if(this.stop(t),this.buffer&&this.bufferSourceNode){for(var e=0;e<this.bufferSourceNodes.length-1;e++)null!==this.bufferSourceNodes[e]&&(this.bufferSourceNodes[e].stop(t),this.bufferSourceNodes[e]=null);if(this.isPlaying()){try{this._counterNode.stop(t)}catch(i){console.log(i)}this._counterNode=null}}this.output&&(this.output.disconnect(),this.output=null),this.panner&&(this.panner.disconnect(),this.panner=null)},t.SoundFile.prototype.connect=function(t){this.panner.connect(t?t.hasOwnProperty("input")?t.input:t:a.input)},t.SoundFile.prototype.disconnect=function(t){this.panner.disconnect(t)},t.SoundFile.prototype.getLevel=function(t){return t&&(this.amplitude.smoothing=t),this.amplitude.getLevel()},t.SoundFile.prototype.setPath=function(e,i){var o=t.prototype._checkFileFormats(e);this.url=o,this.load(i)},t.SoundFile.prototype.setBuffer=function(t){var e=t.length,i=t[0].length,o=u.createBuffer(e,i,u.sampleRate);!t[0]instanceof Float32Array&&(t[0]=new Float32Array(t[0]));for(var n=0;e>n;n++){var s=o.getChannelData(n);s.set(t[n])}this.buffer=o,this.panner.inputChannels(e)},t.SoundFile.prototype._initCounterNode=function(){var e=this,i=u.currentTime,o=u.createBufferSource();return e._scopeNode&&(e._scopeNode.disconnect(),e._scopeNode=null),e._scopeNode=u.createScriptProcessor(256,1,1),o.buffer=c(e.buffer),o.playbackRate.setValueAtTime(e.playbackRate,i),o.connect(e._scopeNode),e._scopeNode.connect(t.soundOut._silentNode),e._scopeNode.onaudioprocess=function(t){var i=t.inputBuffer.getChannelData(0);e._lastPos=i[i.length-1]||0,e._onTimeUpdate(e._lastPos)},o},t.SoundFile.prototype._initSourceNode=function(){var t=this,e=u.currentTime,i=u.createBufferSource();return i.buffer=t.buffer,i.playbackRate.setValueAtTime(t.playbackRate,e),i};var c=function(t){for(var e=new Float32Array(t.length),i=u.createBuffer(1,t.length,44100),o=0;o<t.length;o++)e[o]=o;return i.getChannelData(0).set(e),i};t.SoundFile.prototype.processPeaks=function(t,i,r,a){var u=this.buffer.length,c=this.buffer.sampleRate,h=this.buffer,l=i||.9,f=l,d=r||.22,y=a||200,m=new OfflineAudioContext(1,u,c),v=m.createBufferSource();v.buffer=h;var g=m.createBiquadFilter();g.type="lowpass",v.connect(g),g.connect(m.destination),v.start(0),m.startRendering(),m.oncomplete=function(i){var r=i.renderedBuffer,a=r.getChannelData(0);do p=e(a,f),f-=.005;while(Object.keys(p).length<y&&f>=d);var u=o(p),c=n(u,r.sampleRate),h=c.sort(function(t,e){return e.count-t.count}).splice(0,5);this.tempo=h[0].tempo;var l=5,m=s(p,h[0].tempo,r.sampleRate,l);t(m)}};var h=function(t,e){this.sampleIndex=e,this.amplitude=t,this.tempos=[],this.intervals=[]},p=[];t.SoundFile.prototype.addCue=function(t,e,i){var o=this._cueIDCounter++,n=new l(e,t,o,i);return this._cues.push(n),o},t.SoundFile.prototype.removeCue=function(t){for(var e=0;e<this._cues.length;e++){var i=this._cues[e];i.id===t&&this.cues.splice(e,1)}0===this._cues.length},t.SoundFile.prototype.clearCues=function(){this._cues=[]},t.SoundFile.prototype._onTimeUpdate=function(t){for(var e=t/this.buffer.sampleRate,i=0;i<this._cues.length;i++){var o=this._cues[i].time,n=this._cues[i].val;this._prevTime<o&&e>=o&&this._cues[i].callback(n)}this._prevTime=e};var l=function(t,e,i,o){this.callback=t,this.time=e,this.id=i,this.val=o}}(e,i);var r;r=function(){"use strict";var e=i;t.Amplitude=function(t){this.bufferSize=2048,this.audiocontext=e.audiocontext,this.processor=this.audiocontext.createScriptProcessor(this.bufferSize,2,1),this.input=this.processor,this.output=this.audiocontext.createGain(),this.smoothing=t||0,this.volume=0,this.average=0,this.stereoVol=[0,0],this.stereoAvg=[0,0],this.stereoVolNorm=[0,0],this.volMax=.001,this.normalize=!1,this.processor.onaudioprocess=this._audioProcess.bind(this),this.processor.connect(this.output),this.output.gain.value=0,this.output.connect(this.audiocontext.destination),e.meter.connect(this.processor)},t.Amplitude.prototype.setInput=function(i,o){e.meter.disconnect(),o&&(this.smoothing=o),null==i?(console.log("Amplitude input source is not ready! Connecting to master output instead"),e.meter.connect(this.processor)):i instanceof t.Signal?i.output.connect(this.processor):i?(i.connect(this.processor),this.processor.disconnect(),this.processor.connect(this.output)):e.meter.connect(this.processor)},t.Amplitude.prototype.connect=function(t){this.output.connect(t?t.hasOwnProperty("input")?t.input:t:this.panner.connect(e.input))},t.Amplitude.prototype.disconnect=function(){this.output.disconnect()},t.Amplitude.prototype._audioProcess=function(t){for(var e=0;e<t.inputBuffer.numberOfChannels;e++){for(var i,o=t.inputBuffer.getChannelData(e),n=o.length,s=0,r=0,a=0;n>a;a++)i=o[a],this.normalize?(s+=Math.max(Math.min(i/this.volMax,1),-1),r+=Math.max(Math.min(i/this.volMax,1),-1)*Math.max(Math.min(i/this.volMax,1),-1)):(s+=i,r+=i*i);var u=s/n,c=Math.sqrt(r/n);this.stereoVol[e]=Math.max(c,this.stereoVol[e]*this.smoothing),this.stereoAvg[e]=Math.max(u,this.stereoVol[e]*this.smoothing),this.volMax=Math.max(this.stereoVol[e],this.volMax)}var h=this,p=this.stereoVol.reduce(function(t,e,i){return h.stereoVolNorm[i-1]=Math.max(Math.min(h.stereoVol[i-1]/h.volMax,1),0),h.stereoVolNorm[i]=Math.max(Math.min(h.stereoVol[i]/h.volMax,1),0),t+e});this.volume=p/this.stereoVol.length,this.volNorm=Math.max(Math.min(this.volume/this.volMax,1),0)},t.Amplitude.prototype.getLevel=function(t){return"undefined"!=typeof t?this.normalize?this.stereoVolNorm[t]:this.stereoVol[t]:this.normalize?this.volNorm:this.volume},t.Amplitude.prototype.toggleNormalize=function(t){this.normalize="boolean"==typeof t?t:!this.normalize},t.Amplitude.prototype.smooth=function(t){t>=0&&1>t?this.smoothing=t:console.log("Error: smoothing must be between 0 and 1")}}(i);var a;a=function(){"use strict";var e=i;t.FFT=function(t,i){this.smoothing=t||.8,this.bins=i||1024;var o=2*i||2048;this.input=this.analyser=e.audiocontext.createAnalyser(),e.fftMeter.connect(this.analyser),this.analyser.smoothingTimeConstant=this.smoothing,this.analyser.fftSize=o,this.freqDomain=new Uint8Array(this.analyser.frequencyBinCount),this.timeDomain=new Uint8Array(this.analyser.frequencyBinCount),this.bass=[20,140],this.lowMid=[140,400],this.mid=[400,2600],this.highMid=[2600,5200],this.treble=[5200,14e3]},t.FFT.prototype.setInput=function(t){t?(t.output?t.output.connect(this.analyser):t.connect&&t.connect(this.analyser),e.fftMeter.disconnect()):e.fftMeter.connect(this.analyser)},t.FFT.prototype.waveform=function(){for(var e,i,o,n=0;n<arguments.length;n++)"number"==typeof arguments[n]&&(e=arguments[n],this.analyser.fftSize=2*e),"string"==typeof arguments[n]&&(i=arguments[n]);if(i&&!t.prototype._isSafari())return s(this,this.timeDomain),this.analyser.getFloatTimeDomainData(this.timeDomain),this.timeDomain;r(this,this.timeDomain),this.analyser.getByteTimeDomainData(this.timeDomain);for(var o=new Array,n=0;n<this.timeDomain.length;n++){var a=t.prototype.map(this.timeDomain[n],0,255,-1,1);o.push(a)}return o},t.FFT.prototype.analyze=function(){for(var t,e,i=0;i<arguments.length;i++)"number"==typeof arguments[i]&&(t=this.bins=arguments[i],this.analyser.fftSize=2*this.bins),"string"==typeof arguments[i]&&(e=arguments[i]);if(e&&"db"===e.toLowerCase())return o(this),this.analyser.getFloatFrequencyData(this.freqDomain),this.freqDomain;n(this,this.freqDomain),this.analyser.getByteFrequencyData(this.freqDomain);var s=Array.apply([],this.freqDomain);return s.length===this.analyser.fftSize,s.constructor===Array,s},t.FFT.prototype.getEnergy=function(t,i){var o=e.audiocontext.sampleRate/2;if("bass"===t?(t=this.bass[0],i=this.bass[1]):"lowMid"===t?(t=this.lowMid[0],i=this.lowMid[1]):"mid"===t?(t=this.mid[0],i=this.mid[1]):"highMid"===t?(t=this.highMid[0],i=this.highMid[1]):"treble"===t&&(t=this.treble[0],i=this.treble[1]),"number"!=typeof t)throw"invalid input for getEnergy()";if(i){if(t&&i){if(t>i){var n=i;i=t,t=n}for(var s=Math.round(t/o*this.freqDomain.length),r=Math.round(i/o*this.freqDomain.length),a=0,u=0,c=s;r>=c;c++)a+=this.freqDomain[c],u+=1;var h=a/u;return h}throw"invalid input for getEnergy()"}var p=Math.round(t/o*this.freqDomain.length);return this.freqDomain[p]},t.FFT.prototype.getFreq=function(t,e){console.log("getFreq() is deprecated. Please use getEnergy() instead.");var i=this.getEnergy(t,e);return i},t.FFT.prototype.smooth=function(t){t&&(this.smoothing=t),this.analyser.smoothingTimeConstant=t};var o=function(t){t.freqDomain instanceof Float32Array==!1&&(t.freqDomain=new Float32Array(t.analyser.frequencyBinCount))},n=function(t){t.freqDomain instanceof Uint8Array==!1&&(t.freqDomain=new Uint8Array(t.analyser.frequencyBinCount))},s=function(t){t.timeDomain instanceof Float32Array==!1&&(t.timeDomain=new Float32Array(t.analyser.frequencyBinCount))},r=function(t){t.timeDomain instanceof Uint8Array==!1&&(t.timeDomain=new Uint8Array(t.analyser.frequencyBinCount))}}(i);var u;u=function(){"use strict";function t(t){return void 0===t}var e;if(t(window.AudioContext)&&(window.AudioContext=window.webkitAudioContext),t(window.OfflineAudioContext)&&(window.OfflineAudioContext=window.webkitOfflineAudioContext),t(AudioContext))throw new Error("Web Audio is not supported in this browser");e=new AudioContext,"function"!=typeof AudioContext.prototype.createGain&&(AudioContext.prototype.createGain=AudioContext.prototype.createGainNode),"function"!=typeof AudioContext.prototype.createDelay&&(AudioContext.prototype.createDelay=AudioContext.prototype.createDelayNode),"function"!=typeof AudioContext.prototype.createPeriodicWave&&(AudioContext.prototype.createPeriodicWave=AudioContext.prototype.createWaveTable),"function"!=typeof AudioBufferSourceNode.prototype.start&&(AudioBufferSourceNode.prototype.start=AudioBufferSourceNode.prototype.noteGrainOn),"function"!=typeof AudioBufferSourceNode.prototype.stop&&(AudioBufferSourceNode.prototype.stop=AudioBufferSourceNode.prototype.noteOff),"function"!=typeof OscillatorNode.prototype.start&&(OscillatorNode.prototype.start=OscillatorNode.prototype.noteOn),"function"!=typeof OscillatorNode.prototype.stop&&(OscillatorNode.prototype.stop=OscillatorNode.prototype.noteOff),"function"!=typeof OscillatorNode.prototype.setPeriodicWave&&(OscillatorNode.prototype.setPeriodicWave=OscillatorNode.prototype.setWaveTable),window.Tone||(AudioNode.prototype._nativeConnect=AudioNode.prototype.connect,AudioNode.prototype.connect=function(e,i,o){if(e.input)Array.isArray(e.input)?(t(o)&&(o=0),this.connect(e.input[o])):this.connect(e.input,i,o);else try{e instanceof AudioNode?this._nativeConnect(e,i,o):this._nativeConnect(e,i)}catch(n){throw new Error("error connecting to node: "+e)}});var i=function(e,i){t(e)||1===e?this.input=this.context.createGain():e>1&&(this.input=new Array(e)),t(i)||1===i?this.output=this.context.createGain():i>1&&(this.output=new Array(e))};i.context=e,i.prototype.context=i.context,i.prototype.bufferSize=2048,i.prototype.bufferTime=i.prototype.bufferSize/i.context.sampleRate,i.prototype.connect=function(t,e,i){Array.isArray(this.output)?(e=this.defaultArg(e,0),this.output[e].connect(t,0,i)):this.output.connect(t,e,i)},i.prototype.disconnect=function(t){Array.isArray(this.output)?(t=this.defaultArg(t,0),this.output[t].disconnect()):this.output.disconnect()},i.prototype.connectSeries=function(){if(arguments.length>1)for(var t=arguments[0],e=1;e<arguments.length;e++){var i=arguments[e];t.connect(i),t=i}},i.prototype.connectParallel=function(){var t=arguments[0];if(arguments.length>1)for(var e=1;e<arguments.length;e++){var i=arguments[e];t.connect(i)}},i.prototype.chain=function(){if(arguments.length>0)for(var t=this,e=0;e<arguments.length;e++){var i=arguments[e];t.connect(i),t=i}},i.prototype.fan=function(){if(arguments.length>0)for(var t=1;t<arguments.length;t++)this.connect(arguments[t])},AudioNode.prototype.chain=i.prototype.chain,AudioNode.prototype.fan=i.prototype.fan,i.prototype.defaultArg=function(e,i){if("object"==typeof e&&"object"==typeof i){var o={};for(var n in e)o[n]=this.defaultArg(e[n],e[n]);for(var s in i)o[s]=this.defaultArg(e[s],i[s]);return o}return t(e)?i:e},i.prototype.optionsObject=function(t,e,i){var o={};if(1===t.length&&"object"==typeof t[0])o=t[0];else for(var n=0;n<e.length;n++)o[e[n]]=t[n];return this.isUndef(i)?o:this.defaultArg(o,i)},i.prototype.isUndef=t,i.prototype.equalPowerScale=function(t){var e=.5*Math.PI;return Math.sin(t*e)},i.prototype.logScale=function(t){return Math.max(this.normalize(this.gainToDb(t),-100,0),0)},i.prototype.expScale=function(t){return this.dbToGain(this.interpolate(t,-100,0))},i.prototype.dbToGain=function(t){return Math.pow(2,t/6)},i.prototype.gainToDb=function(t){return 20*(Math.log(t)/Math.LN10)},i.prototype.interpolate=function(t,e,i){return t*(i-e)+e},i.prototype.normalize=function(t,e,i){if(e>i){var o=i;i=e,e=o}else if(e==i)return 0;return(t-e)/(i-e)},i.prototype.dispose=function(){this.isUndef(this.input)||(this.input instanceof AudioNode&&this.input.disconnect(),this.input=null),this.isUndef(this.output)||(this.output instanceof AudioNode&&this.output.disconnect(),this.output=null)};var o=null;i.prototype.noGC=function(){this.output.connect(o)},AudioNode.prototype.noGC=function(){this.connect(o)},i.prototype.now=function(){return this.context.currentTime},i.prototype.samplesToSeconds=function(t){return t/this.context.sampleRate},i.prototype.toSamples=function(t){var e=this.toSeconds(t);return Math.round(e*this.context.sampleRate)},i.prototype.toSeconds=function(t,e){if(e=this.defaultArg(e,this.now()),"number"==typeof t)return t;if("string"==typeof t){var i=0;return"+"===t.charAt(0)&&(t=t.slice(1),i=e),parseFloat(t)+i}return e},i.prototype.frequencyToSeconds=function(t){return 1/parseFloat(t)},i.prototype.secondsToFrequency=function(t){return 1/t};var n=[];return i._initAudioContext=function(t){t(i.context),n.push(t)},i.setContext=function(t){i.prototype.context=t,i.context=t;for(var e=0;e<n.length;e++)n[e](t)},i.extend=function(e,o){function n(){}t(o)&&(o=i),n.prototype=o.prototype,e.prototype=new n,e.prototype.constructor=e},i.startMobile=function(){var t=i.context.createOscillator(),e=i.context.createGain();e.gain.value=0,t.connect(e),e.connect(i.context.destination);var o=i.context.currentTime;t.start(o),t.stop(o+1)},i._initAudioContext(function(t){i.prototype.bufferTime=i.prototype.bufferSize/t.sampleRate,o=t.createGain(),o.gain.value=0,o.connect(t.destination)}),i}();var c;c=function(t){"use strict";return t.SignalBase=function(){},t.extend(t.SignalBase),t.SignalBase.prototype.connect=function(e,i,o){e instanceof t.Signal?e.setValue(0):e instanceof AudioParam&&(e.value=0),t.prototype.connect.call(this,e,i,o)},t.SignalBase.prototype.dispose=function(){t.prototype.dispose.call(this)},t.SignalBase}(u);var h;h=function(t){"use strict";return t.WaveShaper=function(t,e){this._shaper=this.input=this.output=this.context.createWaveShaper(),this._curve=null,Array.isArray(t)?this.setCurve(t):isFinite(t)||this.isUndef(t)?this._curve=new Float32Array(this.defaultArg(t,1024)):"function"==typeof t&&(this._curve=new Float32Array(this.defaultArg(e,1024)),this.setMap(t))
},t.extend(t.WaveShaper,t.SignalBase),t.WaveShaper.prototype.setMap=function(t){for(var e=0,i=this._curve.length;i>e;e++){var o=e/i*2-1,n=e/(i-1)*2-1;this._curve[e]=t(o,e,n)}this._shaper.curve=this._curve},t.WaveShaper.prototype.setCurve=function(t){if(this._isSafari()){var e=t[0];t.unshift(e)}this._curve=new Float32Array(t),this._shaper.curve=this._curve},t.WaveShaper.prototype.setOversample=function(t){this._shaper.oversample=t},t.WaveShaper.prototype._isSafari=function(){var t=navigator.userAgent.toLowerCase();return-1!==t.indexOf("safari")&&-1===t.indexOf("chrome")},t.WaveShaper.prototype.dispose=function(){t.prototype.dispose.call(this),this._shaper.disconnect(),this._shaper=null,this._curve=null},t.WaveShaper}(u);var p;p=function(t){"use strict";return t.Signal=function(e){this._scalar=this.context.createGain(),this.input=this.output=this.context.createGain(),this._syncRatio=1,this.value=this.defaultArg(e,0),t.Signal._constant.chain(this._scalar,this.output)},t.extend(t.Signal,t.SignalBase),t.Signal.prototype.getValue=function(){return this._scalar.gain.value},t.Signal.prototype.setValue=function(t){0===this._syncRatio?t=0:t*=this._syncRatio,this._scalar.gain.value=t},t.Signal.prototype.setValueAtTime=function(t,e){t*=this._syncRatio,this._scalar.gain.setValueAtTime(t,this.toSeconds(e))},t.Signal.prototype.setCurrentValueNow=function(t){t=this.defaultArg(t,this.now());var e=this.getValue();return this.cancelScheduledValues(t),this._scalar.gain.setValueAtTime(e,t),e},t.Signal.prototype.linearRampToValueAtTime=function(t,e){t*=this._syncRatio,this._scalar.gain.linearRampToValueAtTime(t,this.toSeconds(e))},t.Signal.prototype.exponentialRampToValueAtTime=function(t,e){t*=this._syncRatio;try{this._scalar.gain.exponentialRampToValueAtTime(t,this.toSeconds(e))}catch(i){this._scalar.gain.linearRampToValueAtTime(t,this.toSeconds(e))}},t.Signal.prototype.exponentialRampToValueNow=function(t,e){var i=this.now();this.setCurrentValueNow(i),"+"===e.toString().charAt(0)&&(e=e.substr(1)),this.exponentialRampToValueAtTime(t,i+this.toSeconds(e))},t.Signal.prototype.linearRampToValueNow=function(t,e){var i=this.now();this.setCurrentValueNow(i),t*=this._syncRatio,"+"===e.toString().charAt(0)&&(e=e.substr(1)),this._scalar.gain.linearRampToValueAtTime(t,i+this.toSeconds(e))},t.Signal.prototype.setTargetAtTime=function(t,e,i){t*=this._syncRatio,this._scalar.gain.setTargetAtTime(t,this.toSeconds(e),i)},t.Signal.prototype.setValueCurveAtTime=function(t,e,i){for(var o=0;o<t.length;o++)t[o]*=this._syncRatio;this._scalar.gain.setValueCurveAtTime(t,this.toSeconds(e),this.toSeconds(i))},t.Signal.prototype.cancelScheduledValues=function(t){this._scalar.gain.cancelScheduledValues(this.toSeconds(t))},t.Signal.prototype.sync=function(t,e){this._syncRatio=e?e:0!==t.getValue()?this.getValue()/t.getValue():0,this._scalar.disconnect(),this._scalar=this.context.createGain(),this.connectSeries(t,this._scalar,this.output),this._scalar.gain.value=this._syncRatio},t.Signal.prototype.unsync=function(){var e=this.getValue();this._scalar.disconnect(),this._scalar=this.context.createGain(),this._scalar.gain.value=e/this._syncRatio,this._syncRatio=1,t.Signal._constant.chain(this._scalar,this.output)},t.Signal.prototype.dispose=function(){t.prototype.dispose.call(this),this._scalar.disconnect(),this._scalar=null},Object.defineProperty(t.Signal.prototype,"value",{get:function(){return this.getValue()},set:function(t){this.setValue(t)}}),t.Signal._generator=null,t.Signal._constant=null,t._initAudioContext(function(e){t.Signal._generator=e.createOscillator(),t.Signal._constant=new t.WaveShaper([1,1]),t.Signal._generator.connect(t.Signal._constant),t.Signal._generator.start(0),t.Signal._generator.noGC()}),t.Signal}(u);var l;l=function(t){"use strict";return t.Add=function(e){t.call(this,2,0),this._sum=this.input[0]=this.input[1]=this.output=this.context.createGain(),this._value=null,isFinite(e)&&(this._value=new t.Signal(e),this._value.connect(this._sum))},t.extend(t.Add,t.SignalBase),t.Add.prototype.setValue=function(t){if(null===this._value)throw new Error("cannot switch from signal to number");this._value.setValue(t)},t.Add.prototype.dispose=function(){t.prototype.dispose.call(this),this._sum=null,this._value&&(this._value.dispose(),this._value=null)},t.Add}(u);var f;f=function(t){"use strict";return t.Multiply=function(e){t.call(this,2,0),this._mult=this.input[0]=this.output=this.context.createGain(),this._factor=this.input[1]=this.output.gain,this._factor.value=this.defaultArg(e,0)},t.extend(t.Multiply,t.SignalBase),t.Multiply.prototype.setValue=function(t){this._factor.value=t},t.Multiply.prototype.dispose=function(){t.prototype.dispose.call(this),this._mult=null,this._factor=null},t.Multiply}(u);var d;d=function(t){"use strict";return t.Scale=function(e,i){this._outputMin=this.defaultArg(e,0),this._outputMax=this.defaultArg(i,1),this._scale=this.input=new t.Multiply(1),this._add=this.output=new t.Add(0),this._scale.connect(this._add),this._setRange()},t.extend(t.Scale,t.SignalBase),t.Scale.prototype.setMin=function(t){this._outputMin=t,this._setRange()},t.Scale.prototype.setMax=function(t){this._outputMax=t,this._setRange()},t.Scale.prototype._setRange=function(){this._add.setValue(this._outputMin),this._scale.setValue(this._outputMax-this._outputMin)},t.Scale.prototype.dispose=function(){t.prototype.dispose.call(this),this._add.dispose(),this._add=null,this._scale.dispose(),this._scale=null},t.Scale}(u,l,f);var y;y=function(){"use strict";var e=p,o=l,n=f,s=d,r=u,a=i;r.setContext(a.audiocontext),t.Signal=function(t){var i=new e(t);return i},e.prototype.fade=e.prototype.linearRampToValueAtTime,n.prototype.fade=e.prototype.fade,o.prototype.fade=e.prototype.fade,s.prototype.fade=e.prototype.fade,e.prototype.setInput=function(t){t.connect(this)},n.prototype.setInput=e.prototype.setInput,o.prototype.setInput=e.prototype.setInput,s.prototype.setInput=e.prototype.setInput,e.prototype.add=function(t){var e=new o(t);return this.connect(e),e},n.prototype.add=e.prototype.add,o.prototype.add=e.prototype.add,s.prototype.add=e.prototype.add,e.prototype.mult=function(t){var e=new n(t);return this.connect(e),e},n.prototype.mult=e.prototype.mult,o.prototype.mult=e.prototype.mult,s.prototype.mult=e.prototype.mult,e.prototype.scale=function(e,i,o,n){var r,a;4===arguments.length?(r=t.prototype.map(o,e,i,0,1)-.5,a=t.prototype.map(n,e,i,0,1)-.5):(r=arguments[0],a=arguments[1]);var u=new s(r,a);return this.connect(u),u},n.prototype.scale=e.prototype.scale,o.prototype.scale=e.prototype.scale,s.prototype.scale=e.prototype.scale}(p,l,f,d,u,i);var m;m=function(){"use strict";var e=i,o=l,n=f,s=d;t.Oscillator=function(i,o){if("string"==typeof i){var n=o;o=i,i=n}if("number"==typeof o){var n=o;o=i,i=n}this.started=!1,this.oscillator=e.audiocontext.createOscillator(),this.f=i||440,this.oscillator.frequency.setValueAtTime(this.f,e.audiocontext.currentTime),this.oscillator.type=o||"sine";this.oscillator;this.input=e.audiocontext.createGain(),this.output=e.audiocontext.createGain(),this._freqMods=[],this.output.gain.value=.5,this.output.gain.setValueAtTime(.5,e.audiocontext.currentTime),this.oscillator.connect(this.output),this.panPosition=0,this.connection=e.input,this.panner=new t.Panner(this.output,this.connection,1),this.mathOps=[this.output],e.soundArray.push(this)},t.Oscillator.prototype.start=function(t,i){if(this.started){var o=e.audiocontext.currentTime;this.stop(o)}if(!this.started){var n=i||this.f,s=this.oscillator.type;this.oscillator=e.audiocontext.createOscillator(),this.oscillator.frequency.exponentialRampToValueAtTime(Math.abs(n),e.audiocontext.currentTime),this.oscillator.type=s,this.oscillator.connect(this.output),t=t||0,this.oscillator.start(t+e.audiocontext.currentTime),this.freqNode=this.oscillator.frequency;for(var r in this._freqMods)"undefined"!=typeof this._freqMods[r].connect&&this._freqMods[r].connect(this.oscillator.frequency);this.started=!0}},t.Oscillator.prototype.stop=function(t){if(this.started){var i=t||0,o=e.audiocontext.currentTime;this.oscillator.stop(i+o),this.started=!1}},t.Oscillator.prototype.amp=function(t,i,o){var n=this;if("number"==typeof t){var i=i||0,o=o||0,s=e.audiocontext.currentTime,r=this.output.gain.value;this.output.gain.cancelScheduledValues(s),this.output.gain.linearRampToValueAtTime(r,s+o),this.output.gain.linearRampToValueAtTime(t,s+o+i)}else{if(!t)return this.output.gain;console.log(t),t.connect(n.output.gain)}},t.Oscillator.prototype.fade=t.Oscillator.prototype.amp,t.Oscillator.prototype.getAmp=function(){return this.output.gain.value},t.Oscillator.prototype.freq=function(t,i,o){if("number"!=typeof t||isNaN(t)){if(!t)return this.oscillator.frequency;t.output&&(t=t.output),t.connect(this.oscillator.frequency),this._freqMods.push(t)}else{this.f=t;var n=e.audiocontext.currentTime,i=i||0,o=o||0,s=this.oscillator.frequency.value;this.oscillator.frequency.cancelScheduledValues(n),this.oscillator.frequency.setValueAtTime(s,n+o),t>0?this.oscillator.frequency.exponentialRampToValueAtTime(t,o+i+n):this.oscillator.frequency.linearRampToValueAtTime(t,o+i+n)}},t.Oscillator.prototype.getFreq=function(){return this.oscillator.frequency.value},t.Oscillator.prototype.setType=function(t){this.oscillator.type=t},t.Oscillator.prototype.getType=function(){return this.oscillator.type},t.Oscillator.prototype.connect=function(t){t?t.hasOwnProperty("input")?(this.panner.connect(t.input),this.connection=t.input):(this.panner.connect(t),this.connection=t):this.panner.connect(e.input)},t.Oscillator.prototype.disconnect=function(){this.output.disconnect(),this.panner.disconnect(),this.output.connect(this.panner),this.oscMods=[]},t.Oscillator.prototype.pan=function(t,e){this.panPosition=t,this.panner.pan(t,e)},t.Oscillator.prototype.getPan=function(){return this.panPosition},t.Oscillator.prototype.dispose=function(){if(this.oscillator){var t=e.audiocontext.currentTime;this.stop(t),this.disconnect(),this.oscillator.disconnect(),this.panner=null,this.oscillator=null}this.osc2&&this.osc2.dispose()},t.Oscillator.prototype.phase=function(i){this.dNode||(this.dNode=e.audiocontext.createDelay(),this.output.disconnect(),this.output.connect(this.dNode),this.dNode.connect(this.panner));var o=e.audiocontext.currentTime;this.dNode.delayTime.linearRampToValueAtTime(t.prototype.map(i,0,1,0,1/this.oscillator.frequency.value),o)};var r=function(t,e,i,o,n){var s=t.oscillator;for(var r in t.mathOps)t.mathOps[r]instanceof n&&(s.disconnect(),t.mathOps[r].dispose(),i=r,i<t.mathOps.length-2&&(o=t.mathOps[r+1]));return i==t.mathOps.length-1&&t.mathOps.push(o),r>0&&(s=t.mathOps[r-1]),s.disconnect(),s.connect(e),e.connect(o),t.mathOps[i]=e,t};t.Oscillator.prototype.add=function(t){var e=new o(t),i=this.mathOps.length-1,n=this.output;return r(this,e,i,n,o)},t.Oscillator.prototype.mult=function(t){var e=new n(t),i=this.mathOps.length-1,o=this.output;return r(this,e,i,o,n)},t.Oscillator.prototype.scale=function(e,i,o,n){var a,u;4===arguments.length?(a=t.prototype.map(o,e,i,0,1)-.5,u=t.prototype.map(n,e,i,0,1)-.5):(a=arguments[0],u=arguments[1]);var c=new s(a,u),h=this.mathOps.length-1,p=this.output;return r(this,c,h,p,s)},t.SinOsc=function(e){t.Oscillator.call(this,e,"sine")},t.SinOsc.prototype=Object.create(t.Oscillator.prototype),t.TriOsc=function(e){t.Oscillator.call(this,e,"triangle")},t.TriOsc.prototype=Object.create(t.Oscillator.prototype),t.SawOsc=function(e){t.Oscillator.call(this,e,"sawtooth")},t.SawOsc.prototype=Object.create(t.Oscillator.prototype),t.SqrOsc=function(e){t.Oscillator.call(this,e,"square")},t.SqrOsc.prototype=Object.create(t.Oscillator.prototype)}(i,p,l,f,d);var v;v=function(){"use strict";var e=i,o=l,n=f,s=d,r=u;r.setContext(e.audiocontext);var a=null,c=!1;t.Env=function(i,o,n,s,r,a,u,c){this.aTime=i,this.aLevel=o,this.dTime=n||0,this.dLevel=s||0,this.sTime=r||0,this.sLevel=a||0,this.rTime=u||0,this.rLevel=c||0,this.output=e.audiocontext.createGain(),this.control=new t.Signal,this.control.connect(this.output),this.connection=null,this.mathOps=[this.control],e.soundArray.push(this)},t.Env.prototype.set=function(t,e,i,o,n,s,r,a){this.aTime=t,this.aLevel=e,this.dTime=i||0,this.dLevel=o||0,this.sTime=n||0,this.sLevel=s||0,this.rTime=r||0,this.rLevel=a||0},t.Env.prototype.setInput=function(){for(var t=0;t<arguments.length;t++)this.connect(arguments[t])},t.Env.prototype.ctrl=function(t){this.connect(t)},t.Env.prototype.play=function(t,i){var o=e.audiocontext.currentTime,n=i||0,s=o+n;t&&this.connection!==t&&this.connect(t);var r=this.control.getValue();this.control.cancelScheduledValues(s),this.control.linearRampToValueAtTime(r,s),this.control.linearRampToValueAtTime(this.aLevel,s+this.aTime),this.control.linearRampToValueAtTime(this.dLevel,s+this.aTime+this.dTime),this.control.linearRampToValueAtTime(this.sLevel,s+this.aTime+this.dTime+this.sTime),this.control.linearRampToValueAtTime(this.rLevel,s+this.aTime+this.dTime+this.sTime+this.rTime);s+this.aTime+this.dTime+this.sTime+this.rTime},t.Env.prototype.triggerAttack=function(t,i){var o=e.audiocontext.currentTime,n=i||0,s=o+n;this.lastAttack=s,c=!0;var r=this.control.getValue();console.log(r),this.control.cancelScheduledValues(s),this.control.linearRampToValueAtTime(r,s),t&&this.connection!==t&&this.connect(t),this.control.linearRampToValueAtTime(this.aLevel,s+this.aTime),this.control.linearRampToValueAtTime(this.aLevel,s+this.aTime),this.control.linearRampToValueAtTime(this.dLevel,s+this.aTime+this.dTime),this.control.linearRampToValueAtTime(this.sLevel,s+this.aTime+this.dTime+this.sTime)},t.Env.prototype.triggerRelease=function(t,i){if(c){var o,n=e.audiocontext.currentTime,s=i||0,r=n+s;if(t&&this.connection!==t&&this.connect(t),this.control.cancelScheduledValues(r),n-this.lastAttack<this.aTime){var u=this.aTime-(r-this.lastAttack);this.control.linearRampToValueAtTime(this.aLevel,r+u),this.control.linearRampToValueAtTime(this.dLevel,r+u+this.dTime),this.control.linearRampToValueAtTime(this.sLevel,r+u+this.dTime+this.sTime),this.control.linearRampToValueAtTime(this.rLevel,r+u+this.dTime+this.sTime+this.rTime),o=r+this.dTime+this.sTime+this.rTime}else if(n-this.lastAttack<this.aTime+this.dTime){var h=this.aTime+this.dTime-(n-this.lastAttack);this.control.linearRampToValueAtTime(this.dLevel,r+h),this.control.linearRampToValueAtTime(this.sLevel,r+h+.01),this.control.linearRampToValueAtTime(this.rLevel,r+h+.01+this.rTime),o=r+this.sTime+this.rTime}else if(n-this.lastAttack<this.aTime+this.dTime+this.sTime){var p=this.aTime+this.dTime+this.sTime-(n-this.lastAttack);this.control.linearRampToValueAtTime(this.sLevel,r+p),this.control.linearRampToValueAtTime(this.rLevel,r+p+this.rTime),o=r+this.rTime}else this.control.linearRampToValueAtTime(this.sLevel,r),this.control.linearRampToValueAtTime(this.rLevel,r+this.rTime),o=r+this.dTime+this.sTime+this.rTime;var l=r+this.aTime+this.dTime+this.sTime+this.rTime;this.connection&&this.connection.hasOwnProperty("oscillator")?(a=this.connection.oscillator,a.stop(l+.01)):this.connect&&this.connection.hasOwnProperty("source")&&(a=this.connection.source,a.stop(l+.01)),c=!1}},t.Env.prototype.connect=function(i){this.connection=i,(i instanceof t.Oscillator||i instanceof t.SoundFile||i instanceof t.AudioIn||i instanceof t.Reverb||i instanceof t.Noise||i instanceof t.Filter||i instanceof t.Delay)&&(i=i.output.gain),i instanceof AudioParam&&i.setValueAtTime(0,e.audiocontext.currentTime),i instanceof t.Signal&&i.setValue(0),this.output.connect(i)},t.Env.prototype.disconnect=function(){this.output.disconnect()},t.Env.prototype.add=function(e){var i=new o(e),n=this.mathOps.length,s=this.output;return t.prototype._mathChain(this,i,n,s,o)},t.Env.prototype.mult=function(e){var i=new n(e),o=this.mathOps.length,s=this.output;return t.prototype._mathChain(this,i,o,s,n)},t.Env.prototype.scale=function(e,i,o,n){var r=new s(e,i,o,n),a=this.mathOps.length,u=this.output;return t.prototype._mathChain(this,r,a,u,s)},t.Env.prototype.dispose=function(){e.audiocontext.currentTime;this.disconnect();try{this.control.dispose(),this.control=null}catch(t){}for(var i=1;i<this.mathOps.length;i++)mathOps[i].dispose()}}(i,l,f,d,u);var g;g=function(){"use strict";function e(){for(var t=o.audiocontext,e=t.createBuffer(1,2048,t.sampleRate),i=e.getChannelData(0),n=0;2048>n;n++)i[n]=1;var s=t.createBufferSource();return s.buffer=e,s.loop=!0,s}var o=i;t.Pulse=function(i,n){t.Oscillator.call(this,i,"sawtooth"),this.w=n||0,this.osc2=new t.SawOsc(i),this.dNode=o.audiocontext.createDelay(),this.dcOffset=e(),this.dcGain=o.audiocontext.createGain(),this.dcOffset.connect(this.dcGain),this.dcGain.connect(this.output),this.f=i||440;var s=this.w/this.oscillator.frequency.value;this.dNode.delayTime.value=s,this.dcGain.gain.value=1.7*(.5-this.w),this.osc2.disconnect(),this.osc2.panner.disconnect(),this.osc2.amp(-1),this.osc2.output.connect(this.dNode),this.dNode.connect(this.output),this.output.gain.value=1,this.output.connect(this.panner)},t.Pulse.prototype=Object.create(t.Oscillator.prototype),t.Pulse.prototype.width=function(e){if("number"==typeof e){if(1>=e&&e>=0){this.w=e;var i=this.w/this.oscillator.frequency.value;this.dNode.delayTime.value=i}this.dcGain.gain.value=1.7*(.5-this.w)}else{e.connect(this.dNode.delayTime);var o=new t.SignalAdd(-.5);o.setInput(e),o=o.mult(-1),o=o.mult(1.7),o.connect(this.dcGain.gain)}},t.Pulse.prototype.start=function(t,i){var n=o.audiocontext.currentTime,s=i||0;if(!this.started){var r=t||this.f,a=this.oscillator.type;this.oscillator=o.audiocontext.createOscillator(),this.oscillator.frequency.setValueAtTime(r,n),this.oscillator.type=a,this.oscillator.connect(this.output),this.oscillator.start(s+n),this.osc2.oscillator=o.audiocontext.createOscillator(),this.osc2.oscillator.frequency.setValueAtTime(r,s+n),this.osc2.oscillator.type=a,this.osc2.oscillator.connect(this.osc2.output),this.osc2.start(s+n),this.freqNode=[this.oscillator.frequency,this.osc2.oscillator.frequency],this.dcOffset=e(),this.dcOffset.connect(this.dcGain),this.dcOffset.start(s+n),void 0!==this.mods&&void 0!==this.mods.frequency&&(this.mods.frequency.connect(this.freqNode[0]),this.mods.frequency.connect(this.freqNode[1])),this.started=!0,this.osc2.started=!0}},t.Pulse.prototype.stop=function(t){if(this.started){var e=t||0,i=o.audiocontext.currentTime;this.oscillator.stop(e+i),this.osc2.oscillator.stop(e+i),this.dcOffset.stop(e+i),this.started=!1,this.osc2.started=!1}},t.Pulse.prototype.freq=function(t,e,i){if("number"==typeof t){this.f=t;var n=o.audiocontext.currentTime,e=e||0,i=i||0,s=this.oscillator.frequency.value;this.oscillator.frequency.cancelScheduledValues(n),this.oscillator.frequency.setValueAtTime(s,n+i),this.oscillator.frequency.exponentialRampToValueAtTime(t,i+e+n),this.osc2.oscillator.frequency.cancelScheduledValues(n),this.osc2.oscillator.frequency.setValueAtTime(s,n+i),this.osc2.oscillator.frequency.exponentialRampToValueAtTime(t,i+e+n),this.freqMod&&(this.freqMod.output.disconnect(),this.freqMod=null)}else t.output&&(t.output.disconnect(),t.output.connect(this.oscillator.frequency),t.output.connect(this.osc2.oscillator.frequency),this.freqMod=t)}}(i,m);var T;T=function(){"use strict";var e=i;t.Noise=function(){t.Oscillator.call(this),delete this.f,delete this.freq,delete this.oscillator,this.buffer=o},t.Noise.prototype=Object.create(t.Oscillator.prototype);var o=function(){for(var t=2*e.audiocontext.sampleRate,i=e.audiocontext.createBuffer(1,t,e.audiocontext.sampleRate),o=i.getChannelData(0),n=0;t>n;n++)o[n]=2*Math.random()-1;return i.type="white",i}(),n=function(){var t,i,o,n,s,r,a,u=2*e.audiocontext.sampleRate,c=e.audiocontext.createBuffer(1,u,e.audiocontext.sampleRate),h=c.getChannelData(0);t=i=o=n=s=r=a=0;for(var p=0;u>p;p++){var l=2*Math.random()-1;t=.99886*t+.0555179*l,i=.99332*i+.0750759*l,o=.969*o+.153852*l,n=.8665*n+.3104856*l,s=.55*s+.5329522*l,r=-.7616*r-.016898*l,h[p]=t+i+o+n+s+r+a+.5362*l,h[p]*=.11,a=.115926*l}return c.type="pink",c}(),s=function(){for(var t=2*e.audiocontext.sampleRate,i=e.audiocontext.createBuffer(1,t,e.audiocontext.sampleRate),o=i.getChannelData(0),n=0,s=0;t>s;s++){var r=2*Math.random()-1;o[s]=(n+.02*r)/1.02,n=o[s],o[s]*=3.5}return i.type="brown",i}();t.Noise.prototype.setType=function(t){switch(t){case"white":this.buffer=o;break;case"pink":this.buffer=n;break;case"brown":this.buffer=s;break;default:this.buffer=o}if(this.started){var i=e.audiocontext.currentTime;this.stop(i),this.start(i+.01)}},t.Noise.prototype.getType=function(){return this.buffer.type},t.Noise.prototype.start=function(){this.started&&this.stop(),this.noise=e.audiocontext.createBufferSource(),this.noise.buffer=this.buffer,this.noise.loop=!0,this.noise.connect(this.output);var t=e.audiocontext.currentTime;this.noise.start(t),this.started=!0},t.Noise.prototype.stop=function(){var t=e.audiocontext.currentTime;this.noise&&(this.noise.stop(t),this.started=!1)},t.Noise.prototype.dispose=function(){var t=e.audiocontext.currentTime;this.noise&&(this.noise.disconnect(),this.stop(t)),this.output&&this.output.disconnect(),this.panner&&this.panner.disconnect(),this.output=null,this.panner=null,this.buffer=null,this.noise=null}}(i);var S;S=function(){"use strict";var e=i;t.AudioIn=function(){this.input=e.audiocontext.createGain(),this.output=e.audiocontext.createGain(),this.stream=null,this.mediaStream=null,this.currentSource=0,this.enabled=!1,this.amplitude=new t.Amplitude,this.output.connect(this.amplitude.input),"undefined"==typeof window.MediaStreamTrack?window.alert("This browser does not support MediaStreamTrack"):"function"==typeof window.MediaStreamTrack.getSources&&window.MediaStreamTrack.getSources(this._gotSources),e.soundArray.push(this)},t.AudioIn.prototype.start=function(){var t=this;if(e.inputSources[t.currentSource]){var i=e.inputSources[t.currentSource].id,o={audio:{optional:[{sourceId:i}]}};navigator.getUserMedia(o,this._onStream=function(i){t.stream=i,t.enabled=!0,t.mediaStream=e.audiocontext.createMediaStreamSource(i),t.mediaStream.connect(t.output),t.amplitude.setInput(t.output)},this._onStreamError=function(t){console.error(t)})}else window.navigator.getUserMedia({audio:!0},this._onStream=function(i){t.stream=i,t.enabled=!0,t.mediaStream=e.audiocontext.createMediaStreamSource(i),t.mediaStream.connect(t.output),t.amplitude.setInput(t.output)},this._onStreamError=function(t){console.error(t)})},t.AudioIn.prototype.stop=function(){this.stream&&this.stream.stop()},t.AudioIn.prototype.connect=function(t){this.output.connect(t?t.hasOwnProperty("input")?t.input:t.hasOwnProperty("analyser")?t.analyser:t:e.input)},t.AudioIn.prototype.disconnect=function(t){this.output.disconnect(t),this.output.connect(this.amplitude.input)},t.AudioIn.prototype.getLevel=function(t){return t&&(this.amplitude.smoothing=t),this.amplitude.getLevel()},t.AudioIn.prototype._gotSources=function(t){for(var e=0;e<t.length;e++){var i=t[e];if("audio"===i.kind)return i}},t.AudioIn.prototype.amp=function(t,i){if(i){var o=i||0,n=this.output.gain.value;this.output.gain.cancelScheduledValues(e.audiocontext.currentTime),this.output.gain.setValueAtTime(n,e.audiocontext.currentTime),this.output.gain.linearRampToValueAtTime(t,o+e.audiocontext.currentTime)}else this.output.gain.cancelScheduledValues(e.audiocontext.currentTime),this.output.gain.setValueAtTime(t,e.audiocontext.currentTime)},t.AudioIn.prototype.listSources=function(){return console.log("listSources is deprecated - please use AudioIn.getSources"),console.log("input sources: "),e.inputSources.length>0?e.inputSources:"This browser does not support MediaStreamTrack.getSources()"},t.AudioIn.prototype.getSources=function(t){"function"==typeof window.MediaStreamTrack.getSources?window.MediaStreamTrack.getSources(function(i){for(var o=0,n=i.length;n>o;o++){var s=i[o];"audio"===s.kind&&e.inputSources.push(s)}t(e.inputSources)}):console.log("This browser does not support MediaStreamTrack.getSources()")},t.AudioIn.prototype.setSource=function(t){var i=this;e.inputSources.length>0&&t<e.inputSources.length?(i.currentSource=t,console.log("set source to "+e.inputSources[i.currentSource].id)):console.log("unable to set input source")},t.AudioIn.prototype.dispose=function(){this.stop(),this.output&&this.output.disconnect(),this.amplitude&&this.amplitude.disconnect(),this.amplitude=null,this.output=null}}(i);var _;_=function(){"use strict";var e=i;t.Filter=function(t){this.ac=e.audiocontext,this.input=this.ac.createGain(),this.output=this.ac.createGain(),this.biquad=this.ac.createBiquadFilter(),this.input.connect(this.biquad),this.biquad.connect(this.output),this.connect(),t&&this.setType(t)},t.Filter.prototype.process=function(t,e,i){t.connect(this.input),this.set(e,i)},t.Filter.prototype.set=function(t,e,i){t&&this.freq(t,i),e&&this.res(e,i)},t.Filter.prototype.freq=function(t,e){var i=this,o=e||0;return 0>=t&&(t=1),"number"==typeof t?(i.biquad.frequency.value=t,i.biquad.frequency.cancelScheduledValues(this.ac.currentTime+.01+o),i.biquad.frequency.exponentialRampToValueAtTime(t,this.ac.currentTime+.02+o)):t&&t.connect(this.biquad.frequency),i.biquad.frequency.value},t.Filter.prototype.res=function(t,e){var i=this,o=e||0;return"number"==typeof t?(i.biquad.Q.value=t,i.biquad.Q.cancelScheduledValues(i.ac.currentTime+.01+o),i.biquad.Q.linearRampToValueAtTime(t,i.ac.currentTime+.02+o)):t&&freq.connect(this.biquad.Q),i.biquad.Q.value},t.Filter.prototype.setType=function(t){this.biquad.type=t},t.Filter.prototype.amp=function(t,i,o){var i=i||0,o=o||0,n=e.audiocontext.currentTime,s=this.output.gain.value;this.output.gain.cancelScheduledValues(n),this.output.gain.linearRampToValueAtTime(s,n+o+.001),this.output.gain.linearRampToValueAtTime(t,n+o+i+.001)},t.Filter.prototype.connect=function(e){var i=e||t.soundOut.input;this.output.connect(i)},t.Filter.prototype.disconnect=function(){this.output.disconnect()},t.LowPass=function(){t.Filter.call(this,"lowpass")},t.LowPass.prototype=Object.create(t.Filter.prototype),t.HighPass=function(){t.Filter.call(this,"highpass")},t.HighPass.prototype=Object.create(t.Filter.prototype),t.BandPass=function(){t.Filter.call(this,"bandpass")},t.BandPass.prototype=Object.create(t.Filter.prototype)}(i);var b;b=function(){"use strict";var e=i;t.Delay=function(){this.ac=e.audiocontext,this.input=this.ac.createGain(),this.output=this.ac.createGain(),this._split=this.ac.createChannelSplitter(2),this._merge=this.ac.createChannelMerger(2),this._leftGain=this.ac.createGain(),this._rightGain=this.ac.createGain(),this.leftDelay=this.ac.createDelay(),this.rightDelay=this.ac.createDelay(),this._leftFilter=new t.Filter,this._rightFilter=new t.Filter,this._leftFilter.disconnect(),this._rightFilter.disconnect(),this.lowPass=this._leftFilter,this._leftFilter.biquad.frequency.setValueAtTime(1200,this.ac.currentTime),this._rightFilter.biquad.frequency.setValueAtTime(1200,this.ac.currentTime),this._leftFilter.biquad.Q.setValueAtTime(.3,this.ac.currentTime),this._rightFilter.biquad.Q.setValueAtTime(.3,this.ac.currentTime),this.input.connect(this._split),this.leftDelay.connect(this._leftGain),this.rightDelay.connect(this._rightGain),this._leftGain.connect(this._leftFilter.input),this._rightGain.connect(this._rightFilter.input),this._merge.connect(this.output),this.output.connect(t.soundOut.input),this._leftFilter.biquad.gain.setValueAtTime(1,this.ac.currentTime),this._rightFilter.biquad.gain.setValueAtTime(1,this.ac.currentTime),this.setType(0),this._maxDelay=this.leftDelay.delayTime.maxValue},t.Delay.prototype.process=function(t,e,i,o){var n=i||0,s=e||0;if(n>=1)throw new Error("Feedback value will force a positive feedback loop.");if(s>=this._maxDelay)throw new Error("Delay Time exceeds maximum delay time of "+this._maxDelay+" second.");t.connect(this.input),this.leftDelay.delayTime.setValueAtTime(s,this.ac.currentTime),this.rightDelay.delayTime.setValueAtTime(s,this.ac.currentTime),this._leftGain.gain.setValueAtTime(n,this.ac.currentTime),this._rightGain.gain.setValueAtTime(n,this.ac.currentTime),o&&(this._leftFilter.freq(o),this._rightFilter.freq(o))},t.Delay.prototype.delayTime=function(t){"number"!=typeof t?(t.connect(this.leftDelay.delayTime),t.connect(this.rightDelay.delayTime)):(this.leftDelay.delayTime.cancelScheduledValues(this.ac.currentTime),this.rightDelay.delayTime.cancelScheduledValues(this.ac.currentTime),this.leftDelay.delayTime.linearRampToValueAtTime(t,this.ac.currentTime),this.rightDelay.delayTime.linearRampToValueAtTime(t,this.ac.currentTime))},t.Delay.prototype.feedback=function(t){if("number"!=typeof t)t.connect(this._leftGain.gain),t.connect(this._rightGain.gain);else{if(t>=1)throw new Error("Feedback value will force a positive feedback loop.");this._leftGain.gain.exponentialRampToValueAtTime(t,this.ac.currentTime),this._rightGain.gain.exponentialRampToValueAtTime(t,this.ac.currentTime)}},t.Delay.prototype.filter=function(t,e){this._leftFilter.set(t,e),this._rightFilter.set(t,e)},t.Delay.prototype.setType=function(t){switch(1===t&&(t="pingPong"),this._split.disconnect(),this._leftFilter.disconnect(),this._rightFilter.disconnect(),this._split.connect(this.leftDelay,0),this._split.connect(this.rightDelay,1),t){case"pingPong":this._rightFilter.setType(this._leftFilter.biquad.type),this._leftFilter.output.connect(this._merge,0,0),this._rightFilter.output.connect(this._merge,0,1),this._leftFilter.output.connect(this.rightDelay),this._rightFilter.output.connect(this.leftDelay);break;default:this._leftFilter.output.connect(this._merge,0,0),this._leftFilter.output.connect(this._merge,0,1),this._leftFilter.output.connect(this.leftDelay),this._leftFilter.output.connect(this.rightDelay)}},t.Delay.prototype.amp=function(t,i,o){var i=i||0,o=o||0,n=e.audiocontext.currentTime,s=this.output.gain.value;this.output.gain.cancelScheduledValues(n),this.output.gain.linearRampToValueAtTime(s,n+o+.001),this.output.gain.linearRampToValueAtTime(t,n+o+i+.001)},t.Delay.prototype.connect=function(e){var i=e||t.soundOut.input;this.output.connect(i)},t.Delay.prototype.disconnect=function(){this.output.disconnect()}}(i,_);var w;w=function(){"use strict";var e=i;t.Reverb=function(){this.ac=e.audiocontext,this.convolverNode=this.ac.createConvolver(),this.input=this.ac.createGain(),this.output=this.ac.createGain(),this.input.gain.value=.5,this.input.connect(this.convolverNode),this.convolverNode.connect(this.output),this._seconds=3,this._decay=2,this._reverse=!1,this._buildImpulse(),this.connect(),e.soundArray.push(this)},t.Reverb.prototype.process=function(t,e,i,o){t.connect(this.input);var n=!1;e&&(this._seconds=e,n=!0),i&&(this._decay=i),o&&(this._reverse=o),n&&this._buildImpulse()},t.Reverb.prototype.set=function(t,e,i){var o=!1;t&&(this._seconds=t,o=!0),e&&(this._decay=e),i&&(this._reverse=i),o&&this._buildImpulse()},t.Reverb.prototype.amp=function(t,i,o){var i=i||0,o=o||0,n=e.audiocontext.currentTime,s=this.output.gain.value;this.output.gain.cancelScheduledValues(n),this.output.gain.linearRampToValueAtTime(s,n+o+.001),this.output.gain.linearRampToValueAtTime(t,n+o+i+.001)},t.Reverb.prototype.connect=function(e){var i=e||t.soundOut.input;this.output.connect(i.input?i.input:i)},t.Reverb.prototype.disconnect=function(){this.output.disconnect()},t.Reverb.prototype._buildImpulse=function(){var t,e,i=this.ac.sampleRate,o=i*this._seconds,n=this._decay,s=this.ac.createBuffer(2,o,i),r=s.getChannelData(0),a=s.getChannelData(1);for(e=0;o>e;e++)t=this.reverse?o-e:e,r[e]=(2*Math.random()-1)*Math.pow(1-t/o,n),a[e]=(2*Math.random()-1)*Math.pow(1-t/o,n);this.convolverNode.buffer=s},t.Reverb.prototype.dispose=function(){this.convolverNode&&(this.convolverNode.buffer=null,this.convolverNode=null),"undefined"!=typeof this.output&&(this.output.disconnect(),this.output=null),"undefined"!=typeof this.panner&&(this.panner.disconnect(),this.panner=null)},t.Convolver=function(t,i){this.ac=e.audiocontext,this.convolverNode=this.ac.createConvolver(),this.input=this.ac.createGain(),this.output=this.ac.createGain(),this.input.gain.value=.5,this.input.connect(this.convolverNode),this.convolverNode.connect(this.output),t?(this.impulses=[],this._loadBuffer(t,i)):(this._seconds=3,this._decay=2,this._reverse=!1,this._buildImpulse()),this.connect(),e.soundArray.push(this)
},t.Convolver.prototype=Object.create(t.Reverb.prototype),t.prototype.registerPreloadMethod("createConvolver"),t.prototype.createConvolver=function(e,i){window.location.origin.indexOf("file://")>-1&&"undefined"===window.cordova&&alert("This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS");var o=new t.Convolver(e,i);return o.impulses=[],o},t.Convolver.prototype._loadBuffer=function(e,i){e=t.prototype._checkFileFormats(e);var o=new XMLHttpRequest;o.open("GET",e,!0),o.responseType="arraybuffer";var n=this;o.onload=function(){var s=t.prototype.getAudioContext();s.decodeAudioData(o.response,function(t){var o={},s=e.split("/");o.name=s[s.length-1],o.audioBuffer=t,n.impulses.push(o),n.convolverNode.buffer=o.audioBuffer,i&&i(o)})},o.send()},t.Convolver.prototype.set=null,t.Convolver.prototype.process=function(t){t.connect(this.input)},t.Convolver.prototype.impulses=[],t.Convolver.prototype.addImpulse=function(t,e){window.location.origin.indexOf("file://")>-1&&"undefined"===window.cordova&&alert("This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS"),this._loadBuffer(t,e)},t.Convolver.prototype.resetImpulse=function(t,e){window.location.origin.indexOf("file://")>-1&&"undefined"===window.cordova&&alert("This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS"),this.impulses=[],this._loadBuffer(t,e)},t.Convolver.prototype.toggleImpulse=function(t){if("number"==typeof t&&t<this.impulses.length&&(this.convolverNode.buffer=this.impulses[t].audioBuffer),"string"==typeof t)for(var e=0;e<this.impulses.length;e++)if(this.impulses[e].name===t){this.convolverNode.buffer=this.impulses[e].audioBuffer;break}},t.Convolver.prototype.dispose=function(){for(var t in this.impulses)this.impulses[t]=null;this.convolverNode.disconnect(),this.concolverNode=null,"undefined"!=typeof this.output&&(this.output.disconnect(),this.output=null),"undefined"!=typeof this.panner&&(this.panner.disconnect(),this.panner=null)}}(i,e);var A;A=function(t){"use strict";return t.Clock=function(e,i){this._oscillator=null,this._jsNode=this.context.createScriptProcessor(this.bufferSize,1,1),this._jsNode.onaudioprocess=this._processBuffer.bind(this),this._controlSignal=new t.Signal(1),this._upTick=!1,this.tick=this.defaultArg(i,function(){}),this._jsNode.noGC(),this.setRate(e)},t.extend(t.Clock),t.Clock.prototype.setRate=function(t,e){var i=this.secondsToFrequency(this.toSeconds(t));e?this._controlSignal.exponentialRampToValueNow(i,e):(this._controlSignal.cancelScheduledValues(0),this._controlSignal.setValue(i))},t.Clock.prototype.getRate=function(){return this._controlSignal.getValue()},t.Clock.prototype.start=function(t){this._oscillator=this.context.createOscillator(),this._oscillator.type="square",this._oscillator.connect(this._jsNode),this._controlSignal.connect(this._oscillator.frequency),this._upTick=!1;var e=this.toSeconds(t);this._oscillator.start(e),this._oscillator.onended=function(){}},t.Clock.prototype.stop=function(t,e){var i=this.toSeconds(t);this._oscillator.onended=e,this._oscillator.stop(i)},t.Clock.prototype._processBuffer=function(t){for(var e=this.defaultArg(t.playbackTime,this.now()),i=this._jsNode.bufferSize,o=t.inputBuffer.getChannelData(0),n=this._upTick,s=this,r=0;i>r;r++){var a=o[r];a>0&&!n?(n=!0,setTimeout(function(){var t=e+s.samplesToSeconds(r+2*i);return function(){s.tick(t)}}(),0)):0>a&&n&&(n=!1)}this._upTick=n},t.Clock.prototype.dispose=function(){this._jsNode.disconnect(),this._controlSignal.dispose(),this._oscillator&&(this._oscillator.onended(),this._oscillator.disconnect()),this._jsNode.onaudioprocess=function(){},this._jsNode=null,this._controlSignal=null,this._oscillator=null},t.Clock}(u);var x;x=function(){"use strict";var e=i,o=A,n=e.audiocontext;t.Metro=function(){this.clock=new o(n.sampleRate,this.ontick.bind(this)),this.syncedParts=[],this.bpm=120,this._init(),this.tickCallback=function(){}};var s=0,r=0;t.Metro.prototype.ontick=function(t){var i=t-s,o=t-e.audiocontext.currentTime;if(!(-.02>=i-r)){s=t;for(var n in this.syncedParts){var a=this.syncedParts[n];a.incrementStep(o);for(var u in a.phrases){var c=a.phrases[u],h=c.sequence,p=this.metroTicks%h.length;0!==h[p]&&(this.metroTicks<h.length||!c.looping)&&c.callback(o,h[p])}}this.metroTicks+=1,this.tickCallback(o)}},t.Metro.prototype.setBPM=function(t,i){var o=60/(t*this.tatums);r=o;this.clock.setRate(o,i+e.audiocontext.currentTime),this.bpm=t},t.Metro.prototype.getBPM=function(){return this.clock.getRate()/this.tatums*60},t.Metro.prototype._init=function(){this.metroTicks=0},t.Metro.prototype.resetSync=function(t){this.syncedParts=[t]},t.Metro.prototype.pushSync=function(t){this.syncedParts.push(t)},t.Metro.prototype.start=function(t){var e=t||0;this.clock.start(e),this.setBPM(this.bpm)},t.Metro.prototype.stop=function(t){var e=t||0;this.clock._oscillator&&this.clock.stop(e)},t.Metro.prototype.beatLength=function(t){this.tatums=1/t/4}}(i,A);var P;P=function(){"use strict";function e(t){t.currentPart++,t.currentPart>=t.parts.length?(t.scoreStep=0,t.onended()):(t.scoreStep=0,t.parts[t.currentPart-1].stop(),t.parts[t.currentPart].start())}var o=i,n=120;t.prototype.setBPM=function(t,e){n=t;for(var i in o.parts)o.parts[i].setBPM(n,e)},t.Phrase=function(t,e,i){this.phraseStep=0,this.name=t,this.callback=e,this.sequence=i},t.Part=function(e,i){this.length=e||0,this.partStep=0,this.phrases=[],this.looping=!1,this.isPlaying=!1,this.onended=function(){this.stop()},this.tatums=i||.0625,this.metro=new t.Metro,this.metro._init(),this.metro.beatLength(this.tatums),this.metro.setBPM(n),o.parts.push(this),this.callback=function(){}},t.Part.prototype.setBPM=function(t,e){this.metro.setBPM(t,e)},t.Part.prototype.getBPM=function(){return this.metro.getBPM()},t.Part.prototype.start=function(t){if(!this.isPlaying){this.isPlaying=!0,this.metro.resetSync(this);var e=t||0;this.metro.start(e)}},t.Part.prototype.loop=function(t){this.looping=!0,this.onended=function(){this.partStep=0};var e=t||0;this.start(e)},t.Part.prototype.noLoop=function(){this.looping=!1,this.onended=function(){this.stop()}},t.Part.prototype.stop=function(t){this.partStep=0,this.pause(t)},t.Part.prototype.pause=function(t){this.isPlaying=!1;var e=t||0;this.metro.stop(e)},t.Part.prototype.addPhrase=function(e,i,o){var n;if(3===arguments.length)n=new t.Phrase(e,i,o);else{if(!(arguments[0]instanceof t.Phrase))throw"invalid input. addPhrase accepts name, callback, array or a p5.Phrase";n=arguments[0]}this.phrases.push(n),n.sequence.length>this.length&&(this.length=n.sequence.length)},t.Part.prototype.removePhrase=function(t){for(var e in this.phrases)this.phrases[e].name===t&&this.phrases.split(e,1)},t.Part.prototype.getPhrase=function(t){for(var e in this.phrases)if(this.phrases[e].name===t)return this.phrases[e]},t.Part.prototype.replaceSequence=function(t,e){for(var i in this.phrases)this.phrases[i].name===t&&(this.phrases[i].sequence=e)},t.Part.prototype.incrementStep=function(t){this.partStep<this.length-1?(this.callback(t),this.partStep+=1):(this.looping&&this.callback(t),this.onended(),this.partStep=0)},t.Part.prototype.onStep=function(t){this.callback=t},t.Score=function(){this.parts=[],this.currentPart=0;var t=this;for(var i in arguments)this.parts[i]=arguments[i],this.parts[i].nextPart=this.parts[i+1],this.parts[i].onended=function(){t.resetPart(i),e(t)};this.looping=!1},t.Score.prototype.onended=function(){this.looping?this.parts[0].start():this.parts[this.parts.length-1].onended=function(){this.stop(),this.resetParts()},this.currentPart=0},t.Score.prototype.start=function(){this.parts[this.currentPart].start(),this.scoreStep=0},t.Score.prototype.stop=function(){this.parts[this.currentPart].stop(),this.currentPart=0,this.scoreStep=0},t.Score.prototype.pause=function(){this.parts[this.currentPart].stop()},t.Score.prototype.loop=function(){this.looping=!0,this.start()},t.Score.prototype.noLoop=function(){this.looping=!1},t.Score.prototype.resetParts=function(){for(var t in this.parts)this.resetPart(t)},t.Score.prototype.resetPart=function(t){this.parts[t].stop(),this.parts[t].partStep=0;for(var e in this.parts[t].phrases)this.parts[t].phrases[e].phraseStep=0},t.Score.prototype.setBPM=function(t,e){for(var i in this.parts)this.parts[i].setBPM(t,e)}}(i);var N;N=function(){"use strict";function e(t,e){for(var i=t.length+e.length,o=new Float32Array(i),n=0,s=0;i>s;)o[s++]=t[n],o[s++]=e[n],n++;return o}function o(t,e,i){for(var o=i.length,n=0;o>n;n++)t.setUint8(e+n,i.charCodeAt(n))}var n=i,s=n.audiocontext;t.SoundRecorder=function(){this.input=s.createGain(),this.output=s.createGain(),this.recording=!1,this.bufferSize=1024,this._channels=2,this._clear(),this._jsNode=s.createScriptProcessor(this.bufferSize,this._channels,2),this._jsNode.onaudioprocess=this._audioprocess.bind(this),this._callback=function(){},this._jsNode.connect(t.soundOut._silentNode),this.setInput(),n.soundArray.push(this)},t.SoundRecorder.prototype.setInput=function(e){this.input.disconnect(),this.input=null,this.input=s.createGain(),this.input.connect(this._jsNode),this.input.connect(this.output),e?e.connect(this.input):t.soundOut.output.connect(this.input)},t.SoundRecorder.prototype.record=function(t,e,i){this.recording=!0,e&&(this.sampleLimit=Math.round(e*s.sampleRate)),t&&i?this._callback=function(){this.buffer=this._getBuffer(),t.setBuffer(this.buffer),i()}:t&&(this._callback=function(){this.buffer=this._getBuffer(),t.setBuffer(this.buffer)})},t.SoundRecorder.prototype.stop=function(){this.recording=!1,this._callback(),this._clear()},t.SoundRecorder.prototype._clear=function(){this._leftBuffers=[],this._rightBuffers=[],this.recordedSamples=0,this.sampleLimit=null},t.SoundRecorder.prototype._audioprocess=function(t){if(this.recording!==!1&&this.recording===!0)if(this.sampleLimit&&this.recordedSamples>=this.sampleLimit)this.stop();else{var e=t.inputBuffer.getChannelData(0),i=t.inputBuffer.getChannelData(1);this._leftBuffers.push(new Float32Array(e)),this._rightBuffers.push(new Float32Array(i)),this.recordedSamples+=this.bufferSize}},t.SoundRecorder.prototype._getBuffer=function(){var t=[];return t.push(this._mergeBuffers(this._leftBuffers)),t.push(this._mergeBuffers(this._rightBuffers)),t},t.SoundRecorder.prototype._mergeBuffers=function(t){for(var e=new Float32Array(this.recordedSamples),i=0,o=t.length,n=0;o>n;n++){var s=t[n];e.set(s,i),i+=s.length}return e},t.SoundRecorder.prototype.dispose=function(){this._clear(),this._callback=function(){},this.input&&this.input.disconnect(),this.input=null,this._jsNode=null},t.prototype.saveSound=function(i,n){var s=i.buffer.getChannelData(0),r=i.buffer.getChannelData(1),a=e(s,r),u=new ArrayBuffer(44+2*a.length),c=new DataView(u);o(c,0,"RIFF"),c.setUint32(4,44+2*a.length,!0),o(c,8,"WAVE"),o(c,12,"fmt "),c.setUint32(16,16,!0),c.setUint16(20,1,!0),c.setUint16(22,2,!0),c.setUint32(24,44100,!0),c.setUint32(28,176400,!0),c.setUint16(32,4,!0),c.setUint16(34,16,!0),o(c,36,"data"),c.setUint32(40,2*a.length,!0);for(var h=a.length,p=44,l=1,f=0;h>f;f++)c.setInt16(p,32767*a[f]*l,!0),p+=2;t.prototype.writeFile([c],n,"wav")}}(e,i);var F;F=function(){"use strict";t.PeakDetect=function(t,e,i,o){this.framesPerPeak=o||20,this.framesSinceLastPeak=0,this.decayRate=.95,this.threshold=i||.35,this.cutoff=0,this.cutoffMult=1.5,this.energy=0,this.penergy=0,this.currentValue=0,this.isDetected=!1,this.f1=t||40,this.f2=e||2e4,this._onPeak=function(){}},t.PeakDetect.prototype.update=function(t){var e=this.energy=t.getEnergy(this.f1,this.f2)/255;e>this.cutoff&&e>this.threshold&&e-this.penergy>0?(this._onPeak(),this.isDetected=!0,this.cutoff=e*this.cutoffMult,this.framesSinceLastPeak=0):(this.isDetected=!1,this.framesSinceLastPeak<=this.framesPerPeak?this.framesSinceLastPeak++:(this.cutoff*=this.decayRate,this.cutoff=Math.max(this.cutoff,this.threshold))),this.currentValue=e,this.penergy=e},t.PeakDetect.prototype.onPeak=function(t,e){var i=this;i._onPeak=function(){t(i.energy,e)}}}(i);var V;V=function(){"use strict";var e=i;t.Gain=function(){this.ac=e.audiocontext,this.input=this.ac.createGain(),this.output=this.ac.createGain(),this.input.gain.value=.5,this.input.connect(this.output)},t.Gain.prototype.setInput=function(t){t.connect(this.input)},t.Gain.prototype.connect=function(e){var i=e||t.soundOut.input;this.output.connect(i.input?i.input:i)},t.Gain.prototype.disconnect=function(){this.output.disconnect()},t.Gain.prototype.amp=function(t,i,o){var i=i||0,o=o||0,n=e.audiocontext.currentTime,s=this.output.gain.value;this.output.gain.cancelScheduledValues(n),this.output.gain.linearRampToValueAtTime(s,n+o),this.output.gain.linearRampToValueAtTime(t,n+o+i)}}(i,e);var M;M=function(){"use strict";var t=e;return t}(e,i,o,n,s,r,a,y,m,v,g,T,S,_,b,w,x,P,N,F,V)});
var baseNote = 36;
// var noteScale = [0, 2, 4, 5, 7, 9, 10, 12];
var noteScale = [0, 2, 4, 7, 9, 12];
var octaveRange = 2;
// initialize audio components
var osc = new Tone.OmniOscillator('D2', 'sawtooth24');
var filter = new Tone.LowpassCombFilter();
filter.resonance.value = 0.2;
filter.delayTime.value = 0.2;
var gainNode = Tone.context.createGain();
var env = new Tone.Envelope({
"attack" : 0.01,
"decay" : 0.8,
"sustain" : 0.01,
"release" : 0.2,
});
env.connect(gainNode.gain);
// routing
osc.connect(gainNode);
gainNode.connect(filter);
filter.toMaster();
// start audio
osc.start();
Tone.Transport.bpm.value = 96;
// start loop
var loop = new Tone.Loop(function(time){
counter++;
curMatrixIndex = counter % (numRows * numCols);
var noteIndex = ~~map(curColor[0], 0, 0.7, 0, noteScale.length*octaveRange);
var note = noteScale[noteIndex % noteScale.length];
var root = baseNote + Math.floor(noteIndex/noteScale.length)*12;
osc.frequency.value = osc.midiToFrequency(note + root);
filter.dampening.value = map(curColor[2], 0, 1, 30, 3500);
if (curMatrixIndex !== prevMatrixIndex) {
// trigger note!
var vel = map(curColor[1], 0, 1, 0, 1);
if (vel > 0.1) {
env.triggerAttackRelease(0.2, undefined, vel);
}
}
prevMatrixIndex = curMatrixIndex;
}, "16n").start(0);
Tone.Transport.start();
html, body {
overflow: hidden;
margin: 0;
padding: 0;
/*background: #c8c5c2;*/
/*background: #AFAFAF;*/
background:#58585B;
}
#defaultCanvas {
margin-top: auto;
margin-bottom: auto;
margin-left: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
This file has been truncated, but you can view the full file.
(function (root) {
"use strict";
var Tone;
//constructs the main Tone object
function Main(func){
Tone = func();
}
//invokes each of the modules with the main Tone object as the argument
function Module(func){
func(Tone);
}
/**
* Tone.js
* @author Yotam Mann
* @license http://opensource.org/licenses/MIT MIT License
* @copyright 2014-2015 Yotam Mann
*/
Main(function () {
//////////////////////////////////////////////////////////////////////////
// WEB AUDIO CONTEXT
///////////////////////////////////////////////////////////////////////////
//borrowed from underscore.js
function isUndef(val) {
return val === void 0;
}
//borrowed from underscore.js
function isFunction(val) {
return typeof val === 'function';
}
var audioContext;
//polyfill for AudioContext and OfflineAudioContext
if (isUndef(window.AudioContext)) {
window.AudioContext = window.webkitAudioContext;
}
if (isUndef(window.OfflineAudioContext)) {
window.OfflineAudioContext = window.webkitOfflineAudioContext;
}
if (!isUndef(AudioContext)) {
audioContext = new AudioContext();
} else {
throw new Error('Web Audio is not supported in this browser');
}
//SHIMS////////////////////////////////////////////////////////////////////
if (!isFunction(AudioContext.prototype.createGain)) {
AudioContext.prototype.createGain = AudioContext.prototype.createGainNode;
}
if (!isFunction(AudioContext.prototype.createDelay)) {
AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode;
}
if (!isFunction(AudioContext.prototype.createPeriodicWave)) {
AudioContext.prototype.createPeriodicWave = AudioContext.prototype.createWaveTable;
}
if (!isFunction(AudioBufferSourceNode.prototype.start)) {
AudioBufferSourceNode.prototype.start = AudioBufferSourceNode.prototype.noteGrainOn;
}
if (!isFunction(AudioBufferSourceNode.prototype.stop)) {
AudioBufferSourceNode.prototype.stop = AudioBufferSourceNode.prototype.noteOff;
}
if (!isFunction(OscillatorNode.prototype.start)) {
OscillatorNode.prototype.start = OscillatorNode.prototype.noteOn;
}
if (!isFunction(OscillatorNode.prototype.stop)) {
OscillatorNode.prototype.stop = OscillatorNode.prototype.noteOff;
}
if (!isFunction(OscillatorNode.prototype.setPeriodicWave)) {
OscillatorNode.prototype.setPeriodicWave = OscillatorNode.prototype.setWaveTable;
}
//extend the connect function to include Tones
AudioNode.prototype._nativeConnect = AudioNode.prototype.connect;
AudioNode.prototype.connect = function (B, outNum, inNum) {
if (B.input) {
if (Array.isArray(B.input)) {
if (isUndef(inNum)) {
inNum = 0;
}
this.connect(B.input[inNum]);
} else {
this.connect(B.input, outNum, inNum);
}
} else {
try {
if (B instanceof AudioNode) {
this._nativeConnect(B, outNum, inNum);
} else {
this._nativeConnect(B, outNum);
}
} catch (e) {
throw new Error('error connecting to node: ' + B);
}
}
};
///////////////////////////////////////////////////////////////////////////
// TONE
///////////////////////////////////////////////////////////////////////////
/**
* @class Tone is the base class of all other classes. It provides
* a lot of methods and functionality to all classes that extend
* it.
*
* @constructor
* @alias Tone
* @param {number} [inputs=1] the number of input nodes
* @param {number} [outputs=1] the number of output nodes
*/
var Tone = function (inputs, outputs) {
/**
* the input node(s)
* @type {GainNode|Array}
*/
if (isUndef(inputs) || inputs === 1) {
this.input = this.context.createGain();
} else if (inputs > 1) {
this.input = new Array(inputs);
}
/**
* the output node(s)
* @type {GainNode|Array}
*/
if (isUndef(outputs) || outputs === 1) {
this.output = this.context.createGain();
} else if (outputs > 1) {
this.output = new Array(inputs);
}
};
/**
* Set the parameters at once. Either pass in an
* object mapping parameters to values, or to set a
* single parameter, by passing in a string and value.
* The last argument is an optional ramp time which
* will ramp any signal values to their destination value
* over the duration of the rampTime.
* @param {Object|string} params
* @param {number=} value
* @param {Time=} rampTime
* @returns {Tone} this
* @example
* //set values using an object
* filter.set({
* "frequency" : 300,
* "type" : highpass
* });
* @example
* filter.set("type", "highpass");
* @example
* //ramp to the value 220 over 3 seconds.
* oscillator.set({
* "frequency" : 220
* }, 3);
*/
Tone.prototype.set = function (params, value, rampTime) {
if (this.isObject(params)) {
rampTime = value;
} else if (this.isString(params)) {
var tmpObj = {};
tmpObj[params] = value;
params = tmpObj;
}
for (var attr in params) {
value = params[attr];
var parent = this;
if (attr.indexOf('.') !== -1) {
var attrSplit = attr.split('.');
for (var i = 0; i < attrSplit.length - 1; i++) {
parent = parent[attrSplit[i]];
}
attr = attrSplit[attrSplit.length - 1];
}
var param = parent[attr];
if (isUndef(param)) {
continue;
}
if (Tone.Signal && param instanceof Tone.Signal || Tone.Param && param instanceof Tone.Param) {
if (param.value !== value) {
if (isUndef(rampTime)) {
param.value = value;
} else {
param.rampTo(value, rampTime);
}
}
} else if (param instanceof AudioParam) {
if (param.value !== value) {
param.value = value;
}
} else if (param instanceof Tone) {
param.set(value);
} else if (param !== value) {
parent[attr] = value;
}
}
return this;
};
/**
* Get the object's attributes. Given no arguments get
* will return all available object properties and their corresponding
* values. Pass in a single attribute to retrieve or an array
* of attributes. The attribute strings can also include a "."
* to access deeper properties.
* @example
* osc.get();
* //returns {"type" : "sine", "frequency" : 440, ...etc}
* @example
* osc.get("type");
* //returns { "type" : "sine"}
* @example
* //use dot notation to access deep properties
* synth.get(["envelope.attack", "envelope.release"]);
* //returns {"envelope" : {"attack" : 0.2, "release" : 0.4}}
* @param {Array=|string|undefined} params the parameters to get, otherwise will return
* all available.
* @returns {Object}
*/
Tone.prototype.get = function (params) {
if (isUndef(params)) {
params = this._collectDefaults(this.constructor);
} else if (this.isString(params)) {
params = [params];
}
var ret = {};
for (var i = 0; i < params.length; i++) {
var attr = params[i];
var parent = this;
var subRet = ret;
if (attr.indexOf('.') !== -1) {
var attrSplit = attr.split('.');
for (var j = 0; j < attrSplit.length - 1; j++) {
var subAttr = attrSplit[j];
subRet[subAttr] = subRet[subAttr] || {};
subRet = subRet[subAttr];
parent = parent[subAttr];
}
attr = attrSplit[attrSplit.length - 1];
}
var param = parent[attr];
if (this.isObject(params[attr])) {
subRet[attr] = param.get();
} else if (Tone.Signal && param instanceof Tone.Signal) {
subRet[attr] = param.value;
} else if (Tone.Param && param instanceof Tone.Param) {
subRet[attr] = param.value;
} else if (param instanceof AudioParam) {
subRet[attr] = param.value;
} else if (param instanceof Tone) {
subRet[attr] = param.get();
} else if (!isFunction(param) && !isUndef(param)) {
subRet[attr] = param;
}
}
return ret;
};
/**
* collect all of the default attributes in one
* @private
* @param {function} constr the constructor to find the defaults from
* @return {Array} all of the attributes which belong to the class
*/
Tone.prototype._collectDefaults = function (constr) {
var ret = [];
if (!isUndef(constr.defaults)) {
ret = Object.keys(constr.defaults);
}
if (!isUndef(constr._super)) {
var superDefs = this._collectDefaults(constr._super);
//filter out repeats
for (var i = 0; i < superDefs.length; i++) {
if (ret.indexOf(superDefs[i]) === -1) {
ret.push(superDefs[i]);
}
}
}
return ret;
};
/**
* @returns {string} returns the name of the class as a string
*/
Tone.prototype.toString = function () {
for (var className in Tone) {
var isLetter = className[0].match(/^[A-Z]$/);
var sameConstructor = Tone[className] === this.constructor;
if (isFunction(Tone[className]) && isLetter && sameConstructor) {
return className;
}
}
return 'Tone';
};
///////////////////////////////////////////////////////////////////////////
// CLASS VARS
///////////////////////////////////////////////////////////////////////////
/**
* A static pointer to the audio context accessible as Tone.context.
* @type {AudioContext}
*/
Tone.context = audioContext;
/**
* The audio context.
* @type {AudioContext}
*/
Tone.prototype.context = Tone.context;
/**
* the default buffer size
* @type {number}
* @static
* @const
*/
Tone.prototype.bufferSize = 2048;
/**
* The delay time of a single frame (128 samples according to the spec).
* @type {number}
* @static
* @const
*/
Tone.prototype.blockTime = 128 / Tone.context.sampleRate;
///////////////////////////////////////////////////////////////////////////
// CONNECTIONS
///////////////////////////////////////////////////////////////////////////
/**
* disconnect and dispose
* @returns {Tone} this
*/
Tone.prototype.dispose = function () {
if (!this.isUndef(this.input)) {
if (this.input instanceof AudioNode) {
this.input.disconnect();
}
this.input = null;
}
if (!this.isUndef(this.output)) {
if (this.output instanceof AudioNode) {
this.output.disconnect();
}
this.output = null;
}
return this;
};
/**
* a silent connection to the DesinationNode
* which will ensure that anything connected to it
* will not be garbage collected
*
* @private
*/
var _silentNode = null;
/**
* makes a connection to ensure that the node will not be garbage collected
* until 'dispose' is explicitly called
*
* use carefully. circumvents JS and WebAudio's normal Garbage Collection behavior
* @returns {Tone} this
*/
Tone.prototype.noGC = function () {
this.output.connect(_silentNode);
return this;
};
AudioNode.prototype.noGC = function () {
this.connect(_silentNode);
return this;
};
/**
* connect the output of a ToneNode to an AudioParam, AudioNode, or ToneNode
* @param {Tone | AudioParam | AudioNode} unit
* @param {number} [outputNum=0] optionally which output to connect from
* @param {number} [inputNum=0] optionally which input to connect to
* @returns {Tone} this
*/
Tone.prototype.connect = function (unit, outputNum, inputNum) {
if (Array.isArray(this.output)) {
outputNum = this.defaultArg(outputNum, 0);
this.output[outputNum].connect(unit, 0, inputNum);
} else {
this.output.connect(unit, outputNum, inputNum);
}
return this;
};
/**
* disconnect the output
* @returns {Tone} this
*/
Tone.prototype.disconnect = function (outputNum) {
if (Array.isArray(this.output)) {
outputNum = this.defaultArg(outputNum, 0);
this.output[outputNum].disconnect();
} else {
this.output.disconnect();
}
return this;
};
/**
* connect together all of the arguments in series
* @param {...AudioParam|Tone|AudioNode} nodes
* @returns {Tone} this
*/
Tone.prototype.connectSeries = function () {
if (arguments.length > 1) {
var currentUnit = arguments[0];
for (var i = 1; i < arguments.length; i++) {
var toUnit = arguments[i];
currentUnit.connect(toUnit);
currentUnit = toUnit;
}
}
return this;
};
/**
* fan out the connection from the first argument to the rest of the arguments
* @param {...AudioParam|Tone|AudioNode} nodes
* @returns {Tone} this
*/
Tone.prototype.connectParallel = function () {
var connectFrom = arguments[0];
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
var connectTo = arguments[i];
connectFrom.connect(connectTo);
}
}
return this;
};
/**
* Connect the output of this node to the rest of the nodes in series.
* @example
* //connect a node to an effect, panVol and then to the master output
* node.chain(effect, panVol, Tone.Master);
* @param {...AudioParam|Tone|AudioNode} nodes
* @returns {Tone} this
*/
Tone.prototype.chain = function () {
if (arguments.length > 0) {
var currentUnit = this;
for (var i = 0; i < arguments.length; i++) {
var toUnit = arguments[i];
currentUnit.connect(toUnit);
currentUnit = toUnit;
}
}
return this;
};
/**
* connect the output of this node to the rest of the nodes in parallel.
* @param {...AudioParam|Tone|AudioNode} nodes
* @returns {Tone} this
*/
Tone.prototype.fan = function () {
if (arguments.length > 0) {
for (var i = 0; i < arguments.length; i++) {
this.connect(arguments[i]);
}
}
return this;
};
//give native nodes chain and fan methods
AudioNode.prototype.chain = Tone.prototype.chain;
AudioNode.prototype.fan = Tone.prototype.fan;
///////////////////////////////////////////////////////////////////////////
// UTILITIES / HELPERS / MATHS
///////////////////////////////////////////////////////////////////////////
/**
* If the `given` parameter is undefined, use the `fallback`.
* If both `given` and `fallback` are object literals, it will
* return a deep copy which includes all of the parameters from both
* objects. If a parameter is undefined in given, it will return
* the fallback property.
* <br><br>
* WARNING: if object is self referential, it will go into an an
* infinite recursive loop.
*
* @param {*} given
* @param {*} fallback
* @return {*}
*/
Tone.prototype.defaultArg = function (given, fallback) {
if (this.isObject(given) && this.isObject(fallback)) {
var ret = {};
//make a deep copy of the given object
for (var givenProp in given) {
ret[givenProp] = this.defaultArg(fallback[givenProp], given[givenProp]);
}
for (var fallbackProp in fallback) {
ret[fallbackProp] = this.defaultArg(given[fallbackProp], fallback[fallbackProp]);
}
return ret;
} else {
return isUndef(given) ? fallback : given;
}
};
/**
* returns the args as an options object with given arguments
* mapped to the names provided.
*
* if the args given is an array containing only one object, it is assumed
* that that's already the options object and will just return it.
*
* @param {Array} values the 'arguments' object of the function
* @param {Array} keys the names of the arguments as they
* should appear in the options object
* @param {Object=} defaults optional defaults to mixin to the returned
* options object
* @return {Object} the options object with the names mapped to the arguments
*/
Tone.prototype.optionsObject = function (values, keys, defaults) {
var options = {};
if (values.length === 1 && this.isObject(values[0])) {
options = values[0];
} else {
for (var i = 0; i < keys.length; i++) {
options[keys[i]] = values[i];
}
}
if (!this.isUndef(defaults)) {
return this.defaultArg(options, defaults);
} else {
return options;
}
};
///////////////////////////////////////////////////////////////////////////
// TYPE CHECKING
///////////////////////////////////////////////////////////////////////////
/**
* test if the arg is undefined
* @param {*} arg the argument to test
* @returns {boolean} true if the arg is undefined
* @function
*/
Tone.prototype.isUndef = isUndef;
/**
* test if the arg is a function
* @param {*} arg the argument to test
* @returns {boolean} true if the arg is a function
* @function
*/
Tone.prototype.isFunction = isFunction;
/**
* Test if the argument is a number.
* @param {*} arg the argument to test
* @returns {boolean} true if the arg is a number
*/
Tone.prototype.isNumber = function (arg) {
return typeof arg === 'number';
};
/**
* Test if the given argument is an object literal (i.e. `{}`);
* @param {*} arg the argument to test
* @returns {boolean} true if the arg is an object literal.
*/
Tone.prototype.isObject = function (arg) {
return Object.prototype.toString.call(arg) === '[object Object]' && arg.constructor === Object;
};
/**
* Test if the argument is a boolean.
* @param {*} arg the argument to test
* @returns {boolean} true if the arg is a boolean
*/
Tone.prototype.isBoolean = function (arg) {
return typeof arg === 'boolean';
};
/**
* Test if the argument is an Array
* @param {*} arg the argument to test
* @returns {boolean} true if the arg is an array
*/
Tone.prototype.isArray = function (arg) {
return Array.isArray(arg);
};
/**
* Test if the argument is a string.
* @param {*} arg the argument to test
* @returns {boolean} true if the arg is a string
*/
Tone.prototype.isString = function (arg) {
return typeof arg === 'string';
};
/**
* An empty function.
* @static
*/
Tone.noOp = function () {
};
/**
* Make the property not writable. Internal use only.
* @private
* @param {string} property the property to make not writable
*/
Tone.prototype._readOnly = function (property) {
if (Array.isArray(property)) {
for (var i = 0; i < property.length; i++) {
this._readOnly(property[i]);
}
} else {
Object.defineProperty(this, property, {
writable: false,
enumerable: true
});
}
};
/**
* Make an attribute writeable. Interal use only.
* @private
* @param {string} property the property to make writable
*/
Tone.prototype._writable = function (property) {
if (Array.isArray(property)) {
for (var i = 0; i < property.length; i++) {
this._writable(property[i]);
}
} else {
Object.defineProperty(this, property, { writable: true });
}
};
/**
* Possible play states.
* @enum {string}
*/
Tone.State = {
Started: 'started',
Stopped: 'stopped',
Paused: 'paused'
};
///////////////////////////////////////////////////////////////////////////
// GAIN CONVERSIONS
///////////////////////////////////////////////////////////////////////////
/**
* Equal power gain scale. Good for cross-fading.
* @param {NormalRange} percent (0-1)
* @return {Number} output gain (0-1)
*/
Tone.prototype.equalPowerScale = function (percent) {
var piFactor = 0.5 * Math.PI;
return Math.sin(percent * piFactor);
};
/**
* Convert decibels into gain.
* @param {Decibels} db
* @return {Number}
*/
Tone.prototype.dbToGain = function (db) {
return Math.pow(2, db / 6);
};
/**
* Convert gain to decibels.
* @param {Number} gain (0-1)
* @return {Decibels}
*/
Tone.prototype.gainToDb = function (gain) {
return 20 * (Math.log(gain) / Math.LN10);
};
///////////////////////////////////////////////////////////////////////////
// TIMING
///////////////////////////////////////////////////////////////////////////
/**
* Return the current time of the clock + a single buffer frame.
* If this value is used to schedule a value to change, the earliest
* it could be scheduled is the following frame.
* @return {number} the currentTime from the AudioContext
*/
Tone.prototype.now = function () {
return this.context.currentTime;
};
///////////////////////////////////////////////////////////////////////////
// INHERITANCE
///////////////////////////////////////////////////////////////////////////
/**
* have a child inherit all of Tone's (or a parent's) prototype
* to inherit the parent's properties, make sure to call
* Parent.call(this) in the child's constructor
*
* based on closure library's inherit function
*
* @static
* @param {function} child
* @param {function=} parent (optional) parent to inherit from
* if no parent is supplied, the child
* will inherit from Tone
*/
Tone.extend = function (child, parent) {
if (isUndef(parent)) {
parent = Tone;
}
function TempConstructor() {
}
TempConstructor.prototype = parent.prototype;
child.prototype = new TempConstructor();
/** @override */
child.prototype.constructor = child;
child._super = parent;
};
///////////////////////////////////////////////////////////////////////////
// CONTEXT
///////////////////////////////////////////////////////////////////////////
/**
* array of callbacks to be invoked when a new context is added
* @private
* @private
*/
var newContextCallbacks = [];
/**
* invoke this callback when a new context is added
* will be invoked initially with the first context
* @private
* @static
* @param {function(AudioContext)} callback the callback to be invoked
* with the audio context
*/
Tone._initAudioContext = function (callback) {
//invoke the callback with the existing AudioContext
callback(Tone.context);
//add it to the array
newContextCallbacks.push(callback);
};
/**
* Tone automatically creates a context on init, but if you are working
* with other libraries which also create an AudioContext, it can be
* useful to set your own. If you are going to set your own context,
* be sure to do it at the start of your code, before creating any objects.
* @static
* @param {AudioContext} ctx The new audio context to set
*/
Tone.setContext = function (ctx) {
//set the prototypes
Tone.prototype.context = ctx;
Tone.context = ctx;
//invoke all the callbacks
for (var i = 0; i < newContextCallbacks.length; i++) {
newContextCallbacks[i](ctx);
}
};
/**
* Bind this to a touchstart event to start the audio on mobile devices.
* <br>
* http://stackoverflow.com/questions/12517000/no-sound-on-ios-6-web-audio-api/12569290#12569290
* @static
*/
Tone.startMobile = function () {
var osc = Tone.context.createOscillator();
var silent = Tone.context.createGain();
silent.gain.value = 0;
osc.connect(silent);
silent.connect(Tone.context.destination);
var now = Tone.context.currentTime;
osc.start(now);
osc.stop(now + 1);
};
//setup the context
Tone._initAudioContext(function (audioContext) {
//set the blockTime
Tone.prototype.blockTime = 128 / audioContext.sampleRate;
_silentNode = audioContext.createGain();
_silentNode.gain.value = 0;
_silentNode.connect(audioContext.destination);
});
Tone.version = 'r6';
console.log('%c * Tone.js ' + Tone.version + ' * ', 'background: #000; color: #fff');
return Tone;
});
Module(function (Tone) {
/**
* @class Base class for all Signals. Used Internally.
*
* @constructor
* @extends {Tone}
*/
Tone.SignalBase = function () {
};
Tone.extend(Tone.SignalBase);
/**
* When signals connect to other signals or AudioParams,
* they take over the output value of that signal or AudioParam.
* For all other nodes, the behavior is the same as a default <code>connect</code>.
*
* @override
* @param {AudioParam|AudioNode|Tone.Signal|Tone} node
* @param {number} [outputNumber=0] The output number to connect from.
* @param {number} [inputNumber=0] The input number to connect to.
* @returns {Tone.SignalBase} this
*/
Tone.SignalBase.prototype.connect = function (node, outputNumber, inputNumber) {
//zero it out so that the signal can have full control
if (Tone.Signal && Tone.Signal === node.constructor || Tone.Param && Tone.Param === node.constructor || Tone.TimelineSignal && Tone.TimelineSignal === node.constructor) {
//cancel changes
node._param.cancelScheduledValues(0);
//reset the value
node._param.value = 0;
//mark the value as overridden
node.overridden = true;
} else if (node instanceof AudioParam) {
node.cancelScheduledValues(0);
node.value = 0;
}
Tone.prototype.connect.call(this, node, outputNumber, inputNumber);
return this;
};
return Tone.SignalBase;
});
Module(function (Tone) {
/**
* @class Wraps the native Web Audio API
* [WaveShaperNode](http://webaudio.github.io/web-audio-api/#the-waveshapernode-interface).
*
* @extends {Tone.SignalBase}
* @constructor
* @param {function|Array|Number} mapping The function used to define the values.
* The mapping function should take two arguments:
* the first is the value at the current position
* and the second is the array position.
* If the argument is an array, that array will be
* set as the wave shaping function. The input
* signal is an AudioRange [-1, 1] value and the output
* signal can take on any numerical values.
*
* @param {Number} [bufferLen=1024] The length of the WaveShaperNode buffer.
* @example
* var timesTwo = new Tone.WaveShaper(function(val){
* return val * 2;
* }, 2048);
* @example
* //a waveshaper can also be constructed with an array of values
* var invert = new Tone.WaveShaper([1, -1]);
*/
Tone.WaveShaper = function (mapping, bufferLen) {
/**
* the waveshaper
* @type {WaveShaperNode}
* @private
*/
this._shaper = this.input = this.output = this.context.createWaveShaper();
/**
* the waveshapers curve
* @type {Float32Array}
* @private
*/
this._curve = null;
if (Array.isArray(mapping)) {
this.curve = mapping;
} else if (isFinite(mapping) || this.isUndef(mapping)) {
this._curve = new Float32Array(this.defaultArg(mapping, 1024));
} else if (this.isFunction(mapping)) {
this._curve = new Float32Array(this.defaultArg(bufferLen, 1024));
this.setMap(mapping);
}
};
Tone.extend(Tone.WaveShaper, Tone.SignalBase);
/**
* Uses a mapping function to set the value of the curve.
* @param {function} mapping The function used to define the values.
* The mapping function take two arguments:
* the first is the value at the current position
* which goes from -1 to 1 over the number of elements
* in the curve array. The second argument is the array position.
* @returns {Tone.WaveShaper} this
* @example
* //map the input signal from [-1, 1] to [0, 10]
* shaper.setMap(function(val, index){
* return (val + 1) * 5;
* })
*/
Tone.WaveShaper.prototype.setMap = function (mapping) {
for (var i = 0, len = this._curve.length; i < len; i++) {
var normalized = i / len * 2 - 1;
this._curve[i] = mapping(normalized, i);
}
this._shaper.curve = this._curve;
return this;
};
/**
* The array to set as the waveshaper curve. For linear curves
* array length does not make much difference, but for complex curves
* longer arrays will provide smoother interpolation.
* @memberOf Tone.WaveShaper#
* @type {Array}
* @name curve
*/
Object.defineProperty(Tone.WaveShaper.prototype, 'curve', {
get: function () {
return this._shaper.curve;
},
set: function (mapping) {
this._curve = new Float32Array(mapping);
this._shaper.curve = this._curve;
}
});
/**
* Specifies what type of oversampling (if any) should be used when
* applying the shaping curve. Can either be "none", "2x" or "4x".
* @memberOf Tone.WaveShaper#
* @type {string}
* @name oversample
*/
Object.defineProperty(Tone.WaveShaper.prototype, 'oversample', {
get: function () {
return this._shaper.oversample;
},
set: function (oversampling) {
if ([
'none',
'2x',
'4x'
].indexOf(oversampling) !== -1) {
this._shaper.oversample = oversampling;
} else {
throw new Error('invalid oversampling: ' + oversampling);
}
}
});
/**
* Clean up.
* @returns {Tone.WaveShaper} this
*/
Tone.WaveShaper.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._shaper.disconnect();
this._shaper = null;
this._curve = null;
return this;
};
return Tone.WaveShaper;
});
Module(function (Tone) {
///////////////////////////////////////////////////////////////////////////
// TYPES
///////////////////////////////////////////////////////////////////////////
/**
* Units which a value can take on.
* @enum {String}
*/
Tone.Type = {
/**
* The default value is a number which can take on any value between [-Infinity, Infinity]
*/
Default: 'number',
/**
* Time can be described in a number of ways. Read more [Time](https://github.com/Tonejs/Tone.js/wiki/Time).
*
* <ul>
* <li>Numbers, which will be taken literally as the time (in seconds).</li>
* <li>Notation, ("4n", "8t") describes time in BPM and time signature relative values.</li>
* <li>TransportTime, ("4:3:2") will also provide tempo and time signature relative times
* in the form BARS:QUARTERS:SIXTEENTHS.</li>
* <li>Frequency, ("8hz") is converted to the length of the cycle in seconds.</li>
* <li>Now-Relative, ("+1") prefix any of the above with "+" and it will be interpreted as
* "the current time plus whatever expression follows".</li>
* <li>Expressions, ("3:0 + 2 - (1m / 7)") any of the above can also be combined
* into a mathematical expression which will be evaluated to compute the desired time.</li>
* <li>No Argument, for methods which accept time, no argument will be interpreted as
* "now" (i.e. the currentTime).</li>
* </ul>
*
* @typedef {Time}
*/
Time: 'time',
/**
* Frequency can be described similar to time, except ultimately the
* values are converted to frequency instead of seconds. A number
* is taken literally as the value in hertz. Additionally any of the
* Time encodings can be used. Note names in the form
* of NOTE OCTAVE (i.e. C4) are also accepted and converted to their
* frequency value.
* @typedef {Frequency}
*/
Frequency: 'frequency',
/**
* Normal values are within the range [0, 1].
* @typedef {NormalRange}
*/
NormalRange: 'normalRange',
/**
* AudioRange values are between [-1, 1].
* @typedef {AudioRange}
*/
AudioRange: 'audioRange',
/**
* Decibels are a logarithmic unit of measurement which is useful for volume
* because of the logarithmic way that we perceive loudness. 0 decibels
* means no change in volume. -10db is approximately half as loud and 10db
* is twice is loud.
* @typedef {Decibels}
*/
Decibels: 'db',
/**
* Half-step note increments, i.e. 12 is an octave above the root. and 1 is a half-step up.
* @typedef {Interval}
*/
Interval: 'interval',
/**
* Beats per minute.
* @typedef {BPM}
*/
BPM: 'bpm',
/**
* The value must be greater than or equal to 0.
* @typedef {Positive}
*/
Positive: 'positive',
/**
* A cent is a hundredth of a semitone.
* @typedef {Cents}
*/
Cents: 'cents',
/**
* Angle between 0 and 360.
* @typedef {Degrees}
*/
Degrees: 'degrees',
/**
* A number representing a midi note.
* @typedef {MIDI}
*/
MIDI: 'midi',
/**
* A colon-separated representation of time in the form of
* BARS:QUARTERS:SIXTEENTHS.
* @typedef {TransportTime}
*/
TransportTime: 'transportTime',
/**
* Ticks are the basic subunit of the Transport. They are
* the smallest unit of time that the Transport supports.
* @typedef {Ticks}
*/
Ticks: 'tick',
/**
* A frequency represented by a letter name,
* accidental and octave. This system is known as
* [Scientific Pitch Notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation).
* @typedef {Note}
*/
Note: 'note',
/**
* One millisecond is a thousandth of a second.
* @typedef {Milliseconds}
*/
Milliseconds: 'milliseconds',
/**
* A string representing a duration relative to a measure.
* <ul>
* <li>"4n" = quarter note</li>
* <li>"2m" = two measures</li>
* <li>"8t" = eighth-note triplet</li>
* </ul>
* @typedef {Notation}
*/
Notation: 'notation'
};
///////////////////////////////////////////////////////////////////////////
// MATCHING TESTS
///////////////////////////////////////////////////////////////////////////
/**
* Test if a function is "now-relative", i.e. starts with "+".
*
* @param {String} str The string to test
* @return {boolean}
* @method isNowRelative
* @lends Tone.prototype.isNowRelative
*/
Tone.prototype.isNowRelative = function () {
var nowRelative = new RegExp(/^\s*\+(.)+/i);
return function (note) {
return nowRelative.test(note);
};
}();
/**
* Tests if a string is in Ticks notation.
*
* @param {String} str The string to test
* @return {boolean}
* @method isTicks
* @lends Tone.prototype.isTicks
*/
Tone.prototype.isTicks = function () {
var tickFormat = new RegExp(/^\d+i$/i);
return function (note) {
return tickFormat.test(note);
};
}();
/**
* Tests if a string is musical notation.
* i.e.:
* <ul>
* <li>4n = quarter note</li>
* <li>2m = two measures</li>
* <li>8t = eighth-note triplet</li>
* </ul>
*
* @param {String} str The string to test
* @return {boolean}
* @method isNotation
* @lends Tone.prototype.isNotation
*/
Tone.prototype.isNotation = function () {
var notationFormat = new RegExp(/^[0-9]+[mnt]$/i);
return function (note) {
return notationFormat.test(note);
};
}();
/**
* Test if a string is in the transportTime format.
* "Bars:Beats:Sixteenths"
* @param {String} transportTime
* @return {boolean}
* @method isTransportTime
* @lends Tone.prototype.isTransportTime
*/
Tone.prototype.isTransportTime = function () {
var transportTimeFormat = new RegExp(/^(\d+(\.\d+)?\:){1,2}(\d+(\.\d+)?)?$/i);
return function (transportTime) {
return transportTimeFormat.test(transportTime);
};
}();
/**
* Test if a string is in Scientific Pitch Notation: i.e. "C4".
* @param {String} note The note to test
* @return {boolean} true if it's in the form of a note
* @method isNote
* @lends Tone.prototype.isNote
* @function
*/
Tone.prototype.isNote = function () {
var noteFormat = new RegExp(/^[a-g]{1}(b|#|x|bb)?-?[0-9]+$/i);
return function (note) {
return noteFormat.test(note);
};
}();
/**
* Test if the input is in the format of number + hz
* i.e.: 10hz
*
* @param {String} freq
* @return {boolean}
* @function
*/
Tone.prototype.isFrequency = function () {
var freqFormat = new RegExp(/^\d*\.?\d+hz$/i);
return function (freq) {
return freqFormat.test(freq);
};
}();
///////////////////////////////////////////////////////////////////////////
// TO SECOND CONVERSIONS
///////////////////////////////////////////////////////////////////////////
/**
* @private
* @return {Object} The Transport's BPM if the Transport exists,
* otherwise returns reasonable defaults.
*/
function getTransportBpm() {
if (Tone.Transport && Tone.Transport.bpm) {
return Tone.Transport.bpm.value;
} else {
return 120;
}
}
/**
* @private
* @return {Object} The Transport's Time Signature if the Transport exists,
* otherwise returns reasonable defaults.
*/
function getTransportTimeSignature() {
if (Tone.Transport && Tone.Transport.timeSignature) {
return Tone.Transport.timeSignature;
} else {
return 4;
}
}
/**
*
* convert notation format strings to seconds
*
* @param {String} notation
* @param {BPM=} bpm
* @param {number=} timeSignature
* @return {number}
*
*/
Tone.prototype.notationToSeconds = function (notation, bpm, timeSignature) {
bpm = this.defaultArg(bpm, getTransportBpm());
timeSignature = this.defaultArg(timeSignature, getTransportTimeSignature());
var beatTime = 60 / bpm;
//special case: 1n = 1m
if (notation === '1n') {
notation = '1m';
}
var subdivision = parseInt(notation, 10);
var beats = 0;
if (subdivision === 0) {
beats = 0;
}
var lastLetter = notation.slice(-1);
if (lastLetter === 't') {
beats = 4 / subdivision * 2 / 3;
} else if (lastLetter === 'n') {
beats = 4 / subdivision;
} else if (lastLetter === 'm') {
beats = subdivision * timeSignature;
} else {
beats = 0;
}
return beatTime * beats;
};
/**
* convert transportTime into seconds.
*
* ie: 4:2:3 == 4 measures + 2 quarters + 3 sixteenths
*
* @param {TransportTime} transportTime
* @param {BPM=} bpm
* @param {number=} timeSignature
* @return {number} seconds
*/
Tone.prototype.transportTimeToSeconds = function (transportTime, bpm, timeSignature) {
bpm = this.defaultArg(bpm, getTransportBpm());
timeSignature = this.defaultArg(timeSignature, getTransportTimeSignature());
var measures = 0;
var quarters = 0;
var sixteenths = 0;
var split = transportTime.split(':');
if (split.length === 2) {
measures = parseFloat(split[0]);
quarters = parseFloat(split[1]);
} else if (split.length === 1) {
quarters = parseFloat(split[0]);
} else if (split.length === 3) {
measures = parseFloat(split[0]);
quarters = parseFloat(split[1]);
sixteenths = parseFloat(split[2]);
}
var beats = measures * timeSignature + quarters + sixteenths / 4;
return beats * (60 / bpm);
};
/**
* Convert ticks into seconds
* @param {Ticks} ticks
* @param {BPM=} bpm
* @return {number} seconds
*/
Tone.prototype.ticksToSeconds = function (ticks, bpm) {
if (this.isUndef(Tone.Transport)) {
return 0;
}
ticks = parseFloat(ticks);
bpm = this.defaultArg(bpm, getTransportBpm());
var tickTime = 60 / bpm / Tone.Transport.PPQ;
return tickTime * ticks;
};
/**
* Convert a frequency into seconds.
* Accepts numbers and strings: i.e. "10hz" or
* 10 both return 0.1.
*
* @param {Frequency} freq
* @return {number}
*/
Tone.prototype.frequencyToSeconds = function (freq) {
return 1 / parseFloat(freq);
};
/**
* Convert a sample count to seconds.
* @param {number} samples
* @return {number}
*/
Tone.prototype.samplesToSeconds = function (samples) {
return samples / this.context.sampleRate;
};
/**
* Convert from seconds to samples.
* @param {number} seconds
* @return {number} The number of samples
*/
Tone.prototype.secondsToSamples = function (seconds) {
return seconds * this.context.sampleRate;
};
///////////////////////////////////////////////////////////////////////////
// FROM SECOND CONVERSIONS
///////////////////////////////////////////////////////////////////////////
/**
* Convert seconds to transportTime in the form
* "measures:quarters:sixteenths"
*
* @param {Number} seconds
* @param {BPM=} bpm
* @param {Number=} timeSignature
* @return {TransportTime}
*/
Tone.prototype.secondsToTransportTime = function (seconds, bpm, timeSignature) {
bpm = this.defaultArg(bpm, getTransportBpm());
timeSignature = this.defaultArg(timeSignature, getTransportTimeSignature());
var quarterTime = 60 / bpm;
var quarters = seconds / quarterTime;
var measures = Math.floor(quarters / timeSignature);
var sixteenths = quarters % 1 * 4;
quarters = Math.floor(quarters) % timeSignature;
var progress = [
measures,
quarters,
sixteenths
];
return progress.join(':');
};
/**
* Convert a number in seconds to a frequency.
* @param {number} seconds
* @return {number}
*/
Tone.prototype.secondsToFrequency = function (seconds) {
return 1 / seconds;
};
///////////////////////////////////////////////////////////////////////////
// GENERALIZED CONVERSIONS
///////////////////////////////////////////////////////////////////////////
/**
* Convert seconds to the closest transportTime in the form
* measures:quarters:sixteenths
*
* @method toTransportTime
*
* @param {Time} time
* @param {BPM=} bpm
* @param {number=} timeSignature
* @return {TransportTime}
*
* @lends Tone.prototype.toTransportTime
*/
Tone.prototype.toTransportTime = function (time, bpm, timeSignature) {
var seconds = this.toSeconds(time);
return this.secondsToTransportTime(seconds, bpm, timeSignature);
};
/**
* Convert a frequency representation into a number.
*
* @param {Frequency} freq
* @param {number=} now if passed in, this number will be
* used for all 'now' relative timings
* @return {number} the frequency in hertz
*/
Tone.prototype.toFrequency = function (freq, now) {
if (this.isFrequency(freq)) {
return parseFloat(freq);
} else if (this.isNotation(freq) || this.isTransportTime(freq)) {
return this.secondsToFrequency(this.toSeconds(freq, now));
} else if (this.isNote(freq)) {
return this.noteToFrequency(freq);
} else {
return freq;
}
};
/**
* Convert the time representation into ticks.
* Now-Relative timing will be relative to the current
* Tone.Transport.ticks.
* @param {Time} time
* @return {Ticks}
*/
Tone.prototype.toTicks = function (time) {
if (this.isUndef(Tone.Transport)) {
return 0;
}
var bpm = Tone.Transport.bpm.value;
//get the seconds
var plusNow = 0;
if (this.isNowRelative(time)) {
time = time.replace('+', '');
plusNow = Tone.Transport.ticks;
} else if (this.isUndef(time)) {
return Tone.Transport.ticks;
}
var seconds = this.toSeconds(time);
var quarter = 60 / bpm;
var quarters = seconds / quarter;
var tickNum = quarters * Tone.Transport.PPQ;
//align the tick value
return Math.round(tickNum + plusNow);
};
/**
* convert a time into samples
*
* @param {Time} time
* @return {number}
*/
Tone.prototype.toSamples = function (time) {
var seconds = this.toSeconds(time);
return Math.round(seconds * this.context.sampleRate);
};
/**
* Convert Time into seconds.
*
* Unlike the method which it overrides, this takes into account
* transporttime and musical notation.
*
* Time : 1.40
* Notation: 4n|1m|2t
* TransportTime: 2:4:1 (measure:quarters:sixteens)
* Now Relative: +3n
* Math: 3n+16n or even complicated expressions ((3n*2)/6 + 1)
*
* @override
* @param {Time} time
* @param {number=} now if passed in, this number will be
* used for all 'now' relative timings
* @return {number}
*/
Tone.prototype.toSeconds = function (time, now) {
now = this.defaultArg(now, this.now());
if (this.isNumber(time)) {
return time; //assuming that it's seconds
} else if (this.isString(time)) {
var plusTime = 0;
if (this.isNowRelative(time)) {
time = time.replace('+', '');
plusTime = now;
}
var betweenParens = time.match(/\(([^)(]+)\)/g);
if (betweenParens) {
//evaluate the expressions between the parenthesis
for (var j = 0; j < betweenParens.length; j++) {
//remove the parens
var symbol = betweenParens[j].replace(/[\(\)]/g, '');
var symbolVal = this.toSeconds(symbol);
time = time.replace(betweenParens[j], symbolVal);
}
}
//test if it is quantized
if (time.indexOf('@') !== -1) {
var quantizationSplit = time.split('@');
if (!this.isUndef(Tone.Transport)) {
var toQuantize = quantizationSplit[0].trim();
//if there's no argument it should be evaluated as the current time
if (toQuantize === '') {
toQuantize = undefined;
}
//if it's now-relative, it should be evaluated by `quantize`
if (plusTime > 0) {
toQuantize = '+' + toQuantize;
plusTime = 0;
}
var subdivision = quantizationSplit[1].trim();
time = Tone.Transport.quantize(toQuantize, subdivision);
} else {
throw new Error('quantization requires Tone.Transport');
}
} else {
var components = time.split(/[\(\)\-\+\/\*]/);
if (components.length > 1) {
var originalTime = time;
for (var i = 0; i < components.length; i++) {
var symb = components[i].trim();
if (symb !== '') {
var val = this.toSeconds(symb);
time = time.replace(symb, val);
}
}
try {
//eval is evil
time = eval(time); // jshint ignore:line
} catch (e) {
throw new EvalError('cannot evaluate Time: ' + originalTime);
}
} else if (this.isNotation(time)) {
time = this.notationToSeconds(time);
} else if (this.isTransportTime(time)) {
time = this.transportTimeToSeconds(time);
} else if (this.isFrequency(time)) {
time = this.frequencyToSeconds(time);
} else if (this.isTicks(time)) {
time = this.ticksToSeconds(time);
} else {
time = parseFloat(time);
}
}
return time + plusTime;
} else {
return now;
}
};
/**
* Convert a Time to Notation. Values will be thresholded to the nearest 128th note.
* @param {Time} time
* @param {BPM=} bpm
* @param {number=} timeSignature
* @return {Notation}
*/
Tone.prototype.toNotation = function (time, bpm, timeSignature) {
var testNotations = [
'1m',
'2n',
'4n',
'8n',
'16n',
'32n',
'64n',
'128n'
];
var retNotation = toNotationHelper.call(this, time, bpm, timeSignature, testNotations);
//try the same thing but with tripelets
var testTripletNotations = [
'1m',
'2n',
'2t',
'4n',
'4t',
'8n',
'8t',
'16n',
'16t',
'32n',
'32t',
'64n',
'64t',
'128n'
];
var retTripletNotation = toNotationHelper.call(this, time, bpm, timeSignature, testTripletNotations);
//choose the simpler expression of the two
if (retTripletNotation.split('+').length < retNotation.split('+').length) {
return retTripletNotation;
} else {
return retNotation;
}
};
/**
* Helper method for Tone.toNotation
* @private
*/
function toNotationHelper(time, bpm, timeSignature, testNotations) {
var seconds = this.toSeconds(time);
var threshold = this.notationToSeconds(testNotations[testNotations.length - 1], bpm, timeSignature);
var retNotation = '';
for (var i = 0; i < testNotations.length; i++) {
var notationTime = this.notationToSeconds(testNotations[i], bpm, timeSignature);
//account for floating point errors (i.e. round up if the value is 0.999999)
var multiple = seconds / notationTime;
var floatingPointError = 0.000001;
if (1 - multiple % 1 < floatingPointError) {
multiple += floatingPointError;
}
multiple = Math.floor(multiple);
if (multiple > 0) {
if (multiple === 1) {
retNotation += testNotations[i];
} else {
retNotation += multiple.toString() + '*' + testNotations[i];
}
seconds -= multiple * notationTime;
if (seconds < threshold) {
break;
} else {
retNotation += ' + ';
}
}
}
if (retNotation === '') {
retNotation = '0';
}
return retNotation;
}
/**
* Convert the given value from the type specified by units
* into a number.
* @param {*} val the value to convert
* @return {Number} the number which the value should be set to
*/
Tone.prototype.fromUnits = function (val, units) {
if (this.convert || this.isUndef(this.convert)) {
switch (units) {
case Tone.Type.Time:
return this.toSeconds(val);
case Tone.Type.Frequency:
return this.toFrequency(val);
case Tone.Type.Decibels:
return this.dbToGain(val);
case Tone.Type.NormalRange:
return Math.min(Math.max(val, 0), 1);
case Tone.Type.AudioRange:
return Math.min(Math.max(val, -1), 1);
case Tone.Type.Positive:
return Math.max(val, 0);
default:
return val;
}
} else {
return val;
}
};
/**
* Convert a number to the specified units.
* @param {number} val the value to convert
* @return {number}
*/
Tone.prototype.toUnits = function (val, units) {
if (this.convert || this.isUndef(this.convert)) {
switch (units) {
case Tone.Type.Decibels:
return this.gainToDb(val);
default:
return val;
}
} else {
return val;
}
};
///////////////////////////////////////////////////////////////////////////
// FREQUENCY CONVERSIONS
///////////////////////////////////////////////////////////////////////////
/**
* Note to scale index
* @type {Object}
*/
var noteToScaleIndex = {
'cbb': -2,
'cb': -1,
'c': 0,
'c#': 1,
'cx': 2,
'dbb': 0,
'db': 1,
'd': 2,
'd#': 3,
'dx': 4,
'ebb': 2,
'eb': 3,
'e': 4,
'e#': 5,
'ex': 6,
'fbb': 3,
'fb': 4,
'f': 5,
'f#': 6,
'fx': 7,
'gbb': 5,
'gb': 6,
'g': 7,
'g#': 8,
'gx': 9,
'abb': 7,
'ab': 8,
'a': 9,
'a#': 10,
'ax': 11,
'bbb': 9,
'bb': 10,
'b': 11,
'b#': 12,
'bx': 13
};
/**
* scale index to note (sharps)
* @type {Array}
*/
var scaleIndexToNote = [
'C',
'C#',
'D',
'D#',
'E',
'F',
'F#',
'G',
'G#',
'A',
'A#',
'B'
];
/**
* The [concert pitch](https://en.wikipedia.org/wiki/Concert_pitch,
* A4's values in Hertz.
* @type {Frequency}
* @static
*/
Tone.A4 = 440;
/**
* Convert a note name to frequency.
* @param {String} note
* @return {number}
* @example
* var freq = tone.noteToFrequency("A4"); //returns 440
*/
Tone.prototype.noteToFrequency = function (note) {
//break apart the note by frequency and octave
var parts = note.split(/(-?\d+)/);
if (parts.length === 3) {
var index = noteToScaleIndex[parts[0].toLowerCase()];
var octave = parts[1];
var noteNumber = index + (parseInt(octave, 10) + 1) * 12;
return this.midiToFrequency(noteNumber);
} else {
return 0;
}
};
/**
* Convert a frequency to a note name (i.e. A4, C#5).
* @param {number} freq
* @return {String}
*/
Tone.prototype.frequencyToNote = function (freq) {
var log = Math.log(freq / Tone.A4) / Math.LN2;
var noteNumber = Math.round(12 * log) + 57;
var octave = Math.floor(noteNumber / 12);
if (octave < 0) {
noteNumber += -12 * octave;
}
var noteName = scaleIndexToNote[noteNumber % 12];
return noteName + octave.toString();
};
/**
* Convert an interval (in semitones) to a frequency ratio.
*
* @param {Interval} interval the number of semitones above the base note
* @return {number} the frequency ratio
* @example
* tone.intervalToFrequencyRatio(0); // returns 1
* tone.intervalToFrequencyRatio(12); // returns 2
*/
Tone.prototype.intervalToFrequencyRatio = function (interval) {
return Math.pow(2, interval / 12);
};
/**
* Convert a midi note number into a note name.
*
* @param {MIDI} midiNumber the midi note number
* @return {String} the note's name and octave
* @example
* tone.midiToNote(60); // returns "C3"
*/
Tone.prototype.midiToNote = function (midiNumber) {
var octave = Math.floor(midiNumber / 12) - 1;
var note = midiNumber % 12;
return scaleIndexToNote[note] + octave;
};
/**
* Convert a note to it's midi value.
*
* @param {String} note the note name (i.e. "C3")
* @return {MIDI} the midi value of that note
* @example
* tone.noteToMidi("C3"); // returns 60
*/
Tone.prototype.noteToMidi = function (note) {
//break apart the note by frequency and octave
var parts = note.split(/(\d+)/);
if (parts.length === 3) {
var index = noteToScaleIndex[parts[0].toLowerCase()];
var octave = parts[1];
return index + (parseInt(octave, 10) + 1) * 12;
} else {
return 0;
}
};
/**
* Convert a MIDI note to frequency value.
*
* @param {MIDI} midi The midi number to convert.
* @return {Frequency} the corresponding frequency value
* @example
* tone.midiToFrequency(57); // returns 440
*/
Tone.prototype.midiToFrequency = function (midi) {
return Tone.A4 * Math.pow(2, (midi - 69) / 12);
};
return Tone;
});
Module(function (Tone) {
/**
* @class Tone.Param wraps the native Web Audio's AudioParam to provide
* additional unit conversion functionality. It also
* serves as a base-class for classes which have a single,
* automatable parameter.
* @extends {Tone}
* @param {AudioParam} param The parameter to wrap.
* @param {Tone.Type} units The units of the audio param.
* @param {Boolean} convert If the param should be converted.
*/
Tone.Param = function () {
var options = this.optionsObject(arguments, [
'param',
'units',
'convert'
], Tone.Param.defaults);
/**
* The native parameter to control
* @type {AudioParam}
* @private
*/
this._param = this.input = options.param;
/**
* The units of the parameter
* @type {Tone.Type}
*/
this.units = options.units;
/**
* If the value should be converted or not
* @type {Boolean}
*/
this.convert = options.convert;
/**
* True if the signal value is being overridden by
* a connected signal.
* @readOnly
* @type {boolean}
* @private
*/
this.overridden = false;
if (!this.isUndef(options.value)) {
this.value = options.value;
}
};
Tone.extend(Tone.Param);
/**
* Defaults
* @type {Object}
* @const
*/
Tone.Param.defaults = {
'units': Tone.Type.Default,
'convert': true,
'param': undefined
};
/**
* The current value of the parameter.
* @memberOf Tone.Param#
* @type {Number}
* @name value
*/
Object.defineProperty(Tone.Param.prototype, 'value', {
get: function () {
return this._toUnits(this._param.value);
},
set: function (value) {
var convertedVal = this._fromUnits(value);
this._param.value = convertedVal;
}
});
/**
* Convert the given value from the type specified by Tone.Param.units
* into the destination value (such as Gain or Frequency).
* @private
* @param {*} val the value to convert
* @return {number} the number which the value should be set to
*/
Tone.Param.prototype._fromUnits = function (val) {
if (this.convert || this.isUndef(this.convert)) {
switch (this.units) {
case Tone.Type.Time:
return this.toSeconds(val);
case Tone.Type.Frequency:
return this.toFrequency(val);
case Tone.Type.Decibels:
return this.dbToGain(val);
case Tone.Type.NormalRange:
return Math.min(Math.max(val, 0), 1);
case Tone.Type.AudioRange:
return Math.min(Math.max(val, -1), 1);
case Tone.Type.Positive:
return Math.max(val, 0);
default:
return val;
}
} else {
return val;
}
};
/**
* Convert the parameters value into the units specified by Tone.Param.units.
* @private
* @param {number} val the value to convert
* @return {number}
*/
Tone.Param.prototype._toUnits = function (val) {
if (this.convert || this.isUndef(this.convert)) {
switch (this.units) {
case Tone.Type.Decibels:
return this.gainToDb(val);
default:
return val;
}
} else {
return val;
}
};
/**
* the minimum output value
* @type {Number}
* @private
*/
Tone.Param.prototype._minOutput = 0.00001;
/**
* Schedules a parameter value change at the given time.
* @param {*} value The value to set the signal.
* @param {Time} time The time when the change should occur.
* @returns {Tone.Param} this
* @example
* //set the frequency to "G4" in exactly 1 second from now.
* freq.setValueAtTime("G4", "+1");
*/
Tone.Param.prototype.setValueAtTime = function (value, time) {
value = this._fromUnits(value);
this._param.setValueAtTime(value, this.toSeconds(time));
return this;
};
/**
* Creates a schedule point with the current value at the current time.
* This is useful for creating an automation anchor point in order to
* schedule changes from the current value.
*
* @param {number=} now (Optionally) pass the now value in.
* @returns {Tone.Param} this
*/
Tone.Param.prototype.setRampPoint = function (now) {
now = this.defaultArg(now, this.now());
var currentVal = this._param.value;
this._param.setValueAtTime(currentVal, now);
return this;
};
/**
* Schedules a linear continuous change in parameter value from the
* previous scheduled parameter value to the given value.
*
* @param {number} value
* @param {Time} endTime
* @returns {Tone.Param} this
*/
Tone.Param.prototype.linearRampToValueAtTime = function (value, endTime) {
value = this._fromUnits(value);
this._param.linearRampToValueAtTime(value, this.toSeconds(endTime));
return this;
};
/**
* Schedules an exponential continuous change in parameter value from
* the previous scheduled parameter value to the given value.
*
* @param {number} value
* @param {Time} endTime
* @returns {Tone.Param} this
*/
Tone.Param.prototype.exponentialRampToValueAtTime = function (value, endTime) {
value = this._fromUnits(value);
value = Math.max(this._minOutput, value);
this._param.exponentialRampToValueAtTime(value, this.toSeconds(endTime));
return this;
};
/**
* Schedules an exponential continuous change in parameter value from
* the current time and current value to the given value over the
* duration of the rampTime.
*
* @param {number} value The value to ramp to.
* @param {Time} rampTime the time that it takes the
* value to ramp from it's current value
* @returns {Tone.Param} this
* @example
* //exponentially ramp to the value 2 over 4 seconds.
* signal.exponentialRampToValue(2, 4);
*/
Tone.Param.prototype.exponentialRampToValue = function (value, rampTime) {
var now = this.now();
// exponentialRampToValueAt cannot ever ramp from 0, apparently.
// More info: https://bugzilla.mozilla.org/show_bug.cgi?id=1125600#c2
var currentVal = this.value;
this.setValueAtTime(Math.max(currentVal, this._minOutput), now);
this.exponentialRampToValueAtTime(value, now + this.toSeconds(rampTime));
return this;
};
/**
* Schedules an linear continuous change in parameter value from
* the current time and current value to the given value over the
* duration of the rampTime.
*
* @param {number} value The value to ramp to.
* @param {Time} rampTime the time that it takes the
* value to ramp from it's current value
* @returns {Tone.Param} this
* @example
* //linearly ramp to the value 4 over 3 seconds.
* signal.linearRampToValue(4, 3);
*/
Tone.Param.prototype.linearRampToValue = function (value, rampTime) {
var now = this.now();
this.setRampPoint(now);
this.linearRampToValueAtTime(value, now + this.toSeconds(rampTime));
return this;
};
/**
* Start exponentially approaching the target value at the given time with
* a rate having the given time constant.
* @param {number} value
* @param {Time} startTime
* @param {number} timeConstant
* @returns {Tone.Param} this
*/
Tone.Param.prototype.setTargetAtTime = function (value, startTime, timeConstant) {
value = this._fromUnits(value);
// The value will never be able to approach without timeConstant > 0.
// http://www.w3.org/TR/webaudio/#dfn-setTargetAtTime, where the equation
// is described. 0 results in a division by 0.
value = Math.max(this._minOutput, value);
timeConstant = Math.max(this._minOutput, timeConstant);
this._param.setTargetAtTime(value, this.toSeconds(startTime), timeConstant);
return this;
};
/**
* Sets an array of arbitrary parameter values starting at the given time
* for the given duration.
*
* @param {Array} values
* @param {Time} startTime
* @param {Time} duration
* @returns {Tone.Param} this
*/
Tone.Param.prototype.setValueCurveAtTime = function (values, startTime, duration) {
for (var i = 0; i < values.length; i++) {
values[i] = this._fromUnits(values[i]);
}
this._param.setValueCurveAtTime(values, this.toSeconds(startTime), this.toSeconds(duration));
return this;
};
/**
* Cancels all scheduled parameter changes with times greater than or
* equal to startTime.
*
* @param {Time} startTime
* @returns {Tone.Param} this
*/
Tone.Param.prototype.cancelScheduledValues = function (startTime) {
this._param.cancelScheduledValues(this.toSeconds(startTime));
return this;
};
/**
* Ramps to the given value over the duration of the rampTime.
* Automatically selects the best ramp type (exponential or linear)
* depending on the `units` of the signal
*
* @param {number} value
* @param {Time} rampTime the time that it takes the
* value to ramp from it's current value
* @returns {Tone.Param} this
* @example
* //ramp to the value either linearly or exponentially
* //depending on the "units" value of the signal
* signal.rampTo(0, 10);
*/
Tone.Param.prototype.rampTo = function (value, rampTime) {
rampTime = this.defaultArg(rampTime, 0);
if (this.units === Tone.Type.Frequency || this.units === Tone.Type.BPM) {
this.exponentialRampToValue(value, rampTime);
} else {
this.linearRampToValue(value, rampTime);
}
return this;
};
/**
* Clean up
* @returns {Tone.Param} this
*/
Tone.Param.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._param = null;
return this;
};
return Tone.Param;
});
Module(function (Tone) {
/**
* @class A thin wrapper around the Native Web Audio GainNode.
* The GainNode is a basic building block of the Web Audio
* API and is useful for routing audio and adjusting gains.
* @extends {Tone}
* @param {Number=} gain The initial gain of the GainNode
* @param {Tone.Type=} units The units of the gain parameter.
*/
Tone.Gain = function () {
var options = this.optionsObject(arguments, [
'gain',
'units'
], Tone.Gain.defaults);
/**
* The GainNode
* @type {GainNode}
* @private
*/
this.input = this.output = this._gainNode = this.context.createGain();
/**
* The gain parameter of the gain node.
* @type {AudioParam}
* @signal
*/
this.gain = new Tone.Param({
'param': this._gainNode.gain,
'units': options.units,
'value': options.gain,
'convert': options.convert
});
this._readOnly('gain');
};
Tone.extend(Tone.Gain);
/**
* The defaults
* @const
* @type {Object}
*/
Tone.Gain.defaults = {
'gain': 1,
'convert': true
};
/**
* Clean up.
* @return {Tone.Gain} this
*/
Tone.Gain.prototype.dispose = function () {
Tone.Param.prototype.dispose.call(this);
this._gainNode.disconnect();
this._gainNode = null;
this._writable('gain');
this.gain.dispose();
this.gain = null;
};
return Tone.Gain;
});
Module(function (Tone) {
/**
* @class A signal is an audio-rate value. Tone.Signal is a core component of the library.
* Unlike a number, Signals can be scheduled with sample-level accuracy. Tone.Signal
* has all of the methods available to native Web Audio
* [AudioParam](http://webaudio.github.io/web-audio-api/#the-audioparam-interface)
* as well as additional conveniences. Read more about working with signals
* [here](https://github.com/Tonejs/Tone.js/wiki/Signals).
*
* @constructor
* @extends {Tone.Param}
* @param {Number|AudioParam} [value] Initial value of the signal. If an AudioParam
* is passed in, that parameter will be wrapped
* and controlled by the Signal.
* @param {string} [units=Number] unit The units the signal is in.
* @example
* var signal = new Tone.Signal(10);
*/
Tone.Signal = function () {
var options = this.optionsObject(arguments, [
'value',
'units'
], Tone.Signal.defaults);
/**
* The node where the constant signal value is scaled.
* @type {GainNode}
* @private
*/
this.output = this._gain = this.context.createGain();
options.param = this._gain.gain;
Tone.Param.call(this, options);
/**
* The node where the value is set.
* @type {Tone.Param}
* @private
*/
this.input = this._param = this._gain.gain;
//connect the const output to the node output
Tone.Signal._constant.chain(this._gain);
};
Tone.extend(Tone.Signal, Tone.Param);
/**
* The default values
* @type {Object}
* @static
* @const
*/
Tone.Signal.defaults = {
'value': 0,
'units': Tone.Type.Default,
'convert': true
};
/**
* When signals connect to other signals or AudioParams,
* they take over the output value of that signal or AudioParam.
* For all other nodes, the behavior is the same as a default <code>connect</code>.
*
* @override
* @param {AudioParam|AudioNode|Tone.Signal|Tone} node
* @param {number} [outputNumber=0] The output number to connect from.
* @param {number} [inputNumber=0] The input number to connect to.
* @returns {Tone.SignalBase} this
* @method
*/
Tone.Signal.prototype.connect = Tone.SignalBase.prototype.connect;
/**
* dispose and disconnect
* @returns {Tone.Signal} this
*/
Tone.Signal.prototype.dispose = function () {
Tone.Param.prototype.dispose.call(this);
this._param = null;
this._gain.disconnect();
this._gain = null;
return this;
};
///////////////////////////////////////////////////////////////////////////
// STATIC
///////////////////////////////////////////////////////////////////////////
/**
* Generates a constant output of 1.
* @static
* @private
* @const
* @type {AudioBufferSourceNode}
*/
Tone.Signal._constant = null;
/**
* initializer function
*/
Tone._initAudioContext(function (audioContext) {
var buffer = audioContext.createBuffer(1, 128, audioContext.sampleRate);
var arr = buffer.getChannelData(0);
for (var i = 0; i < arr.length; i++) {
arr[i] = 1;
}
Tone.Signal._constant = audioContext.createBufferSource();
Tone.Signal._constant.channelCount = 1;
Tone.Signal._constant.channelCountMode = 'explicit';
Tone.Signal._constant.buffer = buffer;
Tone.Signal._constant.loop = true;
Tone.Signal._constant.start(0);
Tone.Signal._constant.noGC();
});
return Tone.Signal;
});
Module(function (Tone) {
/**
* @class A Timeline class for scheduling and maintaining state
* along a timeline. All events must have a "time" property.
* Internally, events are stored in time order for fast
* retrieval.
* @extends {Tone}
* @param {Positive} [memory=Infinity] The number of previous events that are retained.
*/
Tone.Timeline = function () {
var options = this.optionsObject(arguments, ['memory'], Tone.Timeline.defaults);
/**
* The array of scheduled timeline events
* @type {Array}
* @private
*/
this._timeline = [];
/**
* An array of items to remove from the list.
* @type {Array}
* @private
*/
this._toRemove = [];
/**
* Flag if the tieline is mid iteration
* @private
* @type {Boolean}
*/
this._iterating = false;
/**
* The memory of the timeline, i.e.
* how many events in the past it will retain
* @type {Positive}
*/
this.memory = options.memory;
};
Tone.extend(Tone.Timeline);
/**
* the default parameters
* @static
* @const
*/
Tone.Timeline.defaults = { 'memory': Infinity };
/**
* The number of items in the timeline.
* @type {Number}
* @memberOf Tone.Timeline#
* @name length
* @readOnly
*/
Object.defineProperty(Tone.Timeline.prototype, 'length', {
get: function () {
return this._timeline.length;
}
});
/**
* Insert an event object onto the timeline. Events must have a "time" attribute.
* @param {Object} event The event object to insert into the
* timeline.
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.addEvent = function (event) {
//the event needs to have a time attribute
if (this.isUndef(event.time)) {
throw new Error('events must have a time attribute');
}
event.time = this.toSeconds(event.time);
if (this._timeline.length) {
var index = this._search(event.time);
this._timeline.splice(index + 1, 0, event);
} else {
this._timeline.push(event);
}
//if the length is more than the memory, remove the previous ones
if (this.length > this.memory) {
var diff = this.length - this.memory;
this._timeline.splice(0, diff);
}
return this;
};
/**
* Remove an event from the timeline.
* @param {Object} event The event object to remove from the list.
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.removeEvent = function (event) {
if (this._iterating) {
this._toRemove.push(event);
} else {
var index = this._timeline.indexOf(event);
if (index !== -1) {
this._timeline.splice(index, 1);
}
}
return this;
};
/**
* Get the event whose time is less than or equal to the given time.
* @param {Number} time The time to query.
* @returns {Object} The event object set after that time.
*/
Tone.Timeline.prototype.getEvent = function (time) {
time = this.toSeconds(time);
var index = this._search(time);
if (index !== -1) {
return this._timeline[index];
} else {
return null;
}
};
/**
* Get the event which is scheduled after the given time.
* @param {Number} time The time to query.
* @returns {Object} The event object after the given time
*/
Tone.Timeline.prototype.getEventAfter = function (time) {
time = this.toSeconds(time);
var index = this._search(time);
if (index + 1 < this._timeline.length) {
return this._timeline[index + 1];
} else {
return null;
}
};
/**
* Get the event before the event at the given time.
* @param {Number} time The time to query.
* @returns {Object} The event object before the given time
*/
Tone.Timeline.prototype.getEventBefore = function (time) {
time = this.toSeconds(time);
var index = this._search(time);
if (index - 1 >= 0) {
return this._timeline[index - 1];
} else {
return null;
}
};
/**
* Cancel events after the given time
* @param {Time} time The time to query.
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.cancel = function (after) {
if (this._timeline.length > 1) {
after = this.toSeconds(after);
var index = this._search(after);
if (index >= 0) {
this._timeline = this._timeline.slice(0, index);
} else {
this._timeline = [];
}
} else if (this._timeline.length === 1) {
//the first item's time
if (this._timeline[0].time >= after) {
this._timeline = [];
}
}
return this;
};
/**
* Cancel events before or equal to the given time.
* @param {Time} time The time to cancel before.
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.cancelBefore = function (time) {
if (this._timeline.length) {
time = this.toSeconds(time);
var index = this._search(time);
if (index >= 0) {
this._timeline = this._timeline.slice(index + 1);
}
}
return this;
};
/**
* Does a binary serach on the timeline array and returns the
* event which is after or equal to the time.
* @param {Number} time
* @return {Number} the index in the timeline array
* @private
*/
Tone.Timeline.prototype._search = function (time) {
var beginning = 0;
var len = this._timeline.length;
var end = len;
// continue searching while [imin,imax] is not empty
while (beginning <= end && beginning < len) {
// calculate the midpoint for roughly equal partition
var midPoint = Math.floor(beginning + (end - beginning) / 2);
var event = this._timeline[midPoint];
if (event.time === time) {
//choose the last one that has the same time
for (var i = midPoint; i < this._timeline.length; i++) {
var testEvent = this._timeline[i];
if (testEvent.time === time) {
midPoint = i;
}
}
return midPoint;
} else if (event.time > time) {
//search lower
end = midPoint - 1;
} else if (event.time < time) {
//search upper
beginning = midPoint + 1;
}
}
return beginning - 1;
};
/**
* Internal iterator. Applies extra safety checks for
* removing items from the array.
* @param {Function} callback
* @param {Number=} lowerBound
* @param {Number=} upperBound
* @private
*/
Tone.Timeline.prototype._iterate = function (callback, lowerBound, upperBound) {
this._iterating = true;
lowerBound = this.defaultArg(lowerBound, 0);
upperBound = this.defaultArg(upperBound, this._timeline.length - 1);
for (var i = lowerBound; i <= upperBound; i++) {
callback(this._timeline[i]);
}
this._iterating = false;
if (this._toRemove.length > 0) {
for (var j = 0; j < this._toRemove.length; j++) {
var index = this._timeline.indexOf(this._toRemove[j]);
if (index !== -1) {
this._timeline.splice(index, 1);
}
}
this._toRemove = [];
}
};
/**
* Iterate over everything in the array
* @param {Function} callback The callback to invoke with every item
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.forEach = function (callback) {
this._iterate(callback);
return this;
};
/**
* Iterate over everything in the array at or before the given time.
* @param {Time} time The time to check if items are before
* @param {Function} callback The callback to invoke with every item
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.forEachBefore = function (time, callback) {
//iterate over the items in reverse so that removing an item doesn't break things
time = this.toSeconds(time);
var upperBound = this._search(time);
if (upperBound !== -1) {
this._iterate(callback, 0, upperBound);
}
return this;
};
/**
* Iterate over everything in the array after the given time.
* @param {Time} time The time to check if items are before
* @param {Function} callback The callback to invoke with every item
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.forEachAfter = function (time, callback) {
//iterate over the items in reverse so that removing an item doesn't break things
time = this.toSeconds(time);
var lowerBound = this._search(time);
this._iterate(callback, lowerBound + 1);
return this;
};
/**
* Iterate over everything in the array at or after the given time. Similar to
* forEachAfter, but includes the item(s) at the given time.
* @param {Time} time The time to check if items are before
* @param {Function} callback The callback to invoke with every item
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.forEachFrom = function (time, callback) {
//iterate over the items in reverse so that removing an item doesn't break things
time = this.toSeconds(time);
var lowerBound = this._search(time);
//work backwards until the event time is less than time
while (lowerBound >= 0 && this._timeline[lowerBound].time >= time) {
lowerBound--;
}
this._iterate(callback, lowerBound + 1);
return this;
};
/**
* Iterate over everything in the array at the given time
* @param {Time} time The time to check if items are before
* @param {Function} callback The callback to invoke with every item
* @returns {Tone.Timeline} this
*/
Tone.Timeline.prototype.forEachAtTime = function (time, callback) {
//iterate over the items in reverse so that removing an item doesn't break things
time = this.toSeconds(time);
var upperBound = this._search(time);
if (upperBound !== -1) {
this._iterate(function (event) {
if (event.time === time) {
callback(event);
}
}, 0, upperBound);
}
return this;
};
/**
* Clean up.
* @return {Tone.Timeline} this
*/
Tone.Timeline.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._timeline = null;
this._toRemove = null;
};
return Tone.Timeline;
});
Module(function (Tone) {
/**
* @class A signal which adds the method getValueAtTime.
* Code and inspiration from https://github.com/jsantell/web-audio-automation-timeline
* @extends {Tone.Param}
* @param {Number=} value The initial value of the signal
* @param {String=} units The conversion units of the signal.
*/
Tone.TimelineSignal = function () {
var options = this.optionsObject(arguments, [
'value',
'units'
], Tone.Signal.defaults);
//constructors
Tone.Signal.apply(this, options);
options.param = this._param;
Tone.Param.call(this, options);
/**
* The scheduled events
* @type {Tone.Timeline}
* @private
*/
this._events = new Tone.Timeline(10);
/**
* The initial scheduled value
* @type {Number}
* @private
*/
this._initial = this._fromUnits(this._param.value);
};
Tone.extend(Tone.TimelineSignal, Tone.Param);
/**
* The event types of a schedulable signal.
* @enum {String}
*/
Tone.TimelineSignal.Type = {
Linear: 'linear',
Exponential: 'exponential',
Target: 'target',
Set: 'set'
};
/**
* The current value of the signal.
* @memberOf Tone.TimelineSignal#
* @type {Number}
* @name value
*/
Object.defineProperty(Tone.TimelineSignal.prototype, 'value', {
get: function () {
return this._toUnits(this._param.value);
},
set: function (value) {
var convertedVal = this._fromUnits(value);
this._initial = convertedVal;
this._param.value = convertedVal;
}
});
///////////////////////////////////////////////////////////////////////////
// SCHEDULING
///////////////////////////////////////////////////////////////////////////
/**
* Schedules a parameter value change at the given time.
* @param {*} value The value to set the signal.
* @param {Time} time The time when the change should occur.
* @returns {Tone.TimelineSignal} this
* @example
* //set the frequency to "G4" in exactly 1 second from now.
* freq.setValueAtTime("G4", "+1");
*/
Tone.TimelineSignal.prototype.setValueAtTime = function (value, startTime) {
value = this._fromUnits(value);
startTime = this.toSeconds(startTime);
this._events.addEvent({
'type': Tone.TimelineSignal.Type.Set,
'value': value,
'time': startTime
});
//invoke the original event
this._param.setValueAtTime(value, startTime);
return this;
};
/**
* Schedules a linear continuous change in parameter value from the
* previous scheduled parameter value to the given value.
*
* @param {number} value
* @param {Time} endTime
* @returns {Tone.TimelineSignal} this
*/
Tone.TimelineSignal.prototype.linearRampToValueAtTime = function (value, endTime) {
value = this._fromUnits(value);
endTime = this.toSeconds(endTime);
this._events.addEvent({
'type': Tone.TimelineSignal.Type.Linear,
'value': value,
'time': endTime
});
this._param.linearRampToValueAtTime(value, endTime);
return this;
};
/**
* Schedules an exponential continuous change in parameter value from
* the previous scheduled parameter value to the given value.
*
* @param {number} value
* @param {Time} endTime
* @returns {Tone.TimelineSignal} this
*/
Tone.TimelineSignal.prototype.exponentialRampToValueAtTime = function (value, endTime) {
value = this._fromUnits(value);
value = Math.max(this._minOutput, value);
endTime = this.toSeconds(endTime);
this._events.addEvent({
'type': Tone.TimelineSignal.Type.Exponential,
'value': value,
'time': endTime
});
this._param.exponentialRampToValueAtTime(value, endTime);
return this;
};
/**
* Start exponentially approaching the target value at the given time with
* a rate having the given time constant.
* @param {number} value
* @param {Time} startTime
* @param {number} timeConstant
* @returns {Tone.TimelineSignal} this
*/
Tone.TimelineSignal.prototype.setTargetAtTime = function (value, startTime, timeConstant) {
value = this._fromUnits(value);
value = Math.max(this._minOutput, value);
timeConstant = Math.max(this._minOutput, timeConstant);
startTime = this.toSeconds(startTime);
this._events.addEvent({
'type': Tone.TimelineSignal.Type.Target,
'value': value,
'time': startTime,
'constant': timeConstant
});
this._param.setTargetAtTime(value, startTime, timeConstant);
return this;
};
/**
* Cancels all scheduled parameter changes with times greater than or
* equal to startTime.
*
* @param {Time} startTime
* @returns {Tone.TimelineSignal} this
*/
Tone.TimelineSignal.prototype.cancelScheduledValues = function (after) {
this._events.cancel(after);
this._param.cancelScheduledValues(this.toSeconds(after));
return this;
};
/**
* Sets the computed value at the given time. This provides
* a point from which a linear or exponential curve
* can be scheduled after. Will cancel events after
* the given time and shorten the currently scheduled
* linear or exponential ramp so that it ends at `time` .
* This is to avoid discontinuities and clicks in envelopes.
* @param {Time} time When to set the ramp point
* @returns {Tone.TimelineSignal} this
*/
Tone.TimelineSignal.prototype.setRampPoint = function (time) {
time = this.toSeconds(time);
//get the value at the given time
var val = this.getValueAtTime(time);
//reschedule the next event to end at the given time
var after = this._searchAfter(time);
if (after) {
//cancel the next event(s)
this.cancelScheduledValues(time);
if (after.type === Tone.TimelineSignal.Type.Linear) {
this.linearRampToValueAtTime(val, time);
} else if (after.type === Tone.TimelineSignal.Type.Exponential) {
this.exponentialRampToValueAtTime(val, time);
}
}
this.setValueAtTime(val, time);
return this;
};
/**
* Do a linear ramp to the given value between the start and finish times.
* @param {Number} value The value to ramp to.
* @param {Time} start The beginning anchor point to do the linear ramp
* @param {Time} finish The ending anchor point by which the value of
* the signal will equal the given value.
* @returns {Tone.TimelineSignal} this
*/
Tone.TimelineSignal.prototype.linearRampToValueBetween = function (value, start, finish) {
this.setRampPoint(start);
this.linearRampToValueAtTime(value, finish);
return this;
};
/**
* Do a exponential ramp to the given value between the start and finish times.
* @param {Number} value The value to ramp to.
* @param {Time} start The beginning anchor point to do the exponential ramp
* @param {Time} finish The ending anchor point by which the value of
* the signal will equal the given value.
* @returns {Tone.TimelineSignal} this
*/
Tone.TimelineSignal.prototype.exponentialRampToValueBetween = function (value, start, finish) {
this.setRampPoint(start);
this.exponentialRampToValueAtTime(value, finish);
return this;
};
///////////////////////////////////////////////////////////////////////////
// GETTING SCHEDULED VALUES
///////////////////////////////////////////////////////////////////////////
/**
* Returns the value before or equal to the given time
* @param {Number} time The time to query
* @return {Object} The event at or before the given time.
* @private
*/
Tone.TimelineSignal.prototype._searchBefore = function (time) {
return this._events.getEvent(time);
};
/**
* The event after the given time
* @param {Number} time The time to query.
* @return {Object} The next event after the given time
* @private
*/
Tone.TimelineSignal.prototype._searchAfter = function (time) {
return this._events.getEventAfter(time);
};
/**
* Get the scheduled value at the given time. This will
* return the unconverted (raw) value.
* @param {Number} time The time in seconds.
* @return {Number} The scheduled value at the given time.
*/
Tone.TimelineSignal.prototype.getValueAtTime = function (time) {
var after = this._searchAfter(time);
var before = this._searchBefore(time);
var value = this._initial;
//if it was set by
if (before === null) {
value = this._initial;
} else if (before.type === Tone.TimelineSignal.Type.Target) {
var previous = this._events.getEventBefore(before.time);
var previouVal;
if (previous === null) {
previouVal = this._initial;
} else {
previouVal = previous.value;
}
value = this._exponentialApproach(before.time, previouVal, before.value, before.constant, time);
} else if (after === null) {
value = before.value;
} else if (after.type === Tone.TimelineSignal.Type.Linear) {
value = this._linearInterpolate(before.time, before.value, after.time, after.value, time);
} else if (after.type === Tone.TimelineSignal.Type.Exponential) {
value = this._exponentialInterpolate(before.time, before.value, after.time, after.value, time);
} else {
value = before.value;
}
return value;
};
/**
* When signals connect to other signals or AudioParams,
* they take over the output value of that signal or AudioParam.
* For all other nodes, the behavior is the same as a default <code>connect</code>.
*
* @override
* @param {AudioParam|AudioNode|Tone.Signal|Tone} node
* @param {number} [outputNumber=0] The output number to connect from.
* @param {number} [inputNumber=0] The input number to connect to.
* @returns {Tone.TimelineSignal} this
* @method
*/
Tone.TimelineSignal.prototype.connect = Tone.SignalBase.prototype.connect;
///////////////////////////////////////////////////////////////////////////
// AUTOMATION CURVE CALCULATIONS
// MIT License, copyright (c) 2014 Jordan Santell
///////////////////////////////////////////////////////////////////////////
/**
* Calculates the the value along the curve produced by setTargetAtTime
* @private
*/
Tone.TimelineSignal.prototype._exponentialApproach = function (t0, v0, v1, timeConstant, t) {
return v1 + (v0 - v1) * Math.exp(-(t - t0) / timeConstant);
};
/**
* Calculates the the value along the curve produced by linearRampToValueAtTime
* @private
*/
Tone.TimelineSignal.prototype._linearInterpolate = function (t0, v0, t1, v1, t) {
return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
};
/**
* Calculates the the value along the curve produced by exponentialRampToValueAtTime
* @private
*/
Tone.TimelineSignal.prototype._exponentialInterpolate = function (t0, v0, t1, v1, t) {
v0 = Math.max(this._minOutput, v0);
return v0 * Math.pow(v1 / v0, (t - t0) / (t1 - t0));
};
/**
* Clean up.
* @return {Tone.TimelineSignal} this
*/
Tone.TimelineSignal.prototype.dispose = function () {
Tone.Signal.prototype.dispose.call(this);
Tone.Param.prototype.dispose.call(this);
this._events.dispose();
this._events = null;
};
return Tone.TimelineSignal;
});
Module(function (Tone) {
/**
* @class Pow applies an exponent to the incoming signal. The incoming signal
* must be AudioRange.
*
* @extends {Tone.SignalBase}
* @constructor
* @param {Positive} exp The exponent to apply to the incoming signal, must be at least 2.
* @example
* var pow = new Tone.Pow(2);
* var sig = new Tone.Signal(0.5).connect(pow);
* //output of pow is 0.25.
*/
Tone.Pow = function (exp) {
/**
* the exponent
* @private
* @type {number}
*/
this._exp = this.defaultArg(exp, 1);
/**
* @type {WaveShaperNode}
* @private
*/
this._expScaler = this.input = this.output = new Tone.WaveShaper(this._expFunc(this._exp), 8192);
};
Tone.extend(Tone.Pow, Tone.SignalBase);
/**
* The value of the exponent.
* @memberOf Tone.Pow#
* @type {number}
* @name value
*/
Object.defineProperty(Tone.Pow.prototype, 'value', {
get: function () {
return this._exp;
},
set: function (exp) {
this._exp = exp;
this._expScaler.setMap(this._expFunc(this._exp));
}
});
/**
* the function which maps the waveshaper
* @param {number} exp
* @return {function}
* @private
*/
Tone.Pow.prototype._expFunc = function (exp) {
return function (val) {
return Math.pow(Math.abs(val), exp);
};
};
/**
* Clean up.
* @returns {Tone.Pow} this
*/
Tone.Pow.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._expScaler.dispose();
this._expScaler = null;
return this;
};
return Tone.Pow;
});
Module(function (Tone) {
/**
* @class Tone.Envelope is an [ADSR](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope)
* envelope generator. Tone.Envelope outputs a signal which
* can be connected to an AudioParam or Tone.Signal.
* <img src="https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg">
*
* @constructor
* @extends {Tone}
* @param {Time} [attack] The amount of time it takes for the envelope to go from
* 0 to it's maximum value.
* @param {Time} [decay] The period of time after the attack that it takes for the envelope
* to fall to the sustain value.
* @param {NormalRange} [sustain] The percent of the maximum value that the envelope rests at until
* the release is triggered.
* @param {Time} [release] The amount of time after the release is triggered it takes to reach 0.
* @example
* //an amplitude envelope
* var gainNode = Tone.context.createGain();
* var env = new Tone.Envelope({
* "attack" : 0.1,
* "decay" : 0.2,
* "sustain" : 1,
* "release" : 0.8,
* });
* env.connect(gainNode.gain);
*/
Tone.Envelope = function () {
//get all of the defaults
var options = this.optionsObject(arguments, [
'attack',
'decay',
'sustain',
'release'
], Tone.Envelope.defaults);
/**
* When triggerAttack is called, the attack time is the amount of
* time it takes for the envelope to reach it's maximum value.
* @type {Time}
*/
this.attack = options.attack;
/**
* After the attack portion of the envelope, the value will fall
* over the duration of the decay time to it's sustain value.
* @type {Time}
*/
this.decay = options.decay;
/**
* The sustain value is the value
* which the envelope rests at after triggerAttack is
* called, but before triggerRelease is invoked.
* @type {NormalRange}
*/
this.sustain = options.sustain;
/**
* After triggerRelease is called, the envelope's
* value will fall to it's miminum value over the
* duration of the release time.
* @type {Time}
*/
this.release = options.release;
/**
* the next time the envelope is at standby
* @type {number}
* @private
*/
this._attackCurve = Tone.Envelope.Type.Linear;
/**
* the next time the envelope is at standby
* @type {number}
* @private
*/
this._releaseCurve = Tone.Envelope.Type.Exponential;
/**
* the minimum output value
* @type {number}
* @private
*/
this._minOutput = 0.00001;
/**
* the signal
* @type {Tone.TimelineSignal}
* @private
*/
this._sig = this.output = new Tone.TimelineSignal();
this._sig.setValueAtTime(this._minOutput, 0);
//set the attackCurve initially
this.attackCurve = options.attackCurve;
this.releaseCurve = options.releaseCurve;
};
Tone.extend(Tone.Envelope);
/**
* the default parameters
* @static
* @const
*/
Tone.Envelope.defaults = {
'attack': 0.01,
'decay': 0.1,
'sustain': 0.5,
'release': 1,
'attackCurve': 'linear',
'releaseCurve': 'exponential'
};
/**
* the envelope time multipler
* @type {number}
* @private
*/
Tone.Envelope.prototype._timeMult = 0.25;
/**
* Read the current value of the envelope. Useful for
* syncronizing visual output to the envelope.
* @memberOf Tone.Envelope#
* @type {Number}
* @name value
* @readOnly
*/
Object.defineProperty(Tone.Envelope.prototype, 'value', {
get: function () {
return this._sig.value;
}
});
/**
* The slope of the attack. Either "linear" or "exponential".
* @memberOf Tone.Envelope#
* @type {string}
* @name attackCurve
* @example
* env.attackCurve = "linear";
*/
Object.defineProperty(Tone.Envelope.prototype, 'attackCurve', {
get: function () {
return this._attackCurve;
},
set: function (type) {
if (type === Tone.Envelope.Type.Linear || type === Tone.Envelope.Type.Exponential) {
this._attackCurve = type;
} else {
throw Error('attackCurve must be either "linear" or "exponential". Invalid type: ', type);
}
}
});
/**
* The slope of the Release. Either "linear" or "exponential".
* @memberOf Tone.Envelope#
* @type {string}
* @name releaseCurve
* @example
* env.releaseCurve = "linear";
*/
Object.defineProperty(Tone.Envelope.prototype, 'releaseCurve', {
get: function () {
return this._releaseCurve;
},
set: function (type) {
if (type === Tone.Envelope.Type.Linear || type === Tone.Envelope.Type.Exponential) {
this._releaseCurve = type;
} else {
throw Error('releaseCurve must be either "linear" or "exponential". Invalid type: ', type);
}
}
});
/**
* Trigger the attack/decay portion of the ADSR envelope.
* @param {Time} [time=now] When the attack should start.
* @param {NormalRange} [velocity=1] The velocity of the envelope scales the vales.
* number between 0-1
* @returns {Tone.Envelope} this
* @example
* //trigger the attack 0.5 seconds from now with a velocity of 0.2
* env.triggerAttack("+0.5", 0.2);
*/
Tone.Envelope.prototype.triggerAttack = function (time, velocity) {
//to seconds
var now = this.now() + this.blockTime;
time = this.toSeconds(time, now);
var attack = this.toSeconds(this.attack) + time;
var decay = this.toSeconds(this.decay);
velocity = this.defaultArg(velocity, 1);
//attack
if (this._attackCurve === Tone.Envelope.Type.Linear) {
this._sig.linearRampToValueBetween(velocity, time, attack);
} else {
this._sig.exponentialRampToValueBetween(velocity, time, attack);
}
//decay
this._sig.setValueAtTime(velocity, attack);
this._sig.exponentialRampToValueAtTime(this.sustain * velocity, attack + decay);
return this;
};
/**
* Triggers the release of the envelope.
* @param {Time} [time=now] When the release portion of the envelope should start.
* @returns {Tone.Envelope} this
* @example
* //trigger release immediately
* env.triggerRelease();
*/
Tone.Envelope.prototype.triggerRelease = function (time) {
var now = this.now() + this.blockTime;
time = this.toSeconds(time, now);
var release = this.toSeconds(this.release);
if (this._releaseCurve === Tone.Envelope.Type.Linear) {
this._sig.linearRampToValueBetween(this._minOutput, time, time + release);
} else {
this._sig.exponentialRampToValueBetween(this._minOutput, time, release + time);
}
return this;
};
/**
* triggerAttackRelease is shorthand for triggerAttack, then waiting
* some duration, then triggerRelease.
* @param {Time} duration The duration of the sustain.
* @param {Time} [time=now] When the attack should be triggered.
* @param {number} [velocity=1] The velocity of the envelope.
* @returns {Tone.Envelope} this
* @example
* //trigger the attack and then the release after 0.6 seconds.
* env.triggerAttackRelease(0.6);
*/
Tone.Envelope.prototype.triggerAttackRelease = function (duration, time, velocity) {
time = this.toSeconds(time);
this.triggerAttack(time, velocity);
this.triggerRelease(time + this.toSeconds(duration));
return this;
};
/**
* Borrows the connect method from Tone.Signal.
* @function
* @private
*/
Tone.Envelope.prototype.connect = Tone.Signal.prototype.connect;
/**
* Disconnect and dispose.
* @returns {Tone.Envelope} this
*/
Tone.Envelope.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._sig.dispose();
this._sig = null;
return this;
};
/**
* The phase of the envelope.
* @enum {string}
*/
Tone.Envelope.Phase = {
Attack: 'attack',
Decay: 'decay',
Sustain: 'sustain',
Release: 'release',
Standby: 'standby'
};
/**
* The phase of the envelope.
* @enum {string}
*/
Tone.Envelope.Type = {
Linear: 'linear',
Exponential: 'exponential'
};
return Tone.Envelope;
});
Module(function (Tone) {
/**
* @class Tone.AmplitudeEnvelope is a Tone.Envelope connected to a gain node.
* Unlike Tone.Envelope, which outputs the envelope's value, Tone.AmplitudeEnvelope accepts
* an audio signal as the input and will apply the envelope to the amplitude
* of the signal. Read more about ADSR Envelopes on [Wikipedia](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope).
*
* @constructor
* @extends {Tone.Envelope}
* @param {Time|Object} [attack] The amount of time it takes for the envelope to go from
* 0 to it's maximum value.
* @param {Time} [decay] The period of time after the attack that it takes for the envelope
* to fall to the sustain value.
* @param {NormalRange} [sustain] The percent of the maximum value that the envelope rests at until
* the release is triggered.
* @param {Time} [release] The amount of time after the release is triggered it takes to reach 0.
* @example
* var ampEnv = new Tone.AmplitudeEnvelope({
* "attack": 0.1,
* "decay": 0.2,
* "sustain": 1.0,
* "release": 0.8
* }).toMaster();
* //create an oscillator and connect it
* var osc = new Tone.Oscillator().connect(ampEnv).start();
* //trigger the envelopes attack and release "8t" apart
* ampEnv.triggerAttackRelease("8t");
*/
Tone.AmplitudeEnvelope = function () {
Tone.Envelope.apply(this, arguments);
/**
* the input node
* @type {GainNode}
* @private
*/
this.input = this.output = new Tone.Gain();
this._sig.connect(this.output.gain);
};
Tone.extend(Tone.AmplitudeEnvelope, Tone.Envelope);
/**
* Clean up
* @return {Tone.AmplitudeEnvelope} this
*/
Tone.AmplitudeEnvelope.prototype.dispose = function () {
this.input.dispose();
this.input = null;
Tone.Envelope.prototype.dispose.call(this);
return this;
};
return Tone.AmplitudeEnvelope;
});
Module(function (Tone) {
/**
* @class Wrapper around the native Web Audio's
* [AnalyserNode](http://webaudio.github.io/web-audio-api/#idl-def-AnalyserNode).
* Extracts FFT or Waveform data from the incoming signal.
* @extends {Tone}
* @param {Number=} size The size of the FFT. Value must be a power of
* two in the range 32 to 32768.
* @param {String=} type The return type of the analysis, either "fft", or "waveform".
*/
Tone.Analyser = function () {
var options = this.optionsObject(arguments, [
'size',
'type'
], Tone.Analyser.defaults);
/**
* The analyser node.
* @private
* @type {AnalyserNode}
*/
this._analyser = this.input = this.context.createAnalyser();
/**
* The analysis type
* @type {String}
* @private
*/
this._type = options.type;
/**
* The return type of the analysis
* @type {String}
* @private
*/
this._returnType = options.returnType;
/**
* The buffer that the FFT data is written to
* @type {TypedArray}
* @private
*/
this._buffer = null;
//set the values initially
this.size = options.size;
this.type = options.type;
this.returnType = options.returnType;
this.minDecibels = options.minDecibels;
this.maxDecibels = options.maxDecibels;
};
Tone.extend(Tone.Analyser);
/**
* The default values.
* @type {Object}
* @const
*/
Tone.Analyser.defaults = {
'size': 2048,
'returnType': 'byte',
'type': 'fft',
'smoothing': 0.8,
'maxDecibels': -30,
'minDecibels': -100
};
/**
* Possible return types of Tone.Analyser.value
* @enum {String}
*/
Tone.Analyser.Type = {
Waveform: 'waveform',
FFT: 'fft'
};
/**
* Possible return types of Tone.Analyser.value
* @enum {String}
*/
Tone.Analyser.ReturnType = {
Byte: 'byte',
Float: 'float'
};
/**
* Run the analysis given the current settings and return the
* result as a TypedArray.
* @returns {TypedArray}
*/
Tone.Analyser.prototype.analyse = function () {
if (this._type === Tone.Analyser.Type.FFT) {
if (this._returnType === Tone.Analyser.ReturnType.Byte) {
this._analyser.getByteFrequencyData(this._buffer);
} else {
this._analyser.getFloatFrequencyData(this._buffer);
}
} else if (this._type === Tone.Analyser.Type.Waveform) {
if (this._returnType === Tone.Analyser.ReturnType.Byte) {
this._analyser.getByteTimeDomainData(this._buffer);
} else {
this._analyser.getFloatTimeDomainData(this._buffer);
}
}
return this._buffer;
};
/**
* The size of analysis. This must be a power of two in the range 32 to 32768.
* @memberOf Tone.Analyser#
* @type {Number}
* @name size
*/
Object.defineProperty(Tone.Analyser.prototype, 'size', {
get: function () {
return this._analyser.frequencyBinCount;
},
set: function (size) {
this._analyser.fftSize = size * 2;
this.type = this._type;
}
});
/**
* The return type of Tone.Analyser.value, either "byte" or "float".
* When the type is set to "byte" the range of values returned in the array
* are between 0-255, when set to "float" the values are between 0-1.
* @memberOf Tone.Analyser#
* @type {String}
* @name type
*/
Object.defineProperty(Tone.Analyser.prototype, 'returnType', {
get: function () {
return this._returnType;
},
set: function (type) {
if (type === Tone.Analyser.ReturnType.Byte) {
this._buffer = new Uint8Array(this._analyser.frequencyBinCount);
} else if (type === Tone.Analyser.ReturnType.Float) {
this._buffer = new Float32Array(this._analyser.frequencyBinCount);
} else {
throw new Error('Invalid Return Type: ' + type);
}
this._returnType = type;
}
});
/**
* The analysis function returned by Tone.Analyser.value, either "fft" or "waveform".
* @memberOf Tone.Analyser#
* @type {String}
* @name type
*/
Object.defineProperty(Tone.Analyser.prototype, 'type', {
get: function () {
return this._type;
},
set: function (type) {
if (type !== Tone.Analyser.Type.Waveform && type !== Tone.Analyser.Type.FFT) {
throw new Error('Invalid Type: ' + type);
}
this._type = type;
}
});
/**
* 0 represents no time averaging with the last analysis frame.
* @memberOf Tone.Analyser#
* @type {NormalRange}
* @name smoothing
*/
Object.defineProperty(Tone.Analyser.prototype, 'smoothing', {
get: function () {
return this._analyser.smoothingTimeConstant;
},
set: function (val) {
this._analyser.smoothingTimeConstant = val;
}
});
/**
* The smallest decibel value which is analysed by the FFT.
* @memberOf Tone.Analyser#
* @type {Decibels}
* @name minDecibels
*/
Object.defineProperty(Tone.Analyser.prototype, 'minDecibels', {
get: function () {
return this._analyser.minDecibels;
},
set: function (val) {
this._analyser.minDecibels = val;
}
});
/**
* The largest decibel value which is analysed by the FFT.
* @memberOf Tone.Analyser#
* @type {Decibels}
* @name maxDecibels
*/
Object.defineProperty(Tone.Analyser.prototype, 'maxDecibels', {
get: function () {
return this._analyser.maxDecibels;
},
set: function (val) {
this._analyser.maxDecibels = val;
}
});
/**
* Clean up.
* @return {Tone.Analyser} this
*/
Tone.Analyser.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._analyser.disconnect();
this._analyser = null;
this._buffer = null;
};
return Tone.Analyser;
});
Module(function (Tone) {
/**
* @class Tone.Compressor is a thin wrapper around the Web Audio
* [DynamicsCompressorNode](http://webaudio.github.io/web-audio-api/#the-dynamicscompressornode-interface).
* Compression reduces the volume of loud sounds or amplifies quiet sounds
* by narrowing or "compressing" an audio signal's dynamic range.
* Read more on [Wikipedia](https://en.wikipedia.org/wiki/Dynamic_range_compression).
*
* @extends {Tone}
* @constructor
* @param {Decibels|Object} [threshold] The value above which the compression starts to be applied.
* @param {Positive} [ratio] The gain reduction ratio.
* @example
* var comp = new Tone.Compressor(-30, 3);
*/
Tone.Compressor = function () {
var options = this.optionsObject(arguments, [
'threshold',
'ratio'
], Tone.Compressor.defaults);
/**
* the compressor node
* @type {DynamicsCompressorNode}
* @private
*/
this._compressor = this.input = this.output = this.context.createDynamicsCompressor();
/**
* the threshold vaue
* @type {Decibels}
* @signal
*/
this.threshold = this._compressor.threshold;
/**
* The attack parameter
* @type {Time}
* @signal
*/
this.attack = new Tone.Param(this._compressor.attack, Tone.Type.Time);
/**
* The release parameter
* @type {Time}
* @signal
*/
this.release = new Tone.Param(this._compressor.release, Tone.Type.Time);
/**
* The knee parameter
* @type {Decibels}
* @signal
*/
this.knee = this._compressor.knee;
/**
* The ratio value
* @type {Number}
* @signal
*/
this.ratio = this._compressor.ratio;
//set the defaults
this._readOnly([
'knee',
'release',
'attack',
'ratio',
'threshold'
]);
this.set(options);
};
Tone.extend(Tone.Compressor);
/**
* @static
* @const
* @type {Object}
*/
Tone.Compressor.defaults = {
'ratio': 12,
'threshold': -24,
'release': 0.25,
'attack': 0.003,
'knee': 30
};
/**
* clean up
* @returns {Tone.Compressor} this
*/
Tone.Compressor.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable([
'knee',
'release',
'attack',
'ratio',
'threshold'
]);
this._compressor.disconnect();
this._compressor = null;
this.attack.dispose();
this.attack = null;
this.release.dispose();
this.release = null;
this.threshold = null;
this.ratio = null;
this.knee = null;
return this;
};
return Tone.Compressor;
});
Module(function (Tone) {
/**
* @class Add a signal and a number or two signals. When no value is
* passed into the constructor, Tone.Add will sum <code>input[0]</code>
* and <code>input[1]</code>. If a value is passed into the constructor,
* the it will be added to the input.
*
* @constructor
* @extends {Tone.Signal}
* @param {number=} value If no value is provided, Tone.Add will sum the first
* and second inputs.
* @example
* var signal = new Tone.Signal(2);
* var add = new Tone.Add(2);
* signal.connect(add);
* //the output of add equals 4
* @example
* //if constructed with no arguments
* //it will add the first and second inputs
* var add = new Tone.Add();
* var sig0 = new Tone.Signal(3).connect(add, 0, 0);
* var sig1 = new Tone.Signal(4).connect(add, 0, 1);
* //the output of add equals 7.
*/
Tone.Add = function (value) {
Tone.call(this, 2, 0);
/**
* the summing node
* @type {GainNode}
* @private
*/
this._sum = this.input[0] = this.input[1] = this.output = this.context.createGain();
/**
* @private
* @type {Tone.Signal}
*/
this._param = this.input[1] = new Tone.Signal(value);
this._param.connect(this._sum);
};
Tone.extend(Tone.Add, Tone.Signal);
/**
* Clean up.
* @returns {Tone.Add} this
*/
Tone.Add.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._sum.disconnect();
this._sum = null;
this._param.dispose();
this._param = null;
return this;
};
return Tone.Add;
});
Module(function (Tone) {
/**
* @class Multiply two incoming signals. Or, if a number is given in the constructor,
* multiplies the incoming signal by that value.
*
* @constructor
* @extends {Tone.Signal}
* @param {number=} value Constant value to multiple. If no value is provided,
* it will return the product of the first and second inputs
* @example
* var mult = new Tone.Multiply();
* var sigA = new Tone.Signal(3);
* var sigB = new Tone.Signal(4);
* sigA.connect(mult, 0, 0);
* sigB.connect(mult, 0, 1);
* //output of mult is 12.
* @example
* var mult = new Tone.Multiply(10);
* var sig = new Tone.Signal(2).connect(mult);
* //the output of mult is 20.
*/
Tone.Multiply = function (value) {
Tone.call(this, 2, 0);
/**
* the input node is the same as the output node
* it is also the GainNode which handles the scaling of incoming signal
*
* @type {GainNode}
* @private
*/
this._mult = this.input[0] = this.output = this.context.createGain();
/**
* the scaling parameter
* @type {AudioParam}
* @private
*/
this._param = this.input[1] = this.output.gain;
this._param.value = this.defaultArg(value, 0);
};
Tone.extend(Tone.Multiply, Tone.Signal);
/**
* clean up
* @returns {Tone.Multiply} this
*/
Tone.Multiply.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._mult.disconnect();
this._mult = null;
this._param = null;
return this;
};
return Tone.Multiply;
});
Module(function (Tone) {
/**
* @class Negate the incoming signal. i.e. an input signal of 10 will output -10
*
* @constructor
* @extends {Tone.SignalBase}
* @example
* var neg = new Tone.Negate();
* var sig = new Tone.Signal(-2).connect(neg);
* //output of neg is positive 2.
*/
Tone.Negate = function () {
/**
* negation is done by multiplying by -1
* @type {Tone.Multiply}
* @private
*/
this._multiply = this.input = this.output = new Tone.Multiply(-1);
};
Tone.extend(Tone.Negate, Tone.SignalBase);
/**
* clean up
* @returns {Tone.Negate} this
*/
Tone.Negate.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._multiply.dispose();
this._multiply = null;
return this;
};
return Tone.Negate;
});
Module(function (Tone) {
/**
* @class Subtract the signal connected to <code>input[1]</code> from the signal connected
* to <code>input[0]</code>. If an argument is provided in the constructor, the
* signals <code>.value</code> will be subtracted from the incoming signal.
*
* @extends {Tone.Signal}
* @constructor
* @param {number=} value The value to subtract from the incoming signal. If the value
* is omitted, it will subtract the second signal from the first.
* @example
* var sub = new Tone.Subtract(1);
* var sig = new Tone.Signal(4).connect(sub);
* //the output of sub is 3.
* @example
* var sub = new Tone.Subtract();
* var sigA = new Tone.Signal(10);
* var sigB = new Tone.Signal(2.5);
* sigA.connect(sub, 0, 0);
* sigB.connect(sub, 0, 1);
* //output of sub is 7.5
*/
Tone.Subtract = function (value) {
Tone.call(this, 2, 0);
/**
* the summing node
* @type {GainNode}
* @private
*/
this._sum = this.input[0] = this.output = this.context.createGain();
/**
* negate the input of the second input before connecting it
* to the summing node.
* @type {Tone.Negate}
* @private
*/
this._neg = new Tone.Negate();
/**
* the node where the value is set
* @private
* @type {Tone.Signal}
*/
this._param = this.input[1] = new Tone.Signal(value);
this._param.chain(this._neg, this._sum);
};
Tone.extend(Tone.Subtract, Tone.Signal);
/**
* Clean up.
* @returns {Tone.SignalBase} this
*/
Tone.Subtract.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._neg.dispose();
this._neg = null;
this._sum.disconnect();
this._sum = null;
this._param.dispose();
this._param = null;
return this;
};
return Tone.Subtract;
});
Module(function (Tone) {
/**
* @class GreaterThanZero outputs 1 when the input is strictly greater than zero
*
* @constructor
* @extends {Tone.SignalBase}
* @example
* var gt0 = new Tone.GreaterThanZero();
* var sig = new Tone.Signal(0.01).connect(gt0);
* //the output of gt0 is 1.
* sig.value = 0;
* //the output of gt0 is 0.
*/
Tone.GreaterThanZero = function () {
/**
* @type {Tone.WaveShaper}
* @private
*/
this._thresh = this.output = new Tone.WaveShaper(function (val) {
if (val <= 0) {
return 0;
} else {
return 1;
}
});
/**
* scale the first thresholded signal by a large value.
* this will help with values which are very close to 0
* @type {Tone.Multiply}
* @private
*/
this._scale = this.input = new Tone.Multiply(10000);
//connections
this._scale.connect(this._thresh);
};
Tone.extend(Tone.GreaterThanZero, Tone.SignalBase);
/**
* dispose method
* @returns {Tone.GreaterThanZero} this
*/
Tone.GreaterThanZero.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._scale.dispose();
this._scale = null;
this._thresh.dispose();
this._thresh = null;
return this;
};
return Tone.GreaterThanZero;
});
Module(function (Tone) {
/**
* @class EqualZero outputs 1 when the input is equal to
* 0 and outputs 0 otherwise.
*
* @constructor
* @extends {Tone.SignalBase}
* @example
* var eq0 = new Tone.EqualZero();
* var sig = new Tone.Signal(0).connect(eq0);
* //the output of eq0 is 1.
*/
Tone.EqualZero = function () {
/**
* scale the incoming signal by a large factor
* @private
* @type {Tone.Multiply}
*/
this._scale = this.input = new Tone.Multiply(10000);
/**
* @type {Tone.WaveShaper}
* @private
*/
this._thresh = new Tone.WaveShaper(function (val) {
if (val === 0) {
return 1;
} else {
return 0;
}
}, 128);
/**
* threshold the output so that it's 0 or 1
* @type {Tone.GreaterThanZero}
* @private
*/
this._gtz = this.output = new Tone.GreaterThanZero();
//connections
this._scale.chain(this._thresh, this._gtz);
};
Tone.extend(Tone.EqualZero, Tone.SignalBase);
/**
* Clean up.
* @returns {Tone.EqualZero} this
*/
Tone.EqualZero.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._gtz.dispose();
this._gtz = null;
this._scale.dispose();
this._scale = null;
this._thresh.dispose();
this._thresh = null;
return this;
};
return Tone.EqualZero;
});
Module(function (Tone) {
/**
* @class Output 1 if the signal is equal to the value, otherwise outputs 0.
* Can accept two signals if connected to inputs 0 and 1.
*
* @constructor
* @extends {Tone.SignalBase}
* @param {number=} value The number to compare the incoming signal to
* @example
* var eq = new Tone.Equal(3);
* var sig = new Tone.Signal(3).connect(eq);
* //the output of eq is 1.
*/
Tone.Equal = function (value) {
Tone.call(this, 2, 0);
/**
* subtract the value from the incoming signal
*
* @type {Tone.Add}
* @private
*/
this._sub = this.input[0] = new Tone.Subtract(value);
/**
* @type {Tone.EqualZero}
* @private
*/
this._equals = this.output = new Tone.EqualZero();
this._sub.connect(this._equals);
this.input[1] = this._sub.input[1];
};
Tone.extend(Tone.Equal, Tone.SignalBase);
/**
* The value to compare to the incoming signal.
* @memberOf Tone.Equal#
* @type {number}
* @name value
*/
Object.defineProperty(Tone.Equal.prototype, 'value', {
get: function () {
return this._sub.value;
},
set: function (value) {
this._sub.value = value;
}
});
/**
* Clean up.
* @returns {Tone.Equal} this
*/
Tone.Equal.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._equals.dispose();
this._equals = null;
this._sub.dispose();
this._sub = null;
return this;
};
return Tone.Equal;
});
Module(function (Tone) {
/**
* @class Select between any number of inputs, sending the one
* selected by the gate signal to the output
*
* @constructor
* @extends {Tone.SignalBase}
* @param {number} [sourceCount=2] the number of inputs the switch accepts
* @example
* var sel = new Tone.Select(2);
* var sigA = new Tone.Signal(10).connect(sel, 0, 0);
* var sigB = new Tone.Signal(20).connect(sel, 0, 1);
* sel.gate.value = 0;
* //sel outputs 10 (the value of sigA);
* sel.gate.value = 1;
* //sel outputs 20 (the value of sigB);
*/
Tone.Select = function (sourceCount) {
sourceCount = this.defaultArg(sourceCount, 2);
Tone.call(this, sourceCount, 1);
/**
* the control signal
* @type {Number}
* @signal
*/
this.gate = new Tone.Signal(0);
this._readOnly('gate');
//make all the inputs and connect them
for (var i = 0; i < sourceCount; i++) {
var switchGate = new SelectGate(i);
this.input[i] = switchGate;
this.gate.connect(switchGate.selecter);
switchGate.connect(this.output);
}
};
Tone.extend(Tone.Select, Tone.SignalBase);
/**
* Open a specific input and close the others.
* @param {number} which The gate to open.
* @param {Time} [time=now] The time when the switch will open
* @returns {Tone.Select} this
* @example
* //open input 1 in a half second from now
* sel.select(1, "+0.5");
*/
Tone.Select.prototype.select = function (which, time) {
//make sure it's an integer
which = Math.floor(which);
this.gate.setValueAtTime(which, this.toSeconds(time));
return this;
};
/**
* Clean up.
* @returns {Tone.Select} this
*/
Tone.Select.prototype.dispose = function () {
this._writable('gate');
this.gate.dispose();
this.gate = null;
for (var i = 0; i < this.input.length; i++) {
this.input[i].dispose();
this.input[i] = null;
}
Tone.prototype.dispose.call(this);
return this;
};
////////////START HELPER////////////
/**
* helper class for Tone.Select representing a single gate
* @constructor
* @extends {Tone}
* @private
*/
var SelectGate = function (num) {
/**
* the selector
* @type {Tone.Equal}
*/
this.selecter = new Tone.Equal(num);
/**
* the gate
* @type {GainNode}
*/
this.gate = this.input = this.output = this.context.createGain();
//connect the selecter to the gate gain
this.selecter.connect(this.gate.gain);
};
Tone.extend(SelectGate);
/**
* clean up
* @private
*/
SelectGate.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this.selecter.dispose();
this.gate.disconnect();
this.selecter = null;
this.gate = null;
};
////////////END HELPER////////////
//return Tone.Select
return Tone.Select;
});
Module(function (Tone) {
/**
* @class IfThenElse has three inputs. When the first input (if) is true (i.e. === 1),
* then it will pass the second input (then) through to the output, otherwise,
* if it's not true (i.e. === 0) then it will pass the third input (else)
* through to the output.
*
* @extends {Tone.SignalBase}
* @constructor
* @example
* var ifThenElse = new Tone.IfThenElse();
* var ifSignal = new Tone.Signal(1).connect(ifThenElse.if);
* var pwmOsc = new Tone.PWMOscillator().connect(ifThenElse.then);
* var pulseOsc = new Tone.PulseOscillator().connect(ifThenElse.else);
* //ifThenElse outputs pwmOsc
* signal.value = 0;
* //now ifThenElse outputs pulseOsc
*/
Tone.IfThenElse = function () {
Tone.call(this, 3, 0);
/**
* the selector node which is responsible for the routing
* @type {Tone.Select}
* @private
*/
this._selector = this.output = new Tone.Select(2);
//the input mapping
this.if = this.input[0] = this._selector.gate;
this.then = this.input[1] = this._selector.input[1];
this.else = this.input[2] = this._selector.input[0];
};
Tone.extend(Tone.IfThenElse, Tone.SignalBase);
/**
* clean up
* @returns {Tone.IfThenElse} this
*/
Tone.IfThenElse.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._selector.dispose();
this._selector = null;
this.if = null;
this.then = null;
this.else = null;
return this;
};
return Tone.IfThenElse;
});
Module(function (Tone) {
/**
* @class [OR](https://en.wikipedia.org/wiki/OR_gate)
* the inputs together. True if at least one of the inputs is true.
*
* @extends {Tone.SignalBase}
* @constructor
* @param {number} [inputCount=2] the input count
* @example
* var or = new Tone.OR(2);
* var sigA = new Tone.Signal(0)connect(or, 0, 0);
* var sigB = new Tone.Signal(1)connect(or, 0, 1);
* //output of or is 1 because at least
* //one of the inputs is equal to 1.
*/
Tone.OR = function (inputCount) {
inputCount = this.defaultArg(inputCount, 2);
Tone.call(this, inputCount, 0);
/**
* a private summing node
* @type {GainNode}
* @private
*/
this._sum = this.context.createGain();
/**
* @type {Tone.Equal}
* @private
*/
this._gtz = this.output = new Tone.GreaterThanZero();
//make each of the inputs an alias
for (var i = 0; i < inputCount; i++) {
this.input[i] = this._sum;
}
this._sum.connect(this._gtz);
};
Tone.extend(Tone.OR, Tone.SignalBase);
/**
* clean up
* @returns {Tone.OR} this
*/
Tone.OR.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._gtz.dispose();
this._gtz = null;
this._sum.disconnect();
this._sum = null;
return this;
};
return Tone.OR;
});
Module(function (Tone) {
/**
* @class [AND](https://en.wikipedia.org/wiki/Logical_conjunction)
* returns 1 when all the inputs are equal to 1 and returns 0 otherwise.
*
* @extends {Tone.SignalBase}
* @constructor
* @param {number} [inputCount=2] the number of inputs. NOTE: all inputs are
* connected to the single AND input node
* @example
* var and = new Tone.AND(2);
* var sigA = new Tone.Signal(0).connect(and, 0, 0);
* var sigB = new Tone.Signal(1).connect(and, 0, 1);
* //the output of and is 0.
*/
Tone.AND = function (inputCount) {
inputCount = this.defaultArg(inputCount, 2);
Tone.call(this, inputCount, 0);
/**
* @type {Tone.Equal}
* @private
*/
this._equals = this.output = new Tone.Equal(inputCount);
//make each of the inputs an alias
for (var i = 0; i < inputCount; i++) {
this.input[i] = this._equals;
}
};
Tone.extend(Tone.AND, Tone.SignalBase);
/**
* clean up
* @returns {Tone.AND} this
*/
Tone.AND.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._equals.dispose();
this._equals = null;
return this;
};
return Tone.AND;
});
Module(function (Tone) {
/**
* @class Just an alias for Tone.EqualZero, but has the same effect as a NOT operator.
* Outputs 1 when input equals 0.
*
* @constructor
* @extends {Tone.SignalBase}
* @example
* var not = new Tone.NOT();
* var sig = new Tone.Signal(1).connect(not);
* //output of not equals 0.
* sig.value = 0;
* //output of not equals 1.
*/
Tone.NOT = Tone.EqualZero;
return Tone.NOT;
});
Module(function (Tone) {
/**
* @class Output 1 if the signal is greater than the value, otherwise outputs 0.
* can compare two signals or a signal and a number.
*
* @constructor
* @extends {Tone.Signal}
* @param {number} [value=0] the value to compare to the incoming signal
* @example
* var gt = new Tone.GreaterThan(2);
* var sig = new Tone.Signal(4).connect(gt);
* //output of gt is equal 1.
*/
Tone.GreaterThan = function (value) {
Tone.call(this, 2, 0);
/**
* subtract the amount from the incoming signal
* @type {Tone.Subtract}
* @private
*/
this._param = this.input[0] = new Tone.Subtract(value);
this.input[1] = this._param.input[1];
/**
* compare that amount to zero
* @type {Tone.GreaterThanZero}
* @private
*/
this._gtz = this.output = new Tone.GreaterThanZero();
//connect
this._param.connect(this._gtz);
};
Tone.extend(Tone.GreaterThan, Tone.Signal);
/**
* dispose method
* @returns {Tone.GreaterThan} this
*/
Tone.GreaterThan.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._param.dispose();
this._param = null;
this._gtz.dispose();
this._gtz = null;
return this;
};
return Tone.GreaterThan;
});
Module(function (Tone) {
/**
* @class Output 1 if the signal is less than the value, otherwise outputs 0.
* Can compare two signals or a signal and a number.
*
* @constructor
* @extends {Tone.Signal}
* @param {number=} value The value to compare to the incoming signal.
* If no value is provided, it will compare
* <code>input[0]</code> and <code>input[1]</code>
* @example
* var lt = new Tone.LessThan(2);
* var sig = new Tone.Signal(-1).connect(lt);
* //if (sig < 2) lt outputs 1
*/
Tone.LessThan = function (value) {
Tone.call(this, 2, 0);
/**
* negate the incoming signal
* @type {Tone.Negate}
* @private
*/
this._neg = this.input[0] = new Tone.Negate();
/**
* input < value === -input > -value
* @type {Tone.GreaterThan}
* @private
*/
this._gt = this.output = new Tone.GreaterThan();
/**
* negate the signal coming from the second input
* @private
* @type {Tone.Negate}
*/
this._rhNeg = new Tone.Negate();
/**
* the node where the value is set
* @private
* @type {Tone.Signal}
*/
this._param = this.input[1] = new Tone.Signal(value);
//connect
this._neg.connect(this._gt);
this._param.connect(this._rhNeg);
this._rhNeg.connect(this._gt, 0, 1);
};
Tone.extend(Tone.LessThan, Tone.Signal);
/**
* Clean up.
* @returns {Tone.LessThan} this
*/
Tone.LessThan.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._neg.dispose();
this._neg = null;
this._gt.dispose();
this._gt = null;
this._rhNeg.dispose();
this._rhNeg = null;
this._param.dispose();
this._param = null;
return this;
};
return Tone.LessThan;
});
Module(function (Tone) {
/**
* @class Return the absolute value of an incoming signal.
*
* @constructor
* @extends {Tone.SignalBase}
* @example
* var signal = new Tone.Signal(-1);
* var abs = new Tone.Abs();
* signal.connect(abs);
* //the output of abs is 1.
*/
Tone.Abs = function () {
Tone.call(this, 1, 0);
/**
* @type {Tone.LessThan}
* @private
*/
this._ltz = new Tone.LessThan(0);
/**
* @type {Tone.Select}
* @private
*/
this._switch = this.output = new Tone.Select(2);
/**
* @type {Tone.Negate}
* @private
*/
this._negate = new Tone.Negate();
//two signal paths, positive and negative
this.input.connect(this._switch, 0, 0);
this.input.connect(this._negate);
this._negate.connect(this._switch, 0, 1);
//the control signal
this.input.chain(this._ltz, this._switch.gate);
};
Tone.extend(Tone.Abs, Tone.SignalBase);
/**
* dispose method
* @returns {Tone.Abs} this
*/
Tone.Abs.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._switch.dispose();
this._switch = null;
this._ltz.dispose();
this._ltz = null;
this._negate.dispose();
this._negate = null;
return this;
};
return Tone.Abs;
});
Module(function (Tone) {
/**
* @class Outputs the greater of two signals. If a number is provided in the constructor
* it will use that instead of the signal.
*
* @constructor
* @extends {Tone.Signal}
* @param {number=} max Max value if provided. if not provided, it will use the
* signal value from input 1.
* @example
* var max = new Tone.Max(2);
* var sig = new Tone.Signal(3).connect(max);
* //max outputs 3
* sig.value = 1;
* //max outputs 2
* @example
* var max = new Tone.Max();
* var sigA = new Tone.Signal(3);
* var sigB = new Tone.Signal(4);
* sigA.connect(max, 0, 0);
* sigB.connect(max, 0, 1);
* //output of max is 4.
*/
Tone.Max = function (max) {
Tone.call(this, 2, 0);
this.input[0] = this.context.createGain();
/**
* the max signal
* @type {Tone.Signal}
* @private
*/
this._param = this.input[1] = new Tone.Signal(max);
/**
* @type {Tone.Select}
* @private
*/
this._ifThenElse = this.output = new Tone.IfThenElse();
/**
* @type {Tone.Select}
* @private
*/
this._gt = new Tone.GreaterThan();
//connections
this.input[0].chain(this._gt, this._ifThenElse.if);
this.input[0].connect(this._ifThenElse.then);
this._param.connect(this._ifThenElse.else);
this._param.connect(this._gt, 0, 1);
};
Tone.extend(Tone.Max, Tone.Signal);
/**
* Clean up.
* @returns {Tone.Max} this
*/
Tone.Max.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._param.dispose();
this._ifThenElse.dispose();
this._gt.dispose();
this._param = null;
this._ifThenElse = null;
this._gt = null;
return this;
};
return Tone.Max;
});
Module(function (Tone) {
/**
* @class Outputs the lesser of two signals. If a number is given
* in the constructor, it will use a signal and a number.
*
* @constructor
* @extends {Tone.Signal}
* @param {number} min The minimum to compare to the incoming signal
* @example
* var min = new Tone.Min(2);
* var sig = new Tone.Signal(3).connect(min);
* //min outputs 2
* sig.value = 1;
* //min outputs 1
* @example
* var min = new Tone.Min();
* var sigA = new Tone.Signal(3);
* var sigB = new Tone.Signal(4);
* sigA.connect(min, 0, 0);
* sigB.connect(min, 0, 1);
* //output of min is 3.
*/
Tone.Min = function (min) {
Tone.call(this, 2, 0);
this.input[0] = this.context.createGain();
/**
* @type {Tone.Select}
* @private
*/
this._ifThenElse = this.output = new Tone.IfThenElse();
/**
* @type {Tone.Select}
* @private
*/
this._lt = new Tone.LessThan();
/**
* the min signal
* @type {Tone.Signal}
* @private
*/
this._param = this.input[1] = new Tone.Signal(min);
//connections
this.input[0].chain(this._lt, this._ifThenElse.if);
this.input[0].connect(this._ifThenElse.then);
this._param.connect(this._ifThenElse.else);
this._param.connect(this._lt, 0, 1);
};
Tone.extend(Tone.Min, Tone.Signal);
/**
* clean up
* @returns {Tone.Min} this
*/
Tone.Min.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._param.dispose();
this._ifThenElse.dispose();
this._lt.dispose();
this._param = null;
this._ifThenElse = null;
this._lt = null;
return this;
};
return Tone.Min;
});
Module(function (Tone) {
/**
* @class Signal-rate modulo operator. Only works in AudioRange [-1, 1] and for modulus
* values in the NormalRange.
*
* @constructor
* @extends {Tone.SignalBase}
* @param {NormalRange} modulus The modulus to apply.
* @example
* var mod = new Tone.Modulo(0.2)
* var sig = new Tone.Signal(0.5).connect(mod);
* //mod outputs 0.1
*/
Tone.Modulo = function (modulus) {
Tone.call(this, 1, 1);
/**
* A waveshaper gets the integer multiple of
* the input signal and the modulus.
* @private
* @type {Tone.WaveShaper}
*/
this._shaper = new Tone.WaveShaper(Math.pow(2, 16));
/**
* the integer multiple is multiplied by the modulus
* @type {Tone.Multiply}
* @private
*/
this._multiply = new Tone.Multiply();
/**
* and subtracted from the input signal
* @type {Tone.Subtract}
* @private
*/
this._subtract = this.output = new Tone.Subtract();
/**
* the modulus signal
* @type {Tone.Signal}
* @private
*/
this._modSignal = new Tone.Signal(modulus);
//connections
this.input.fan(this._shaper, this._subtract);
this._modSignal.connect(this._multiply, 0, 0);
this._shaper.connect(this._multiply, 0, 1);
this._multiply.connect(this._subtract, 0, 1);
this._setWaveShaper(modulus);
};
Tone.extend(Tone.Modulo, Tone.SignalBase);
/**
* @param {number} mod the modulus to apply
* @private
*/
Tone.Modulo.prototype._setWaveShaper = function (mod) {
this._shaper.setMap(function (val) {
var multiple = Math.floor((val + 0.0001) / mod);
return multiple;
});
};
/**
* The modulus value.
* @memberOf Tone.Modulo#
* @type {NormalRange}
* @name value
*/
Object.defineProperty(Tone.Modulo.prototype, 'value', {
get: function () {
return this._modSignal.value;
},
set: function (mod) {
this._modSignal.value = mod;
this._setWaveShaper(mod);
}
});
/**
* clean up
* @returns {Tone.Modulo} this
*/
Tone.Modulo.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._shaper.dispose();
this._shaper = null;
this._multiply.dispose();
this._multiply = null;
this._subtract.dispose();
this._subtract = null;
this._modSignal.dispose();
this._modSignal = null;
return this;
};
return Tone.Modulo;
});
Module(function (Tone) {
/**
* @class AudioToGain converts an input in AudioRange [-1,1] to NormalRange [0,1].
* See Tone.GainToAudio.
*
* @extends {Tone.SignalBase}
* @constructor
* @example
* var a2g = new Tone.AudioToGain();
*/
Tone.AudioToGain = function () {
/**
* @type {WaveShaperNode}
* @private
*/
this._norm = this.input = this.output = new Tone.WaveShaper(function (x) {
return (x + 1) / 2;
});
};
Tone.extend(Tone.AudioToGain, Tone.SignalBase);
/**
* clean up
* @returns {Tone.AudioToGain} this
*/
Tone.AudioToGain.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._norm.dispose();
this._norm = null;
return this;
};
return Tone.AudioToGain;
});
Module(function (Tone) {
/**
* @class Evaluate an expression at audio rate. <br><br>
* Parsing code modified from https://code.google.com/p/tapdigit/
* Copyright 2011 2012 Ariya Hidayat, New BSD License
*
* @extends {Tone.SignalBase}
* @constructor
* @param {string} expr the expression to generate
* @example
* //adds the signals from input[0] and input[1].
* var expr = new Tone.Expr("$0 + $1");
*/
Tone.Expr = function () {
var expr = this._replacements(Array.prototype.slice.call(arguments));
var inputCount = this._parseInputs(expr);
/**
* hold onto all of the nodes for disposal
* @type {Array}
* @private
*/
this._nodes = [];
/**
* The inputs. The length is determined by the expression.
* @type {Array}
*/
this.input = new Array(inputCount);
//create a gain for each input
for (var i = 0; i < inputCount; i++) {
this.input[i] = this.context.createGain();
}
//parse the syntax tree
var tree = this._parseTree(expr);
//evaluate the results
var result;
try {
result = this._eval(tree);
} catch (e) {
this._disposeNodes();
throw new Error('Could evaluate expression: ' + expr);
}
/**
* The output node is the result of the expression
* @type {Tone}
*/
this.output = result;
};
Tone.extend(Tone.Expr, Tone.SignalBase);
//some helpers to cut down the amount of code
function applyBinary(Constructor, args, self) {
var op = new Constructor();
self._eval(args[0]).connect(op, 0, 0);
self._eval(args[1]).connect(op, 0, 1);
return op;
}
function applyUnary(Constructor, args, self) {
var op = new Constructor();
self._eval(args[0]).connect(op, 0, 0);
return op;
}
function getNumber(arg) {
return arg ? parseFloat(arg) : undefined;
}
function literalNumber(arg) {
return arg && arg.args ? parseFloat(arg.args) : undefined;
}
/*
* the Expressions that Tone.Expr can parse.
*
* each expression belongs to a group and contains a regexp
* for selecting the operator as well as that operators method
*
* @type {Object}
* @private
*/
Tone.Expr._Expressions = {
//values
'value': {
'signal': {
regexp: /^\d+\.\d+|^\d+/,
method: function (arg) {
var sig = new Tone.Signal(getNumber(arg));
return sig;
}
},
'input': {
regexp: /^\$\d/,
method: function (arg, self) {
return self.input[getNumber(arg.substr(1))];
}
}
},
//syntactic glue
'glue': {
'(': { regexp: /^\(/ },
')': { regexp: /^\)/ },
',': { regexp: /^,/ }
},
//functions
'func': {
'abs': {
regexp: /^abs/,
method: applyUnary.bind(this, Tone.Abs)
},
'min': {
regexp: /^min/,
method: applyBinary.bind(this, Tone.Min)
},
'max': {
regexp: /^max/,
method: applyBinary.bind(this, Tone.Max)
},
'if': {
regexp: /^if/,
method: function (args, self) {
var op = new Tone.IfThenElse();
self._eval(args[0]).connect(op.if);
self._eval(args[1]).connect(op.then);
self._eval(args[2]).connect(op.else);
return op;
}
},
'gt0': {
regexp: /^gt0/,
method: applyUnary.bind(this, Tone.GreaterThanZero)
},
'eq0': {
regexp: /^eq0/,
method: applyUnary.bind(this, Tone.EqualZero)
},
'mod': {
regexp: /^mod/,
method: function (args, self) {
var modulus = literalNumber(args[1]);
var op = new Tone.Modulo(modulus);
self._eval(args[0]).connect(op);
return op;
}
},
'pow': {
regexp: /^pow/,
method: function (args, self) {
var exp = literalNumber(args[1]);
var op = new Tone.Pow(exp);
self._eval(args[0]).connect(op);
return op;
}
},
'a2g': {
regexp: /^a2g/,
method: function (args, self) {
var op = new Tone.AudioToGain();
self._eval(args[0]).connect(op);
return op;
}
}
},
//binary expressions
'binary': {
'+': {
regexp: /^\+/,
precedence: 1,
method: applyBinary.bind(this, Tone.Add)
},
'-': {
regexp: /^\-/,
precedence: 1,
method: function (args, self) {
//both unary and binary op
if (args.length === 1) {
return applyUnary(Tone.Negate, args, self);
} else {
return applyBinary(Tone.Subtract, args, self);
}
}
},
'*': {
regexp: /^\*/,
precedence: 0,
method: applyBinary.bind(this, Tone.Multiply)
},
'>': {
regexp: /^\>/,
precedence: 2,
method: applyBinary.bind(this, Tone.GreaterThan)
},
'<': {
regexp: /^</,
precedence: 2,
method: applyBinary.bind(this, Tone.LessThan)
},
'==': {
regexp: /^==/,
precedence: 3,
method: applyBinary.bind(this, Tone.Equal)
},
'&&': {
regexp: /^&&/,
precedence: 4,
method: applyBinary.bind(this, Tone.AND)
},
'||': {
regexp: /^\|\|/,
precedence: 5,
method: applyBinary.bind(this, Tone.OR)
}
},
//unary expressions
'unary': {
'-': {
regexp: /^\-/,
method: applyUnary.bind(this, Tone.Negate)
},
'!': {
regexp: /^\!/,
method: applyUnary.bind(this, Tone.NOT)
}
}
};
/**
* @param {string} expr the expression string
* @return {number} the input count
* @private
*/
Tone.Expr.prototype._parseInputs = function (expr) {
var inputArray = expr.match(/\$\d/g);
var inputMax = 0;
if (inputArray !== null) {
for (var i = 0; i < inputArray.length; i++) {
var inputNum = parseInt(inputArray[i].substr(1)) + 1;
inputMax = Math.max(inputMax, inputNum);
}
}
return inputMax;
};
/**
* @param {Array} args an array of arguments
* @return {string} the results of the replacements being replaced
* @private
*/
Tone.Expr.prototype._replacements = function (args) {
var expr = args.shift();
for (var i = 0; i < args.length; i++) {
expr = expr.replace(/\%/i, args[i]);
}
return expr;
};
/**
* tokenize the expression based on the Expressions object
* @param {string} expr
* @return {Object} returns two methods on the tokenized list, next and peek
* @private
*/
Tone.Expr.prototype._tokenize = function (expr) {
var position = -1;
var tokens = [];
while (expr.length > 0) {
expr = expr.trim();
var token = getNextToken(expr);
tokens.push(token);
expr = expr.substr(token.value.length);
}
function getNextToken(expr) {
for (var type in Tone.Expr._Expressions) {
var group = Tone.Expr._Expressions[type];
for (var opName in group) {
var op = group[opName];
var reg = op.regexp;
var match = expr.match(reg);
if (match !== null) {
return {
type: type,
value: match[0],
method: op.method
};
}
}
}
throw new SyntaxError('Unexpected token ' + expr);
}
return {
next: function () {
return tokens[++position];
},
peek: function () {
return tokens[position + 1];
}
};
};
/**
* recursively parse the string expression into a syntax tree
*
* @param {string} expr
* @return {Object}
* @private
*/
Tone.Expr.prototype._parseTree = function (expr) {
var lexer = this._tokenize(expr);
var isUndef = this.isUndef.bind(this);
function matchSyntax(token, syn) {
return !isUndef(token) && token.type === 'glue' && token.value === syn;
}
function matchGroup(token, groupName, prec) {
var ret = false;
var group = Tone.Expr._Expressions[groupName];
if (!isUndef(token)) {
for (var opName in group) {
var op = group[opName];
if (op.regexp.test(token.value)) {
if (!isUndef(prec)) {
if (op.precedence === prec) {
return true;
}
} else {
return true;
}
}
}
}
return ret;
}
function parseExpression(precedence) {
if (isUndef(precedence)) {
precedence = 5;
}
var expr;
if (precedence < 0) {
expr = parseUnary();
} else {
expr = parseExpression(precedence - 1);
}
var token = lexer.peek();
while (matchGroup(token, 'binary', precedence)) {
token = lexer.next();
expr = {
operator: token.value,
method: token.method,
args: [
expr,
parseExpression(precedence)
]
};
token = lexer.peek();
}
return expr;
}
function parseUnary() {
var token, expr;
token = lexer.peek();
if (matchGroup(token, 'unary')) {
token = lexer.next();
expr = parseUnary();
return {
operator: token.value,
method: token.method,
args: [expr]
};
}
return parsePrimary();
}
function parsePrimary() {
var token, expr;
token = lexer.peek();
if (isUndef(token)) {
throw new SyntaxError('Unexpected termination of expression');
}
if (token.type === 'func') {
token = lexer.next();
return parseFunctionCall(token);
}
if (token.type === 'value') {
token = lexer.next();
return {
method: token.method,
args: token.value
};
}
if (matchSyntax(token, '(')) {
lexer.next();
expr = parseExpression();
token = lexer.next();
if (!matchSyntax(token, ')')) {
throw new SyntaxError('Expected )');
}
return expr;
}
throw new SyntaxError('Parse error, cannot process token ' + token.value);
}
function parseFunctionCall(func) {
var token, args = [];
token = lexer.next();
if (!matchSyntax(token, '(')) {
throw new SyntaxError('Expected ( in a function call "' + func.value + '"');
}
token = lexer.peek();
if (!matchSyntax(token, ')')) {
args = parseArgumentList();
}
token = lexer.next();
if (!matchSyntax(token, ')')) {
throw new SyntaxError('Expected ) in a function call "' + func.value + '"');
}
return {
method: func.method,
args: args,
name: name
};
}
function parseArgumentList() {
var token, expr, args = [];
while (true) {
expr = parseExpression();
if (isUndef(expr)) {
// TODO maybe throw exception?
break;
}
args.push(expr);
token = lexer.peek();
if (!matchSyntax(token, ',')) {
break;
}
lexer.next();
}
return args;
}
return parseExpression();
};
/**
* recursively evaluate the expression tree
* @param {Object} tree
* @return {AudioNode} the resulting audio node from the expression
* @private
*/
Tone.Expr.prototype._eval = function (tree) {
if (!this.isUndef(tree)) {
var node = tree.method(tree.args, this);
this._nodes.push(node);
return node;
}
};
/**
* dispose all the nodes
* @private
*/
Tone.Expr.prototype._disposeNodes = function () {
for (var i = 0; i < this._nodes.length; i++) {
var node = this._nodes[i];
if (this.isFunction(node.dispose)) {
node.dispose();
} else if (this.isFunction(node.disconnect)) {
node.disconnect();
}
node = null;
this._nodes[i] = null;
}
this._nodes = null;
};
/**
* clean up
*/
Tone.Expr.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._disposeNodes();
};
return Tone.Expr;
});
Module(function (Tone) {
/**
* @class Convert an incoming signal between 0, 1 to an equal power gain scale.
*
* @extends {Tone.SignalBase}
* @constructor
* @example
* var eqPowGain = new Tone.EqualPowerGain();
*/
Tone.EqualPowerGain = function () {
/**
* @type {Tone.WaveShaper}
* @private
*/
this._eqPower = this.input = this.output = new Tone.WaveShaper(function (val) {
if (Math.abs(val) < 0.001) {
//should output 0 when input is 0
return 0;
} else {
return this.equalPowerScale(val);
}
}.bind(this), 4096);
};
Tone.extend(Tone.EqualPowerGain, Tone.SignalBase);
/**
* clean up
* @returns {Tone.EqualPowerGain} this
*/
Tone.EqualPowerGain.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._eqPower.dispose();
this._eqPower = null;
return this;
};
return Tone.EqualPowerGain;
});
Module(function (Tone) {
/**
* @class Tone.Crossfade provides equal power fading between two inputs.
* More on crossfading technique [here](https://en.wikipedia.org/wiki/Fade_(audio_engineering)#Crossfading).
*
* @constructor
* @extends {Tone}
* @param {NormalRange} [initialFade=0.5]
* @example
* var crossFade = new Tone.CrossFade(0.5);
* //connect effect A to crossfade from
* //effect output 0 to crossfade input 0
* effectA.connect(crossFade, 0, 0);
* //connect effect B to crossfade from
* //effect output 0 to crossfade input 1
* effectB.connect(crossFade, 0, 1);
* crossFade.fade.value = 0;
* // ^ only effectA is output
* crossFade.fade.value = 1;
* // ^ only effectB is output
* crossFade.fade.value = 0.5;
* // ^ the two signals are mixed equally.
*/
Tone.CrossFade = function (initialFade) {
Tone.call(this, 2, 1);
/**
* Alias for <code>input[0]</code>.
* @type {GainNode}
*/
this.a = this.input[0] = this.context.createGain();
/**
* Alias for <code>input[1]</code>.
* @type {GainNode}
*/
this.b = this.input[1] = this.context.createGain();
/**
* The mix between the two inputs. A fade value of 0
* will output 100% <code>input[0]</code> and
* a value of 1 will output 100% <code>input[1]</code>.
* @type {NormalRange}
* @signal
*/
this.fade = new Tone.Signal(this.defaultArg(initialFade, 0.5), Tone.Type.NormalRange);
/**
* equal power gain cross fade
* @private
* @type {Tone.EqualPowerGain}
*/
this._equalPowerA = new Tone.EqualPowerGain();
/**
* equal power gain cross fade
* @private
* @type {Tone.EqualPowerGain}
*/
this._equalPowerB = new Tone.EqualPowerGain();
/**
* invert the incoming signal
* @private
* @type {Tone}
*/
this._invert = new Tone.Expr('1 - $0');
//connections
this.a.connect(this.output);
this.b.connect(this.output);
this.fade.chain(this._equalPowerB, this.b.gain);
this.fade.chain(this._invert, this._equalPowerA, this.a.gain);
this._readOnly('fade');
};
Tone.extend(Tone.CrossFade);
/**
* clean up
* @returns {Tone.CrossFade} this
*/
Tone.CrossFade.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable('fade');
this._equalPowerA.dispose();
this._equalPowerA = null;
this._equalPowerB.dispose();
this._equalPowerB = null;
this.fade.dispose();
this.fade = null;
this._invert.dispose();
this._invert = null;
this.a.disconnect();
this.a = null;
this.b.disconnect();
this.b = null;
return this;
};
return Tone.CrossFade;
});
Module(function (Tone) {
/**
* @class Tone.Filter is a filter which allows for all of the same native methods
* as the [BiquadFilterNode](http://webaudio.github.io/web-audio-api/#the-biquadfilternode-interface).
* Tone.Filter has the added ability to set the filter rolloff at -12
* (default), -24 and -48.
*
* @constructor
* @extends {Tone}
* @param {Frequency|Object} [frequency] The cutoff frequency of the filter.
* @param {string=} type The type of filter.
* @param {number=} rolloff The drop in decibels per octave after the cutoff frequency.
* 3 choices: -12, -24, and -48
* @example
* var filter = new Tone.Filter(200, "highpass");
*/
Tone.Filter = function () {
Tone.call(this);
var options = this.optionsObject(arguments, [
'frequency',
'type',
'rolloff'
], Tone.Filter.defaults);
/**
* the filter(s)
* @type {Array}
* @private
*/
this._filters = [];
/**
* The cutoff frequency of the filter.
* @type {Frequency}
* @signal
*/
this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
/**
* The detune parameter
* @type {Cents}
* @signal
*/
this.detune = new Tone.Signal(0, Tone.Type.Cents);
/**
* The gain of the filter, only used in certain filter types
* @type {Number}
* @signal
*/
this.gain = new Tone.Signal({
'value': options.gain,
'convert': false
});
/**
* The Q or Quality of the filter
* @type {Positive}
* @signal
*/
this.Q = new Tone.Signal(options.Q);
/**
* the type of the filter
* @type {string}
* @private
*/
this._type = options.type;
/**
* the rolloff value of the filter
* @type {number}
* @private
*/
this._rolloff = options.rolloff;
//set the rolloff;
this.rolloff = options.rolloff;
this._readOnly([
'detune',
'frequency',
'gain',
'Q'
]);
};
Tone.extend(Tone.Filter);
/**
* the default parameters
*
* @static
* @type {Object}
*/
Tone.Filter.defaults = {
'type': 'lowpass',
'frequency': 350,
'rolloff': -12,
'Q': 1,
'gain': 0
};
/**
* The type of the filter. Types: "lowpass", "highpass",
* "bandpass", "lowshelf", "highshelf", "notch", "allpass", or "peaking".
* @memberOf Tone.Filter#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.Filter.prototype, 'type', {
get: function () {
return this._type;
},
set: function (type) {
var types = [
'lowpass',
'highpass',
'bandpass',
'lowshelf',
'highshelf',
'notch',
'allpass',
'peaking'
];
if (types.indexOf(type) === -1) {
throw new Error('Tone.Filter does not have filter type ' + type);
}
this._type = type;
for (var i = 0; i < this._filters.length; i++) {
this._filters[i].type = type;
}
}
});
/**
* The rolloff of the filter which is the drop in db
* per octave. Implemented internally by cascading filters.
* Only accepts the values -12, -24, -48 and -96.
* @memberOf Tone.Filter#
* @type {number}
* @name rolloff
*/
Object.defineProperty(Tone.Filter.prototype, 'rolloff', {
get: function () {
return this._rolloff;
},
set: function (rolloff) {
rolloff = parseInt(rolloff, 10);
var possibilities = [
-12,
-24,
-48,
-96
];
var cascadingCount = possibilities.indexOf(rolloff);
//check the rolloff is valid
if (cascadingCount === -1) {
throw new Error('Filter rolloff can only be -12, -24, -48 or -96');
}
cascadingCount += 1;
this._rolloff = rolloff;
//first disconnect the filters and throw them away
this.input.disconnect();
for (var i = 0; i < this._filters.length; i++) {
this._filters[i].disconnect();
this._filters[i] = null;
}
this._filters = new Array(cascadingCount);
for (var count = 0; count < cascadingCount; count++) {
var filter = this.context.createBiquadFilter();
filter.type = this._type;
this.frequency.connect(filter.frequency);
this.detune.connect(filter.detune);
this.Q.connect(filter.Q);
this.gain.connect(filter.gain);
this._filters[count] = filter;
}
//connect them up
var connectionChain = [this.input].concat(this._filters).concat([this.output]);
this.connectSeries.apply(this, connectionChain);
}
});
/**
* Clean up.
* @return {Tone.Filter} this
*/
Tone.Filter.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
for (var i = 0; i < this._filters.length; i++) {
this._filters[i].disconnect();
this._filters[i] = null;
}
this._filters = null;
this._writable([
'detune',
'frequency',
'gain',
'Q'
]);
this.frequency.dispose();
this.Q.dispose();
this.frequency = null;
this.Q = null;
this.detune.dispose();
this.detune = null;
this.gain.dispose();
this.gain = null;
return this;
};
return Tone.Filter;
});
Module(function (Tone) {
/**
* @class Split the incoming signal into three bands (low, mid, high)
* with two crossover frequency controls.
*
* @extends {Tone}
* @constructor
* @param {Frequency|Object} [lowFrequency] the low/mid crossover frequency
* @param {Frequency} [highFrequency] the mid/high crossover frequency
*/
Tone.MultibandSplit = function () {
var options = this.optionsObject(arguments, [
'lowFrequency',
'highFrequency'
], Tone.MultibandSplit.defaults);
/**
* the input
* @type {GainNode}
* @private
*/
this.input = this.context.createGain();
/**
* the outputs
* @type {Array}
* @private
*/
this.output = new Array(3);
/**
* The low band. Alias for <code>output[0]</code>
* @type {Tone.Filter}
*/
this.low = this.output[0] = new Tone.Filter(0, 'lowpass');
/**
* the lower filter of the mid band
* @type {Tone.Filter}
* @private
*/
this._lowMidFilter = new Tone.Filter(0, 'highpass');
/**
* The mid band output. Alias for <code>output[1]</code>
* @type {Tone.Filter}
*/
this.mid = this.output[1] = new Tone.Filter(0, 'lowpass');
/**
* The high band output. Alias for <code>output[2]</code>
* @type {Tone.Filter}
*/
this.high = this.output[2] = new Tone.Filter(0, 'highpass');
/**
* The low/mid crossover frequency.
* @type {Frequency}
* @signal
*/
this.lowFrequency = new Tone.Signal(options.lowFrequency, Tone.Type.Frequency);
/**
* The mid/high crossover frequency.
* @type {Frequency}
* @signal
*/
this.highFrequency = new Tone.Signal(options.highFrequency, Tone.Type.Frequency);
/**
* The quality of all the filters
* @type {Number}
* @signal
*/
this.Q = new Tone.Signal(options.Q);
this.input.fan(this.low, this.high);
this.input.chain(this._lowMidFilter, this.mid);
//the frequency control signal
this.lowFrequency.connect(this.low.frequency);
this.lowFrequency.connect(this._lowMidFilter.frequency);
this.highFrequency.connect(this.mid.frequency);
this.highFrequency.connect(this.high.frequency);
//the Q value
this.Q.connect(this.low.Q);
this.Q.connect(this._lowMidFilter.Q);
this.Q.connect(this.mid.Q);
this.Q.connect(this.high.Q);
this._readOnly([
'high',
'mid',
'low',
'highFrequency',
'lowFrequency'
]);
};
Tone.extend(Tone.MultibandSplit);
/**
* @private
* @static
* @type {Object}
*/
Tone.MultibandSplit.defaults = {
'lowFrequency': 400,
'highFrequency': 2500,
'Q': 1
};
/**
* Clean up.
* @returns {Tone.MultibandSplit} this
*/
Tone.MultibandSplit.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable([
'high',
'mid',
'low',
'highFrequency',
'lowFrequency'
]);
this.low.dispose();
this.low = null;
this._lowMidFilter.dispose();
this._lowMidFilter = null;
this.mid.dispose();
this.mid = null;
this.high.dispose();
this.high = null;
this.lowFrequency.dispose();
this.lowFrequency = null;
this.highFrequency.dispose();
this.highFrequency = null;
this.Q.dispose();
this.Q = null;
return this;
};
return Tone.MultibandSplit;
});
Module(function (Tone) {
/**
* @class Tone.EQ3 is a three band EQ with control over low, mid, and high gain as
* well as the low and high crossover frequencies.
*
* @constructor
* @extends {Tone}
*
* @param {Decibels|Object} [lowLevel] The gain applied to the lows.
* @param {Decibels} [midLevel] The gain applied to the mid.
* @param {Decibels} [highLevel] The gain applied to the high.
* @example
* var eq = new Tone.EQ3(-10, 3, -20);
*/
Tone.EQ3 = function () {
var options = this.optionsObject(arguments, [
'low',
'mid',
'high'
], Tone.EQ3.defaults);
/**
* the output node
* @type {GainNode}
* @private
*/
this.output = this.context.createGain();
/**
* the multiband split
* @type {Tone.MultibandSplit}
* @private
*/
this._multibandSplit = this.input = new Tone.MultibandSplit({
'lowFrequency': options.lowFrequency,
'highFrequency': options.highFrequency
});
/**
* The gain for the lower signals
* @type {Tone.Gain}
* @private
*/
this._lowGain = new Tone.Gain(options.low, Tone.Type.Decibels);
/**
* The gain for the mid signals
* @type {Tone.Gain}
* @private
*/
this._midGain = new Tone.Gain(options.mid, Tone.Type.Decibels);
/**
* The gain in decibels of the high part
* @type {Tone.Gain}
* @private
*/
this._highGain = new Tone.Gain(options.high, Tone.Type.Decibels);
/**
* The gain in decibels of the low part
* @type {Decibels}
* @signal
*/
this.low = this._lowGain.gain;
/**
* The gain in decibels of the mid part
* @type {Decibels}
* @signal
*/
this.mid = this._midGain.gain;
/**
* The gain in decibels of the high part
* @type {Decibels}
* @signal
*/
this.high = this._highGain.gain;
/**
* The Q value for all of the filters.
* @type {Positive}
* @signal
*/
this.Q = this._multibandSplit.Q;
/**
* The low/mid crossover frequency.
* @type {Frequency}
* @signal
*/
this.lowFrequency = this._multibandSplit.lowFrequency;
/**
* The mid/high crossover frequency.
* @type {Frequency}
* @signal
*/
this.highFrequency = this._multibandSplit.highFrequency;
//the frequency bands
this._multibandSplit.low.chain(this._lowGain, this.output);
this._multibandSplit.mid.chain(this._midGain, this.output);
this._multibandSplit.high.chain(this._highGain, this.output);
this._readOnly([
'low',
'mid',
'high',
'lowFrequency',
'highFrequency'
]);
};
Tone.extend(Tone.EQ3);
/**
* the default values
*/
Tone.EQ3.defaults = {
'low': 0,
'mid': 0,
'high': 0,
'lowFrequency': 400,
'highFrequency': 2500
};
/**
* clean up
* @returns {Tone.EQ3} this
*/
Tone.EQ3.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable([
'low',
'mid',
'high',
'lowFrequency',
'highFrequency'
]);
this._multibandSplit.dispose();
this._multibandSplit = null;
this.lowFrequency = null;
this.highFrequency = null;
this._lowGain.dispose();
this._lowGain = null;
this._midGain.dispose();
this._midGain = null;
this._highGain.dispose();
this._highGain = null;
this.low = null;
this.mid = null;
this.high = null;
this.Q = null;
return this;
};
return Tone.EQ3;
});
Module(function (Tone) {
/**
* @class Performs a linear scaling on an input signal.
* Scales a NormalRange input to between
* outputMin and outputMax.
*
* @constructor
* @extends {Tone.SignalBase}
* @param {number} [outputMin=0] The output value when the input is 0.
* @param {number} [outputMax=1] The output value when the input is 1.
* @example
* var scale = new Tone.Scale(50, 100);
* var signal = new Tone.Signal(0.5).connect(scale);
* //the output of scale equals 75
*/
Tone.Scale = function (outputMin, outputMax) {
/**
* @private
* @type {number}
*/
this._outputMin = this.defaultArg(outputMin, 0);
/**
* @private
* @type {number}
*/
this._outputMax = this.defaultArg(outputMax, 1);
/**
* @private
* @type {Tone.Multiply}
* @private
*/
this._scale = this.input = new Tone.Multiply(1);
/**
* @private
* @type {Tone.Add}
* @private
*/
this._add = this.output = new Tone.Add(0);
this._scale.connect(this._add);
this._setRange();
};
Tone.extend(Tone.Scale, Tone.SignalBase);
/**
* The minimum output value. This number is output when
* the value input value is 0.
* @memberOf Tone.Scale#
* @type {number}
* @name min
*/
Object.defineProperty(Tone.Scale.prototype, 'min', {
get: function () {
return this._outputMin;
},
set: function (min) {
this._outputMin = min;
this._setRange();
}
});
/**
* The maximum output value. This number is output when
* the value input value is 1.
* @memberOf Tone.Scale#
* @type {number}
* @name max
*/
Object.defineProperty(Tone.Scale.prototype, 'max', {
get: function () {
return this._outputMax;
},
set: function (max) {
this._outputMax = max;
this._setRange();
}
});
/**
* set the values
* @private
*/
Tone.Scale.prototype._setRange = function () {
this._add.value = this._outputMin;
this._scale.value = this._outputMax - this._outputMin;
};
/**
* Clean up.
* @returns {Tone.Scale} this
*/
Tone.Scale.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._add.dispose();
this._add = null;
this._scale.dispose();
this._scale = null;
return this;
};
return Tone.Scale;
});
Module(function (Tone) {
/**
* @class Performs an exponential scaling on an input signal.
* Scales a NormalRange value [0,1] exponentially
* to the output range of outputMin to outputMax.
*
* @constructor
* @extends {Tone.SignalBase}
* @param {number} [outputMin=0] The output value when the input is 0.
* @param {number} [outputMax=1] The output value when the input is 1.
* @param {number} [exponent=2] The exponent which scales the incoming signal.
* @example
* var scaleExp = new Tone.ScaleExp(0, 100, 2);
* var signal = new Tone.Signal(0.5).connect(scaleExp);
*/
Tone.ScaleExp = function (outputMin, outputMax, exponent) {
/**
* scale the input to the output range
* @type {Tone.Scale}
* @private
*/
this._scale = this.output = new Tone.Scale(outputMin, outputMax);
/**
* @private
* @type {Tone.Pow}
* @private
*/
this._exp = this.input = new Tone.Pow(this.defaultArg(exponent, 2));
this._exp.connect(this._scale);
};
Tone.extend(Tone.ScaleExp, Tone.SignalBase);
/**
* Instead of interpolating linearly between the <code>min</code> and
* <code>max</code> values, setting the exponent will interpolate between
* the two values with an exponential curve.
* @memberOf Tone.ScaleExp#
* @type {number}
* @name exponent
*/
Object.defineProperty(Tone.ScaleExp.prototype, 'exponent', {
get: function () {
return this._exp.value;
},
set: function (exp) {
this._exp.value = exp;
}
});
/**
* The minimum output value. This number is output when
* the value input value is 0.
* @memberOf Tone.ScaleExp#
* @type {number}
* @name min
*/
Object.defineProperty(Tone.ScaleExp.prototype, 'min', {
get: function () {
return this._scale.min;
},
set: function (min) {
this._scale.min = min;
}
});
/**
* The maximum output value. This number is output when
* the value input value is 1.
* @memberOf Tone.ScaleExp#
* @type {number}
* @name max
*/
Object.defineProperty(Tone.ScaleExp.prototype, 'max', {
get: function () {
return this._scale.max;
},
set: function (max) {
this._scale.max = max;
}
});
/**
* Clean up.
* @returns {Tone.ScaleExp} this
*/
Tone.ScaleExp.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._scale.dispose();
this._scale = null;
this._exp.dispose();
this._exp = null;
return this;
};
return Tone.ScaleExp;
});
Module(function (Tone) {
/**
* @class Comb filters are basic building blocks for physical modeling. Read more
* about comb filters on [CCRMA's website](https://ccrma.stanford.edu/~jos/pasp/Feedback_Comb_Filters.html).
*
* @extends {Tone}
* @constructor
* @param {Time|Object} [delayTime] The delay time of the filter.
* @param {NormalRange=} resonance The amount of feedback the filter has.
*/
Tone.FeedbackCombFilter = function () {
Tone.call(this);
var options = this.optionsObject(arguments, [
'delayTime',
'resonance'
], Tone.FeedbackCombFilter.defaults);
/**
* the delay node
* @type {DelayNode}
* @private
*/
this._delay = this.input = this.output = this.context.createDelay(1);
/**
* The amount of delay of the comb filter.
* @type {Time}
* @signal
*/
this.delayTime = new Tone.Param({
'param': this._delay.delayTime,
'value': options.delayTime,
'units': Tone.Type.Time
});
/**
* the feedback node
* @type {GainNode}
* @private
*/
this._feedback = this.context.createGain();
/**
* The amount of feedback of the delayed signal.
* @type {NormalRange}
* @signal
*/
this.resonance = new Tone.Param({
'param': this._feedback.gain,
'value': options.resonance,
'units': Tone.Type.NormalRange
});
this._delay.chain(this._feedback, this._delay);
this._readOnly([
'resonance',
'delayTime'
]);
};
Tone.extend(Tone.FeedbackCombFilter);
/**
* the default parameters
* @static
* @const
* @type {Object}
*/
Tone.FeedbackCombFilter.defaults = {
'delayTime': 0.1,
'resonance': 0.5
};
/**
* clean up
* @returns {Tone.FeedbackCombFilter} this
*/
Tone.FeedbackCombFilter.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable([
'resonance',
'delayTime'
]);
this._delay.disconnect();
this._delay = null;
this.delayTime.dispose();
this.delayTime = null;
this.resonance.dispose();
this.resonance = null;
this._feedback.disconnect();
this._feedback = null;
return this;
};
return Tone.FeedbackCombFilter;
});
Module(function (Tone) {
/**
* @class Tone.Follower is a crude envelope follower which will follow
* the amplitude of an incoming signal.
* Take care with small (< 0.02) attack or decay values
* as follower has some ripple which is exaggerated
* at these values. Read more about envelope followers (also known
* as envelope detectors) on [Wikipedia](https://en.wikipedia.org/wiki/Envelope_detector).
*
* @constructor
* @extends {Tone}
* @param {Time|Object} [attack] The rate at which the follower rises.
* @param {Time=} release The rate at which the folower falls.
* @example
* var follower = new Tone.Follower(0.2, 0.4);
*/
Tone.Follower = function () {
Tone.call(this);
var options = this.optionsObject(arguments, [
'attack',
'release'
], Tone.Follower.defaults);
/**
* @type {Tone.Abs}
* @private
*/
this._abs = new Tone.Abs();
/**
* the lowpass filter which smooths the input
* @type {BiquadFilterNode}
* @private
*/
this._filter = this.context.createBiquadFilter();
this._filter.type = 'lowpass';
this._filter.frequency.value = 0;
this._filter.Q.value = -100;
/**
* @type {WaveShaperNode}
* @private
*/
this._frequencyValues = new Tone.WaveShaper();
/**
* @type {Tone.Subtract}
* @private
*/
this._sub = new Tone.Subtract();
/**
* @type {DelayNode}
* @private
*/
this._delay = this.context.createDelay();
this._delay.delayTime.value = this.blockTime;
/**
* this keeps it far from 0, even for very small differences
* @type {Tone.Multiply}
* @private
*/
this._mult = new Tone.Multiply(10000);
/**
* @private
* @type {number}
*/
this._attack = options.attack;
/**
* @private
* @type {number}
*/
this._release = options.release;
//the smoothed signal to get the values
this.input.chain(this._abs, this._filter, this.output);
//the difference path
this._abs.connect(this._sub, 0, 1);
this._filter.chain(this._delay, this._sub);
//threshold the difference and use the thresh to set the frequency
this._sub.chain(this._mult, this._frequencyValues, this._filter.frequency);
//set the attack and release values in the table
this._setAttackRelease(this._attack, this._release);
};
Tone.extend(Tone.Follower);
/**
* @static
* @type {Object}
*/
Tone.Follower.defaults = {
'attack': 0.05,
'release': 0.5
};
/**
* sets the attack and release times in the wave shaper
* @param {Time} attack
* @param {Time} release
* @private
*/
Tone.Follower.prototype._setAttackRelease = function (attack, release) {
var minTime = this.blockTime;
attack = this.secondsToFrequency(this.toSeconds(attack));
release = this.secondsToFrequency(this.toSeconds(release));
attack = Math.max(attack, minTime);
release = Math.max(release, minTime);
this._frequencyValues.setMap(function (val) {
if (val <= 0) {
return attack;
} else {
return release;
}
});
};
/**
* The attack time.
* @memberOf Tone.Follower#
* @type {Time}
* @name attack
*/
Object.defineProperty(Tone.Follower.prototype, 'attack', {
get: function () {
return this._attack;
},
set: function (attack) {
this._attack = attack;
this._setAttackRelease(this._attack, this._release);
}
});
/**
* The release time.
* @memberOf Tone.Follower#
* @type {Time}
* @name release
*/
Object.defineProperty(Tone.Follower.prototype, 'release', {
get: function () {
return this._release;
},
set: function (release) {
this._release = release;
this._setAttackRelease(this._attack, this._release);
}
});
/**
* Borrows the connect method from Signal so that the output can be used
* as a Tone.Signal control signal.
* @function
*/
Tone.Follower.prototype.connect = Tone.Signal.prototype.connect;
/**
* dispose
* @returns {Tone.Follower} this
*/
Tone.Follower.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._filter.disconnect();
this._filter = null;
this._frequencyValues.disconnect();
this._frequencyValues = null;
this._delay.disconnect();
this._delay = null;
this._sub.disconnect();
this._sub = null;
this._abs.dispose();
this._abs = null;
this._mult.dispose();
this._mult = null;
this._curve = null;
return this;
};
return Tone.Follower;
});
Module(function (Tone) {
/**
* @class Tone.ScaledEnvelop is an envelope which can be scaled
* to any range. It's useful for applying an envelope
* to a frequency or any other non-NormalRange signal
* parameter.
*
* @extends {Tone.Envelope}
* @constructor
* @param {Time|Object} [attack] the attack time in seconds
* @param {Time} [decay] the decay time in seconds
* @param {number} [sustain] a percentage (0-1) of the full amplitude
* @param {Time} [release] the release time in seconds
* @example
* var scaledEnv = new Tone.ScaledEnvelope({
* "attack" : 0.2,
* "min" : 200,
* "max" : 2000
* });
* scaledEnv.connect(oscillator.frequency);
*/
Tone.ScaledEnvelope = function () {
//get all of the defaults
var options = this.optionsObject(arguments, [
'attack',
'decay',
'sustain',
'release'
], Tone.Envelope.defaults);
Tone.Envelope.call(this, options);
options = this.defaultArg(options, Tone.ScaledEnvelope.defaults);
/**
* scale the incoming signal by an exponent
* @type {Tone.Pow}
* @private
*/
this._exp = this.output = new Tone.Pow(options.exponent);
/**
* scale the signal to the desired range
* @type {Tone.Multiply}
* @private
*/
this._scale = this.output = new Tone.Scale(options.min, options.max);
this._sig.chain(this._exp, this._scale);
};
Tone.extend(Tone.ScaledEnvelope, Tone.Envelope);
/**
* the default parameters
* @static
*/
Tone.ScaledEnvelope.defaults = {
'min': 0,
'max': 1,
'exponent': 1
};
/**
* The envelope's min output value. This is the value which it
* starts at.
* @memberOf Tone.ScaledEnvelope#
* @type {number}
* @name min
*/
Object.defineProperty(Tone.ScaledEnvelope.prototype, 'min', {
get: function () {
return this._scale.min;
},
set: function (min) {
this._scale.min = min;
}
});
/**
* The envelope's max output value. In other words, the value
* at the peak of the attack portion of the envelope.
* @memberOf Tone.ScaledEnvelope#
* @type {number}
* @name max
*/
Object.defineProperty(Tone.ScaledEnvelope.prototype, 'max', {
get: function () {
return this._scale.max;
},
set: function (max) {
this._scale.max = max;
}
});
/**
* The envelope's exponent value.
* @memberOf Tone.ScaledEnvelope#
* @type {number}
* @name exponent
*/
Object.defineProperty(Tone.ScaledEnvelope.prototype, 'exponent', {
get: function () {
return this._exp.value;
},
set: function (exp) {
this._exp.value = exp;
}
});
/**
* clean up
* @returns {Tone.ScaledEnvelope} this
*/
Tone.ScaledEnvelope.prototype.dispose = function () {
Tone.Envelope.prototype.dispose.call(this);
this._scale.dispose();
this._scale = null;
this._exp.dispose();
this._exp = null;
return this;
};
return Tone.ScaledEnvelope;
});
Module(function (Tone) {
/**
* @class Tone.FrequencyEnvelope is a Tone.ScaledEnvelope, but instead of `min` and `max`
* it's got a `baseFrequency` and `octaves` parameter.
*
* @extends {Tone.Envelope}
* @constructor
* @param {Time|Object} [attack] the attack time in seconds
* @param {Time} [decay] the decay time in seconds
* @param {number} [sustain] a percentage (0-1) of the full amplitude
* @param {Time} [release] the release time in seconds
* @example
* var env = new Tone.FrequencyEnvelope({
* "attack" : 0.2,
* "baseFrequency" : "C2",
* "octaves" : 4
* });
* scaledEnv.connect(oscillator.frequency);
*/
Tone.FrequencyEnvelope = function () {
var options = this.optionsObject(arguments, [
'attack',
'decay',
'sustain',
'release'
], Tone.Envelope.defaults);
Tone.ScaledEnvelope.call(this, options);
options = this.defaultArg(options, Tone.FrequencyEnvelope.defaults);
/**
* Stores the octave value
* @type {Positive}
* @private
*/
this._octaves = options.octaves;
//setup
this.baseFrequency = options.baseFrequency;
this.octaves = options.octaves;
};
Tone.extend(Tone.FrequencyEnvelope, Tone.Envelope);
/**
* the default parameters
* @static
*/
Tone.FrequencyEnvelope.defaults = {
'baseFrequency': 200,
'octaves': 4,
'exponent': 2
};
/**
* The envelope's mininum output value. This is the value which it
* starts at.
* @memberOf Tone.FrequencyEnvelope#
* @type {Frequency}
* @name baseFrequency
*/
Object.defineProperty(Tone.FrequencyEnvelope.prototype, 'baseFrequency', {
get: function () {
return this._scale.min;
},
set: function (min) {
this._scale.min = this.toFrequency(min);
}
});
/**
* The number of octaves above the baseFrequency that the
* envelope will scale to.
* @memberOf Tone.FrequencyEnvelope#
* @type {Positive}
* @name octaves
*/
Object.defineProperty(Tone.FrequencyEnvelope.prototype, 'octaves', {
get: function () {
return this._octaves;
},
set: function (octaves) {
this._octaves = octaves;
this._scale.max = this.baseFrequency * Math.pow(2, octaves);
}
});
/**
* The envelope's exponent value.
* @memberOf Tone.FrequencyEnvelope#
* @type {number}
* @name exponent
*/
Object.defineProperty(Tone.FrequencyEnvelope.prototype, 'exponent', {
get: function () {
return this._exp.value;
},
set: function (exp) {
this._exp.value = exp;
}
});
/**
* clean up
* @returns {Tone.FrequencyEnvelope} this
*/
Tone.FrequencyEnvelope.prototype.dispose = function () {
Tone.ScaledEnvelope.prototype.dispose.call(this);
return this;
};
return Tone.FrequencyEnvelope;
});
Module(function (Tone) {
/**
* @class Tone.Gate only passes a signal through when the incoming
* signal exceeds a specified threshold. To do this, Gate uses
* a Tone.Follower to follow the amplitude of the incoming signal.
* A common implementation of this class is a [Noise Gate](https://en.wikipedia.org/wiki/Noise_gate).
*
* @constructor
* @extends {Tone}
* @param {Decibels|Object} [threshold] The threshold above which the gate will open.
* @param {Time=} attack The follower's attack time
* @param {Time=} release The follower's release time
* @example
* var gate = new Tone.Gate(-30, 0.2, 0.3).toMaster();
* var mic = new Tone.Microphone().connect(gate);
* //the gate will only pass through the incoming
* //signal when it's louder than -30db
*/
Tone.Gate = function () {
Tone.call(this);
var options = this.optionsObject(arguments, [
'threshold',
'attack',
'release'
], Tone.Gate.defaults);
/**
* @type {Tone.Follower}
* @private
*/
this._follower = new Tone.Follower(options.attack, options.release);
/**
* @type {Tone.GreaterThan}
* @private
*/
this._gt = new Tone.GreaterThan(this.dbToGain(options.threshold));
//the connections
this.input.connect(this.output);
//the control signal
this.input.chain(this._gt, this._follower, this.output.gain);
};
Tone.extend(Tone.Gate);
/**
* @const
* @static
* @type {Object}
*/
Tone.Gate.defaults = {
'attack': 0.1,
'release': 0.1,
'threshold': -40
};
/**
* The threshold of the gate in decibels
* @memberOf Tone.Gate#
* @type {Decibels}
* @name threshold
*/
Object.defineProperty(Tone.Gate.prototype, 'threshold', {
get: function () {
return this.gainToDb(this._gt.value);
},
set: function (thresh) {
this._gt.value = this.dbToGain(thresh);
}
});
/**
* The attack speed of the gate
* @memberOf Tone.Gate#
* @type {Time}
* @name attack
*/
Object.defineProperty(Tone.Gate.prototype, 'attack', {
get: function () {
return this._follower.attack;
},
set: function (attackTime) {
this._follower.attack = attackTime;
}
});
/**
* The release speed of the gate
* @memberOf Tone.Gate#
* @type {Time}
* @name release
*/
Object.defineProperty(Tone.Gate.prototype, 'release', {
get: function () {
return this._follower.release;
},
set: function (releaseTime) {
this._follower.release = releaseTime;
}
});
/**
* Clean up.
* @returns {Tone.Gate} this
*/
Tone.Gate.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._follower.dispose();
this._gt.dispose();
this._follower = null;
this._gt = null;
return this;
};
return Tone.Gate;
});
Module(function (Tone) {
/**
* @class A Timeline State. Provides the methods: <code>setStateAtTime("state", time)</code>
* and <code>getStateAtTime(time)</code>.
*
* @extends {Tone.Timeline}
* @param {String} initial The initial state of the TimelineState.
* Defaults to <code>undefined</code>
*/
Tone.TimelineState = function (initial) {
Tone.Timeline.call(this);
/**
* The initial state
* @private
* @type {String}
*/
this._initial = initial;
};
Tone.extend(Tone.TimelineState, Tone.Timeline);
/**
* Returns the scheduled state scheduled before or at
* the given time.
* @param {Time} time The time to query.
* @return {String} The name of the state input in setStateAtTime.
*/
Tone.TimelineState.prototype.getStateAtTime = function (time) {
var event = this.getEvent(time);
if (event !== null) {
return event.state;
} else {
return this._initial;
}
};
/**
* Returns the scheduled state scheduled before or at
* the given time.
* @param {String} state The name of the state to set.
* @param {Time} time The time to query.
*/
Tone.TimelineState.prototype.setStateAtTime = function (state, time) {
this.addEvent({
'state': state,
'time': this.toSeconds(time)
});
};
return Tone.TimelineState;
});
Module(function (Tone) {
/**
* @class A sample accurate clock which provides a callback at the given rate.
* While the callback is not sample-accurate (it is still susceptible to
* loose JS timing), the time passed in as the argument to the callback
* is precise. For most applications, it is better to use Tone.Transport
* instead of the Clock by itself since you can synchronize multiple callbacks.
*
* @constructor
* @extends {Tone}
* @param {function} callback The callback to be invoked with the time of the audio event
* @param {Frequency} frequency The rate of the callback
* @example
* //the callback will be invoked approximately once a second
* //and will print the time exactly once a second apart.
* var clock = new Tone.Clock(function(time){
* console.log(time);
* }, 1);
*/
Tone.Clock = function () {
var options = this.optionsObject(arguments, [
'callback',
'frequency'
], Tone.Clock.defaults);
/**
* The callback function to invoke at the scheduled tick.
* @type {Function}
*/
this.callback = options.callback;
/**
* The time which the clock will schedule events in advance
* of the current time. Scheduling notes in advance improves
* performance and decreases the chance for clicks caused
* by scheduling events in the past. If set to "auto",
* this value will be automatically computed based on the
* rate of requestAnimationFrame (0.016 seconds). Larger values
* will yeild better performance, but at the cost of latency.
* Values less than 0.016 are not recommended.
* @type {Number|String}
*/
this._lookAhead = 'auto';
/**
* The lookahead value which was automatically
* computed using a time-based averaging.
* @type {Number}
* @private
*/
this._computedLookAhead = 1 / 60;
/**
* The value afterwhich events are thrown out
* @type {Number}
* @private
*/
this._threshold = 0.5;
/**
* The next time the callback is scheduled.
* @type {Number}
* @private
*/
this._nextTick = -1;
/**
* The last time the callback was invoked
* @type {Number}
* @private
*/
this._lastUpdate = 0;
/**
* The id of the requestAnimationFrame
* @type {Number}
* @private
*/
this._loopID = -1;
/**
* The rate the callback function should be invoked.
* @type {BPM}
* @signal
*/
this.frequency = new Tone.TimelineSignal(options.frequency, Tone.Type.Frequency);
/**
* The number of times the callback was invoked. Starts counting at 0
* and increments after the callback was invoked.
* @type {Ticks}
* @readOnly
*/
this.ticks = 0;
/**
* The state timeline
* @type {Tone.TimelineState}
* @private
*/
this._state = new Tone.TimelineState(Tone.State.Stopped);
/**
* A pre-binded loop function to save a tiny bit of overhead
* of rebinding the function on every frame.
* @type {Function}
* @private
*/
this._boundLoop = this._loop.bind(this);
this._readOnly('frequency');
//start the loop
this._loop();
};
Tone.extend(Tone.Clock);
/**
* The defaults
* @const
* @type {Object}
*/
Tone.Clock.defaults = {
'callback': Tone.noOp,
'frequency': 1,
'lookAhead': 'auto'
};
/**
* Returns the playback state of the source, either "started", "stopped" or "paused".
* @type {Tone.State}
* @readOnly
* @memberOf Tone.Clock#
* @name state
*/
Object.defineProperty(Tone.Clock.prototype, 'state', {
get: function () {
return this._state.getStateAtTime(this.now());
}
});
/**
* The time which the clock will schedule events in advance
* of the current time. Scheduling notes in advance improves
* performance and decreases the chance for clicks caused
* by scheduling events in the past. If set to "auto",
* this value will be automatically computed based on the
* rate of requestAnimationFrame (0.016 seconds). Larger values
* will yeild better performance, but at the cost of latency.
* Values less than 0.016 are not recommended.
* @type {Number|String}
* @memberOf Tone.Clock#
* @name lookAhead
*/
Object.defineProperty(Tone.Clock.prototype, 'lookAhead', {
get: function () {
return this._lookAhead;
},
set: function (val) {
if (val === 'auto') {
this._lookAhead = 'auto';
} else {
this._lookAhead = this.toSeconds(val);
}
}
});
/**
* Start the clock at the given time. Optionally pass in an offset
* of where to start the tick counter from.
* @param {Time} time The time the clock should start
* @param {Ticks=} offset Where the tick counter starts counting from.
* @return {Tone.Clock} this
*/
Tone.Clock.prototype.start = function (time, offset) {
time = this.toSeconds(time);
if (this._state.getStateAtTime(time) !== Tone.State.Started) {
this._state.addEvent({
'state': Tone.State.Started,
'time': time,
'offset': offset
});
}
return this;
};
/**
* Stop the clock. Stopping the clock resets the tick counter to 0.
* @param {Time} [time=now] The time when the clock should stop.
* @returns {Tone.Clock} this
* @example
* clock.stop();
*/
Tone.Clock.prototype.stop = function (time) {
time = this.toSeconds(time);
if (this._state.getStateAtTime(time) !== Tone.State.Stopped) {
this._state.setStateAtTime(Tone.State.Stopped, time);
}
return this;
};
/**
* Pause the clock. Pausing does not reset the tick counter.
* @param {Time} [time=now] The time when the clock should stop.
* @returns {Tone.Clock} this
*/
Tone.Clock.prototype.pause = function (time) {
time = this.toSeconds(time);
if (this._state.getStateAtTime(time) === Tone.State.Started) {
this._state.setStateAtTime(Tone.State.Paused, time);
}
return this;
};
/**
* The scheduling loop.
* @param {Number} time The current page time starting from 0
* when the page was loaded.
* @private
*/
Tone.Clock.prototype._loop = function (time) {
this._loopID = requestAnimationFrame(this._boundLoop);
//compute the look ahead
if (this._lookAhead === 'auto') {
if (!this.isUndef(time)) {
var diff = (time - this._lastUpdate) / 1000;
this._lastUpdate = time;
//throw away large differences
if (diff < this._threshold) {
//averaging
this._computedLookAhead = (9 * this._computedLookAhead + diff) / 10;
}
}
} else {
this._computedLookAhead = this._lookAhead;
}
//get the frequency value to compute the value of the next loop
var now = this.now();
//if it's started
var lookAhead = this._computedLookAhead * 2;
var event = this._state.getEvent(now + lookAhead);
var state = Tone.State.Stopped;
if (event) {
state = event.state;
//if it was stopped and now started
if (this._nextTick === -1 && state === Tone.State.Started) {
this._nextTick = event.time;
if (!this.isUndef(event.offset)) {
this.ticks = event.offset;
}
}
}
if (state === Tone.State.Started) {
while (now + lookAhead > this._nextTick) {
//catch up
if (now > this._nextTick + this._threshold) {
this._nextTick = now;
}
var tickTime = this._nextTick;
this._nextTick += 1 / this.frequency.getValueAtTime(this._nextTick);
this.callback(tickTime);
this.ticks++;
}
} else if (state === Tone.State.Stopped) {
this._nextTick = -1;
this.ticks = 0;
}
};
/**
* Returns the scheduled state at the given time.
* @param {Time} time The time to query.
* @return {String} The name of the state input in setStateAtTime.
* @example
* clock.start("+0.1");
* clock.getStateAtTime("+0.1"); //returns "started"
*/
Tone.Clock.prototype.getStateAtTime = function (time) {
return this._state.getStateAtTime(time);
};
/**
* Clean up
* @returns {Tone.Clock} this
*/
Tone.Clock.prototype.dispose = function () {
cancelAnimationFrame(this._loopID);
Tone.TimelineState.prototype.dispose.call(this);
this._writable('frequency');
this.frequency.dispose();
this.frequency = null;
this._boundLoop = Tone.noOp;
this._nextTick = Infinity;
this.callback = null;
this._state.dispose();
this._state = null;
};
return Tone.Clock;
});
Module(function (Tone) {
/**
* @class Tone.Emitter gives classes which extend it
* the ability to listen for and trigger events.
* Inspiration and reference from Jerome Etienne's [MicroEvent](https://github.com/jeromeetienne/microevent.js).
* MIT (c) 2011 Jerome Etienne.
*
* @extends {Tone}
*/
Tone.Emitter = function () {
/**
* Contains all of the events.
* @private
* @type {Object}
*/
this._events = {};
};
Tone.extend(Tone.Emitter);
/**
* Bind a callback to a specific event.
* @param {String} event The name of the event to listen for.
* @param {Function} callback The callback to invoke when the
* event is triggered
* @return {Tone.Emitter} this
*/
Tone.Emitter.prototype.on = function (event, callback) {
//split the event
var events = event.split(/\W+/);
for (var i = 0; i < events.length; i++) {
var eventName = events[i];
if (!this._events.hasOwnProperty(eventName)) {
this._events[eventName] = [];
}
this._events[eventName].push(callback);
}
return this;
};
/**
* Remove the event listener.
* @param {String} event The event to stop listening to.
* @param {Function=} callback The callback which was bound to
* the event with Tone.Emitter.on.
* If no callback is given, all callbacks
* events are removed.
* @return {Tone.Emitter} this
*/
Tone.Emitter.prototype.off = function (event, callback) {
var events = event.split(/\W+/);
for (var ev = 0; ev < events.length; ev++) {
event = events[ev];
if (this._events.hasOwnProperty(event)) {
if (Tone.prototype.isUndef(callback)) {
this._events[event] = [];
} else {
var eventList = this._events[event];
for (var i = 0; i < eventList.length; i++) {
if (eventList[i] === callback) {
eventList.splice(i, 1);
}
}
}
}
}
return this;
};
/**
* Invoke all of the callbacks bound to the event
* with any arguments passed in.
* @param {String} event The name of the event.
* @param {*...} args The arguments to pass to the functions listening.
* @return {Tone.Emitter} this
*/
Tone.Emitter.prototype.trigger = function (event) {
if (this._events) {
var args = Array.prototype.slice.call(arguments, 1);
if (this._events.hasOwnProperty(event)) {
var eventList = this._events[event];
for (var i = 0, len = eventList.length; i < len; i++) {
eventList[i].apply(this, args);
}
}
}
return this;
};
/**
* Add Emitter functions (on/off/trigger) to the object
* @param {Object|Function} object The object or class to extend.
*/
Tone.Emitter.mixin = function (object) {
var functions = [
'on',
'off',
'trigger'
];
object._events = {};
for (var i = 0; i < functions.length; i++) {
var func = functions[i];
var emitterFunc = Tone.Emitter.prototype[func];
object[func] = emitterFunc;
}
};
/**
* Clean up
* @return {Tone.Emitter} this
*/
Tone.Emitter.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._events = null;
return this;
};
return Tone.Emitter;
});
Module(function (Tone) {
/**
* @class Similar to Tone.Timeline, but all events represent
* intervals with both "time" and "duration" times. The
* events are placed in a tree structure optimized
* for querying an intersection point with the timeline
* events. Internally uses an [Interval Tree](https://en.wikipedia.org/wiki/Interval_tree)
* to represent the data.
* @extends {Tone}
*/
Tone.IntervalTimeline = function () {
/**
* The root node of the inteval tree
* @type {IntervalNode}
* @private
*/
this._root = null;
/**
* Keep track of the length of the timeline.
* @type {Number}
* @private
*/
this._length = 0;
};
Tone.extend(Tone.IntervalTimeline);
/**
* The event to add to the timeline. All events must
* have a time and duration value
* @param {Object} event The event to add to the timeline
* @return {Tone.IntervalTimeline} this
*/
Tone.IntervalTimeline.prototype.addEvent = function (event) {
if (this.isUndef(event.time) || this.isUndef(event.duration)) {
throw new Error('events must have time and duration parameters');
}
var node = new IntervalNode(event.time, event.time + event.duration, event);
if (this._root === null) {
this._root = node;
} else {
this._root.insert(node);
}
this._length++;
// Restructure tree to be balanced
while (node !== null) {
node.updateHeight();
node.updateMax();
this._rebalance(node);
node = node.parent;
}
return this;
};
/**
* Remove an event from the timeline.
* @param {Object} event The event to remove from the timeline
* @return {Tone.IntervalTimeline} this
*/
Tone.IntervalTimeline.prototype.removeEvent = function (event) {
if (this._root !== null) {
var results = [];
this._root.search(event.time, results);
for (var i = 0; i < results.length; i++) {
var node = results[i];
if (node.event === event) {
this._removeNode(node);
this._length--;
break;
}
}
}
return this;
};
/**
* The number of items in the timeline.
* @type {Number}
* @memberOf Tone.IntervalTimeline#
* @name length
* @readOnly
*/
Object.defineProperty(Tone.IntervalTimeline.prototype, 'length', {
get: function () {
return this._length;
}
});
/**
* Remove events whose time time is after the given time
* @param {Time} time The time to query.
* @returns {Tone.IntervalTimeline} this
*/
Tone.IntervalTimeline.prototype.cancel = function (after) {
after = this.toSeconds(after);
this.forEachAfter(after, function (event) {
this.removeEvent(event);
}.bind(this));
return this;
};
/**
* Set the root node as the given node
* @param {IntervalNode} node
* @private
*/
Tone.IntervalTimeline.prototype._setRoot = function (node) {
this._root = node;
if (this._root !== null) {
this._root.parent = null;
}
};
/**
* Replace the references to the node in the node's parent
* with the replacement node.
* @param {IntervalNode} node
* @param {IntervalNode} replacement
* @private
*/
Tone.IntervalTimeline.prototype._replaceNodeInParent = function (node, replacement) {
if (node.parent !== null) {
if (node.isLeftChild()) {
node.parent.left = replacement;
} else {
node.parent.right = replacement;
}
this._rebalance(node.parent);
} else {
this._setRoot(replacement);
}
};
/**
* Remove the node from the tree and replace it with
* a successor which follows the schema.
* @param {IntervalNode} node
* @private
*/
Tone.IntervalTimeline.prototype._removeNode = function (node) {
if (node.left === null && node.right === null) {
this._replaceNodeInParent(node, null);
} else if (node.right === null) {
this._replaceNodeInParent(node, node.left);
} else if (node.left === null) {
this._replaceNodeInParent(node, node.right);
} else {
var balance = node.getBalance();
var replacement, temp;
if (balance > 0) {
if (node.left.right === null) {
replacement = node.left;
replacement.right = node.right;
temp = replacement;
} else {
replacement = node.left.right;
while (replacement.right !== null) {
replacement = replacement.right;
}
replacement.parent.right = replacement.left;
temp = replacement.parent;
replacement.left = node.left;
replacement.right = node.right;
}
} else {
if (node.right.left === null) {
replacement = node.right;
replacement.left = node.left;
temp = replacement;
} else {
replacement = node.right.left;
while (replacement.left !== null) {
replacement = replacement.left;
}
replacement.parent = replacement.parent;
replacement.parent.left = replacement.right;
temp = replacement.parent;
replacement.left = node.left;
replacement.right = node.right;
}
}
if (node.parent !== null) {
if (node.isLeftChild()) {
node.parent.left = replacement;
} else {
node.parent.right = replacement;
}
} else {
this._setRoot(replacement);
}
// this._replaceNodeInParent(node, replacement);
this._rebalance(temp);
}
node.dispose();
};
/**
* Rotate the tree to the left
* @param {IntervalNode} node
* @private
*/
Tone.IntervalTimeline.prototype._rotateLeft = function (node) {
var parent = node.parent;
var isLeftChild = node.isLeftChild();
// Make node.right the new root of this sub tree (instead of node)
var pivotNode = node.right;
node.right = pivotNode.left;
pivotNode.left = node;
if (parent !== null) {
if (isLeftChild) {
parent.left = pivotNode;
} else {
parent.right = pivotNode;
}
} else {
this._setRoot(pivotNode);
}
};
/**
* Rotate the tree to the right
* @param {IntervalNode} node
* @private
*/
Tone.IntervalTimeline.prototype._rotateRight = function (node) {
var parent = node.parent;
var isLeftChild = node.isLeftChild();
// Make node.left the new root of this sub tree (instead of node)
var pivotNode = node.left;
node.left = pivotNode.right;
pivotNode.right = node;
if (parent !== null) {
if (isLeftChild) {
parent.left = pivotNode;
} else {
parent.right = pivotNode;
}
} else {
this._setRoot(pivotNode);
}
};
/**
* Balance the BST
* @param {IntervalNode} node
* @private
*/
Tone.IntervalTimeline.prototype._rebalance = function (node) {
var balance = node.getBalance();
if (balance > 1) {
if (node.left.getBalance() < 0) {
this._rotateLeft(node.left);
} else {
this._rotateRight(node);
}
} else if (balance < -1) {
if (node.right.getBalance() > 0) {
this._rotateRight(node.right);
} else {
this._rotateLeft(node);
}
}
};
/**
* Get an event whose time and duration span the give time. Will
* return the match whose "time" value is closest to the given time.
* @param {Object} event The event to add to the timeline
* @return {Object} The event which spans the desired time
*/
Tone.IntervalTimeline.prototype.getEvent = function (time) {
if (this._root !== null) {
var results = [];
this._root.search(time, results);
if (results.length > 0) {
var max = results[0];
for (var i = 1; i < results.length; i++) {
if (results[i].low > max.low) {
max = results[i];
}
}
return max.event;
}
}
return null;
};
/**
* Iterate over everything in the timeline.
* @param {Function} callback The callback to invoke with every item
* @returns {Tone.IntervalTimeline} this
*/
Tone.IntervalTimeline.prototype.forEach = function (callback) {
if (this._root !== null) {
var allNodes = [];
if (this._root !== null) {
this._root.traverse(function (node) {
allNodes.push(node);
});
}
for (var i = 0; i < allNodes.length; i++) {
var ev = allNodes[i].event;
if (ev) {
callback(ev);
}
}
}
return this;
};
/**
* Iterate over everything in the array in which the given time
* overlaps with the time and duration time of the event.
* @param {Time} time The time to check if items are overlapping
* @param {Function} callback The callback to invoke with every item
* @returns {Tone.IntervalTimeline} this
*/
Tone.IntervalTimeline.prototype.forEachOverlap = function (time, callback) {
time = this.toSeconds(time);
if (this._root !== null) {
var results = [];
this._root.search(time, results);
for (var i = results.length - 1; i >= 0; i--) {
var ev = results[i].event;
if (ev) {
callback(ev);
}
}
}
return this;
};
/**
* Iterate over everything in the array in which the time is greater
* than the given time.
* @param {Time} time The time to check if items are before
* @param {Function} callback The callback to invoke with every item
* @returns {Tone.IntervalTimeline} this
*/
Tone.IntervalTimeline.prototype.forEachAfter = function (time, callback) {
time = this.toSeconds(time);
if (this._root !== null) {
var results = [];
this._root.searchAfter(time, results);
for (var i = results.length - 1; i >= 0; i--) {
var ev = results[i].event;
if (ev) {
callback(ev);
}
}
}
return this;
};
/**
* Clean up
* @return {Tone.IntervalTimeline} this
*/
Tone.IntervalTimeline.prototype.dispose = function () {
var allNodes = [];
if (this._root !== null) {
this._root.traverse(function (node) {
allNodes.push(node);
});
}
for (var i = 0; i < allNodes.length; i++) {
allNodes[i].dispose();
}
allNodes = null;
this._root = null;
return this;
};
///////////////////////////////////////////////////////////////////////////
// INTERVAL NODE HELPER
///////////////////////////////////////////////////////////////////////////
/**
* Represents a node in the binary search tree, with the addition
* of a "high" value which keeps track of the highest value of
* its children.
* References:
* https://brooknovak.wordpress.com/2013/12/07/augmented-interval-tree-in-c/
* http://www.mif.vu.lt/~valdas/ALGORITMAI/LITERATURA/Cormen/Cormen.pdf
* @param {Number} low
* @param {Number} high
* @private
*/
var IntervalNode = function (low, high, event) {
//the event container
this.event = event;
//the low value
this.low = low;
//the high value
this.high = high;
//the high value for this and all child nodes
this.max = this.high;
//the nodes to the left
this._left = null;
//the nodes to the right
this._right = null;
//the parent node
this.parent = null;
//the number of child nodes
this.height = 0;
};
/**
* Insert a node into the correct spot in the tree
* @param {IntervalNode} node
*/
IntervalNode.prototype.insert = function (node) {
if (node.low <= this.low) {
if (this.left === null) {
this.left = node;
} else {
this.left.insert(node);
}
} else {
if (this.right === null) {
this.right = node;
} else {
this.right.insert(node);
}
}
};
/**
* Search the tree for nodes which overlap
* with the given point
* @param {Number} point The point to query
* @param {Array} results The array to put the results
*/
IntervalNode.prototype.search = function (point, results) {
// If p is to the right of the rightmost point of any interval
// in this node and all children, there won't be any matches.
if (point > this.max) {
return;
}
// Search left children
if (this.left !== null) {
this.left.search(point, results);
}
// Check this node
if (this.low <= point && this.high >= point) {
results.push(this);
}
// If p is to the left of the time of this interval,
// then it can't be in any child to the right.
if (this.low > point) {
return;
}
// Search right children
if (this.right !== null) {
this.right.search(point, results);
}
};
/**
* Search the tree for nodes which are less
* than the given point
* @param {Number} point The point to query
* @param {Array} results The array to put the results
*/
IntervalNode.prototype.searchAfter = function (point, results) {
// Check this node
if (this.low >= point) {
results.push(this);
if (this.left !== null) {
this.left.searchAfter(point, results);
}
}
// search the right side
if (this.right !== null) {
this.right.searchAfter(point, results);
}
};
/**
* Invoke the callback on this element and both it's branches
* @param {Function} callback
*/
IntervalNode.prototype.traverse = function (callback) {
callback(this);
if (this.left !== null) {
this.left.traverse(callback);
}
if (this.right !== null) {
this.right.traverse(callback);
}
};
/**
* Update the height of the node
*/
IntervalNode.prototype.updateHeight = function () {
if (this.left !== null && this.right !== null) {
this.height = Math.max(this.left.height, this.right.height) + 1;
} else if (this.right !== null) {
this.height = this.right.height + 1;
} else if (this.left !== null) {
this.height = this.left.height + 1;
} else {
this.height = 0;
}
};
/**
* Update the height of the node
*/
IntervalNode.prototype.updateMax = function () {
this.max = this.high;
if (this.left !== null) {
this.max = Math.max(this.max, this.left.max);
}
if (this.right !== null) {
this.max = Math.max(this.max, this.right.max);
}
};
/**
* The balance is how the leafs are distributed on the node
* @return {Number} Negative numbers are balanced to the right
*/
IntervalNode.prototype.getBalance = function () {
var balance = 0;
if (this.left !== null && this.right !== null) {
balance = this.left.height - this.right.height;
} else if (this.left !== null) {
balance = this.left.height + 1;
} else if (this.right !== null) {
balance = -(this.right.height + 1);
}
return balance;
};
/**
* @returns {Boolean} true if this node is the left child
* of its parent
*/
IntervalNode.prototype.isLeftChild = function () {
return this.parent !== null && this.parent.left === this;
};
/**
* get/set the left node
* @type {IntervalNode}
*/
Object.defineProperty(IntervalNode.prototype, 'left', {
get: function () {
return this._left;
},
set: function (node) {
this._left = node;
if (node !== null) {
node.parent = this;
}
this.updateHeight();
this.updateMax();
}
});
/**
* get/set the right node
* @type {IntervalNode}
*/
Object.defineProperty(IntervalNode.prototype, 'right', {
get: function () {
return this._right;
},
set: function (node) {
this._right = node;
if (node !== null) {
node.parent = this;
}
this.updateHeight();
this.updateMax();
}
});
/**
* null out references.
*/
IntervalNode.prototype.dispose = function () {
this.parent = null;
this._left = null;
this._right = null;
this.event = null;
};
///////////////////////////////////////////////////////////////////////////
// END INTERVAL NODE HELPER
///////////////////////////////////////////////////////////////////////////
return Tone.IntervalTimeline;
});
Module(function (Tone) {
/**
* @class Transport for timing musical events.
* Supports tempo curves and time changes. Unlike browser-based timing (setInterval, requestAnimationFrame)
* Tone.Transport timing events pass in the exact time of the scheduled event
* in the argument of the callback function. Pass that time value to the object
* you're scheduling. <br><br>
* A single transport is created for you when the library is initialized.
* <br><br>
* The transport emits the events: "start", "stop", "pause", and "loop" which are
* called with the time of that event as the argument.
*
* @extends {Tone.Emitter}
* @singleton
* @example
* //repeated event every 8th note
* Tone.Transport.setInterval(function(time){
* //do something with the time
* }, "8n");
* @example
* //one time event 1 second in the future
* Tone.Transport.setTimeout(function(time){
* //do something with the time
* }, 1);
* @example
* //event fixed to the Transports timeline.
* Tone.Transport.setTimeline(function(time){
* //do something with the time
* }, "16:0:0");
*/
Tone.Transport = function () {
Tone.Emitter.call(this);
///////////////////////////////////////////////////////////////////////
// LOOPING
//////////////////////////////////////////////////////////////////////
/**
* If the transport loops or not.
* @type {boolean}
*/
this.loop = false;
/**
* The loop start position in ticks
* @type {Ticks}
* @private
*/
this._loopStart = 0;
/**
* The loop end position in ticks
* @type {Ticks}
* @private
*/
this._loopEnd = 0;
///////////////////////////////////////////////////////////////////////
// CLOCK/TEMPO
//////////////////////////////////////////////////////////////////////
/**
* Pulses per quarter is the number of ticks per quarter note.
* @private
* @type {Number}
*/
this._ppq = TransportConstructor.defaults.PPQ;
/**
* watches the main oscillator for timing ticks
* initially starts at 120bpm
* @private
* @type {Tone.Clock}
*/
this._clock = new Tone.Clock({
'callback': this._processTick.bind(this),
'frequency': 0
});
/**
* The Beats Per Minute of the Transport.
* @type {BPM}
* @signal
* @example
* Tone.Transport.bpm.value = 80;
* //ramp the bpm to 120 over 10 seconds
* Tone.Transport.bpm.rampTo(120, 10);
*/
this.bpm = this._clock.frequency;
this.bpm._toUnits = this._toUnits.bind(this);
this.bpm._fromUnits = this._fromUnits.bind(this);
this.bpm.units = Tone.Type.BPM;
this.bpm.value = TransportConstructor.defaults.bpm;
this._readOnly('bpm');
/**
* The time signature, or more accurately the numerator
* of the time signature over a denominator of 4.
* @type {Number}
* @private
*/
this._timeSignature = TransportConstructor.defaults.timeSignature;
///////////////////////////////////////////////////////////////////////
// TIMELINE EVENTS
//////////////////////////////////////////////////////////////////////
/**
* All the events in an object to keep track by ID
* @type {Object}
* @private
*/
this._scheduledEvents = {};
/**
* The event ID counter
* @type {Number}
* @private
*/
this._eventID = 0;
/**
* The scheduled events.
* @type {Tone.Timeline}
* @private
*/
this._timeline = new Tone.Timeline();
/**
* Repeated events
* @type {Array}
* @private
*/
this._repeatedEvents = new Tone.IntervalTimeline();
/**
* Events that occur once
* @type {Array}
* @private
*/
this._onceEvents = new Tone.Timeline();
/**
* All of the synced Signals
* @private
* @type {Array}
*/
this._syncedSignals = [];
///////////////////////////////////////////////////////////////////////
// SWING
//////////////////////////////////////////////////////////////////////
var swingSeconds = this.notationToSeconds(TransportConstructor.defaults.swingSubdivision, TransportConstructor.defaults.bpm, TransportConstructor.defaults.timeSignature);
/**
* The subdivision of the swing
* @type {Ticks}
* @private
*/
this._swingTicks = swingSeconds / (60 / TransportConstructor.defaults.bpm) * this._ppq;
/**
* The swing amount
* @type {NormalRange}
* @private
*/
this._swingAmount = 0;
};
Tone.extend(Tone.Transport, Tone.Emitter);
/**
* the defaults
* @type {Object}
* @const
* @static
*/
Tone.Transport.defaults = {
'bpm': 120,
'swing': 0,
'swingSubdivision': '16n',
'timeSignature': 4,
'loopStart': 0,
'loopEnd': '4m',
'PPQ': 48
};
///////////////////////////////////////////////////////////////////////////////
// TICKS
///////////////////////////////////////////////////////////////////////////////
/**
* called on every tick
* @param {number} tickTime clock relative tick time
* @private
*/
Tone.Transport.prototype._processTick = function (tickTime) {
//handle swing
if (this._swingAmount > 0 && this._clock.ticks % this._ppq !== 0 && //not on a downbeat
this._clock.ticks % this._swingTicks === 0) {
//add some swing
tickTime += this.ticksToSeconds(this._swingTicks) * this._swingAmount;
}
//do the loop test
if (this.loop) {
if (this._clock.ticks === this._loopEnd) {
this.ticks = this._loopStart;
this.trigger('loop', tickTime);
}
}
var ticks = this._clock.ticks;
//fire the next tick events if their time has come
this._timeline.forEachAtTime(ticks, function (event) {
event.callback(tickTime);
});
//process the repeated events
this._repeatedEvents.forEachOverlap(ticks, function (event) {
if ((ticks - event.time) % event.interval === 0) {
event.callback(tickTime);
}
});
//process the single occurrence events
this._onceEvents.forEachBefore(ticks, function (event) {
event.callback(tickTime);
});
//and clear the single occurrence timeline
this._onceEvents.cancelBefore(ticks);
};
///////////////////////////////////////////////////////////////////////////////
// SCHEDULABLE EVENTS
///////////////////////////////////////////////////////////////////////////////
/**
* Schedule an event along the timeline.
* @param {Function} callback The callback to be invoked at the time.
* @param {Time} time The time to invoke the callback at.
* @return {Number} The id of the event which can be used for canceling the event.
* @example
* //trigger the callback when the Transport reaches the desired time
* Tone.Transport.schedule(function(time){
* envelope.triggerAttack(time);
* }, "128i");
*/
Tone.Transport.prototype.schedule = function (callback, time) {
var event = {
'time': this.toTicks(time),
'callback': callback
};
var id = this._eventID++;
this._scheduledEvents[id.toString()] = {
'event': event,
'timeline': this._timeline
};
this._timeline.addEvent(event);
return id;
};
/**
* Schedule a repeated event along the timeline. The event will fire
* at the `interval` starting at the `startTime` and for the specified
* `duration`.
* @param {Function} callback The callback to invoke.
* @param {Time} interval The duration between successive
* callbacks.
* @param {Time=} startTime When along the timeline the events should
* start being invoked.
* @param {Time} [duration=Infinity] How long the event should repeat.
* @return {Number} The ID of the scheduled event. Use this to cancel
* the event.
* @example
* //a callback invoked every eighth note after the first measure
* Tone.Transport.scheduleRepeat(callback, "8n", "1m");
*/
Tone.Transport.prototype.scheduleRepeat = function (callback, interval, startTime, duration) {
if (interval <= 0) {
throw new Error('repeat events must have an interval larger than 0');
}
var event = {
'time': this.toTicks(startTime),
'duration': this.toTicks(this.defaultArg(duration, Infinity)),
'interval': this.toTicks(interval),
'callback': callback
};
var id = this._eventID++;
this._scheduledEvents[id.toString()] = {
'event': event,
'timeline': this._repeatedEvents
};
this._repeatedEvents.addEvent(event);
return id;
};
/**
* Schedule an event that will be removed after it is invoked.
* Note that if the given time is less than the current transport time,
* the event will be invoked immediately.
* @param {Function} callback The callback to invoke once.
* @param {Time} time The time the callback should be invoked.
* @returns {Number} The ID of the scheduled event.
*/
Tone.Transport.prototype.scheduleOnce = function (callback, time) {
var event = {
'time': this.toTicks(time),
'callback': callback
};
var id = this._eventID++;
this._scheduledEvents[id.toString()] = {
'event': event,
'timeline': this._onceEvents
};
this._onceEvents.addEvent(event);
return id;
};
/**
* Clear the passed in event id from the timeline
* @param {Number} eventId The id of the event.
* @returns {Tone.Transport} this
*/
Tone.Transport.prototype.clear = function (eventId) {
if (this._scheduledEvents.hasOwnProperty(eventId)) {
var item = this._scheduledEvents[eventId.toString()];
item.timeline.removeEvent(item.event);
delete this._scheduledEvents[eventId.toString()];
}
return this;
};
/**
* Remove scheduled events from the timeline after
* the given time. Repeated events will be removed
* if their startTime is after the given time
* @param {Time} [after=0] Clear all events after
* this time.
* @returns {Tone.Transport} this
*/
Tone.Transport.prototype.cancel = function (after) {
after = this.defaultArg(after, 0);
after = this.toTicks(after);
this._timeline.cancel(after);
this._onceEvents.cancel(after);
this._repeatedEvents.cancel(after);
return this;
};
///////////////////////////////////////////////////////////////////////////////
// QUANTIZATION
///////////////////////////////////////////////////////////////////////////////
/**
* Returns the time closest time (equal to or after the given time) that aligns
* to the subidivision.
* @param {Time} time The time value to quantize to the given subdivision
* @param {String} [subdivision="4n"] The subdivision to quantize to.
* @return {Number} the time in seconds until the next subdivision.
* @example
* Tone.Transport.bpm.value = 120;
* Tone.Transport.quantize("3 * 4n", "1m"); //return 0.5
* //if the clock is started, it will return a value less than 0.5
*/
Tone.Transport.prototype.quantize = function (time, subdivision) {
subdivision = this.defaultArg(subdivision, '4n');
var tickTime = this.toTicks(time);
subdivision = this.toTicks(subdivision);
var remainingTicks = subdivision - tickTime % subdivision;
if (remainingTicks === subdivision) {
remainingTicks = 0;
}
var now = this.now();
if (this.state === Tone.State.Started) {
now = this._clock._nextTick;
}
return this.toSeconds(time, now) + this.ticksToSeconds(remainingTicks);
};
///////////////////////////////////////////////////////////////////////////////
// START/STOP/PAUSE
///////////////////////////////////////////////////////////////////////////////
/**
* Returns the playback state of the source, either "started", "stopped", or "paused"
* @type {Tone.State}
* @readOnly
* @memberOf Tone.Transport#
* @name state
*/
Object.defineProperty(Tone.Transport.prototype, 'state', {
get: function () {
return this._clock.getStateAtTime(this.now());
}
});
/**
* Start the transport and all sources synced to the transport.
* @param {Time} [time=now] The time when the transport should start.
* @param {Time=} offset The timeline offset to start the transport.
* @returns {Tone.Transport} this
* @example
* //start the transport in one second starting at beginning of the 5th measure.
* Tone.Transport.start("+1", "4:0:0");
*/
Tone.Transport.prototype.start = function (time, offset) {
time = this.toSeconds(time);
if (!this.isUndef(offset)) {
offset = this.toTicks(offset);
} else {
offset = this.defaultArg(offset, this._clock.ticks);
}
//start the clock
this._clock.start(time, offset);
this.trigger('start', time, this.ticksToSeconds(offset));
return this;
};
/**
* Stop the transport and all sources synced to the transport.
* @param {Time} [time=now] The time when the transport should stop.
* @returns {Tone.Transport} this
* @example
* Tone.Transport.stop();
*/
Tone.Transport.prototype.stop = function (time) {
time = this.toSeconds(time);
this._clock.stop(time);
this.trigger('stop', time);
return this;
};
/**
* Pause the transport and all sources synced to the transport.
* @param {Time} [time=now]
* @returns {Tone.Transport} this
*/
Tone.Transport.prototype.pause = function (time) {
time = this.toSeconds(time);
this._clock.pause(time);
this.trigger('pause', time);
return this;
};
///////////////////////////////////////////////////////////////////////////////
// SETTERS/GETTERS
///////////////////////////////////////////////////////////////////////////////
/**
* The time signature as just the numerator over 4.
* For example 4/4 would be just 4 and 6/8 would be 3.
* @memberOf Tone.Transport#
* @type {Number|Array}
* @name timeSignature
* @example
* //common time
* Tone.Transport.timeSignature = 4;
* // 7/8
* Tone.Transport.timeSignature = [7, 8];
* //this will be reduced to a single number
* Tone.Transport.timeSignature; //returns 3.5
*/
Object.defineProperty(Tone.Transport.prototype, 'timeSignature', {
get: function () {
return this._timeSignature;
},
set: function (timeSig) {
if (this.isArray(timeSig)) {
timeSig = timeSig[0] / timeSig[1] * 4;
}
this._timeSignature = timeSig;
}
});
/**
* When the Tone.Transport.loop = true, this is the starting position of the loop.
* @memberOf Tone.Transport#
* @type {Time}
* @name loopStart
*/
Object.defineProperty(Tone.Transport.prototype, 'loopStart', {
get: function () {
return this.ticksToSeconds(this._loopStart);
},
set: function (startPosition) {
this._loopStart = this.toTicks(startPosition);
}
});
/**
* When the Tone.Transport.loop = true, this is the ending position of the loop.
* @memberOf Tone.Transport#
* @type {Time}
* @name loopEnd
*/
Object.defineProperty(Tone.Transport.prototype, 'loopEnd', {
get: function () {
return this.ticksToSeconds(this._loopEnd);
},
set: function (endPosition) {
this._loopEnd = this.toTicks(endPosition);
}
});
/**
* Set the loop start and stop at the same time.
* @param {Time} startPosition
* @param {Time} endPosition
* @returns {Tone.Transport} this
* @example
* //loop over the first measure
* Tone.Transport.setLoopPoints(0, "1m");
* Tone.Transport.loop = true;
*/
Tone.Transport.prototype.setLoopPoints = function (startPosition, endPosition) {
this.loopStart = startPosition;
this.loopEnd = endPosition;
return this;
};
/**
* The swing value. Between 0-1 where 1 equal to
* the note + half the subdivision.
* @memberOf Tone.Transport#
* @type {NormalRange}
* @name swing
*/
Object.defineProperty(Tone.Transport.prototype, 'swing', {
get: function () {
return this._swingAmount * 2;
},
set: function (amount) {
//scale the values to a normal range
this._swingAmount = amount * 0.5;
}
});
/**
* Set the subdivision which the swing will be applied to.
* The default values is a 16th note. Value must be less
* than a quarter note.
*
* @memberOf Tone.Transport#
* @type {Time}
* @name swingSubdivision
*/
Object.defineProperty(Tone.Transport.prototype, 'swingSubdivision', {
get: function () {
return this.toNotation(this._swingTicks + 'i');
},
set: function (subdivision) {
this._swingTicks = this.toTicks(subdivision);
}
});
/**
* The Transport's position in MEASURES:BEATS:SIXTEENTHS.
* Setting the value will jump to that position right away.
*
* @memberOf Tone.Transport#
* @type {TransportTime}
* @name position
*/
Object.defineProperty(Tone.Transport.prototype, 'position', {
get: function () {
var quarters = this.ticks / this._ppq;
var measures = Math.floor(quarters / this._timeSignature);
var sixteenths = quarters % 1 * 4;
//if the sixteenths aren't a whole number, fix their length
if (sixteenths % 1 > 0) {
sixteenths = sixteenths.toFixed(3);
}
quarters = Math.floor(quarters) % this._timeSignature;
var progress = [
measures,
quarters,
sixteenths
];
return progress.join(':');
},
set: function (progress) {
var ticks = this.toTicks(progress);
this.ticks = ticks;
}
});
/**
* The Transport's loop position as a normalized value. Always
* returns 0 if the transport if loop is not true.
* @memberOf Tone.Transport#
* @name progress
* @type {NormalRange}
*/
Object.defineProperty(Tone.Transport.prototype, 'progress', {
get: function () {
if (this.loop) {
return (this.ticks - this._loopStart) / (this._loopEnd - this._loopStart);
} else {
return 0;
}
}
});
/**
* The transports current tick position.
*
* @memberOf Tone.Transport#
* @type {Ticks}
* @name ticks
*/
Object.defineProperty(Tone.Transport.prototype, 'ticks', {
get: function () {
return this._clock.ticks;
},
set: function (t) {
this._clock.ticks = t;
}
});
/**
* Pulses Per Quarter note. This is the smallest resolution
* the Transport timing supports. This should be set once
* on initialization and not set again. Changing this value
* after other objects have been created can cause problems.
*
* @memberOf Tone.Transport#
* @type {Number}
* @name PPQ
*/
Object.defineProperty(Tone.Transport.prototype, 'PPQ', {
get: function () {
return this._ppq;
},
set: function (ppq) {
this._ppq = ppq;
this.bpm.value = this.bpm.value;
}
});
/**
* Convert from BPM to frequency (factoring in PPQ)
* @param {BPM} bpm The BPM value to convert to frequency
* @return {Frequency} The BPM as a frequency with PPQ factored in.
* @private
*/
Tone.Transport.prototype._fromUnits = function (bpm) {
return 1 / (60 / bpm / this.PPQ);
};
/**
* Convert from frequency (with PPQ) into BPM
* @param {Frequency} freq The clocks frequency to convert to BPM
* @return {BPM} The frequency value as BPM.
* @private
*/
Tone.Transport.prototype._toUnits = function (freq) {
return freq / this.PPQ * 60;
};
///////////////////////////////////////////////////////////////////////////////
// SYNCING
///////////////////////////////////////////////////////////////////////////////
/**
* Attaches the signal to the tempo control signal so that
* any changes in the tempo will change the signal in the same
* ratio.
*
* @param {Tone.Signal} signal
* @param {number=} ratio Optionally pass in the ratio between
* the two signals. Otherwise it will be computed
* based on their current values.
* @returns {Tone.Transport} this
*/
Tone.Transport.prototype.syncSignal = function (signal, ratio) {
if (!ratio) {
//get the sync ratio
if (signal._param.value !== 0) {
ratio = signal._param.value / this.bpm._param.value;
} else {
ratio = 0;
}
}
var ratioSignal = new Tone.Gain(ratio);
this.bpm.chain(ratioSignal, signal._param);
this._syncedSignals.push({
'ratio': ratioSignal,
'signal': signal,
'initial': signal._param.value
});
signal._param.value = 0;
return this;
};
/**
* Unsyncs a previously synced signal from the transport's control.
* See Tone.Transport.syncSignal.
* @param {Tone.Signal} signal
* @returns {Tone.Transport} this
*/
Tone.Transport.prototype.unsyncSignal = function (signal) {
for (var i = this._syncedSignals.length - 1; i >= 0; i--) {
var syncedSignal = this._syncedSignals[i];
if (syncedSignal.signal === signal) {
syncedSignal.ratio.dispose();
syncedSignal.signal._param.value = syncedSignal.initial;
this._syncedSignals.splice(i, 1);
}
}
return this;
};
/**
* Clean up.
* @returns {Tone.Transport} this
* @private
*/
Tone.Transport.prototype.dispose = function () {
Tone.Emitter.prototype.dispose.call(this);
this._clock.dispose();
this._clock = null;
this._writable('bpm');
this.bpm = null;
this._timeline.dispose();
this._timeline = null;
this._onceEvents.dispose();
this._onceEvents = null;
this._repeatedEvents.dispose();
this._repeatedEvents = null;
return this;
};
///////////////////////////////////////////////////////////////////////////////
// DEPRECATED FUNCTIONS
// (will be removed in r7)
///////////////////////////////////////////////////////////////////////////////
/**
* @deprecated Use Tone.scheduleRepeat instead.
* Set a callback for a recurring event.
* @param {function} callback
* @param {Time} interval
* @return {number} the id of the interval
* @example
* //triggers a callback every 8th note with the exact time of the event
* Tone.Transport.setInterval(function(time){
* envelope.triggerAttack(time);
* }, "8n");
* @private
*/
Tone.Transport.prototype.setInterval = function (callback, interval) {
console.warn('This method is deprecated. Use Tone.Transport.scheduleRepeat instead.');
return Tone.Transport.scheduleRepeat(callback, interval);
};
/**
* @deprecated Use Tone.cancel instead.
* Stop and ongoing interval.
* @param {number} intervalID The ID of interval to remove. The interval
* ID is given as the return value in Tone.Transport.setInterval.
* @return {boolean} true if the event was removed
* @private
*/
Tone.Transport.prototype.clearInterval = function (id) {
console.warn('This method is deprecated. Use Tone.Transport.clear instead.');
return Tone.Transport.clear(id);
};
/**
* @deprecated Use Tone.Note instead.
* Set a timeout to occur after time from now. NB: the transport must be
* running for this to be triggered. All timeout events are cleared when the
* transport is stopped.
*
* @param {function} callback
* @param {Time} time The time (from now) that the callback will be invoked.
* @return {number} The id of the timeout.
* @example
* //trigger an event to happen 1 second from now
* Tone.Transport.setTimeout(function(time){
* player.start(time);
* }, 1)
* @private
*/
Tone.Transport.prototype.setTimeout = function (callback, timeout) {
console.warn('This method is deprecated. Use Tone.Transport.scheduleOnce instead.');
return Tone.Transport.scheduleOnce(callback, timeout);
};
/**
* @deprecated Use Tone.Note instead.
* Clear a timeout using it's ID.
* @param {number} intervalID The ID of timeout to remove. The timeout
* ID is given as the return value in Tone.Transport.setTimeout.
* @return {boolean} true if the timeout was removed
* @private
*/
Tone.Transport.prototype.clearTimeout = function (id) {
console.warn('This method is deprecated. Use Tone.Transport.clear instead.');
return Tone.Transport.clear(id);
};
/**
* @deprecated Use Tone.Note instead.
* Timeline events are synced to the timeline of the Tone.Transport.
* Unlike Timeout, Timeline events will restart after the
* Tone.Transport has been stopped and restarted.
*
* @param {function} callback
* @param {Time} time
* @return {number} the id for clearing the transportTimeline event
* @example
* //trigger the start of a part on the 16th measure
* Tone.Transport.setTimeline(function(time){
* part.start(time);
* }, "16m");
* @private
*/
Tone.Transport.prototype.setTimeline = function (callback, time) {
console.warn('This method is deprecated. Use Tone.Transport.schedule instead.');
return Tone.Transport.schedule(callback, time);
};
/**
* @deprecated Use Tone.Note instead.
* Clear the timeline event.
* @param {number} id
* @return {boolean} true if it was removed
* @private
*/
Tone.Transport.prototype.clearTimeline = function (id) {
console.warn('This method is deprecated. Use Tone.Transport.clear instead.');
return Tone.Transport.clear(id);
};
///////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
///////////////////////////////////////////////////////////////////////////////
var TransportConstructor = Tone.Transport;
Tone._initAudioContext(function () {
if (typeof Tone.Transport === 'function') {
//a single transport object
Tone.Transport = new Tone.Transport();
} else {
//stop the clock
Tone.Transport.stop();
//get the previous values
var prevSettings = Tone.Transport.get();
//destory the old transport
Tone.Transport.dispose();
//make new Transport insides
TransportConstructor.call(Tone.Transport);
//set the previous config
Tone.Transport.set(prevSettings);
}
});
return Tone.Transport;
});
Module(function (Tone) {
/**
* @class Tone.Volume is a simple volume node, useful for creating a volume fader.
*
* @extends {Tone}
* @constructor
* @param {Decibels} [volume=0] the initial volume
* @example
* var vol = new Tone.Volume(-12);
* instrument.chain(vol, Tone.Master);
*/
Tone.Volume = function () {
var options = this.optionsObject(arguments, ['volume'], Tone.Volume.defaults);
/**
* the output node
* @type {GainNode}
* @private
*/
this.output = this.input = new Tone.Gain(options.volume, Tone.Type.Decibels);
/**
* The volume control in decibels.
* @type {Decibels}
* @signal
*/
this.volume = this.output.gain;
this._readOnly('volume');
};
Tone.extend(Tone.Volume);
/**
* Defaults
* @type {Object}
* @const
* @static
*/
Tone.Volume.defaults = { 'volume': 0 };
/**
* clean up
* @returns {Tone.Volume} this
*/
Tone.Volume.prototype.dispose = function () {
this.input.dispose();
Tone.prototype.dispose.call(this);
this._writable('volume');
this.volume.dispose();
this.volume = null;
return this;
};
return Tone.Volume;
});
Module(function (Tone) {
/**
* @class Base class for sources. Sources have start/stop methods
* and the ability to be synced to the
* start/stop of Tone.Transport.
*
* @constructor
* @extends {Tone}
* @example
* //Multiple state change events can be chained together,
* //but must be set in the correct order and with ascending times
*
* // OK
* state.start().stop("+0.2");
* // AND
* state.start().stop("+0.2").start("+0.4").stop("+0.7")
*
* // BAD
* state.stop("+0.2").start();
* // OR
* state.start("+0.3").stop("+0.2");
*
*/
Tone.Source = function (options) {
//Sources only have an output and no input
Tone.call(this);
options = this.defaultArg(options, Tone.Source.defaults);
/**
* The output volume node
* @type {Tone.Volume}
* @private
*/
this._volume = this.output = new Tone.Volume(options.volume);
/**
* The volume of the output in decibels.
* @type {Decibels}
* @signal
* @example
* source.volume.value = -6;
*/
this.volume = this._volume.volume;
this._readOnly('volume');
/**
* Keep track of the scheduled state.
* @type {Tone.TimelineState}
* @private
*/
this._state = new Tone.TimelineState(Tone.State.Stopped);
/**
* The synced `start` callback function from the transport
* @type {Function}
* @private
*/
this._syncStart = function (time, offset) {
time = this.toSeconds(time);
time += this.toSeconds(this._startDelay);
this.start(time, offset);
}.bind(this);
/**
* The synced `stop` callback function from the transport
* @type {Function}
* @private
*/
this._syncStop = this.stop.bind(this);
/**
* The offset from the start of the Transport `start`
* @type {Time}
* @private
*/
this._startDelay = 0;
//make the output explicitly stereo
this._volume.output.output.channelCount = 2;
this._volume.output.output.channelCountMode = 'explicit';
};
Tone.extend(Tone.Source);
/**
* The default parameters
* @static
* @const
* @type {Object}
*/
Tone.Source.defaults = { 'volume': 0 };
/**
* Returns the playback state of the source, either "started" or "stopped".
* @type {Tone.State}
* @readOnly
* @memberOf Tone.Source#
* @name state
*/
Object.defineProperty(Tone.Source.prototype, 'state', {
get: function () {
return this._state.getStateAtTime(this.now());
}
});
/**
* Start the source at the specified time. If no time is given,
* start the source now.
* @param {Time} [time=now] When the source should be started.
* @returns {Tone.Source} this
* @example
* source.start("+0.5"); //starts the source 0.5 seconds from now
*/
Tone.Source.prototype.start = function (time) {
time = this.toSeconds(time);
if (this._state.getStateAtTime(time) !== Tone.State.Started || this.retrigger) {
this._state.setStateAtTime(Tone.State.Started, time);
if (this._start) {
this._start.apply(this, arguments);
}
}
return this;
};
/**
* Stop the source at the specified time. If no time is given,
* stop the source now.
* @param {Time} [time=now] When the source should be stopped.
* @returns {Tone.Source} this
* @example
* source.stop(); // stops the source immediately
*/
Tone.Source.prototype.stop = function (time) {
time = this.toSeconds(time);
if (this._state.getStateAtTime(time) === Tone.State.Started) {
this._state.setStateAtTime(Tone.State.Stopped, time);
if (this._stop) {
this._stop.apply(this, arguments);
}
}
return this;
};
/**
* Sync the source to the Transport so that when the transport
* is started, this source is started and when the transport is stopped
* or paused, so is the source.
*
* @param {Time} [delay=0] Delay time before starting the source after the
* Transport has started.
* @returns {Tone.Source} this
* @example
* //sync the source to start 1 measure after the transport starts
* source.sync("1m");
* //start the transport. the source will start 1 measure later.
* Tone.Transport.start();
*/
Tone.Source.prototype.sync = function (delay) {
this._startDelay = this.defaultArg(delay, 0);
Tone.Transport.on('start', this._syncStart);
Tone.Transport.on('stop pause', this._syncStop);
return this;
};
/**
* Unsync the source to the Transport. See Tone.Source.sync
* @returns {Tone.Source} this
*/
Tone.Source.prototype.unsync = function () {
this._startDelay = 0;
Tone.Transport.off('start', this._syncStart);
Tone.Transport.off('stop pause', this._syncStop);
return this;
};
/**
* Clean up.
* @return {Tone.Source} this
*/
Tone.Source.prototype.dispose = function () {
this.stop();
Tone.prototype.dispose.call(this);
this.unsync();
this._writable('volume');
this._volume.dispose();
this._volume = null;
this.volume = null;
this._state.dispose();
this._state = null;
this._syncStart = null;
this._syncStart = null;
};
return Tone.Source;
});
Module(function (Tone) {
/**
* @class Tone.Oscillator supports a number of features including
* phase rotation, multiple oscillator types (see Tone.Oscillator.type),
* and Transport syncing (see Tone.Oscillator.syncFrequency).
*
* @constructor
* @extends {Tone.Source}
* @param {Frequency} [frequency] Starting frequency
* @param {string} [type] The oscillator type. Read more about type below.
* @example
* //make and start a 440hz sine tone
* var osc = new Tone.Oscillator(440, "sine").toMaster().start();
*/
Tone.Oscillator = function () {
var options = this.optionsObject(arguments, [
'frequency',
'type'
], Tone.Oscillator.defaults);
Tone.Source.call(this, options);
/**
* the main oscillator
* @type {OscillatorNode}
* @private
*/
this._oscillator = null;
/**
* The frequency control.
* @type {Frequency}
* @signal
*/
this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
/**
* The detune control signal.
* @type {Cents}
* @signal
*/
this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);
/**
* the periodic wave
* @type {PeriodicWave}
* @private
*/
this._wave = null;
/**
* The partials of the oscillator
* @type {Array}
* @private
*/
this._partials = this.defaultArg(options.partials, [1]);
/**
* the phase of the oscillator
* between 0 - 360
* @type {number}
* @private
*/
this._phase = options.phase;
/**
* the type of the oscillator
* @type {string}
* @private
*/
this._type = null;
//setup
this.type = options.type;
this.phase = this._phase;
this._readOnly([
'frequency',
'detune'
]);
};
Tone.extend(Tone.Oscillator, Tone.Source);
/**
* the default parameters
* @type {Object}
*/
Tone.Oscillator.defaults = {
'type': 'sine',
'frequency': 440,
'detune': 0,
'phase': 0,
'partials': []
};
/**
* The Oscillator types
* @enum {String}
*/
Tone.Oscillator.Type = {
Sine: 'sine',
Triangle: 'triangle',
Sawtooth: 'sawtooth',
Square: 'square',
Custom: 'custom'
};
/**
* start the oscillator
* @param {Time} [time=now]
* @private
*/
Tone.Oscillator.prototype._start = function (time) {
//new oscillator with previous values
this._oscillator = this.context.createOscillator();
this._oscillator.setPeriodicWave(this._wave);
//connect the control signal to the oscillator frequency & detune
this._oscillator.connect(this.output);
this.frequency.connect(this._oscillator.frequency);
this.detune.connect(this._oscillator.detune);
//start the oscillator
this._oscillator.start(this.toSeconds(time));
};
/**
* stop the oscillator
* @private
* @param {Time} [time=now] (optional) timing parameter
* @returns {Tone.Oscillator} this
*/
Tone.Oscillator.prototype._stop = function (time) {
if (this._oscillator) {
this._oscillator.stop(this.toSeconds(time));
this._oscillator = null;
}
return this;
};
/**
* Sync the signal to the Transport's bpm. Any changes to the transports bpm,
* will also affect the oscillators frequency.
* @returns {Tone.Oscillator} this
* @example
* Tone.Transport.bpm.value = 120;
* osc.frequency.value = 440;
* //the ration between the bpm and the frequency will be maintained
* osc.syncFrequency();
* Tone.Transport.bpm.value = 240;
* // the frequency of the oscillator is doubled to 880
*/
Tone.Oscillator.prototype.syncFrequency = function () {
Tone.Transport.syncSignal(this.frequency);
return this;
};
/**
* Unsync the oscillator's frequency from the Transport.
* See Tone.Oscillator.syncFrequency
* @returns {Tone.Oscillator} this
*/
Tone.Oscillator.prototype.unsyncFrequency = function () {
Tone.Transport.unsyncSignal(this.frequency);
return this;
};
/**
* The type of the oscillator: either sine, square, triangle, or sawtooth. Also capable of
* setting the first x number of partials of the oscillator. For example: "sine4" would
* set be the first 4 partials of the sine wave and "triangle8" would set the first
* 8 partials of the triangle wave.
* <br><br>
* Uses PeriodicWave internally even for native types so that it can set the phase.
* PeriodicWave equations are from the
* [Webkit Web Audio implementation](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp&sq=package:chromium).
*
* @memberOf Tone.Oscillator#
* @type {string}
* @name type
* @example
* //set it to a square wave
* osc.type = "square";
* @example
* //set the first 6 partials of a sawtooth wave
* osc.type = "sawtooth6";
*/
Object.defineProperty(Tone.Oscillator.prototype, 'type', {
get: function () {
return this._type;
},
set: function (type) {
var coefs = this._getRealImaginary(type, this._phase);
var periodicWave = this.context.createPeriodicWave(coefs[0], coefs[1]);
this._wave = periodicWave;
if (this._oscillator !== null) {
this._oscillator.setPeriodicWave(this._wave);
}
this._type = type;
}
});
/**
* Returns the real and imaginary components based
* on the oscillator type.
* @returns {Array} [real, imaginary]
* @private
*/
Tone.Oscillator.prototype._getRealImaginary = function (type, phase) {
var fftSize = 4096;
var periodicWaveSize = fftSize / 2;
var real = new Float32Array(periodicWaveSize);
var imag = new Float32Array(periodicWaveSize);
var partialCount = 1;
if (type === Tone.Oscillator.Type.Custom) {
partialCount = this._partials.length + 1;
periodicWaveSize = partialCount;
} else {
var partial = /^(sine|triangle|square|sawtooth)(\d+)$/.exec(type);
if (partial) {
partialCount = parseInt(partial[2]) + 1;
type = partial[1];
partialCount = Math.max(partialCount, 2);
periodicWaveSize = partialCount;
}
}
for (var n = 1; n < periodicWaveSize; ++n) {
var piFactor = 2 / (n * Math.PI);
var b;
switch (type) {
case Tone.Oscillator.Type.Sine:
b = n <= partialCount ? 1 : 0;
break;
case Tone.Oscillator.Type.Square:
b = n & 1 ? 2 * piFactor : 0;
break;
case Tone.Oscillator.Type.Sawtooth:
b = piFactor * (n & 1 ? 1 : -1);
break;
case Tone.Oscillator.Type.Triangle:
if (n & 1) {
b = 2 * (piFactor * piFactor) * (n - 1 >> 1 & 1 ? -1 : 1);
} else {
b = 0;
}
break;
case Tone.Oscillator.Type.Custom:
b = this._partials[n - 1];
break;
default:
throw new Error('invalid oscillator type: ' + type);
}
if (b !== 0) {
real[n] = -b * Math.sin(phase * n);
imag[n] = b * Math.cos(phase * n);
} else {
real[n] = 0;
imag[n] = 0;
}
}
return [
real,
imag
];
};
/**
* Compute the inverse FFT for a given phase.
* @param {Float32Array} real
* @param {Float32Array} imag
* @param {NormalRange} phase
* @return {AudioRange}
* @private
*/
Tone.Oscillator.prototype._inverseFFT = function (real, imag, phase) {
var sum = 0;
var len = real.length;
for (var i = 0; i < len; i++) {
sum += real[i] * Math.cos(i * phase) + imag[i] * Math.sin(i * phase);
}
return sum;
};
/**
* Returns the initial value of the oscillator.
* @return {AudioRange}
* @private
*/
Tone.Oscillator.prototype._getInitialValue = function () {
var coefs = this._getRealImaginary(this._type, 0);
var real = coefs[0];
var imag = coefs[1];
var maxValue = 0;
var twoPi = Math.PI * 2;
//check for peaks in 8 places
for (var i = 0; i < 8; i++) {
maxValue = Math.max(this._inverseFFT(real, imag, i / 8 * twoPi), maxValue);
}
return -this._inverseFFT(real, imag, this._phase) / maxValue;
};
/**
* The partials of the waveform. A partial represents
* the amplitude at a harmonic. The first harmonic is the
* fundamental frequency, the second is the octave and so on
* following the harmonic series.
* Setting this value will automatically set the type to "custom".
* The value is an empty array when the type is not "custom".
* @memberOf Tone.Oscillator#
* @type {Array}
* @name partials
* @example
* osc.partials = [1, 0.2, 0.01];
*/
Object.defineProperty(Tone.Oscillator.prototype, 'partials', {
get: function () {
if (this._type !== Tone.Oscillator.Type.Custom) {
return [];
} else {
return this._partials;
}
},
set: function (partials) {
this._partials = partials;
this.type = Tone.Oscillator.Type.Custom;
}
});
/**
* The phase of the oscillator in degrees.
* @memberOf Tone.Oscillator#
* @type {Degrees}
* @name phase
* @example
* osc.phase = 180; //flips the phase of the oscillator
*/
Object.defineProperty(Tone.Oscillator.prototype, 'phase', {
get: function () {
return this._phase * (180 / Math.PI);
},
set: function (phase) {
this._phase = phase * Math.PI / 180;
//reset the type
this.type = this._type;
}
});
/**
* Dispose and disconnect.
* @return {Tone.Oscillator} this
*/
Tone.Oscillator.prototype.dispose = function () {
Tone.Source.prototype.dispose.call(this);
if (this._oscillator !== null) {
this._oscillator.disconnect();
this._oscillator = null;
}
this._wave = null;
this._writable([
'frequency',
'detune'
]);
this.frequency.dispose();
this.frequency = null;
this.detune.dispose();
this.detune = null;
this._partials = null;
return this;
};
return Tone.Oscillator;
});
Module(function (Tone) {
/**
* @class LFO stands for low frequency oscillator. Tone.LFO produces an output signal
* which can be attached to an AudioParam or Tone.Signal
* in order to modulate that parameter with an oscillator. The LFO can
* also be synced to the transport to start/stop and change when the tempo changes.
*
* @constructor
* @extends {Tone.Oscillator}
* @param {Frequency|Object} [frequency] The frequency of the oscillation. Typically, LFOs will be
* in the frequency range of 0.1 to 10 hertz.
* @param {number=} min The minimum output value of the LFO.
* @param {number=} max The maximum value of the LFO.
* @example
* var lfo = new Tone.LFO("4n", 400, 4000);
* lfo.connect(filter.frequency);
*/
Tone.LFO = function () {
var options = this.optionsObject(arguments, [
'frequency',
'min',
'max'
], Tone.LFO.defaults);
/**
* The oscillator.
* @type {Tone.Oscillator}
* @private
*/
this._oscillator = new Tone.Oscillator({
'frequency': options.frequency,
'type': options.type
});
/**
* the lfo's frequency
* @type {Frequency}
* @signal
*/
this.frequency = this._oscillator.frequency;
/**
* The amplitude of the LFO, which controls the output range between
* the min and max output. For example if the min is -10 and the max
* is 10, setting the amplitude to 0.5 would make the LFO modulate
* between -5 and 5.
* @type {Number}
* @signal
*/
this.amplitude = this._oscillator.volume;
this.amplitude.units = Tone.Type.NormalRange;
this.amplitude.value = options.amplitude;
/**
* The signal which is output when the LFO is stopped
* @type {Tone.Signal}
* @private
*/
this._stoppedSignal = new Tone.Signal(0, Tone.Type.AudioRange);
/**
* The value that the LFO outputs when it's stopped
* @type {AudioRange}
* @private
*/
this._stoppedValue = 0;
/**
* @type {Tone.AudioToGain}
* @private
*/
this._a2g = new Tone.AudioToGain();
/**
* @type {Tone.Scale}
* @private
*/
this._scaler = this.output = new Tone.Scale(options.min, options.max);
/**
* the units of the LFO (used for converting)
* @type {Tone.Type}
* @private
*/
this._units = Tone.Type.Default;
this.units = options.units;
//connect it up
this._oscillator.chain(this._a2g, this._scaler);
this._stoppedSignal.connect(this._a2g);
this._readOnly([
'amplitude',
'frequency'
]);
this.phase = options.phase;
};
Tone.extend(Tone.LFO, Tone.Oscillator);
/**
* the default parameters
*
* @static
* @const
* @type {Object}
*/
Tone.LFO.defaults = {
'type': 'sine',
'min': 0,
'max': 1,
'phase': 0,
'frequency': '4n',
'amplitude': 1,
'units': Tone.Type.Default
};
/**
* Start the LFO.
* @param {Time} [time=now] the time the LFO will start
* @returns {Tone.LFO} this
*/
Tone.LFO.prototype.start = function (time) {
time = this.toSeconds(time);
this._stoppedSignal.setValueAtTime(0, time);
this._oscillator.start(time);
return this;
};
/**
* Stop the LFO.
* @param {Time} [time=now] the time the LFO will stop
* @returns {Tone.LFO} this
*/
Tone.LFO.prototype.stop = function (time) {
time = this.toSeconds(time);
this._stoppedSignal.setValueAtTime(this._stoppedValue, time);
this._oscillator.stop(time);
return this;
};
/**
* Sync the start/stop/pause to the transport
* and the frequency to the bpm of the transport
*
* @param {Time} [delay=0] the time to delay the start of the
* LFO from the start of the transport
* @returns {Tone.LFO} this
* @example
* lfo.frequency.value = "8n";
* lfo.sync();
* //the rate of the LFO will always be an eighth note,
* //even as the tempo changes
*/
Tone.LFO.prototype.sync = function (delay) {
this._oscillator.sync(delay);
this._oscillator.syncFrequency();
return this;
};
/**
* unsync the LFO from transport control
* @returns {Tone.LFO} this
*/
Tone.LFO.prototype.unsync = function () {
this._oscillator.unsync();
this._oscillator.unsyncFrequency();
return this;
};
/**
* The miniumum output of the LFO.
* @memberOf Tone.LFO#
* @type {number}
* @name min
*/
Object.defineProperty(Tone.LFO.prototype, 'min', {
get: function () {
return this._toUnits(this._scaler.min);
},
set: function (min) {
min = this._fromUnits(min);
this._scaler.min = min;
}
});
/**
* The maximum output of the LFO.
* @memberOf Tone.LFO#
* @type {number}
* @name max
*/
Object.defineProperty(Tone.LFO.prototype, 'max', {
get: function () {
return this._toUnits(this._scaler.max);
},
set: function (max) {
max = this._fromUnits(max);
this._scaler.max = max;
}
});
/**
* The type of the oscillator: sine, square, sawtooth, triangle.
* @memberOf Tone.LFO#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.LFO.prototype, 'type', {
get: function () {
return this._oscillator.type;
},
set: function (type) {
this._oscillator.type = type;
this._stoppedValue = this._oscillator._getInitialValue();
this._stoppedSignal.value = this._stoppedValue;
}
});
/**
* The phase of the LFO.
* @memberOf Tone.LFO#
* @type {number}
* @name phase
*/
Object.defineProperty(Tone.LFO.prototype, 'phase', {
get: function () {
return this._oscillator.phase;
},
set: function (phase) {
this._oscillator.phase = phase;
this._stoppedValue = this._oscillator._getInitialValue();
this._stoppedSignal.value = this._stoppedValue;
}
});
/**
* The output units of the LFO.
* @memberOf Tone.LFO#
* @type {Tone.Type}
* @name units
*/
Object.defineProperty(Tone.LFO.prototype, 'units', {
get: function () {
return this._units;
},
set: function (val) {
var currentMin = this.min;
var currentMax = this.max;
//convert the min and the max
this._units = val;
this.min = currentMin;
this.max = currentMax;
}
});
/**
* Returns the playback state of the source, either "started" or "stopped".
* @type {Tone.State}
* @readOnly
* @memberOf Tone.LFO#
* @name state
*/
Object.defineProperty(Tone.LFO.prototype, 'state', {
get: function () {
return this._oscillator.state;
}
});
/**
* Connect the output of the LFO to an AudioParam, AudioNode, or Tone Node.
* Tone.LFO will automatically convert to the destination units of the
* will get the units from the connected node.
* @param {Tone | AudioParam | AudioNode} node
* @param {number} [outputNum=0] optionally which output to connect from
* @param {number} [inputNum=0] optionally which input to connect to
* @returns {Tone.LFO} this
* @private
*/
Tone.LFO.prototype.connect = function (node) {
if (node.constructor === Tone.Signal || node.constructor === Tone.Param || node.constructor === Tone.TimelineSignal) {
this.convert = node.convert;
this.units = node.units;
}
Tone.Signal.prototype.connect.apply(this, arguments);
return this;
};
/**
* private method borrowed from Param converts
* units from their destination value
* @function
* @private
*/
Tone.LFO.prototype._fromUnits = Tone.Param.prototype._fromUnits;
/**
* private method borrowed from Param converts
* units to their destination value
* @function
* @private
*/
Tone.LFO.prototype._toUnits = Tone.Param.prototype._toUnits;
/**
* disconnect and dispose
* @returns {Tone.LFO} this
*/
Tone.LFO.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable([
'amplitude',
'frequency'
]);
this._oscillator.dispose();
this._oscillator = null;
this._stoppedSignal.dispose();
this._stoppedSignal = null;
this._scaler.dispose();
this._scaler = null;
this._a2g.dispose();
this._a2g = null;
this.frequency = null;
this.amplitude = null;
return this;
};
return Tone.LFO;
});
Module(function (Tone) {
/**
* @class Tone.Limiter will limit the loudness of an incoming signal.
* It is composed of a Tone.Compressor with a fast attack
* and release. Limiters are commonly used to safeguard against
* signal clipping. Unlike a compressor, limiters do not provide
* smooth gain reduction and almost completely prevent
* additional gain above the threshold.
*
* @extends {Tone}
* @constructor
* @param {number} threshold The theshold above which the limiting is applied.
* @example
* var limiter = new Tone.Limiter(-6);
*/
Tone.Limiter = function () {
var options = this.optionsObject(arguments, ['threshold'], Tone.Limiter.defaults);
/**
* the compressor
* @private
* @type {Tone.Compressor}
*/
this._compressor = this.input = this.output = new Tone.Compressor({
'attack': 0.001,
'decay': 0.001,
'threshold': options.threshold
});
/**
* The threshold of of the limiter
* @type {Decibel}
* @signal
*/
this.threshold = this._compressor.threshold;
this._readOnly('threshold');
};
Tone.extend(Tone.Limiter);
/**
* The default value
* @type {Object}
* @const
* @static
*/
Tone.Limiter.defaults = { 'threshold': -12 };
/**
* Clean up.
* @returns {Tone.Limiter} this
*/
Tone.Limiter.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._compressor.dispose();
this._compressor = null;
this._writable('threshold');
this.threshold = null;
return this;
};
return Tone.Limiter;
});
Module(function (Tone) {
/**
* @class Tone.Lowpass is a lowpass feedback comb filter. It is similar to
* Tone.FeedbackCombFilter, but includes a lowpass filter.
*
* @extends {Tone}
* @constructor
* @param {Time|Object} [delayTime] The delay time of the comb filter
* @param {NormalRange=} resonance The resonance (feedback) of the comb filter
* @param {Frequency=} dampening The cutoff of the lowpass filter dampens the
* signal as it is fedback.
*/
Tone.LowpassCombFilter = function () {
Tone.call(this);
var options = this.optionsObject(arguments, [
'delayTime',
'resonance',
'dampening'
], Tone.LowpassCombFilter.defaults);
/**
* the delay node
* @type {DelayNode}
* @private
*/
this._delay = this.input = this.context.createDelay(1);
/**
* The delayTime of the comb filter.
* @type {Time}
* @signal
*/
this.delayTime = new Tone.Signal(options.delayTime, Tone.Type.Time);
/**
* the lowpass filter
* @type {BiquadFilterNode}
* @private
*/
this._lowpass = this.output = this.context.createBiquadFilter();
this._lowpass.Q.value = 0;
this._lowpass.type = 'lowpass';
/**
* The dampening control of the feedback
* @type {Frequency}
* @signal
*/
this.dampening = new Tone.Param({
'param': this._lowpass.frequency,
'units': Tone.Type.Frequency,
'value': options.dampening
});
/**
* the feedback gain
* @type {GainNode}
* @private
*/
this._feedback = this.context.createGain();
/**
* The amount of feedback of the delayed signal.
* @type {NormalRange}
* @signal
*/
this.resonance = new Tone.Param({
'param': this._feedback.gain,
'units': Tone.Type.NormalRange,
'value': options.resonance
});
//connections
this._delay.chain(this._lowpass, this._feedback, this._delay);
this.delayTime.connect(this._delay.delayTime);
this._readOnly([
'dampening',
'resonance',
'delayTime'
]);
};
Tone.extend(Tone.LowpassCombFilter);
/**
* the default parameters
* @static
* @const
* @type {Object}
*/
Tone.LowpassCombFilter.defaults = {
'delayTime': 0.1,
'resonance': 0.5,
'dampening': 3000
};
/**
* Clean up.
* @returns {Tone.LowpassCombFilter} this
*/
Tone.LowpassCombFilter.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable([
'dampening',
'resonance',
'delayTime'
]);
this.dampening.dispose();
this.dampening = null;
this.resonance.dispose();
this.resonance = null;
this._delay.disconnect();
this._delay = null;
this._lowpass.disconnect();
this._lowpass = null;
this._feedback.disconnect();
this._feedback = null;
this.delayTime.dispose();
this.delayTime = null;
return this;
};
return Tone.LowpassCombFilter;
});
Module(function (Tone) {
/**
* @class Tone.Merge brings two signals into the left and right
* channels of a single stereo channel.
*
* @constructor
* @extends {Tone}
* @example
* var merge = new Tone.Merge().toMaster();
* //routing a sine tone in the left channel
* //and noise in the right channel
* var osc = new Tone.Oscillator().connect(merge.left);
* var noise = new Tone.Noise().connect(merge.right);
* //starting our oscillators
* noise.start();
* osc.start();
*/
Tone.Merge = function () {
Tone.call(this, 2, 0);
/**
* The left input channel.
* Alias for <code>input[0]</code>
* @type {GainNode}
*/
this.left = this.input[0] = this.context.createGain();
/**
* The right input channel.
* Alias for <code>input[1]</code>.
* @type {GainNode}
*/
this.right = this.input[1] = this.context.createGain();
/**
* the merger node for the two channels
* @type {ChannelMergerNode}
* @private
*/
this._merger = this.output = this.context.createChannelMerger(2);
//connections
this.left.connect(this._merger, 0, 0);
this.right.connect(this._merger, 0, 1);
this.left.channelCount = 1;
this.right.channelCount = 1;
this.left.channelCountMode = 'explicit';
this.right.channelCountMode = 'explicit';
};
Tone.extend(Tone.Merge);
/**
* Clean up.
* @returns {Tone.Merge} this
*/
Tone.Merge.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this.left.disconnect();
this.left = null;
this.right.disconnect();
this.right = null;
this._merger.disconnect();
this._merger = null;
return this;
};
return Tone.Merge;
});
Module(function (Tone) {
/**
* @class Tone.Meter gets the [RMS](https://en.wikipedia.org/wiki/Root_mean_square)
* of an input signal with some averaging applied.
* It can also get the raw value of the signal or the value in dB. For signal
* processing, it's better to use Tone.Follower which will produce an audio-rate
* envelope follower instead of needing to poll the Meter to get the output.
* <br><br>
* Meter was inspired by [Chris Wilsons Volume Meter](https://github.com/cwilso/volume-meter/blob/master/volume-meter.js).
*
* @constructor
* @extends {Tone}
* @param {number} [channels=1] number of channels being metered
* @param {number} [smoothing=0.8] amount of smoothing applied to the volume
* @param {number} [clipMemory=0.5] number in seconds that a "clip" should be remembered
* @example
* var meter = new Tone.Meter();
* var mic = new Tone.Microphone().start();
* //connect mic to the meter
* mic.connect(meter);
* //use getLevel or getDb
* //to access meter level
* meter.getLevel();
*/
Tone.Meter = function () {
var options = this.optionsObject(arguments, [
'channels',
'smoothing'
], Tone.Meter.defaults);
//extends Unit
Tone.call(this);
/**
* The channel count
* @type {number}
* @private
*/
this._channels = options.channels;
/**
* The amount which the decays of the meter are smoothed. Small values
* will follow the contours of the incoming envelope more closely than large values.
* @type {NormalRange}
*/
this.smoothing = options.smoothing;
/**
* The amount of time a clip is remember for.
* @type {Time}
*/
this.clipMemory = options.clipMemory;
/**
* The value above which the signal is considered clipped.
* @type {Number}
*/
this.clipLevel = options.clipLevel;
/**
* the rms for each of the channels
* @private
* @type {Array}
*/
this._volume = new Array(this._channels);
/**
* the raw values for each of the channels
* @private
* @type {Array}
*/
this._values = new Array(this._channels);
//zero out the volume array
for (var i = 0; i < this._channels; i++) {
this._volume[i] = 0;
this._values[i] = 0;
}
/**
* last time the values clipped
* @private
* @type {Array}
*/
this._lastClip = new Array(this._channels);
//zero out the clip array
for (var j = 0; j < this._lastClip.length; j++) {
this._lastClip[j] = 0;
}
/**
* @private
* @type {ScriptProcessorNode}
*/
this._jsNode = this.context.createScriptProcessor(options.bufferSize, this._channels, 1);
this._jsNode.onaudioprocess = this._onprocess.bind(this);
//so it doesn't get garbage collected
this._jsNode.noGC();
//signal just passes
this.input.connect(this.output);
this.input.connect(this._jsNode);
};
Tone.extend(Tone.Meter);
/**
* The defaults
* @type {Object}
* @static
* @const
*/
Tone.Meter.defaults = {
'smoothing': 0.8,
'bufferSize': 1024,
'clipMemory': 0.5,
'clipLevel': 0.9,
'channels': 1
};
/**
* called on each processing frame
* @private
* @param {AudioProcessingEvent} event
*/
Tone.Meter.prototype._onprocess = function (event) {
var bufferSize = this._jsNode.bufferSize;
var smoothing = this.smoothing;
for (var channel = 0; channel < this._channels; channel++) {
var input = event.inputBuffer.getChannelData(channel);
var sum = 0;
var total = 0;
var x;
for (var i = 0; i < bufferSize; i++) {
x = input[i];
total += x;
sum += x * x;
}
var average = total / bufferSize;
var rms = Math.sqrt(sum / bufferSize);
if (rms > 0.9) {
this._lastClip[channel] = Date.now();
}
this._volume[channel] = Math.max(rms, this._volume[channel] * smoothing);
this._values[channel] = average;
}
};
/**
* Get the rms of the signal.
* @param {number} [channel=0] which channel
* @return {number} the value
*/
Tone.Meter.prototype.getLevel = function (channel) {
channel = this.defaultArg(channel, 0);
var vol = this._volume[channel];
if (vol < 0.00001) {
return 0;
} else {
return vol;
}
};
/**
* Get the raw value of the signal.
* @param {number=} channel
* @return {number}
*/
Tone.Meter.prototype.getValue = function (channel) {
channel = this.defaultArg(channel, 0);
return this._values[channel];
};
/**
* Get the volume of the signal in dB
* @param {number=} channel
* @return {Decibels}
*/
Tone.Meter.prototype.getDb = function (channel) {
return this.gainToDb(this.getLevel(channel));
};
/**
* @returns {boolean} if the audio has clipped. The value resets
* based on the clipMemory defined.
*/
Tone.Meter.prototype.isClipped = function (channel) {
channel = this.defaultArg(channel, 0);
return Date.now() - this._lastClip[channel] < this._clipMemory * 1000;
};
/**
* Clean up.
* @returns {Tone.Meter} this
*/
Tone.Meter.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._jsNode.disconnect();
this._jsNode.onaudioprocess = null;
this._jsNode = null;
this._volume = null;
this._values = null;
this._lastClip = null;
return this;
};
return Tone.Meter;
});
Module(function (Tone) {
/**
* @class Tone.Split splits an incoming signal into left and right channels.
*
* @constructor
* @extends {Tone}
* @example
* var split = new Tone.Split();
* stereoSignal.connect(split);
*/
Tone.Split = function () {
Tone.call(this, 0, 2);
/**
* @type {ChannelSplitterNode}
* @private
*/
this._splitter = this.input = this.context.createChannelSplitter(2);
/**
* Left channel output.
* Alias for <code>output[0]</code>
* @type {GainNode}
*/
this.left = this.output[0] = this.context.createGain();
/**
* Right channel output.
* Alias for <code>output[1]</code>
* @type {GainNode}
*/
this.right = this.output[1] = this.context.createGain();
//connections
this._splitter.connect(this.left, 0, 0);
this._splitter.connect(this.right, 1, 0);
};
Tone.extend(Tone.Split);
/**
* Clean up.
* @returns {Tone.Split} this
*/
Tone.Split.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._splitter.disconnect();
this.left.disconnect();
this.right.disconnect();
this.left = null;
this.right = null;
this._splitter = null;
return this;
};
return Tone.Split;
});
Module(function (Tone) {
/**
* @class Mid/Side processing separates the the 'mid' signal
* (which comes out of both the left and the right channel)
* and the 'side' (which only comes out of the the side channels). <br><br>
* <code>
* Mid = (Left+Right)/sqrt(2); // obtain mid-signal from left and right<br>
* Side = (Left-Right)/sqrt(2); // obtain side-signal from left and righ<br>
* </code>
*
* @extends {Tone}
* @constructor
*/
Tone.MidSideSplit = function () {
Tone.call(this, 0, 2);
/**
* split the incoming signal into left and right channels
* @type {Tone.Split}
* @private
*/
this._split = this.input = new Tone.Split();
/**
* The mid send. Connect to mid processing. Alias for
* <code>output[0]</code>
* @type {Tone.Expr}
*/
this.mid = this.output[0] = new Tone.Expr('($0 + $1) * $2');
/**
* The side output. Connect to side processing. Alias for
* <code>output[1]</code>
* @type {Tone.Expr}
*/
this.side = this.output[1] = new Tone.Expr('($0 - $1) * $2');
this._split.connect(this.mid, 0, 0);
this._split.connect(this.mid, 1, 1);
this._split.connect(this.side, 0, 0);
this._split.connect(this.side, 1, 1);
sqrtTwo.connect(this.mid, 0, 2);
sqrtTwo.connect(this.side, 0, 2);
};
Tone.extend(Tone.MidSideSplit);
/**
* a constant signal equal to 1 / sqrt(2)
* @type {Number}
* @signal
* @private
* @static
*/
var sqrtTwo = null;
Tone._initAudioContext(function () {
sqrtTwo = new Tone.Signal(1 / Math.sqrt(2));
});
/**
* clean up
* @returns {Tone.MidSideSplit} this
*/
Tone.MidSideSplit.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this.mid.dispose();
this.mid = null;
this.side.dispose();
this.side = null;
this._split.dispose();
this._split = null;
return this;
};
return Tone.MidSideSplit;
});
Module(function (Tone) {
/**
* @class Mid/Side processing separates the the 'mid' signal
* (which comes out of both the left and the right channel)
* and the 'side' (which only comes out of the the side channels).
* MidSideMerge merges the mid and side signal after they've been seperated
* by Tone.MidSideSplit.<br><br>
* <code>
* Left = (Mid+Side)/sqrt(2); // obtain left signal from mid and side<br>
* Right = (Mid-Side)/sqrt(2); // obtain right signal from mid and side<br>
* </code>
*
* @extends {Tone.StereoEffect}
* @constructor
*/
Tone.MidSideMerge = function () {
Tone.call(this, 2, 0);
/**
* The mid signal input. Alias for
* <code>input[0]</code>
* @type {GainNode}
*/
this.mid = this.input[0] = this.context.createGain();
/**
* recombine the mid/side into Left
* @type {Tone.Expr}
* @private
*/
this._left = new Tone.Expr('($0 + $1) * $2');
/**
* The side signal input. Alias for
* <code>input[1]</code>
* @type {GainNode}
*/
this.side = this.input[1] = this.context.createGain();
/**
* recombine the mid/side into Right
* @type {Tone.Expr}
* @private
*/
this._right = new Tone.Expr('($0 - $1) * $2');
/**
* Merge the left/right signal back into a stereo signal.
* @type {Tone.Merge}
* @private
*/
this._merge = this.output = new Tone.Merge();
this.mid.connect(this._left, 0, 0);
this.side.connect(this._left, 0, 1);
this.mid.connect(this._right, 0, 0);
this.side.connect(this._right, 0, 1);
this._left.connect(this._merge, 0, 0);
this._right.connect(this._merge, 0, 1);
sqrtTwo.connect(this._left, 0, 2);
sqrtTwo.connect(this._right, 0, 2);
};
Tone.extend(Tone.MidSideMerge);
/**
* A constant signal equal to 1 / sqrt(2).
* @type {Number}
* @signal
* @private
* @static
*/
var sqrtTwo = null;
Tone._initAudioContext(function () {
sqrtTwo = new Tone.Signal(1 / Math.sqrt(2));
});
/**
* clean up
* @returns {Tone.MidSideMerge} this
*/
Tone.MidSideMerge.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this.mid.disconnect();
this.mid = null;
this.side.disconnect();
this.side = null;
this._left.dispose();
this._left = null;
this._right.dispose();
this._right = null;
this._merge.dispose();
this._merge = null;
return this;
};
return Tone.MidSideMerge;
});
Module(function (Tone) {
/**
* @class Tone.MidSideCompressor applies two different compressors to the mid
* and side signal components. See Tone.MidSideSplit.
*
* @extends {Tone}
* @param {Object} options The options that are passed to the mid and side
* compressors.
* @constructor
*/
Tone.MidSideCompressor = function (options) {
options = this.defaultArg(options, Tone.MidSideCompressor.defaults);
/**
* the mid/side split
* @type {Tone.MidSideSplit}
* @private
*/
this._midSideSplit = this.input = new Tone.MidSideSplit();
/**
* the mid/side recombination
* @type {Tone.MidSideMerge}
* @private
*/
this._midSideMerge = this.output = new Tone.MidSideMerge();
/**
* The compressor applied to the mid signal
* @type {Tone.Compressor}
*/
this.mid = new Tone.Compressor(options.mid);
/**
* The compressor applied to the side signal
* @type {Tone.Compressor}
*/
this.side = new Tone.Compressor(options.side);
this._midSideSplit.mid.chain(this.mid, this._midSideMerge.mid);
this._midSideSplit.side.chain(this.side, this._midSideMerge.side);
this._readOnly([
'mid',
'side'
]);
};
Tone.extend(Tone.MidSideCompressor);
/**
* @const
* @static
* @type {Object}
*/
Tone.MidSideCompressor.defaults = {
'mid': {
'ratio': 3,
'threshold': -24,
'release': 0.03,
'attack': 0.02,
'knee': 16
},
'side': {
'ratio': 6,
'threshold': -30,
'release': 0.25,
'attack': 0.03,
'knee': 10
}
};
/**
* Clean up.
* @returns {Tone.MidSideCompressor} this
*/
Tone.MidSideCompressor.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable([
'mid',
'side'
]);
this.mid.dispose();
this.mid = null;
this.side.dispose();
this.side = null;
this._midSideSplit.dispose();
this._midSideSplit = null;
this._midSideMerge.dispose();
this._midSideMerge = null;
return this;
};
return Tone.MidSideCompressor;
});
Module(function (Tone) {
/**
* @class Tone.Mono coerces the incoming mono or stereo signal into a mono signal
* where both left and right channels have the same value. This can be useful
* for [stereo imaging](https://en.wikipedia.org/wiki/Stereo_imaging).
*
* @extends {Tone}
* @constructor
*/
Tone.Mono = function () {
Tone.call(this, 1, 0);
/**
* merge the signal
* @type {Tone.Merge}
* @private
*/
this._merge = this.output = new Tone.Merge();
this.input.connect(this._merge, 0, 0);
this.input.connect(this._merge, 0, 1);
this.input.gain.value = this.dbToGain(-10);
};
Tone.extend(Tone.Mono);
/**
* clean up
* @returns {Tone.Mono} this
*/
Tone.Mono.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._merge.dispose();
this._merge = null;
return this;
};
return Tone.Mono;
});
Module(function (Tone) {
/**
* @class A compressor with seperate controls over low/mid/high dynamics
*
* @extends {Tone}
* @constructor
* @param {Object} options The low/mid/high compressor settings.
* @example
* var multiband = new Tone.MultibandCompressor({
* "lowFrequency" : 200,
* "highFrequency" : 1300
* "low" : {
* "threshold" : -12
* }
* })
*/
Tone.MultibandCompressor = function (options) {
options = this.defaultArg(arguments, Tone.MultibandCompressor.defaults);
/**
* split the incoming signal into high/mid/low
* @type {Tone.MultibandSplit}
* @private
*/
this._splitter = this.input = new Tone.MultibandSplit({
'lowFrequency': options.lowFrequency,
'highFrequency': options.highFrequency
});
/**
* low/mid crossover frequency.
* @type {Frequency}
* @signal
*/
this.lowFrequency = this._splitter.lowFrequency;
/**
* mid/high crossover frequency.
* @type {Frequency}
* @signal
*/
this.highFrequency = this._splitter.highFrequency;
/**
* the output
* @type {GainNode}
* @private
*/
this.output = this.context.createGain();
/**
* The compressor applied to the low frequencies.
* @type {Tone.Compressor}
*/
this.low = new Tone.Compressor(options.low);
/**
* The compressor applied to the mid frequencies.
* @type {Tone.Compressor}
*/
this.mid = new Tone.Compressor(options.mid);
/**
* The compressor applied to the high frequencies.
* @type {Tone.Compressor}
*/
this.high = new Tone.Compressor(options.high);
//connect the compressor
this._splitter.low.chain(this.low, this.output);
this._splitter.mid.chain(this.mid, this.output);
this._splitter.high.chain(this.high, this.output);
this._readOnly([
'high',
'mid',
'low',
'highFrequency',
'lowFrequency'
]);
};
Tone.extend(Tone.MultibandCompressor);
/**
* @const
* @static
* @type {Object}
*/
Tone.MultibandCompressor.defaults = {
'low': Tone.Compressor.defaults,
'mid': Tone.Compressor.defaults,
'high': Tone.Compressor.defaults,
'lowFrequency': 250,
'highFrequency': 2000
};
/**
* clean up
* @returns {Tone.MultibandCompressor} this
*/
Tone.MultibandCompressor.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._splitter.dispose();
this._writable([
'high',
'mid',
'low',
'highFrequency',
'lowFrequency'
]);
this.low.dispose();
this.mid.dispose();
this.high.dispose();
this._splitter = null;
this.low = null;
this.mid = null;
this.high = null;
this.lowFrequency = null;
this.highFrequency = null;
return this;
};
return Tone.MultibandCompressor;
});
Module(function (Tone) {
/**
* @class Maps a NormalRange [0, 1] to an AudioRange [-1, 1].
* See also Tone.AudioToGain.
*
* @extends {Tone.SignalBase}
* @constructor
* @example
* var g2a = new Tone.GainToAudio();
*/
Tone.GainToAudio = function () {
/**
* @type {WaveShaperNode}
* @private
*/
this._norm = this.input = this.output = new Tone.WaveShaper(function (x) {
return Math.abs(x) * 2 - 1;
});
};
Tone.extend(Tone.GainToAudio, Tone.SignalBase);
/**
* clean up
* @returns {Tone.GainToAudio} this
*/
Tone.GainToAudio.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._norm.dispose();
this._norm = null;
return this;
};
return Tone.GainToAudio;
});
Module(function (Tone) {
/**
* @class Tone.Panner is an equal power Left/Right Panner and does not
* support 3D. Panner uses the StereoPannerNode when available.
*
* @constructor
* @extends {Tone}
* @param {NormalRange} [initialPan=0.5] The initail panner value (defaults to 0.5 = center)
* @example
* //pan the input signal hard right.
* var panner = new Tone.Panner(1);
*/
Tone.Panner = function (initialPan) {
Tone.call(this);
/**
* indicates if the panner is using the new StereoPannerNode internally
* @type {boolean}
* @private
*/
this._hasStereoPanner = this.isFunction(this.context.createStereoPanner);
if (this._hasStereoPanner) {
/**
* the panner node
* @type {StereoPannerNode}
* @private
*/
this._panner = this.input = this.output = this.context.createStereoPanner();
/**
* The pan control. 0 = hard left, 1 = hard right.
* @type {NormalRange}
* @signal
*/
this.pan = new Tone.Signal(0, Tone.Type.NormalRange);
/**
* scale the pan signal to between -1 and 1
* @type {Tone.WaveShaper}
* @private
*/
this._scalePan = new Tone.GainToAudio();
//connections
this.pan.chain(this._scalePan, this._panner.pan);
} else {
/**
* the dry/wet knob
* @type {Tone.CrossFade}
* @private
*/
this._crossFade = new Tone.CrossFade();
/**
* @type {Tone.Merge}
* @private
*/
this._merger = this.output = new Tone.Merge();
/**
* @type {Tone.Split}
* @private
*/
this._splitter = this.input = new Tone.Split();
/**
* The pan control. 0 = hard left, 1 = hard right.
* @type {NormalRange}
* @signal
*/
this.pan = this._crossFade.fade;
//CONNECTIONS:
//left channel is a, right channel is b
this._splitter.connect(this._crossFade, 0, 0);
this._splitter.connect(this._crossFade, 1, 1);
//merge it back together
this._crossFade.a.connect(this._merger, 0, 0);
this._crossFade.b.connect(this._merger, 0, 1);
}
//initial value
this.pan.value = this.defaultArg(initialPan, 0.5);
this._readOnly('pan');
};
Tone.extend(Tone.Panner);
/**
* Clean up.
* @returns {Tone.Panner} this
*/
Tone.Panner.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable('pan');
if (this._hasStereoPanner) {
this._panner.disconnect();
this._panner = null;
this.pan.dispose();
this.pan = null;
this._scalePan.dispose();
this._scalePan = null;
} else {
this._crossFade.dispose();
this._crossFade = null;
this._splitter.dispose();
this._splitter = null;
this._merger.dispose();
this._merger = null;
this.pan = null;
}
return this;
};
return Tone.Panner;
});
Module(function (Tone) {
/**
* @class Tone.PanVol is a Tone.Panner and Tone.Volume in one.
*
* @extends {Tone}
* @constructor
* @param {NormalRange} pan the initial pan
* @param {number} volume The output volume.
* @example
* //pan the incoming signal left and drop the volume
* var panVol = new Tone.PanVol(0.25, -12);
*/
Tone.PanVol = function () {
var options = this.optionsObject(arguments, [
'pan',
'volume'
], Tone.PanVol.defaults);
/**
* The panning node
* @type {Tone.Panner}
* @private
*/
this._panner = this.input = new Tone.Panner(options.pan);
/**
* The L/R panning control.
* @type {NormalRange}
* @signal
*/
this.pan = this._panner.pan;
/**
* The volume node
* @type {Tone.Volume}
*/
this._volume = this.output = new Tone.Volume(options.volume);
/**
* The volume control in decibels.
* @type {Decibels}
* @signal
*/
this.volume = this._volume.volume;
//connections
this._panner.connect(this._volume);
this._readOnly([
'pan',
'volume'
]);
};
Tone.extend(Tone.PanVol);
/**
* The defaults
* @type {Object}
* @const
* @static
*/
Tone.PanVol.defaults = {
'pan': 0.5,
'volume': 0
};
/**
* clean up
* @returns {Tone.PanVol} this
*/
Tone.PanVol.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable([
'pan',
'volume'
]);
this._panner.dispose();
this._panner = null;
this.pan = null;
this._volume.dispose();
this._volume = null;
this.volume = null;
return this;
};
return Tone.PanVol;
});
Module(function (Tone) {
/**
* @class Tone.CtrlInterpolate will interpolate between given values based
* on the "index" property. Passing in an array or object literal
* will interpolate each of the parameters. Note (i.e. "C3")
* and Time (i.e. "4n + 2") can be interpolated. All other values are
* assumed to be numbers.
* @example
* var interp = new Tone.CtrlInterpolate([0, 2, 9, 4]);
* interp.index = 0.75;
* interp.value; //returns 1.5
*
* @example
* var interp = new Tone.CtrlInterpolate([
* ["C3", "G4", "E5"],
* ["D4", "F#4", "E5"],
* ]);
* @param {Array} values The array of values to interpolate over
* @param {Positive} index The initial interpolation index.
* @extends {Tone}
*/
Tone.CtrlInterpolate = function () {
var options = this.optionsObject(arguments, [
'values',
'index'
], Tone.CtrlInterpolate.defaults);
/**
* The values to interpolate between
* @type {Array}
*/
this.values = options.values;
/**
* The interpolated index between values. For example: a value of 1.5
* would interpolate equally between the value at index 1
* and the value at index 2.
* @example
* interp.index = 0;
* interp.value; //returns the value at 0
* interp.index = 0.5;
* interp.value; //returns the value between indices 0 and 1.
* @type {Positive}
*/
this.index = options.index;
};
Tone.extend(Tone.CtrlInterpolate);
/**
* The defaults
* @const
* @type {Object}
*/
Tone.CtrlInterpolate.defaults = {
'index': 0,
'values': []
};
/**
* The current interpolated value based on the index
* @readOnly
* @memberOf Tone.CtrlInterpolate#
* @type {*}
* @name value
*/
Object.defineProperty(Tone.CtrlInterpolate.prototype, 'value', {
get: function () {
var index = this.index;
index = Math.min(index, this.values.length - 1);
var lowerPosition = Math.floor(index);
var lower = this.values[lowerPosition];
var upper = this.values[Math.ceil(index)];
return this._interpolate(index - lowerPosition, lower, upper);
}
});
/**
* Internal interpolation routine
* @param {NormalRange} index The index between the lower and upper
* @param {*} lower
* @param {*} upper
* @return {*} The interpolated value
* @private
*/
Tone.CtrlInterpolate.prototype._interpolate = function (index, lower, upper) {
if (this.isArray(lower)) {
var retArray = [];
for (var i = 0; i < lower.length; i++) {
retArray[i] = this._interpolate(index, lower[i], upper[i]);
}
return retArray;
} else if (this.isObject(lower)) {
var retObj = {};
for (var attr in lower) {
retObj[attr] = this._interpolate(index, lower[attr], upper[attr]);
}
return retObj;
} else {
lower = this._toNumber(lower);
upper = this._toNumber(upper);
return (1 - index) * lower + index * upper;
}
};
/**
* Convert from the given type into a number
* @param {Number|String} value
* @return {Number}
* @private
*/
Tone.CtrlInterpolate.prototype._toNumber = function (val) {
if (this.isNumber(val)) {
return val;
} else if (this.isNote(val)) {
return this.toFrequency(val);
} else {
//otherwise assume that it's Time...
return this.toSeconds(val);
}
};
/**
* Clean up
* @return {Tone.CtrlInterpolate} this
*/
Tone.CtrlInterpolate.prototype.dispose = function () {
this.values = null;
};
return Tone.CtrlInterpolate;
});
Module(function (Tone) {
/**
* @class Tone.CtrlMarkov represents a Markov Chain where each call
* to Tone.CtrlMarkov.next will move to the next state. If the next
* state choice is an array, the next state is chosen randomly with
* even probability for all of the choices. For a weighted probability
* of the next choices, pass in an object with "state" and "probability" attributes.
* The probabilities will be normalized and then chosen. If no next options
* are given for the current state, the state will stay there.
* @extends {Tone}
* @example
* var chain = new Tone.CtrlMarkov({
* "beginning" : ["end", "middle"],
* "middle" : "end"
* });
* chain.value = "beginning";
* chain.next(); //returns "end" or "middle" with 50% probability
*
* @example
* var chain = new Tone.CtrlMarkov({
* "beginning" : [{"value" : "end", "probability" : 0.8},
* {"value" : "middle", "probability" : 0.2}],
* "middle" : "end"
* });
* chain.value = "beginning";
* chain.next(); //returns "end" with 80% probability or "middle" with 20%.
* @param {Object} values An object with the state names as the keys
* and the next state(s) as the values.
*/
Tone.CtrlMarkov = function (values, initial) {
/**
* The Markov values with states as the keys
* and next state(s) as the values.
* @type {Object}
*/
this.values = this.defaultArg(values, {});
/**
* The current state of the Markov values. The next
* state will be evaluated and returned when Tone.CtrlMarkov.next
* is invoked.
* @type {String}
*/
this.value = this.defaultArg(initial, Object.keys(this.values)[0]);
};
Tone.extend(Tone.CtrlMarkov);
/**
* Returns the next state of the Markov values.
* @return {String}
*/
Tone.CtrlMarkov.prototype.next = function () {
if (this.values.hasOwnProperty(this.value)) {
var next = this.values[this.value];
if (this.isArray(next)) {
var distribution = this._getProbDistribution(next);
var rand = Math.random();
var total = 0;
for (var i = 0; i < distribution.length; i++) {
var dist = distribution[i];
if (rand > total && rand < total + dist) {
var chosen = next[i];
if (this.isObject(chosen)) {
this.value = chosen.value;
} else {
this.value = chosen;
}
}
total += dist;
}
} else {
this.value = next;
}
}
return this.value;
};
/**
* Choose randomly from an array weighted options in the form
* {"state" : string, "probability" : number} or an array of values
* @param {Array} options
* @return {Array} The randomly selected choice
* @private
*/
Tone.CtrlMarkov.prototype._getProbDistribution = function (options) {
var distribution = [];
var total = 0;
var needsNormalizing = false;
for (var i = 0; i < options.length; i++) {
var option = options[i];
if (this.isObject(option)) {
needsNormalizing = true;
distribution[i] = option.probability;
} else {
distribution[i] = 1 / options.length;
}
total += distribution[i];
}
if (needsNormalizing) {
//normalize the values
for (var j = 0; j < distribution.length; j++) {
distribution[j] = distribution[j] / total;
}
}
return distribution;
};
/**
* Clean up
* @return {Tone.CtrlMarkov} this
*/
Tone.CtrlMarkov.prototype.dispose = function () {
this.values = null;
};
return Tone.CtrlMarkov;
});
Module(function (Tone) {
/**
* @class Generate patterns from an array of values.
* Has a number of arpeggiation and randomized
* selection patterns.
* <ul>
* <li>"up" - cycles upward</li>
* <li>"down" - cycles downward</li>
* <li>"upDown" - up then and down</li>
* <li>"downUp" - cycles down then and up</li>
* <li>"alternateUp" - jump up two and down one</li>
* <li>"alternateDown" - jump down two and up one</li>
* <li>"random" - randomly select an index</li>
* <li>"randomWalk" - randomly moves one index away from the current position</li>
* <li>"randomOnce" - randomly select an index without repeating until all values have been chosen.</li>
* </ul>
* @param {Array} values An array of options to choose from.
* @param {Tone.CtrlPattern.Type=} type The name of the pattern.
* @extends {Tone}
*/
Tone.CtrlPattern = function () {
var options = this.optionsObject(arguments, [
'values',
'type'
], Tone.CtrlPattern.defaults);
/**
* The array of values to arpeggiate over
* @type {Array}
*/
this.values = options.values;
/**
* The current position in the values array
* @type {Number}
*/
this.index = 0;
/**
* The type placeholder
* @type {Tone.CtrlPattern.Type}
* @private
*/
this._type = null;
/**
* Shuffled values for the RandomOnce type
* @type {Array}
* @private
*/
this._shuffled = null;
/**
* The direction of the movement
* @type {String}
* @private
*/
this._direction = null;
this.type = options.type;
};
Tone.extend(Tone.CtrlPattern);
/**
* The Control Patterns
* @type {Object}
* @static
*/
Tone.CtrlPattern.Type = {
Up: 'up',
Down: 'down',
UpDown: 'upDown',
DownUp: 'downUp',
AlternateUp: 'alternateUp',
AlternateDown: 'alternateDown',
Random: 'random',
RandomWalk: 'randomWalk',
RandomOnce: 'randomOnce'
};
/**
* The default values.
* @type {Object}
*/
Tone.CtrlPattern.defaults = {
'type': Tone.CtrlPattern.Type.Up,
'values': []
};
/**
* The value at the current index of the pattern.
* @readOnly
* @memberOf Tone.CtrlPattern#
* @type {*}
* @name value
*/
Object.defineProperty(Tone.CtrlPattern.prototype, 'value', {
get: function () {
//some safeguards
if (this.values.length === 0) {
return;
} else if (this.values.length === 1) {
return this.values[0];
}
this.index = Math.min(this.index, this.values.length - 1);
var val = this.values[this.index];
if (this.type === Tone.CtrlPattern.Type.RandomOnce) {
if (this.values.length !== this._shuffled.length) {
this._shuffleValues();
}
val = this.values[this._shuffled[this.index]];
}
return val;
}
});
/**
* The pattern used to select the next
* item from the values array
* @memberOf Tone.CtrlPattern#
* @type {Tone.CtrlPattern.Type}
* @name type
*/
Object.defineProperty(Tone.CtrlPattern.prototype, 'type', {
get: function () {
return this._type;
},
set: function (type) {
this._type = type;
this._shuffled = null;
//the first index
if (this._type === Tone.CtrlPattern.Type.Up || this._type === Tone.CtrlPattern.Type.UpDown || this._type === Tone.CtrlPattern.Type.RandomOnce || this._type === Tone.CtrlPattern.Type.AlternateUp) {
this.index = 0;
} else if (this._type === Tone.CtrlPattern.Type.Down || this._type === Tone.CtrlPattern.Type.DownUp || this._type === Tone.CtrlPattern.Type.AlternateDown) {
this.index = this.values.length - 1;
}
//the direction
if (this._type === Tone.CtrlPattern.Type.UpDown || this._type === Tone.CtrlPattern.Type.AlternateUp) {
this._direction = Tone.CtrlPattern.Type.Up;
} else if (this._type === Tone.CtrlPattern.Type.DownUp || this._type === Tone.CtrlPattern.Type.AlternateDown) {
this._direction = Tone.CtrlPattern.Type.Down;
}
//randoms
if (this._type === Tone.CtrlPattern.Type.RandomOnce) {
this._shuffleValues();
} else if (this._type === Tone.CtrlPattern.Random) {
this.index = Math.floor(Math.random() * this.values.length);
}
}
});
/**
* Return the next value given the current position
* and pattern.
* @return {*} The next value
*/
Tone.CtrlPattern.prototype.next = function () {
var type = this.type;
//choose the next index
if (type === Tone.CtrlPattern.Type.Up) {
this.index++;
if (this.index >= this.values.length) {
this.index = 0;
}
} else if (type === Tone.CtrlPattern.Type.Down) {
this.index--;
if (this.index < 0) {
this.index = this.values.length - 1;
}
} else if (type === Tone.CtrlPattern.Type.UpDown || type === Tone.CtrlPattern.Type.DownUp) {
if (this._direction === Tone.CtrlPattern.Type.Up) {
this.index++;
} else {
this.index--;
}
if (this.index < 0) {
this.index = 1;
this._direction = Tone.CtrlPattern.Type.Up;
} else if (this.index >= this.values.length) {
this.index = this.values.length - 2;
this._direction = Tone.CtrlPattern.Type.Down;
}
} else if (type === Tone.CtrlPattern.Type.Random) {
this.index = Math.floor(Math.random() * this.values.length);
} else if (type === Tone.CtrlPattern.Type.RandomWalk) {
if (Math.random() < 0.5) {
this.index--;
this.index = Math.max(this.index, 0);
} else {
this.index++;
this.index = Math.min(this.index, this.values.length - 1);
}
} else if (type === Tone.CtrlPattern.Type.RandomOnce) {
this.index++;
if (this.index >= this.values.length) {
this.index = 0;
//reshuffle the values for next time
this._shuffleValues();
}
} else if (type === Tone.CtrlPattern.Type.AlternateUp) {
if (this._direction === Tone.CtrlPattern.Type.Up) {
this.index += 2;
this._direction = Tone.CtrlPattern.Type.Down;
} else {
this.index -= 1;
this._direction = Tone.CtrlPattern.Type.Up;
}
if (this.index >= this.values.length) {
this.index = 0;
this._direction = Tone.CtrlPattern.Type.Up;
}
} else if (type === Tone.CtrlPattern.Type.AlternateDown) {
if (this._direction === Tone.CtrlPattern.Type.Up) {
this.index += 1;
this._direction = Tone.CtrlPattern.Type.Down;
} else {
this.index -= 2;
this._direction = Tone.CtrlPattern.Type.Up;
}
if (this.index < 0) {
this.index = this.values.length - 1;
this._direction = Tone.CtrlPattern.Type.Down;
}
}
return this.value;
};
/**
* Shuffles the values and places the results into the _shuffled
* @private
*/
Tone.CtrlPattern.prototype._shuffleValues = function () {
var copy = [];
this._shuffled = [];
for (var i = 0; i < this.values.length; i++) {
copy[i] = i;
}
while (copy.length > 0) {
var randVal = copy.splice(Math.floor(copy.length * Math.random()), 1);
this._shuffled.push(randVal[0]);
}
};
/**
* Clean up
* @returns {Tone.CtrlPattern} this
*/
Tone.CtrlPattern.prototype.dispose = function () {
this._shuffled = null;
this.values = null;
};
return Tone.CtrlPattern;
});
Module(function (Tone) {
/**
* @class Choose a random value.
* @extends {Tone}
* @example
* var randomWalk = new Tone.CtrlRandom({
* "min" : 0,
* "max" : 10,
* "integer" : true
* });
* randomWalk.eval();
*
* @param {Number|Time=} min The minimum return value.
* @param {Number|Time=} max The maximum return value.
*/
Tone.CtrlRandom = function () {
var options = this.optionsObject(arguments, [
'min',
'max'
], Tone.CtrlRandom.defaults);
/**
* The minimum return value
* @type {Number|Time}
*/
this.min = options.min;
/**
* The maximum return value
* @type {Number|Time}
*/
this.max = options.max;
/**
* If the return value should be an integer
* @type {Boolean}
*/
this.integer = options.integer;
};
Tone.extend(Tone.CtrlRandom);
/**
* The defaults
* @const
* @type {Object}
*/
Tone.CtrlRandom.defaults = {
'min': 0,
'max': 1,
'integer': false
};
/**
* Return a random value between min and max.
* @readOnly
* @memberOf Tone.CtrlRandom#
* @type {*}
* @name value
*/
Object.defineProperty(Tone.CtrlRandom.prototype, 'value', {
get: function () {
var min = this.toSeconds(this.min);
var max = this.toSeconds(this.max);
var rand = Math.random();
var val = rand * min + (1 - rand) * max;
if (this.integer) {
val = Math.floor(val);
}
return val;
}
});
return Tone.CtrlRandom;
});
Module(function (Tone) {
/**
* @class Buffer loading and storage. Tone.Buffer is used internally by all
* classes that make requests for audio files such as Tone.Player,
* Tone.Sampler and Tone.Convolver.
* <br><br>
* Aside from load callbacks from individual buffers, Tone.Buffer
* provides static methods which keep track of the loading progress
* of all of the buffers. These methods are Tone.Buffer.onload, Tone.Buffer.onprogress,
* and Tone.Buffer.onerror.
*
* @constructor
* @extends {Tone}
* @param {AudioBuffer|string} url The url to load, or the audio buffer to set.
* @param {function=} onload A callback which is invoked after the buffer is loaded.
* It's recommended to use Tone.Buffer.onload instead
* since it will give you a callback when ALL buffers are loaded.
* @example
* var buffer = new Tone.Buffer("path/to/sound.mp3", function(){
* //the buffer is now available.
* var buff = buffer.get();
* });
*/
Tone.Buffer = function () {
var options = this.optionsObject(arguments, [
'url',
'onload'
], Tone.Buffer.defaults);
/**
* stores the loaded AudioBuffer
* @type {AudioBuffer}
* @private
*/
this._buffer = null;
/**
* indicates if the buffer should be reversed or not
* @type {boolean}
* @private
*/
this._reversed = options.reverse;
/**
* The url of the buffer. <code>undefined</code> if it was
* constructed with a buffer
* @type {string}
* @readOnly
*/
this.url = undefined;
/**
* Indicates if the buffer is loaded or not.
* @type {boolean}
* @readOnly
*/
this.loaded = false;
/**
* The callback to invoke when everything is loaded.
* @type {function}
*/
this.onload = options.onload.bind(this, this);
if (options.url instanceof AudioBuffer || options.url instanceof Tone.Buffer) {
this.set(options.url);
this.onload(this);
} else if (this.isString(options.url)) {
this.url = options.url;
Tone.Buffer._addToQueue(options.url, this);
}
};
Tone.extend(Tone.Buffer);
/**
* the default parameters
* @type {Object}
*/
Tone.Buffer.defaults = {
'url': undefined,
'onload': Tone.noOp,
'reverse': false
};
/**
* Pass in an AudioBuffer or Tone.Buffer to set the value
* of this buffer.
* @param {AudioBuffer|Tone.Buffer} buffer the buffer
* @returns {Tone.Buffer} this
*/
Tone.Buffer.prototype.set = function (buffer) {
if (buffer instanceof Tone.Buffer) {
this._buffer = buffer.get();
} else {
this._buffer = buffer;
}
this.loaded = true;
return this;
};
/**
* @return {AudioBuffer} The audio buffer stored in the object.
*/
Tone.Buffer.prototype.get = function () {
return this._buffer;
};
/**
* Load url into the buffer.
* @param {String} url The url to load
* @param {Function=} callback The callback to invoke on load.
* don't need to set if `onload` is
* already set.
* @returns {Tone.Buffer} this
*/
Tone.Buffer.prototype.load = function (url, callback) {
this.url = url;
this.onload = this.defaultArg(callback, this.onload);
Tone.Buffer._addToQueue(url, this);
return this;
};
/**
* dispose and disconnect
* @returns {Tone.Buffer} this
*/
Tone.Buffer.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
Tone.Buffer._removeFromQueue(this);
this._buffer = null;
this.onload = Tone.Buffer.defaults.onload;
return this;
};
/**
* The duration of the buffer.
* @memberOf Tone.Buffer#
* @type {number}
* @name duration
* @readOnly
*/
Object.defineProperty(Tone.Buffer.prototype, 'duration', {
get: function () {
if (this._buffer) {
return this._buffer.duration;
} else {
return 0;
}
}
});
/**
* Reverse the buffer.
* @private
* @return {Tone.Buffer} this
*/
Tone.Buffer.prototype._reverse = function () {
if (this.loaded) {
for (var i = 0; i < this._buffer.numberOfChannels; i++) {
Array.prototype.reverse.call(this._buffer.getChannelData(i));
}
}
return this;
};
/**
* Reverse the buffer.
* @memberOf Tone.Buffer#
* @type {boolean}
* @name reverse
*/
Object.defineProperty(Tone.Buffer.prototype, 'reverse', {
get: function () {
return this._reversed;
},
set: function (rev) {
if (this._reversed !== rev) {
this._reversed = rev;
this._reverse();
}
}
});
///////////////////////////////////////////////////////////////////////////
// STATIC METHODS
///////////////////////////////////////////////////////////////////////////
//statically inherits Emitter methods
Tone.Emitter.mixin(Tone.Buffer);
/**
* the static queue for all of the xhr requests
* @type {Array}
* @private
*/
Tone.Buffer._queue = [];
/**
* the array of current downloads
* @type {Array}
* @private
*/
Tone.Buffer._currentDownloads = [];
/**
* the total number of downloads
* @type {number}
* @private
*/
Tone.Buffer._totalDownloads = 0;
/**
* the maximum number of simultaneous downloads
* @static
* @type {number}
*/
Tone.Buffer.MAX_SIMULTANEOUS_DOWNLOADS = 6;
/**
* Adds a file to be loaded to the loading queue
* @param {string} url the url to load
* @param {function} callback the callback to invoke once it's loaded
* @private
*/
Tone.Buffer._addToQueue = function (url, buffer) {
Tone.Buffer._queue.push({
url: url,
Buffer: buffer,
progress: 0,
xhr: null
});
this._totalDownloads++;
Tone.Buffer._next();
};
/**
* Remove an object from the queue's (if it's still there)
* Abort the XHR if it's in progress
* @param {Tone.Buffer} buffer the buffer to remove
* @private
*/
Tone.Buffer._removeFromQueue = function (buffer) {
var i;
for (i = 0; i < Tone.Buffer._queue.length; i++) {
var q = Tone.Buffer._queue[i];
if (q.Buffer === buffer) {
Tone.Buffer._queue.splice(i, 1);
}
}
for (i = 0; i < Tone.Buffer._currentDownloads.length; i++) {
var dl = Tone.Buffer._currentDownloads[i];
if (dl.Buffer === buffer) {
Tone.Buffer._currentDownloads.splice(i, 1);
dl.xhr.abort();
dl.xhr.onprogress = null;
dl.xhr.onload = null;
dl.xhr.onerror = null;
}
}
};
/**
* load the next buffer in the queue
* @private
*/
Tone.Buffer._next = function () {
if (Tone.Buffer._queue.length > 0) {
if (Tone.Buffer._currentDownloads.length < Tone.Buffer.MAX_SIMULTANEOUS_DOWNLOADS) {
var next = Tone.Buffer._queue.shift();
Tone.Buffer._currentDownloads.push(next);
next.xhr = Tone.Buffer.load(next.url, function (buffer) {
//remove this one from the queue
var index = Tone.Buffer._currentDownloads.indexOf(next);
Tone.Buffer._currentDownloads.splice(index, 1);
next.Buffer.set(buffer);
if (next.Buffer._reversed) {
next.Buffer._reverse();
}
next.Buffer.onload(next.Buffer);
Tone.Buffer._onprogress();
Tone.Buffer._next();
});
next.xhr.onprogress = function (event) {
next.progress = event.loaded / event.total;
Tone.Buffer._onprogress();
};
next.xhr.onerror = function (e) {
Tone.Buffer.trigger('error', e);
};
}
} else if (Tone.Buffer._currentDownloads.length === 0) {
Tone.Buffer.trigger('load');
//reset the downloads
Tone.Buffer._totalDownloads = 0;
}
};
/**
* internal progress event handler
* @private
*/
Tone.Buffer._onprogress = function () {
var curretDownloadsProgress = 0;
var currentDLLen = Tone.Buffer._currentDownloads.length;
var inprogress = 0;
if (currentDLLen > 0) {
for (var i = 0; i < currentDLLen; i++) {
var dl = Tone.Buffer._currentDownloads[i];
curretDownloadsProgress += dl.progress;
}
inprogress = curretDownloadsProgress;
}
var currentDownloadProgress = currentDLLen - inprogress;
var completed = Tone.Buffer._totalDownloads - Tone.Buffer._queue.length - currentDownloadProgress;
Tone.Buffer.trigger('progress', completed / Tone.Buffer._totalDownloads);
};
/**
* Makes an xhr reqest for the selected url then decodes
* the file as an audio buffer. Invokes
* the callback once the audio buffer loads.
* @param {string} url The url of the buffer to load.
* filetype support depends on the
* browser.
* @param {function} callback The function to invoke when the url is loaded.
* @returns {XMLHttpRequest} returns the XHR
*/
Tone.Buffer.load = function (url, callback) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// decode asynchronously
request.onload = function () {
Tone.context.decodeAudioData(request.response, function (buff) {
if (!buff) {
throw new Error('could not decode audio data:' + url);
}
callback(buff);
});
};
//send the request
request.send();
return request;
};
/**
* @deprecated us on([event]) instead
*/
Object.defineProperty(Tone.Buffer, 'onload', {
set: function (cb) {
console.warn('Tone.Buffer.onload is deprecated, use Tone.Buffer.on(\'load\', callback)');
Tone.Buffer.on('load', cb);
}
});
Object.defineProperty(Tone.Buffer, 'onprogress', {
set: function (cb) {
console.warn('Tone.Buffer.onprogress is deprecated, use Tone.Buffer.on(\'progress\', callback)');
Tone.Buffer.on('progress', cb);
}
});
Object.defineProperty(Tone.Buffer, 'onerror', {
set: function (cb) {
console.warn('Tone.Buffer.onerror is deprecated, use Tone.Buffer.on(\'error\', callback)');
Tone.Buffer.on('error', cb);
}
});
return Tone.Buffer;
});
Module(function (Tone) {
/**
* buses are another way of routing audio
*
* augments Tone.prototype to include send and recieve
*/
/**
* All of the routes
*
* @type {Object}
* @static
* @private
*/
var Buses = {};
/**
* Send this signal to the channel name.
* @param {string} channelName A named channel to send the signal to.
* @param {Decibels} amount The amount of the source to send to the bus.
* @return {GainNode} The gain node which connects this node to the desired channel.
* Can be used to adjust the levels of the send.
* @example
* source.send("reverb", -12);
*/
Tone.prototype.send = function (channelName, amount) {
if (!Buses.hasOwnProperty(channelName)) {
Buses[channelName] = this.context.createGain();
}
var sendKnob = this.context.createGain();
sendKnob.gain.value = this.dbToGain(this.defaultArg(amount, 1));
this.output.chain(sendKnob, Buses[channelName]);
return sendKnob;
};
/**
* Recieve the input from the desired channelName to the input
*
* @param {string} channelName A named channel to send the signal to.
* @param {AudioNode} [input] If no input is selected, the
* input of the current node is
* chosen.
* @returns {Tone} this
* @example
* reverbEffect.receive("reverb");
*/
Tone.prototype.receive = function (channelName, input) {
if (!Buses.hasOwnProperty(channelName)) {
Buses[channelName] = this.context.createGain();
}
if (this.isUndef(input)) {
input = this.input;
}
Buses[channelName].connect(input);
return this;
};
return Tone;
});
Module(function (Tone) {
/**
* @class Wrapper around Web Audio's native [DelayNode](http://webaudio.github.io/web-audio-api/#the-delaynode-interface).
* @extends {Tone}
* @param {Time=} delayTime The delay applied to the incoming signal.
* @param {Time=} maxDelay The maximum delay time.
*/
Tone.Delay = function () {
var options = this.optionsObject(arguments, [
'delayTime',
'maxDelay'
], Tone.Delay.defaults);
/**
* The native delay node
* @type {DelayNode}
* @private
*/
this._delayNode = this.input = this.output = this.context.createDelay(this.toSeconds(options.maxDelay));
/**
* The amount of time the incoming signal is
* delayed.
* @type {Tone.Param}
* @signal
*/
this.delayTime = new Tone.Param({
'param': this._delayNode.delayTime,
'units': Tone.Type.Time,
'value': options.delayTime
});
this._readOnly('delayTime');
};
Tone.extend(Tone.Delay);
/**
* The defaults
* @const
* @type {Object}
*/
Tone.Delay.defaults = {
'maxDelay': 1,
'delayTime': 0
};
/**
* Clean up.
* @return {Tone.Delay} this
*/
Tone.Delay.prototype.dispose = function () {
Tone.Param.prototype.dispose.call(this);
this._delayNode.disconnect();
this._delayNode = null;
this._writable('delayTime');
this.delayTime = null;
return this;
};
return Tone.Delay;
});
Module(function (Tone) {
/**
* @class A single master output which is connected to the
* AudioDestinationNode (aka your speakers).
* It provides useful conveniences such as the ability
* to set the volume and mute the entire application.
* It also gives you the ability to apply master effects to your application.
* <br><br>
* Like Tone.Transport, A single Tone.Master is created
* on initialization and you do not need to explicitly construct one.
*
* @constructor
* @extends {Tone}
* @singleton
* @example
* //the audio will go from the oscillator to the speakers
* oscillator.connect(Tone.Master);
* //a convenience for connecting to the master output is also provided:
* oscillator.toMaster();
* //the above two examples are equivalent.
*/
Tone.Master = function () {
Tone.call(this);
/**
* the unmuted volume
* @type {number}
* @private
*/
this._unmutedVolume = 1;
/**
* if the master is muted
* @type {boolean}
* @private
*/
this._muted = false;
/**
* The private volume node
* @type {Tone.Volume}
* @private
*/
this._volume = this.output = new Tone.Volume();
/**
* The volume of the master output.
* @type {Decibels}
* @signal
*/
this.volume = this._volume.volume;
this._readOnly('volume');
//connections
this.input.chain(this.output, this.context.destination);
};
Tone.extend(Tone.Master);
/**
* @type {Object}
* @const
*/
Tone.Master.defaults = {
'volume': 0,
'mute': false
};
/**
* Mute the output.
* @memberOf Tone.Master#
* @type {boolean}
* @name mute
* @example
* //mute the output
* Tone.Master.mute = true;
*/
Object.defineProperty(Tone.Master.prototype, 'mute', {
get: function () {
return this._muted;
},
set: function (mute) {
if (!this._muted && mute) {
this._unmutedVolume = this.volume.value;
//maybe it should ramp here?
this.volume.value = -Infinity;
} else if (this._muted && !mute) {
this.volume.value = this._unmutedVolume;
}
this._muted = mute;
}
});
/**
* Add a master effects chain. NOTE: this will disconnect any nodes which were previously
* chained in the master effects chain.
* @param {AudioNode|Tone...} args All arguments will be connected in a row
* and the Master will be routed through it.
* @return {Tone.Master} this
* @example
* //some overall compression to keep the levels in check
* var masterCompressor = new Tone.Compressor({
* "threshold" : -6,
* "ratio" : 3,
* "attack" : 0.5,
* "release" : 0.1
* });
* //give a little boost to the lows
* var lowBump = new Tone.Filter(200, "lowshelf");
* //route everything through the filter
* //and compressor before going to the speakers
* Tone.Master.chain(lowBump, masterCompressor);
*/
Tone.Master.prototype.chain = function () {
this.input.disconnect();
this.input.chain.apply(this.input, arguments);
arguments[arguments.length - 1].connect(this.output);
};
/**
* Clean up
* @return {Tone.Master} this
*/
Tone.Master.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._writable('volume');
this._volume.dispose();
this._volume = null;
this.volume = null;
};
///////////////////////////////////////////////////////////////////////////
// AUGMENT TONE's PROTOTYPE
///////////////////////////////////////////////////////////////////////////
/**
* Connect 'this' to the master output. Shorthand for this.connect(Tone.Master)
* @returns {Tone} this
* @example
* //connect an oscillator to the master output
* var osc = new Tone.Oscillator().toMaster();
*/
Tone.prototype.toMaster = function () {
this.connect(Tone.Master);
return this;
};
/**
* Also augment AudioNode's prototype to include toMaster
* as a convenience
* @returns {AudioNode} this
*/
AudioNode.prototype.toMaster = function () {
this.connect(Tone.Master);
return this;
};
var MasterConstructor = Tone.Master;
/**
* initialize the module and listen for new audio contexts
*/
Tone._initAudioContext(function () {
//a single master output
if (!Tone.prototype.isUndef(Tone.Master)) {
Tone.Master = new MasterConstructor();
} else {
MasterConstructor.prototype.dispose.call(Tone.Master);
MasterConstructor.call(Tone.Master);
}
});
return Tone.Master;
});
Module(function (Tone) {
/**
* @class A timed note. Creating a note will register a callback
* which will be invoked on the channel at the time with
* whatever value was specified.
*
* @constructor
* @param {number|string} channel the channel name of the note
* @param {Time} time the time when the note will occur
* @param {string|number|Object|Array} value the value of the note
*/
Tone.Note = function (channel, time, value) {
/**
* the value of the note. This value is returned
* when the channel callback is invoked.
*
* @type {string|number|Object}
*/
this.value = value;
/**
* the channel name or number
*
* @type {string|number}
* @private
*/
this._channel = channel;
/**
* an internal reference to the id of the timeline
* callback which is set.
*
* @type {number}
* @private
*/
this._timelineID = Tone.Transport.setTimeline(this._trigger.bind(this), time);
};
/**
* invoked by the timeline
* @private
* @param {number} time the time at which the note should play
*/
Tone.Note.prototype._trigger = function (time) {
//invoke the callback
channelCallbacks(this._channel, time, this.value);
};
/**
* clean up
* @returns {Tone.Note} this
*/
Tone.Note.prototype.dispose = function () {
Tone.Transport.clearTimeline(this._timelineID);
this.value = null;
return this;
};
/**
* @private
* @static
* @type {Object}
*/
var NoteChannels = {};
/**
* invoke all of the callbacks on a specific channel
* @private
*/
function channelCallbacks(channel, time, value) {
if (NoteChannels.hasOwnProperty(channel)) {
var callbacks = NoteChannels[channel];
for (var i = 0, len = callbacks.length; i < len; i++) {
var callback = callbacks[i];
if (Array.isArray(value)) {
callback.apply(window, [time].concat(value));
} else {
callback(time, value);
}
}
}
}
/**
* listen to a specific channel, get all of the note callbacks
* @static
* @param {string|number} channel the channel to route note events from
* @param {function(*)} callback callback to be invoked when a note will occur
* on the specified channel
*/
Tone.Note.route = function (channel, callback) {
if (NoteChannels.hasOwnProperty(channel)) {
NoteChannels[channel].push(callback);
} else {
NoteChannels[channel] = [callback];
}
};
/**
* Remove a previously routed callback from a channel.
* @static
* @param {string|number} channel The channel to unroute note events from
* @param {function(*)} callback Callback which was registered to the channel.
*/
Tone.Note.unroute = function (channel, callback) {
if (NoteChannels.hasOwnProperty(channel)) {
var channelCallback = NoteChannels[channel];
var index = channelCallback.indexOf(callback);
if (index !== -1) {
NoteChannels[channel].splice(index, 1);
}
}
};
/**
* Parses a score and registers all of the notes along the timeline.
* <br><br>
* Scores are a JSON object with instruments at the top level
* and an array of time and values. The value of a note can be 0 or more
* parameters.
* <br><br>
* The only requirement for the score format is that the time is the first (or only)
* value in the array. All other values are optional and will be passed into the callback
* function registered using `Note.route(channelName, callback)`.
* <br><br>
* To convert MIDI files to score notation, take a look at utils/MidiToScore.js
*
* @example
* //an example JSON score which sets up events on channels
* var score = {
* "synth" : [["0", "C3"], ["0:1", "D3"], ["0:2", "E3"], ... ],
* "bass" : [["0", "C2"], ["1:0", "A2"], ["2:0", "C2"], ["3:0", "A2"], ... ],
* "kick" : ["0", "0:2", "1:0", "1:2", "2:0", ... ],
* //...
* };
* //parse the score into Notes
* Tone.Note.parseScore(score);
* //route all notes on the "synth" channel
* Tone.Note.route("synth", function(time, note){
* //trigger synth
* });
* @static
* @param {Object} score
* @return {Array} an array of all of the notes that were created
*/
Tone.Note.parseScore = function (score) {
var notes = [];
for (var inst in score) {
var part = score[inst];
if (inst === 'tempo') {
Tone.Transport.bpm.value = part;
} else if (inst === 'timeSignature') {
Tone.Transport.timeSignature = part[0] / (part[1] / 4);
} else if (Array.isArray(part)) {
for (var i = 0; i < part.length; i++) {
var noteDescription = part[i];
var note;
if (Array.isArray(noteDescription)) {
var time = noteDescription[0];
var value = noteDescription.slice(1);
note = new Tone.Note(inst, time, value);
} else if (typeof noteDescription === 'object') {
note = new Tone.Note(inst, noteDescription.time, noteDescription);
} else {
note = new Tone.Note(inst, noteDescription);
}
notes.push(note);
}
} else {
throw new TypeError('score parts must be Arrays');
}
}
return notes;
};
return Tone.Note;
});
Module(function (Tone) {
/**
* @class Tone.Effect is the base class for effects. Connect the effect between
* the effectSend and effectReturn GainNodes, then control the amount of
* effect which goes to the output using the wet control.
*
* @constructor
* @extends {Tone}
* @param {NormalRange|Object} [wet] The starting wet value.
*/
Tone.Effect = function () {
Tone.call(this);
//get all of the defaults
var options = this.optionsObject(arguments, ['wet'], Tone.Effect.defaults);
/**
* the drywet knob to control the amount of effect
* @type {Tone.CrossFade}
* @private
*/
this._dryWet = new Tone.CrossFade(options.wet);
/**
* The wet control is how much of the effected
* will pass through to the output. 1 = 100% effected
* signal, 0 = 100% dry signal.
* @type {NormalRange}
* @signal
*/
this.wet = this._dryWet.fade;
/**
* connect the effectSend to the input of hte effect
* @type {GainNode}
* @private
*/
this.effectSend = this.context.createGain();
/**
* connect the output of the effect to the effectReturn
* @type {GainNode}
* @private
*/
this.effectReturn = this.context.createGain();
//connections
this.input.connect(this._dryWet.a);
this.input.connect(this.effectSend);
this.effectReturn.connect(this._dryWet.b);
this._dryWet.connect(this.output);
this._readOnly(['wet']);
};
Tone.extend(Tone.Effect);
/**
* @static
* @type {Object}
*/
Tone.Effect.defaults = { 'wet': 1 };
/**
* chains the effect in between the effectSend and effectReturn
* @param {Tone} effect
* @private
* @returns {Tone.Effect} this
*/
Tone.Effect.prototype.connectEffect = function (effect) {
this.effectSend.chain(effect, this.effectReturn);
return this;
};
/**
* Clean up.
* @returns {Tone.Effect} this
*/
Tone.Effect.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._dryWet.dispose();
this._dryWet = null;
this.effectSend.disconnect();
this.effectSend = null;
this.effectReturn.disconnect();
this.effectReturn = null;
this._writable(['wet']);
this.wet = null;
return this;
};
return Tone.Effect;
});
Module(function (Tone) {
/**
* @class Tone.AutoFilter is a Tone.Filter with a Tone.LFO connected to the filter cutoff frequency.
* Setting the LFO rate and depth allows for control over the filter modulation rate
* and depth.
*
* @constructor
* @extends {Tone.Effect}
* @param {Time|Object} [frequency] The rate of the LFO.
* @param {Frequency=} baseFrequency The lower value of the LFOs oscillation
* @param {Frequency=} octaves The number of octaves above the baseFrequency
* @example
* //create an autofilter and start it's LFO
* var autoFilter = new Tone.AutoFilter("4n").toMaster().start();
* //route an oscillator through the filter and start it
* var oscillator = new Tone.Oscillator().connect(autoFilter).start();
*/
Tone.AutoFilter = function () {
var options = this.optionsObject(arguments, [
'frequency',
'baseFrequency',
'octaves'
], Tone.AutoFilter.defaults);
Tone.Effect.call(this, options);
/**
* the lfo which drives the filter cutoff
* @type {Tone.LFO}
* @private
*/
this._lfo = new Tone.LFO({
'frequency': options.frequency,
'amplitude': options.depth
});
/**
* The range of the filter modulating between the min and max frequency.
* 0 = no modulation. 1 = full modulation.
* @type {NormalRange}
* @signal
*/
this.depth = this._lfo.amplitude;
/**
* How fast the filter modulates between min and max.
* @type {Frequency}
* @signal
*/
this.frequency = this._lfo.frequency;
/**
* The filter node
* @type {Tone.Filter}
*/
this.filter = new Tone.Filter(options.filter);
/**
* The octaves placeholder
* @type {Positive}
* @private
*/
this._octaves = 0;
//connections
this.connectEffect(this.filter);
this._lfo.connect(this.filter.frequency);
this.type = options.type;
this._readOnly([
'frequency',
'depth'
]);
this.octaves = options.octaves;
this.baseFrequency = options.baseFrequency;
};
//extend Effect
Tone.extend(Tone.AutoFilter, Tone.Effect);
/**
* defaults
* @static
* @type {Object}
*/
Tone.AutoFilter.defaults = {
'frequency': 1,
'type': 'sine',
'depth': 1,
'baseFrequency': 200,
'octaves': 2.6,
'filter': {
'type': 'lowpass',
'rolloff': -12,
'Q': 1
}
};
/**
* Start the effect.
* @param {Time} [time=now] When the LFO will start.
* @returns {Tone.AutoFilter} this
*/
Tone.AutoFilter.prototype.start = function (time) {
this._lfo.start(time);
return this;
};
/**
* Stop the effect.
* @param {Time} [time=now] When the LFO will stop.
* @returns {Tone.AutoFilter} this
*/
Tone.AutoFilter.prototype.stop = function (time) {
this._lfo.stop(time);
return this;
};
/**
* Sync the filter to the transport.
* @param {Time} [delay=0] Delay time before starting the effect after the
* Transport has started.
* @returns {Tone.AutoFilter} this
*/
Tone.AutoFilter.prototype.sync = function (delay) {
this._lfo.sync(delay);
return this;
};
/**
* Unsync the filter from the transport.
* @returns {Tone.AutoFilter} this
*/
Tone.AutoFilter.prototype.unsync = function () {
this._lfo.unsync();
return this;
};
/**
* Type of oscillator attached to the AutoFilter.
* Possible values: "sine", "square", "triangle", "sawtooth".
* @memberOf Tone.AutoFilter#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.AutoFilter.prototype, 'type', {
get: function () {
return this._lfo.type;
},
set: function (type) {
this._lfo.type = type;
}
});
/**
* The minimum value of the filter's cutoff frequency.
* @memberOf Tone.AutoFilter#
* @type {Frequency}
* @name min
*/
Object.defineProperty(Tone.AutoFilter.prototype, 'baseFrequency', {
get: function () {
return this._lfo.min;
},
set: function (freq) {
this._lfo.min = this.toFrequency(freq);
}
});
/**
* The maximum value of the filter's cutoff frequency.
* @memberOf Tone.AutoFilter#
* @type {Positive}
* @name octaves
*/
Object.defineProperty(Tone.AutoFilter.prototype, 'octaves', {
get: function () {
return this._octaves;
},
set: function (oct) {
this._octaves = oct;
this._lfo.max = this.baseFrequency * Math.pow(2, oct);
}
});
/**
* Clean up.
* @returns {Tone.AutoFilter} this
*/
Tone.AutoFilter.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._lfo.dispose();
this._lfo = null;
this.filter.dispose();
this.filter = null;
this._writable([
'frequency',
'depth'
]);
this.frequency = null;
this.depth = null;
return this;
};
return Tone.AutoFilter;
});
Module(function (Tone) {
/**
* @class Tone.AutoPanner is a Tone.Panner with an LFO connected to the pan amount.
* More on using autopanners [here](https://www.ableton.com/en/blog/autopan-chopper-effect-and-more-liveschool/).
*
* @constructor
* @extends {Tone.Effect}
* @param {Frequency|Object} [frequency] Rate of left-right oscillation.
* @example
* //create an autopanner and start it's LFO
* var autoPanner = new Tone.AutoPanner("4n").toMaster().start();
* //route an oscillator through the panner and start it
* var oscillator = new Tone.Oscillator().connect(autoPanner).start();
*/
Tone.AutoPanner = function () {
var options = this.optionsObject(arguments, ['frequency'], Tone.AutoPanner.defaults);
Tone.Effect.call(this, options);
/**
* the lfo which drives the panning
* @type {Tone.LFO}
* @private
*/
this._lfo = new Tone.LFO({
'frequency': options.frequency,
'amplitude': options.depth,
'min': 0,
'max': 1
});
/**
* The amount of panning between left and right.
* 0 = always center. 1 = full range between left and right.
* @type {NormalRange}
* @signal
*/
this.depth = this._lfo.amplitude;
/**
* the panner node which does the panning
* @type {Tone.Panner}
* @private
*/
this._panner = new Tone.Panner();
/**
* How fast the panner modulates between left and right.
* @type {Frequency}
* @signal
*/
this.frequency = this._lfo.frequency;
//connections
this.connectEffect(this._panner);
this._lfo.connect(this._panner.pan);
this.type = options.type;
this._readOnly([
'depth',
'frequency'
]);
};
//extend Effect
Tone.extend(Tone.AutoPanner, Tone.Effect);
/**
* defaults
* @static
* @type {Object}
*/
Tone.AutoPanner.defaults = {
'frequency': 1,
'type': 'sine',
'depth': 1
};
/**
* Start the effect.
* @param {Time} [time=now] When the LFO will start.
* @returns {Tone.AutoPanner} this
*/
Tone.AutoPanner.prototype.start = function (time) {
this._lfo.start(time);
return this;
};
/**
* Stop the effect.
* @param {Time} [time=now] When the LFO will stop.
* @returns {Tone.AutoPanner} this
*/
Tone.AutoPanner.prototype.stop = function (time) {
this._lfo.stop(time);
return this;
};
/**
* Sync the panner to the transport.
* @param {Time} [delay=0] Delay time before starting the effect after the
* Transport has started.
* @returns {Tone.AutoPanner} this
*/
Tone.AutoPanner.prototype.sync = function (delay) {
this._lfo.sync(delay);
return this;
};
/**
* Unsync the panner from the transport
* @returns {Tone.AutoPanner} this
*/
Tone.AutoPanner.prototype.unsync = function () {
this._lfo.unsync();
return this;
};
/**
* Type of oscillator attached to the AutoFilter.
* Possible values: "sine", "square", "triangle", "sawtooth".
* @memberOf Tone.AutoFilter#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.AutoPanner.prototype, 'type', {
get: function () {
return this._lfo.type;
},
set: function (type) {
this._lfo.type = type;
}
});
/**
* clean up
* @returns {Tone.AutoPanner} this
*/
Tone.AutoPanner.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._lfo.dispose();
this._lfo = null;
this._panner.dispose();
this._panner = null;
this._writable([
'depth',
'frequency'
]);
this.frequency = null;
this.depth = null;
return this;
};
return Tone.AutoPanner;
});
Module(function (Tone) {
/**
* @class Tone.AutoWah connects a Tone.Follower to a bandpass filter (Tone.Filter).
* The frequency of the filter is adjusted proportionally to the
* incoming signal's amplitude. Inspiration from [Tuna.js](https://github.com/Dinahmoe/tuna).
*
* @constructor
* @extends {Tone.Effect}
* @param {Frequency|Object} [baseFrequency] The frequency the filter is set
* to at the low point of the wah
* @param {Positive} [octaves] The number of octaves above the baseFrequency
* the filter will sweep to when fully open
* @param {Decibels} [sensitivity] The decibel threshold sensitivity for
* the incoming signal. Normal range of -40 to 0.
* @example
* var autoWah = new Tone.AutoWah(50, 6, -30).toMaster();
* //initialize the synth and connect to autowah
* var synth = new SimpleSynth.connect(autoWah);
* //Q value influences the effect of the wah - default is 2
* autoWah.Q.value = 6;
* //more audible on higher notes
* synth.triggerAttackRelease("C4", "8n")
*/
Tone.AutoWah = function () {
var options = this.optionsObject(arguments, [
'baseFrequency',
'octaves',
'sensitivity'
], Tone.AutoWah.defaults);
Tone.Effect.call(this, options);
/**
* The envelope follower. Set the attack/release
* timing to adjust how the envelope is followed.
* @type {Tone.Follower}
* @private
*/
this.follower = new Tone.Follower(options.follower);
/**
* scales the follower value to the frequency domain
* @type {Tone}
* @private
*/
this._sweepRange = new Tone.ScaleExp(0, 1, 0.5);
/**
* @type {number}
* @private
*/
this._baseFrequency = options.baseFrequency;
/**
* @type {number}
* @private
*/
this._octaves = options.octaves;
/**
* the input gain to adjust the sensitivity
* @type {GainNode}
* @private
*/
this._inputBoost = this.context.createGain();
/**
* @type {BiquadFilterNode}
* @private
*/
this._bandpass = new Tone.Filter({
'rolloff': -48,
'frequency': 0,
'Q': options.Q
});
/**
* @type {Tone.Filter}
* @private
*/
this._peaking = new Tone.Filter(0, 'peaking');
this._peaking.gain.value = options.gain;
/**
* The gain of the filter.
* @type {Number}
* @signal
*/
this.gain = this._peaking.gain;
/**
* The quality of the filter.
* @type {Positive}
* @signal
*/
this.Q = this._bandpass.Q;
//the control signal path
this.effectSend.chain(this._inputBoost, this.follower, this._sweepRange);
this._sweepRange.connect(this._bandpass.frequency);
this._sweepRange.connect(this._peaking.frequency);
//the filtered path
this.effectSend.chain(this._bandpass, this._peaking, this.effectReturn);
//set the initial value
this._setSweepRange();
this.sensitivity = options.sensitivity;
this._readOnly([
'gain',
'Q'
]);
};
Tone.extend(Tone.AutoWah, Tone.Effect);
/**
* @static
* @type {Object}
*/
Tone.AutoWah.defaults = {
'baseFrequency': 100,
'octaves': 6,
'sensitivity': 0,
'Q': 2,
'gain': 2,
'follower': {
'attack': 0.3,
'release': 0.5
}
};
/**
* The number of octaves that the filter will sweep above the
* baseFrequency.
* @memberOf Tone.AutoWah#
* @type {Number}
* @name octaves
*/
Object.defineProperty(Tone.AutoWah.prototype, 'octaves', {
get: function () {
return this._octaves;
},
set: function (octaves) {
this._octaves = octaves;
this._setSweepRange();
}
});
/**
* The base frequency from which the sweep will start from.
* @memberOf Tone.AutoWah#
* @type {Frequency}
* @name baseFrequency
*/
Object.defineProperty(Tone.AutoWah.prototype, 'baseFrequency', {
get: function () {
return this._baseFrequency;
},
set: function (baseFreq) {
this._baseFrequency = baseFreq;
this._setSweepRange();
}
});
/**
* The sensitivity to control how responsive to the input signal the filter is.
* @memberOf Tone.AutoWah#
* @type {Decibels}
* @name sensitivity
*/
Object.defineProperty(Tone.AutoWah.prototype, 'sensitivity', {
get: function () {
return this.gainToDb(1 / this._inputBoost.gain.value);
},
set: function (sensitivy) {
this._inputBoost.gain.value = 1 / this.dbToGain(sensitivy);
}
});
/**
* sets the sweep range of the scaler
* @private
*/
Tone.AutoWah.prototype._setSweepRange = function () {
this._sweepRange.min = this._baseFrequency;
this._sweepRange.max = Math.min(this._baseFrequency * Math.pow(2, this._octaves), this.context.sampleRate / 2);
};
/**
* Clean up.
* @returns {Tone.AutoWah} this
*/
Tone.AutoWah.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this.follower.dispose();
this.follower = null;
this._sweepRange.dispose();
this._sweepRange = null;
this._bandpass.dispose();
this._bandpass = null;
this._peaking.dispose();
this._peaking = null;
this._inputBoost.disconnect();
this._inputBoost = null;
this._writable([
'gain',
'Q'
]);
this.gain = null;
this.Q = null;
return this;
};
return Tone.AutoWah;
});
Module(function (Tone) {
/**
* @class Tone.Bitcrusher downsamples the incoming signal to a different bitdepth.
* Lowering the bitdepth of the signal creates distortion. Read more about Bitcrushing
* on [Wikipedia](https://en.wikipedia.org/wiki/Bitcrusher).
*
* @constructor
* @extends {Tone.Effect}
* @param {Number} bits The number of bits to downsample the signal. Nominal range
* of 1 to 8.
* @example
* //initialize crusher and route a synth through it
* var crusher = new Tone.BitCrusher(4).toMaster();
* var synth = new Tone.MonoSynth().connect(crusher);
*/
Tone.BitCrusher = function () {
var options = this.optionsObject(arguments, ['bits'], Tone.BitCrusher.defaults);
Tone.Effect.call(this, options);
var invStepSize = 1 / Math.pow(2, options.bits - 1);
/**
* Subtract the input signal and the modulus of the input signal
* @type {Tone.Subtract}
* @private
*/
this._subtract = new Tone.Subtract();
/**
* The mod function
* @type {Tone.Modulo}
* @private
*/
this._modulo = new Tone.Modulo(invStepSize);
/**
* keeps track of the bits
* @type {number}
* @private
*/
this._bits = options.bits;
//connect it up
this.effectSend.fan(this._subtract, this._modulo);
this._modulo.connect(this._subtract, 0, 1);
this._subtract.connect(this.effectReturn);
};
Tone.extend(Tone.BitCrusher, Tone.Effect);
/**
* the default values
* @static
* @type {Object}
*/
Tone.BitCrusher.defaults = { 'bits': 4 };
/**
* The bit depth of the effect. Nominal range of 1-8.
* @memberOf Tone.BitCrusher#
* @type {number}
* @name bits
*/
Object.defineProperty(Tone.BitCrusher.prototype, 'bits', {
get: function () {
return this._bits;
},
set: function (bits) {
this._bits = bits;
var invStepSize = 1 / Math.pow(2, bits - 1);
this._modulo.value = invStepSize;
}
});
/**
* Clean up.
* @returns {Tone.BitCrusher} this
*/
Tone.BitCrusher.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._subtract.dispose();
this._subtract = null;
this._modulo.dispose();
this._modulo = null;
return this;
};
return Tone.BitCrusher;
});
Module(function (Tone) {
/**
* @class Tone.ChebyShev is a Chebyshev waveshaper, an effect which is good
* for making different types of distortion sounds.
* Note that odd orders sound very different from even ones,
* and order = 1 is no change.
* Read more at [music.columbia.edu](http://music.columbia.edu/cmc/musicandcomputers/chapter4/04_06.php).
*
* @extends {Tone.Effect}
* @constructor
* @param {Positive|Object} [order] The order of the chebyshev polynomial. Normal range between 1-100.
* @example
* //create a new cheby
* var cheby = new Tone.Chebyshev(50);
* //create a monosynth connected to our cheby
* synth = new Tone.MonoSynth().connect(cheby);
*/
Tone.Chebyshev = function () {
var options = this.optionsObject(arguments, ['order'], Tone.Chebyshev.defaults);
Tone.Effect.call(this, options);
/**
* @type {WaveShaperNode}
* @private
*/
this._shaper = new Tone.WaveShaper(4096);
/**
* holds onto the order of the filter
* @type {number}
* @private
*/
this._order = options.order;
this.connectEffect(this._shaper);
this.order = options.order;
this.oversample = options.oversample;
};
Tone.extend(Tone.Chebyshev, Tone.Effect);
/**
* @static
* @const
* @type {Object}
*/
Tone.Chebyshev.defaults = {
'order': 1,
'oversample': 'none'
};
/**
* get the coefficient for that degree
* @param {number} x the x value
* @param {number} degree
* @param {Object} memo memoize the computed value.
* this speeds up computation greatly.
* @return {number} the coefficient
* @private
*/
Tone.Chebyshev.prototype._getCoefficient = function (x, degree, memo) {
if (memo.hasOwnProperty(degree)) {
return memo[degree];
} else if (degree === 0) {
memo[degree] = 0;
} else if (degree === 1) {
memo[degree] = x;
} else {
memo[degree] = 2 * x * this._getCoefficient(x, degree - 1, memo) - this._getCoefficient(x, degree - 2, memo);
}
return memo[degree];
};
/**
* The order of the Chebyshev polynomial which creates
* the equation which is applied to the incoming
* signal through a Tone.WaveShaper. The equations
* are in the form:<br>
* order 2: 2x^2 + 1<br>
* order 3: 4x^3 + 3x <br>
* @memberOf Tone.Chebyshev#
* @type {Positive}
* @name order
*/
Object.defineProperty(Tone.Chebyshev.prototype, 'order', {
get: function () {
return this._order;
},
set: function (order) {
this._order = order;
var curve = new Array(4096);
var len = curve.length;
for (var i = 0; i < len; ++i) {
var x = i * 2 / len - 1;
if (x === 0) {
//should output 0 when input is 0
curve[i] = 0;
} else {
curve[i] = this._getCoefficient(x, order, {});
}
}
this._shaper.curve = curve;
}
});
/**
* The oversampling of the effect. Can either be "none", "2x" or "4x".
* @memberOf Tone.Chebyshev#
* @type {string}
* @name oversample
*/
Object.defineProperty(Tone.Chebyshev.prototype, 'oversample', {
get: function () {
return this._shaper.oversample;
},
set: function (oversampling) {
this._shaper.oversample = oversampling;
}
});
/**
* Clean up.
* @returns {Tone.Chebyshev} this
*/
Tone.Chebyshev.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._shaper.dispose();
this._shaper = null;
return this;
};
return Tone.Chebyshev;
});
Module(function (Tone) {
/**
* @class Base class for Stereo effects. Provides effectSendL/R and effectReturnL/R.
*
* @constructor
* @extends {Tone.Effect}
*/
Tone.StereoEffect = function () {
Tone.call(this);
//get the defaults
var options = this.optionsObject(arguments, ['wet'], Tone.Effect.defaults);
/**
* the drywet knob to control the amount of effect
* @type {Tone.CrossFade}
* @private
*/
this._dryWet = new Tone.CrossFade(options.wet);
/**
* The wet control, i.e. how much of the effected
* will pass through to the output.
* @type {NormalRange}
* @signal
*/
this.wet = this._dryWet.fade;
/**
* then split it
* @type {Tone.Split}
* @private
*/
this._split = new Tone.Split();
/**
* the effects send LEFT
* @type {GainNode}
* @private
*/
this.effectSendL = this._split.left;
/**
* the effects send RIGHT
* @type {GainNode}
* @private
*/
this.effectSendR = this._split.right;
/**
* the stereo effect merger
* @type {Tone.Merge}
* @private
*/
this._merge = new Tone.Merge();
/**
* the effect return LEFT
* @type {GainNode}
* @private
*/
this.effectReturnL = this._merge.left;
/**
* the effect return RIGHT
* @type {GainNode}
* @private
*/
this.effectReturnR = this._merge.right;
//connections
this.input.connect(this._split);
//dry wet connections
this.input.connect(this._dryWet, 0, 0);
this._merge.connect(this._dryWet, 0, 1);
this._dryWet.connect(this.output);
this._readOnly(['wet']);
};
Tone.extend(Tone.StereoEffect, Tone.Effect);
/**
* Clean up.
* @returns {Tone.StereoEffect} this
*/
Tone.StereoEffect.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._dryWet.dispose();
this._dryWet = null;
this._split.dispose();
this._split = null;
this._merge.dispose();
this._merge = null;
this.effectSendL = null;
this.effectSendR = null;
this.effectReturnL = null;
this.effectReturnR = null;
this._writable(['wet']);
this.wet = null;
return this;
};
return Tone.StereoEffect;
});
Module(function (Tone) {
/**
* @class Tone.FeedbackEffect provides a loop between an
* audio source and its own output. This is a base-class
* for feedback effects.
*
* @constructor
* @extends {Tone.Effect}
* @param {NormalRange|Object} [feedback] The initial feedback value.
*/
Tone.FeedbackEffect = function () {
var options = this.optionsObject(arguments, ['feedback']);
options = this.defaultArg(options, Tone.FeedbackEffect.defaults);
Tone.Effect.call(this, options);
/**
* The amount of signal which is fed back into the effect input.
* @type {NormalRange}
* @signal
*/
this.feedback = new Tone.Signal(options.feedback, Tone.Type.NormalRange);
/**
* the gain which controls the feedback
* @type {GainNode}
* @private
*/
this._feedbackGain = this.context.createGain();
//the feedback loop
this.effectReturn.chain(this._feedbackGain, this.effectSend);
this.feedback.connect(this._feedbackGain.gain);
this._readOnly(['feedback']);
};
Tone.extend(Tone.FeedbackEffect, Tone.Effect);
/**
* @static
* @type {Object}
*/
Tone.FeedbackEffect.defaults = { 'feedback': 0.125 };
/**
* Clean up.
* @returns {Tone.FeedbackEffect} this
*/
Tone.FeedbackEffect.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._writable(['feedback']);
this.feedback.dispose();
this.feedback = null;
this._feedbackGain.disconnect();
this._feedbackGain = null;
return this;
};
return Tone.FeedbackEffect;
});
Module(function (Tone) {
/**
* @class Just like a stereo feedback effect, but the feedback is routed from left to right
* and right to left instead of on the same channel.
*
* @constructor
* @extends {Tone.FeedbackEffect}
*/
Tone.StereoXFeedbackEffect = function () {
var options = this.optionsObject(arguments, ['feedback'], Tone.FeedbackEffect.defaults);
Tone.StereoEffect.call(this, options);
/**
* The amount of feedback from the output
* back into the input of the effect (routed
* across left and right channels).
* @type {NormalRange}
* @signal
*/
this.feedback = new Tone.Signal(options.feedback, Tone.Type.NormalRange);
/**
* the left side feeback
* @type {GainNode}
* @private
*/
this._feedbackLR = this.context.createGain();
/**
* the right side feeback
* @type {GainNode}
* @private
*/
this._feedbackRL = this.context.createGain();
//connect it up
this.effectReturnL.chain(this._feedbackLR, this.effectSendR);
this.effectReturnR.chain(this._feedbackRL, this.effectSendL);
this.feedback.fan(this._feedbackLR.gain, this._feedbackRL.gain);
this._readOnly(['feedback']);
};
Tone.extend(Tone.StereoXFeedbackEffect, Tone.FeedbackEffect);
/**
* clean up
* @returns {Tone.StereoXFeedbackEffect} this
*/
Tone.StereoXFeedbackEffect.prototype.dispose = function () {
Tone.StereoEffect.prototype.dispose.call(this);
this._writable(['feedback']);
this.feedback.dispose();
this.feedback = null;
this._feedbackLR.disconnect();
this._feedbackLR = null;
this._feedbackRL.disconnect();
this._feedbackRL = null;
return this;
};
return Tone.StereoXFeedbackEffect;
});
Module(function (Tone) {
/**
* @class Tone.Chorus is a stereo chorus effect with feedback composed of
* a left and right delay with a Tone.LFO applied to the delayTime of each channel.
* Inspiration from [Tuna.js](https://github.com/Dinahmoe/tuna/blob/master/tuna.js).
* Read more on the chorus effect on [SoundOnSound](http://www.soundonsound.com/sos/jun04/articles/synthsecrets.htm).
*
* @constructor
* @extends {Tone.StereoXFeedbackEffect}
* @param {Frequency|Object} [frequency] The frequency of the LFO.
* @param {Milliseconds} [delayTime] The delay of the chorus effect in ms.
* @param {NormalRange} [depth] The depth of the chorus.
* @example
* var chorus = new Tone.Chorus(4, 2.5, 0.5);
* var synth = new Tone.PolySynth(4, Tone.MonoSynth).connect(chorus);
* synth.triggerAttackRelease(["C3","E3","G3"], "8n");
*/
Tone.Chorus = function () {
var options = this.optionsObject(arguments, [
'frequency',
'delayTime',
'depth'
], Tone.Chorus.defaults);
Tone.StereoXFeedbackEffect.call(this, options);
/**
* the depth of the chorus
* @type {number}
* @private
*/
this._depth = options.depth;
/**
* the delayTime
* @type {number}
* @private
*/
this._delayTime = options.delayTime / 1000;
/**
* the lfo which controls the delayTime
* @type {Tone.LFO}
* @private
*/
this._lfoL = new Tone.LFO({
'frequency': options.frequency,
'min': 0,
'max': 1
});
/**
* another LFO for the right side with a 180 degree phase diff
* @type {Tone.LFO}
* @private
*/
this._lfoR = new Tone.LFO({
'frequency': options.frequency,
'min': 0,
'max': 1,
'phase': 180
});
/**
* delay for left
* @type {DelayNode}
* @private
*/
this._delayNodeL = this.context.createDelay();
/**
* delay for right
* @type {DelayNode}
* @private
*/
this._delayNodeR = this.context.createDelay();
/**
* The frequency of the LFO which modulates the delayTime.
* @type {Frequency}
* @signal
*/
this.frequency = this._lfoL.frequency;
//connections
this.effectSendL.chain(this._delayNodeL, this.effectReturnL);
this.effectSendR.chain(this._delayNodeR, this.effectReturnR);
//and pass through to make the detune apparent
this.effectSendL.connect(this.effectReturnL);
this.effectSendR.connect(this.effectReturnR);
//lfo setup
this._lfoL.connect(this._delayNodeL.delayTime);
this._lfoR.connect(this._delayNodeR.delayTime);
//start the lfo
this._lfoL.start();
this._lfoR.start();
//have one LFO frequency control the other
this._lfoL.frequency.connect(this._lfoR.frequency);
//set the initial values
this.depth = this._depth;
this.frequency.value = options.frequency;
this.type = options.type;
this._readOnly(['frequency']);
this.spread = options.spread;
};
Tone.extend(Tone.Chorus, Tone.StereoXFeedbackEffect);
/**
* @static
* @type {Object}
*/
Tone.Chorus.defaults = {
'frequency': 1.5,
'delayTime': 3.5,
'depth': 0.7,
'feedback': 0.1,
'type': 'sine',
'spread': 180
};
/**
* The depth of the effect. A depth of 1 makes the delayTime
* modulate between 0 and 2*delayTime (centered around the delayTime).
* @memberOf Tone.Chorus#
* @type {NormalRange}
* @name depth
*/
Object.defineProperty(Tone.Chorus.prototype, 'depth', {
get: function () {
return this._depth;
},
set: function (depth) {
this._depth = depth;
var deviation = this._delayTime * depth;
this._lfoL.min = Math.max(this._delayTime - deviation, 0);
this._lfoL.max = this._delayTime + deviation;
this._lfoR.min = Math.max(this._delayTime - deviation, 0);
this._lfoR.max = this._delayTime + deviation;
}
});
/**
* The delayTime in milliseconds of the chorus. A larger delayTime
* will give a more pronounced effect. Nominal range a delayTime
* is between 2 and 20ms.
* @memberOf Tone.Chorus#
* @type {Milliseconds}
* @name delayTime
*/
Object.defineProperty(Tone.Chorus.prototype, 'delayTime', {
get: function () {
return this._delayTime * 1000;
},
set: function (delayTime) {
this._delayTime = delayTime / 1000;
this.depth = this._depth;
}
});
/**
* The oscillator type of the LFO.
* @memberOf Tone.Chorus#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.Chorus.prototype, 'type', {
get: function () {
return this._lfoL.type;
},
set: function (type) {
this._lfoL.type = type;
this._lfoR.type = type;
}
});
/**
* Amount of stereo spread. When set to 0, both LFO's will be panned centrally.
* When set to 180, LFO's will be panned hard left and right respectively.
* @memberOf Tone.Chorus#
* @type {Degrees}
* @name spread
*/
Object.defineProperty(Tone.Chorus.prototype, 'spread', {
get: function () {
return this._lfoR.phase - this._lfoL.phase; //180
},
set: function (spread) {
this._lfoL.phase = 90 - spread / 2;
this._lfoR.phase = spread / 2 + 90;
}
});
/**
* Clean up.
* @returns {Tone.Chorus} this
*/
Tone.Chorus.prototype.dispose = function () {
Tone.StereoXFeedbackEffect.prototype.dispose.call(this);
this._lfoL.dispose();
this._lfoL = null;
this._lfoR.dispose();
this._lfoR = null;
this._delayNodeL.disconnect();
this._delayNodeL = null;
this._delayNodeR.disconnect();
this._delayNodeR = null;
this._writable('frequency');
this.frequency = null;
return this;
};
return Tone.Chorus;
});
Module(function (Tone) {
/**
* @class Tone.Convolver is a wrapper around the Native Web Audio
* [ConvolverNode](http://webaudio.github.io/web-audio-api/#the-convolvernode-interface).
* Convolution is useful for reverb and filter emulation. Read more about convolution reverb on
* [Wikipedia](https://en.wikipedia.org/wiki/Convolution_reverb).
*
* @constructor
* @extends {Tone.Effect}
* @param {string|Tone.Buffer|Object} [url] The URL of the impulse response or the Tone.Buffer
* contianing the impulse response.
* @example
* //initializing the convolver with an impulse response
* var convolver = new Tone.Convolver("./path/to/ir.wav");
* convolver.toMaster();
* //after the buffer has loaded
* Tone.Buffer.onload = function(){
* //testing out convolution with a noise burst
* var burst = new Tone.NoiseSynth().connect(convolver);
* burst.triggerAttackRelease("16n");
* };
*/
Tone.Convolver = function () {
var options = this.optionsObject(arguments, ['url'], Tone.Convolver.defaults);
Tone.Effect.call(this, options);
/**
* convolver node
* @type {ConvolverNode}
* @private
*/
this._convolver = this.context.createConvolver();
/**
* the convolution buffer
* @type {Tone.Buffer}
* @private
*/
this._buffer = new Tone.Buffer(options.url, function (buffer) {
this.buffer = buffer;
options.onload();
}.bind(this));
this.connectEffect(this._convolver);
};
Tone.extend(Tone.Convolver, Tone.Effect);
/**
* @static
* @const
* @type {Object}
*/
Tone.Convolver.defaults = {
'url': '',
'onload': Tone.noOp
};
/**
* The convolver's buffer
* @memberOf Tone.Convolver#
* @type {AudioBuffer}
* @name buffer
*/
Object.defineProperty(Tone.Convolver.prototype, 'buffer', {
get: function () {
return this._buffer.get();
},
set: function (buffer) {
this._buffer.set(buffer);
this._convolver.buffer = this._buffer.get();
}
});
/**
* Load an impulse response url as an audio buffer.
* Decodes the audio asynchronously and invokes
* the callback once the audio buffer loads.
* @param {string} url The url of the buffer to load.
* filetype support depends on the
* browser.
* @param {function=} callback
* @returns {Tone.Convolver} this
*/
Tone.Convolver.prototype.load = function (url, callback) {
this._buffer.load(url, function (buff) {
this.buffer = buff;
if (callback) {
callback();
}
}.bind(this));
return this;
};
/**
* Clean up.
* @returns {Tone.Convolver} this
*/
Tone.Convolver.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._convolver.disconnect();
this._convolver = null;
this._buffer.dispose();
this._buffer = null;
return this;
};
return Tone.Convolver;
});
Module(function (Tone) {
/**
* @class Tone.Distortion is a simple distortion effect using Tone.WaveShaper.
* Algorithm from [a stackoverflow answer](http://stackoverflow.com/a/22313408).
*
* @extends {Tone.Effect}
* @constructor
* @param {Number|Object} [distortion] The amount of distortion (nominal range of 0-1)
* @example
* var dist = new Tone.Distortion(0.8).toMaster();
* var fm = new Tone.SimpleFM().connect(dist);
* //this sounds good on bass notes
* fm.triggerAttackRelease("A1", "8n");
*/
Tone.Distortion = function () {
var options = this.optionsObject(arguments, ['distortion'], Tone.Distortion.defaults);
Tone.Effect.call(this, options);
/**
* @type {Tone.WaveShaper}
* @private
*/
this._shaper = new Tone.WaveShaper(4096);
/**
* holds the distortion amount
* @type {number}
* @private
*/
this._distortion = options.distortion;
this.connectEffect(this._shaper);
this.distortion = options.distortion;
this.oversample = options.oversample;
};
Tone.extend(Tone.Distortion, Tone.Effect);
/**
* @static
* @const
* @type {Object}
*/
Tone.Distortion.defaults = {
'distortion': 0.4,
'oversample': 'none'
};
/**
* The amount of distortion.
* @memberOf Tone.Distortion#
* @type {NormalRange}
* @name distortion
*/
Object.defineProperty(Tone.Distortion.prototype, 'distortion', {
get: function () {
return this._distortion;
},
set: function (amount) {
this._distortion = amount;
var k = amount * 100;
var deg = Math.PI / 180;
this._shaper.setMap(function (x) {
if (Math.abs(x) < 0.001) {
//should output 0 when input is 0
return 0;
} else {
return (3 + k) * x * 20 * deg / (Math.PI + k * Math.abs(x));
}
});
}
});
/**
* The oversampling of the effect. Can either be "none", "2x" or "4x".
* @memberOf Tone.Distortion#
* @type {string}
* @name oversample
*/
Object.defineProperty(Tone.Distortion.prototype, 'oversample', {
get: function () {
return this._shaper.oversample;
},
set: function (oversampling) {
this._shaper.oversample = oversampling;
}
});
/**
* Clean up.
* @returns {Tone.Distortion} this
*/
Tone.Distortion.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._shaper.dispose();
this._shaper = null;
return this;
};
return Tone.Distortion;
});
Module(function (Tone) {
/**
* @class Tone.FeedbackDelay is a DelayNode in which part of output
* signal is fed back into the delay.
*
* @constructor
* @extends {Tone.FeedbackEffect}
* @param {Time|Object} [delayTime] The delay applied to the incoming signal.
* @param {NormalRange=} feedback The amount of the effected signal which
* is fed back through the delay.
* @example
* var feedbackDelay = new Tone.FeedbackDelay("8n", 0.5).toMaster();
* var tom = new Tone.DrumSynth({
* "octaves" : 4,
* "pitchDecay" : 0.1
* }).connect(feedbackDelay);
* tom.triggerAttackRelease("A2","32n");
*/
Tone.FeedbackDelay = function () {
var options = this.optionsObject(arguments, [
'delayTime',
'feedback'
], Tone.FeedbackDelay.defaults);
Tone.FeedbackEffect.call(this, options);
/**
* The delayTime of the DelayNode.
* @type {Time}
* @signal
*/
this.delayTime = new Tone.Signal(options.delayTime, Tone.Type.Time);
/**
* the delay node
* @type {DelayNode}
* @private
*/
this._delayNode = this.context.createDelay(4);
// connect it up
this.connectEffect(this._delayNode);
this.delayTime.connect(this._delayNode.delayTime);
this._readOnly(['delayTime']);
};
Tone.extend(Tone.FeedbackDelay, Tone.FeedbackEffect);
/**
* The default values.
* @const
* @static
* @type {Object}
*/
Tone.FeedbackDelay.defaults = { 'delayTime': 0.25 };
/**
* clean up
* @returns {Tone.FeedbackDelay} this
*/
Tone.FeedbackDelay.prototype.dispose = function () {
Tone.FeedbackEffect.prototype.dispose.call(this);
this.delayTime.dispose();
this._delayNode.disconnect();
this._delayNode = null;
this._writable(['delayTime']);
this.delayTime = null;
return this;
};
return Tone.FeedbackDelay;
});
Module(function (Tone) {
/**
* an array of comb filter delay values from Freeverb implementation
* @static
* @private
* @type {Array}
*/
var combFilterTunings = [
1557 / 44100,
1617 / 44100,
1491 / 44100,
1422 / 44100,
1277 / 44100,
1356 / 44100,
1188 / 44100,
1116 / 44100
];
/**
* an array of allpass filter frequency values from Freeverb implementation
* @private
* @static
* @type {Array}
*/
var allpassFilterFrequencies = [
225,
556,
441,
341
];
/**
* @class Tone.Freeverb is a reverb based on [Freeverb](https://ccrma.stanford.edu/~jos/pasp/Freeverb.html).
* Read more on reverb on [SoundOnSound](http://www.soundonsound.com/sos/may00/articles/reverb.htm).
*
* @extends {Tone.Effect}
* @constructor
* @param {NormalRange|Object} [roomSize] Correlated to the decay time.
* @param {Frequency} [dampening] The cutoff frequency of a lowpass filter as part
* of the reverb.
* @example
* var freeverb = new Tone.Freeverb().toMaster();
* freeverb.dampening.value = 1000;
* //routing synth through the reverb
* var synth = new Tone.AMSynth().connect(freeverb);
*/
Tone.Freeverb = function () {
var options = this.optionsObject(arguments, [
'roomSize',
'dampening'
], Tone.Freeverb.defaults);
Tone.StereoEffect.call(this, options);
/**
* The roomSize value between. A larger roomSize
* will result in a longer decay.
* @type {NormalRange}
* @signal
*/
this.roomSize = new Tone.Signal(options.roomSize, Tone.Type.NormalRange);
/**
* The amount of dampening of the reverberant signal.
* @type {Frequency}
* @signal
*/
this.dampening = new Tone.Signal(options.dampening, Tone.Type.Frequency);
/**
* the comb filters
* @type {Array}
* @private
*/
this._combFilters = [];
/**
* the allpass filters on the left
* @type {Array}
* @private
*/
this._allpassFiltersL = [];
/**
* the allpass filters on the right
* @type {Array}
* @private
*/
this._allpassFiltersR = [];
//make the allpass filters on teh right
for (var l = 0; l < allpassFilterFrequencies.length; l++) {
var allpassL = this.context.createBiquadFilter();
allpassL.type = 'allpass';
allpassL.frequency.value = allpassFilterFrequencies[l];
this._allpassFiltersL.push(allpassL);
}
//make the allpass filters on the left
for (var r = 0; r < allpassFilterFrequencies.length; r++) {
var allpassR = this.context.createBiquadFilter();
allpassR.type = 'allpass';
allpassR.frequency.value = allpassFilterFrequencies[r];
this._allpassFiltersR.push(allpassR);
}
//make the comb filters
for (var c = 0; c < combFilterTunings.length; c++) {
var lfpf = new Tone.LowpassCombFilter(combFilterTunings[c]);
if (c < combFilterTunings.length / 2) {
this.effectSendL.chain(lfpf, this._allpassFiltersL[0]);
} else {
this.effectSendR.chain(lfpf, this._allpassFiltersR[0]);
}
this.roomSize.connect(lfpf.resonance);
this.dampening.connect(lfpf.dampening);
this._combFilters.push(lfpf);
}
//chain the allpass filters togetehr
this.connectSeries.apply(this, this._allpassFiltersL);
this.connectSeries.apply(this, this._allpassFiltersR);
this._allpassFiltersL[this._allpassFiltersL.length - 1].connect(this.effectReturnL);
this._allpassFiltersR[this._allpassFiltersR.length - 1].connect(this.effectReturnR);
this._readOnly([
'roomSize',
'dampening'
]);
};
Tone.extend(Tone.Freeverb, Tone.StereoEffect);
/**
* @static
* @type {Object}
*/
Tone.Freeverb.defaults = {
'roomSize': 0.7,
'dampening': 3000
};
/**
* Clean up.
* @returns {Tone.Freeverb} this
*/
Tone.Freeverb.prototype.dispose = function () {
Tone.StereoEffect.prototype.dispose.call(this);
for (var al = 0; al < this._allpassFiltersL.length; al++) {
this._allpassFiltersL[al].disconnect();
this._allpassFiltersL[al] = null;
}
this._allpassFiltersL = null;
for (var ar = 0; ar < this._allpassFiltersR.length; ar++) {
this._allpassFiltersR[ar].disconnect();
this._allpassFiltersR[ar] = null;
}
this._allpassFiltersR = null;
for (var cf = 0; cf < this._combFilters.length; cf++) {
this._combFilters[cf].dispose();
this._combFilters[cf] = null;
}
this._combFilters = null;
this._writable([
'roomSize',
'dampening'
]);
this.roomSize.dispose();
this.roomSize = null;
this.dampening.dispose();
this.dampening = null;
return this;
};
return Tone.Freeverb;
});
Module(function (Tone) {
/**
* an array of the comb filter delay time values
* @private
* @static
* @type {Array}
*/
var combFilterDelayTimes = [
1687 / 25000,
1601 / 25000,
2053 / 25000,
2251 / 25000
];
/**
* the resonances of each of the comb filters
* @private
* @static
* @type {Array}
*/
var combFilterResonances = [
0.773,
0.802,
0.753,
0.733
];
/**
* the allpass filter frequencies
* @private
* @static
* @type {Array}
*/
var allpassFilterFreqs = [
347,
113,
37
];
/**
* @class Tone.JCReverb is a simple [Schroeder Reverberator](https://ccrma.stanford.edu/~jos/pasp/Schroeder_Reverberators.html)
* tuned by John Chowning in 1970.
* It is made up of three allpass filters and four Tone.FeedbackCombFilter.
*
*
* @extends {Tone.Effect}
* @constructor
* @param {NormalRange|Object} [roomSize] Coorelates to the decay time.
* @example
* var reverb = new Tone.JCReverb(0.4).connect(Tone.Master);
* var delay = new Tone.FeedbackDelay(0.5);
* //connecting the synth to reverb through delay
* var synth = new Tone.DuoSynth().chain(delay, reverb);
* synth.triggerAttackRelease("A4","8n");
*/
Tone.JCReverb = function () {
var options = this.optionsObject(arguments, ['roomSize'], Tone.JCReverb.defaults);
Tone.StereoEffect.call(this, options);
/**
* room size control values between [0,1]
* @type {NormalRange}
* @signal
*/
this.roomSize = new Tone.Signal(options.roomSize, Tone.Type.NormalRange);
/**
* scale the room size
* @type {Tone.Scale}
* @private
*/
this._scaleRoomSize = new Tone.Scale(-0.733, 0.197);
/**
* a series of allpass filters
* @type {Array}
* @private
*/
this._allpassFilters = [];
/**
* parallel feedback comb filters
* @type {Array}
* @private
*/
this._feedbackCombFilters = [];
//make the allpass filters
for (var af = 0; af < allpassFilterFreqs.length; af++) {
var allpass = this.context.createBiquadFilter();
allpass.type = 'allpass';
allpass.frequency.value = allpassFilterFreqs[af];
this._allpassFilters.push(allpass);
}
//and the comb filters
for (var cf = 0; cf < combFilterDelayTimes.length; cf++) {
var fbcf = new Tone.FeedbackCombFilter(combFilterDelayTimes[cf], 0.1);
this._scaleRoomSize.connect(fbcf.resonance);
fbcf.resonance.value = combFilterResonances[cf];
this._allpassFilters[this._allpassFilters.length - 1].connect(fbcf);
if (cf < combFilterDelayTimes.length / 2) {
fbcf.connect(this.effectReturnL);
} else {
fbcf.connect(this.effectReturnR);
}
this._feedbackCombFilters.push(fbcf);
}
//chain the allpass filters together
this.roomSize.connect(this._scaleRoomSize);
this.connectSeries.apply(this, this._allpassFilters);
this.effectSendL.connect(this._allpassFilters[0]);
this.effectSendR.connect(this._allpassFilters[0]);
this._readOnly(['roomSize']);
};
Tone.extend(Tone.JCReverb, Tone.StereoEffect);
/**
* the default values
* @static
* @const
* @type {Object}
*/
Tone.JCReverb.defaults = { 'roomSize': 0.5 };
/**
* Clean up.
* @returns {Tone.JCReverb} this
*/
Tone.JCReverb.prototype.dispose = function () {
Tone.StereoEffect.prototype.dispose.call(this);
for (var apf = 0; apf < this._allpassFilters.length; apf++) {
this._allpassFilters[apf].disconnect();
this._allpassFilters[apf] = null;
}
this._allpassFilters = null;
for (var fbcf = 0; fbcf < this._feedbackCombFilters.length; fbcf++) {
this._feedbackCombFilters[fbcf].dispose();
this._feedbackCombFilters[fbcf] = null;
}
this._feedbackCombFilters = null;
this._writable(['roomSize']);
this.roomSize.dispose();
this.roomSize = null;
this._scaleRoomSize.dispose();
this._scaleRoomSize = null;
return this;
};
return Tone.JCReverb;
});
Module(function (Tone) {
/**
* @class Mid/Side processing separates the the 'mid' signal
* (which comes out of both the left and the right channel)
* and the 'side' (which only comes out of the the side channels)
* and effects them separately before being recombined.
* Applies a Mid/Side seperation and recombination.
* Algorithm found in [kvraudio forums](http://www.kvraudio.com/forum/viewtopic.php?t=212587).
* <br><br>
* This is a base-class for Mid/Side Effects.
*
* @extends {Tone.Effect}
* @constructor
*/
Tone.MidSideEffect = function () {
Tone.Effect.apply(this, arguments);
/**
* The mid/side split
* @type {Tone.MidSideSplit}
* @private
*/
this._midSideSplit = new Tone.MidSideSplit();
/**
* The mid/side merge
* @type {Tone.MidSideMerge}
* @private
*/
this._midSideMerge = new Tone.MidSideMerge();
/**
* The mid send. Connect to mid processing
* @type {Tone.Expr}
* @private
*/
this.midSend = this._midSideSplit.mid;
/**
* The side send. Connect to side processing
* @type {Tone.Expr}
* @private
*/
this.sideSend = this._midSideSplit.side;
/**
* The mid return connection
* @type {GainNode}
* @private
*/
this.midReturn = this._midSideMerge.mid;
/**
* The side return connection
* @type {GainNode}
* @private
*/
this.sideReturn = this._midSideMerge.side;
//the connections
this.effectSend.connect(this._midSideSplit);
this._midSideMerge.connect(this.effectReturn);
};
Tone.extend(Tone.MidSideEffect, Tone.Effect);
/**
* Clean up.
* @returns {Tone.MidSideEffect} this
*/
Tone.MidSideEffect.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._midSideSplit.dispose();
this._midSideSplit = null;
this._midSideMerge.dispose();
this._midSideMerge = null;
this.midSend = null;
this.sideSend = null;
this.midReturn = null;
this.sideReturn = null;
return this;
};
return Tone.MidSideEffect;
});
Module(function (Tone) {
/**
* @class Tone.Phaser is a phaser effect. Phasers work by changing the phase
* of different frequency components of an incoming signal. Read more on
* [Wikipedia](https://en.wikipedia.org/wiki/Phaser_(effect)).
* Inspiration for this phaser comes from [Tuna.js](https://github.com/Dinahmoe/tuna/).
*
* @extends {Tone.StereoEffect}
* @constructor
* @param {Frequency|Object} [frequency] The speed of the phasing.
* @param {number} [octaves] The octaves of the effect.
* @param {Frequency} [baseFrequency] The base frequency of the filters.
* @example
* var phaser = new Tone.Phaser({
* "frequency" : 15,
* "octaves" : 5,
* "baseFrequency" : 1000
* }).toMaster();
* var synth = new Tone.FMSynth().connect(phaser);
* synth.triggerAttackRelease("E3", "2n");
*/
Tone.Phaser = function () {
//set the defaults
var options = this.optionsObject(arguments, [
'frequency',
'octaves',
'baseFrequency'
], Tone.Phaser.defaults);
Tone.StereoEffect.call(this, options);
/**
* the lfo which controls the frequency on the left side
* @type {Tone.LFO}
* @private
*/
this._lfoL = new Tone.LFO(options.frequency, 0, 1);
/**
* the lfo which controls the frequency on the right side
* @type {Tone.LFO}
* @private
*/
this._lfoR = new Tone.LFO(options.frequency, 0, 1);
this._lfoR.phase = 180;
/**
* the base modulation frequency
* @type {number}
* @private
*/
this._baseFrequency = options.baseFrequency;
/**
* the octaves of the phasing
* @type {number}
* @private
*/
this._octaves = options.octaves;
/**
* The quality factor of the filters
* @type {Positive}
* @signal
*/
this.Q = new Tone.Signal(options.Q, Tone.Type.Positive);
/**
* the array of filters for the left side
* @type {Array}
* @private
*/
this._filtersL = this._makeFilters(options.stages, this._lfoL, this.Q);
/**
* the array of filters for the left side
* @type {Array}
* @private
*/
this._filtersR = this._makeFilters(options.stages, this._lfoR, this.Q);
/**
* the frequency of the effect
* @type {Tone.Signal}
*/
this.frequency = this._lfoL.frequency;
this.frequency.value = options.frequency;
//connect them up
this.effectSendL.connect(this._filtersL[0]);
this.effectSendR.connect(this._filtersR[0]);
this._filtersL[options.stages - 1].connect(this.effectReturnL);
this._filtersR[options.stages - 1].connect(this.effectReturnR);
//control the frequency with one LFO
this._lfoL.frequency.connect(this._lfoR.frequency);
//set the options
this.baseFrequency = options.baseFrequency;
this.octaves = options.octaves;
//start the lfo
this._lfoL.start();
this._lfoR.start();
this._readOnly([
'frequency',
'Q'
]);
};
Tone.extend(Tone.Phaser, Tone.StereoEffect);
/**
* defaults
* @static
* @type {object}
*/
Tone.Phaser.defaults = {
'frequency': 0.5,
'octaves': 3,
'stages': 10,
'Q': 10,
'baseFrequency': 350
};
/**
* @param {number} stages
* @returns {Array} the number of filters all connected together
* @private
*/
Tone.Phaser.prototype._makeFilters = function (stages, connectToFreq, Q) {
var filters = new Array(stages);
//make all the filters
for (var i = 0; i < stages; i++) {
var filter = this.context.createBiquadFilter();
filter.type = 'allpass';
Q.connect(filter.Q);
connectToFreq.connect(filter.frequency);
filters[i] = filter;
}
this.connectSeries.apply(this, filters);
return filters;
};
/**
* The number of octaves the phase goes above
* the baseFrequency
* @memberOf Tone.Phaser#
* @type {Positive}
* @name octaves
*/
Object.defineProperty(Tone.Phaser.prototype, 'octaves', {
get: function () {
return this._octaves;
},
set: function (octaves) {
this._octaves = octaves;
var max = this._baseFrequency * Math.pow(2, octaves);
this._lfoL.max = max;
this._lfoR.max = max;
}
});
/**
* The the base frequency of the filters.
* @memberOf Tone.Phaser#
* @type {number}
* @name baseFrequency
*/
Object.defineProperty(Tone.Phaser.prototype, 'baseFrequency', {
get: function () {
return this._baseFrequency;
},
set: function (freq) {
this._baseFrequency = freq;
this._lfoL.min = freq;
this._lfoR.min = freq;
this.octaves = this._octaves;
}
});
/**
* clean up
* @returns {Tone.Phaser} this
*/
Tone.Phaser.prototype.dispose = function () {
Tone.StereoEffect.prototype.dispose.call(this);
this._writable([
'frequency',
'Q'
]);
this.Q.dispose();
this.Q = null;
this._lfoL.dispose();
this._lfoL = null;
this._lfoR.dispose();
this._lfoR = null;
for (var i = 0; i < this._filtersL.length; i++) {
this._filtersL[i].disconnect();
this._filtersL[i] = null;
}
this._filtersL = null;
for (var j = 0; j < this._filtersR.length; j++) {
this._filtersR[j].disconnect();
this._filtersR[j] = null;
}
this._filtersR = null;
this.frequency = null;
return this;
};
return Tone.Phaser;
});
Module(function (Tone) {
/**
* @class Tone.PingPongDelay is a feedback delay effect where the echo is heard
* first in one channel and next in the opposite channel. In a stereo
* system these are the right and left channels.
* PingPongDelay in more simplified terms is two Tone.FeedbackDelays
* with independent delay values. Each delay is routed to one channel
* (left or right), and the channel triggered second will always
* trigger at the same interval after the first.
*
* @constructor
* @extends {Tone.StereoXFeedbackEffect}
* @param {Time|Object} [delayTime] The delayTime between consecutive echos.
* @param {NormalRange=} feedback The amount of the effected signal which
* is fed back through the delay.
* @example
* var pingPong = new Tone.PingPongDelay("4n", 0.2).toMaster();
* var drum = new Tone.DrumSynth().connect(pingPong);
* drum.triggerAttackRelease("C4", "32n");
*/
Tone.PingPongDelay = function () {
var options = this.optionsObject(arguments, [
'delayTime',
'feedback'
], Tone.PingPongDelay.defaults);
Tone.StereoXFeedbackEffect.call(this, options);
/**
* the delay node on the left side
* @type {DelayNode}
* @private
*/
this._leftDelay = this.context.createDelay(options.maxDelayTime);
/**
* the delay node on the right side
* @type {DelayNode}
* @private
*/
this._rightDelay = this.context.createDelay(options.maxDelayTime);
/**
* the predelay on the right side
* @type {DelayNode}
* @private
*/
this._rightPreDelay = this.context.createDelay(options.maxDelayTime);
/**
* the delay time signal
* @type {Time}
* @signal
*/
this.delayTime = new Tone.Signal(options.delayTime, Tone.Type.Time);
//connect it up
this.effectSendL.chain(this._leftDelay, this.effectReturnL);
this.effectSendR.chain(this._rightPreDelay, this._rightDelay, this.effectReturnR);
this.delayTime.fan(this._leftDelay.delayTime, this._rightDelay.delayTime, this._rightPreDelay.delayTime);
//rearranged the feedback to be after the rightPreDelay
this._feedbackLR.disconnect();
this._feedbackLR.connect(this._rightDelay);
this._readOnly(['delayTime']);
};
Tone.extend(Tone.PingPongDelay, Tone.StereoXFeedbackEffect);
/**
* @static
* @type {Object}
*/
Tone.PingPongDelay.defaults = {
'delayTime': 0.25,
'maxDelayTime': 1
};
/**
* Clean up.
* @returns {Tone.PingPongDelay} this
*/
Tone.PingPongDelay.prototype.dispose = function () {
Tone.StereoXFeedbackEffect.prototype.dispose.call(this);
this._leftDelay.disconnect();
this._leftDelay = null;
this._rightDelay.disconnect();
this._rightDelay = null;
this._rightPreDelay.disconnect();
this._rightPreDelay = null;
this._writable(['delayTime']);
this.delayTime.dispose();
this.delayTime = null;
return this;
};
return Tone.PingPongDelay;
});
Module(function (Tone) {
/**
* @class Tone.PitchShift does near-realtime pitch shifting to the incoming signal.
* The effect is achieved by speeding up or slowing down the delayTime
* of a DelayNode using a sawtooth wave.
* Algorithm found in [this pdf](http://dsp-book.narod.ru/soundproc.pdf).
* Additional reference by [Miller Pucket](http://msp.ucsd.edu/techniques/v0.11/book-html/node115.html).
*
* @extends {Tone.FeedbackEffect}
* @param {Interval=} pitch The interval to transpose the incoming signal by.
*/
Tone.PitchShift = function () {
var options = this.optionsObject(arguments, ['pitch'], Tone.PitchShift.defaults);
Tone.FeedbackEffect.call(this, options);
/**
* The pitch signal
* @type {Tone.Signal}
* @private
*/
this._frequency = new Tone.Signal(0);
/**
* Uses two DelayNodes to cover up the jump in
* the sawtooth wave.
* @type {DelayNode}
* @private
*/
this._delayA = new Tone.Delay(0, 1);
/**
* The first LFO.
* @type {Tone.LFO}
* @private
*/
this._lfoA = new Tone.LFO({
'min': 0,
'max': 0.1,
'type': 'sawtooth'
}).connect(this._delayA.delayTime);
/**
* The second DelayNode
* @type {DelayNode}
* @private
*/
this._delayB = new Tone.Delay(0, 1);
/**
* The first LFO.
* @type {Tone.LFO}
* @private
*/
this._lfoB = new Tone.LFO({
'min': 0,
'max': 0.1,
'type': 'sawtooth',
'phase': 180
}).connect(this._delayB.delayTime);
/**
* Crossfade quickly between the two delay lines
* to cover up the jump in the sawtooth wave
* @type {Tone.CrossFade}
* @private
*/
this._crossFade = new Tone.CrossFade();
/**
* LFO which alternates between the two
* delay lines to cover up the disparity in the
* sawtooth wave.
* @type {Tone.LFO}
* @private
*/
this._crossFadeLFO = new Tone.LFO({
'min': 0,
'max': 1,
'type': 'triangle',
'phase': 90
}).connect(this._crossFade.fade);
/**
* The delay node
* @type {Tone.Delay}
* @private
*/
this._feedbackDelay = new Tone.Delay(options.delayTime);
/**
* The amount of delay on the input signal
* @type {Time}
* @signal
*/
this.delayTime = this._feedbackDelay.delayTime;
this._readOnly('delayTime');
/**
* Hold the current pitch
* @type {Number}
* @private
*/
this._pitch = options.pitch;
/**
* Hold the current windowSize
* @type {Number}
* @private
*/
this._windowSize = options.windowSize;
//connect the two delay lines up
this._delayA.connect(this._crossFade.a);
this._delayB.connect(this._crossFade.b);
//connect the frequency
this._frequency.fan(this._lfoA.frequency, this._lfoB.frequency, this._crossFadeLFO.frequency);
//route the input
this.effectSend.fan(this._delayA, this._delayB);
this._crossFade.chain(this._feedbackDelay, this.effectReturn);
//start the LFOs at the same time
var now = this.now();
this._lfoA.start(now);
this._lfoB.start(now);
this._crossFadeLFO.start(now);
//set the initial value
this.windowSize = this._windowSize;
};
Tone.extend(Tone.PitchShift, Tone.FeedbackEffect);
/**
* default values
* @static
* @type {Object}
* @const
*/
Tone.PitchShift.defaults = {
'pitch': 0,
'windowSize': 0.1,
'delayTime': 0,
'feedback': 0
};
/**
* Repitch the incoming signal by some interval (measured
* in semi-tones).
* @memberOf Tone.PitchShift#
* @type {Interval}
* @name pitch
* @example
* pitchShift.pitch = -12; //down one octave
* pitchShift.pitch = 7; //up a fifth
*/
Object.defineProperty(Tone.PitchShift.prototype, 'pitch', {
get: function () {
return this._pitch;
},
set: function (interval) {
this._pitch = interval;
var factor = 0;
if (interval < 0) {
this._lfoA.min = 0;
this._lfoA.max = this._windowSize;
this._lfoB.min = 0;
this._lfoB.max = this._windowSize;
factor = this.intervalToFrequencyRatio(interval - 1) + 1;
} else {
this._lfoA.min = this._windowSize;
this._lfoA.max = 0;
this._lfoB.min = this._windowSize;
this._lfoB.max = 0;
factor = this.intervalToFrequencyRatio(interval) - 1;
}
this._frequency.value = factor * (1.2 / this._windowSize);
}
});
/**
* The window size corresponds roughly to the sample length in a looping sampler.
* Smaller values are desirable for a less noticeable delay time of the pitch shifted
* signal, but larger values will result in smoother pitch shifting for larger intervals.
* A nominal range of 0.03 to 0.1 is recommended.
* @memberOf Tone.PitchShift#
* @type {Time}
* @name windowSize
* @example
* pitchShift.windowSize = 0.1;
*/
Object.defineProperty(Tone.PitchShift.prototype, 'windowSize', {
get: function () {
return this._windowSize;
},
set: function (size) {
this._windowSize = this.toSeconds(size);
this.pitch = this._pitch;
}
});
/**
* Clean up.
* @return {Tone.PitchShift} this
*/
Tone.PitchShift.prototype.dispose = function () {
Tone.FeedbackEffect.prototype.dispose.call(this);
this._frequency.dispose();
this._frequency = null;
this._delayA.disconnect();
this._delayA = null;
this._delayB.disconnect();
this._delayB = null;
this._lfoA.dispose();
this._lfoA = null;
this._lfoB.dispose();
this._lfoB = null;
this._crossFade.dispose();
this._crossFade = null;
this._crossFadeLFO.dispose();
this._crossFadeLFO = null;
this._writable('delayTime');
this._feedbackDelay.dispose();
this._feedbackDelay = null;
this.delayTime = null;
return this;
};
return Tone.PitchShift;
});
Module(function (Tone) {
/**
* @class Base class for stereo feedback effects where the effectReturn
* is fed back into the same channel.
*
* @constructor
* @extends {Tone.FeedbackEffect}
*/
Tone.StereoFeedbackEffect = function () {
var options = this.optionsObject(arguments, ['feedback'], Tone.FeedbackEffect.defaults);
Tone.StereoEffect.call(this, options);
/**
* controls the amount of feedback
* @type {NormalRange}
* @signal
*/
this.feedback = new Tone.Signal(options.feedback, Tone.Type.NormalRange);
/**
* the left side feeback
* @type {GainNode}
* @private
*/
this._feedbackL = this.context.createGain();
/**
* the right side feeback
* @type {GainNode}
* @private
*/
this._feedbackR = this.context.createGain();
//connect it up
this.effectReturnL.chain(this._feedbackL, this.effectSendL);
this.effectReturnR.chain(this._feedbackR, this.effectSendR);
this.feedback.fan(this._feedbackL.gain, this._feedbackR.gain);
this._readOnly(['feedback']);
};
Tone.extend(Tone.StereoFeedbackEffect, Tone.FeedbackEffect);
/**
* clean up
* @returns {Tone.StereoFeedbackEffect} this
*/
Tone.StereoFeedbackEffect.prototype.dispose = function () {
Tone.StereoEffect.prototype.dispose.call(this);
this._writable(['feedback']);
this.feedback.dispose();
this.feedback = null;
this._feedbackL.disconnect();
this._feedbackL = null;
this._feedbackR.disconnect();
this._feedbackR = null;
return this;
};
return Tone.StereoFeedbackEffect;
});
Module(function (Tone) {
/**
* @class Applies a width factor to the mid/side seperation.
* 0 is all mid and 1 is all side.
* Algorithm found in [kvraudio forums](http://www.kvraudio.com/forum/viewtopic.php?t=212587).
* <br><br>
* <code>
* Mid *= 2*(1-width)<br>
* Side *= 2*width
* </code>
*
* @extends {Tone.MidSideEffect}
* @constructor
* @param {NormalRange|Object} [width] The stereo width. A width of 0 is mono and 1 is stereo. 0.5 is no change.
*/
Tone.StereoWidener = function () {
var options = this.optionsObject(arguments, ['width'], Tone.StereoWidener.defaults);
Tone.MidSideEffect.call(this, options);
/**
* The width control. 0 = 100% mid. 1 = 100% side. 0.5 = no change.
* @type {NormalRange}
* @signal
*/
this.width = new Tone.Signal(options.width, Tone.Type.NormalRange);
/**
* Mid multiplier
* @type {Tone.Expr}
* @private
*/
this._midMult = new Tone.Expr('$0 * ($1 * (1 - $2))');
/**
* Side multiplier
* @type {Tone.Expr}
* @private
*/
this._sideMult = new Tone.Expr('$0 * ($1 * $2)');
/**
* constant output of 2
* @type {Tone}
* @private
*/
this._two = new Tone.Signal(2);
//the mid chain
this._two.connect(this._midMult, 0, 1);
this.width.connect(this._midMult, 0, 2);
//the side chain
this._two.connect(this._sideMult, 0, 1);
this.width.connect(this._sideMult, 0, 2);
//connect it to the effect send/return
this.midSend.chain(this._midMult, this.midReturn);
this.sideSend.chain(this._sideMult, this.sideReturn);
this._readOnly(['width']);
};
Tone.extend(Tone.StereoWidener, Tone.MidSideEffect);
/**
* the default values
* @static
* @type {Object}
*/
Tone.StereoWidener.defaults = { 'width': 0.5 };
/**
* Clean up.
* @returns {Tone.StereoWidener} this
*/
Tone.StereoWidener.prototype.dispose = function () {
Tone.MidSideEffect.prototype.dispose.call(this);
this._writable(['width']);
this.width.dispose();
this.width = null;
this._midMult.dispose();
this._midMult = null;
this._sideMult.dispose();
this._sideMult = null;
this._two.dispose();
this._two = null;
return this;
};
return Tone.StereoWidener;
});
Module(function (Tone) {
/**
* @class Tone.Tremolo modulates the amplitude of an incoming signal using a Tone.LFO.
* The type, frequency, and depth of the LFO is controllable.
*
* @extends {Tone.StereoEffect}
* @constructor
* @param {Frequency} [frequency] The rate of the effect.
* @param {NormalRange} [depth] The depth of the effect.
* @example
* //create a tremolo and start it's LFO
* var tremolo = new Tone.Tremolo(9, 0.75).toMaster().start();
* //route an oscillator through the tremolo and start it
* var oscillator = new Tone.Oscillator().connect(tremolo).start();
*/
Tone.Tremolo = function () {
var options = this.optionsObject(arguments, [
'frequency',
'depth'
], Tone.Tremolo.defaults);
Tone.StereoEffect.call(this, options);
/**
* The tremelo LFO in the left channel
* @type {Tone.LFO}
* @private
*/
this._lfoL = new Tone.LFO({
'phase': options.spread,
'min': 1,
'max': 0
});
/**
* The tremelo LFO in the left channel
* @type {Tone.LFO}
* @private
*/
this._lfoR = new Tone.LFO({
'phase': options.spread,
'min': 1,
'max': 0
});
/**
* Where the gain is multiplied
* @type {Tone.Gain}
* @private
*/
this._amplitudeL = new Tone.Gain();
/**
* Where the gain is multiplied
* @type {Tone.Gain}
* @private
*/
this._amplitudeR = new Tone.Gain();
/**
* The frequency of the tremolo.
* @type {Frequency}
* @signal
*/
this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
/**
* The depth of the effect. A depth of 0, has no effect
* on the amplitude, and a depth of 1 makes the amplitude
* modulate fully between 0 and 1.
* @type {NormalRange}
* @signal
*/
this.depth = new Tone.Signal(options.depth, Tone.Type.NormalRange);
this._readOnly([
'frequency',
'depth'
]);
this.effectSendL.chain(this._amplitudeL, this.effectReturnL);
this.effectSendR.chain(this._amplitudeR, this.effectReturnR);
this._lfoL.connect(this._amplitudeL.gain);
this._lfoR.connect(this._amplitudeR.gain);
this.frequency.fan(this._lfoL.frequency, this._lfoR.frequency);
this.depth.fan(this._lfoR.amplitude, this._lfoL.amplitude);
this.type = options.type;
this.spread = options.spread;
};
Tone.extend(Tone.Tremolo, Tone.StereoEffect);
/**
* @static
* @const
* @type {Object}
*/
Tone.Tremolo.defaults = {
'frequency': 10,
'type': 'sine',
'depth': 0.5,
'spread': 180
};
/**
* Start the tremolo.
* @param {Time} [time=now] When the tremolo begins.
* @returns {Tone.Tremolo} this
*/
Tone.Tremolo.prototype.start = function (time) {
this._lfoL.start(time);
this._lfoR.start(time);
return this;
};
/**
* Stop the tremolo.
* @param {Time} [time=now] When the tremolo stops.
* @returns {Tone.Tremolo} this
*/
Tone.Tremolo.prototype.stop = function (time) {
this._lfoL.stop(time);
this._lfoR.stop(time);
return this;
};
/**
* Sync the effect to the transport.
* @param {Time} [delay=0] Delay time before starting the effect after the
* Transport has started.
* @returns {Tone.AutoFilter} this
*/
Tone.Tremolo.prototype.sync = function (delay) {
this._lfoL.sync(delay);
this._lfoR.sync(delay);
return this;
};
/**
* Unsync the filter from the transport
* @returns {Tone.Tremolo} this
*/
Tone.Tremolo.prototype.unsync = function () {
this._lfoL.unsync();
this._lfoR.unsync();
return this;
};
/**
* The Tremolo's oscillator type.
* @memberOf Tone.Tremolo#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.Tremolo.prototype, 'type', {
get: function () {
return this._lfoL.type;
},
set: function (type) {
this._lfoL.type = type;
this._lfoR.type = type;
}
});
/**
* Amount of stereo spread. When set to 0, both LFO's will be panned centrally.
* When set to 180, LFO's will be panned hard left and right respectively.
* @memberOf Tone.Tremolo#
* @type {Degrees}
* @name spread
*/
Object.defineProperty(Tone.Tremolo.prototype, 'spread', {
get: function () {
return this._lfoR.phase - this._lfoL.phase; //180
},
set: function (spread) {
this._lfoL.phase = 90 - spread / 2;
this._lfoR.phase = spread / 2 + 90;
}
});
/**
* clean up
* @returns {Tone.Tremolo} this
*/
Tone.Tremolo.prototype.dispose = function () {
Tone.StereoEffect.prototype.dispose.call(this);
this._writable([
'frequency',
'depth'
]);
this._lfoL.dispose();
this._lfoL = null;
this._lfoR.dispose();
this._lfoR = null;
this._amplitudeL.dispose();
this._amplitudeL = null;
this._amplitudeR.dispose();
this._amplitudeR = null;
this.frequency = null;
this.depth = null;
return this;
};
return Tone.Tremolo;
});
Module(function (Tone) {
/**
* @class A Vibrato effect composed of a Tone.Delay and a Tone.LFO. The LFO
* modulates the delayTime of the delay, causing the pitch to rise
* and fall.
* @extends {Tone.Effect}
* @param {Frequency} frequency The frequency of the vibrato.
* @param {NormalRange} depth The amount the pitch is modulated.
*/
Tone.Vibrato = function () {
var options = this.optionsObject(arguments, [
'frequency',
'depth'
], Tone.Vibrato.defaults);
Tone.Effect.call(this, options);
/**
* The delay node used for the vibrato effect
* @type {Tone.Delay}
* @private
*/
this._delayNode = new Tone.Delay(0, options.maxDelay);
/**
* The LFO used to control the vibrato
* @type {Tone.LFO}
* @private
*/
this._lfo = new Tone.LFO({
'type': options.type,
'min': 0,
'max': options.maxDelay,
'frequency': options.frequency,
'phase': -90 //offse the phase so the resting position is in the center
}).start().connect(this._delayNode.delayTime);
/**
* The frequency of the vibrato
* @type {Frequency}
* @signal
*/
this.frequency = this._lfo.frequency;
/**
* The depth of the vibrato.
* @type {NormalRange}
* @signal
*/
this.depth = this._lfo.amplitude;
this.depth.value = options.depth;
this._readOnly([
'frequency',
'depth'
]);
this.effectSend.chain(this._delayNode, this.effectReturn);
};
Tone.extend(Tone.Vibrato, Tone.Effect);
/**
* The defaults
* @type {Object}
* @const
*/
Tone.Vibrato.defaults = {
'maxDelay': 0.005,
'frequency': 5,
'depth': 0.1,
'type': 'sine'
};
/**
* Type of oscillator attached to the Vibrato.
* @memberOf Tone.Vibrato#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.Vibrato.prototype, 'type', {
get: function () {
return this._lfo.type;
},
set: function (type) {
this._lfo.type = type;
}
});
/**
* Clean up.
* @returns {Tone.Vibrato} this
*/
Tone.Vibrato.prototype.dispose = function () {
Tone.Effect.prototype.dispose.call(this);
this._delayNode.dispose();
this._delayNode = null;
this._lfo.dispose();
this._lfo = null;
this._writable([
'frequency',
'depth'
]);
this.frequency = null;
this.depth = null;
};
return Tone.Vibrato;
});
Module(function (Tone) {
/**
* @class Tone.Event abstracts away Tone.Transport.schedule and provides a schedulable
* callback for a single or repeatable events along the timeline.
*
* @extends {Tone}
* @param {function} callback The callback to invoke at the time.
* @param {*} value The value or values which should be passed to
* the callback function on invocation.
* @example
* var chord = new Tone.Event(function(time, chord){
* //the chord as well as the exact time of the event
* //are passed in as arguments to the callback function
* }, ["D4", "E4", "F4"]);
* //start the chord at the beginning of the transport timeline
* chord.start();
* //loop it every measure for 8 measures
* chord.loop = 8;
* chord.loopEnd = "1m";
*/
Tone.Event = function () {
var options = this.optionsObject(arguments, [
'callback',
'value'
], Tone.Event.defaults);
/**
* Loop value
* @type {Boolean|Positive}
* @private
*/
this._loop = options.loop;
/**
* The callback to invoke.
* @type {Function}
*/
this.callback = options.callback;
/**
* The value which is passed to the
* callback function.
* @type {*}
* @private
*/
this.value = options.value;
/**
* When the note is scheduled to start.
* @type {Number}
* @private
*/
this._loopStart = this.toTicks(options.loopStart);
/**
* When the note is scheduled to start.
* @type {Number}
* @private
*/
this._loopEnd = this.toTicks(options.loopEnd);
/**
* Tracks the scheduled events
* @type {Tone.TimelineState}
* @private
*/
this._state = new Tone.TimelineState(Tone.State.Stopped);
/**
* The playback speed of the note. A speed of 1
* is no change.
* @private
* @type {Positive}
*/
this._playbackRate = 1;
/**
* A delay time from when the event is scheduled to start
* @type {Ticks}
* @private
*/
this._startOffset = 0;
/**
* The probability that the callback will be invoked
* at the scheduled time.
* @type {NormalRange}
* @example
* //the callback will be invoked 50% of the time
* event.probability = 0.5;
*/
this.probability = options.probability;
/**
* If set to true, will apply small (+/-0.02 seconds) random variation
* to the callback time. If the value is given as a time, it will randomize
* by that amount.
* @example
* event.humanize = true;
* @type {Boolean|Time}
*/
this.humanize = options.humanize;
/**
* If mute is true, the callback won't be
* invoked.
* @type {Boolean}
*/
this.mute = options.mute;
//set the initial values
this.playbackRate = options.playbackRate;
};
Tone.extend(Tone.Event);
/**
* The default values
* @type {Object}
* @const
*/
Tone.Event.defaults = {
'callback': Tone.noOp,
'loop': false,
'loopEnd': '1m',
'loopStart': 0,
'playbackRate': 1,
'value': null,
'probability': 1,
'mute': false,
'humanize': false
};
/**
* Reschedule all of the events along the timeline
* with the updated values.
* @param {Time} after Only reschedules events after the given time.
* @return {Tone.Event} this
* @private
*/
Tone.Event.prototype._rescheduleEvents = function (after) {
//if no argument is given, schedules all of the events
after = this.defaultArg(after, -1);
this._state.forEachFrom(after, function (event) {
var duration;
if (event.state === Tone.State.Started) {
if (!this.isUndef(event.id)) {
Tone.Transport.clear(event.id);
}
var startTick = event.time + Math.round(this.startOffset / this._playbackRate);
if (this._loop) {
duration = Infinity;
if (this.isNumber(this._loop)) {
duration = (this._loop - 1) * this._getLoopDuration();
}
var nextEvent = this._state.getEventAfter(startTick);
if (nextEvent !== null) {
duration = Math.min(duration, nextEvent.time - startTick);
}
if (duration !== Infinity) {
//schedule a stop since it's finite duration
this._state.setStateAtTime(Tone.State.Stopped, startTick + duration + 1);
duration += 'i';
}
event.id = Tone.Transport.scheduleRepeat(this._tick.bind(this), this._getLoopDuration().toString() + 'i', startTick + 'i', duration);
} else {
event.id = Tone.Transport.schedule(this._tick.bind(this), startTick + 'i');
}
}
}.bind(this));
return this;
};
/**
* Returns the playback state of the note, either "started" or "stopped".
* @type {String}
* @readOnly
* @memberOf Tone.Event#
* @name state
*/
Object.defineProperty(Tone.Event.prototype, 'state', {
get: function () {
return this._state.getStateAtTime(Tone.Transport.ticks);
}
});
/**
* The start from the scheduled start time
* @type {Ticks}
* @memberOf Tone.Event#
* @name startOffset
* @private
*/
Object.defineProperty(Tone.Event.prototype, 'startOffset', {
get: function () {
return this._startOffset;
},
set: function (offset) {
this._startOffset = offset;
}
});
/**
* Start the note at the given time.
* @param {Time} time When the note should start.
* @return {Tone.Event} this
*/
Tone.Event.prototype.start = function (time) {
time = this.toTicks(time);
if (this._state.getStateAtTime(time) === Tone.State.Stopped) {
this._state.addEvent({
'state': Tone.State.Started,
'time': time,
'id': undefined
});
this._rescheduleEvents(time);
}
return this;
};
/**
* Stop the Event at the given time.
* @param {Time} time When the note should stop.
* @return {Tone.Event} this
*/
Tone.Event.prototype.stop = function (time) {
this.cancel(time);
time = this.toTicks(time);
if (this._state.getStateAtTime(time) === Tone.State.Started) {
this._state.setStateAtTime(Tone.State.Stopped, time);
var previousEvent = this._state.getEventBefore(time);
var reschedulTime = time;
if (previousEvent !== null) {
reschedulTime = previousEvent.time;
}
this._rescheduleEvents(reschedulTime);
}
return this;
};
/**
* Cancel all scheduled events greater than or equal to the given time
* @param {Time} [time=0] The time after which events will be cancel.
* @return {Tone.Event} this
*/
Tone.Event.prototype.cancel = function (time) {
time = this.defaultArg(time, -Infinity);
time = this.toTicks(time);
this._state.forEachFrom(time, function (event) {
Tone.Transport.clear(event.id);
});
this._state.cancel(time);
return this;
};
/**
* The callback function invoker. Also
* checks if the Event is done playing
* @param {Number} time The time of the event in seconds
* @private
*/
Tone.Event.prototype._tick = function (time) {
if (!this.mute && this._state.getStateAtTime(Tone.Transport.ticks) === Tone.State.Started) {
if (this.probability < 1 && Math.random() > this.probability) {
return;
}
if (this.humanize) {
var variation = 0.02;
if (!this.isBoolean(this.humanize)) {
variation = this.toSeconds(this.humanize);
}
time += (Math.random() * 2 - 1) * variation;
}
this.callback(time, this.value);
}
};
/**
* Get the duration of the loop.
* @return {Ticks}
* @private
*/
Tone.Event.prototype._getLoopDuration = function () {
return Math.round((this._loopEnd - this._loopStart) / this._playbackRate);
};
/**
* If the note should loop or not
* between Tone.Event.loopStart and
* Tone.Event.loopEnd. An integer
* value corresponds to the number of
* loops the Event does after it starts.
* @memberOf Tone.Event#
* @type {Boolean|Positive}
* @name loop
*/
Object.defineProperty(Tone.Event.prototype, 'loop', {
get: function () {
return this._loop;
},
set: function (loop) {
this._loop = loop;
this._rescheduleEvents();
}
});
/**
* The playback rate of the note. Defaults to 1.
* @memberOf Tone.Event#
* @type {Positive}
* @name playbackRate
* @example
* note.loop = true;
* //repeat the note twice as fast
* note.playbackRate = 2;
*/
Object.defineProperty(Tone.Event.prototype, 'playbackRate', {
get: function () {
return this._playbackRate;
},
set: function (rate) {
this._playbackRate = rate;
this._rescheduleEvents();
}
});
/**
* The loopEnd point is the time the event will loop.
* Note: only loops if Tone.Event.loop is true.
* @memberOf Tone.Event#
* @type {Boolean|Positive}
* @name loopEnd
*/
Object.defineProperty(Tone.Event.prototype, 'loopEnd', {
get: function () {
return this.toNotation(this._loopEnd + 'i');
},
set: function (loopEnd) {
this._loopEnd = this.toTicks(loopEnd);
if (this._loop) {
this._rescheduleEvents();
}
}
});
/**
* The time when the loop should start.
* @memberOf Tone.Event#
* @type {Boolean|Positive}
* @name loopStart
*/
Object.defineProperty(Tone.Event.prototype, 'loopStart', {
get: function () {
return this.toNotation(this._loopStart + 'i');
},
set: function (loopStart) {
this._loopStart = this.toTicks(loopStart);
if (this._loop) {
this._rescheduleEvents();
}
}
});
/**
* The current progress of the loop interval.
* Returns 0 if the event is not started yet or
* it is not set to loop.
* @memberOf Tone.Event#
* @type {NormalRange}
* @name progress
* @readOnly
*/
Object.defineProperty(Tone.Event.prototype, 'progress', {
get: function () {
if (this._loop) {
var ticks = Tone.Transport.ticks;
var lastEvent = this._state.getEvent(ticks);
if (lastEvent !== null && lastEvent.state === Tone.State.Started) {
var loopDuration = this._getLoopDuration();
var progress = (ticks - lastEvent.time) % loopDuration;
return progress / loopDuration;
} else {
return 0;
}
} else {
return 0;
}
}
});
/**
* Clean up
* @return {Tone.Event} this
*/
Tone.Event.prototype.dispose = function () {
this.cancel();
this._state.dispose();
this._state = null;
this.callback = null;
this.value = null;
};
return Tone.Event;
});
Module(function (Tone) {
/**
* @class Tone.Loop creates a looped callback at the
* specified interval. The callback can be
* started, stopped and scheduled along
* the Transport's timeline.
* @example
* var loop = new Tone.Loop(function(time){
* //triggered every eighth note.
* console.log(time);
* }, "8n").start(0);
* Tone.Transport.start();
* @extends {Tone}
* @param {Function} callback The callback to invoke with the
* event.
* @param {Array} events The events to arpeggiate over.
*/
Tone.Loop = function () {
var options = this.optionsObject(arguments, [
'callback',
'interval'
], Tone.Loop.defaults);
/**
* The event which produces the callbacks
*/
this._event = new Tone.Event({
'callback': this._tick.bind(this),
'loop': true,
'loopEnd': options.interval,
'playbackRate': options.playbackRate,
'probability': options.probability
});
/**
* The callback to invoke with the next event in the pattern
* @type {Function}
*/
this.callback = options.callback;
//set the iterations
this.iterations = options.iterations;
};
Tone.extend(Tone.Loop);
/**
* The defaults
* @const
* @type {Object}
*/
Tone.Loop.defaults = {
'interval': '4n',
'callback': Tone.noOp,
'playbackRate': 1,
'iterations': Infinity,
'probability': true,
'mute': false
};
/**
* Start the loop at the specified time along the Transport's
* timeline.
* @param {Time=} time When to start the Loop.
* @return {Tone.Loop} this
*/
Tone.Loop.prototype.start = function (time) {
this._event.start(time);
return this;
};
/**
* Stop the loop at the given time.
* @param {Time=} time When to stop the Arpeggio
* @return {Tone.Loop} this
*/
Tone.Loop.prototype.stop = function (time) {
this._event.stop(time);
return this;
};
/**
* Cancel all scheduled events greater than or equal to the given time
* @param {Time} [time=0] The time after which events will be cancel.
* @return {Tone.Loop} this
*/
Tone.Loop.prototype.cancel = function (time) {
this._event.cancel(time);
return this;
};
/**
* Internal function called when the notes should be called
* @param {Number} time The time the event occurs
* @private
*/
Tone.Loop.prototype._tick = function (time) {
this.callback(time);
};
/**
* The state of the Loop, either started or stopped.
* @memberOf Tone.Loop#
* @type {String}
* @name state
* @readOnly
*/
Object.defineProperty(Tone.Loop.prototype, 'state', {
get: function () {
return this._event.state;
}
});
/**
* The progress of the loop as a value between 0-1. 0, when
* the loop is stopped or done iterating.
* @memberOf Tone.Loop#
* @type {NormalRange}
* @name progress
* @readOnly
*/
Object.defineProperty(Tone.Loop.prototype, 'progress', {
get: function () {
return this._event.progress;
}
});
/**
* The time between successive callbacks.
* @example
* loop.interval = "8n"; //loop every 8n
* @memberOf Tone.Loop#
* @type {Time}
* @name interval
*/
Object.defineProperty(Tone.Loop.prototype, 'interval', {
get: function () {
return this._event.loopEnd;
},
set: function (interval) {
this._event.loopEnd = interval;
}
});
/**
* The playback rate of the loop. The normal playback rate is 1 (no change).
* A `playbackRate` of 2 would be twice as fast.
* @memberOf Tone.Loop#
* @type {Time}
* @name playbackRate
*/
Object.defineProperty(Tone.Loop.prototype, 'playbackRate', {
get: function () {
return this._event.playbackRate;
},
set: function (rate) {
this._event.playbackRate = rate;
}
});
/**
* Random variation +/-0.01s to the scheduled time.
* Or give it a time value which it will randomize by.
* @type {Boolean|Time}
* @memberOf Tone.Loop#
* @name humanize
*/
Object.defineProperty(Tone.Loop.prototype, 'humanize', {
get: function () {
return this._event.humanize;
},
set: function (variation) {
this._event.humanize = variation;
}
});
/**
* The probably of the callback being invoked.
* @memberOf Tone.Loop#
* @type {NormalRange}
* @name probability
*/
Object.defineProperty(Tone.Loop.prototype, 'probability', {
get: function () {
return this._event.probability;
},
set: function (prob) {
this._event.probability = prob;
}
});
/**
* Muting the Loop means that no callbacks are invoked.
* @memberOf Tone.Loop#
* @type {Boolean}
* @name mute
*/
Object.defineProperty(Tone.Loop.prototype, 'mute', {
get: function () {
return this._event.mute;
},
set: function (mute) {
this._event.mute = mute;
}
});
/**
* The number of iterations of the loop. The default
* value is Infinity (loop forever).
* @memberOf Tone.Loop#
* @type {Positive}
* @name iterations
*/
Object.defineProperty(Tone.Loop.prototype, 'iterations', {
get: function () {
if (this._event.loop === true) {
return Infinity;
} else {
return this._event.loop;
}
return this._pattern.index;
},
set: function (iters) {
if (iters === Infinity) {
this._event.loop = true;
} else {
this._event.loop = iters;
}
}
});
/**
* Clean up
* @return {Tone.Loop} this
*/
Tone.Loop.prototype.dispose = function () {
this._event.dispose();
this._event = null;
this.callback = null;
};
return Tone.Loop;
});
Module(function (Tone) {
/**
* @class Tone.Part is a collection Tone.Events which can be
* started/stoped and looped as a single unit.
*
* @extends {Tone.Event}
* @param {Function} callback The callback to invoke on each event
* @param {Array} events the array of events
* @example
* var part = new Tone.Part(function(time, note){
* //the notes given as the second element in the array
* //will be passed in as the second argument
* synth.triggerAttackRelease(note, "8n", time);
* }, [[0, "C2"], ["0:2", "C3"], ["0:3:2", "G2"]]);
* @example
* //use an array of objects as long as the object has a "time" attribute
* var part = new Tone.Part(function(time, value){
* //the value is an object which contains both the note and the velocity
* synth.triggerAttackRelease(value.note, "8n", time, value.velocity);
* }, [{"time" : 0, "note" : "C3", "velocity": 0.9},
* {"time" : "0:2", "note" : "C4", "velocity": 0.5}
* ]).start(0);
*/
Tone.Part = function () {
var options = this.optionsObject(arguments, [
'callback',
'events'
], Tone.Part.defaults);
/**
* If the part is looping or not
* @type {Boolean|Positive}
* @private
*/
this._loop = options.loop;
/**
* When the note is scheduled to start.
* @type {Ticks}
* @private
*/
this._loopStart = this.toTicks(options.loopStart);
/**
* When the note is scheduled to start.
* @type {Ticks}
* @private
*/
this._loopEnd = this.toTicks(options.loopEnd);
/**
* The playback rate of the part
* @type {Positive}
* @private
*/
this._playbackRate = options.playbackRate;
/**
* private holder of probability value
* @type {NormalRange}
* @private
*/
this._probability = options.probability;
/**
* the amount of variation from the
* given time.
* @type {Boolean|Time}
* @private
*/
this._humanize = options.humanize;
/**
* The start offset
* @type {Ticks}
* @private
*/
this._startOffset = 0;
/**
* Keeps track of the current state
* @type {Tone.TimelineState}
* @private
*/
this._state = new Tone.TimelineState(Tone.State.Stopped);
/**
* An array of Objects.
* @type {Array}
* @private
*/
this._events = [];
/**
* The callback to invoke at all the scheduled events.
* @type {Function}
*/
this.callback = options.callback;
/**
* If mute is true, the callback won't be
* invoked.
* @type {Boolean}
*/
this.mute = options.mute;
//add the events
var events = this.defaultArg(options.events, []);
if (!this.isUndef(options.events)) {
for (var i = 0; i < events.length; i++) {
if (Array.isArray(events[i])) {
this.add(events[i][0], events[i][1]);
} else {
this.add(events[i]);
}
}
}
};
Tone.extend(Tone.Part, Tone.Event);
/**
* The default values
* @type {Object}
* @const
*/
Tone.Part.defaults = {
'callback': Tone.noOp,
'loop': false,
'loopEnd': '1m',
'loopStart': 0,
'playbackRate': 1,
'probability': 1,
'humanize': false,
'mute': false
};
/**
* Start the part at the given time.
* @param {Time} time When to start the part.
* @param {Time=} offset The offset from the start of the part
* to begin playing at.
* @return {Tone.Part} this
*/
Tone.Part.prototype.start = function (time, offset) {
var ticks = this.toTicks(time);
if (this._state.getStateAtTime(ticks) !== Tone.State.Started) {
offset = this.defaultArg(offset, 0);
offset = this.toTicks(offset);
this._state.addEvent({
'state': Tone.State.Started,
'time': ticks,
'offset': offset
});
this._forEach(function (event) {
this._startNote(event, ticks, offset);
});
}
return this;
};
/**
* Start the event in the given event at the correct time given
* the ticks and offset and looping.
* @param {Tone.Event} event
* @param {Ticks} ticks
* @param {Ticks} offset
* @private
*/
Tone.Part.prototype._startNote = function (event, ticks, offset) {
ticks -= offset;
if (this._loop) {
if (event.startOffset >= this._loopStart && event.startOffset < this._loopEnd) {
if (event.startOffset < offset) {
//start it on the next loop
ticks += this._getLoopDuration();
}
event.start(ticks + 'i');
}
} else {
if (event.startOffset >= offset) {
event.start(ticks + 'i');
}
}
};
/**
* The start from the scheduled start time
* @type {Ticks}
* @memberOf Tone.Part#
* @name startOffset
* @private
*/
Object.defineProperty(Tone.Part.prototype, 'startOffset', {
get: function () {
return this._startOffset;
},
set: function (offset) {
this._startOffset = offset;
this._forEach(function (event) {
event.startOffset += this._startOffset;
});
}
});
/**
* Stop the part at the given time.
* @param {Time} time When to stop the part.
* @return {Tone.Part} this
*/
Tone.Part.prototype.stop = function (time) {
var ticks = this.toTicks(time);
if (this._state.getStateAtTime(ticks) === Tone.State.Started) {
this._state.setStateAtTime(Tone.State.Stopped, ticks);
this._forEach(function (event) {
event.stop(time);
});
}
return this;
};
/**
* Get/Set an Event's value at the given time.
* If a value is passed in and no event exists at
* the given time, one will be created with that value.
* If two events are at the same time, the first one will
* be returned.
* @example
* part.at("1m"); //returns the part at the first measure
*
* part.at("2m", "C2"); //set the value at "2m" to C2.
* //if an event didn't exist at that time, it will be created.
* @param {Time} time the time of the event to get or set
* @param {*=} value If a value is passed in, the value of the
* event at the given time will be set to it.
* @return {Tone.Event} the event at the time
*/
Tone.Part.prototype.at = function (time, value) {
time = this.toTicks(time);
var tickTime = this.ticksToSeconds(1);
for (var i = 0; i < this._events.length; i++) {
var event = this._events[i];
if (Math.abs(time - event.startOffset) < tickTime) {
if (!this.isUndef(value)) {
event.value = value;
}
return event;
}
}
//if there was no event at that time, create one
if (!this.isUndef(value)) {
this.add(time + 'i', value);
//return the new event
return this._events[this._events.length - 1];
} else {
return null;
}
};
/**
* Add a an event to the part.
* @param {Time} time The time the note should start.
* If an object is passed in, it should
* have a 'time' attribute and the rest
* of the object will be used as the 'value'.
* @param {Tone.Event|*} value
* @returns {Tone.Part} this
* @example
* part.add("1m", "C#+11");
*/
Tone.Part.prototype.add = function (time, value) {
//extract the parameters
if (this.isObject(time) && time.hasOwnProperty('time')) {
value = time;
time = value.time;
delete value.time;
}
time = this.toTicks(time);
var event;
if (value instanceof Tone.Event) {
event = value;
event.callback = this._tick.bind(this);
} else {
event = new Tone.Event({
'callback': this._tick.bind(this),
'value': value
});
}
//the start offset
event.startOffset = time;
//initialize the values
event.set({
'loopEnd': this.loopEnd,
'loopStart': this.loopStart,
'loop': this.loop,
'humanize': this.humanize,
'playbackRate': this.playbackRate,
'probability': this.probability
});
this._events.push(event);
//start the note if it should be played right now
this._restartEvent(event);
return this;
};
/**
* Restart the given event
* @param {Tone.Event} event
* @private
*/
Tone.Part.prototype._restartEvent = function (event) {
var stateEvent = this._state.getEvent(this.now());
if (stateEvent && stateEvent.state === Tone.State.Started) {
this._startNote(event, stateEvent.time, stateEvent.offset);
}
};
/**
* Remove an event from the part. Will recursively iterate
* into nested parts to find the event.
* @param {Time} time The time of the event
* @param {*} value Optionally select only a specific event value
*/
Tone.Part.prototype.remove = function (time, value) {
//extract the parameters
if (this.isObject(time) && time.hasOwnProperty('time')) {
value = time;
time = value.time;
}
time = this.toTicks(time);
for (var i = this._events.length - 1; i >= 0; i--) {
var event = this._events[i];
if (event instanceof Tone.Part) {
event.remove(time, value);
} else {
if (event.startOffset === time) {
if (this.isUndef(value) || !this.isUndef(value) && event.value === value) {
this._events.splice(i, 1);
event.dispose();
}
}
}
}
return this;
};
/**
* Remove all of the notes from the group.
* @return {Tone.Part} this
*/
Tone.Part.prototype.removeAll = function () {
this._forEach(function (event) {
event.dispose();
});
this._events = [];
return this;
};
/**
* Cancel scheduled state change events: i.e. "start" and "stop".
* @param {Time} after The time after which to cancel the scheduled events.
* @return {Tone.Part} this
*/
Tone.Part.prototype.cancel = function (after) {
this._forEach(function (event) {
event.cancel(after);
});
this._state.cancel(after);
return this;
};
/**
* Iterate over all of the events
* @param {Function} callback
* @param {Object} ctx The context
* @private
*/
Tone.Part.prototype._forEach = function (callback, ctx) {
ctx = this.defaultArg(ctx, this);
for (var i = this._events.length - 1; i >= 0; i--) {
var e = this._events[i];
if (e instanceof Tone.Part) {
e._forEach(callback, ctx);
} else {
callback.call(ctx, e);
}
}
return this;
};
/**
* Set the attribute of all of the events
* @param {String} attr the attribute to set
* @param {*} value The value to set it to
* @private
*/
Tone.Part.prototype._setAll = function (attr, value) {
this._forEach(function (event) {
event[attr] = value;
});
};
/**
* Internal tick method
* @param {Number} time The time of the event in seconds
* @private
*/
Tone.Part.prototype._tick = function (time, value) {
if (!this.mute) {
this.callback(time, value);
}
};
/**
* Determine if the event should be currently looping
* given the loop boundries of this Part.
* @param {Tone.Event} event The event to test
* @private
*/
Tone.Part.prototype._testLoopBoundries = function (event) {
if (event.startOffset < this._loopStart || event.startOffset >= this._loopEnd) {
event.cancel();
} else {
//reschedule it if it's stopped
if (event.state === Tone.State.Stopped) {
this._restartEvent(event);
}
}
};
/**
* The probability of the notes being triggered.
* @memberOf Tone.Part#
* @type {NormalRange}
* @name probability
*/
Object.defineProperty(Tone.Part.prototype, 'probability', {
get: function () {
return this._probability;
},
set: function (prob) {
this._probability = prob;
this._setAll('probability', prob);
}
});
/**
* If set to true, will apply small random variation
* to the callback time. If the value is given as a time, it will randomize
* by that amount.
* @example
* event.humanize = true;
* @type {Boolean|Time}
* @name humanize
*/
Object.defineProperty(Tone.Part.prototype, 'humanize', {
get: function () {
return this._humanize;
},
set: function (variation) {
this._humanize = variation;
this._setAll('humanize', variation);
}
});
/**
* If the part should loop or not
* between Tone.Part.loopStart and
* Tone.Part.loopEnd. An integer
* value corresponds to the number of
* loops the Part does after it starts.
* @memberOf Tone.Part#
* @type {Boolean|Positive}
* @name loop
* @example
* //loop the part 8 times
* part.loop = 8;
*/
Object.defineProperty(Tone.Part.prototype, 'loop', {
get: function () {
return this._loop;
},
set: function (loop) {
this._loop = loop;
this._forEach(function (event) {
event._loopStart = this._loopStart;
event._loopEnd = this._loopEnd;
event.loop = loop;
this._testLoopBoundries(event);
});
}
});
/**
* The loopEnd point determines when it will
* loop if Tone.Part.loop is true.
* @memberOf Tone.Part#
* @type {Boolean|Positive}
* @name loopEnd
*/
Object.defineProperty(Tone.Part.prototype, 'loopEnd', {
get: function () {
return this.toNotation(this._loopEnd + 'i');
},
set: function (loopEnd) {
this._loopEnd = this.toTicks(loopEnd);
if (this._loop) {
this._forEach(function (event) {
event.loopEnd = this.loopEnd;
this._testLoopBoundries(event);
});
}
}
});
/**
* The loopStart point determines when it will
* loop if Tone.Part.loop is true.
* @memberOf Tone.Part#
* @type {Boolean|Positive}
* @name loopStart
*/
Object.defineProperty(Tone.Part.prototype, 'loopStart', {
get: function () {
return this.toNotation(this._loopStart + 'i');
},
set: function (loopStart) {
this._loopStart = this.toTicks(loopStart);
if (this._loop) {
this._forEach(function (event) {
event.loopStart = this.loopStart;
this._testLoopBoundries(event);
});
}
}
});
/**
* The playback rate of the part
* @memberOf Tone.Part#
* @type {Positive}
* @name playbackRate
*/
Object.defineProperty(Tone.Part.prototype, 'playbackRate', {
get: function () {
return this._playbackRate;
},
set: function (rate) {
this._playbackRate = rate;
this._setAll('playbackRate', rate);
}
});
/**
* The number of scheduled notes in the part.
* @memberOf Tone.Part#
* @type {Positive}
* @name length
* @readOnly
*/
Object.defineProperty(Tone.Part.prototype, 'length', {
get: function () {
return this._events.length;
}
});
/**
* Clean up
* @return {Tone.Part} this
*/
Tone.Part.prototype.dispose = function () {
this.removeAll();
this._state.dispose();
this._state = null;
this.callback = null;
this._events = null;
return this;
};
return Tone.Part;
});
Module(function (Tone) {
/**
* @class Tone.Pattern arpeggiates between the given notes
* in a number of patterns. See Tone.CtrlPattern for
* a full list of patterns.
* @example
* var pattern = new Tone.Pattern(function(time, note){
* //the order of the notes passed in depends on the pattern
* }, ["C2", "D4", "E5", "A6"], "upDown");
* @extends {Tone.Loop}
* @param {Function} callback The callback to invoke with the
* event.
* @param {Array} events The events to arpeggiate over.
*/
Tone.Pattern = function () {
var options = this.optionsObject(arguments, [
'callback',
'events',
'pattern'
], Tone.Pattern.defaults);
Tone.Loop.call(this, options);
/**
* The pattern manager
* @type {Tone.CtrlPattern}
* @private
*/
this._pattern = new Tone.CtrlPattern({
'values': options.events,
'type': options.pattern,
'index': options.index
});
};
Tone.extend(Tone.Pattern, Tone.Loop);
/**
* The defaults
* @const
* @type {Object}
*/
Tone.Pattern.defaults = {
'pattern': Tone.CtrlPattern.Type.Up,
'events': []
};
/**
* Internal function called when the notes should be called
* @param {Number} time The time the event occurs
* @private
*/
Tone.Pattern.prototype._tick = function (time) {
this.callback(time, this._pattern.value);
this._pattern.next();
};
/**
* The current index in the events array.
* @memberOf Tone.Pattern#
* @type {Positive}
* @name index
*/
Object.defineProperty(Tone.Pattern.prototype, 'index', {
get: function () {
return this._pattern.index;
},
set: function (i) {
this._pattern.index = i;
}
});
/**
* The array of events.
* @memberOf Tone.Pattern#
* @type {Array}
* @name events
*/
Object.defineProperty(Tone.Pattern.prototype, 'events', {
get: function () {
return this._pattern.values;
},
set: function (vals) {
this._pattern.values = vals;
}
});
/**
* The current value of the pattern.
* @memberOf Tone.Pattern#
* @type {*}
* @name value
* @readOnly
*/
Object.defineProperty(Tone.Pattern.prototype, 'value', {
get: function () {
return this._pattern.value;
}
});
/**
* The pattern type. See Tone.CtrlPattern for the full list of patterns.
* @memberOf Tone.Pattern#
* @type {String}
* @name pattern
*/
Object.defineProperty(Tone.Pattern.prototype, 'pattern', {
get: function () {
return this._pattern.type;
},
set: function (pattern) {
this._pattern.type = pattern;
}
});
/**
* Clean up
* @return {Tone.Pattern} this
*/
Tone.Pattern.prototype.dispose = function () {
Tone.Loop.prototype.dispose.call(this);
this._pattern.dispose();
this._pattern = null;
};
return Tone.Pattern;
});
Module(function (Tone) {
/**
* @class A sequence is an alternate notation of a part. Instead
* of passing in an array of [time, event] pairs, pass
* in an array of events which will be spaced at the
* given subdivision. Sub-arrays will subdivide that beat
* by the number of items are in the array.
* Sequence notation inspiration from [Tidal](http://yaxu.org/tidal/)
* @param {Function} callback The callback to invoke with every note
* @param {Array} events The sequence
* @param {Time} subdivision The subdivision between which events are placed.
* @extends {Tone.Part}
* @example
* var seq = new Tone.Sequence(function(time, note){
* console.log(note);
* //straight quater notes
* }, ["C4", "E4", "G4", "A4"], "4n");
* @example
* var seq = new Tone.Sequence(function(time, note){
* console.log(note);
* //subdivisions are given as subarrays
* }, ["C4", ["E4", "D4", "E4"], "G4", ["A4", "G4"]]);
*/
Tone.Sequence = function () {
var options = this.optionsObject(arguments, [
'callback',
'events',
'subdivision'
], Tone.Sequence.defaults);
//remove the events
var events = options.events;
delete options.events;
Tone.Part.call(this, options);
/**
* The subdivison of each note
* @type {Ticks}
* @private
*/
this._subdivision = this.toTicks(options.subdivision);
//if no time was passed in, the loop end is the end of the cycle
if (this.isUndef(options.loopEnd) && !this.isUndef(events)) {
this._loopEnd = events.length * this._subdivision;
}
//defaults to looping
this._loop = true;
//add all of the events
if (!this.isUndef(events)) {
for (var i = 0; i < events.length; i++) {
this.add(i, events[i]);
}
}
};
Tone.extend(Tone.Sequence, Tone.Part);
/**
* The default values.
* @type {Object}
*/
Tone.Sequence.defaults = { 'subdivision': '4n' };
/**
* The subdivision of the sequence. This can only be
* set in the constructor. The subdivision is the
* interval between successive steps.
* @type {Time}
* @memberOf Tone.Sequence#
* @name subdivision
* @readOnly
*/
Object.defineProperty(Tone.Sequence.prototype, 'subdivision', {
get: function () {
return this.toNotation(this._subdivision + 'i');
}
});
/**
* Get/Set an index of the sequence. If the index contains a subarray,
* a Tone.Sequence representing that sub-array will be returned.
* @example
* var sequence = new Tone.Sequence(playNote, ["E4", "C4", "F#4", ["A4", "Bb3"]])
* sequence.at(0)// => returns "E4"
* //set a value
* sequence.at(0, "G3");
* //get a nested sequence
* sequence.at(3).at(1)// => returns "Bb3"
* @param {Positive} index The index to get or set
* @param {*} value Optionally pass in the value to set at the given index.
*/
Tone.Sequence.prototype.at = function (index, value) {
//if the value is an array,
if (this.isArray(value)) {
//remove the current event at that index
this.remove(index);
}
//call the parent's method
return Tone.Part.prototype.at.call(this, this._indexTime(index), value);
};
/**
* Add an event at an index, if there's already something
* at that index, overwrite it. If `value` is an array,
* it will be parsed as a subsequence.
* @param {Number} index The index to add the event to
* @param {*} value The value to add at that index
* @returns {Tone.Sequence} this
*/
Tone.Sequence.prototype.add = function (index, value) {
if (value === null) {
return this;
}
if (this.isArray(value)) {
//make a subsequence and add that to the sequence
var subSubdivision = Math.round(this._subdivision / value.length) + 'i';
value = new Tone.Sequence(this._tick.bind(this), value, subSubdivision);
}
Tone.Part.prototype.add.call(this, this._indexTime(index), value);
return this;
};
/**
* Remove a value from the sequence by index
* @param {Number} index The index of the event to remove
* @returns {Tone.Sequence} this
*/
Tone.Sequence.prototype.remove = function (index, value) {
Tone.Part.prototype.remove.call(this, this._indexTime(index), value);
return this;
};
/**
* Get the time of the index given the Sequence's subdivision
* @param {Number} index
* @return {Time} The time of that index
* @private
*/
Tone.Sequence.prototype._indexTime = function (index) {
if (this.isTicks(index)) {
return index;
} else {
return index * this._subdivision + this.startOffset + 'i';
}
};
/**
* Clean up.
* @return {Tone.Sequence} this
*/
Tone.Sequence.prototype.dispose = function () {
Tone.Part.prototype.dispose.call(this);
return this;
};
return Tone.Sequence;
});
Module(function (Tone) {
/**
* @class Tone.PulseOscillator is a pulse oscillator with control over pulse width,
* also known as the duty cycle. At 50% duty cycle (width = 0.5) the wave is
* a square and only odd-numbered harmonics are present. At all other widths
* even-numbered harmonics are present. Read more
* [here](https://wigglewave.wordpress.com/2014/08/16/pulse-waveforms-and-harmonics/).
*
* @constructor
* @extends {Tone.Oscillator}
* @param {Frequency} [frequency] The frequency of the oscillator
* @param {NormalRange} [width] The width of the pulse
* @example
* var pulse = new Tone.PulseOscillator("E5", 0.4).toMaster().start();
*/
Tone.PulseOscillator = function () {
var options = this.optionsObject(arguments, [
'frequency',
'width'
], Tone.Oscillator.defaults);
Tone.Source.call(this, options);
/**
* The width of the pulse.
* @type {NormalRange}
* @signal
*/
this.width = new Tone.Signal(options.width, Tone.Type.NormalRange);
/**
* gate the width amount
* @type {GainNode}
* @private
*/
this._widthGate = this.context.createGain();
/**
* the sawtooth oscillator
* @type {Tone.Oscillator}
* @private
*/
this._sawtooth = new Tone.Oscillator({
frequency: options.frequency,
detune: options.detune,
type: 'sawtooth',
phase: options.phase
});
/**
* The frequency control.
* @type {Frequency}
* @signal
*/
this.frequency = this._sawtooth.frequency;
/**
* The detune in cents.
* @type {Cents}
* @signal
*/
this.detune = this._sawtooth.detune;
/**
* Threshold the signal to turn it into a square
* @type {Tone.WaveShaper}
* @private
*/
this._thresh = new Tone.WaveShaper(function (val) {
if (val < 0) {
return -1;
} else {
return 1;
}
});
//connections
this._sawtooth.chain(this._thresh, this.output);
this.width.chain(this._widthGate, this._thresh);
this._readOnly([
'width',
'frequency',
'detune'
]);
};
Tone.extend(Tone.PulseOscillator, Tone.Oscillator);
/**
* The default parameters.
* @static
* @const
* @type {Object}
*/
Tone.PulseOscillator.defaults = {
'frequency': 440,
'detune': 0,
'phase': 0,
'width': 0.2
};
/**
* start the oscillator
* @param {Time} time
* @private
*/
Tone.PulseOscillator.prototype._start = function (time) {
time = this.toSeconds(time);
this._sawtooth.start(time);
this._widthGate.gain.setValueAtTime(1, time);
};
/**
* stop the oscillator
* @param {Time} time
* @private
*/
Tone.PulseOscillator.prototype._stop = function (time) {
time = this.toSeconds(time);
this._sawtooth.stop(time);
//the width is still connected to the output.
//that needs to be stopped also
this._widthGate.gain.setValueAtTime(0, time);
};
/**
* The phase of the oscillator in degrees.
* @memberOf Tone.PulseOscillator#
* @type {Degrees}
* @name phase
*/
Object.defineProperty(Tone.PulseOscillator.prototype, 'phase', {
get: function () {
return this._sawtooth.phase;
},
set: function (phase) {
this._sawtooth.phase = phase;
}
});
/**
* The type of the oscillator. Always returns "pulse".
* @readOnly
* @memberOf Tone.PulseOscillator#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.PulseOscillator.prototype, 'type', {
get: function () {
return 'pulse';
}
});
/**
* The partials of the waveform. Cannot set partials for this waveform type
* @memberOf Tone.PulseOscillator#
* @type {Array}
* @name partials
* @private
*/
Object.defineProperty(Tone.PulseOscillator.prototype, 'partials', {
get: function () {
return [];
}
});
/**
* Clean up method.
* @return {Tone.PulseOscillator} this
*/
Tone.PulseOscillator.prototype.dispose = function () {
Tone.Source.prototype.dispose.call(this);
this._sawtooth.dispose();
this._sawtooth = null;
this._writable([
'width',
'frequency',
'detune'
]);
this.width.dispose();
this.width = null;
this._widthGate.disconnect();
this._widthGate = null;
this._widthGate = null;
this._thresh.disconnect();
this._thresh = null;
this.frequency = null;
this.detune = null;
return this;
};
return Tone.PulseOscillator;
});
Module(function (Tone) {
/**
* @class Tone.PWMOscillator modulates the width of a Tone.PulseOscillator
* at the modulationFrequency. This has the effect of continuously
* changing the timbre of the oscillator by altering the harmonics
* generated.
*
* @extends {Tone.Oscillator}
* @constructor
* @param {Frequency} frequency The starting frequency of the oscillator.
* @param {Frequency} modulationFrequency The modulation frequency of the width of the pulse.
* @example
* var pwm = new Tone.PWMOscillator("Ab3", 0.3).toMaster().start();
*/
Tone.PWMOscillator = function () {
var options = this.optionsObject(arguments, [
'frequency',
'modulationFrequency'
], Tone.PWMOscillator.defaults);
Tone.Source.call(this, options);
/**
* the pulse oscillator
* @type {Tone.PulseOscillator}
* @private
*/
this._pulse = new Tone.PulseOscillator(options.modulationFrequency);
//change the pulse oscillator type
this._pulse._sawtooth.type = 'sine';
/**
* the modulator
* @type {Tone.Oscillator}
* @private
*/
this._modulator = new Tone.Oscillator({
'frequency': options.frequency,
'detune': options.detune,
'phase': options.phase
});
/**
* Scale the oscillator so it doesn't go silent
* at the extreme values.
* @type {Tone.Multiply}
* @private
*/
this._scale = new Tone.Multiply(1.01);
/**
* The frequency control.
* @type {Frequency}
* @signal
*/
this.frequency = this._modulator.frequency;
/**
* The detune of the oscillator.
* @type {Cents}
* @signal
*/
this.detune = this._modulator.detune;
/**
* The modulation rate of the oscillator.
* @type {Frequency}
* @signal
*/
this.modulationFrequency = this._pulse.frequency;
//connections
this._modulator.chain(this._scale, this._pulse.width);
this._pulse.connect(this.output);
this._readOnly([
'modulationFrequency',
'frequency',
'detune'
]);
};
Tone.extend(Tone.PWMOscillator, Tone.Oscillator);
/**
* default values
* @static
* @type {Object}
* @const
*/
Tone.PWMOscillator.defaults = {
'frequency': 440,
'detune': 0,
'phase': 0,
'modulationFrequency': 0.4
};
/**
* start the oscillator
* @param {Time} [time=now]
* @private
*/
Tone.PWMOscillator.prototype._start = function (time) {
time = this.toSeconds(time);
this._modulator.start(time);
this._pulse.start(time);
};
/**
* stop the oscillator
* @param {Time} time (optional) timing parameter
* @private
*/
Tone.PWMOscillator.prototype._stop = function (time) {
time = this.toSeconds(time);
this._modulator.stop(time);
this._pulse.stop(time);
};
/**
* The type of the oscillator. Always returns "pwm".
* @readOnly
* @memberOf Tone.PWMOscillator#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.PWMOscillator.prototype, 'type', {
get: function () {
return 'pwm';
}
});
/**
* The partials of the waveform. Cannot set partials for this waveform type
* @memberOf Tone.PWMOscillator#
* @type {Array}
* @name partials
* @private
*/
Object.defineProperty(Tone.PWMOscillator.prototype, 'partials', {
get: function () {
return [];
}
});
/**
* The phase of the oscillator in degrees.
* @memberOf Tone.PWMOscillator#
* @type {number}
* @name phase
*/
Object.defineProperty(Tone.PWMOscillator.prototype, 'phase', {
get: function () {
return this._modulator.phase;
},
set: function (phase) {
this._modulator.phase = phase;
}
});
/**
* Clean up.
* @return {Tone.PWMOscillator} this
*/
Tone.PWMOscillator.prototype.dispose = function () {
Tone.Source.prototype.dispose.call(this);
this._pulse.dispose();
this._pulse = null;
this._scale.dispose();
this._scale = null;
this._modulator.dispose();
this._modulator = null;
this._writable([
'modulationFrequency',
'frequency',
'detune'
]);
this.frequency = null;
this.detune = null;
this.modulationFrequency = null;
return this;
};
return Tone.PWMOscillator;
});
Module(function (Tone) {
/**
* @class Tone.OmniOscillator aggregates Tone.Oscillator, Tone.PulseOscillator,
* and Tone.PWMOscillator into one class, allowing it to have the
* types: sine, square, triangle, sawtooth, pulse or pwm. Additionally,
* OmniOscillator is capable of setting the first x number of partials
* of the oscillator. For example: "sine4" would set be the first 4
* partials of the sine wave and "triangle8" would set the first
* 8 partials of the triangle wave.
*
* @extends {Tone.Oscillator}
* @constructor
* @param {Frequency} frequency The initial frequency of the oscillator.
* @param {string} type The type of the oscillator.
* @example
* var omniOsc = new Tone.OmniOscillator("C#4", "pwm");
*/
Tone.OmniOscillator = function () {
var options = this.optionsObject(arguments, [
'frequency',
'type'
], Tone.OmniOscillator.defaults);
Tone.Source.call(this, options);
/**
* The frequency control.
* @type {Frequency}
* @signal
*/
this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
/**
* The detune control
* @type {Cents}
* @signal
*/
this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);
/**
* the type of the oscillator source
* @type {string}
* @private
*/
this._sourceType = undefined;
/**
* the oscillator
* @type {Tone.Oscillator|Tone.PWMOscillator|Tone.PulseOscillator}
* @private
*/
this._oscillator = null;
//set the oscillator
this.type = options.type;
this.phase = options.phase;
this._readOnly([
'frequency',
'detune'
]);
if (this.isArray(options.partials)) {
this.partials = options.partials;
}
};
Tone.extend(Tone.OmniOscillator, Tone.Oscillator);
/**
* default values
* @static
* @type {Object}
* @const
*/
Tone.OmniOscillator.defaults = {
'frequency': 440,
'detune': 0,
'type': 'sine',
'phase': 0,
'width': 0.4,
//only applies if the oscillator is set to "pulse",
'modulationFrequency': 0.4
};
/**
* @enum {string}
* @private
*/
var OmniOscType = {
PulseOscillator: 'PulseOscillator',
PWMOscillator: 'PWMOscillator',
Oscillator: 'Oscillator'
};
/**
* start the oscillator
* @param {Time} [time=now] the time to start the oscillator
* @private
*/
Tone.OmniOscillator.prototype._start = function (time) {
this._oscillator.start(time);
};
/**
* start the oscillator
* @param {Time} [time=now] the time to start the oscillator
* @private
*/
Tone.OmniOscillator.prototype._stop = function (time) {
this._oscillator.stop(time);
};
/**
* The type of the oscillator. sine, square, triangle, sawtooth, pwm, or pulse.
* @memberOf Tone.OmniOscillator#
* @type {string}
* @name type
*/
Object.defineProperty(Tone.OmniOscillator.prototype, 'type', {
get: function () {
return this._oscillator.type;
},
set: function (type) {
if (type.indexOf('sine') === 0 || type.indexOf('square') === 0 || type.indexOf('triangle') === 0 || type.indexOf('sawtooth') === 0 || type === Tone.Oscillator.Type.Custom) {
if (this._sourceType !== OmniOscType.Oscillator) {
this._sourceType = OmniOscType.Oscillator;
this._createNewOscillator(Tone.Oscillator);
}
this._oscillator.type = type;
} else if (type === 'pwm') {
if (this._sourceType !== OmniOscType.PWMOscillator) {
this._sourceType = OmniOscType.PWMOscillator;
this._createNewOscillator(Tone.PWMOscillator);
}
} else if (type === 'pulse') {
if (this._sourceType !== OmniOscType.PulseOscillator) {
this._sourceType = OmniOscType.PulseOscillator;
this._createNewOscillator(Tone.PulseOscillator);
}
} else {
throw new Error('Tone.OmniOscillator does not support type ' + type);
}
}
});
/**
* The partials of the waveform. A partial represents
* the amplitude at a harmonic. The first harmonic is the
* fundamental frequency, the second is the octave and so on
* following the harmonic series.
* Setting this value will automatically set the type to "custom".
* The value is an empty array when the type is not "custom".
* @memberOf Tone.OmniOscillator#
* @type {Array}
* @name partials
* @example
* osc.partials = [1, 0.2, 0.01];
*/
Object.defineProperty(Tone.OmniOscillator.prototype, 'partials', {
get: function () {
return this._oscillator.partials;
},
set: function (partials) {
if (this._sourceType !== OmniOscType.Oscillator) {
this.type = Tone.Oscillator.Type.Custom;
}
this._oscillator.partials = partials;
}
});
/**
* connect the oscillator to the frequency and detune signals
* @private
*/
Tone.OmniOscillator.prototype._createNewOscillator = function (OscillatorConstructor) {
//short delay to avoid clicks on the change
var now = this.now() + this.blockTime;
if (this._oscillator !== null) {
var oldOsc = this._oscillator;
oldOsc.stop(now);
//dispose the old one
setTimeout(function () {
oldOsc.dispose();
oldOsc = null;
}, this.blockTime * 1000);
}
this._oscillator = new OscillatorConstructor();
this.frequency.connect(this._oscillator.frequency);
this.detune.connect(this._oscillator.detune);
this._oscillator.connect(this.output);
if (this.state === Tone.State.Started) {
this._oscillator.start(now);
}
};
/**
* The phase of the oscillator in degrees.
* @memberOf Tone.OmniOscillator#
* @type {Degrees}
* @name phase
*/
Object.defineProperty(Tone.OmniOscillator.prototype, 'phase', {
get: function () {
return this._oscillator.phase;
},
set: function (phase) {
this._oscillator.phase = phase;
}
});
/**
* The width of the oscillator (only if the oscillator is set to pulse)
* @memberOf Tone.OmniOscillator#
* @type {NormalRange}
* @signal
* @name width
* @example
* var omniOsc = new Tone.OmniOscillator(440, "pulse");
* //can access the width attribute only if type === "pulse"
* omniOsc.width.value = 0.2;
*/
Object.defineProperty(Tone.OmniOscillator.prototype, 'width', {
get: function () {
if (this._sourceType === OmniOscType.PulseOscillator) {
return this._oscillator.width;
}
}
});
/**
* The modulationFrequency Signal of the oscillator
* (only if the oscillator type is set to pwm).
* @memberOf Tone.OmniOscillator#
* @type {Frequency}
* @signal
* @name modulationFrequency
* @example
* var omniOsc = new Tone.OmniOscillator(440, "pwm");
* //can access the modulationFrequency attribute only if type === "pwm"
* omniOsc.modulationFrequency.value = 0.2;
*/
Object.defineProperty(Tone.OmniOscillator.prototype, 'modulationFrequency', {
get: function () {
if (this._sourceType === OmniOscType.PWMOscillator) {
return this._oscillator.modulationFrequency;
}
}
});
/**
* Clean up.
* @return {Tone.OmniOscillator} this
*/
Tone.OmniOscillator.prototype.dispose = function () {
Tone.Source.prototype.dispose.call(this);
this._writable([
'frequency',
'detune'
]);
this.detune.dispose();
this.detune = null;
this.frequency.dispose();
this.frequency = null;
this._oscillator.dispose();
this._oscillator = null;
this._sourceType = null;
return this;
};
return Tone.OmniOscillator;
});
Module(function (Tone) {
/**
* @class Base-class for all instruments
*
* @constructor
* @extends {Tone}
*/
Tone.Instrument = function (options) {
//get the defaults
options = this.defaultArg(options, Tone.Instrument.defaults);
/**
* The output and volume triming node
* @type {Tone.Volume}
* @private
*/
this._volume = this.output = new Tone.Volume(options.volume);
/**
* The volume of the output in decibels.
* @type {Decibels}
* @signal
* @example
* source.volume.value = -6;
*/
this.volume = this._volume.volume;
this._readOnly('volume');
};
Tone.extend(Tone.Instrument);
/**
* the default attributes
* @type {object}
*/
Tone.Instrument.defaults = {
/** the volume of the output in decibels */
'volume': 0
};
/**
* @abstract
* @param {string|number} note the note to trigger
* @param {Time} [time=now] the time to trigger the ntoe
* @param {number} [velocity=1] the velocity to trigger the note
*/
Tone.Instrument.prototype.triggerAttack = Tone.noOp;
/**
* @abstract
* @param {Time} [time=now] when to trigger the release
*/
Tone.Instrument.prototype.triggerRelease = Tone.noOp;
/**
* Trigger the attack and then the release after the duration.
* @param {Frequency} note The note to trigger.
* @param {Time} duration How long the note should be held for before
* triggering the release.
* @param {Time} [time=now] When the note should be triggered.
* @param {NormalRange} [velocity=1] The velocity the note should be triggered at.
* @returns {Tone.Instrument} this
* @example
* //trigger "C4" for the duration of an 8th note
* synth.triggerAttackRelease("C4", "8n");
*/
Tone.Instrument.prototype.triggerAttackRelease = function (note, duration, time, velocity) {
time = this.toSeconds(time);
duration = this.toSeconds(duration);
this.triggerAttack(note, time, velocity);
this.triggerRelease(time + duration);
return this;
};
/**
* clean up
* @returns {Tone.Instrument} this
*/
Tone.Instrument.prototype.dispose = function () {
Tone.prototype.dispose.call(this);
this._volume.dispose();
this._volume = null;
this._writable(['volume']);
this.volume = null;
return this;
};
return Tone.Instrument;
});
Module(function (Tone) {
/**
* @class This is an abstract base class for other monophonic instruments to
* extend. IMPORTANT: It does not make any sound on its own and
* shouldn't be directly instantiated.
*
* @constructor
* @abstract
* @extends {Tone.Instrument}
*/
Tone.Monophonic = function (options) {
//get the defaults
options = this.defaultArg(options, Tone.Monophonic.defaults);
Tone.Instrument.call(this, options);
/**
* The glide time between notes.
* @type {Time}
*/
this.portamento = options.portamento;
};
Tone.extend(Tone.Monophonic, Tone.Instrument);
/**
* @static
* @const
* @type {Object}
*/
Tone.Monophonic.defaults = { 'portamento': 0 };
/**
* Trigger the attack of the note optionally with a given velocity.
*
*
* @param {Frequency} note The note to trigger.
* @param {Time} [time=now] When the note should start.
* @param {number} [velocity=1] velocity The velocity scaler
* determines how "loud" the note
* will be triggered.
* @returns {Tone.Monophonic} this
* @example
* synth.triggerAttack("C4");
* @example
* //trigger the note a half second from now at half velocity
* synth.triggerAttack("C4", "+0.5", 0.5);
*/
Tone.Monophonic.prototype.triggerAttack = function (note, time, velocity) {
time = this.toSeconds(time);
this._triggerEnvelopeAttack(time, velocity);
this.setNote(note, time);
return this;
};
/**
* Trigger the release portion of the envelope
* @param {Time} [time=now] If no time is given, the release happens immediatly
* @returns {Tone.Monophonic} this
* @example
* synth.triggerRelease();
*/
Tone.Monophonic.prototype.triggerRelease = function (time) {
this._triggerEnvelopeRelease(time);
return this;
};
/**
* override this method with the actual method
* @abstract
* @private
*/
Tone.Monophonic.prototype._triggerEnvelopeAttack = function () {
};
/**
* override this method with the actual method
* @abstract
* @private
*/
Tone.Monophonic.prototype._triggerEnvelopeRelease = function () {
};
/**
* Set the note at the given time. If no time is given, the note
* will set immediately.
* @param {Frequency} note The note to change to.
* @param {Time} [time=now] The time when the note should be set.
* @returns {Tone.Monophonic} this
* @example
* //change to F#6 in one quarter note from now.
* synth.setNote("F#6", "+4n");
* @example
* //change to Bb4 right now
* synth.setNote("Bb4");
*/
Tone.Monophonic.prototype.setNote = function (note, time) {
time = this.toSeconds(time);
if (this.portamento > 0) {
var currentNote = this.frequency.value;
this.frequency.setValueAtTime(currentNote, time);
var portTime = this.toSeconds(this.portamento);
this.frequency.exponentialRampToValueAtTime(note, time + portTime);
} else {
this.frequency.setValueAtTime(note, time);
}
return this;
};
return Tone.Monophonic;
});
Module(function (Tone) {
/**
* @class Tone.MonoSynth is composed of one oscillator, one filter, and two envelopes.
* The amplitude of the Tone.Oscillator and the cutoff frequency of the
* Tone.Filter are controlled by Tone.Envelopes.
* <img src="https://docs.google.com/drawings/d/1gaY1DF9_Hzkodqf8JI1Cg2VZfwSElpFQfI94IQwad38/pub?w=924&h=240">
*
* @constructor
* @extends {Tone.Monophonic}
* @param {Object} [options] the options available for the synth
* see defaults below
* @example
* var synth = new Tone.MonoSynth({
* "oscillator" : {
* "type" : "square"
* },
* "envelope" : {
* "attack" : 0.1
* }
* }).toMaster();
* synth.triggerAttackRelease("C4", "8n");
*/
Tone.MonoSynth = function (options) {
//get the defaults
options = this.defaultArg(options, Tone.MonoSynth.defaults);
Tone.Monophonic.call(this, options);
/**
* The oscillator.
* @type {Tone.OmniOscillator}
*/
this.oscillator = new Tone.OmniOscillator(options.oscillator);
/**
* The frequency control.
* @type {Frequency}
* @signal
*/
this.frequency = this.oscillator.frequency;
/**
* The detune control.
* @type {Cents}
* @signal
*/
this.detune = this.oscillator.detune;
/**
* The filter.
* @type {Tone.Filter}
*/
this.filter = new Tone.Filter(options.filter);
/**
* The filter envelope.
* @type {Tone.FrequencyEnvelope}
*/
this.filterEnvelope = new Tone.FrequencyEnvelope(options.filterEnvelope);
/**
* The amplitude envelope.
* @type {Tone.AmplitudeEnvelope}
*/
this.envelope = new Tone.AmplitudeEnvelope(options.envelope);
//connect the oscillators to the output
this.oscillator.chain(this.filter, this.envelope, this.output);
//start the oscillators
this.oscillator.start();
//connect the filter envelope
this.filterEnvelope.connect(this.filter.frequency);
this._readOnly([
'oscillator',
'frequency',
'detune',
'filter',
'filterEnvelope',
'envelope'
]);
};
Tone.extend(Tone.MonoSynth, Tone.Monophonic);
/**
* @const
* @static
* @type {Object}
*/
Tone.MonoSynth.defaults = {
'frequency': 'C4',
'detune': 0,
'oscillator': { 'type': 'square' },
'filter': {
'Q': 6,
'type': 'lowpass',
'rolloff': -24
},
'envelope': {
'attack': 0.005,
'decay': 0.1,
'sustain': 0.9,
'release': 1
},
'filterEnvelope': {
'attack': 0.06,
'decay': 0.2,
'sustain': 0.5,
'release': 2,
'baseFrequency': 200,
'octaves': 7,
'exponent': 2
}
};
/**
* start the attack portion of the envelope
* @param {Time} [time=now] the time the attack should start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment