diff --git a/Gruntfile.js b/Gruntfile.js index 10a8a985..92911303 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -70,7 +70,7 @@ module.exports = function(grunt) { include: ['src/app'], onBuildWrite: function( name, path, contents ) { if (path.indexOf('node_modules/tone/') > -1) { - return '/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/\n' + + return '/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/\n' + require('amdclean').clean({ 'code': contents.replace(/console.log(.*);/g, ''), 'escodegen': { @@ -103,6 +103,7 @@ module.exports = function(grunt) { out: 'lib/p5.sound.js', paths: { 'Tone' : 'node_modules/tone/Tone', + 'automation-timeline': 'node_modules/web-audio-automation-timeline/build/automation-timeline-amd', 'panner' : 'src/panner', 'sndcore': 'src/sndcore', 'master': 'src/master', diff --git a/examples/DelayNoiseEnvelope/sketch.js b/examples/DelayNoiseEnvelope/sketch.js index c4b4ba30..4aea241e 100644 --- a/examples/DelayNoiseEnvelope/sketch.js +++ b/examples/DelayNoiseEnvelope/sketch.js @@ -22,9 +22,10 @@ function setup() { delay = new p5.Delay(); delay.process(noise, .12, .7, 2300); // tell delay to process noise - // the Env accepts time / value pairs to - // create a series of timed fades - env = new p5.Env(.01, 1, .2, .1); + // the Env ADSR: attackTime, decayTime, sustainLevel, releaseTime + env = new p5.Env(); + env.setADSR(0.01, 0.2, 0.2, 0.1) + env.setRange(1, 0); // p5.Amplitude will analyze all sound in the sketch analyzer = new p5.Amplitude(); @@ -52,5 +53,5 @@ function draw() { } function mousePressed() { - env.play(noise); + env.play(noise, 0, 0.1, 0); } \ No newline at end of file diff --git a/examples/bells_envelope_test/assets/LadyChapelStAlbansCathedral.wav b/examples/bells_envelope_test/assets/LadyChapelStAlbansCathedral.wav new file mode 100755 index 00000000..228b3706 Binary files /dev/null and b/examples/bells_envelope_test/assets/LadyChapelStAlbansCathedral.wav differ diff --git a/examples/bells_envelope_test/index.html b/examples/bells_envelope_test/index.html new file mode 100755 index 00000000..a60e707c --- /dev/null +++ b/examples/bells_envelope_test/index.html @@ -0,0 +1,16 @@ + + + + + bells_envelope_test + + + + + + + + + + + diff --git a/examples/bells_envelope_test/sketch.js b/examples/bells_envelope_test/sketch.js new file mode 100755 index 00000000..78d079da --- /dev/null +++ b/examples/bells_envelope_test/sketch.js @@ -0,0 +1,142 @@ + +// This example shows a more complex use of the .ramp function for the envelope. +// You can use it to make a simple attack/decay envelope for struck or plucked style notes. +// Here, we're creating synthetic bells using additive synthesis, and triggering each of their attacks and decays differently to make different harmonics last for different times. +// Have fun! - Jeff Snyder +var osc = []; +var envelope = []; +var fft; +var myPhraseAttack, myPhraseRelease, myPart; +var atPattern = [1, 1,1,1,0,1,1,1,1,0,0,0,0]; // this rhythmic pattern puts some rests in there +var patternArray = [0,1,2,3,3,2,0,1]; // pattern of the notes (in terms of array indices from scaleArray) +var scaleArray = [64, 60, 62, 55]; // classic bell tune +var harmonicsArray = [.5, 1., 1.183, 1.506, 2., 2.514, 2.662, 3.011, 4.166, 5.433, 6.796, 8.215]; // bell partials taken from https://en.wikipedia.org/wiki/Strike_tone +var idealArray = [.5, 1., 1.2, 1.5, 2, 2.5, 2.6667, 3.0, 4.0, 5.3333, 6.6667, 8.0]; // ideal bell partials +var note = 0; +var startPoint = 0; +var endPoint = 0; +var numWaveforms = 100; +var numOsc = 12; // reduce this to reduce the number of overtones, 4 makes a nice, dark gamelan sound +var numNotes = 4; +var rawImpulse; +var cVerb; +var oscVols = []; +var firstNote = 1; +var pitchRatio = .8; //change this to transpose things around +var pitchDeviation = .001; +var idealOrReal = 0; // change this to 1 to change to an ideal bell instead of a measured bell +var maxAttack = .001; // in seconds ... setting to .001 makes things very percussive, setting to > 1 makes them sound far away +var maxDecay = 9.0; // in seconds ... short times make for deader bells +var percentWashed = 0.0; +var washedMax = 4; + + +function preload() +{ + // create a p5.Convolver + cVerb = createConvolver('assets/LadyChapelStAlbansCathedral.wav'); + +} + +function setup() +{ + createCanvas(1000, 400); + rawImpulse = loadSound('assets/' + cVerb.impulses[0].name); + + for (var i = 0; i < numNotes; i++) + { + // make the arrays into 2D arrays + osc[i] = []; + envelope[i] = []; + oscVols[i] = []; + var midiValue = scaleArray[i]; + var freqValue = midiToFreq(midiValue); + + for(var j = 0; j < numOsc; j++) + { + // make arrays of sine waves for each note, additive synthesis, and assign independent envelopes, amplitudes, and slight detunings for each harmonic + osc[i][j] = new p5.SinOsc(); + envelope[i][j] = new p5.Env(); + if (random(0, 1) > percentWashed) + { + myMaxAttack = maxAttack; + print("normal"); + } + else + { + myMaxAttack = washedMax; + print("washed"); + } + envelope[i][j].setADSR(random(.001, myMaxAttack), random(.01, maxDecay)); // turning sustain level to 0. makes an AD envelope + osc[i][j].amp(0.); + oscVols[i][j] = random(.01, .3); + if (idealOrReal == 0) + { + var myOvertone = harmonicsArray[j]; + } + else + { + var myOvertone = idealArray[j]; + } + osc[i][j].freq(freqValue * harmonicsArray[j] * random(1.0 - pitchDeviation, 1 + pitchDeviation) * pitchRatio); + osc[i][j].start(); + osc[i][j].disconnect(); + //put 'em through that reverb, ahhhhhh yeah it's like a New Age in here + cVerb.process(osc[i][j]); + } + } + myPhraseAttack = new p5.Phrase('testerAttack', makeSoundAttack, atPattern); + myPart = new p5.Part(); + myPart.addPhrase(myPhraseAttack); + myPart.setBPM(15); // super slow because it's in 16th notes + myPart.loop(); + myPart.start(); + fft = new p5.FFT(); // for the drawing of the waveform (just using the buffer part) + endPoint = width / numWaveforms; // for the drawing + background(20); +} + +function draw() +{ + background(0, 0, 0, 9); //to make the trails fade like on a scope :) + var waveform = fft.waveform(); // analyze the waveform + fft.analyze(); + beginShape(); + noFill(); + stroke(fft.getEnergy("bass") * 2.0, fft.getEnergy("mid")* 2.0, fft.getEnergy("treble") * 2.0); // the (* 2.0) is just to make the colors a little brighter + for (var i = 0; i < waveform.length; i++) + { + var x = map(i, 0, waveform.length, startPoint, endPoint); + var y = map(waveform[i], -.9, .9, height, 0); + vertex(x, y); + } + endShape(); + startPoint = endPoint + 1; + endPoint += (width / numWaveforms); + if (endPoint > width) + { + redrawWaveform(); + } +} + +function makeSoundAttack(time, playbackRate) +{ + var whichNote = patternArray[note]; + for (var i = 0; i < numOsc; i++) + { + envelope[whichNote][i].ramp(osc[whichNote][i], time, (oscVols[whichNote][i] * random(.8, 1.0)), 0); // the added randomness just makes each strike a little different. + } + note = (note + 1) % patternArray.length; + if (firstNote == 1) + { + setTimeout(redrawWaveform, time * 1000.0); // just so the drawing display starts at the left on the first note + } + firstNote = 0; +} + + +function redrawWaveform() +{ + startPoint = 0; + endPoint = (width / numWaveforms); +} diff --git a/examples/envAmpFreq/index.html b/examples/envAmpFreq/index.html new file mode 100644 index 00000000..2079ffdd --- /dev/null +++ b/examples/envAmpFreq/index.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + click to trigger amplitude and frequency envelopes + + \ No newline at end of file diff --git a/examples/envAmpFreq/sketch.js b/examples/envAmpFreq/sketch.js new file mode 100644 index 00000000..cc170881 --- /dev/null +++ b/examples/envAmpFreq/sketch.js @@ -0,0 +1,35 @@ +/** + * Control the level of an envelope + */ + +var env; // this is the env +var osc; // this oscillator will modulate the amplitude of the carrier +var freqEnv; // env for frequency + +function setup() { + env = new p5.Env(); + env.setADSR(0.01, 0.2, 0.2, 0.3); + env.setRange(0, 1); + + freqEnv = new p5.Env(); + freqEnv.setADSR(0.01, 0.2, 0.2, 0.3); + freqEnv.setRange(300, 5000); + + + osc = new p5.Oscillator(); // connects to master output by default + osc.start(0); + osc.freq(220); + // osc.freq(env.scale(0,1,800,300)); + osc.freq(freqEnv); + osc.amp(env); +} + +function mousePressed() { + env.triggerAttack(); + freqEnv.triggerAttack(); +} + +function mouseReleased() { + env.triggerRelease(); + freqEnv.triggerRelease(); +} \ No newline at end of file diff --git a/examples/envSignalMath/index.html b/examples/envExp/index.html similarity index 100% rename from examples/envSignalMath/index.html rename to examples/envExp/index.html diff --git a/examples/envExp/sketch.js b/examples/envExp/sketch.js new file mode 100755 index 00000000..34aefe7d --- /dev/null +++ b/examples/envExp/sketch.js @@ -0,0 +1,118 @@ +/** + * @name Note Envelope + * @description

An Envelope is a series of fades, defined + * as time / value pairs. In this example, the envelope + * will be used to "play" a note by controlling the output + * amplitude of an oscillator.

+ * The p5.Oscillator sends its output through + * an internal Web Audio GainNode (p5.Oscillator.output). + * By default, that node has a constant value of 0.5. It can + * be reset with the osc.amp() method. Or, in this example, an + * Envelope takes control of that node, turning the amplitude + * up and down like a volume knob.

+ *

To run this example locally, you will need the + * p5.sound library and a + * sound file.

+ */ +var osc, envelope, fft; +var myPhraseAttack, myPhraseRelease, myPart; +var atPattern = [1, 0]; +var relPattern = [0, 1]; +var scaleArray = [60, 62, 64, 65, 67, 69, 71, 72]; +var note = 0; +var expOrNot = 1; +var startPoint = 0; +var endPoint = 0; +var numWaveforms = 50; + +var audioContext; + +function setup() { + createCanvas(710, 200); + osc = new p5.SinOsc(); + + audioContext = getAudioContext(); + + // Instantiate the envelope with time / value pairs + envelope = new p5.Env(0.1, 0.5, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0); + osc.amp(0.); + osc.start(); + myPhraseAttack = new p5.Phrase('testerAttack', makeSoundAttack, atPattern); + myPhraseRelease = new p5.Phrase('testerRelease', makeSoundRelease, relPattern); + myPart = new p5.Part(); + myPart.addPhrase(myPhraseAttack); + //myPart.addPhrase(myPhraseRelease); + myPart.setBPM(120); + myPart.loop(); + myPart.start(); + fft = new p5.FFT(); + fft.setInput(osc); + masterVolume(0); + endPoint = width / numWaveforms; + noStroke(); + background(20); +} + +function draw() { + + var waveform = fft.waveform(); // analyze the waveform + beginShape(); + strokeWeight(5); + for (var i = 0; i < waveform.length; i++){ + var x = map(i, 0, waveform.length, startPoint, endPoint); + var y = map(waveform[i], -1, 1, height, 0); + vertex(x, y); + } + endShape(); + startPoint = endPoint + 1; + endPoint += (width / numWaveforms); + if (endPoint > width) + { + background(20); + startPoint = 0; + endPoint = (width / numWaveforms); + } + + +} + + +function makeSoundAttack(time, playbackRate) +{ + var midiValue = scaleArray[note]; + var freqValue = midiToFreq(midiValue); + + if (note == 0) + { + // if (expOrNot == 0) + // { + // envelope.setExp(true); + // expOrNot = 1; + // } + // else + // { + // envelope.setExp(false); + // expOrNot = 0; + // } + } + + osc.freq(freqValue * 2, 0, time); + // envelope.play(osc, time); + envelope.triggerAttack(osc, time); + //envelope.triggerRelease(osc); + note = (note + 1) % scaleArray.length; + setTimeout(redrawWaveform, time * 1000.0); + +} + +function makeSoundRelease(time, playbackRate) +{ + envelope.triggerRelease(osc, time); +} + +function redrawWaveform() +{ + background(20); + startPoint = 0; + endPoint = (width / numWaveforms); +} diff --git a/examples/envSignalMath/sketch.js b/examples/envSignalMath/sketch.js deleted file mode 100644 index bff0301b..00000000 --- a/examples/envSignalMath/sketch.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Control the level of an envelope with math - */ - -var env; // this is the oscillator we will hear -var osc; // this oscillator will modulate the amplitude of the carrier - -function setup() { - env = new p5.Env(0.01, 1, 0.5, 0.8, 0.3,0.2); - - osc = new p5.Oscillator(); // connects to master output by default - osc.start(0); - osc.freq(1); - osc.freq(env.scale(0,1,800,300)); - osc.amp(env); -} - -function mousePressed() { - env.triggerAttack(osc); -} - -function mouseReleased() { - env.triggerRelease(osc); -} \ No newline at end of file diff --git a/examples/envelope/sketch.js b/examples/envelope/sketch.js index ef33a024..4102c5f1 100644 --- a/examples/envelope/sketch.js +++ b/examples/envelope/sketch.js @@ -2,15 +2,15 @@ /* This sketch shows how to use envelopes and oscillators. Envelopes are pre-defined amplitude -distribution over time. The sound library provides an ASR envelope which stands for attach, -sustain, release. The amplitude rises then sustains at the maximum level and decays slowly -depending on pre defined time segments. +distribution over time. The sound library provides an ADSR envelope which stands for attack, +decay, sustain, release. The amplitude rises then decays to a sustain level, then decays slowly +toward the release value. - .________ - . --- - . --- - . --- - A S R + . + . . _______ + . --- + . --- + A D S R */ @@ -19,13 +19,13 @@ var env; var a; // Times and levels for the ASR envelope -var attackTime = 0.01; -var attackLevel = 0.7; +var attackTime = 0.001; +var attackLevel = 0.9; var decayTime = 0.3; -var decayLevel = 0.2; +var susPercent = 0.2; var sustainTime = 0.1; -var sustainLevel = decayLevel; var releaseTime = 0.5; +var releaseLevel = 0; var midiSequence = [ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72 ]; var duration = 1000; @@ -36,8 +36,8 @@ var trigger; var note = 0; function setup(){ - createCanvas(600, 600); - background(255); + createCanvas(600, 400); + fill(0, 255, 0); trigger = millis(); @@ -45,15 +45,16 @@ function setup(){ triOsc.amp(0); triOsc.start(); - env = new p5.Env(attackTime, attackLevel, decayTime, decayLevel, sustainTime, sustainLevel, releaseTime); - fill(0); + env = new p5.Env(); + env.setADSR(attackTime, decayTime, susPercent, releaseTime); + env.setRange(attackLevel, releaseLevel); a = new p5.Amplitude(); } function draw(){ var size = 10; - background(255, 255,255,20); + background(20, 20, 20, 70); ellipse(map ( (trigger - millis()) % duration, 1000, 0, 0, width), map ( a.getLevel(), 0, .5, height-size, 0), size, size); // If the determined trigger moment in time matches up with the computer clock and we if the @@ -63,7 +64,8 @@ function draw(){ triOsc.freq(midiToFreq(midiSequence[note])); // The envelope gets triggered with the oscillator as input and the times and levels we defined earlier - env.play(triOsc); + // play accepts an object to play, time from now, and a sustain time—how long to hold before the release. + env.play(triOsc, 0, sustainTime); // Create the new trigger according to predefined durations and speed it up by deviding by 1.5 trigger = millis() + duration; diff --git a/examples/envelopeMultipleSources/sketch.js b/examples/envelopeMultipleSources/sketch.js index ce506e71..53dcc418 100644 --- a/examples/envelopeMultipleSources/sketch.js +++ b/examples/envelopeMultipleSources/sketch.js @@ -1,18 +1,18 @@ // Adapting Wilm Thoben's Envelope example from the Processing Handbook ex2 /* -This sketch shows how to use envelopes and oscillators. Envelopes are pre-defined amplitude -distribution over time. The sound library provides an ASR envelope which stands for attach, -sustain, release. The amplitude rises then sustains at the maximum level and decays slowly -depending on pre defined time segments. - - .________ - . --- - . --- - . --- - A S R - -In this example, the envelope controls two sources: a Pink Noise and a Triangle Oscillator +This sketch shows how to use envelopes to trigger multiple sources (in this case,noise and oscillator). + +Envelopes are pre-defined amplitude distribution over time. +The sound library provides an ADSR envelope which stands for attack, decay, sustain, release. +The amplitude rises then decays to a sustain level, then decays slowly toward the release value. + + . + . . _______ + . --- + . --- + A D S R + */ var triOsc; @@ -38,8 +38,8 @@ var trigger; var note = 0; function setup(){ - createCanvas(600, 600); - background(255); + createCanvas(600, 400); + fill(0, 255, 0); trigger = millis(); @@ -59,14 +59,13 @@ function setup(){ // triOsc.amp(env); env.setInput(noise, triOsc); - fill(0); a = new p5.Amplitude(); } function draw(){ var size = 10; - background(255, 255,255,20); + background(20, 20, 20, 70); ellipse(map ( (trigger - millis()) % duration, 1000, 0, 0, width), map ( a.getLevel(), 0, .3, height-size, 0), size, size); // If the determined trigger moment in time matches up with the computer clock and we if the @@ -94,9 +93,9 @@ function draw(){ function mouseClicked() { if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { if ( getMasterVolume() == 0) { - setMasterVolume(0.3, 0.5); + masterVolume(0.3, 0.5); } else { - setMasterVolume(0, 0.5); + masterVolume(0, 0.5); } } } \ No newline at end of file diff --git a/examples/envelopeOnOff/sketch.js b/examples/envelopeOnOff/sketch.js index 49f900ee..1afaa895 100644 --- a/examples/envelopeOnOff/sketch.js +++ b/examples/envelopeOnOff/sketch.js @@ -4,18 +4,18 @@ * Trigger the Release when the mouse is released. */ -var triOsc; +var osc; var env; var a; // Times and levels for the ADSR envelope var attackTime = 0.001; -var attackLevel = 0.9; -var decayTime = 0.25; -var decayLevel = 0.2; -var sustainTime = 0.1; -var sustainLevel = decayLevel; -var releaseTime = .8; +var attackLevel = 0.6; +var decayTime = 0.1; +var susPercent = 0.2; +var releaseTime = 0.5; +var releaseLevel = 0; + var duration = 1000; // Set the note trigger var trigger; @@ -25,17 +25,21 @@ var note = 0; function setup(){ - createCanvas(600, 600); - background(255); + createCanvas(600, 300); + background(20); + fill(0,255,0); trigger = millis(); - triOsc = new p5.TriOsc(); - triOsc.freq(220); - triOsc.start(); - env = new p5.Env(attackTime, attackLevel, decayTime, decayLevel, sustainTime, sustainLevel, releaseTime); - triOsc.amp(env); - fill(0); + osc = new p5.SinOsc(); + osc.freq(220); + osc.start(); + + env = new p5.Env(); + env.setADSR(attackTime, decayTime, susPercent, releaseTime); + env.setRange(attackLevel, releaseLevel); + + osc.amp(env); createP('click mouse to triggerAttack, release mouse to triggerRelease'); a = new p5.Amplitude(); @@ -43,14 +47,13 @@ function setup(){ function draw(){ var size = 10; - background(255, 255,255,20); + background(20, 20, 20, 70); ellipse( map ( (trigger - millis()) % duration, 1000, 0, 0, width) % width, map ( a.getLevel(), 0, .5, height-size, 0), size, size); } function mousePressed(){ - // The envelope gets triggered with the oscillator as input and the times and levels we defined earlier - env.triggerAttack(); - trigger = millis() + duration; + env.triggerAttack(); + trigger = millis() + duration; } function mouseReleased(){ diff --git a/examples/envelopeRamp/index.html b/examples/envelopeRamp/index.html new file mode 100755 index 00000000..41584b86 --- /dev/null +++ b/examples/envelopeRamp/index.html @@ -0,0 +1,18 @@ + + + + + envelope_ramp + + + + + + + + + + + + + diff --git a/examples/envelopeRamp/sketch.js b/examples/envelopeRamp/sketch.js new file mode 100755 index 00000000..8d390ce2 --- /dev/null +++ b/examples/envelopeRamp/sketch.js @@ -0,0 +1,68 @@ +var osc, envelope, fft; +var myPhraseAttack, myPhraseRelease, myPart; +var atPattern = [1, 0,0,0]; +var scaleArray = [60, 62, 64, 65, 67, 69, 71, 72]; +var note = 0; +var startPoint = 0; +var endPoint = 0; +var numWaveforms = 50; + +function setup() { + createCanvas(710, 200); + osc = new p5.SinOsc(); + envelope = new p5.Env(); + envelope.setADSR(.005,0.02); + osc.amp(0.); + osc.start(); + myPhraseAttack = new p5.Phrase('testerAttack', makeSoundAttack, atPattern); + myPart = new p5.Part(); + myPart.addPhrase(myPhraseAttack); + myPart.setBPM(240); + myPart.loop(); + myPart.start(); + fft = new p5.FFT(); + endPoint = width / numWaveforms; + noFill(); + background(20); +} + +function draw() { + + + var waveform = fft.waveform(); // analyze the waveform + beginShape(); + stroke(255, 255, 0); + for (var i = 0; i < waveform.length; i++){ + var x = map(i, 0, waveform.length, startPoint, endPoint); + var y = map(waveform[i], -1, 1, height, 0); + vertex(x, y); + } + endShape(); + startPoint = endPoint + 1; + endPoint += (width / numWaveforms); + if (endPoint > width) + { + background(20); + startPoint = 0; + endPoint = (width / numWaveforms); + } +} + + +function makeSoundAttack(time, playbackRate) +{ + var midiValue = scaleArray[note]; + var freqValue = midiToFreq(midiValue); + osc.freq(freqValue * 2, .001, time); + envelope.ramp(osc, time, 1, 0); + note = (note + 1) % scaleArray.length; + setTimeout(redrawWaveform, time * 1000.0); +} + + +function redrawWaveform() +{ + background(20); + startPoint = 0; + endPoint = (width / numWaveforms); +} diff --git a/examples/envelope_exponential_play/index.html b/examples/envelope_exponential_play/index.html new file mode 100755 index 00000000..d6246922 --- /dev/null +++ b/examples/envelope_exponential_play/index.html @@ -0,0 +1,16 @@ + + + + + envelope_exponential_play + + + + + + + + + + + diff --git a/examples/envelope_exponential_play/sketch.js b/examples/envelope_exponential_play/sketch.js new file mode 100755 index 00000000..9ddb42c6 --- /dev/null +++ b/examples/envelope_exponential_play/sketch.js @@ -0,0 +1,78 @@ +var osc, envelope, fft; +var myPhraseAttack, myPhraseRelease, myPart; +var atPattern = [1, 0,0,0]; +var relPattern = [0, 0,1,0]; +var scaleArray = [60, 62, 64, 65, 67, 69, 71, 72]; +var note = 0; +var startPoint = 0; +var endPoint = 0; +var numWaveforms = 50; + +function setup() { + createCanvas(710, 200); + osc = new p5.SinOsc(); + envelope = new p5.Env(0.1, 1.0, 0.1, .5, .1, .5, .1, 0.0); // + envelope.setExp(true); + //envelope.setADSR(0.1, 1.0, 1.0, 0.2, 5.0, 0.0); //AT, AL, DT, SL, RT, RL + osc.amp(0.); + osc.start(); + myPhraseAttack = new p5.Phrase('testerAttack', makeSoundAttack, atPattern); + myPhraseRelease = new p5.Phrase('testerRelease', makeSoundRelease, relPattern); + myPart = new p5.Part(); + myPart.addPhrase(myPhraseAttack); + myPart.addPhrase(myPhraseRelease); // comment this back in to check release + myPart.setBPM(100); + myPart.loop(); + myPart.start(); + fft = new p5.FFT(); + endPoint = width / numWaveforms; + noFill(); + background(20); +} + +function draw() { + + + var waveform = fft.waveform(); // analyze the waveform + beginShape(); + stroke(255, 255, 0); + for (var i = 0; i < waveform.length; i++){ + var x = map(i, 0, waveform.length, startPoint, endPoint); + var y = map(waveform[i], -1, 1, height, 0); + vertex(x, y); + } + endShape(); + startPoint = endPoint + 1; + endPoint += (width / numWaveforms); + if (endPoint > width) + { + background(20); + startPoint = 0; + endPoint = (width / numWaveforms); + } +} + + +function makeSoundAttack(time, playbackRate) +{ + var midiValue = scaleArray[note]; + var freqValue = midiToFreq(midiValue); + osc.freq(freqValue * 2, .01, time); // comment this back in to check pitch changes + envelope.play(osc, time); + //envelope.triggerAttack(osc, time); + note = (note + 1) % scaleArray.length; + setTimeout(redrawWaveform, time * 1000.0); + +} + +function makeSoundRelease(time, playbackRate) +{ + //envelope.triggerRelease(osc, time); // comment this back in to check release +} + +function redrawWaveform() +{ + background(20); + startPoint = 0; + endPoint = (width / numWaveforms); +} diff --git a/examples/envelope_exponential_trig_rel/index.html b/examples/envelope_exponential_trig_rel/index.html new file mode 100755 index 00000000..069ae044 --- /dev/null +++ b/examples/envelope_exponential_trig_rel/index.html @@ -0,0 +1,16 @@ + + + + + envelope_exponential_trig_rel + + + + + + + + + + + diff --git a/examples/envelope_exponential_trig_rel/sketch.js b/examples/envelope_exponential_trig_rel/sketch.js new file mode 100755 index 00000000..f0688ada --- /dev/null +++ b/examples/envelope_exponential_trig_rel/sketch.js @@ -0,0 +1,77 @@ +var osc, envelope, fft; +var myPhraseAttack, myPhraseRelease, myPart; +var atPattern = [1, 0,0,0]; +var relPattern = [0, 0,1,0]; +var scaleArray = [60, 62, 64, 65, 67, 69, 71, 72]; +var note = 0; +var startPoint = 0; +var endPoint = 0; +var numWaveforms = 50; + +function setup() { + createCanvas(710, 200); + osc = new p5.SinOsc(); + envelope = new p5.Env(); + envelope.setExp(true); + envelope.setADSR(0.1, 1.0, .1, 0.2, .01, 0.0); //AT, AL, DT, SL, RT, RL + osc.amp(0.); + osc.start(); + myPhraseAttack = new p5.Phrase('testerAttack', makeSoundAttack, atPattern); + myPhraseRelease = new p5.Phrase('testerRelease', makeSoundRelease, relPattern); + myPart = new p5.Part(); + myPart.addPhrase(myPhraseAttack); + myPart.addPhrase(myPhraseRelease); // comment this back in to check release + myPart.setBPM(100); + myPart.loop(); + myPart.start(); + fft = new p5.FFT(); + endPoint = width / numWaveforms; + noFill(); + background(20); +} + +function draw() { + + + var waveform = fft.waveform(); // analyze the waveform + beginShape(); + stroke(255, 255, 0); + for (var i = 0; i < waveform.length; i++){ + var x = map(i, 0, waveform.length, startPoint, endPoint); + var y = map(waveform[i], -1, 1, height, 0); + vertex(x, y); + } + endShape(); + startPoint = endPoint + 1; + endPoint += (width / numWaveforms); + if (endPoint > width) + { + background(20); + startPoint = 0; + endPoint = (width / numWaveforms); + } +} + + +function makeSoundAttack(time, playbackRate) +{ + var midiValue = scaleArray[note]; + var freqValue = midiToFreq(midiValue); + osc.freq(freqValue * 2, .01, time); // comment this back in to check pitch changes + envelope.triggerAttack(osc, time); + note = (note + 1) % scaleArray.length; + setTimeout(redrawWaveform, time * 1000.0); + +} + +function makeSoundRelease(time, playbackRate) +{ + envelope.triggerRelease(osc, time); // comment this back in to check release +} + +function redrawWaveform() +{ + background(20); + startPoint = 0; + endPoint = (width / numWaveforms); +} diff --git a/examples/loop_stepSequencer/sketch.js b/examples/loop_stepSequencer/sketch.js index fdcdc6a3..3725d439 100644 --- a/examples/loop_stepSequencer/sketch.js +++ b/examples/loop_stepSequencer/sketch.js @@ -31,7 +31,6 @@ function setup() { // set tempo (Beats Per Minute) of the part and tell it to loop part.setBPM(80); part.loop(); - } function playKick(time, params) { diff --git a/lib/p5.sound.js b/lib/p5.sound.js index e4bc8153..349be07f 100644 --- a/lib/p5.sound.js +++ b/lib/p5.sound.js @@ -1,4 +1,4 @@ -/*! p5.sound.js v0.2.17 2016-01-18 */ +/*! p5.sound.js v0.3.0 2016-01-31 */ (function (root, factory) { if (typeof define === 'function' && define.amd) define('p5.sound', ['p5'], function (p5) { (factory(p5));}); @@ -2786,6 +2786,87 @@ fft = function () { var x = this.getEnergy(freq1, freq2); return x; }; + /** + * Returns the + * + * spectral centroid of the input signal. + * NOTE: analyze() must be called prior to getCentroid(). Analyze() + * tells the FFT to analyze frequency data, and getCentroid() uses + * the results determine the spectral centroid.

+ * + * @method getCentroid + * @return {Number} Spectral Centroid Frequency Frequency of the spectral centroid in Hz. + * + * + * @example + *
+ * + * + *function setup(){ + * cnv = createCanvas(800,400); + * sound = new p5.AudioIn(); + * sound.start(); + * fft = new p5.FFT(); + * sound.connect(fft); + *} + * + * + *function draw(){ + * + * var centroidplot = 0.0; + * var spectralCentroid = 0; + * + * + * background(0); + * stroke(0,255,0); + * var spectrum = fft.analyze(); + * fill(0,255,0); // spectrum is green + * + * //draw the spectrum + * + * for (var i = 0; i< spectrum.length; i++){ + * var x = map(log(i), 0, log(spectrum.length), 0, width); + * var h = map(spectrum[i], 0, 255, 0, height); + * var rectangle_width = (log(i+1)-log(i))*(width/log(spectrum.length)); + * rect(x, height, rectangle_width, -h ) + * } + + * var nyquist = 22050; + * + * // get the centroid + * spectralCentroid = fft.getCentroid(); + * + * // the mean_freq_index calculation is for the display. + * var mean_freq_index = spectralCentroid/(nyquist/spectrum.length); + * + * centroidplot = map(log(mean_freq_index), 0, log(spectrum.length), 0, width); + * + * + * stroke(255,0,0); // the line showing where the centroid is will be red + * + * rect(centroidplot, 0, width / spectrum.length, height) + * noStroke(); + * fill(255,255,255); // text is white + * textSize(40); + * text("centroid: "+round(spectralCentroid)+" Hz", 10, 40); + *} + *
+ */ + p5.FFT.prototype.getCentroid = function () { + var nyquist = p5sound.audiocontext.sampleRate / 2; + var cumulative_sum = 0; + var centroid_normalization = 0; + for (var i = 0; i < this.freqDomain.length; i++) { + cumulative_sum += i * this.freqDomain[i]; + centroid_normalization += this.freqDomain[i]; + } + var mean_freq_index = 0; + if (centroid_normalization != 0) { + mean_freq_index = cumulative_sum / centroid_normalization; + } + var spec_centroid_freq = mean_freq_index * (nyquist / this.freqDomain.length); + return spec_centroid_freq; + }; /** * Smooth FFT analysis by averaging with the last analysis frame. * @@ -2828,13 +2909,16 @@ fft = function () { } }; }(master); -/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/ +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ var Tone_core_Tone; Tone_core_Tone = function () { 'use strict'; function isUndef(val) { return val === void 0; } + function isFunction(val) { + return typeof val === 'function'; + } var audioContext; if (isUndef(window.AudioContext)) { window.AudioContext = window.webkitAudioContext; @@ -2847,55 +2931,53 @@ Tone_core_Tone = function () { } else { throw new Error('Web Audio is not supported in this browser'); } - if (typeof AudioContext.prototype.createGain !== 'function') { + if (!isFunction(AudioContext.prototype.createGain)) { AudioContext.prototype.createGain = AudioContext.prototype.createGainNode; } - if (typeof AudioContext.prototype.createDelay !== 'function') { + if (!isFunction(AudioContext.prototype.createDelay)) { AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode; } - if (typeof AudioContext.prototype.createPeriodicWave !== 'function') { + if (!isFunction(AudioContext.prototype.createPeriodicWave)) { AudioContext.prototype.createPeriodicWave = AudioContext.prototype.createWaveTable; } - if (typeof AudioBufferSourceNode.prototype.start !== 'function') { + if (!isFunction(AudioBufferSourceNode.prototype.start)) { AudioBufferSourceNode.prototype.start = AudioBufferSourceNode.prototype.noteGrainOn; } - if (typeof AudioBufferSourceNode.prototype.stop !== 'function') { + if (!isFunction(AudioBufferSourceNode.prototype.stop)) { AudioBufferSourceNode.prototype.stop = AudioBufferSourceNode.prototype.noteOff; } - if (typeof OscillatorNode.prototype.start !== 'function') { + if (!isFunction(OscillatorNode.prototype.start)) { OscillatorNode.prototype.start = OscillatorNode.prototype.noteOn; } - if (typeof OscillatorNode.prototype.stop !== 'function') { + if (!isFunction(OscillatorNode.prototype.stop)) { OscillatorNode.prototype.stop = OscillatorNode.prototype.noteOff; } - if (typeof OscillatorNode.prototype.setPeriodicWave !== 'function') { + if (!isFunction(OscillatorNode.prototype.setPeriodicWave)) { OscillatorNode.prototype.setPeriodicWave = OscillatorNode.prototype.setWaveTable; } - if (!window.Tone) { - 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); + 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 { - 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); + 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); } - }; - } + } + }; var Tone = function (inputs, outputs) { if (isUndef(inputs) || inputs === 1) { this.input = this.context.createGain(); @@ -2908,10 +2990,139 @@ Tone_core_Tone = function () { this.output = new Array(inputs); } }; + 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; + }; + 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; + }; + 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); + for (var i = 0; i < superDefs.length; i++) { + if (ret.indexOf(superDefs[i]) === -1) { + ret.push(superDefs[i]); + } + } + } + return ret; + }; + 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'; + }; Tone.context = audioContext; Tone.prototype.context = Tone.context; Tone.prototype.bufferSize = 2048; - Tone.prototype.bufferTime = Tone.prototype.bufferSize / Tone.context.sampleRate; + Tone.prototype.blockTime = 128 / Tone.context.sampleRate; + 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; + }; + var _silentNode = null; + Tone.prototype.noGC = function () { + this.output.connect(_silentNode); + return this; + }; + AudioNode.prototype.noGC = function () { + this.connect(_silentNode); + return this; + }; Tone.prototype.connect = function (unit, outputNum, inputNum) { if (Array.isArray(this.output)) { outputNum = this.defaultArg(outputNum, 0); @@ -2919,6 +3130,7 @@ Tone_core_Tone = function () { } else { this.output.connect(unit, outputNum, inputNum); } + return this; }; Tone.prototype.disconnect = function (outputNum) { if (Array.isArray(this.output)) { @@ -2927,6 +3139,7 @@ Tone_core_Tone = function () { } else { this.output.disconnect(); } + return this; }; Tone.prototype.connectSeries = function () { if (arguments.length > 1) { @@ -2937,6 +3150,7 @@ Tone_core_Tone = function () { currentUnit = toUnit; } } + return this; }; Tone.prototype.connectParallel = function () { var connectFrom = arguments[0]; @@ -2946,6 +3160,7 @@ Tone_core_Tone = function () { connectFrom.connect(connectTo); } } + return this; }; Tone.prototype.chain = function () { if (arguments.length > 0) { @@ -2956,24 +3171,26 @@ Tone_core_Tone = function () { currentUnit = toUnit; } } + return this; }; Tone.prototype.fan = function () { if (arguments.length > 0) { - for (var i = 1; i < arguments.length; i++) { + for (var i = 0; i < arguments.length; i++) { this.connect(arguments[i]); } } + return this; }; AudioNode.prototype.chain = Tone.prototype.chain; AudioNode.prototype.fan = Tone.prototype.fan; Tone.prototype.defaultArg = function (given, fallback) { - if (typeof given === 'object' && typeof fallback === 'object') { + if (this.isObject(given) && this.isObject(fallback)) { var ret = {}; for (var givenProp in given) { - ret[givenProp] = this.defaultArg(given[givenProp], given[givenProp]); + ret[givenProp] = this.defaultArg(fallback[givenProp], given[givenProp]); } - for (var prop in fallback) { - ret[prop] = this.defaultArg(given[prop], fallback[prop]); + for (var fallbackProp in fallback) { + ret[fallbackProp] = this.defaultArg(given[fallbackProp], fallback[fallbackProp]); } return ret; } else { @@ -2982,7 +3199,7 @@ Tone_core_Tone = function () { }; Tone.prototype.optionsObject = function (values, keys, defaults) { var options = {}; - if (values.length === 1 && typeof values[0] === 'object') { + if (values.length === 1 && this.isObject(values[0])) { options = values[0]; } else { for (var i = 0; i < keys.length; i++) { @@ -2996,86 +3213,73 @@ Tone_core_Tone = function () { } }; Tone.prototype.isUndef = isUndef; - Tone.prototype.equalPowerScale = function (percent) { - var piFactor = 0.5 * Math.PI; - return Math.sin(percent * piFactor); + Tone.prototype.isFunction = isFunction; + Tone.prototype.isNumber = function (arg) { + return typeof arg === 'number'; }; - Tone.prototype.logScale = function (gain) { - return Math.max(this.normalize(this.gainToDb(gain), -100, 0), 0); + Tone.prototype.isObject = function (arg) { + return Object.prototype.toString.call(arg) === '[object Object]' && arg.constructor === Object; }; - Tone.prototype.expScale = function (gain) { - return this.dbToGain(this.interpolate(gain, -100, 0)); + Tone.prototype.isBoolean = function (arg) { + return typeof arg === 'boolean'; }; - Tone.prototype.dbToGain = function (db) { - return Math.pow(2, db / 6); + Tone.prototype.isArray = function (arg) { + return Array.isArray(arg); }; - Tone.prototype.gainToDb = function (gain) { - return 20 * (Math.log(gain) / Math.LN10); + Tone.prototype.isString = function (arg) { + return typeof arg === 'string'; }; - Tone.prototype.interpolate = function (input, outputMin, outputMax) { - return input * (outputMax - outputMin) + outputMin; + Tone.noOp = function () { }; - Tone.prototype.normalize = function (input, inputMin, inputMax) { - if (inputMin > inputMax) { - var tmp = inputMax; - inputMax = inputMin; - inputMin = tmp; - } else if (inputMin == inputMax) { - return 0; - } - return (input - inputMin) / (inputMax - inputMin); - }; - Tone.prototype.dispose = function () { - if (!this.isUndef(this.input)) { - if (this.input instanceof AudioNode) { - this.input.disconnect(); + Tone.prototype._readOnly = function (property) { + if (Array.isArray(property)) { + for (var i = 0; i < property.length; i++) { + this._readOnly(property[i]); } - this.input = null; + } else { + Object.defineProperty(this, property, { + writable: false, + enumerable: true + }); } - if (!this.isUndef(this.output)) { - if (this.output instanceof AudioNode) { - this.output.disconnect(); + }; + Tone.prototype._writable = function (property) { + if (Array.isArray(property)) { + for (var i = 0; i < property.length; i++) { + this._writable(property[i]); } - this.output = null; + } else { + Object.defineProperty(this, property, { writable: true }); } }; - var _silentNode = null; - Tone.prototype.noGC = function () { - this.output.connect(_silentNode); + Tone.State = { + Started: 'started', + Stopped: 'stopped', + Paused: 'paused' }; - AudioNode.prototype.noGC = function () { - this.connect(_silentNode); + Tone.prototype.equalPowerScale = function (percent) { + var piFactor = 0.5 * Math.PI; + return Math.sin(percent * piFactor); }; - Tone.prototype.now = function () { - return this.context.currentTime; + Tone.prototype.dbToGain = function (db) { + return Math.pow(2, db / 6); }; - Tone.prototype.samplesToSeconds = function (samples) { - return samples / this.context.sampleRate; + Tone.prototype.gainToDb = function (gain) { + return 20 * (Math.log(gain) / Math.LN10); }; - Tone.prototype.toSamples = function (time) { - var seconds = this.toSeconds(time); - return Math.round(seconds * this.context.sampleRate); + Tone.prototype.now = function () { + return this.context.currentTime; }; - Tone.prototype.toSeconds = function (time, now) { - now = this.defaultArg(now, this.now()); - if (typeof time === 'number') { - return time; - } else if (typeof time === 'string') { - var plusTime = 0; - if (time.charAt(0) === '+') { - time = time.slice(1); - plusTime = now; - } - return parseFloat(time) + plusTime; - } else { - return now; + Tone.extend = function (child, parent) { + if (isUndef(parent)) { + parent = Tone; } - }; - Tone.prototype.frequencyToSeconds = function (freq) { - return 1 / parseFloat(freq); - }; - Tone.prototype.secondsToFrequency = function (seconds) { - return 1 / seconds; + function TempConstructor() { + } + TempConstructor.prototype = parent.prototype; + child.prototype = new TempConstructor(); + child.prototype.constructor = child; + child._super = parent; }; var newContextCallbacks = []; Tone._initAudioContext = function (callback) { @@ -3089,16 +3293,6 @@ Tone_core_Tone = function () { newContextCallbacks[i](ctx); } }; - Tone.extend = function (child, parent) { - if (isUndef(parent)) { - parent = Tone; - } - function TempConstructor() { - } - TempConstructor.prototype = parent.prototype; - child.prototype = new TempConstructor(); - child.prototype.constructor = child; - }; Tone.startMobile = function () { var osc = Tone.context.createOscillator(); var silent = Tone.context.createGain(); @@ -3110,14 +3304,15 @@ Tone_core_Tone = function () { osc.stop(now + 1); }; Tone._initAudioContext(function (audioContext) { - Tone.prototype.bufferTime = Tone.prototype.bufferSize / audioContext.sampleRate; + Tone.prototype.blockTime = 128 / audioContext.sampleRate; _silentNode = audioContext.createGain(); _silentNode.gain.value = 0; _silentNode.connect(audioContext.destination); }); + Tone.version = 'r7-dev'; return Tone; }(); -/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/ +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ var Tone_signal_SignalBase; Tone_signal_SignalBase = function (Tone) { 'use strict'; @@ -3125,19 +3320,20 @@ Tone_signal_SignalBase = function (Tone) { }; Tone.extend(Tone.SignalBase); Tone.SignalBase.prototype.connect = function (node, outputNumber, inputNumber) { - if (node instanceof Tone.Signal) { - node.setValue(0); + if (Tone.Signal && Tone.Signal === node.constructor || Tone.Param && Tone.Param === node.constructor || Tone.TimelineSignal && Tone.TimelineSignal === node.constructor) { + node._param.cancelScheduledValues(0); + node._param.value = 0; + node.overridden = true; } else if (node instanceof AudioParam) { + node.cancelScheduledValues(0); node.value = 0; } Tone.prototype.connect.call(this, node, outputNumber, inputNumber); - }; - Tone.SignalBase.prototype.dispose = function () { - Tone.prototype.dispose.call(this); + return this; }; return Tone.SignalBase; }(Tone_core_Tone); -/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/ +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ var Tone_signal_WaveShaper; Tone_signal_WaveShaper = function (Tone) { 'use strict'; @@ -3145,10 +3341,10 @@ Tone_signal_WaveShaper = function (Tone) { this._shaper = this.input = this.output = this.context.createWaveShaper(); this._curve = null; if (Array.isArray(mapping)) { - this.setCurve(mapping); + this.curve = mapping; } else if (isFinite(mapping) || this.isUndef(mapping)) { this._curve = new Float32Array(this.defaultArg(mapping, 1024)); - } else if (typeof mapping === 'function') { + } else if (this.isFunction(mapping)) { this._curve = new Float32Array(this.defaultArg(bufferLen, 1024)); this.setMap(mapping); } @@ -3157,213 +3353,756 @@ Tone_signal_WaveShaper = function (Tone) { Tone.WaveShaper.prototype.setMap = function (mapping) { for (var i = 0, len = this._curve.length; i < len; i++) { var normalized = i / len * 2 - 1; - var normOffOne = i / (len - 1) * 2 - 1; - this._curve[i] = mapping(normalized, i, normOffOne); + this._curve[i] = mapping(normalized, i); } this._shaper.curve = this._curve; + return this; }; - Tone.WaveShaper.prototype.setCurve = function (mapping) { - if (this._isSafari()) { - var first = mapping[0]; - mapping.unshift(first); + 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; } - this._curve = new Float32Array(mapping); - this._shaper.curve = this._curve; - }; - Tone.WaveShaper.prototype.setOversample = function (oversampling) { - this._shaper.oversample = oversampling; - }; - Tone.WaveShaper.prototype._isSafari = function () { - var ua = navigator.userAgent.toLowerCase(); - return ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1; - }; + }); + 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); + } + } + }); Tone.WaveShaper.prototype.dispose = function () { Tone.prototype.dispose.call(this); this._shaper.disconnect(); this._shaper = null; this._curve = null; + return this; }; return Tone.WaveShaper; }(Tone_core_Tone); -/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/ -var Tone_signal_Signal; -Tone_signal_Signal = function (Tone) { +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ +var Tone_core_Type; +Tone_core_Type = function (Tone) { 'use strict'; - Tone.Signal = function (value) { - this._scalar = this.context.createGain(); - this.input = this.output = this.context.createGain(); - this._syncRatio = 1; - this.value = this.defaultArg(value, 0); - Tone.Signal._constant.chain(this._scalar, this.output); - }; - Tone.extend(Tone.Signal, Tone.SignalBase); - Tone.Signal.prototype.getValue = function () { - return this._scalar.gain.value; - }; - Tone.Signal.prototype.setValue = function (value) { - if (this._syncRatio === 0) { - value = 0; + Tone.Type = { + Default: 'number', + Time: 'time', + Frequency: 'frequency', + NormalRange: 'normalRange', + AudioRange: 'audioRange', + Decibels: 'db', + Interval: 'interval', + BPM: 'bpm', + Positive: 'positive', + Cents: 'cents', + Degrees: 'degrees', + MIDI: 'midi', + TransportTime: 'transportTime', + Ticks: 'tick', + Note: 'note', + Milliseconds: 'milliseconds', + Notation: 'notation' + }; + Tone.prototype.isNowRelative = function () { + var nowRelative = new RegExp(/^\s*\+(.)+/i); + return function (note) { + return nowRelative.test(note); + }; + }(); + Tone.prototype.isTicks = function () { + var tickFormat = new RegExp(/^\d+i$/i); + return function (note) { + return tickFormat.test(note); + }; + }(); + Tone.prototype.isNotation = function () { + var notationFormat = new RegExp(/^[0-9]+[mnt]$/i); + return function (note) { + return notationFormat.test(note); + }; + }(); + Tone.prototype.isTransportTime = function () { + var transportTimeFormat = new RegExp(/^(\d+(\.\d+)?\:){1,2}(\d+(\.\d+)?)?$/i); + return function (transportTime) { + return transportTimeFormat.test(transportTime); + }; + }(); + Tone.prototype.isNote = function () { + var noteFormat = new RegExp(/^[a-g]{1}(b|#|x|bb)?-?[0-9]+$/i); + return function (note) { + return noteFormat.test(note); + }; + }(); + Tone.prototype.isFrequency = function () { + var freqFormat = new RegExp(/^\d*\.?\d+hz$/i); + return function (freq) { + return freqFormat.test(freq); + }; + }(); + function getTransportBpm() { + if (Tone.Transport && Tone.Transport.bpm) { + return Tone.Transport.bpm.value; + } else { + return 120; + } + } + function getTransportTimeSignature() { + if (Tone.Transport && Tone.Transport.timeSignature) { + return Tone.Transport.timeSignature; } else { - value *= this._syncRatio; + return 4; + } + } + Tone.prototype.notationToSeconds = function (notation, bpm, timeSignature) { + bpm = this.defaultArg(bpm, getTransportBpm()); + timeSignature = this.defaultArg(timeSignature, getTransportTimeSignature()); + var beatTime = 60 / bpm; + 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; + }; + 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); + }; + Tone.prototype.ticksToSeconds = function (ticks, bpm) { + if (this.isUndef(Tone.Transport)) { + return 0; } - this._scalar.gain.value = value; + ticks = parseFloat(ticks); + bpm = this.defaultArg(bpm, getTransportBpm()); + var tickTime = 60 / bpm / Tone.Transport.PPQ; + return tickTime * ticks; }; - Tone.Signal.prototype.setValueAtTime = function (value, time) { - value *= this._syncRatio; - this._scalar.gain.setValueAtTime(value, this.toSeconds(time)); + Tone.prototype.frequencyToSeconds = function (freq) { + return 1 / parseFloat(freq); }; - Tone.Signal.prototype.setCurrentValueNow = function (now) { - now = this.defaultArg(now, this.now()); - var currentVal = this.getValue(); - this.cancelScheduledValues(now); - this._scalar.gain.setValueAtTime(currentVal, now); - return currentVal; + Tone.prototype.samplesToSeconds = function (samples) { + return samples / this.context.sampleRate; }; - Tone.Signal.prototype.linearRampToValueAtTime = function (value, endTime) { - value *= this._syncRatio; - this._scalar.gain.linearRampToValueAtTime(value, this.toSeconds(endTime)); + Tone.prototype.secondsToSamples = function (seconds) { + return seconds * this.context.sampleRate; + }; + 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(':'); }; - Tone.Signal.prototype.exponentialRampToValueAtTime = function (value, endTime) { - value *= this._syncRatio; - try { - this._scalar.gain.exponentialRampToValueAtTime(value, this.toSeconds(endTime)); - } catch (e) { - this._scalar.gain.linearRampToValueAtTime(value, this.toSeconds(endTime)); - } + Tone.prototype.secondsToFrequency = function (seconds) { + return 1 / seconds; }; - Tone.Signal.prototype.exponentialRampToValueNow = function (value, endTime) { - var now = this.now(); - this.setCurrentValueNow(now); - if (endTime.toString().charAt(0) === '+') { - endTime = endTime.substr(1); + Tone.prototype.toTransportTime = function (time, bpm, timeSignature) { + var seconds = this.toSeconds(time); + return this.secondsToTransportTime(seconds, bpm, timeSignature); + }; + 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; } - this.exponentialRampToValueAtTime(value, now + this.toSeconds(endTime)); }; - Tone.Signal.prototype.linearRampToValueNow = function (value, endTime) { - var now = this.now(); - this.setCurrentValueNow(now); - value *= this._syncRatio; - if (endTime.toString().charAt(0) === '+') { - endTime = endTime.substr(1); + Tone.prototype.toTicks = function (time) { + if (this.isUndef(Tone.Transport)) { + return 0; } - this._scalar.gain.linearRampToValueAtTime(value, now + this.toSeconds(endTime)); + var bpm = Tone.Transport.bpm.value; + 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; + return Math.round(tickNum + plusNow); }; - Tone.Signal.prototype.setTargetAtTime = function (value, startTime, timeConstant) { - value *= this._syncRatio; - this._scalar.gain.setTargetAtTime(value, this.toSeconds(startTime), timeConstant); + Tone.prototype.toSamples = function (time) { + var seconds = this.toSeconds(time); + return Math.round(seconds * this.context.sampleRate); }; - Tone.Signal.prototype.setValueCurveAtTime = function (values, startTime, duration) { - for (var i = 0; i < values.length; i++) { - values[i] *= this._syncRatio; + Tone.prototype.toSeconds = function (time, now) { + now = this.defaultArg(now, this.now()); + if (this.isNumber(time)) { + return time; + } else if (this.isString(time)) { + var plusTime = 0; + if (this.isNowRelative(time)) { + time = time.replace('+', ''); + plusTime = now; + } + var betweenParens = time.match(/\(([^)(]+)\)/g); + if (betweenParens) { + for (var j = 0; j < betweenParens.length; j++) { + var symbol = betweenParens[j].replace(/[\(\)]/g, ''); + var symbolVal = this.toSeconds(symbol); + time = time.replace(betweenParens[j], symbolVal); + } + } + if (time.indexOf('@') !== -1) { + var quantizationSplit = time.split('@'); + if (!this.isUndef(Tone.Transport)) { + var toQuantize = quantizationSplit[0].trim(); + if (toQuantize === '') { + toQuantize = undefined; + } + 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 { + time = eval(time); + } 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; } - this._scalar.gain.setValueCurveAtTime(values, this.toSeconds(startTime), this.toSeconds(duration)); }; - Tone.Signal.prototype.cancelScheduledValues = function (startTime) { - this._scalar.gain.cancelScheduledValues(this.toSeconds(startTime)); + 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); + 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); + if (retTripletNotation.split('+').length < retNotation.split('+').length) { + return retTripletNotation; + } else { + return retNotation; + } }; - Tone.Signal.prototype.sync = function (signal, ratio) { - if (ratio) { - this._syncRatio = ratio; + 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); + 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; + } + 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 { - if (signal.getValue() !== 0) { - this._syncRatio = this.getValue() / signal.getValue(); - } else { - this._syncRatio = 0; + return val; + } + }; + 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; + } + }; + 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 + }; + var scaleIndexToNote = [ + 'C', + 'C#', + 'D', + 'D#', + 'E', + 'F', + 'F#', + 'G', + 'G#', + 'A', + 'A#', + 'B' + ]; + Tone.A4 = 440; + Tone.prototype.noteToFrequency = function (note) { + 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; } - this._scalar.disconnect(); - this._scalar = this.context.createGain(); - this.connectSeries(signal, this._scalar, this.output); - this._scalar.gain.value = this._syncRatio; }; - Tone.Signal.prototype.unsync = function () { - var currentGain = this.getValue(); - this._scalar.disconnect(); - this._scalar = this.context.createGain(); - this._scalar.gain.value = currentGain / this._syncRatio; - this._syncRatio = 1; - Tone.Signal._constant.chain(this._scalar, this.output); + 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(); }; - Tone.Signal.prototype.dispose = function () { - Tone.prototype.dispose.call(this); - this._scalar.disconnect(); - this._scalar = null; + Tone.prototype.intervalToFrequencyRatio = function (interval) { + return Math.pow(2, interval / 12); + }; + Tone.prototype.midiToNote = function (midiNumber) { + var octave = Math.floor(midiNumber / 12) - 1; + var note = midiNumber % 12; + return scaleIndexToNote[note] + octave; + }; + Tone.prototype.noteToMidi = function (note) { + 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; + } }; - Object.defineProperty(Tone.Signal.prototype, 'value', { + Tone.prototype.midiToFrequency = function (midi) { + return Tone.A4 * Math.pow(2, (midi - 69) / 12); + }; + return Tone; +}(Tone_core_Tone); +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ +var Tone_core_Param; +Tone_core_Param = function (Tone) { + 'use strict'; + Tone.Param = function () { + var options = this.optionsObject(arguments, [ + 'param', + 'units', + 'convert' + ], Tone.Param.defaults); + this._param = this.input = options.param; + this.units = options.units; + this.convert = options.convert; + this.overridden = false; + if (!this.isUndef(options.value)) { + this.value = options.value; + } + }; + Tone.extend(Tone.Param); + Tone.Param.defaults = { + 'units': Tone.Type.Default, + 'convert': true, + 'param': undefined + }; + Object.defineProperty(Tone.Param.prototype, 'value', { get: function () { - return this.getValue(); + return this._toUnits(this._param.value); }, - set: function (val) { - this.setValue(val); + set: function (value) { + var convertedVal = this._fromUnits(value); + this._param.value = convertedVal; } }); - Tone.Signal._generator = null; + 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; + } + }; + 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; + } + }; + Tone.Param.prototype._minOutput = 0.00001; + Tone.Param.prototype.setValueAtTime = function (value, time) { + value = this._fromUnits(value); + this._param.setValueAtTime(value, this.toSeconds(time)); + return 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; + }; + Tone.Param.prototype.linearRampToValueAtTime = function (value, endTime) { + value = this._fromUnits(value); + this._param.linearRampToValueAtTime(value, this.toSeconds(endTime)); + return 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; + }; + Tone.Param.prototype.exponentialRampToValue = function (value, rampTime) { + var now = this.now(); + var currentVal = this.value; + this.setValueAtTime(Math.max(currentVal, this._minOutput), now); + this.exponentialRampToValueAtTime(value, now + this.toSeconds(rampTime)); + return this; + }; + Tone.Param.prototype.linearRampToValue = function (value, rampTime) { + var now = this.now(); + this.setRampPoint(now); + this.linearRampToValueAtTime(value, now + this.toSeconds(rampTime)); + return this; + }; + Tone.Param.prototype.setTargetAtTime = function (value, startTime, timeConstant) { + value = this._fromUnits(value); + value = Math.max(this._minOutput, value); + timeConstant = Math.max(this._minOutput, timeConstant); + this._param.setTargetAtTime(value, this.toSeconds(startTime), timeConstant); + return 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; + }; + Tone.Param.prototype.cancelScheduledValues = function (startTime) { + this._param.cancelScheduledValues(this.toSeconds(startTime)); + return this; + }; + 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; + }; + Tone.Param.prototype.dispose = function () { + Tone.prototype.dispose.call(this); + this._param = null; + return this; + }; + return Tone.Param; +}(Tone_core_Tone); +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ +var Tone_core_Gain; +Tone_core_Gain = function (Tone) { + 'use strict'; + Tone.Gain = function () { + var options = this.optionsObject(arguments, [ + 'gain', + 'units' + ], Tone.Gain.defaults); + this.input = this.output = this._gainNode = this.context.createGain(); + this.gain = new Tone.Param({ + 'param': this._gainNode.gain, + 'units': options.units, + 'value': options.gain, + 'convert': options.convert + }); + this._readOnly('gain'); + }; + Tone.extend(Tone.Gain); + Tone.Gain.defaults = { + 'gain': 1, + 'convert': true + }; + 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; +}(Tone_core_Tone, Tone_core_Param); +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ +var Tone_signal_Signal; +Tone_signal_Signal = function (Tone) { + 'use strict'; + Tone.Signal = function () { + var options = this.optionsObject(arguments, [ + 'value', + 'units' + ], Tone.Signal.defaults); + this.output = this._gain = this.context.createGain(); + options.param = this._gain.gain; + Tone.Param.call(this, options); + this.input = this._param = this._gain.gain; + Tone.Signal._constant.chain(this._gain); + }; + Tone.extend(Tone.Signal, Tone.Param); + Tone.Signal.defaults = { + 'value': 0, + 'units': Tone.Type.Default, + 'convert': true + }; + Tone.Signal.prototype.connect = Tone.SignalBase.prototype.connect; + Tone.Signal.prototype.dispose = function () { + Tone.Param.prototype.dispose.call(this); + this._param = null; + this._gain.disconnect(); + this._gain = null; + return this; + }; Tone.Signal._constant = null; Tone._initAudioContext(function (audioContext) { - Tone.Signal._generator = audioContext.createOscillator(); - Tone.Signal._constant = new Tone.WaveShaper([ - 1, - 1 - ]); - Tone.Signal._generator.connect(Tone.Signal._constant); - Tone.Signal._generator.start(0); - Tone.Signal._generator.noGC(); + 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; -}(Tone_core_Tone); -/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/ +}(Tone_core_Tone, Tone_signal_WaveShaper, Tone_core_Type, Tone_core_Param); +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ var Tone_signal_Add; Tone_signal_Add = function (Tone) { 'use strict'; Tone.Add = function (value) { Tone.call(this, 2, 0); this._sum = this.input[0] = this.input[1] = this.output = this.context.createGain(); - this._value = null; - if (isFinite(value)) { - this._value = new Tone.Signal(value); - this._value.connect(this._sum); - } - }; - Tone.extend(Tone.Add, Tone.SignalBase); - Tone.Add.prototype.setValue = function (value) { - if (this._value !== null) { - this._value.setValue(value); - } else { - throw new Error('cannot switch from signal to number'); - } + this._param = this.input[1] = new Tone.Signal(value); + this._param.connect(this._sum); }; + Tone.extend(Tone.Add, Tone.Signal); Tone.Add.prototype.dispose = function () { Tone.prototype.dispose.call(this); + this._sum.disconnect(); this._sum = null; - if (this._value) { - this._value.dispose(); - this._value = null; - } + this._param.dispose(); + this._param = null; + return this; }; return Tone.Add; }(Tone_core_Tone); -/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/ +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ var Tone_signal_Multiply; Tone_signal_Multiply = function (Tone) { 'use strict'; Tone.Multiply = function (value) { Tone.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(value, 0); - }; - Tone.extend(Tone.Multiply, Tone.SignalBase); - Tone.Multiply.prototype.setValue = function (value) { - this._factor.value = value; + this._param = this.input[1] = this.output.gain; + this._param.value = this.defaultArg(value, 0); }; + Tone.extend(Tone.Multiply, Tone.Signal); Tone.Multiply.prototype.dispose = function () { Tone.prototype.dispose.call(this); + this._mult.disconnect(); this._mult = null; - this._factor = null; + this._param = null; + return this; }; return Tone.Multiply; }(Tone_core_Tone); -/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/ +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ var Tone_signal_Scale; Tone_signal_Scale = function (Tone) { 'use strict'; @@ -3376,17 +4115,27 @@ Tone_signal_Scale = function (Tone) { this._setRange(); }; Tone.extend(Tone.Scale, Tone.SignalBase); - Tone.Scale.prototype.setMin = function (min) { - this._outputMin = min; - this._setRange(); - }; - Tone.Scale.prototype.setMax = function (max) { - this._outputMax = max; - this._setRange(); - }; + Object.defineProperty(Tone.Scale.prototype, 'min', { + get: function () { + return this._outputMin; + }, + set: function (min) { + this._outputMin = min; + this._setRange(); + } + }); + Object.defineProperty(Tone.Scale.prototype, 'max', { + get: function () { + return this._outputMax; + }, + set: function (max) { + this._outputMax = max; + this._setRange(); + } + }); Tone.Scale.prototype._setRange = function () { - this._add.setValue(this._outputMin); - this._scale.setValue(this._outputMax - this._outputMin); + this._add.value = this._outputMin; + this._scale.value = this._outputMax - this._outputMin; }; Tone.Scale.prototype.dispose = function () { Tone.prototype.dispose.call(this); @@ -3394,6 +4143,7 @@ Tone_signal_Scale = function (Tone) { this._add = null; this._scale.dispose(); this._scale = null; + return this; }; return Tone.Scale; }(Tone_core_Tone, Tone_signal_Add, Tone_signal_Multiply); @@ -3771,13 +4521,17 @@ oscillator = function () { var now = p5sound.audiocontext.currentTime; var rampTime = rampTime || 0; var tFromNow = tFromNow || 0; - var currentFreq = this.oscillator.frequency.value; - this.oscillator.frequency.cancelScheduledValues(now); - this.oscillator.frequency.setValueAtTime(currentFreq, now + tFromNow); - if (val > 0) { - this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); + // var currentFreq = this.oscillator.frequency.value; + // this.oscillator.frequency.cancelScheduledValues(now); + if (rampTime == 0) { + this.oscillator.frequency.cancelScheduledValues(now); + this.oscillator.frequency.setValueAtTime(val, tFromNow + now); } else { - this.oscillator.frequency.linearRampToValueAtTime(val, tFromNow + rampTime + now); + if (val > 0) { + this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); + } else { + this.oscillator.frequency.linearRampToValueAtTime(val, tFromNow + rampTime + now); + } } // reset phase if oscillator has a phase if (this.phaseAmount) { @@ -4033,23 +4787,370 @@ oscillator = function () { p5.SawOsc = function (freq) { p5.Oscillator.call(this, freq, 'sawtooth'); }; - p5.SawOsc.prototype = Object.create(p5.Oscillator.prototype); - /** - * Constructor: new p5.SqrOsc(). - * This creates a Square Wave Oscillator and is - * equivalent to new p5.Oscillator('square') - * or creating a p5.Oscillator and then calling - * its method setType('square'). - * See p5.Oscillator for methods. - * - * @method p5.SqrOsc - * @param {[Number]} freq Set the frequency - */ - p5.SqrOsc = function (freq) { - p5.Oscillator.call(this, freq, 'square'); + p5.SawOsc.prototype = Object.create(p5.Oscillator.prototype); + /** + * Constructor: new p5.SqrOsc(). + * This creates a Square Wave Oscillator and is + * equivalent to new p5.Oscillator('square') + * or creating a p5.Oscillator and then calling + * its method setType('square'). + * See p5.Oscillator for methods. + * + * @method p5.SqrOsc + * @param {[Number]} freq Set the frequency + */ + p5.SqrOsc = function (freq) { + p5.Oscillator.call(this, freq, 'square'); + }; + p5.SqrOsc.prototype = Object.create(p5.Oscillator.prototype); +}(master, Tone_signal_Signal, Tone_signal_Add, Tone_signal_Multiply, Tone_signal_Scale); +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ +var Tone_core_Timeline; +Tone_core_Timeline = function (Tone) { + 'use strict'; + Tone.Timeline = function () { + var options = this.optionsObject(arguments, ['memory'], Tone.Timeline.defaults); + this._timeline = []; + this._toRemove = []; + this._iterating = false; + this.memory = options.memory; + }; + Tone.extend(Tone.Timeline); + Tone.Timeline.defaults = { 'memory': Infinity }; + Object.defineProperty(Tone.Timeline.prototype, 'length', { + get: function () { + return this._timeline.length; + } + }); + Tone.Timeline.prototype.addEvent = function (event) { + 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 (this.length > this.memory) { + var diff = this.length - this.memory; + this._timeline.splice(0, diff); + } + return 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; + }; + 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; + } + }; + 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; + } + }; + 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; + } + }; + 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) { + if (this._timeline[0].time >= after) { + this._timeline = []; + } + } + return 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; + }; + Tone.Timeline.prototype._search = function (time) { + var beginning = 0; + var len = this._timeline.length; + var end = len; + while (beginning <= end && beginning < len) { + var midPoint = Math.floor(beginning + (end - beginning) / 2); + var event = this._timeline[midPoint]; + if (event.time === 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) { + end = midPoint - 1; + } else if (event.time < time) { + beginning = midPoint + 1; + } + } + return beginning - 1; + }; + 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 = []; + } + }; + Tone.Timeline.prototype.forEach = function (callback) { + this._iterate(callback); + return this; + }; + Tone.Timeline.prototype.forEachBefore = function (time, callback) { + time = this.toSeconds(time); + var upperBound = this._search(time); + if (upperBound !== -1) { + this._iterate(callback, 0, upperBound); + } + return this; + }; + Tone.Timeline.prototype.forEachAfter = function (time, callback) { + time = this.toSeconds(time); + var lowerBound = this._search(time); + this._iterate(callback, lowerBound + 1); + return this; + }; + Tone.Timeline.prototype.forEachFrom = function (time, callback) { + time = this.toSeconds(time); + var lowerBound = this._search(time); + while (lowerBound >= 0 && this._timeline[lowerBound].time >= time) { + lowerBound--; + } + this._iterate(callback, lowerBound + 1); + return this; + }; + Tone.Timeline.prototype.forEachAtTime = function (time, callback) { + 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; + }; + Tone.Timeline.prototype.dispose = function () { + Tone.prototype.dispose.call(this); + this._timeline = null; + this._toRemove = null; + }; + return Tone.Timeline; +}(Tone_core_Tone); +/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ +var Tone_signal_TimelineSignal; +Tone_signal_TimelineSignal = function (Tone) { + 'use strict'; + Tone.TimelineSignal = function () { + var options = this.optionsObject(arguments, [ + 'value', + 'units' + ], Tone.Signal.defaults); + Tone.Signal.apply(this, options); + options.param = this._param; + Tone.Param.call(this, options); + this._events = new Tone.Timeline(10); + this._initial = this._fromUnits(this._param.value); + }; + Tone.extend(Tone.TimelineSignal, Tone.Param); + Tone.TimelineSignal.Type = { + Linear: 'linear', + Exponential: 'exponential', + Target: 'target', + Set: 'set' + }; + 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; + } + }); + 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 + }); + this._param.setValueAtTime(value, startTime); + return 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; + }; + 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; + }; + 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; + }; + Tone.TimelineSignal.prototype.cancelScheduledValues = function (after) { + this._events.cancel(after); + this._param.cancelScheduledValues(this.toSeconds(after)); + return this; + }; + Tone.TimelineSignal.prototype.setRampPoint = function (time) { + time = this.toSeconds(time); + var val = this.getValueAtTime(time); + var after = this._searchAfter(time); + if (after) { + 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; + }; + Tone.TimelineSignal.prototype.linearRampToValueBetween = function (value, start, finish) { + this.setRampPoint(start); + this.linearRampToValueAtTime(value, finish); + return this; + }; + Tone.TimelineSignal.prototype.exponentialRampToValueBetween = function (value, start, finish) { + this.setRampPoint(start); + this.exponentialRampToValueAtTime(value, finish); + return this; + }; + Tone.TimelineSignal.prototype._searchBefore = function (time) { + return this._events.getEvent(time); + }; + Tone.TimelineSignal.prototype._searchAfter = function (time) { + return this._events.getEventAfter(time); + }; + Tone.TimelineSignal.prototype.getValueAtTime = function (time) { + var after = this._searchAfter(time); + var before = this._searchBefore(time); + var value = this._initial; + 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; + }; + Tone.TimelineSignal.prototype.connect = Tone.SignalBase.prototype.connect; + Tone.TimelineSignal.prototype._exponentialApproach = function (t0, v0, v1, timeConstant, t) { + return v1 + (v0 - v1) * Math.exp(-(t - t0) / timeConstant); }; - p5.SqrOsc.prototype = Object.create(p5.Oscillator.prototype); -}(master, Tone_signal_Signal, Tone_signal_Add, Tone_signal_Multiply, Tone_signal_Scale); + Tone.TimelineSignal.prototype._linearInterpolate = function (t0, v0, t1, v1, t) { + return v0 + (v1 - v0) * ((t - t0) / (t1 - t0)); + }; + 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)); + }; + 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; +}(Tone_core_Tone, Tone_signal_Signal); var env; env = function () { 'use strict'; @@ -4057,107 +5158,107 @@ env = function () { var Add = Tone_signal_Add; var Mult = Tone_signal_Multiply; var Scale = Tone_signal_Scale; + var TimelineSignal = Tone_signal_TimelineSignal; var Tone = Tone_core_Tone; Tone.setContext(p5sound.audiocontext); /** - *

Envelopes are pre-defined amplitude distribution over time. - * The p5.Env accepts up to four time/level pairs, where time - * determines how long of a ramp before value reaches level. + *

Envelopes are pre-defined amplitude distribution over time. + * The p5.Env accepts up to three time/level pairs, where time + * determines the duration until value reaches level. * Typically, envelopes are used to control the output volume * of an object, a series of fades referred to as Attack, Decay, - * Sustain and Release (ADSR). But p5.Env can control any - * Web Audio Param, for example it can be passed to an Oscillator - * frequency like osc.freq(env)

+ * Sustain and Release ( + * ADSR + * ). But p5.Env can control any Web Audio Param; for example it can be passed to an Oscillator + * frequency like osc.freq(env).

+ *

Use setRange to change the attack/release level. + * Use setADSR to change attackTime, decayTime, sustainPercent and releaseTime.

+ *

Use the play method to play the entire envelope, the ramp method for a pingable trigger, + * or triggerAttack/triggerRelease to trigger noteOn/noteOff.

* * @class p5.Env * @constructor - * @param {Number} aTime Time (in seconds) before level - * reaches attackLevel - * @param {Number} aLevel Typically an amplitude between - * 0.0 and 1.0 - * @param {Number} dTime Time - * @param {Number} [dLevel] Amplitude (In a standard ADSR envelope, - * decayLevel = sustainLevel) - * @param {Number} [sTime] Time (in seconds) - * @param {Number} [sLevel] Amplitude 0.0 to 1.0 - * @param {Number} [rTime] Time (in seconds) - * @param {Number} [rLevel] Amplitude 0.0 to 1.0 * @example *
- * var aT = 0.1; // attack time in seconds - * var aL = 0.7; // attack level 0.0 to 1.0 - * var dT = 0.3; // decay time in seconds - * var dL = 0.1; // decay level 0.0 to 1.0 - * var sT = 0.2; // sustain time in seconds - * var sL = dL; // sustain level 0.0 to 1.0 - * var rT = 0.5; // release time in seconds - * // release level defaults to zero - * - * var env; - * var triOsc; - * + * var attackLevel = 1.0; + * var releaseLevel = 0; + * + * var attackTime = 0.001 + * var decayTime = 0.2; + * var susPercent = 0.2; + * var releaseTime = 0.5; + * + * var env, triOsc; + * * function setup() { - * background(0); - * noStroke(); - * fill(255); + * var cnv = createCanvas(100, 100); + * * textAlign(CENTER); * text('click to play', width/2, height/2); * - * env = new p5.Env(aT, aL, dT, dL, sT, sL, rT); + * env = new p5.Env(); + * env.setADSR(attackTime, decayTime, susPercent, releaseTime); + * env.setRange(attackLevel, releaseLevel); + * * triOsc = new p5.Oscillator('triangle'); - * triOsc.amp(env); // give the env control of the triOsc's amp + * triOsc.amp(env); * triOsc.start(); + * triOsc.freq(220); + * + * cnv.mousePressed(playEnv); * } * - * // mouseClick triggers envelope if over canvas - * function mouseClicked() { - * // is mouse over canvas? - * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { - * env.play(triOsc); - * } + * function playEnv(){ + * env.play(); * } *
*/ - p5.Env = function (t1, l1, t2, l2, t3, l3, t4, l4) { + p5.Env = function (t1, l1, t2, l2, t3, l3) { + var now = p5sound.audiocontext.currentTime; /** + * Time until envelope reaches attackLevel * @property attackTime */ - this.aTime = t1; + this.aTime = t1 || 0.1; /** + * Level once attack is complete. * @property attackLevel */ - this.aLevel = l1; + this.aLevel = l1 || 1; /** + * Time until envelope reaches decayLevel. * @property decayTime */ - this.dTime = t2 || 0; + this.dTime = t2 || 0.5; /** + * Level after decay. The envelope will sustain here until it is released. * @property decayLevel */ this.dLevel = l2 || 0; /** - * @property sustainTime - */ - this.sTime = t3 || 0; - /** - * @property sustainLevel - */ - this.sLevel = l3 || 0; - /** + * Duration of the release portion of the envelope. * @property releaseTime */ - this.rTime = t4 || 0; + this.rTime = t3 || 0; /** + * Level at the end of the release. * @property releaseLevel */ - this.rLevel = l4 || 0; + this.rLevel = l3 || 0; + this._rampHighPercentage = 0.98; + this._rampLowPercentage = 0.02; this.output = p5sound.audiocontext.createGain(); - this.control = new p5.Signal(); + this.control = new TimelineSignal(); + this._init(); + // this makes sure the envelope starts at zero this.control.connect(this.output); + // connect to the output this.connection = null; // store connection //array of math operation signal chaining this.mathOps = [this.control]; + //whether envelope should be linear or exponential curve + this.isExponential = false; // oscillator or buffer source to clear on env complete // to save resources if/when it is retriggered this.sourceToClear = null; @@ -4166,31 +5267,180 @@ env = function () { // add to the soundArray so we can dispose of the env later p5sound.soundArray.push(this); }; + // this init function just smooths the starting value to zero and gives a start point for the timeline + // - it was necessary to remove glitches at the beginning. + p5.Env.prototype._init = function () { + var now = p5sound.audiocontext.currentTime; + var t = now; + this.control.setTargetAtTime(0.00001, t, 0.001); + //also, compute the correct time constants + this._setRampAD(this.aTime, this.dTime); + }; /** * Reset the envelope with a series of time/value pairs. * * @method set - * @param {Number} aTime Time (in seconds) before level + * @param {Number} attackTime Time (in seconds) before level * reaches attackLevel - * @param {Number} aLevel Typically an amplitude between + * @param {Number} attackLevel Typically an amplitude between * 0.0 and 1.0 - * @param {Number} dTime Time - * @param {Number} [dLevel] Amplitude (In a standard ADSR envelope, + * @param {Number} decayTime Time + * @param {Number} decayLevel Amplitude (In a standard ADSR envelope, * decayLevel = sustainLevel) - * @param {Number} [sTime] Time (in seconds) - * @param {Number} [sLevel] Amplitude 0.0 to 1.0 - * @param {Number} [rTime] Time (in seconds) - * @param {Number} [rLevel] Amplitude 0.0 to 1.0 + * @param {Number} releaseTime Release Time (in seconds) + * @param {Number} releaseLevel Amplitude */ - p5.Env.prototype.set = function (t1, l1, t2, l2, t3, l3, t4, l4) { + p5.Env.prototype.set = function (t1, l1, t2, l2, t3, l3) { this.aTime = t1; this.aLevel = l1; this.dTime = t2 || 0; this.dLevel = l2 || 0; - this.sTime = t3 || 0; - this.sLevel = l3 || 0; this.rTime = t4 || 0; this.rLevel = l4 || 0; + // set time constants for ramp + this._setRampAD(t1, t2); + }; + /** + * Set values like a traditional + * + * ADSR envelope + * . + * + * @method setADSR + * @param {Number} attackTime Time (in seconds before envelope + * reaches Attack Level + * @param {Number} [decayTime] Time (in seconds) before envelope + * reaches Decay/Sustain Level + * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, + * where 1.0 = attackLevel, 0.0 = releaseLevel. + * The susRatio determines the decayLevel and the level at which the + * sustain portion of the envelope will sustain. + * For example, if attackLevel is 0.4, releaseLevel is 0, + * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is + * increased to 1.0 (using setRange), + * then decayLevel would increase proportionally, to become 0.5. + * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) + * @example + *
+ * var attackLevel = 1.0; + * var releaseLevel = 0; + * + * var attackTime = 0.001 + * var decayTime = 0.2; + * var susPercent = 0.2; + * var releaseTime = 0.5; + * + * var env, triOsc; + * + * function setup() { + * var cnv = createCanvas(100, 100); + * + * textAlign(CENTER); + * text('click to play', width/2, height/2); + * + * env = new p5.Env(); + * env.setADSR(attackTime, decayTime, susPercent, releaseTime); + * env.setRange(attackLevel, releaseLevel); + * + * triOsc = new p5.Oscillator('triangle'); + * triOsc.amp(env); + * triOsc.start(); + * triOsc.freq(220); + * + * cnv.mousePressed(playEnv); + * } + * + * function playEnv(){ + * env.play(); + * } + */ + p5.Env.prototype.setADSR = function (aTime, dTime, sPercent, rTime) { + this.aTime = aTime; + this.dTime = dTime || 0; + // lerp + this.sPercent = sPercent || 0; + this.dLevel = typeof sPercent !== 'undefined' ? sPercent * (this.aLevel - this.rLevel) + this.rLevel : 0; + this.rTime = rTime || 0; + // also set time constants for ramp + this._setRampAD(aTime, dTime); + }; + /** + * Set max (attackLevel) and min (releaseLevel) of envelope. + * + * @method setRange + * @param {Number} aLevel attack level (defaults to 1) + * @param {Number} rLevel release level (defaults to 0) + * @example + *
+ * var attackLevel = 1.0; + * var releaseLevel = 0; + * + * var attackTime = 0.001 + * var decayTime = 0.2; + * var susPercent = 0.2; + * var releaseTime = 0.5; + * + * var env, triOsc; + * + * function setup() { + * var cnv = createCanvas(100, 100); + * + * textAlign(CENTER); + * text('click to play', width/2, height/2); + * + * env = new p5.Env(); + * env.setADSR(attackTime, decayTime, susPercent, releaseTime); + * env.setRange(attackLevel, releaseLevel); + * + * triOsc = new p5.Oscillator('triangle'); + * triOsc.amp(env); + * triOsc.start(); + * triOsc.freq(220); + * + * cnv.mousePressed(playEnv); + * } + * + * function playEnv(){ + * env.play(); + * } + */ + p5.Env.prototype.setRange = function (aLevel, rLevel) { + this.aLevel = aLevel || 1; + this.rLevel = rLevel || 0; + }; + // private (undocumented) method called when ADSR is set to set time constants for ramp + // + // Set the + // time constants for simple exponential ramps. + // The larger the time constant value, the slower the + // transition will be. + // + // method _setRampAD + // param {Number} attackTimeConstant attack time constant + // param {Number} decayTimeConstant decay time constant + // + p5.Env.prototype._setRampAD = function (t1, t2) { + this._rampAttackTime = this.checkExpInput(t1); + this._rampDecayTime = this.checkExpInput(t2); + var TCDenominator = 1; + /// Aatish Bhatia's calculation for time constant for rise(to adjust 1/1-e calculation to any percentage) + TCDenominator = Math.log(1 / this.checkExpInput(1 - this._rampHighPercentage)); + this._rampAttackTC = t1 / this.checkExpInput(TCDenominator); + TCDenominator = Math.log(1 / this._rampLowPercentage); + this._rampDecayTC = t2 / this.checkExpInput(TCDenominator); + }; + // private method + p5.Env.prototype.setRampPercentages = function (p1, p2) { + //set the percentages that the simple exponential ramps go to + this._rampHighPercentage = this.checkExpInput(p1); + this._rampLowPercentage = this.checkExpInput(p2); + var TCDenominator = 1; + //now re-compute the time constants based on those percentages + /// Aatish Bhatia's calculation for time constant for rise(to adjust 1/1-e calculation to any percentage) + TCDenominator = Math.log(1 / this.checkExpInput(1 - this._rampHighPercentage)); + this._rampAttackTC = this._rampAttackTime / this.checkExpInput(TCDenominator); + TCDenominator = Math.log(1 / this._rampLowPercentage); + this._rampDecayTC = this._rampDecayTime / this.checkExpInput(TCDenominator); }; /** * Assign a parameter to be controlled by this envelope. @@ -4207,46 +5457,53 @@ env = function () { this.connect(arguments[i]); } }; - p5.Env.prototype.ctrl = function (unit) { - this.connect(unit); - }; /** - * Play tells the envelope to start acting on a given input. - * If the input is a p5.sound object (i.e. AudioIn, Oscillator, - * SoundFile), then Env will control its output volume. - * Envelopes can also be used to control any - * Web Audio Audio Param. - * - * @method play - * @param {Object} unit A p5.sound object or - * Web Audio Param. - * @param {Number} secondsFromNow time from now (in seconds) + * Set whether the envelope ramp is linear (default) or exponential. + * Exponential ramps can be useful because we perceive amplitude + * and frequency logarithmically. + * + * @method setExp + * @param {Boolean} isExp true is exponential, false is linear */ - p5.Env.prototype.play = function (unit, secondsFromNow) { + p5.Env.prototype.setExp = function (isExp) { + this.isExponential = isExp; + }; + //helper method to protect against zero values being sent to exponential functions + p5.Env.prototype.checkExpInput = function (value) { + if (value <= 0) { + value = 0.0001; + } + return value; + }; + /** + * Play tells the envelope to start acting on a given input. + * If the input is a p5.sound object (i.e. AudioIn, Oscillator, + * SoundFile), then Env will control its output volume. + * Envelopes can also be used to control any + * Web Audio Audio Param. + * + * @method play + * @param {Object} unit A p5.sound object or + * Web Audio Param. + * @param {Number} [startTime] time from now (in seconds) at which to play + * @param {Number} [sustainTime] time to sustain before releasing the envelope + + */ + p5.Env.prototype.play = function (unit, secondsFromNow, susTime) { var now = p5sound.audiocontext.currentTime; var tFromNow = secondsFromNow || 0; - var t = now + tFromNow; + var susTime = susTime || 0; if (unit) { if (this.connection !== unit) { this.connect(unit); } } - var currentVal = this.control.getValue(); - this.control.cancelScheduledValues(t); - this.control.linearRampToValueAtTime(currentVal, t); - // attack - this.control.linearRampToValueAtTime(this.aLevel, t + this.aTime); - // decay to decay level - this.control.linearRampToValueAtTime(this.dLevel, t + this.aTime + this.dTime); - // hold sustain level - this.control.linearRampToValueAtTime(this.sLevel, t + this.aTime + this.dTime + this.sTime); - // release - this.control.linearRampToValueAtTime(this.rLevel, t + this.aTime + this.dTime + this.sTime + this.rTime); - var clearTime = t + this.aTime + this.dTime + this.sTime + this.rTime; + this.triggerAttack(unit, tFromNow); + this.triggerRelease(unit, tFromNow + this.aTime + this.dTime + susTime); }; /** - * Trigger the Attack, Decay, and Sustain of the Envelope. + * Trigger the Attack, and Decay portion of the Envelope. * Similar to holding down a key on a piano, but it will * hold the sustain level until you let go. Input can be * any p5.sound object, or a -1))throw arguments[t]+" is not a valid sound format!";e.extensions.push(arguments[t])}},t.prototype.disposeSound=function(){for(var t=0;t-1){var s=t.prototype.isFileSupported(n);if(s)o=o;else for(var r=o.split("."),a=r[r.length-1],u=0;u1?(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 r;r=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 l(s,n);i[n]=r,n+=6e3}n++}return i}function o(t){for(var e=[],i=Object.keys(t).sort(),o=0;on;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 s(t,e){var i=[];return t.forEach(function(t){try{var o=Math.abs(60/(t.interval/e));o=a(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 r(t,e,i,o){for(var n=[],s=Object.keys(t).sort(),r=0;r.01?!0:void 0})}function a(t){if(isFinite(t)&&0!=t){for(;90>t;)t*=2;for(;t>180&&t>90;)t/=2;return t}}var u=n,c=i,h=c.audiocontext;t.SoundFile=function(e,i,o,n){if("undefined"!=typeof e){if("string"==typeof e||"string"==typeof e[0]){var s=t.prototype._checkFileFormats(e);this.url=s}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._onended=function(){},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=c.audiocontext.createGain(),this.output=c.audiocontext.createGain(),this.reversed=!1,this.startTime=0,this.endTime=null,this.pauseTime=0,this.mode="sustain",this.startMillis=null,this.panPosition=0,this.panner=new t.Panner(this.output,c.input,2),(this.url||this.file)&&this.load(i,o),c.soundArray.push(this),this._whileLoading="function"==typeof n?n:function(){}},t.prototype.registerPreloadMethod("loadSound",t.prototype),t.prototype.loadSound=function(e,i,o,n){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 s=new t.SoundFile(e,i,o,n);return s},t.SoundFile.prototype.load=function(t,e){var i=this,o=(new Error).stack;if(void 0!=this.url&&""!=this.url){var n=new XMLHttpRequest;n.addEventListener("progress",function(t){i._updateProgress(t)},!1),n.open("GET",this.url,!0),n.responseType="arraybuffer",n.onload=function(){if(200==n.status)h.decodeAudioData(n.response,function(e){i.buffer=e,i.panner.inputChannels(e.numberOfChannels),t&&t(i)},function(){var t=new u("decodeAudioData",o,i.url),n="AudioContext error at decodeAudioData for "+i.url;e?(t.msg=n,e(t)):console.error(n+"\n The error stack trace includes: \n"+t.stack)});else{var s=new u("loadSound",o,i.url),r="Unable to load "+i.url+". The request status was: "+n.status+" ("+n.statusText+")";e?(s.message=r,e(s)):console.error(r+"\n The error stack trace includes: \n"+s.stack)}},n.onerror=function(){var t=new u("loadSound",o,i.url),n="There was no response from the server at "+i.url+". Check the url and internet connectivity.";e?(t.message=n,e(t)):console.error(n+"\n The error stack trace includes: \n"+t.stack)},n.send()}else if(void 0!=this.file){var s=new FileReader,i=this;s.onload=function(){h.decodeAudioData(s.result,function(e){i.buffer=e,i.panner.inputChannels(e.numberOfChannels),t&&t(i)})},s.onerror=function(t){onerror&&onerror(t)},s.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 this._whileLoading("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,a=this,u=c.audiocontext.currentTime,t=t||0;if(0>t&&(t=0),t+=u,!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 u=c.audiocontext.currentTime;this.bufferSourceNode.stop(t),this._counterNode.stop(t)}if(this.bufferSourceNode=this._initSourceNode(),this._counterNode&&(this._counterNode=void 0),this._counterNode=this._initCounterNode(),o){if(!(o>=0&&o0&&this.reversed&&this.reverseBuffer();if(this.bufferSourceNode){var n=c.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/h.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;en;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=h.currentTime,o=h.createBufferSource();return e._scopeNode&&(e._scopeNode.disconnect(),e._scopeNode.onaudioprocess=void 0,e._scopeNode=null),e._scopeNode=h.createScriptProcessor(256,1,1),o.buffer=p(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=h.currentTime,i=h.createBufferSource();return i.buffer=t.buffer,i.playbackRate.setValueAtTime(t.playbackRate,e),i};var p=function(t){for(var e=new Float32Array(t.length),i=h.createBuffer(1,t.length,44100),o=0;o=d);var u=o(f),c=s(u,n.sampleRate),h=c.sort(function(t,e){return e.count-t.count}).splice(0,5);this.tempo=h[0].tempo;var p=5,m=r(f,h[0].tempo,n.sampleRate,p);t(m)}};var l=function(t,e){this.sampleIndex=e,this.amplitude=t,this.tempos=[],this.intervals=[]},f=[];t.SoundFile.prototype.addCue=function(t,e,i){var o=this._cueIDCounter++,n=new d(e,t,o,i);return this._cues.push(n),o},t.SoundFile.prototype.removeCue=function(t){for(var e=this._cues.length,i=0;e>i;i++){var o=this._cues[i];o.id===t&&this.cues.splice(i,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=this._cues.length,o=0;i>o;o++){var n=this._cues[o],s=n.time,r=n.val;this._prevTime=s&&n.callback(r)}this._prevTime=e};var d=function(t,e,i,o){this.callback=t,this.time=e,this.id=i,this.val=o}}(e,n,i);var a;a=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),e.soundArray.push(this)},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;ea;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")},t.Amplitude.prototype.dispose=function(){var t=e.soundArray.indexOf(this);e.soundArray.splice(t,1),this.input.disconnect(),this.output.disconnect(),this.input=this.processor=void 0,this.output=void 0}}(i);var u;u=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],e.soundArray.push(this)},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;ni){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},t.FFT.prototype.dispose=function(){var t=e.soundArray.indexOf(this);e.soundArray.splice(t,1),this.analyser.disconnect(),this.analyser=void 0};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 c;c=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;e1)for(var e=1;e0)for(var t=this,e=0;e0)for(var t=1;ti){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;ee;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}(c);var l;l=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;o0?this.oscillator.frequency.exponentialRampToValueAtTime(t,o+i+n):this.oscillator.frequency.linearRampToValueAtTime(t,o+i+n),this.phaseAmount&&this.phase(this.phaseAmount)}},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(){var t=e.soundArray.indexOf(this);if(e.soundArray.splice(t,1),this.oscillator){var i=e.audiocontext.currentTime;this.stop(i),this.disconnect(),this.oscillator.disconnect(),this.panner=null,this.oscillator=null}this.osc2&&this.osc2.dispose()},t.Oscillator.prototype.phase=function(i){var o=t.prototype.map(i,0,1,0,1/this.f),n=e.audiocontext.currentTime;this.phaseAmount=i,this.dNode||(this.dNode=e.audiocontext.createDelay(),this.oscillator.disconnect(),this.oscillator.connect(this.dNode),this.dNode.connect(this.output)),this.dNode.delayTime.setValueAtTime(o,n)};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,i0&&(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,l,f,d,y);var g;g=function(){"use strict";var e=i,o=f,n=d,s=y,r=c;r.setContext(e.audiocontext),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],this.sourceToClear=null,this.wasTriggered=!1,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;tn;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,v);var _;_=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,i=e.soundArray.indexOf(this);e.soundArray.splice(i,1),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(t,i){var o=this;if(e.inputSources[o.currentSource]){var n=e.inputSources[o.currentSource].id,s={audio:{optional:[{sourceId:n}]}};window.navigator.getUserMedia(s,this._onStream=function(i){o.stream=i,o.enabled=!0,o.mediaStream=e.audiocontext.createMediaStreamSource(i),o.mediaStream.connect(o.output),t&&t(),o.amplitude.setInput(o.output)},this._onStreamError=function(t){i?i(t):console.error(t)})}else window.navigator.getUserMedia({audio:!0},this._onStream=function(i){o.stream=i,o.enabled=!0,o.mediaStream=e.audiocontext.createMediaStreamSource(i),o.mediaStream.connect(o.output),o.amplitude.setInput(o.output),t&&t()},this._onStreamError=function(t){i?i(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;e0?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=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.Filter.prototype.dispose=function(){var t=e.soundArray.indexOf(this);e.soundArray.splice(t,1),this.input.disconnect(),this.input=void 0,this.output.disconnect(),this.output=void 0,this.biquad.disconnect(),this.biquad=void 0},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._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,e.soundArray.push(this)},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()},t.Delay.prototype.dispose=function(){var t=e.soundArray.indexOf(this);e.soundArray.splice(t,1),this.input.disconnect(),this.output.disconnect(),this._split.disconnect(),this._leftFilter.disconnect(),this._rightFilter.disconnect(),this._merge.disconnect(),this._leftGain.disconnect(),this._rightGain.disconnect(),this.leftDelay.disconnect(),this.rightDelay.disconnect(),this.input=void 0,this.output=void 0,this._split=void 0,this._leftFilter=void 0,this._rightFilter=void 0,this._merge=void 0,this._leftGain=void 0,this._rightGain=void 0,this.leftDelay=void 0,this.rightDelay=void 0}}(i,A);var x;x=function(){"use strict";var e=i,o=n;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(){var t=e.soundArray.indexOf(this);e.soundArray.splice(t,1),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,o){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,o)):(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),t.prototype.createConvolver=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.Convolver(e,i,o);return n.impulses=[],n},t.Convolver.prototype._loadBuffer=function(e,i,n){var e=t.prototype._checkFileFormats(e),s=this,r=(new Error).stack,a=t.prototype.getAudioContext(),u=new XMLHttpRequest;u.open("GET",e,!0),u.responseType="arraybuffer",u.onload=function(){if(200==u.status)a.decodeAudioData(u.response,function(t){var o={},n=e.split("/");o.name=n[n.length-1],o.audioBuffer=t,s.impulses.push(o),s.convolverNode.buffer=o.audioBuffer,i&&i(o)},function(){var t=new o("decodeAudioData",r,s.url),e="AudioContext error at decodeAudioData for "+s.url;n?(t.msg=e,n(t)):console.error(e+"\n The error stack trace includes: \n"+t.stack)});else{var t=new o("loadConvolver",r,s.url),c="Unable to load "+s.url+". The request status was: "+u.status+" ("+u.statusText+")";n?(t.message=c,n(t)):console.error(c+"\n The error stack trace includes: \n"+t.stack)}},u.onerror=function(){var t=new o("loadConvolver",r,s.url),e="There was no response from the server at "+s.url+". Check the url and internet connectivity.";n?(t.message=e,n(t)):console.error(e+"\n The error stack trace includes: \n"+t.stack)},u.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,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"),this._loadBuffer(t,e,i)},t.Convolver.prototype.resetImpulse=function(t,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"),this.impulses=[],this._loadBuffer(t,e,i)},t.Convolver.prototype.toggleImpulse=function(t){if("number"==typeof t&&tr;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}(c);var P;P=function(){"use strict";var e=i,o=w,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=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.partSteps;)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();var t=n.soundArray.indexOf(this);n.soundArray.splice(t,1),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 N;N=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),e.soundArray.push(this)},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)},t.Gain.prototype.dispose=function(){var t=e.soundArray.indexOf(this);e.soundArray.splice(t,1),this.output.disconnect(),this.input.disconnect(),this.output=void 0,this.input=void 0}}(i,e);var V;V=function(){"use strict";var t=e;return t}(e,i,o,n,s,r,a,u,m,v,g,T,_,S,A,b,x,P,C,O,F,N)}); \ No newline at end of file +!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(p5){var sndcore;sndcore=function(){"use strict";!function(t,e,i){function n(t){t&&(t.setTargetAtTime||(t.setTargetAtTime=t.setTargetValueAtTime))}return e=e||{},window.hasOwnProperty("webkitAudioContext")&&!window.hasOwnProperty("AudioContext")&&(window.AudioContext=webkitAudioContext,AudioContext.prototype.hasOwnProperty("createGain")||(AudioContext.prototype.createGain=AudioContext.prototype.createGainNode),AudioContext.prototype.hasOwnProperty("createDelay")||(AudioContext.prototype.createDelay=AudioContext.prototype.createDelayNode),AudioContext.prototype.hasOwnProperty("createScriptProcessor")||(AudioContext.prototype.createScriptProcessor=AudioContext.prototype.createJavaScriptNode),AudioContext.prototype.hasOwnProperty("createPeriodicWave")||(AudioContext.prototype.createPeriodicWave=AudioContext.prototype.createWaveTable),AudioContext.prototype.internal_createGain=AudioContext.prototype.createGain,AudioContext.prototype.createGain=function(){var t=this.internal_createGain();return n(t.gain),t},AudioContext.prototype.internal_createDelay=AudioContext.prototype.createDelay,AudioContext.prototype.createDelay=function(t){var e=t?this.internal_createDelay(t):this.internal_createDelay();return n(e.delayTime),e},AudioContext.prototype.internal_createBufferSource=AudioContext.prototype.createBufferSource,AudioContext.prototype.createBufferSource=function(){var t=this.internal_createBufferSource();return t.start?(t.internal_start=t.start,t.start=function(e,i,n){"undefined"!=typeof n?t.internal_start(e||0,i,n):t.internal_start(e||0,i||0)}):t.start=function(t,e,i){e||i?this.noteGrainOn(t||0,e,i):this.noteOn(t||0)},t.stop?(t.internal_stop=t.stop,t.stop=function(e){t.internal_stop(e||0)}):t.stop=function(t){this.noteOff(t||0)},n(t.playbackRate),t},AudioContext.prototype.internal_createDynamicsCompressor=AudioContext.prototype.createDynamicsCompressor,AudioContext.prototype.createDynamicsCompressor=function(){var t=this.internal_createDynamicsCompressor();return n(t.threshold),n(t.knee),n(t.ratio),n(t.reduction),n(t.attack),n(t.release),t},AudioContext.prototype.internal_createBiquadFilter=AudioContext.prototype.createBiquadFilter,AudioContext.prototype.createBiquadFilter=function(){var t=this.internal_createBiquadFilter();return n(t.frequency),n(t.detune),n(t.Q),n(t.gain),t},AudioContext.prototype.hasOwnProperty("createOscillator")&&(AudioContext.prototype.internal_createOscillator=AudioContext.prototype.createOscillator,AudioContext.prototype.createOscillator=function(){var t=this.internal_createOscillator();return t.start?(t.internal_start=t.start,t.start=function(e){t.internal_start(e||0)}):t.start=function(t){this.noteOn(t||0)},t.stop?(t.internal_stop=t.stop,t.stop=function(e){t.internal_stop(e||0)}):t.stop=function(t){this.noteOff(t||0)},t.setPeriodicWave||(t.setPeriodicWave=t.setWaveTable),n(t.frequency),n(t.detune),t})),window.hasOwnProperty("webkitOfflineAudioContext")&&!window.hasOwnProperty("OfflineAudioContext")&&(window.OfflineAudioContext=webkitOfflineAudioContext),e}(window);var t=new window.AudioContext;p5.prototype.getAudioContext=function(){return t},navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia;var e=document.createElement("audio");p5.prototype.isSupported=function(){return!!e.canPlayType};var i=function(){return!!e.canPlayType&&e.canPlayType('audio/ogg; codecs="vorbis"')},n=function(){return!!e.canPlayType&&e.canPlayType("audio/mpeg;")},o=function(){return!!e.canPlayType&&e.canPlayType('audio/wav; codecs="1"')},r=function(){return!!e.canPlayType&&(e.canPlayType("audio/x-m4a;")||e.canPlayType("audio/aac;"))},s=function(){return!!e.canPlayType&&e.canPlayType("audio/x-aiff;")};p5.prototype.isFileSupported=function(t){switch(t.toLowerCase()){case"mp3":return n();case"wav":return o();case"ogg":return i();case"mp4":return r();case"aiff":return s();default:return!1}};var a=navigator.userAgent.match(/(iPad|iPhone|iPod)/g)?!0:!1;if(a){var u=!1,c=function(){if(!u){var e=t.createBuffer(1,1,22050),i=t.createBufferSource();i.buffer=e,i.connect(t.destination),i.start(0),console.log("start ios!"),"running"===t.state&&(u=!0)}};document.addEventListener("touchend",c,!1),document.addEventListener("touchstart",c,!1)}}();var master;master=function(){"use strict";var t=function(){var t=p5.prototype.getAudioContext();this.input=t.createGain(),this.output=t.createGain(),this.limiter=t.createDynamicsCompressor(),this.limiter.threshold.value=0,this.limiter.ratio.value=100,this.audiocontext=t,this.output.disconnect(),this.inputSources=[],this.input.connect(this.limiter),this.limiter.connect(this.output),this.meter=t.createGain(),this.fftMeter=t.createGain(),this.output.connect(this.meter),this.output.connect(this.fftMeter),this.output.connect(this.audiocontext.destination),this.soundArray=[],this.parts=[],this.extensions=[]},e=new t;return p5.prototype.getMasterVolume=function(){return e.output.gain.value},p5.prototype.masterVolume=function(t,i,n){if("number"==typeof t){var i=i||0,n=n||0,o=e.audiocontext.currentTime,r=e.output.gain.value;e.output.gain.cancelScheduledValues(o+n),e.output.gain.linearRampToValueAtTime(r,o+n),e.output.gain.linearRampToValueAtTime(t,o+n+i)}else{if(!t)return e.output.gain;t.connect(e.output.gain)}},p5.soundOut=e,p5.soundOut._silentNode=e.audiocontext.createGain(),p5.soundOut._silentNode.gain.value=0,p5.soundOut._silentNode.connect(e.audiocontext.destination),e}(sndcore);var helpers;helpers=function(){"use strict";var t=master;p5.prototype.sampleRate=function(){return t.audiocontext.sampleRate},p5.prototype.freqToMidi=function(t){var e=Math.log(t/440)/Math.log(2),i=Math.round(12*e)+57;return i},p5.prototype.midiToFreq=function(t){return 440*Math.pow(2,(t-69)/12)},p5.prototype.soundFormats=function(){t.extensions=[];for(var e=0;e-1))throw arguments[e]+" is not a valid sound format!";t.extensions.push(arguments[e])}},p5.prototype.disposeSound=function(){for(var e=0;e-1){var o=p5.prototype.isFileSupported(n);if(o)i=i;else for(var r=i.split("."),s=r[r.length-1],a=0;a1?(this.splitter=e.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=e.createChannelMerger(2),this.left.connect(this.output,0,1),this.right.connect(this.output,0,0),this.output.connect(i)},p5.Panner.prototype.pan=function(t,i){var n=i||0,o=e.currentTime+n,r=(t+1)/2,s=Math.cos(r*Math.PI/2),a=Math.sin(r*Math.PI/2);this.left.gain.linearRampToValueAtTime(a,o),this.right.gain.linearRampToValueAtTime(s,o)},p5.Panner.prototype.inputChannels=function(t){1===t?(this.input.disconnect(),this.input.connect(this.left),this.input.connect(this.right)):2===t&&(this.splitter=e.createChannelSplitter(2),this.input.disconnect(),this.input.connect(this.splitter),this.splitter.connect(this.left,1),this.splitter.connect(this.right,0))},p5.Panner.prototype.connect=function(t){this.output.connect(t)},p5.Panner.prototype.disconnect=function(t){this.output.disconnect()}),p5.Panner3D=function(t,i){var n=e.createPanner();return n.panningModel="HRTF",n.distanceModel="linear",n.setPosition(0,0,0),t.connect(n),n.connect(i),n.pan=function(t,e,i){n.setPosition(t,e,i)},n}}(master);var soundfile;soundfile=function(){"use strict";function t(t,e){for(var i={},n=t.length,o=0;n>o;o++){if(t[o]>e){var r=t[o],s=new c(r,o);i[o]=s,o+=6e3}o++}return i}function e(t){for(var e=[],i=Object.keys(t).sort(),n=0;no;o++){var r=t[i[n]],s=t[i[n+o]];if(r&&s){var a=r.sampleIndex,u=s.sampleIndex,c=u-a;c>0&&r.intervals.push(c);var p=e.some(function(t,e){return t.interval===c?(t.count++,t):void 0});p||e.push({interval:c,count:1})}}return e}function i(t,e){var i=[];return t.forEach(function(t,n){try{var r=Math.abs(60/(t.interval/e));r=o(r);var s=i.some(function(e){return e.tempo===r?e.count+=t.count:void 0});if(!s){if(isNaN(r))return;i.push({tempo:Math.round(r),count:t.count})}}catch(a){throw a}}),i}function n(t,e,i,n){for(var r=[],s=Object.keys(t).sort(),a=0;a.01?!0:void 0})}function o(t){if(isFinite(t)&&0!=t){for(;90>t;)t*=2;for(;t>180&&t>90;)t/=2;return t}}var r=errorHandler,s=master,a=s.audiocontext;p5.SoundFile=function(t,e,i,n){if("undefined"!=typeof t){if("string"==typeof t||"string"==typeof t[0]){var o=p5.prototype._checkFileFormats(t);this.url=o}else if("object"==typeof t&&!(window.File&&window.FileReader&&window.FileList&&window.Blob))throw"Unable to load file because the File API is not supported";t.file&&(t=t.file),this.file=t}this._onended=function(){},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=s.audiocontext.createGain(),this.output=s.audiocontext.createGain(),this.reversed=!1,this.startTime=0,this.endTime=null,this.pauseTime=0,this.mode="sustain",this.startMillis=null,this.panPosition=0,this.panner=new p5.Panner(this.output,s.input,2),(this.url||this.file)&&this.load(e,i),s.soundArray.push(this),"function"==typeof n?this._whileLoading=n:this._whileLoading=function(){}},p5.prototype.registerPreloadMethod("loadSound",p5.prototype),p5.prototype.loadSound=function(t,e,i,n){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 p5.SoundFile(t,e,i,n);return o},p5.SoundFile.prototype.load=function(t,e){var i=this,n=(new Error).stack;if(void 0!=this.url&&""!=this.url){var o=new XMLHttpRequest;o.addEventListener("progress",function(t){i._updateProgress(t)},!1),o.open("GET",this.url,!0),o.responseType="arraybuffer",o.onload=function(){if(200==o.status)a.decodeAudioData(o.response,function(e){i.buffer=e,i.panner.inputChannels(e.numberOfChannels),t&&t(i)},function(t){var o=new r("decodeAudioData",n,i.url),s="AudioContext error at decodeAudioData for "+i.url;e?(o.msg=s,e(o)):console.error(s+"\n The error stack trace includes: \n"+o.stack)});else{var s=new r("loadSound",n,i.url),u="Unable to load "+i.url+". The request status was: "+o.status+" ("+o.statusText+")";e?(s.message=u,e(s)):console.error(u+"\n The error stack trace includes: \n"+s.stack)}},o.onerror=function(t){var o=new r("loadSound",n,i.url),s="There was no response from the server at "+i.url+". Check the url and internet connectivity.";e?(o.message=s,e(o)):console.error(s+"\n The error stack trace includes: \n"+o.stack)},o.send()}else if(void 0!=this.file){var s=new FileReader,i=this;s.onload=function(){a.decodeAudioData(s.result,function(e){i.buffer=e,i.panner.inputChannels(e.numberOfChannels),t&&t(i)})},s.onerror=function(t){onerror&&onerror(t)},s.readAsArrayBuffer(this.file)}},p5.SoundFile.prototype._updateProgress=function(t){if(t.lengthComputable){var e=Math.log(t.loaded/t.total*9.9);this._whileLoading(e)}else this._whileLoading("size unknown")},p5.SoundFile.prototype.isLoaded=function(){return this.buffer?!0:!1},p5.SoundFile.prototype.play=function(t,e,i,n,o){var r,a,u=this,c=s.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=s.audiocontext.currentTime;this.bufferSourceNode.stop(t),this._counterNode.stop(t)}if(this.bufferSourceNode=this._initSourceNode(),this._counterNode&&(this._counterNode=void 0),this._counterNode=this._initCounterNode(),n){if(!(n>=0&&n0&&this.reversed&&this.reverseBuffer();if(this.bufferSourceNode){var o=s.audiocontext.currentTime;this.bufferSourceNode.playbackRate.cancelScheduledValues(o),this.bufferSourceNode.playbackRate.linearRampToValueAtTime(Math.abs(e),o),this._counterNode.playbackRate.cancelScheduledValues(o),this._counterNode.playbackRate.linearRampToValueAtTime(Math.abs(e),o)}}},p5.SoundFile.prototype.setPitch=function(t){var e=midiToFreq(t)/midiToFreq(60);this.rate(e)},p5.SoundFile.prototype.getPlaybackRate=function(){return this.playbackRate},p5.SoundFile.prototype.duration=function(){return this.buffer?this.buffer.duration:0},p5.SoundFile.prototype.currentTime=function(){return this._pauseTime>0?this._pauseTime:this._lastPos/a.sampleRate},p5.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,n=e||this.buffer.duration-t;this.isPlaying()&&this.stop(),this.play(0,this.playbackRate,this.output.gain.value,i,n)},p5.SoundFile.prototype.channels=function(){return this.buffer.numberOfChannels},p5.SoundFile.prototype.sampleRate=function(){return this.buffer.sampleRate},p5.SoundFile.prototype.frames=function(){return this.buffer.length},p5.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,n=~~(i/10)||1,o=e.numberOfChannels,r=new Float32Array(Math.round(t)),s=0;o>s;s++)for(var a=e.getChannelData(s),u=0;t>u;u++){for(var c=~~(u*i),p=~~(c+i),h=0,l=c;p>l;l+=n){var d=a[l];d>h?h=d:-d>h&&(h=d)}(0===s||Math.abs(h)>r[u])&&(r[u]=h)}return r}},p5.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;eo;o++){var r=n.getChannelData(o);r.set(t[o])}this.buffer=n,this.panner.inputChannels(e)},p5.SoundFile.prototype._initCounterNode=function(){var t=this,e=a.currentTime,i=a.createBufferSource();return t._scopeNode&&(t._scopeNode.disconnect(),t._scopeNode.onaudioprocess=void 0,t._scopeNode=null),t._scopeNode=a.createScriptProcessor(256,1,1),i.buffer=u(t.buffer),i.playbackRate.setValueAtTime(t.playbackRate,e),i.connect(t._scopeNode),t._scopeNode.connect(p5.soundOut._silentNode),t._scopeNode.onaudioprocess=function(e){var i=e.inputBuffer.getChannelData(0);t._lastPos=i[i.length-1]||0,t._onTimeUpdate(t._lastPos)},i},p5.SoundFile.prototype._initSourceNode=function(){var t=this,e=a.currentTime,i=a.createBufferSource();return i.buffer=t.buffer,i.playbackRate.setValueAtTime(t.playbackRate,e),i};var u=function(t){for(var e=new Float32Array(t.length),i=a.createBuffer(1,t.length,44100),n=0;n=f);var u=e(p),c=i(u,s.sampleRate),h=c.sort(function(t,e){return e.count-t.count}).splice(0,5);this.tempo=h[0].tempo;var l=5,y=n(p,h[0].tempo,s.sampleRate,l);o(y)}};var c=function(t,e){this.sampleIndex=e,this.amplitude=t,this.tempos=[],this.intervals=[]},p=[];p5.SoundFile.prototype.addCue=function(t,e,i){var n=this._cueIDCounter++,o=new h(e,t,n,i);return this._cues.push(o),n},p5.SoundFile.prototype.removeCue=function(t){for(var e=this._cues.length,i=0;e>i;i++){var n=this._cues[i];n.id===t&&this.cues.splice(i,1)}0===this._cues.length},p5.SoundFile.prototype.clearCues=function(){this._cues=[]},p5.SoundFile.prototype._onTimeUpdate=function(t){for(var e=t/this.buffer.sampleRate,i=this._cues.length,n=0;i>n;n++){var o=this._cues[n],r=o.time,s=o.val;this._prevTime=r&&o.callback(s)}this._prevTime=e};var h=function(t,e,i,n){this.callback=t,this.time=e,this.id=i,this.val=n}}(sndcore,errorHandler,master);var amplitude;amplitude=function(){"use strict";var t=master;p5.Amplitude=function(e){this.bufferSize=2048,this.audiocontext=t.audiocontext,this.processor=this.audiocontext.createScriptProcessor(this.bufferSize,2,1),this.input=this.processor,this.output=this.audiocontext.createGain(),this.smoothing=e||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),t.meter.connect(this.processor),t.soundArray.push(this)},p5.Amplitude.prototype.setInput=function(e,i){t.meter.disconnect(),i&&(this.smoothing=i),null==e?(console.log("Amplitude input source is not ready! Connecting to master output instead"),t.meter.connect(this.processor)):e instanceof p5.Signal?e.output.connect(this.processor):e?(e.connect(this.processor),this.processor.disconnect(),this.processor.connect(this.output)):t.meter.connect(this.processor)},p5.Amplitude.prototype.connect=function(e){e?e.hasOwnProperty("input")?this.output.connect(e.input):this.output.connect(e):this.output.connect(this.panner.connect(t.input))},p5.Amplitude.prototype.disconnect=function(t){this.output.disconnect()},p5.Amplitude.prototype._audioProcess=function(t){for(var e=0;ea;a++)i=n[a],this.normalize?(r+=Math.max(Math.min(i/this.volMax,1),-1),s+=Math.max(Math.min(i/this.volMax,1),-1)*Math.max(Math.min(i/this.volMax,1),-1)):(r+=i,s+=i*i);var u=r/o,c=Math.sqrt(s/o);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 p=this,h=this.stereoVol.reduce(function(t,e,i){return p.stereoVolNorm[i-1]=Math.max(Math.min(p.stereoVol[i-1]/p.volMax,1),0),p.stereoVolNorm[i]=Math.max(Math.min(p.stereoVol[i]/p.volMax,1),0),t+e});this.volume=h/this.stereoVol.length,this.volNorm=Math.max(Math.min(this.volume/this.volMax,1),0)},p5.Amplitude.prototype.getLevel=function(t){return"undefined"!=typeof t?this.normalize?this.stereoVolNorm[t]:this.stereoVol[t]:this.normalize?this.volNorm:this.volume},p5.Amplitude.prototype.toggleNormalize=function(t){"boolean"==typeof t?this.normalize=t:this.normalize=!this.normalize},p5.Amplitude.prototype.smooth=function(t){t>=0&&1>t?this.smoothing=t:console.log("Error: smoothing must be between 0 and 1")},p5.Amplitude.prototype.dispose=function(){var e=t.soundArray.indexOf(this);t.soundArray.splice(e,1),this.input.disconnect(),this.output.disconnect(),this.input=this.processor=void 0,this.output=void 0}}(master);var fft;fft=function(){"use strict";var t=master;p5.FFT=function(e,i){this.smoothing=e||.8,this.bins=i||1024;var n=2*i||2048;this.input=this.analyser=t.audiocontext.createAnalyser(),t.fftMeter.connect(this.analyser),this.analyser.smoothingTimeConstant=this.smoothing,this.analyser.fftSize=n,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.soundArray.push(this)},p5.FFT.prototype.setInput=function(e){e?(e.output?e.output.connect(this.analyser):e.connect&&e.connect(this.analyser),t.fftMeter.disconnect()):t.fftMeter.connect(this.analyser)},p5.FFT.prototype.waveform=function(){for(var t,e,i,r=0;ri){var o=i;i=e,e=o}for(var r=Math.round(e/n*this.freqDomain.length),s=Math.round(i/n*this.freqDomain.length),a=0,u=0,c=r;s>=c;c++)a+=this.freqDomain[c],u+=1;var p=a/u;return p}throw"invalid input for getEnergy()"}var h=Math.round(e/n*this.freqDomain.length);return this.freqDomain[h]},p5.FFT.prototype.getFreq=function(t,e){console.log("getFreq() is deprecated. Please use getEnergy() instead.");var i=this.getEnergy(t,e);return i},p5.FFT.prototype.getCentroid=function(){for(var e=t.audiocontext.sampleRate/2,i=0,n=0,o=0;o1&&(this.input=new Array(e)),t(i)||1===i?this.output=this.context.createGain():i>1&&(this.output=new Array(e))};n.prototype.set=function(e,i,o){if(this.isObject(e))o=i;else if(this.isString(e)){var r={};r[e]=i,e=r}for(var s in e){i=e[s];var a=this;if(-1!==s.indexOf(".")){for(var u=s.split("."),c=0;c1)for(var t=arguments[0],e=1;e1)for(var e=1;e0)for(var t=this,e=0;e0)for(var t=0;te;e++){var n=e/i*2-1;this._curve[e]=t(n,e)}return this._shaper.curve=this._curve,this},Object.defineProperty(t.WaveShaper.prototype,"curve",{get:function(){return this._shaper.curve},set:function(t){this._curve=new Float32Array(t),this._shaper.curve=this._curve}}),Object.defineProperty(t.WaveShaper.prototype,"oversample",{get:function(){return this._shaper.oversample},set:function(t){if(-1===["none","2x","4x"].indexOf(t))throw new Error("invalid oversampling: "+t);this._shaper.oversample=t}}),t.WaveShaper.prototype.dispose=function(){return t.prototype.dispose.call(this),this._shaper.disconnect(),this._shaper=null,this._curve=null,this},t.WaveShaper}(Tone_core_Tone);var Tone_core_Type;Tone_core_Type=function(Tone){"use strict";function getTransportBpm(){return Tone.Transport&&Tone.Transport.bpm?Tone.Transport.bpm.value:120}function getTransportTimeSignature(){return Tone.Transport&&Tone.Transport.timeSignature?Tone.Transport.timeSignature:4}function toNotationHelper(t,e,i,n){for(var o=this.toSeconds(t),r=this.notationToSeconds(n[n.length-1],e,i),s="",a=0;a1-c%1&&(c+=p),c=Math.floor(c),c>0){if(s+=1===c?n[a]:c.toString()+"*"+n[a],o-=c*u,r>o)break;s+=" + "}}return""===s&&(s="0"),s}Tone.Type={Default:"number",Time:"time",Frequency:"frequency",NormalRange:"normalRange",AudioRange:"audioRange",Decibels:"db",Interval:"interval",BPM:"bpm",Positive:"positive",Cents:"cents",Degrees:"degrees",MIDI:"midi",TransportTime:"transportTime",Ticks:"tick",Note:"note",Milliseconds:"milliseconds",Notation:"notation"},Tone.prototype.isNowRelative=function(){var t=new RegExp(/^\s*\+(.)+/i);return function(e){return t.test(e)}}(),Tone.prototype.isTicks=function(){var t=new RegExp(/^\d+i$/i);return function(e){return t.test(e)}}(),Tone.prototype.isNotation=function(){var t=new RegExp(/^[0-9]+[mnt]$/i);return function(e){return t.test(e)}}(),Tone.prototype.isTransportTime=function(){var t=new RegExp(/^(\d+(\.\d+)?\:){1,2}(\d+(\.\d+)?)?$/i);return function(e){return t.test(e)}}(),Tone.prototype.isNote=function(){var t=new RegExp(/^[a-g]{1}(b|#|x|bb)?-?[0-9]+$/i);return function(e){return t.test(e)}}(),Tone.prototype.isFrequency=function(){var t=new RegExp(/^\d*\.?\d+hz$/i);return function(e){return t.test(e)}}(),Tone.prototype.notationToSeconds=function(t,e,i){e=this.defaultArg(e,getTransportBpm()),i=this.defaultArg(i,getTransportTimeSignature());var n=60/e;"1n"===t&&(t="1m");var o=parseInt(t,10),r=0;0===o&&(r=0);var s=t.slice(-1);return r="t"===s?4/o*2/3:"n"===s?4/o:"m"===s?o*i:0,n*r},Tone.prototype.transportTimeToSeconds=function(t,e,i){e=this.defaultArg(e,getTransportBpm()),i=this.defaultArg(i,getTransportTimeSignature());var n=0,o=0,r=0,s=t.split(":");2===s.length?(n=parseFloat(s[0]),o=parseFloat(s[1])):1===s.length?o=parseFloat(s[0]):3===s.length&&(n=parseFloat(s[0]),o=parseFloat(s[1]),r=parseFloat(s[2]));var a=n*i+o+r/4;return a*(60/e)},Tone.prototype.ticksToSeconds=function(t,e){if(this.isUndef(Tone.Transport))return 0;t=parseFloat(t),e=this.defaultArg(e,getTransportBpm());var i=60/e/Tone.Transport.PPQ;return i*t},Tone.prototype.frequencyToSeconds=function(t){return 1/parseFloat(t)},Tone.prototype.samplesToSeconds=function(t){return t/this.context.sampleRate},Tone.prototype.secondsToSamples=function(t){return t*this.context.sampleRate},Tone.prototype.secondsToTransportTime=function(t,e,i){e=this.defaultArg(e,getTransportBpm()),i=this.defaultArg(i,getTransportTimeSignature());var n=60/e,o=t/n,r=Math.floor(o/i),s=o%1*4;o=Math.floor(o)%i;var a=[r,o,s];return a.join(":")},Tone.prototype.secondsToFrequency=function(t){return 1/t},Tone.prototype.toTransportTime=function(t,e,i){var n=this.toSeconds(t);return this.secondsToTransportTime(n,e,i)},Tone.prototype.toFrequency=function(t,e){return this.isFrequency(t)?parseFloat(t):this.isNotation(t)||this.isTransportTime(t)?this.secondsToFrequency(this.toSeconds(t,e)):this.isNote(t)?this.noteToFrequency(t):t},Tone.prototype.toTicks=function(t){if(this.isUndef(Tone.Transport))return 0;var e=Tone.Transport.bpm.value,i=0;if(this.isNowRelative(t))t=t.replace("+",""),i=Tone.Transport.ticks;else if(this.isUndef(t))return Tone.Transport.ticks;var n=this.toSeconds(t),o=60/e,r=n/o,s=r*Tone.Transport.PPQ;return Math.round(s+i)},Tone.prototype.toSamples=function(t){var e=this.toSeconds(t);return Math.round(e*this.context.sampleRate)},Tone.prototype.toSeconds=function(time,now){if(now=this.defaultArg(now,this.now()),this.isNumber(time))return time;if(this.isString(time)){var plusTime=0;this.isNowRelative(time)&&(time=time.replace("+",""),plusTime=now);var betweenParens=time.match(/\(([^)(]+)\)/g);if(betweenParens)for(var j=0;j0&&(toQuantize="+"+toQuantize,plusTime=0);var subdivision=quantizationSplit[1].trim();time=Tone.Transport.quantize(toQuantize,subdivision)}else{var components=time.split(/[\(\)\-\+\/\*]/);if(components.length>1){for(var originalTime=time,i=0;in&&(i+=-12*n);var o=scaleIndexToNote[i%12];return o+n.toString()},Tone.prototype.intervalToFrequencyRatio=function(t){return Math.pow(2,t/12)},Tone.prototype.midiToNote=function(t){var e=Math.floor(t/12)-1,i=t%12;return scaleIndexToNote[i]+e},Tone.prototype.noteToMidi=function(t){var e=t.split(/(\d+)/);if(3===e.length){var i=noteToScaleIndex[e[0].toLowerCase()],n=e[1];return i+12*(parseInt(n,10)+1)}return 0},Tone.prototype.midiToFrequency=function(t){return Tone.A4*Math.pow(2,(t-69)/12)},Tone}(Tone_core_Tone);var Tone_core_Param;Tone_core_Param=function(t){"use strict";return t.Param=function(){var e=this.optionsObject(arguments,["param","units","convert"],t.Param.defaults);this._param=this.input=e.param,this.units=e.units,this.convert=e.convert,this.overridden=!1,this.isUndef(e.value)||(this.value=e.value)},t.extend(t.Param),t.Param.defaults={units:t.Type.Default,convert:!0,param:void 0},Object.defineProperty(t.Param.prototype,"value",{get:function(){return this._toUnits(this._param.value)},set:function(t){var e=this._fromUnits(t);this._param.value=e}}),t.Param.prototype._fromUnits=function(e){if(!this.convert&&!this.isUndef(this.convert))return e;switch(this.units){case t.Type.Time:return this.toSeconds(e);case t.Type.Frequency:return this.toFrequency(e);case t.Type.Decibels:return this.dbToGain(e);case t.Type.NormalRange:return Math.min(Math.max(e,0),1);case t.Type.AudioRange:return Math.min(Math.max(e,-1),1);case t.Type.Positive:return Math.max(e,0);default:return e}},t.Param.prototype._toUnits=function(e){if(!this.convert&&!this.isUndef(this.convert))return e;switch(this.units){case t.Type.Decibels:return this.gainToDb(e);default:return e}},t.Param.prototype._minOutput=1e-5,t.Param.prototype.setValueAtTime=function(t,e){return t=this._fromUnits(t),this._param.setValueAtTime(t,this.toSeconds(e)),this},t.Param.prototype.setRampPoint=function(t){t=this.defaultArg(t,this.now());var e=this._param.value;return this._param.setValueAtTime(e,t),this},t.Param.prototype.linearRampToValueAtTime=function(t,e){return t=this._fromUnits(t),this._param.linearRampToValueAtTime(t,this.toSeconds(e)),this},t.Param.prototype.exponentialRampToValueAtTime=function(t,e){return t=this._fromUnits(t),t=Math.max(this._minOutput,t),this._param.exponentialRampToValueAtTime(t,this.toSeconds(e)),this},t.Param.prototype.exponentialRampToValue=function(t,e){var i=this.now(),n=this.value;return this.setValueAtTime(Math.max(n,this._minOutput),i),this.exponentialRampToValueAtTime(t,i+this.toSeconds(e)),this},t.Param.prototype.linearRampToValue=function(t,e){var i=this.now();return this.setRampPoint(i),this.linearRampToValueAtTime(t,i+this.toSeconds(e)),this},t.Param.prototype.setTargetAtTime=function(t,e,i){return t=this._fromUnits(t),t=Math.max(this._minOutput,t),i=Math.max(this._minOutput,i),this._param.setTargetAtTime(t,this.toSeconds(e),i),this},t.Param.prototype.setValueCurveAtTime=function(t,e,i){for(var n=0;n0?this.oscillator.frequency.exponentialRampToValueAtTime(e,n+i+o):this.oscillator.frequency.linearRampToValueAtTime(e,n+i+o),this.phaseAmount&&this.phase(this.phaseAmount)}},p5.Oscillator.prototype.getFreq=function(){return this.oscillator.frequency.value},p5.Oscillator.prototype.setType=function(t){this.oscillator.type=t},p5.Oscillator.prototype.getType=function(){return this.oscillator.type},p5.Oscillator.prototype.connect=function(e){e?e.hasOwnProperty("input")?(this.panner.connect(e.input),this.connection=e.input):(this.panner.connect(e),this.connection=e):this.panner.connect(t.input)},p5.Oscillator.prototype.disconnect=function(t){this.output.disconnect(),this.panner.disconnect(),this.output.connect(this.panner),this.oscMods=[]},p5.Oscillator.prototype.pan=function(t,e){this.panPosition=t,this.panner.pan(t,e)},p5.Oscillator.prototype.getPan=function(){return this.panPosition},p5.Oscillator.prototype.dispose=function(){var e=t.soundArray.indexOf(this);if(t.soundArray.splice(e,1),this.oscillator){var i=t.audiocontext.currentTime;this.stop(i),this.disconnect(),this.oscillator.disconnect(),this.panner=null,this.oscillator=null}this.osc2&&this.osc2.dispose()},p5.Oscillator.prototype.phase=function(e){var i=p5.prototype.map(e,0,1,0,1/this.f),n=t.audiocontext.currentTime;this.phaseAmount=e,this.dNode||(this.dNode=t.audiocontext.createDelay(),this.oscillator.disconnect(),this.oscillator.connect(this.dNode),this.dNode.connect(this.output)),this.dNode.delayTime.setValueAtTime(i,n)};var o=function(t,e,i,n,o){var r=t.oscillator;for(var s in t.mathOps)t.mathOps[s]instanceof o&&(r.disconnect(),t.mathOps[s].dispose(),i=s,i0&&(r=t.mathOps[s-1]),r.disconnect(),r.connect(e),e.connect(n),t.mathOps[i]=e,t};p5.Oscillator.prototype.add=function(t){var i=new e(t),n=this.mathOps.length-1,r=this.output;return o(this,i,n,r,e)},p5.Oscillator.prototype.mult=function(t){var e=new i(t),n=this.mathOps.length-1,r=this.output;return o(this,e,n,r,i)},p5.Oscillator.prototype.scale=function(t,e,i,r){var s,a;4===arguments.length?(s=p5.prototype.map(i,t,e,0,1)-.5,a=p5.prototype.map(r,t,e,0,1)-.5):(s=arguments[0],a=arguments[1]);var u=new n(s,a),c=this.mathOps.length-1,p=this.output;return o(this,u,c,p,n)},p5.SinOsc=function(t){p5.Oscillator.call(this,t,"sine")},p5.SinOsc.prototype=Object.create(p5.Oscillator.prototype),p5.TriOsc=function(t){p5.Oscillator.call(this,t,"triangle")},p5.TriOsc.prototype=Object.create(p5.Oscillator.prototype),p5.SawOsc=function(t){p5.Oscillator.call(this,t,"sawtooth")},p5.SawOsc.prototype=Object.create(p5.Oscillator.prototype),p5.SqrOsc=function(t){p5.Oscillator.call(this,t,"square")},p5.SqrOsc.prototype=Object.create(p5.Oscillator.prototype)}(master,Tone_signal_Signal,Tone_signal_Add,Tone_signal_Multiply,Tone_signal_Scale);var Tone_core_Timeline;Tone_core_Timeline=function(t){"use strict";return t.Timeline=function(){var e=this.optionsObject(arguments,["memory"],t.Timeline.defaults);this._timeline=[],this._toRemove=[],this._iterating=!1,this.memory=e.memory},t.extend(t.Timeline),t.Timeline.defaults={memory:1/0},Object.defineProperty(t.Timeline.prototype,"length",{get:function(){return this._timeline.length}}),t.Timeline.prototype.addEvent=function(t){if(this.isUndef(t.time))throw new Error("events must have a time attribute");if(t.time=this.toSeconds(t.time),this._timeline.length){var e=this._search(t.time);this._timeline.splice(e+1,0,t)}else this._timeline.push(t);if(this.length>this.memory){var i=this.length-this.memory;this._timeline.splice(0,i)}return this},t.Timeline.prototype.removeEvent=function(t){if(this._iterating)this._toRemove.push(t);else{var e=this._timeline.indexOf(t);-1!==e&&this._timeline.splice(e,1)}return this},t.Timeline.prototype.getEvent=function(t){t=this.toSeconds(t);var e=this._search(t);return-1!==e?this._timeline[e]:null},t.Timeline.prototype.getEventAfter=function(t){t=this.toSeconds(t);var e=this._search(t);return e+1=0?this._timeline[e-1]:null},t.Timeline.prototype.cancel=function(t){if(this._timeline.length>1){t=this.toSeconds(t);var e=this._search(t);e>=0?this._timeline=this._timeline.slice(0,e):this._timeline=[]}else 1===this._timeline.length&&this._timeline[0].time>=t&&(this._timeline=[]);return this},t.Timeline.prototype.cancelBefore=function(t){if(this._timeline.length){t=this.toSeconds(t);var e=this._search(t);e>=0&&(this._timeline=this._timeline.slice(e+1))}return this},t.Timeline.prototype._search=function(t){for(var e=0,i=this._timeline.length,n=i;n>=e&&i>e;){var o=Math.floor(e+(n-e)/2),r=this._timeline[o];if(r.time===t){for(var s=o;st?n=o-1:r.time=n;n++)t(this._timeline[n]);if(this._iterating=!1,this._toRemove.length>0){for(var o=0;o=0&&this._timeline[i].time>=t;)i--;return this._iterate(e,i+1),this},t.Timeline.prototype.forEachAtTime=function(t,e){t=this.toSeconds(t);var i=this._search(t);return-1!==i&&this._iterate(function(i){i.time===t&&e(i)},0,i),this},t.Timeline.prototype.dispose=function(){t.prototype.dispose.call(this),this._timeline=null,this._toRemove=null},t.Timeline}(Tone_core_Tone);var Tone_signal_TimelineSignal;Tone_signal_TimelineSignal=function(t){"use strict";return t.TimelineSignal=function(){var e=this.optionsObject(arguments,["value","units"],t.Signal.defaults);t.Signal.apply(this,e),e.param=this._param,t.Param.call(this,e),this._events=new t.Timeline(10),this._initial=this._fromUnits(this._param.value)},t.extend(t.TimelineSignal,t.Param),t.TimelineSignal.Type={Linear:"linear",Exponential:"exponential",Target:"target",Set:"set"},Object.defineProperty(t.TimelineSignal.prototype,"value",{get:function(){return this._toUnits(this._param.value)},set:function(t){var e=this._fromUnits(t);this._initial=e,this._param.value=e}}),t.TimelineSignal.prototype.setValueAtTime=function(e,i){return e=this._fromUnits(e),i=this.toSeconds(i),this._events.addEvent({type:t.TimelineSignal.Type.Set,value:e,time:i}),this._param.setValueAtTime(e,i),this},t.TimelineSignal.prototype.linearRampToValueAtTime=function(e,i){return e=this._fromUnits(e),i=this.toSeconds(i),this._events.addEvent({type:t.TimelineSignal.Type.Linear,value:e,time:i}),this._param.linearRampToValueAtTime(e,i),this},t.TimelineSignal.prototype.exponentialRampToValueAtTime=function(e,i){return e=this._fromUnits(e),e=Math.max(this._minOutput,e),i=this.toSeconds(i),this._events.addEvent({type:t.TimelineSignal.Type.Exponential,value:e,time:i}),this._param.exponentialRampToValueAtTime(e,i),this},t.TimelineSignal.prototype.setTargetAtTime=function(e,i,n){return e=this._fromUnits(e),e=Math.max(this._minOutput,e),n=Math.max(this._minOutput,n),i=this.toSeconds(i),this._events.addEvent({type:t.TimelineSignal.Type.Target, +value:e,time:i,constant:n}),this._param.setTargetAtTime(e,i,n),this},t.TimelineSignal.prototype.cancelScheduledValues=function(t){return this._events.cancel(t),this._param.cancelScheduledValues(this.toSeconds(t)),this},t.TimelineSignal.prototype.setRampPoint=function(e){e=this.toSeconds(e);var i=this.getValueAtTime(e),n=this._searchAfter(e);return n&&(this.cancelScheduledValues(e),n.type===t.TimelineSignal.Type.Linear?this.linearRampToValueAtTime(i,e):n.type===t.TimelineSignal.Type.Exponential&&this.exponentialRampToValueAtTime(i,e)),this.setValueAtTime(i,e),this},t.TimelineSignal.prototype.linearRampToValueBetween=function(t,e,i){return this.setRampPoint(e),this.linearRampToValueAtTime(t,i),this},t.TimelineSignal.prototype.exponentialRampToValueBetween=function(t,e,i){return this.setRampPoint(e),this.exponentialRampToValueAtTime(t,i),this},t.TimelineSignal.prototype._searchBefore=function(t){return this._events.getEvent(t)},t.TimelineSignal.prototype._searchAfter=function(t){return this._events.getEventAfter(t)},t.TimelineSignal.prototype.getValueAtTime=function(e){var i=this._searchAfter(e),n=this._searchBefore(e),o=this._initial;if(null===n)o=this._initial;else if(n.type===t.TimelineSignal.Type.Target){var r,s=this._events.getEventBefore(n.time);r=null===s?this._initial:s.value,o=this._exponentialApproach(n.time,r,n.value,n.constant,e)}else o=null===i?n.value:i.type===t.TimelineSignal.Type.Linear?this._linearInterpolate(n.time,n.value,i.time,i.value,e):i.type===t.TimelineSignal.Type.Exponential?this._exponentialInterpolate(n.time,n.value,i.time,i.value,e):n.value;return o},t.TimelineSignal.prototype.connect=t.SignalBase.prototype.connect,t.TimelineSignal.prototype._exponentialApproach=function(t,e,i,n,o){return i+(e-i)*Math.exp(-(o-t)/n)},t.TimelineSignal.prototype._linearInterpolate=function(t,e,i,n,o){return e+(n-e)*((o-t)/(i-t))},t.TimelineSignal.prototype._exponentialInterpolate=function(t,e,i,n,o){return e=Math.max(this._minOutput,e),e*Math.pow(n/e,(o-t)/(i-t))},t.TimelineSignal.prototype.dispose=function(){t.Signal.prototype.dispose.call(this),t.Param.prototype.dispose.call(this),this._events.dispose(),this._events=null},t.TimelineSignal}(Tone_core_Tone,Tone_signal_Signal);var env;env=function(){"use strict";var t=master,e=Tone_signal_Add,i=Tone_signal_Multiply,n=Tone_signal_Scale,o=Tone_signal_TimelineSignal,r=Tone_core_Tone;r.setContext(t.audiocontext),p5.Env=function(e,i,n,r,s,a){t.audiocontext.currentTime;this.aTime=e||.1,this.aLevel=i||1,this.dTime=n||.5,this.dLevel=r||0,this.rTime=s||0,this.rLevel=a||0,this._rampHighPercentage=.98,this._rampLowPercentage=.02,this.output=t.audiocontext.createGain(),this.control=new o,this._init(),this.control.connect(this.output),this.connection=null,this.mathOps=[this.control],this.isExponential=!1,this.sourceToClear=null,this.wasTriggered=!1,t.soundArray.push(this)},p5.Env.prototype._init=function(){var e=t.audiocontext.currentTime,i=e;this.control.setTargetAtTime(1e-5,i,.001),this._setRampAD(this.aTime,this.dTime)},p5.Env.prototype.set=function(t,e,i,n,o,r){this.aTime=t,this.aLevel=e,this.dTime=i||0,this.dLevel=n||0,this.rTime=t4||0,this.rLevel=l4||0,this._setRampAD(t,i)},p5.Env.prototype.setADSR=function(t,e,i,n){this.aTime=t,this.dTime=e||0,this.sPercent=i||0,this.dLevel="undefined"!=typeof i?i*(this.aLevel-this.rLevel)+this.rLevel:0,this.rTime=n||0,this._setRampAD(t,e)},p5.Env.prototype.setRange=function(t,e){this.aLevel=t||1,this.rLevel=e||0},p5.Env.prototype._setRampAD=function(t,e){this._rampAttackTime=this.checkExpInput(t),this._rampDecayTime=this.checkExpInput(e);var i=1;i=Math.log(1/this.checkExpInput(1-this._rampHighPercentage)),this._rampAttackTC=t/this.checkExpInput(i),i=Math.log(1/this._rampLowPercentage),this._rampDecayTC=e/this.checkExpInput(i)},p5.Env.prototype.setRampPercentages=function(t,e){this._rampHighPercentage=this.checkExpInput(t),this._rampLowPercentage=this.checkExpInput(e);var i=1;i=Math.log(1/this.checkExpInput(1-this._rampHighPercentage)),this._rampAttackTC=this._rampAttackTime/this.checkExpInput(i),i=Math.log(1/this._rampLowPercentage),this._rampDecayTC=this._rampDecayTime/this.checkExpInput(i)},p5.Env.prototype.setInput=function(t){for(var e=0;e=t&&(t=1e-4),t},p5.Env.prototype.play=function(e,i,n){var o=(t.audiocontext.currentTime,i||0),n=n||0;e&&this.connection!==e&&this.connect(e),this.triggerAttack(e,o),this.triggerRelease(e,o+this.aTime+this.dTime+n)},p5.Env.prototype.triggerAttack=function(e,i){var n=t.audiocontext.currentTime,o=i||0,r=n+o;this.lastAttack=r,this.wasTriggered=!0,e&&this.connection!==e&&this.connect(e);var s=this.control.getValueAtTime(r);this.control.cancelScheduledValues(r),1==this.isExponential?this.control.exponentialRampToValueAtTime(this.checkExpInput(s),r):this.control.linearRampToValueAtTime(s,r),r+=this.aTime,1==this.isExponential?(this.control.exponentialRampToValueAtTime(this.checkExpInput(this.aLevel),r),s=this.checkExpInput(this.control.getValueAtTime(r)),this.control.cancelScheduledValues(r),this.control.exponentialRampToValueAtTime(s,r)):(this.control.linearRampToValueAtTime(this.aLevel,r),s=this.control.getValueAtTime(r),this.control.cancelScheduledValues(r),this.control.linearRampToValueAtTime(s,r)),r+=this.dTime,1==this.isExponential?(this.control.exponentialRampToValueAtTime(this.checkExpInput(this.dLevel),r),s=this.checkExpInput(this.control.getValueAtTime(r)),this.control.cancelScheduledValues(r),this.control.exponentialRampToValueAtTime(s,r)):(this.control.linearRampToValueAtTime(this.dLevel,r),s=this.control.getValueAtTime(r),this.control.cancelScheduledValues(r),this.control.linearRampToValueAtTime(s,r))},p5.Env.prototype.triggerRelease=function(e,i){if(this.wasTriggered){var n=t.audiocontext.currentTime,o=i||0,r=n+o;e&&this.connection!==e&&this.connect(e);var s=this.control.getValueAtTime(r);this.control.cancelScheduledValues(r),1==this.isExponential?this.control.exponentialRampToValueAtTime(this.checkExpInput(s),r):this.control.linearRampToValueAtTime(s,r),r+=this.rTime,1==this.isExponential?(this.control.exponentialRampToValueAtTime(this.checkExpInput(this.rLevel),r),s=this.checkExpInput(this.control.getValueAtTime(r)),this.control.cancelScheduledValues(r),this.control.exponentialRampToValueAtTime(s,r)):(this.control.linearRampToValueAtTime(this.rLevel,r),s=this.control.getValueAtTime(r),this.control.cancelScheduledValues(r),this.control.linearRampToValueAtTime(s,r)),this.wasTriggered=!1}},p5.Env.prototype.ramp=function(e,i,n,o){var r=t.audiocontext.currentTime,s=i||0,a=r+s,u=this.checkExpInput(n),c="undefined"!=typeof o?this.checkExpInput(o):void 0;e&&this.connection!==e&&this.connect(e);var p=this.checkExpInput(this.control.getValueAtTime(a));this.control.cancelScheduledValues(a),u>p?(this.control.setTargetAtTime(u,a,this._rampAttackTC),a+=this._rampAttackTime):p>u&&(this.control.setTargetAtTime(u,a,this._rampDecayTC),a+=this._rampDecayTime),void 0!==c&&(c>u?this.control.setTargetAtTime(c,a,this._rampAttackTC):u>c&&this.control.setTargetAtTime(c,a,this._rampDecayTC))},p5.Env.prototype.connect=function(e){this.connection=e,(e instanceof p5.Oscillator||e instanceof p5.SoundFile||e instanceof p5.AudioIn||e instanceof p5.Reverb||e instanceof p5.Noise||e instanceof p5.Filter||e instanceof p5.Delay)&&(e=e.output.gain),e instanceof AudioParam&&e.setValueAtTime(0,t.audiocontext.currentTime),e instanceof p5.Signal&&e.setValue(0),this.output.connect(e)},p5.Env.prototype.disconnect=function(t){this.output.disconnect()},p5.Env.prototype.add=function(t){var i=new e(t),n=this.mathOps.length,o=this.output;return p5.prototype._mathChain(this,i,n,o,e)},p5.Env.prototype.mult=function(t){var e=new i(t),n=this.mathOps.length,o=this.output;return p5.prototype._mathChain(this,e,n,o,i)},p5.Env.prototype.scale=function(t,e,i,o){var r=new n(t,e,i,o),s=this.mathOps.length,a=this.output;return p5.prototype._mathChain(this,r,s,a,n)},p5.Env.prototype.dispose=function(){var e=t.soundArray.indexOf(this);t.soundArray.splice(e,1);t.audiocontext.currentTime;this.disconnect();try{this.control.dispose(),this.control=null}catch(i){}for(var n=1;no;o++)n[o]=1;var r=t.createBufferSource();return r.buffer=i,r.loop=!0,r}var e=master;p5.Pulse=function(i,n){p5.Oscillator.call(this,i,"sawtooth"),this.w=n||0,this.osc2=new p5.SawOsc(i),this.dNode=e.audiocontext.createDelay(),this.dcOffset=t(),this.dcGain=e.audiocontext.createGain(),this.dcOffset.connect(this.dcGain),this.dcGain.connect(this.output),this.f=i||440;var o=this.w/this.oscillator.frequency.value;this.dNode.delayTime.value=o,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)},p5.Pulse.prototype=Object.create(p5.Oscillator.prototype),p5.Pulse.prototype.width=function(t){if("number"==typeof t){if(1>=t&&t>=0){this.w=t;var e=this.w/this.oscillator.frequency.value;this.dNode.delayTime.value=e}this.dcGain.gain.value=1.7*(.5-this.w)}else{t.connect(this.dNode.delayTime);var i=new p5.SignalAdd(-.5);i.setInput(t),i=i.mult(-1),i=i.mult(1.7),i.connect(this.dcGain.gain)}},p5.Pulse.prototype.start=function(i,n){var o=e.audiocontext.currentTime,r=n||0;if(!this.started){var s=i||this.f,a=this.oscillator.type;this.oscillator=e.audiocontext.createOscillator(),this.oscillator.frequency.setValueAtTime(s,o),this.oscillator.type=a,this.oscillator.connect(this.output),this.oscillator.start(r+o),this.osc2.oscillator=e.audiocontext.createOscillator(),this.osc2.oscillator.frequency.setValueAtTime(s,r+o),this.osc2.oscillator.type=a,this.osc2.oscillator.connect(this.osc2.output),this.osc2.start(r+o),this.freqNode=[this.oscillator.frequency,this.osc2.oscillator.frequency],this.dcOffset=t(),this.dcOffset.connect(this.dcGain),this.dcOffset.start(r+o),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}},p5.Pulse.prototype.stop=function(t){if(this.started){var i=t||0,n=e.audiocontext.currentTime;this.oscillator.stop(i+n),this.osc2.oscillator.stop(i+n),this.dcOffset.stop(i+n),this.started=!1,this.osc2.started=!1}},p5.Pulse.prototype.freq=function(t,i,n){if("number"==typeof t){this.f=t;var o=e.audiocontext.currentTime,i=i||0,n=n||0,r=this.oscillator.frequency.value;this.oscillator.frequency.cancelScheduledValues(o),this.oscillator.frequency.setValueAtTime(r,o+n),this.oscillator.frequency.exponentialRampToValueAtTime(t,n+i+o),this.osc2.oscillator.frequency.cancelScheduledValues(o),this.osc2.oscillator.frequency.setValueAtTime(r,o+n),this.osc2.oscillator.frequency.exponentialRampToValueAtTime(t,n+i+o),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)}}(master,oscillator);var noise;noise=function(){"use strict";var t=master;p5.Noise=function(t){p5.Oscillator.call(this),delete this.f,delete this.freq,delete this.oscillator,this.buffer=e},p5.Noise.prototype=Object.create(p5.Oscillator.prototype);var e=function(){for(var e=2*t.audiocontext.sampleRate,i=t.audiocontext.createBuffer(1,e,t.audiocontext.sampleRate),n=i.getChannelData(0),o=0;e>o;o++)n[o]=2*Math.random()-1;return i.type="white",i}(),i=function(){var e,i,n,o,r,s,a,u=2*t.audiocontext.sampleRate,c=t.audiocontext.createBuffer(1,u,t.audiocontext.sampleRate),p=c.getChannelData(0);e=i=n=o=r=s=a=0;for(var h=0;u>h;h++){var l=2*Math.random()-1;e=.99886*e+.0555179*l,i=.99332*i+.0750759*l,n=.969*n+.153852*l,o=.8665*o+.3104856*l,r=.55*r+.5329522*l,s=-.7616*s-.016898*l,p[h]=e+i+n+o+r+s+a+.5362*l,p[h]*=.11,a=.115926*l}return c.type="pink",c}(),n=function(){for(var e=2*t.audiocontext.sampleRate,i=t.audiocontext.createBuffer(1,e,t.audiocontext.sampleRate),n=i.getChannelData(0),o=0,r=0;e>r;r++){var s=2*Math.random()-1;n[r]=(o+.02*s)/1.02,o=n[r],n[r]*=3.5}return i.type="brown",i}();p5.Noise.prototype.setType=function(o){switch(o){case"white":this.buffer=e;break;case"pink":this.buffer=i;break;case"brown":this.buffer=n;break;default:this.buffer=e}if(this.started){var r=t.audiocontext.currentTime;this.stop(r),this.start(r+.01)}},p5.Noise.prototype.getType=function(){return this.buffer.type},p5.Noise.prototype.start=function(){this.started&&this.stop(),this.noise=t.audiocontext.createBufferSource(),this.noise.buffer=this.buffer,this.noise.loop=!0,this.noise.connect(this.output);var e=t.audiocontext.currentTime;this.noise.start(e),this.started=!0},p5.Noise.prototype.stop=function(){var e=t.audiocontext.currentTime;this.noise&&(this.noise.stop(e),this.started=!1)},p5.Noise.prototype.dispose=function(){var e=t.audiocontext.currentTime,i=t.soundArray.indexOf(this);t.soundArray.splice(i,1),this.noise&&(this.noise.disconnect(),this.stop(e)),this.output&&this.output.disconnect(),this.panner&&this.panner.disconnect(),this.output=null,this.panner=null,this.buffer=null,this.noise=null}}(master);var audioin;audioin=function(){"use strict";var t=master;p5.AudioIn=function(){this.input=t.audiocontext.createGain(),this.output=t.audiocontext.createGain(),this.stream=null,this.mediaStream=null,this.currentSource=0,this.enabled=!1,this.amplitude=new p5.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),t.soundArray.push(this)},p5.AudioIn.prototype.start=function(e,i){var n=this;if(t.inputSources[n.currentSource]){var o=t.inputSources[n.currentSource].id,r={audio:{optional:[{sourceId:o}]}};window.navigator.getUserMedia(r,this._onStream=function(i){n.stream=i,n.enabled=!0,n.mediaStream=t.audiocontext.createMediaStreamSource(i),n.mediaStream.connect(n.output),e&&e(),n.amplitude.setInput(n.output)},this._onStreamError=function(t){i?i(t):console.error(t)})}else window.navigator.getUserMedia({audio:!0},this._onStream=function(i){n.stream=i,n.enabled=!0,n.mediaStream=t.audiocontext.createMediaStreamSource(i),n.mediaStream.connect(n.output),n.amplitude.setInput(n.output),e&&e()},this._onStreamError=function(t){i?i(t):console.error(t)})},p5.AudioIn.prototype.stop=function(){this.stream&&this.stream.stop()},p5.AudioIn.prototype.connect=function(e){e?e.hasOwnProperty("input")?this.output.connect(e.input):e.hasOwnProperty("analyser")?this.output.connect(e.analyser):this.output.connect(e):this.output.connect(t.input)},p5.AudioIn.prototype.disconnect=function(t){this.output.disconnect(t),this.output.connect(this.amplitude.input)},p5.AudioIn.prototype.getLevel=function(t){return t&&(this.amplitude.smoothing=t),this.amplitude.getLevel()},p5.AudioIn.prototype._gotSources=function(t){for(var e=0;e0?t.inputSources:"This browser does not support MediaStreamTrack.getSources()"},p5.AudioIn.prototype.getSources=function(e){"function"==typeof window.MediaStreamTrack.getSources?window.MediaStreamTrack.getSources(function(i){for(var n=0,o=i.length;o>n;n++){var r=i[n];"audio"===r.kind&&t.inputSources.push(r)}e(t.inputSources)}):console.log("This browser does not support MediaStreamTrack.getSources()")},p5.AudioIn.prototype.setSource=function(e){var i=this;t.inputSources.length>0&&e=t&&(t=1),"number"==typeof t?(i.biquad.frequency.value=t,i.biquad.frequency.cancelScheduledValues(this.ac.currentTime+.01+n),i.biquad.frequency.exponentialRampToValueAtTime(t,this.ac.currentTime+.02+n)):t&&t.connect(this.biquad.frequency),i.biquad.frequency.value},p5.Filter.prototype.res=function(t,e){var i=this,n=e||0;return"number"==typeof t?(i.biquad.Q.value=t,i.biquad.Q.cancelScheduledValues(i.ac.currentTime+.01+n),i.biquad.Q.linearRampToValueAtTime(t,i.ac.currentTime+.02+n)):t&&freq.connect(this.biquad.Q),i.biquad.Q.value},p5.Filter.prototype.setType=function(t){this.biquad.type=t},p5.Filter.prototype.amp=function(e,i,n){var i=i||0,n=n||0,o=t.audiocontext.currentTime,r=this.output.gain.value;this.output.gain.cancelScheduledValues(o),this.output.gain.linearRampToValueAtTime(r,o+n+.001),this.output.gain.linearRampToValueAtTime(e,o+n+i+.001)},p5.Filter.prototype.connect=function(t){var e=t||p5.soundOut.input;this.output.connect(e)},p5.Filter.prototype.disconnect=function(){this.output.disconnect()},p5.Filter.prototype.dispose=function(){var e=t.soundArray.indexOf(this);t.soundArray.splice(e,1),this.input.disconnect(),this.input=void 0,this.output.disconnect(),this.output=void 0,this.biquad.disconnect(),this.biquad=void 0},p5.LowPass=function(){p5.Filter.call(this,"lowpass")},p5.LowPass.prototype=Object.create(p5.Filter.prototype),p5.HighPass=function(){p5.Filter.call(this,"highpass")},p5.HighPass.prototype=Object.create(p5.Filter.prototype),p5.BandPass=function(){p5.Filter.call(this,"bandpass")},p5.BandPass.prototype=Object.create(p5.Filter.prototype)}(master);var delay;delay=function(){"use strict";var t=master;p5.Delay=function(){this.ac=t.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 p5.Filter,this._rightFilter=new p5.Filter,this._leftFilter.disconnect(),this._rightFilter.disconnect(),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(p5.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.soundArray.push(this)},p5.Delay.prototype.process=function(t,e,i,n){var o=i||0,r=e||0;if(o>=1)throw new Error("Feedback value will force a positive feedback loop.");if(r>=this._maxDelay)throw new Error("Delay Time exceeds maximum delay time of "+this._maxDelay+" second.");t.connect(this.input),this.leftDelay.delayTime.setValueAtTime(r,this.ac.currentTime),this.rightDelay.delayTime.setValueAtTime(r,this.ac.currentTime),this._leftGain.gain.setValueAtTime(o,this.ac.currentTime),this._rightGain.gain.setValueAtTime(o,this.ac.currentTime),n&&(this._leftFilter.freq(n),this._rightFilter.freq(n))},p5.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))},p5.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)}},p5.Delay.prototype.filter=function(t,e){this._leftFilter.set(t,e),this._rightFilter.set(t,e)},p5.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)}},p5.Delay.prototype.amp=function(e,i,n){var i=i||0,n=n||0,o=t.audiocontext.currentTime,r=this.output.gain.value;this.output.gain.cancelScheduledValues(o),this.output.gain.linearRampToValueAtTime(r,o+n+.001),this.output.gain.linearRampToValueAtTime(e,o+n+i+.001)},p5.Delay.prototype.connect=function(t){var e=t||p5.soundOut.input;this.output.connect(e)},p5.Delay.prototype.disconnect=function(){this.output.disconnect()},p5.Delay.prototype.dispose=function(){var e=t.soundArray.indexOf(this);t.soundArray.splice(e,1),this.input.disconnect(),this.output.disconnect(),this._split.disconnect(),this._leftFilter.disconnect(),this._rightFilter.disconnect(),this._merge.disconnect(),this._leftGain.disconnect(),this._rightGain.disconnect(),this.leftDelay.disconnect(),this.rightDelay.disconnect(),this.input=void 0,this.output=void 0,this._split=void 0,this._leftFilter=void 0,this._rightFilter=void 0,this._merge=void 0,this._leftGain=void 0,this._rightGain=void 0,this.leftDelay=void 0,this.rightDelay=void 0}}(master,filter);var reverb;reverb=function(){"use strict";var t=master,e=errorHandler;p5.Reverb=function(){this.ac=t.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(),t.soundArray.push(this)},p5.Reverb.prototype.process=function(t,e,i,n){t.connect(this.input);var o=!1;e&&(this._seconds=e,o=!0),i&&(this._decay=i),n&&(this._reverse=n),o&&this._buildImpulse()},p5.Reverb.prototype.set=function(t,e,i){var n=!1;t&&(this._seconds=t,n=!0),e&&(this._decay=e),i&&(this._reverse=i),n&&this._buildImpulse()},p5.Reverb.prototype.amp=function(e,i,n){var i=i||0,n=n||0,o=t.audiocontext.currentTime,r=this.output.gain.value;this.output.gain.cancelScheduledValues(o),this.output.gain.linearRampToValueAtTime(r,o+n+.001),this.output.gain.linearRampToValueAtTime(e,o+n+i+.001)},p5.Reverb.prototype.connect=function(t){var e=t||p5.soundOut.input;this.output.connect(e.input?e.input:e)},p5.Reverb.prototype.disconnect=function(){this.output.disconnect()},p5.Reverb.prototype._buildImpulse=function(){var t,e,i=this.ac.sampleRate,n=i*this._seconds,o=this._decay,r=this.ac.createBuffer(2,n,i),s=r.getChannelData(0),a=r.getChannelData(1);for(e=0;n>e;e++)t=this.reverse?n-e:e,s[e]=(2*Math.random()-1)*Math.pow(1-t/n,o),a[e]=(2*Math.random()-1)*Math.pow(1-t/n,o);this.convolverNode.buffer=r},p5.Reverb.prototype.dispose=function(){var e=t.soundArray.indexOf(this);t.soundArray.splice(e,1),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)},p5.Convolver=function(e,i,n){this.ac=t.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),e?(this.impulses=[],this._loadBuffer(e,i,n)):(this._seconds=3,this._decay=2,this._reverse=!1,this._buildImpulse()),this.connect(),t.soundArray.push(this)},p5.Convolver.prototype=Object.create(p5.Reverb.prototype),p5.prototype.registerPreloadMethod("createConvolver",p5.prototype),p5.prototype.createConvolver=function(t,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 n=new p5.Convolver(t,e,i);return n.impulses=[],n},p5.Convolver.prototype._loadBuffer=function(t,i,n){var t=p5.prototype._checkFileFormats(t),o=this,r=(new Error).stack,s=p5.prototype.getAudioContext(),a=new XMLHttpRequest;a.open("GET",t,!0),a.responseType="arraybuffer",a.onload=function(){if(200==a.status)s.decodeAudioData(a.response,function(e){var n={},r=t.split("/");n.name=r[r.length-1],n.audioBuffer=e,o.impulses.push(n),o.convolverNode.buffer=n.audioBuffer,i&&i(n)},function(t){var i=new e("decodeAudioData",r,o.url),s="AudioContext error at decodeAudioData for "+o.url;n?(i.msg=s,n(i)):console.error(s+"\n The error stack trace includes: \n"+i.stack)});else{var u=new e("loadConvolver",r,o.url),c="Unable to load "+o.url+". The request status was: "+a.status+" ("+a.statusText+")";n?(u.message=c,n(u)):console.error(c+"\n The error stack trace includes: \n"+u.stack)}},a.onerror=function(t){var i=new e("loadConvolver",r,o.url),s="There was no response from the server at "+o.url+". Check the url and internet connectivity.";n?(i.message=s,n(i)):console.error(s+"\n The error stack trace includes: \n"+i.stack)},a.send()},p5.Convolver.prototype.set=null,p5.Convolver.prototype.process=function(t){t.connect(this.input)},p5.Convolver.prototype.impulses=[],p5.Convolver.prototype.addImpulse=function(t,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"),this._loadBuffer(t,e,i)},p5.Convolver.prototype.resetImpulse=function(t,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"),this.impulses=[],this._loadBuffer(t,e,i)},p5.Convolver.prototype.toggleImpulse=function(t){if("number"==typeof t&&tthis._nextTick;){n>this._nextTick+this._threshold&&(this._nextTick=n);var a=this._nextTick;this._nextTick+=1/this.frequency.getValueAtTime(this._nextTick),this.callback(a),this.ticks++}else s===t.State.Stopped&&(this._nextTick=-1,this.ticks=0)},t.Clock.prototype.getStateAtTime=function(t){return this._state.getStateAtTime(t)},t.Clock.prototype.dispose=function(){cancelAnimationFrame(this._loopID),t.TimelineState.prototype.dispose.call(this),this._writable("frequency"),this.frequency.dispose(),this.frequency=null,this._boundLoop=t.noOp,this._nextTick=1/0,this.callback=null,this._state.dispose(),this._state=null},t.Clock}(Tone_core_Tone,Tone_signal_TimelineSignal);var metro;metro=function(){"use strict";var t=master,e=Tone_core_Clock;t.audiocontext;p5.Metro=function(){this.clock=new e({callback:this.ontick.bind(this)}),this.syncedParts=[],this.bpm=120,this._init(),this.tickCallback=function(){}};var i=0,n=0;p5.Metro.prototype.ontick=function(e){var o=e-i,r=e-t.audiocontext.currentTime;if(!(-.02>=o-n)){i=e;for(var s in this.syncedParts){ +var a=this.syncedParts[s];a.incrementStep(r);for(var u in a.phrases){var c=a.phrases[u],p=c.sequence,h=this.metroTicks%p.length;0!==p[h]&&(this.metroTicks=t.parts.length?(t.scoreStep=0,t.onended()):(t.scoreStep=0,t.parts[t.currentPart-1].stop(),t.parts[t.currentPart].start())}var e=master,i=120;p5.prototype.setBPM=function(t,n){i=t;for(var o in e.parts)e.parts[o].setBPM(i,n)},p5.Phrase=function(t,e,i){this.phraseStep=0,this.name=t,this.callback=e,this.sequence=i},p5.Part=function(t,n){this.length=t||0,this.partStep=0,this.phrases=[],this.looping=!1,this.isPlaying=!1,this.onended=function(){this.stop()},this.tatums=n||.0625,this.metro=new p5.Metro,this.metro._init(),this.metro.beatLength(this.tatums),this.metro.setBPM(i),e.parts.push(this),this.callback=function(){}},p5.Part.prototype.setBPM=function(t,e){this.metro.setBPM(t,e)},p5.Part.prototype.getBPM=function(){return this.metro.getBPM()},p5.Part.prototype.start=function(t){if(!this.isPlaying){this.isPlaying=!0,this.metro.resetSync(this);var e=t||0;this.metro.start(e)}},p5.Part.prototype.loop=function(t){this.looping=!0,this.onended=function(){this.partStep=0};var e=t||0;this.start(e)},p5.Part.prototype.noLoop=function(){this.looping=!1,this.onended=function(){this.stop()}},p5.Part.prototype.stop=function(t){this.partStep=0,this.pause(t)},p5.Part.prototype.pause=function(t){this.isPlaying=!1;var e=t||0;this.metro.stop(e)},p5.Part.prototype.addPhrase=function(t,e,i){var n;if(3===arguments.length)n=new p5.Phrase(t,e,i);else{if(!(arguments[0]instanceof p5.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)},p5.Part.prototype.removePhrase=function(t){for(var e in this.phrases)this.phrases[e].name===t&&this.phrases.split(e,1)},p5.Part.prototype.getPhrase=function(t){for(var e in this.phrases)if(this.phrases[e].name===t)return this.phrases[e]},p5.Part.prototype.replaceSequence=function(t,e){for(var i in this.phrases)this.phrases[i].name===t&&(this.phrases[i].sequence=e)},p5.Part.prototype.incrementStep=function(t){this.partStepr;)n[r++]=t[o],n[r++]=e[o],o++;return n}function e(t,e,i){for(var n=i.length,o=0;n>o;o++)t.setUint8(e+o,i.charCodeAt(o))}var i=master,n=i.audiocontext;p5.SoundRecorder=function(){this.input=n.createGain(),this.output=n.createGain(),this.recording=!1,this.bufferSize=1024,this._channels=2,this._clear(),this._jsNode=n.createScriptProcessor(this.bufferSize,this._channels,2),this._jsNode.onaudioprocess=this._audioprocess.bind(this),this._callback=function(){},this._jsNode.connect(p5.soundOut._silentNode),this.setInput(),i.soundArray.push(this)},p5.SoundRecorder.prototype.setInput=function(t){this.input.disconnect(),this.input=null,this.input=n.createGain(),this.input.connect(this._jsNode),this.input.connect(this.output),t?t.connect(this.input):p5.soundOut.output.connect(this.input)},p5.SoundRecorder.prototype.record=function(t,e,i){this.recording=!0,e&&(this.sampleLimit=Math.round(e*n.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)})},p5.SoundRecorder.prototype.stop=function(){this.recording=!1,this._callback(),this._clear()},p5.SoundRecorder.prototype._clear=function(){this._leftBuffers=[],this._rightBuffers=[],this.recordedSamples=0,this.sampleLimit=null},p5.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}},p5.SoundRecorder.prototype._getBuffer=function(){var t=[];return t.push(this._mergeBuffers(this._leftBuffers)),t.push(this._mergeBuffers(this._rightBuffers)),t},p5.SoundRecorder.prototype._mergeBuffers=function(t){for(var e=new Float32Array(this.recordedSamples),i=0,n=t.length,o=0;n>o;o++){var r=t[o];e.set(r,i),i+=r.length}return e},p5.SoundRecorder.prototype.dispose=function(){this._clear();var t=i.soundArray.indexOf(this);i.soundArray.splice(t,1),this._callback=function(){},this.input&&this.input.disconnect(),this.input=null,this._jsNode=null},p5.prototype.saveSound=function(i,n){var o=i.buffer.getChannelData(0),r=i.buffer.getChannelData(1),s=t(o,r),a=new ArrayBuffer(44+2*s.length),u=new DataView(a);e(u,0,"RIFF"),u.setUint32(4,44+2*s.length,!0),e(u,8,"WAVE"),e(u,12,"fmt "),u.setUint32(16,16,!0),u.setUint16(20,1,!0),u.setUint16(22,2,!0),u.setUint32(24,44100,!0),u.setUint32(28,176400,!0),u.setUint16(32,4,!0),u.setUint16(34,16,!0),e(u,36,"data"),u.setUint32(40,2*s.length,!0);for(var c=s.length,p=44,h=1,l=0;c>l;l++)u.setInt16(p,s[l]*(32767*h),!0),p+=2;p5.prototype.writeFile([u],n,"wav")}}(sndcore,master);var peakdetect;peakdetect=function(){"use strict";p5.PeakDetect=function(t,e,i,n){this.framesPerPeak=n||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(){}},p5.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},p5.PeakDetect.prototype.onPeak=function(t,e){var i=this;i._onPeak=function(){t(i.energy,e)}}}(master);var gain;gain=function(){"use strict";var t=master;p5.Gain=function(){this.ac=t.audiocontext,this.input=this.ac.createGain(),this.output=this.ac.createGain(),this.input.gain.value=.5,this.input.connect(this.output),t.soundArray.push(this)},p5.Gain.prototype.setInput=function(t){t.connect(this.input)},p5.Gain.prototype.connect=function(t){var e=t||p5.soundOut.input;this.output.connect(e.input?e.input:e)},p5.Gain.prototype.disconnect=function(){this.output.disconnect()},p5.Gain.prototype.amp=function(e,i,n){var i=i||0,n=n||0,o=t.audiocontext.currentTime,r=this.output.gain.value;this.output.gain.cancelScheduledValues(o),this.output.gain.linearRampToValueAtTime(r,o+n),this.output.gain.linearRampToValueAtTime(e,o+n+i)},p5.Gain.prototype.dispose=function(){var e=t.soundArray.indexOf(this);t.soundArray.splice(e,1),this.output.disconnect(),this.input.disconnect(),this.output=void 0,this.input=void 0}}(master,sndcore);var src_app;src_app=function(){"use strict";var t=sndcore;return t}(sndcore,master,helpers,errorHandler,panner,soundfile,amplitude,fft,signal,oscillator,env,pulse,noise,audioin,filter,delay,reverb,metro,looper,soundRecorder,peakdetect,gain)}); \ No newline at end of file diff --git a/package.json b/package.json index cdfcd129..63cdd817 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,8 @@ "type": "git", "url": "https://github.com/therewasaguy/p5.sound.js.git" }, - "version": "0.2.17", - "licenses": [ - { - "type": "MIT" - } - ], + "version": "0.3.0", + "license": "MIT", "devDependencies": { "grunt": "~0.4.2", "grunt-contrib-jshint": "~0.6.3", @@ -22,7 +18,9 @@ "grunt-contrib-yuidoc": "0.5.2", "almond": "~0.2.7", "amdclean": "~2.0", - "grunt-contrib-sass": "~0.7.2", - "tone": "~0.3" + "grunt-contrib-sass": "~0.7.2" + }, + "dependencies": { + "tone": "therewasaguy/tone.js#p5-dev" } } diff --git a/src/env.js b/src/env.js index e062fc73..a6b69731 100644 --- a/src/env.js +++ b/src/env.js @@ -5,115 +5,118 @@ define(function (require) { var Add = require('Tone/signal/Add'); var Mult = require('Tone/signal/Multiply'); var Scale = require('Tone/signal/Scale'); + var TimelineSignal = require('Tone/signal/TimelineSignal'); var Tone = require('Tone/core/Tone'); Tone.setContext( p5sound.audiocontext); /** - *

Envelopes are pre-defined amplitude distribution over time. - * The p5.Env accepts up to four time/level pairs, where time - * determines how long of a ramp before value reaches level. + *

Envelopes are pre-defined amplitude distribution over time. + * The p5.Env accepts up to three time/level pairs, where time + * determines the duration until value reaches level. * Typically, envelopes are used to control the output volume * of an object, a series of fades referred to as Attack, Decay, - * Sustain and Release (ADSR). But p5.Env can control any - * Web Audio Param, for example it can be passed to an Oscillator - * frequency like osc.freq(env)

+ * Sustain and Release ( + *
ADSR + * ). But p5.Env can control any Web Audio Param; for example it can be passed to an Oscillator + * frequency like osc.freq(env).

+ *

Use setRange to change the attack/release level. + * Use setADSR to change attackTime, decayTime, sustainPercent and releaseTime.

+ *

Use the play method to play the entire envelope, the ramp method for a pingable trigger, + * or triggerAttack/triggerRelease to trigger noteOn/noteOff.

* * @class p5.Env * @constructor - * @param {Number} aTime Time (in seconds) before level - * reaches attackLevel - * @param {Number} aLevel Typically an amplitude between - * 0.0 and 1.0 - * @param {Number} dTime Time - * @param {Number} [dLevel] Amplitude (In a standard ADSR envelope, - * decayLevel = sustainLevel) - * @param {Number} [sTime] Time (in seconds) - * @param {Number} [sLevel] Amplitude 0.0 to 1.0 - * @param {Number} [rTime] Time (in seconds) - * @param {Number} [rLevel] Amplitude 0.0 to 1.0 * @example *
- * var aT = 0.1; // attack time in seconds - * var aL = 0.7; // attack level 0.0 to 1.0 - * var dT = 0.3; // decay time in seconds - * var dL = 0.1; // decay level 0.0 to 1.0 - * var sT = 0.2; // sustain time in seconds - * var sL = dL; // sustain level 0.0 to 1.0 - * var rT = 0.5; // release time in seconds - * // release level defaults to zero + * var attackLevel = 1.0; + * var releaseLevel = 0; + * + * var attackTime = 0.001 + * var decayTime = 0.2; + * var susPercent = 0.2; + * var releaseTime = 0.5; + * + * var env, triOsc; * - * var env; - * var triOsc; - * * function setup() { - * background(0); - * noStroke(); - * fill(255); + * var cnv = createCanvas(100, 100); + * * textAlign(CENTER); * text('click to play', width/2, height/2); * - * env = new p5.Env(aT, aL, dT, dL, sT, sL, rT); + * env = new p5.Env(); + * env.setADSR(attackTime, decayTime, susPercent, releaseTime); + * env.setRange(attackLevel, releaseLevel); + * * triOsc = new p5.Oscillator('triangle'); - * triOsc.amp(env); // give the env control of the triOsc's amp + * triOsc.amp(env); * triOsc.start(); + * triOsc.freq(220); + * + * cnv.mousePressed(playEnv); * } * - * // mouseClick triggers envelope if over canvas - * function mouseClicked() { - * // is mouse over canvas? - * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { - * env.play(triOsc); - * } + * function playEnv(){ + * env.play(); * } *
*/ - p5.Env = function(t1, l1, t2, l2, t3, l3, t4, l4){ + p5.Env = function(t1, l1, t2, l2, t3, l3){ + var now = p5sound.audiocontext.currentTime; /** + * Time until envelope reaches attackLevel * @property attackTime */ - this.aTime = t1; + this.aTime = t1 || 0.1; /** + * Level once attack is complete. * @property attackLevel */ - this.aLevel = l1; + this.aLevel = l1 || 1; /** + * Time until envelope reaches decayLevel. * @property decayTime */ - this.dTime = t2 || 0; + this.dTime = t2 || 0.5; /** + * Level after decay. The envelope will sustain here until it is released. * @property decayLevel */ this.dLevel = l2 || 0; /** - * @property sustainTime - */ - this.sTime = t3 || 0; - /** - * @property sustainLevel - */ - this.sLevel = l3 || 0; - /** + * Duration of the release portion of the envelope. * @property releaseTime */ - this.rTime = t4 || 0; + this.rTime = t3 || 0; /** + * Level at the end of the release. * @property releaseLevel */ - this.rLevel = l4 || 0; + this.rLevel = l3 || 0; + + this._rampHighPercentage = 0.98; + + this._rampLowPercentage = 0.02; + this.output = p5sound.audiocontext.createGain();; - this.control = new p5.Signal(); + this.control = new TimelineSignal(); + + this._init(); // this makes sure the envelope starts at zero - this.control.connect(this.output); + this.control.connect(this.output); // connect to the output this.connection = null; // store connection //array of math operation signal chaining this.mathOps = [this.control]; + //whether envelope should be linear or exponential curve + this.isExponential = false; + // oscillator or buffer source to clear on env complete // to save resources if/when it is retriggered this.sourceToClear = null; @@ -126,33 +129,202 @@ define(function (require) { p5sound.soundArray.push(this); }; + // this init function just smooths the starting value to zero and gives a start point for the timeline + // - it was necessary to remove glitches at the beginning. + p5.Env.prototype._init = function () { + var now = p5sound.audiocontext.currentTime; + var t = now; + this.control.setTargetAtTime(0.00001, t, .001); + //also, compute the correct time constants + this._setRampAD(this.aTime, this.dTime) + }; + /** * Reset the envelope with a series of time/value pairs. * * @method set - * @param {Number} aTime Time (in seconds) before level + * @param {Number} attackTime Time (in seconds) before level * reaches attackLevel - * @param {Number} aLevel Typically an amplitude between + * @param {Number} attackLevel Typically an amplitude between * 0.0 and 1.0 - * @param {Number} dTime Time - * @param {Number} [dLevel] Amplitude (In a standard ADSR envelope, + * @param {Number} decayTime Time + * @param {Number} decayLevel Amplitude (In a standard ADSR envelope, * decayLevel = sustainLevel) - * @param {Number} [sTime] Time (in seconds) - * @param {Number} [sLevel] Amplitude 0.0 to 1.0 - * @param {Number} [rTime] Time (in seconds) - * @param {Number} [rLevel] Amplitude 0.0 to 1.0 + * @param {Number} releaseTime Release Time (in seconds) + * @param {Number} releaseLevel Amplitude */ - p5.Env.prototype.set = function(t1, l1, t2, l2, t3, l3, t4, l4){ + p5.Env.prototype.set = function(t1, l1, t2, l2, t3, l3){ this.aTime = t1; this.aLevel = l1; this.dTime = t2 || 0; this.dLevel = l2 || 0; - this.sTime = t3 || 0; - this.sLevel = l3 || 0; this.rTime = t4 || 0; this.rLevel = l4 || 0; + + // set time constants for ramp + this._setRampAD(t1, t2); }; + /** + * Set values like a traditional + * + * ADSR envelope + * . + * + * @method setADSR + * @param {Number} attackTime Time (in seconds before envelope + * reaches Attack Level + * @param {Number} [decayTime] Time (in seconds) before envelope + * reaches Decay/Sustain Level + * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, + * where 1.0 = attackLevel, 0.0 = releaseLevel. + * The susRatio determines the decayLevel and the level at which the + * sustain portion of the envelope will sustain. + * For example, if attackLevel is 0.4, releaseLevel is 0, + * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is + * increased to 1.0 (using setRange), + * then decayLevel would increase proportionally, to become 0.5. + * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) + * @example + *
+ * var attackLevel = 1.0; + * var releaseLevel = 0; + * + * var attackTime = 0.001 + * var decayTime = 0.2; + * var susPercent = 0.2; + * var releaseTime = 0.5; + * + * var env, triOsc; + * + * function setup() { + * var cnv = createCanvas(100, 100); + * + * textAlign(CENTER); + * text('click to play', width/2, height/2); + * + * env = new p5.Env(); + * env.setADSR(attackTime, decayTime, susPercent, releaseTime); + * env.setRange(attackLevel, releaseLevel); + * + * triOsc = new p5.Oscillator('triangle'); + * triOsc.amp(env); + * triOsc.start(); + * triOsc.freq(220); + * + * cnv.mousePressed(playEnv); + * } + * + * function playEnv(){ + * env.play(); + * } + */ + p5.Env.prototype.setADSR = function(aTime, dTime, sPercent, rTime){ + this.aTime = aTime; + this.dTime = dTime || 0; + + // lerp + this.sPercent = sPercent || 0; + this.dLevel = typeof(sPercent) !== 'undefined' ? sPercent * (this.aLevel - this.rLevel) + this.rLevel : 0; + + this.rTime = rTime || 0; + + // also set time constants for ramp + this._setRampAD(aTime, dTime); + }; + + /** + * Set max (attackLevel) and min (releaseLevel) of envelope. + * + * @method setRange + * @param {Number} aLevel attack level (defaults to 1) + * @param {Number} rLevel release level (defaults to 0) + * @example + *
+ * var attackLevel = 1.0; + * var releaseLevel = 0; + * + * var attackTime = 0.001 + * var decayTime = 0.2; + * var susPercent = 0.2; + * var releaseTime = 0.5; + * + * var env, triOsc; + * + * function setup() { + * var cnv = createCanvas(100, 100); + * + * textAlign(CENTER); + * text('click to play', width/2, height/2); + * + * env = new p5.Env(); + * env.setADSR(attackTime, decayTime, susPercent, releaseTime); + * env.setRange(attackLevel, releaseLevel); + * + * triOsc = new p5.Oscillator('triangle'); + * triOsc.amp(env); + * triOsc.start(); + * triOsc.freq(220); + * + * cnv.mousePressed(playEnv); + * } + * + * function playEnv(){ + * env.play(); + * } + */ + p5.Env.prototype.setRange = function(aLevel, rLevel) { + this.aLevel = aLevel || 1; + this.rLevel = rLevel || 0; + + // not sure if this belongs here: + + // {Number} [dLevel] decay/sustain level (optional) + // if (typeof(dLevel) !== 'undefined') { + // this.dLevel = dLevel + // } else if (this.sPercent) { + // this.dLevel = this.sPercent ? this.sPercent * (this.aLevel - this.rLevel) + this.rLevel : 0; + // } + } + + // private (undocumented) method called when ADSR is set to set time constants for ramp + // + // Set the + // time constants for simple exponential ramps. + // The larger the time constant value, the slower the + // transition will be. + // + // method _setRampAD + // param {Number} attackTimeConstant attack time constant + // param {Number} decayTimeConstant decay time constant + // + p5.Env.prototype._setRampAD = function(t1, t2){ + this._rampAttackTime = this.checkExpInput(t1); + this._rampDecayTime = this.checkExpInput(t2); + + var TCDenominator = 1.0; + /// Aatish Bhatia's calculation for time constant for rise(to adjust 1/1-e calculation to any percentage) + TCDenominator = Math.log(1.0 / (this.checkExpInput(1.0 - this._rampHighPercentage))); + this._rampAttackTC = (t1 / this.checkExpInput(TCDenominator)); + TCDenominator = Math.log(1.0 / this._rampLowPercentage); + this._rampDecayTC = (t2 / this.checkExpInput(TCDenominator)); + }; + + // private method + p5.Env.prototype.setRampPercentages = function(p1, p2){ + //set the percentages that the simple exponential ramps go to + this._rampHighPercentage = this.checkExpInput(p1); + this._rampLowPercentage = this.checkExpInput(p2); + var TCDenominator = 1.0; + //now re-compute the time constants based on those percentages + /// Aatish Bhatia's calculation for time constant for rise(to adjust 1/1-e calculation to any percentage) + TCDenominator = Math.log(1.0 / (this.checkExpInput(1.0 - this._rampHighPercentage))); + this._rampAttackTC = (this._rampAttackTime / this.checkExpInput(TCDenominator)); + TCDenominator = Math.log(1.0 / this._rampLowPercentage); + this._rampDecayTC = (this._rampDecayTime / this.checkExpInput(TCDenominator)); + }; + + /** * Assign a parameter to be controlled by this envelope. * If a p5.Sound object is given, then the p5.Env will control its @@ -169,8 +341,25 @@ define(function (require) { } }; - p5.Env.prototype.ctrl = function(unit){ - this.connect(unit); + /** + * Set whether the envelope ramp is linear (default) or exponential. + * Exponential ramps can be useful because we perceive amplitude + * and frequency logarithmically. + * + * @method setExp + * @param {Boolean} isExp true is exponential, false is linear + */ + p5.Env.prototype.setExp = function(isExp){ + this.isExponential = isExp; + }; + + //helper method to protect against zero values being sent to exponential functions + p5.Env.prototype.checkExpInput = function(value) { + if (value <= 0) + { + value = 0.0001; + } + return value; }; /** @@ -184,12 +373,14 @@ define(function (require) { * @method play * @param {Object} unit A p5.sound object or * Web Audio Param. - * @param {Number} secondsFromNow time from now (in seconds) + * @param {Number} [startTime] time from now (in seconds) at which to play + * @param {Number} [sustainTime] time to sustain before releasing the envelope + */ - p5.Env.prototype.play = function(unit, secondsFromNow){ + p5.Env.prototype.play = function(unit, secondsFromNow, susTime){ var now = p5sound.audiocontext.currentTime; var tFromNow = secondsFromNow || 0; - var t = now + tFromNow; + var susTime = susTime || 0; if (unit) { if (this.connection !== unit) { @@ -197,25 +388,14 @@ define(function (require) { } } - var currentVal = this.control.getValue(); - this.control.cancelScheduledValues(t); - this.control.linearRampToValueAtTime(currentVal, t); + this.triggerAttack(unit, tFromNow); - // attack - this.control.linearRampToValueAtTime(this.aLevel, t + this.aTime); - // decay to decay level - this.control.linearRampToValueAtTime(this.dLevel, t + this.aTime + this.dTime); - // hold sustain level - this.control.linearRampToValueAtTime(this.sLevel, t + this.aTime + this.dTime + this.sTime); - // release - this.control.linearRampToValueAtTime(this.rLevel, t + this.aTime + this.dTime + this.sTime + this.rTime); - - var clearTime = (t + this.aTime + this.dTime + this.sTime + this.rTime); //* 1000; + this.triggerRelease(unit, tFromNow + this.aTime + this.dTime + susTime); }; /** - * Trigger the Attack, Decay, and Sustain of the Envelope. + * Trigger the Attack, and Decay portion of the Envelope. * Similar to holding down a key on a piano, but it will * hold the sustain level until you let go. Input can be * any p5.sound object, or a + * spectral centroid of the input signal. + * NOTE: analyze() must be called prior to getCentroid(). Analyze() + * tells the FFT to analyze frequency data, and getCentroid() uses + * the results determine the spectral centroid.

+ * + * @method getCentroid + * @return {Number} Spectral Centroid Frequency Frequency of the spectral centroid in Hz. + * + * + * @example + *
+ * + * + *function setup(){ + * cnv = createCanvas(800,400); + * sound = new p5.AudioIn(); + * sound.start(); + * fft = new p5.FFT(); + * sound.connect(fft); + *} + * + * + *function draw(){ + * + * var centroidplot = 0.0; + * var spectralCentroid = 0; + * + * + * background(0); + * stroke(0,255,0); + * var spectrum = fft.analyze(); + * fill(0,255,0); // spectrum is green + * + * //draw the spectrum + * + * for (var i = 0; i< spectrum.length; i++){ + * var x = map(log(i), 0, log(spectrum.length), 0, width); + * var h = map(spectrum[i], 0, 255, 0, height); + * var rectangle_width = (log(i+1)-log(i))*(width/log(spectrum.length)); + * rect(x, height, rectangle_width, -h ) + * } + + * var nyquist = 22050; + * + * // get the centroid + * spectralCentroid = fft.getCentroid(); + * + * // the mean_freq_index calculation is for the display. + * var mean_freq_index = spectralCentroid/(nyquist/spectrum.length); + * + * centroidplot = map(log(mean_freq_index), 0, log(spectrum.length), 0, width); + * + * + * stroke(255,0,0); // the line showing where the centroid is will be red + * + * rect(centroidplot, 0, width / spectrum.length, height) + * noStroke(); + * fill(255,255,255); // text is white + * textSize(40); + * text("centroid: "+round(spectralCentroid)+" Hz", 10, 40); + *} + *
+ */ + p5.FFT.prototype.getCentroid = function() { + var nyquist = p5sound.audiocontext.sampleRate/2; + var cumulative_sum = 0; + var centroid_normalization = 0; + + for (var i = 0; i < this.freqDomain.length; i++) + { + cumulative_sum += i * this.freqDomain[i]; + centroid_normalization += this.freqDomain[i]; + } + + var mean_freq_index = 0; + + if (centroid_normalization != 0) + { + mean_freq_index = (cumulative_sum / centroid_normalization); + } + + var spec_centroid_freq = (mean_freq_index * (nyquist / this.freqDomain.length)); + return spec_centroid_freq; + } + /** * Smooth FFT analysis by averaging with the last analysis frame. * diff --git a/src/metro.js b/src/metro.js index bd83cd00..f5941562 100644 --- a/src/metro.js +++ b/src/metro.js @@ -11,7 +11,9 @@ define(function (require) { // var upTick = false; p5.Metro = function() { - this.clock = new Clock(ac.sampleRate, this.ontick.bind(this)); + this.clock = new Clock({ + 'callback': this.ontick.bind(this) + }); this.syncedParts = []; this.bpm = 120; // gets overridden by p5.Part this._init(); @@ -50,10 +52,12 @@ define(function (require) { p5.Metro.prototype.setBPM = function(bpm, rampTime) { var beatTime = 60 / (bpm*this.tatums); + var now = p5sound.audiocontext.currentTime; tatumTime = beatTime; - var ramp = rampTime || 0; - this.clock.setRate(beatTime, rampTime + p5sound.audiocontext.currentTime); + var rampTime = rampTime || 0; + this.clock.frequency.setValueAtTime(this.clock.frequency.value, now); + this.clock.frequency.linearRampToValueAtTime(bpm, now + rampTime); this.bpm = bpm; }; @@ -76,16 +80,18 @@ define(function (require) { this.syncedParts.push(part); }; - p5.Metro.prototype.start = function(time) { - var t = time || 0; - this.clock.start(t); + p5.Metro.prototype.start = function(timeFromNow) { + var t = timeFromNow || 0; + var now = p5sound.audiocontext.currentTime; + this.clock.start(now + t); this.setBPM(this.bpm); }; - p5.Metro.prototype.stop = function(time) { - var t = time || 0; + p5.Metro.prototype.stop = function(timeFromNow) { + var t = timeFromNow || 0; + var now = p5sound.audiocontext.currentTime; if (this.clock._oscillator) { - this.clock.stop(t); + this.clock.stop(now + t); } }; diff --git a/src/oscillator.js b/src/oscillator.js index 7ecd1a2b..603ae1a0 100644 --- a/src/oscillator.js +++ b/src/oscillator.js @@ -1,3 +1,4 @@ + define(function (require) { 'use strict'; @@ -86,6 +87,7 @@ define(function (require) { this.f = freq || 440.0; // frequency this.oscillator.frequency.setValueAtTime(this.f, p5sound.audiocontext.currentTime); this.oscillator.type = type || 'sine'; + var o = this.oscillator; // connections @@ -236,15 +238,22 @@ define(function (require) { var now = p5sound.audiocontext.currentTime; var rampTime = rampTime || 0; var tFromNow = tFromNow || 0; - var currentFreq = this.oscillator.frequency.value; - this.oscillator.frequency.cancelScheduledValues(now); - this.oscillator.frequency.setValueAtTime(currentFreq, now + tFromNow); - if (val > 0 ){ - this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); + // var currentFreq = this.oscillator.frequency.value; + // this.oscillator.frequency.cancelScheduledValues(now); + + if (rampTime == 0) { + this.oscillator.frequency.cancelScheduledValues(now); + this.oscillator.frequency.setValueAtTime(val, tFromNow + now); } else { - this.oscillator.frequency.linearRampToValueAtTime(val, tFromNow + rampTime + now); + if (val > 0 ){ + this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); + } else { + this.oscillator.frequency.linearRampToValueAtTime(val, tFromNow + rampTime + now); + } } + + // reset phase if oscillator has a phase if (this.phaseAmount) { this.phase(this.phaseAmount);