vendor: 4,829 bytes, lines 1-104
1/** [p5.sound] Version: 0.3.12 - 2020-01-06 */ 2 /** 3 * <p>p5.sound extends p5 with <a href="http://caniuse.com/audio-api" 4 * target="_blank">Web Audio</a> functionality including audio input, 5 * playback, analysis and synthesis. 6 * </p> 7 * <ul> 8 * <li><a href="#/p5.SoundFile"><b>p5.SoundFile</b></a>: Load and play sound files.</li> 9 * <li><a href="#/p5.Amplitude"><b>p5.Amplitude</b></a>: Get the current volume of a sound.</li> 10 * <li><a href="#/p5.AudioIn"><b>p5.AudioIn</b></a>: Get sound from an input source, typically 11 * a computer microphone.</li> 12 * <li><a href="#/p5.FFT"><b>p5.FFT</b></a>: Analyze the frequency of sound. Returns 13 * results from the frequency spectrum or time domain (waveform).</li> 14 * <li><a href="#/p5.Oscillator"><b>p5.Oscillator</b></a>: Generate Sine, 15 * Triangle, Square and Sawtooth waveforms. Base class of 16 * <li><a href="#/p5.Noise">p5.Noise</a> and <a href="#/p5.Pulse">p5.Pulse</a>. 17 * </li> 18 * <li> 19 * <a href="#/p5.MonoSynth">p5.MonoSynth</a> and <a href="#/p5.PolySynth">p5.PolySynth</a>: Play musical notes 20 * </li> 21 * <li><a href="#/p5.Envelope"><b>p5.Envelope</b></a>: An Envelope is a series 22 * of fades over time. Often used to control an object's 23 * output gain level as an "ADSR Envelope" (Attack, Decay, 24 * Sustain, Release). Can also modulate other parameters.</li> 25 * <li><a href="#/p5.Delay"><b>p5.Delay</b></a>: A delay effect with 26 * parameters for feedback, delayTime, and lowpass filter.</li> 27 * <li><a href="#/p5.Filter"><b>p5.Filter</b></a>: Filter the frequency range of a 28 * sound. 29 * </li> 30 * <li><a href="#/p5.Reverb"><b>p5.Reverb</b></a>: Add reverb to a sound by specifying 31 * duration and decay. </li> 32 * <b><li><a href="#/p5.Convolver">p5.Convolver</a>:</b> Extends 33 * <a href="#/p5.Reverb">p5.Reverb</a> to simulate the sound of real 34 * physical spaces through convolution.</li> 35 * <b><li><a href="#/p5.SoundRecorder">p5.SoundRecorder</a></b>: Record sound for playback 36 * / save the .wav file. 37 * <b><li><a href="#/p5.SoundLoop">p5.SoundLoop</a>, <a href="#/p5.Phrase">p5.Phrase</a></b>, <b><a href="#/p5.Part">p5.Part</a></b> and 38 * <b><a href="#/p5.Score">p5.Score</a></b>: Compose musical sequences. 39 * </li> 40 * <li><a href="#/p5/userStartAudio">userStartAudio</a>: Enable audio in a 41 * browser- and user-friendly way.</a> 42 * <p>p5.sound is on <a href="https://github.com/therewasaguy/p5.sound/">GitHub</a>. 43 * Download the latest version 44 * <a href="https://github.com/therewasaguy/p5.sound/blob/master/lib/p5.sound.js">here</a>.</p> 45 * 46 * @module p5.sound 47 * @submodule p5.sound 48 * @for p5.sound 49 * @main 50 */ 51 52/** 53 * p5.sound 54 * https://p5js.org/reference/#/libraries/p5.sound 55 * 56 * From the Processing Foundation and contributors 57 * https://github.com/processing/p5.js-sound/graphs/contributors 58 * 59 * MIT License (MIT) 60 * https://github.com/processing/p5.js-sound/blob/master/LICENSE 61 * 62 * Some of the many audio libraries & resources that inspire p5.sound: 63 * - TONE.js (c) Yotam Mann. Licensed under The MIT License (MIT). https://github.com/TONEnoTONE/Tone.js 64 * - buzz.js (c) Jay Salvat. Licensed under The MIT License (MIT). http://buzz.jaysalvat.com/ 65 * - Boris Smus Web Audio API book, 2013. Licensed under the Apache License http://www.apache.org/licenses/LICENSE-2.0 66 * - wavesurfer.js https://github.com/katspaugh/wavesurfer.js 67 * - Web Audio Components by Jordan Santell https://github.com/web-audio-components 68 * - Wilm Thoben's Sound library for Processing https://github.com/processing/processing/tree/master/java/libraries/sound 69 * 70 * Web Audio API: http://w3.org/TR/webaudio/ 71 */ 72 73 (function(modules) { 74 var installedModules = {}; 75 function __webpack_require__(moduleId) { 76 if(installedModules[moduleId]) { 77 return installedModules[moduleId].exports; 78 } 79 var module = installedModules[moduleId] = { 80 i: moduleId, 81 l: false, 82 exports: {} 83 }; 84 modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 85 module.l = true; 86 return module.exports; 87 } 88 __webpack_require__.m = modules; 89 __webpack_require__.c = installedModules; 90 __webpack_require__.d = function(exports, name, getter) { 91 if(!__webpack_require__.o(exports, name)) { 92 Object.defineProperty(exports, name, { enumerable: true, get: getter }); 93 } 94 }; 95 __webpack_require__.r = function(exports) { 96 if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 97 Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 98 } 99 Object.defineProperty(exports, '__esModule', { value: true }); 100 }; 101 __webpack_require__.t = function(value, mode) { 102 if(mode & 1) value = __webpack_require__(value); 103 if(mode & 8) return value; 104 if((mode & 4) && typeof value === 'object' && value && value.__esMo
104dule) return value; 105 var ns = Object.create(null); 106 __webpack_require__.r(ns); 107 Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 108 if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 109 return ns; 110 }; 111 __webpack_require__.n = function(module) { 112 var getter = module && module.__esModule ? 113 function getDefault() { return module['default']; } : 114 function getModuleExports() { return module; }; 115 __webpack_require__.d(getter, 'a', getter); 116 return getter; 117 }; 118 __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 119 __webpack_require__.p = ""; 120 return __webpack_require__(__webpack_require__.s = 31); 121 }) 122 ([ 123 (function(module, exports, __webpack_require__) { 124 125var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(){"use strict";function a(t,e){this.isUndef(t)||1===t?this.input=this.context.createGain():1<t&&(this.input=new Array(t)),this.isUndef(e)||1===e?this.output=this.context.createGain():1<e&&(this.output=new Array(t))}var e;return a.prototype.set=function(t,e,n){if(this.isObject(t))n=e;else if(this.isString(t)){var o={};o[t]=e,t=o}t:for(var i in t){e=t[i];var r=this;if(-1!==i.indexOf(".")){for(var s=i.split("."),u=0;u<s.length-1;u++)if((r=r[s[u]])instanceof a){s.splice(0,u+1);var p=s.join(".");r.set(p,e);continue t}i=s[s.length-1]}var c=r[i];this.isUndef(c)||(a.Signal&&c instanceof a.Signal||a.Param&&c instanceof a.Param?c.value!==e&&(this.isUndef(n)?c.value=e:c.rampTo(e,n)):c instanceof AudioParam?c.value!==e&&(c.value=e):c instanceof a?c.set(e):c!==e&&(r[i]=e))}return this},a.prototype.get=function(t){this.isUndef(t)?t=this._collectDefaults(this.constructor):this.isString(t)&&(t=[t]);for(var e={},n=0;n<t.length;n++){var o=t[n],i=this,r=e;if(-1!==o.indexOf(".")){for(var s=o.split("."),u=0;u<s.length-1;u++){var p=s[u];r[p]=r[p]||{},r=r[p],i=i[p]}o=s[s.length-1]}var c=i[o];this.isObject(t[o])?r[o]=c.get():a.Signal&&c instanceof a.Signal?r[o]=c.value:a.Param&&c instanceof a.Param?r[o]=c.value:c instanceof AudioParam?r[o]=c.value:c instanceof a?r[o]=c.get():this.isFunction(c)||this.isUndef(c)||(r[o]=c)}return e},a.prototype._collectDefaults=function(t){var e=[];if(this.isUndef(t.defaults)||(e=Object.keys(t.defaults)),!this.isUndef(t._super))for(var n=this._collectDefaults(t._super),o=0;o<n.length;o++)-1===e.indexOf(n[o])&&e.push(n[o]);return e},a.prototype.toString=function(){for(var t in a){var e=t[0].match(/^[A-Z]$/),n=a[t]===this.constructor;if(this.isFunction(a[t])&&e&&n)return t}return"Tone"},Object.defineProperty(a.prototype,"numberOfInputs",{get:function(){return this.input?this.isArray(this.input)?this.input.length:1:0}}),Object.defineProperty(a.prototype,"numberOfOutputs",{get:function(){return this.output?this.isArray(this.output)?this.output.length:1:0}}),a.prototype.dispose=function(){return this.isUndef(this.input)||(this.input instanceof AudioNode&&this.input.disconnect(),this.input=null),this.isUndef(this.output)||(this.output instanceof AudioNode&&this.output.disconnect(),this.output=null),this},a.prototype.connect=function(t,e,n){return Array.isArray(this.output)?(e=this.defaultArg(e,0),this.output[e].connect(t,0,n)):this.output.connect(t,e,n),this},a.prototype.disconnect=function(t,e,n){this.isArray(this.output)?this.isNumber(t)?this.output[t].disconnect():(e=this.defaultArg(e,0),this.output[e].disconnect(t,0,n)):this.output.disconnect.apply(this.output,arguments)},a.prototype.connectSeries=function(){if(1<arguments.length)for(var t=arguments[0],e=1;e<arguments.length;e++){var n=arguments[e];t.connect(n),t=n}return this},a.prototype.chain=function(){if(0<arguments.length)for(var t=this,e=0;e<arguments.length;e++){var n=arguments[e];t.connect(n),t=n}return this},a.prototype.fan=function(){if(0<arguments.length)for(var t=0;t<arguments.length;t++)this.connect(arguments[t]);return this},AudioNode.prototype.chain=a.prototype.chain,AudioNode.prototype.fan=a.prototype.fan,a.prototype.defaultArg=function(t,e){if(this.isObject(t)&&this.isObject(e)){var n={};for(var o in t)n[o]=this.defaultArg(e[o],t[o]);for(var i in e)n[i]=this.defaultArg(t[i],e[i]);return n}return this.isUndef(t)?e:t},a.prototype.optionsObject=function(t,e,n){var o={};if(1===t.length&&this.isObject(t[0]))o=t[0];else for(var i=0;i<e.length;i++)o[e[i]]=t[i];return this.isUndef(n)?o:this.defaultArg(o,n)},a.prototype.isUndef=function(t){return void 0===t},a.prototype.isFunction=function(t){return"function"==typeof t},a.prototype.isNumber=function(t){return"number"==typeof t},a.prototype.isObject=function(t){return"[object Object]"===Object.prototype.toString.call(t)&&t.constructor===Object},a.prototype.isBoolean=function(t){return"boolean"==typeof t},a.prototype.isArray=function(t){return Array.isArray(t)},a.prototype.isString=function(t){return"string"==typeof t},a.noOp=function(){},a.prototype._readOnly=function(t){if(Array.isArray(t))for(var e=0;e<t.length;e++)this._readOnly(t[e]);else Object.defineProperty(this,t,{writable:!1,enumerable:!0})},a.prototype._writable=function(t){if(Array.isArray(t))for(var e=0;e<t.length;e++)this._writable(t[e]);else Object.defineProperty(this,t,{writable:!0})},a.State={Started:"started",Stopped:"stopped",Paused:"paused"},a.prototype.equalPowerScale=function(t){var e=.5*Math.PI;return Math.sin(t*e)},a.prototype.dbToGain=function(t){return Math.pow(2,t/6)},a.prototype.gainToDb=function(t){return Math.log(t)/Math.LN10*20},a.prototype.intervalToFrequencyRatio=function(t){return Math.pow(2,t/12)},a.prototype.now=function(){return a.context.now()},a.now=function(){return a.context.now()},a.extend=function(t,e){function n(){}a.prototype.isUndef(e)&&(e=a),n.prototype=e.prototype,t.prototype=new n,(t.prototype.constructor=t)._super=e},Object.defineProperty(a,"context",{get:function(){return e},set:function(t){e=a.Context&&t instanceof a.Context?t:new a.Context(t),a.Context&&a.Context.emit("init",e)}}),Object.defineProperty(a.prototype,"context",{get:function(){return a.context}}),a.setContext=function(t){a.context=t},Object.defineProperty(a.prototype,"blockTime",{get:function(){return 128/this.context.sampleRate}}),Object.defineProperty(a.prototype,"sampleTime",{get:function(){return 1/this.context.sampleRate}}),Object.defineProperty(a,"supported",{get:function(){var t=window.hasOwnProperty("AudioContext")||window.hasOwnProperty("webkitAudioContext"),e=window.hasOwnProperty("Promise"),n=window.hasOwnProperty("Worker");return t&&e&&n}}),a.version="r10",window.TONE_SILENCE_VERSION_LOGGING||console.log("%c * Tone.js "+a.version+" * ","background: #000; color: #fff"),a}).call(exports, __webpack_require__, exports, module), 126 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 127 128 }), 129 (function(module, exports, __webpack_require__) { 130 131"use strict"; 132var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__; 133 134!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(17)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (audiocontext) { 135 var Master = function Master() { 136 this.input = audiocontext.createGain(); 137 this.output = audiocontext.createGain(); 138 139 this.limiter = audiocontext.createDynamicsCompressor(); 140 this.limiter.threshold.value = -3; 141 this.limiter.ratio.value = 20; 142 this.limiter.knee.value = 1; 143 this.audiocontext = audiocontext; 144 this.output.disconnect(); 145 146 this.input.connect(this.limiter); 147 148 this.limiter.connect(this.output); 149 150 this.meter = audiocontext.createGain(); 151 this.fftMeter = audiocontext.createGain(); 152 this.output.connect(this.meter); 153 this.output.connect(this.fftMeter); 154 155 this.output.connect(this.audiocontext.destination); 156 157 this.soundArray = []; 158 159 this.parts = []; 160 161 this.extensions = []; 162 }; 163 164 165 var p5sound = new Master(); 166 /** 167 * Returns a number representing the master amplitude (volume) for sound 168 * in this sketch. 169 * 170 * @method getMasterVolume 171 * @return {Number} Master amplitude (volume) for sound in this sketch. 172 * Should be between 0.0 (silence) and 1.0. 173 */ 174 175 p5.prototype.getMasterVolume = function () { 176 return p5sound.output.gain.value; 177 }; 178 /** 179 * <p>Scale the output of all sound in this sketch</p> 180 * Scaled between 0.0 (silence) and 1.0 (full volume). 181 * 1.0 is the maximum amplitude of a digital sound, so multiplying 182 * by greater than 1.0 may cause digital distortion. To 183 * fade, provide a <code>rampTime</code> parameter. For more 184 * complex fades, see the Envelope class. 185 * 186 * Alternately, you can pass in a signal source such as an 187 * oscillator to modulate the amplitude with an audio signal. 188 * 189 * <p><b>How This Works</b>: When you load the p5.sound module, it 190 * creates a single instance of p5sound. All sound objects in this 191 * module output to p5sound before reaching your computer's output. 192 * So if you change the amplitude of p5sound, it impacts all of the 193 * sound in this module.</p> 194 * 195 * <p>If no value is provided, returns a Web Audio API Gain Node</p> 196 * 197 * @method masterVolume 198 * @param {Number|Object} volume Volume (amplitude) between 0.0 199 * and 1.0 or modulating signal/oscillator 200 * @param {Number} [rampTime] Fade for t seconds 201 * @param {Number} [timeFromNow] Schedule this event to happen at
202 * t seconds in the future 203 */ 204 205 206 p5.prototype.masterVolume = function (vol, rampTime, tFromNow) { 207 if (typeof vol === 'number') { 208 var rampTime = rampTime || 0; 209 var tFromNow = tFromNow || 0; 210 var now = p5sound.audiocontext.currentTime; 211 var currentVol = p5sound.output.gain.value; 212 p5sound.output.gain.cancelScheduledValues(now + tFromNow); 213 p5sound.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow); 214 p5sound.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime); 215 } else if (vol) { 216 vol.connect(p5sound.output.gain); 217 } else { 218 return p5sound.output.gain; 219 } 220 }; 221 /** 222 * `p5.soundOut` is the p5.sound master output. It sends output to 223 * the destination of this window's web audio context. It contains 224 * Web Audio API nodes including a dyanmicsCompressor (<code>.limiter</code>), 225 * and Gain Nodes for <code>.input</code> and <code>.output</code>. 226 * 227 * @property {Object} soundOut 228 */ 229 230 231 p5.prototype.soundOut = p5.soundOut = p5sound; 232 233 p5.soundOut._silentNode = p5sound.audiocontext.createGain(); 234 p5.soundOut._silentNode.gain.value = 0; 235 236 p5.soundOut._silentNode.connect(p5sound.audiocontext.destination); 237 238 return p5sound; 239}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 240 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 241 242 }), 243 (function(module, exports, __webpack_require__) { 244 245var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(5),__webpack_require__(8),__webpack_require__(22),__webpack_require__(9)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(n){"use strict";return n.Signal=function(){var t=this.optionsObject(arguments,["value","units"],n.Signal.defaults);this.output=this._gain=this.context.createGain(),t.param=this._gain.gain,n.Param.call(this,t),this.input=this._param=this._gain.gain,this.context.getConstant(1).chain(this._gain)},n.extend(n.Signal,n.Param),n.Signal.defaults={value:0,units:n.Type.Default,convert:!0},n.Signal.prototype.connect=n.SignalBase.prototype.connect,n.Signal.prototype.dispose=function(){return n.Param.prototype.dispose.call(this),this._param=null,this._gain.disconnect(),this._gain=null,this},n.Signal}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 246 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 247 248 }), 249 (function(module, exports, __webpack_require__) { 250 251var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(2),__webpack_require__(9)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(i){"use strict";return i.Multiply=function(t){this.createInsOuts(2,0),this._mult=this.input[0]=this.output=new i.Gain,this._param=this.input[1]=this.output.gain,this._param.value=this.defaultArg(t,0)},i.extend(i.Multiply,i.Signal),i.Multiply.prototype.dispose=function(){return i.prototype.dispose.call(this),this._mult.dispose(),this._mult=null,this._param=null,this},i.Multiply}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 252 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 253 254 }), 255 (function(module, exports, __webpack_require__) { 256 257"use strict"; 258var __WEBPACK_AMD_DEFINE_RESULT__; 259 260!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 261 var p5sound = __webpack_require__(1); 262 263 var CrossFade = __webpack_require__(51); 264 /** 265 * Effect is a base class for audio effects in p5. <br> 266 * This module handles the nodes and methods that are 267 * common and useful for current and future effects. 268 * 269 * 270 * This class is extended by <a href="/reference/#/p5.Distortion">p5.Distortion</a>, 271 * <a href="/reference/#/p5.Compressor">p5.Compressor</a>, 272 * <a href="/reference/#/p5.Delay">p5.Delay</a>, 273 * <a href="/reference/#/p5.Filter">p5.Filter</a>, 274 * <a href="/reference/#/p5.Reverb">p5.Reverb</a>. 275 * 276 * @class p5.Effect 277 * @constructor 278 * 279 * @param {Object} [ac] Reference to the audio context of the p5 object 280 * @param {AudioNode} [input] Gain Node effect wrapper 281 * @param {AudioNode} [output] Gain Node effect wrapper 282 * @param {Object} [_drywet] Tone.JS CrossFade node (defaults to value: 1) 283 * @param {AudioNode} [wet] Effects that extend this class should connect 284 * to the wet signal to this gain
284node, so that dry and wet 285 * signals are mixed properly. 286 */ 287 288 289 p5.Effect = function () { 290 this.ac = p5sound.audiocontext; 291 this.input = this.ac.createGain(); 292 this.output = this.ac.createGain(); 293 /** 294 * The p5.Effect class is built 295 * using Tone.js CrossFade 296 * @private 297 */ 298 299 this._drywet = new CrossFade(1); 300 /** 301 * In classes that extend 302 * p5.Effect, connect effect nodes 303 * to the wet parameter 304 */ 305 306 this.wet = this.ac.createGain(); 307 this.input.connect(this._drywet.a); 308 this.wet.connect(this._drywet.b); 309 310 this._drywet.connect(this.output); 311 312 this.connect(); 313 314 p5sound.soundArray.push(this); 315 }; 316 /** 317 * Set the output volume of the filter. 318 * 319 * @method amp 320 * @for p5.Effect 321 * @param {Number} [vol] amplitude between 0 and 1.0 322 * @param {Number} [rampTime] create a fade that lasts until rampTime 323 * @param {Number} [tFromNow] schedule this event to happen in tFromNow seconds 324 */ 325 326 327 p5.Effect.prototype.amp = function (vol, rampTime, tFromNow) { 328 var rampTime = rampTime || 0; 329 var tFromNow = tFromNow || 0; 330 var now = p5sound.audiocontext.currentTime; 331 var currentVol = this.output.gain.value; 332 this.output.gain.cancelScheduledValues(now); 333 this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow + .001); 334 this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime + .001); 335 }; 336 /** 337 * Link effects together in a chain 338 * Example usage: filter.chain(reverb, delay, panner); 339 * May be used with an open-ended number of arguments 340 * 341 * @method chain 342 * @for p5.Effect 343 * @param {Object} [arguments] Chain together multiple sound objects 344 */ 345 346 347 p5.Effect.prototype.chain = function () { 348 if (arguments.length > 0) { 349 this.connect(arguments[0]); 350 351 for (var i = 1; i < arguments.length; i += 1) { 352 arguments[i - 1].connect(arguments[i]); 353 } 354 } 355 356 return this; 357 }; 358 /** 359 * Adjust the dry/wet value. 360 * 361 * @method drywet 362 * @for p5.Effect 363 * @param {Number} [fade] The desired drywet value (0 - 1.0) 364 */ 365 366 367 p5.Effect.prototype.drywet = function (fade) { 368 if (typeof fade !== "undefined") { 369 this._drywet.fade.value = fade; 370 } 371 372 return this._drywet.fade.value; 373 }; 374 /** 375 * Send output to a p5.js-sound, Web Audio Node, or use signal to 376 * control an AudioParam 377 * 378 * @method connect 379 * @for p5.Effect 380 * @param {Object} unit 381 */ 382 383 384 p5.Effect.prototype.connect = function (unit) { 385 var u = unit || p5.soundOut.input; 386 this.output.connect(u.input ? u.input : u); 387 }; 388 /** 389 * Disconnect all output. 390 * @method disconnect 391 * @for p5.Effect 392 */ 393 394 395 p5.Effect.prototype.disconnect = function () { 396 if (this.output) { 397 this.output.disconnect(); 398 } 399 }; 400 401 p5.Effect.prototype.dispose = function () { 402 var index = p5sound.soundArray.indexOf(this); 403 p5sound.soundArray.splice(index, 1); 404 405 if (this.input) { 406 this.input.disconnect(); 407 delete this.input; 408 } 409 410 if (this.output) { 411 this.output.disconnect(); 412 delete this.output; 413 } 414 415 if (this._drywet) { 416 this._drywet.disconnect(); 417 418 delete this._drywet; 419 } 420 421 if (this.wet) { 422 this.wet.disconnect(); 423 delete this.wet; 424 } 425 426 this.ac = undefined; 427 }; 428 429 return p5.Effect; 430}).call(exports, __webpack_require__, exports, module), 431 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 432 433 }), 434 (function(module, exports, __webpack_require__) { 435 436var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(19)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(e){"use strict";return e.WaveShaper=function(e,t){this._shaper=this.input=this.output=this.context.createWaveShaper(),this._curve=null,Array.isArray(e)?this.curve=e:isFinite(e)||this.isUndef(e)?this._curve=new Float32Array(this.defaultArg(e,1024)):this.isFunction(e)&&(this._curve=new Float32Array(this.defaultArg(t,1024)),this.setMap(e))},e.extend(e.WaveShaper,e.SignalBase),e.WaveShaper.prototype.setMap=function(e){for(var t=0,r=this._curve.length;t<r;t++){var s=t/(r-1)*2-1;this._curve[t]=e(s,t)}return this._shaper.curve=this._curve,this},Object.defineProperty(e.WaveShaper.prototype,"curve",{get:function(){return this._shaper.curve},set:function(e){this._curve=new Float32Array(e),this._shaper.curve=this._curve}}),Object.defineProperty(e.WaveShaper.prototype,"oversample",{get:function(){return this._shaper.oversample},set:function(e){if(-1===["none","2x","4x"].indexOf(e))throw new RangeError("Tone.WaveShaper: oversampling must be either 'none', '2x', or '4x'");this._shaper.oversample=e}}),e.WaveShaper.prototype.dispose=function(){return e.prototype.dispose.call(this),this._shaper.disconnect(),this._shaper=null,this._curve=null,this},e.WaveShaper}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 437 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 438 439 }), 440 (function(module, exports, __webpack_require__) { 441 442"use strict"; 443var __WEBPACK_AMD_DEFINE_RESULT__; 444 445function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 446 447!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 448 var p5sound = __webpack_require__(1); 449 450 var processorNames = __webpack_require__(10); 451 /** 452 * @for p5 453 */ 454 455 /** 456 * Returns a number representing the sample rate, in samples per second, 457 * of all sound objects in this audio context. It is determined by the 458 * sampling rate of your operating system's sound card, and it is not 459 * currently possile to change. 460 * It is often 44100, or twice the range of human hearing. 461 * 462 * @method sampleRate 463 * @return {Number} samplerate samples per second 464 */ 465 466 467 p5.prototype.sampleRate = function () { 468 return p5sound.audiocontext.sampleRate; 469 }; 470 /** 471 * Returns the closest MIDI note value for 472 * a given frequency. 473 * 474 * @method freqToMidi 475 * @param {Number} frequency A freqeuncy, for example, the "A" 476 * above Middle C is 440Hz 477 * @return {Number} MIDI note value 478 */ 479 480 481 p5.prototype.freqToMidi = function (f) { 482 var mathlog2 = Math.log(f / 440) / Math.log(2); 483 var m = Math.round(12 * mathlog2) + 69; 484 return m; 485 }; 486 /**
487 * Returns the frequency value of a MIDI note value. 488 * General MIDI treats notes as integers where middle C 489 * is 60, C# is 61, D is 62 etc. Useful for generating 490 * musical frequencies with oscillators. 491 * 492 * @method midiToFreq 493 * @param {Number} midiNote The number of a MIDI note 494 * @return {Number} Frequency value of the given MIDI note 495 * @example 496 * <div><code> 497 * let midiNotes = [60, 64, 67, 72]; 498 * let noteIndex = 0; 499 * let midiVal, freq; 500 * 501 * function setup() { 502 * let cnv = createCanvas(100, 100); 503 * cnv.mousePressed(startSound); 504 * osc = new p5.TriOsc(); 505 * env = new p5.Envelope(); 506 * } 507 * 508 * function draw() { 509 * background(220); 510 * text('tap to play', 10, 20); 511 * if (midiVal) { 512 * text('MIDI: ' + midiVal, 10, 40); 513 * text('Freq: ' + freq, 10, 60); 514 * } 515 * } 516 * 517 * function startSound() { 518 * // see also: userStartAudio(); 519 * osc.start(); 520 * 521 * midiVal = midiNotes[noteIndex % midiNotes.length]; 522 * freq = midiToFreq(midiVal); 523 * osc.freq(freq); 524 * env.ramp(osc, 0, 1.0, 0); 525 * 526 * noteIndex++; 527 * } 528 * </code></div> 529 */ 530 531 532 var midiToFreq = p5.prototype.midiToFreq = function (m) { 533 return 440 * Math.pow(2, (m - 69) / 12.0); 534 }; 535 536 537 var noteToFreq = function noteToFreq(note) { 538 if (typeof note !== 'string') { 539 return note; 540 } 541 542 var wholeNotes = { 543 A: 21, 544 B: 23, 545 C: 24, 546 D: 26, 547 E: 28, 548 F: 29, 549 G: 31 550 }; 551 var value = wholeNotes[note[0].toUpperCase()]; 552 var octave = ~~note.slice(-1); 553 value += 12 * (octave - 1); 554 555 switch (note[1]) { 556 case '#': 557 value += 1; 558 break; 559 560 case 'b': 561 value -= 1; 562 break; 563 564 default: 565 break; 566 } 567 568 return midiToFreq(value); 569 }; 570 /** 571 * List the SoundFile formats that you will include. LoadSound 572 * will search your directory for these extensions, and will pick 573 * a format that is compatable with the client's web browser. 574 * <a href="http://media.io/">Here</a> is a free online file 575 * converter. 576 * 577 * @method soundFormats 578 * @param {String} [...formats] i.e. 'mp3', 'wav', 'ogg' 579 * @example 580 * <div><code> 581 * function preload() { 582 * // set the global sound formats 583 * soundFormats('mp3', 'ogg'); 584 * 585 * // load either beatbox.mp3, or .ogg, depending on browser 586 * mySound = loadSound('assets/beatbox.mp3'); 587 * } 588 * 589 * function setup() { 590 * let cnv = createCanvas(100, 100); 591 * background(220); 592 * text('sound loaded! tap to play', 10, 20, width - 20); 593 * cnv.mousePressed(function() { 594 * mySound.play(); 595 * }); 596 * } 597 * </code></div> 598 */ 599 600 601 p5.prototype.soundFormats = function () { 602 p5sound.extensions = []; 603 604 for (var i = 0; i < arguments.length; i++) { 605 arguments[i] = arguments[i].toLowerCase(); 606 607 if (['mp3', 'wav', 'ogg', 'm4a', 'aac'].indexOf(arguments[i]) > -1) { 608 p5sound.extensions.push(arguments[i]); 609 } else { 610 throw arguments[i] + ' is not a valid sound format!'; 611 } 612 } 613 }; 614 615 p5.prototype.disposeSound = function () { 616 for (var i = 0; i < p5sound.soundArray.length; i++) { 617 p5sound.soundArray[i].dispose(); 618 } 619 }; 620 621 622 p5.prototype.registerMethod('remove', p5.prototype.disposeSound); 623 624 p5.prototype._checkFileFormats = function (paths) { 625 var path; 626 627 if (typeof paths === 'string') { 628 path = paths; 629 630 var extTest = path.split('.').pop(); 631 632 if (['mp3', 'wav', 'ogg', 'm4a', 'aac'].indexOf(extTest) > -1) { 633 if (p5.prototype.isFileSupported(extTest)) { 634 path = path; 635 } else { 636 var pathSplit = path.split('.'); 637 var pathCore = pathSplit[pathSplit.length - 1]; 638 639 for (var i = 0; i < p5sound.extensions.length; i++) { 640 var extension = p5sound.extensions[i]; 641 var supported = p5.prototype.isFileSupported(extension); 642 643 if (supported) { 644 pathCore = ''; 645 646 if (pathSplit.length === 2) { 647 pathCore += pathSplit[0]; 648 } 649 650 for (var i = 1; i <= pathSplit.length - 2; i++) { 651 var p = pathSplit[i]; 652 pathCore += '.' + p; 653 } 654 655 path = pathCore += '.'; 656 path = path += extension; 657 break; 658 } 659 } 660 } 661 } 662 else { 663 for (var i = 0; i < p5sound.extensions.length; i++) { 664 var extension = p5sound.extensions[i]; 665 var supported = p5.prototype.isFileSupported(extension); 666 667 if (supported) { 668 path = path + '.' + extension; 669 break; 670 } 671 } 672 } 673 } 674 else if (_typeof(paths) === 'object') { 675 for (var i = 0; i < paths.length; i++) { 676 var extension = paths[i].split('.').pop(); 677 var supported = p5.prototype.isFileSupported(extension); 678 679 if (supported) { 680 path = paths[i]; 681 break; 682 } 683 } 684 } 685 686 return path; 687 }; 688 /** 689 * Used by Osc and Envelope to chain signal math 690 */ 691 692 693 p5.prototype._mathChain = function (o, math, thisChain, nextChain, type) { 694 for (var i in o.mathOps) { 695 if (o.mathOps[i] instanceof type) { 696 o.mathOps[i].dispose(); 697 thisChain = i; 698 699 if (thisChain < o.mathOps.length - 1) { 700 nextChain = o.mathOps[i + 1]; 701 } 702 } 703 } 704 705 o.mathOps[thisChain - 1].disconnect(); 706 o.mathOps[thisChain - 1].connect(math); 707 math.connect(nextChain); 708 o.mathOps[thisChain] = math; 709 return o; 710 }; 711 712 713 function convertToWav(audioBuffer) {
714 var leftChannel, rightChannel; 715 leftChannel = audioBuffer.getChannelData(0); 716 717 if (audioBuffer.numberOfChannels > 1) { 718 rightChannel = audioBuffer.getChannelData(1); 719 } else { 720 rightChannel = leftChannel; 721 } 722 723 var interleaved = interleave(leftChannel, rightChannel); 724 725 var buffer = new window.ArrayBuffer(44 + interleaved.length * 2); 726 var view = new window.DataView(buffer); 727 728 writeUTFBytes(view, 0, 'RIFF'); 729 view.setUint32(4, 36 + interleaved.length * 2, true); 730 writeUTFBytes(view, 8, 'WAVE'); 731 732 writeUTFBytes(view, 12, 'fmt '); 733 view.setUint32(16, 16, true); 734 view.setUint16(20, 1, true); 735 736 view.setUint16(22, 2, true); 737 view.setUint32(24, p5sound.audiocontext.sampleRate, true); 738 view.setUint32(28, p5sound.audiocontext.sampleRate * 4, true); 739 view.setUint16(32, 4, true); 740 view.setUint16(34, 16, true); 741 742 writeUTFBytes(view, 36, 'data'); 743 view.setUint32(40, interleaved.length * 2, true); 744 745 var lng = interleaved.length; 746 var index = 44; 747 var volume = 1; 748 749 for (var i = 0; i < lng; i++) { 750 view.setInt16(index, interleaved[i] * (0x7FFF * volume), true); 751 index += 2; 752 } 753 754 return view; 755 } 756 757 758 function interleave(leftChannel, rightChannel) { 759 var length = leftChannel.length + rightChannel.length; 760 var result = new Float32Array(length); 761 var inputIndex = 0; 762 763 for (var index = 0; index < length;) { 764 result[index++] = leftChannel[inputIndex]; 765 result[index++] = rightChannel[inputIndex]; 766 inputIndex++; 767 } 768 769 return result; 770 } 771 772 function writeUTFBytes(view, offset, string) { 773 var lng = string.length; 774 775 for (var i = 0; i < lng; i++) { 776 view.setUint8(offset + i, string.charCodeAt(i)); 777 } 778 } 779 780 function safeBufferSize(idealBufferSize) { 781 var bufferSize = idealBufferSize; 782 783 var tempAudioWorkletNode = new AudioWorkletNode(p5sound.audiocontext, processorNames.soundFileProcessor); 784 785 if (tempAudioWorkletNode instanceof ScriptProcessorNode) { 786 bufferSize = tempAudioWorkletNode.bufferSize; 787 } 788 789 tempAudioWorkletNode.disconnect(); 790 tempAudioWorkletNode = null; 791 return bufferSize; 792 } 793 794 return { 795 convertToWav: convertToWav, 796 midiToFreq: midiToFreq, 797 noteToFreq: noteToFreq, 798 safeBufferSize: safeBufferSize 799 }; 800}).call(exports, __webpack_require__, exports, module), 801 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 802 803 }), 804 (function(module, exports, __webpack_require__) { 805 806var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(2),__webpack_require__(9)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(i){"use strict";return i.Add=function(t){this.createInsOuts(2,0),this._sum=this.input[0]=this.input[1]=this.output=new i.Gain,this._param=this.input[1]=new i.Signal(t),this._param.connect(this._sum)},i.extend(i.Add,i.Signal),i.Add.prototype.dispose=function(){return i.prototype.dispose.call(this),this._sum.dispose(),this._sum=null,this._param.dispose(),this._param=null,this},i.Add}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 807 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 808 809 }), 810 (function(module, exports, __webpack_require__) { 811 812var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(20),__webpack_require__(45),__webpack_require__(46),__webpack_require__(12)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(t){return t.Type={Default:"number",Time:"time",Frequency:"frequency",TransportTime:"transportTime",Ticks:"ticks",NormalRange:"normalRange",AudioRange:"audioRange",Decibels:"db",Interval:"interval",BPM:"bpm",Positive:"positive",Cents:"cents",Degrees:"degrees",MIDI:"midi",BarsBeatsSixteenths:"barsBeatsSixteenths",Samples:"samples",Hertz:"hertz",Note:"note",Milliseconds:"milliseconds",Seconds:"seconds",Notation:"notation"},t.prototype.toSeconds=function(e){return this.isNumber(e)?e:this.isUndef(e)?this.now():this.isString(e)?new t.Time(e).toSeconds():e instanceof t.TimeBase?e.toSeconds():void 0},t.prototype.toFrequency=function(e){return this.isNumber(e)?e:this.isString(e)||this.isUndef(e)?new t.Frequency(e).valueOf():e instanceof t.TimeBase?e.toFrequency():void 0},t.prototype.toTicks=function(e){return this.isNumber(e)||this.isString(e)?new t.TransportTime(e).toTicks():this.isUndef(e)?t.Transport.ticks:e instanceof t.TimeBase?e.toTicks():void 0},t}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 813 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 814 815 }), 816 (function(module, exports, __webpack_require__) { 817 818var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(22),__webpack_require__(8)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(i){"use strict";return window.GainNode&&!AudioContext.prototype.createGain&&(AudioContext.prototype.createGain=AudioContext.prototype.createGainNode),i.Gain=function(){var t=this.optionsObject(arguments,["gain","units"],i.Gain.defaults);this.input=this.output=this._gainNode=this.context.createGain(),this.gain=new i.Param({param:this._gainNode.gain,units:t.units,value:t.gain,convert:t.convert}),this._readOnly("gain")},i.extend(i.Gain),i.Gain.defaults={gain:1,convert:!0},i.Gain.prototype.dispose=function(){i.Param.prototype.dispose.call(this),this._gainNode.disconnect(),this._gainNode=null,this._writable("gain"),this.gain.dispose(),this.gain=null},i.prototype.createInsOuts=function(t,n){1===t?this.input=new i.Gain:1<t&&(this.input=new Array(t)),1===n?this.output=new i.Gain:1<n&&(this.output=new Array(t))},i.Gain}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 819 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 820 821 }),
822 (function(module, exports) { 823 824module.exports = { 825 recorderProcessor: 'recorder-processor', 826 soundFileProcessor: 'sound-file-processor', 827 amplitudeProcessor: 'amplitude-processor' 828}; 829 830 }), 831 (function(module, exports, __webpack_require__) { 832 833"use strict"; 834var __WEBPACK_AMD_DEFINE_RESULT__; 835 836!(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { 837 var CustomError = function CustomError(name, errorTrace, failedPath) { 838 var err = new Error(); 839 var tempStack, splitStack; 840 err.name = name; 841 err.originalStack = err.stack + errorTrace; 842 tempStack = err.stack + errorTrace; 843 err.failedPath = failedPath; 844 845 var splitStack = tempStack.split('\n'); 846 splitStack = splitStack.filter(function (ln) { 847 return !ln.match(/(p5.|native code|globalInit)/g); 848 }); 849 err.stack = splitStack.join('\n'); 850 return err; 851 }; 852 853 return CustomError; 854}).call(exports, __webpack_require__, exports, module), 855 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 856 857 }), 858 (function(module, exports, __webpack_require__) { 859 860var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(18)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(o){function t(e,t,n){if(e.input)Array.isArray(e.input)?(o.prototype.isUndef(n)&&(n=0),this.connect(e.input[n])):this.connect(e.input,t,n);else try{e instanceof AudioNode?i.call(this,e,t,n):i.call(this,e,t)}catch(t){throw new Error("error connecting to node: "+e+"\n"+t)}}var i,r;return!window.hasOwnProperty("AudioContext")&&window.hasOwnProperty("webkitAudioContext")&&(window.AudioContext=window.webkitAudioContext),o.Context=function(t){for(var e in o.Emitter.call(this),t=t||new window.AudioContext,this._context=t,this._context)this._defineProperty(this._context,e);this._latencyHint="interactive",this._lookAhead=.1,this._updateInterval=this._lookAhead/3,this._computedUpdateInterval=0,this._worker=this._createWorker(),this._constants={}},o.extend(o.Context,o.Emitter),o.Emitter.mixin(o.Context),o.Context.prototype._defineProperty=function(e,n){this.isUndef(this[n])&&Object.defineProperty(this,n,{get:function(){return"function"==typeof e[n]?e[n].bind(e):e[n]},set:function(t){e[n]=t}})},o.Context.prototype.now=function(){return this._context.currentTime},o.Context.prototype._createWorker=function(){window.URL=window.URL||window.webkitURL;var t=new Blob(["var timeoutTime = "+(1e3*this._updateInterval).toFixed(1)+";self.onmessage = function(msg){\ttimeoutTime = parseInt(msg.data);};function tick(){\tsetTimeout(tick, timeoutTime);\tself.postMessage('tick');}tick();"]),e=URL.createObjectURL(t),n=new Worker(e);return n.addEventListener("message",function(){this.emit("tick")}.bind(this)),n.addEventListener("message",function(){var t=this.now();if(this.isNumber(this._lastUpdate)){var e=t-this._lastUpdate;this._computedUpdateInterval=Math.max(e,.97*this._computedUpdateInterval)}this._lastUpdate=t}.bind(this)),n},o.Context.prototype.getConstant=function(t){if(this._constants[t])return this._constants[t];for(var e=this._context.createBuffer(1,128,this._context.sampleRate),n=e.getChannelData(0),o=0;o<n.length;o++)n[o]=t;var i=this._context.createBufferSource();return i.channelCount=1,i.channelCountMode="explicit",i.buffer=e,i.loop=!0,i.start(0),this._constants[t]=i},Object.defineProperty(o.Context.prototype,"lag",{get:function(){var t=this._computedUpdateInterval-this._updateInterval;return t=Math.max(t,0)}}),Object.defineProperty(o.Context.prototype,"lookAhead",{get:function(){return this._lookAhead},set:function(t){this._lookAhead=t}}),Object.defineProperty(o.Context.prototype,"updateInterval",{get:function(){return this._updateInterval},set:function(t){this._updateInterval=Math.max(t,o.prototype.blockTime),this._worker.postMessage(Math.max(1e3*t,1))}}),Object.defineProperty(o.Context.prototype,"latencyHint",{get:function(){return this._latencyHint},set:function(t){var e=t;if(this._latencyHint=t,this.isString(t))switch(t){case"interactive":e=.1,this._context.latencyHint=t;break;case"playback":e=.8,this._context.latencyHint=t;break;case"balanced":e=.25,this._context.latencyHint=t;break;case"fastest":e=.01}this.lookAhead=e,this.updateInterval=e/3}}),o.supported?(i=AudioNode.prototype.connect,r=AudioNode.prototype.disconnect,AudioNode.prototype.connect!==t&&(AudioNode.prototype.connect=t,AudioNode.prototype.disconnect=function(e,t,n){if(e&&e.input&&Array.isArray(e.input))o.prototype.isUndef(n)&&(n=0),this.disconnect(e.input[n],t,n);else if(e&&e.input)this.disconnect(e.input,t,n);else try{r.apply(this,arguments)}catch(t){throw new Error("error disconnecting node: "+e+"\n"+t)}}),o.context=new o.Context):console.warn("This browser does not support Tone.js"),o.Context}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 861 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 862 863 }), 864 (function(module, exports, __webpack_require__) { 865 866var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(7),__webpack_require__(3),__webpack_require__(2)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(i){"use strict";return i.Scale=function(t,e){this._outputMin=this.defaultArg(t,0),this._outputMax=this.defaultArg(e,1),this._scale=this.input=new i.Multiply(1),this._add=this.output=new i.Add(0),this._scale.connect(this._add),this._setRange()},i.extend(i.Scale,i.SignalBase),Object.defineProperty(i.Scale.prototype,"min",{get:function(){return this._outputMin},set:function(t){this._outputMin=t,this._setRange()}}),Object.defineProperty(i.Scale.prototype,"max",{get:function(){return this._outputMax},set:function(t){this._outputMax=t,this._setRange()}}),i.Scale.prototype._setRange=function(){this._add.value=this._outputMin,this._scale.value=this._outputMax-this._outputMin},i.Scale.prototype.dispose=function(){return i.prototype.dispose.call(this),this._add.dispose(),this._add=null,this._scale.dispose(),this._scale=null,this},i.Scale}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 867 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 868 869 }), 870 (function(module, exports, __webpack_require__) { 871 872var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(2),__webpack_require__(24)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(o){"use strict";return o.TimelineSignal=function(){var e=this.optionsObject(arguments,["value","units"],o.Signal.defaults);this._events=new o.Timeline(10),o.Signal.apply(this,e),e.param=this._param,o.Param.call(this,e),this._initial=this._fromUnits(this._param.value)},o.extend(o.TimelineSignal,o.Param),o.TimelineSignal.Type={Linear:"linear",Exponential:"exponential",Target:"target",Curve:"curve",Set:"set"},Object.defineProperty(o.TimelineSignal.prototype,"value",{get:function(){var e=this.now(),t=this.getValueAtTime(e);return this._toUnits(t)},set:function(e){var t=this._fromUnits(e);this._initial=t,this.cancelScheduledValues(),this._param.value=t}}),o.TimelineSignal.prototype.setValueAtTime=function(e,t){return e=this._fromUnits(e),t=this.toSeconds(t),this._events.add({type:o.TimelineSignal.Type.Set,value:e,time:t}),this._param.setValueAtTime(e,t),this},o.TimelineSignal.prototype.linearRampToValueAtTime=function(e,t){return e=this._fromUnits(e),t=this.toSeconds(t),this._events.add({type:o.TimelineSignal.Type.Linear,value:e,time:t}),this._param.linearRampToValueAtTime(e,t),this}
872,o.TimelineSignal.prototype.exponentialRampToValueAtTime=function(e,t){t=this.toSeconds(t);var i=this._searchBefore(t);i&&0===i.value&&this.setValueAtTime(this._minOutput,i.time),e=this._fromUnits(e);var n=Math.max(e,this._minOutput);return this._events.add({type:o.TimelineSignal.Type.Exponential,value:n,time:t}),e<this._minOutput?(this._param.exponentialRampToValueAtTime(this._minOutput,t-this.sampleTime),this.setValueAtTime(0,t)):this._param.exponentialRampToValueAtTime(e,t),this},o.TimelineSignal.prototype.setTargetAtTime=function(e,t,i){return e=this._fromUnits(e),e=Math.max(this._minOutput,e),i=Math.max(this._minOutput,i),t=this.toSeconds(t),this._events.add({type:o.TimelineSignal.Type.Target,value:e,time:t,constant:i}),this._param.setTargetAtTime(e,t,i),this},o.TimelineSignal.prototype.setValueCurveAtTime=function(e,t,i,n){n=this.defaultArg(n,1);for(var a=new Array(e.length),l=0;l<a.length;l++)a[l]=this._fromUnits(e[l])*n;t=this.toSeconds(t),i=this.toSeconds(i),this._events.add({type:o.TimelineSignal.Type.Curve,value:a,time:t,duration:i}),this._param.setValueAtTime(a[0],t);for(var s=1;s<a.length;s++){var r=t+s/(a.length-1)*i;this._param.linearRampToValueAtTime(a[s],r)}return this},o.TimelineSignal.prototype.cancelScheduledValues=function(e){return e=this.toSeconds(e),this._events.cancel(e),this._param.cancelScheduledValues(e),this},o.TimelineSignal.prototype.setRampPoint=function(e){e=this.toSeconds(e);var t=this._toUnits(this.getValueAtTime(e)),i=this._searchBefore(e);if(i&&i.time===e)this.cancelScheduledValues(e+this.sampleTime);else if(i&&i.type===o.TimelineSignal.Type.Curve&&i.time+i.duration>e)this.cancelScheduledValues(e),this.linearRampToValueAtTime(t,e);else{var n=this._searchAfter(e);n&&(this.cancelScheduledValues(e),n.type===o.TimelineSignal.Type.Linear?this.linearRampToValueAtTime(t,e):n.type===o.TimelineSignal.Type.Exponential&&this.exponentialRampToValueAtTime(t,e)),this.setValueAtTime(t,e)}return this},o.TimelineSignal.prototype.linearRampToValueBetween=function(e,t,i){return this.setRampPoint(t),this.linearRampToValueAtTime(e,i),this},o.TimelineSignal.prototype.exponentialRampToValueBetween=function(e,t,i){return this.setRampPoint(t),this.exponentialRampToValueAtTime(e,i),this},o.TimelineSignal.prototype._searchBefore=function(e){return this._events.get(e)},o.TimelineSignal.prototype._searchAfter=function(e){return this._events.getAfter(e)},o.TimelineSignal.prototype.getValueAtTime=function(e){e=this.toSeconds(e);var t=this._searchAfter(e),i=this._searchBefore(e),n=this._initial;if(null===i)n=this._initial;else if(i.type===o.TimelineSignal.Type.Target){var a,l=this._events.getBefore(i.time);a=null===l?this._initial:l.value,n=this._exponentialApproach(i.time,a,i.value,i.constant,e)}else n=i.type===o.TimelineSignal.Type.Curve?this._curveInterpolate(i.time,i.value,i.duration,e):null===t?i.value:t.type===o.TimelineSignal.Type.Linear?this._linearInterpolate(i.time,i.value,t.time,t.value,e):t.type===o.TimelineSignal.Type.Exponential?this._exponentialInterpolate(i.time,i.value,t.time,t.value,e):i.value;return n},o.TimelineSignal.prototype.connect=o.SignalBase.prototype.connect,o.TimelineSignal.prototype._exponentialApproach=function(e,t,i,n,a){return i+(t-i)*Math.exp(-(a-e)/n)},o.TimelineSignal.prototype._linearInterpolate=function(e,t,i,n,a){return t+(a-e)/(i-e)*(n-t)},o.TimelineSignal.prototype._exponentialInterpolate=function(e,t,i,n,a){return(t=Math.max(this._minOutput,t))*Math.pow(n/t,(a-e)/(i-e))},o.TimelineSignal.prototype._curveInterpolate=function(e,t,i,n){var a=t.length;if(e+i<=n)return t[a-1];if(n<=e)return t[0];var l=(n-e)/i,s=Math.floor((a-1)*l),r=Math.ceil((a-1)*l),o=t[s],p=t[r];return r===s?o:this._linearInterpolate(s,o,r,p,l*(a-1))},o.TimelineSignal.prototype.dispose=function(){o.Signal.prototype.dispose.call(this),o.Param.prototype.dispose.call(this),this._events.dispose(),this._events=null},o.TimelineSignal}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 873 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 874 875 }), 876 (function(module, exports, __webpack_require__) { 877 878"use strict"; 879var __WEBPACK_AMD_DEFINE_RESULT__; 880 881!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 882 var Effect = __webpack_require__(4); 883 /** 884 * <p>A p5.Filter uses a Web Audio Biquad Filter to filter 885 * the frequency response of an input source. Subclasses 886 * include:</p> 887 * <a href="/reference/#/p5.LowPass"><code>p5.LowPass</code></a>: 888 * Allows frequencies below the cutoff frequency to pass through, 889 * and attenuates frequencies above the cutoff.<br/> 890 * <a href="/reference/#/p5.HighPass"><code>p5.HighPass</code></a>: 891 * The opposite of a lowpass filter. <br/> 892 * <a href="/reference/#/p5.BandPass"><code>p5.BandPass</code></a>: 893 * Allows a range of frequencies to pass through and attenuates 894 * the frequencies below and above this frequency range.<br/> 895 * 896 * The <code>.res()</code> method controls either width of the 897 * bandpass, or resonance of the low/highpass cutoff frequency. 898 * 899 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 900 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 901 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 902 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 903 * 904 * @class p5.Filter
905 * @extends p5.Effect 906 * @constructor 907 * @param {String} [type] 'lowpass' (default), 'highpass', 'bandpass' 908 * @example 909 * <div><code> 910 * let fft, noise, filter; 911 * 912 * function setup() { 913 * let cnv = createCanvas(100,100); 914 * cnv.mousePressed(makeNoise); 915 * fill(255, 0, 255); 916 * 917 * filter = new p5.BandPass(); 918 * noise = new p5.Noise(); 919 * noise.disconnect(); 920 * noise.connect(filter); 921 * 922 * fft = new p5.FFT(); 923 * } 924 * 925 * function draw() { 926 * background(220); 927 * 928 * // set the BandPass frequency based on mouseX 929 * let freq = map(mouseX, 0, width, 20, 10000); 930 * freq = constrain(freq, 0, 22050); 931 * filter.freq(freq); 932 * // give the filter a narrow band (lower res = wider bandpass) 933 * filter.res(50); 934 * 935 * // draw filtered spectrum 936 * let spectrum = fft.analyze(); 937 * noStroke(); 938 * for (let i = 0; i < spectrum.length; i++) { 939 * let x = map(i, 0, spectrum.length, 0, width); 940 * let h = -height + map(spectrum[i], 0, 255, height, 0); 941 * rect(x, height, width/spectrum.length, h); 942 * } 943 * if (!noise.started) { 944 * text('tap here and drag to change frequency', 10, 20, width - 20); 945 * } else { 946 * text('Frequency: ' + round(freq)+'Hz', 20, 20, width - 20); 947 * } 948 * } 949 * 950 * function makeNoise() { 951 * // see also: `userStartAudio()` 952 * noise.start(); 953 * noise.amp(0.5, 0.2); 954 * } 955 * 956 * function mouseReleased() { 957 * noise.amp(0, 0.2); 958 * } 959 * 960 * </code></div> 961 */ 962 963 964 p5.Filter = function (type) { 965 Effect.call(this); 966 967 /** 968 * The p5.Filter is built with a 969 * <a href="http://www.w3.org/TR/webaudio/#BiquadFilterNode"> 970 * Web Audio BiquadFilter Node</a>. 971 * 972 * @property {DelayNode} biquadFilter 973 */ 974 975 this.biquad = this.ac.createBiquadFilter(); 976 this.input.connect(this.biquad); 977 this.biquad.connect(this.wet); 978 979 if (type) { 980 this.setType(type); 981 } 982 983 984 this._on = true; 985 this._untoggledType = this.biquad.type; 986 }; 987 988 p5.Filter.prototype = Object.create(Effect.prototype); 989 /** 990 * Filter an audio signal according to a set 991 * of filter parameters. 992 * 993 * @method process 994 * @param {Object} Signal An object that outputs audio 995 * @param {Number} [freq] Frequency in Hz, from 10 to 22050 996 * @param {Number} [res] Resonance/Width of the filter frequency 997 * from 0.001 to 1000 998 */ 999 1000 p5.Filter.prototype.process = function (src, freq, res, time) { 1001 src.connect(this.input); 1002 this.set(freq, res, time); 1003 }; 1004 /** 1005 * Set the frequency and the resonance of the filter. 1006 * 1007 * @method set 1008 * @param {Number} [freq] Frequency in Hz, from 10 to 22050 1009 * @param {Number} [res] Resonance (Q) from 0.001 to 1000 1010 * @param {Number} [timeFromNow] schedule this event to happen 1011 * seconds from now 1012 */ 1013 1014 1015 p5.Filter.prototype.set = function (freq, res, time) { 1016 if (freq) { 1017 this.freq(freq, time); 1018 } 1019 1020 if (res) { 1021 this.res(res, time); 1022 } 1023 }; 1024 /** 1025 * Set the filter frequency, in Hz, from 10 to 22050 (the range of 1026 * human hearing, although in reality most people hear in a narrower 1027 * range). 1028 * 1029 * @method freq 1030 * @param {Number} freq Filter Frequency 1031 * @param {Number} [timeFromNow] schedule this event to happen 1032 * seconds from now 1033 * @return {Number} value Returns the current frequency value 1034 */ 1035 1036 1037 p5.Filter.prototype.freq = function (freq, time) { 1038 var t = time || 0; 1039 1040 if (freq <= 0) { 1041 freq = 1; 1042 } 1043 1044 if (typeof freq === 'number') { 1045 this.biquad.frequency.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 1046 this.biquad.frequency.exponentialRampToValueAtTime(freq, this.ac.currentTime + 0.02 + t); 1047 } else if (freq) { 1048 freq.connect(this.biquad.frequency); 1049 } 1050 1051 return this.biquad.frequency.value; 1052 }; 1053 /** 1054 * Controls either width of a bandpass frequency, 1055 * or the resonance of a low/highpass cutoff frequency. 1056 * 1057 * @method res 1058 * @param {Number} res Resonance/Width of filter freq 1059 * from 0.001 to 1000 1060 * @param {Number} [timeFromNow] schedule this event to happen 1061 * seconds from now 1062 * @return {Number} value Returns the current res value 1063 */ 1064 1065 1066 p5.Filter.prototype.res = function (res, time) { 1067 var t = time || 0; 1068 1069 if (typeof res === 'number') { 1070 this.biquad.Q.value = res; 1071 this.biquad.Q.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 1072 this.biquad.Q.linearRampToValueAtTime(res, this.ac.currentTime + 0.02 + t); 1073 } else if (res) { 1074 res.connect(this.biquad.Q); 1075 } 1076 1077 return this.biquad.Q.value; 1078 }; 1079 /** 1080 * Controls the gain attribute of a Biquad Filter. 1081 * This is distinctly different from .amp() which is inherited from p5.Effect 1082 * .amp() controls the volume via the output gain node 1083 * p5.Filter.gain() controls the gain parameter of a Biquad Filter node. 1084 * 1085 * @method gain 1086 * @param {Number} gain 1087 * @return {Number} Returns the current or updated gain value 1088 */ 1089 1090 1091 p5.Filter.prototype.gain = function (gain, time) { 1092 var t = time || 0; 1093 1094 if (typeof gain === 'number') { 1095 this.biquad.gain.value = gain; 1096 this.biquad.gain.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 1097 this.biquad.gain.linearRampToValueAtTime(gain, this.ac.currentTime + 0.02 + t); 1098 } else if (gain) { 1099 gain.connect(this.biquad.gain); 1100 } 1101 1102 return this.biquad.gain.value; 1103 }; 1104 /** 1105 * Toggle function. Switches between the specified type and allpass 1106 * 1107 * @method toggle 1108 * @return {boolean} [Toggle value] 1109 */ 1110 1111 1112 p5.Filter.prototype.toggle = function () { 1113 this._on = !this._on; 1114 1115 if (this._on === true) { 1116 this.biquad.type = this._untoggledType; 1117 } else if (this._on === false) { 1118 this.biquad.type = 'allpass'; 1119 } 1120 1121 return this._on; 1122 }; 1123 /** 1124 * Set the type of a p5.Filter. Possible types include: 1125 * "lowpass" (default), "highpass", "bandpass", 1126 * "lowshelf", "highshelf", "peaking", "notch", 1127 * "allpass". 1128 * 1129 * @method setType 1130 * @param {String} t 1131 */ 1132 1133 1134 p5.Filter.prototype.setType = function (t) { 1135 this.biquad.type = t; 1136 this._untoggledType = this.biquad.type; 1137 }; 1138 1139 p5.Filter.prototype.dispose = function () { 1140 Effect.prototype.dispose.apply(this); 1141 1142 if (this.biquad) { 1143 this.biquad.disconnect(); 1144 delete this.biquad; 1145 } 1146 }; 1147 /** 1148 * Constructor: <code>new p5.LowPass()</code> Filter. 1149 * This is the same as creating a p5.Filter and then calling 1150 * its method <code>setType('lowpass')</code>. 1151 * See p5.Filter for methods. 1152 * 1153 * @class p5.LowPass 1154 * @constructor 1155 * @extends p5.Filter 1156 */ 1157 1158 1159 p5.LowPass = function () { 1160 p5.Filter.call(this, 'lowpass'); 1161 }; 1162 1163 p5.LowPass.prototype = Object.create(p5.Filter.prototype); 1164 /** 1165 * Constructor: <code>new p5.HighPass()</code> Filter. 1166 * This is the same as creating a p5.Filter and then calling 1167 * its method <code>setType('highpass')</code>. 1168 * See p5.Filter for methods. 1169 * 1170 * @class p5.HighPass 1171 * @constructor 1172 * @extends p5.Filter 1173 */ 1174 1175 p5.HighPass = function () { 1176 p5.Filter.call(this, 'highpass'); 1177 }; 1178 1179 p5.HighPass.prototype = Object.create(p5.Filter.prototype); 1180 /** 1181 * Constructor: <code>new p5.BandPass()</code> Filter. 1182 * This is the same as creating a p5.Filter and then calling 1183 * its method <code>setType('bandpass')</code>. 1184 * See p5.Filter for methods. 1185 * 1186 * @class p5.BandPass 1187 * @constructor 1188 * @extends p5.Filter 1189 */ 1190 1191 p5.BandPass = function () { 1192 p5.Filter.call(this, 'bandpass'); 1193 }; 1194 1195 p5.BandPass.prototype = Object.create(p5.Filter.prototype); 1196 return p5.Filter; 1197}).call(exports, __webpack_require__, exports, module), 1198 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1199 1200 }), 1201 (function(module, exports, __webpack_require__) { 1202 1203var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(7),__webpack_require__(25),__webpack_require__(2),__webpack_require__(9)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(n){"use strict";return n.Subtract=function(t){this.createInsOuts(2,0),this._sum=this.input[0]=this.output=new n.Gain,this._neg=new n.Negate,this._param=this.input[1]=new n.Signal(t),this._param.chain(this._neg,this._sum)},n.extend(n.Subtract,n.Signal),n.Subtract.prototype.dispose=function(){return n.prototype.dispose.call(this),this._neg.dispose(),this._neg=null,this._sum.disconnect(),this._sum=null,this._param.dispose(),this._param=null,this},n.Subtract}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1204 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1205 1206 }), 1207 (function(module, exports, __webpack_require__) { 1208 1209"use strict"; 1210(function(global) {var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__; 1211 1212global.TONE_SILENCE_VERSION_LOGGING = true; 1213!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(35), __webpack_require__(12), __webpack_require__(0)], __WEBPACK_AMD_DEFINE_RESULT__ = (function (StartAudioContext, Context, Tone) { 1214 var audiocontext = new window.AudioContext(); 1215 1216 Tone.context.dispose(); 1217 Tone.setContext(audiocontext); 1218 /** 1219 * <p>Returns the Audio Context for this sketch. Useful for users 1220 * who would like to dig deeper into the <a target='_blank' href= 1221 * 'http://webaudio.github.io/web-audio-api/'>Web Audio API 1222 * </a>.</p> 1223 * 1224 * <p>Some browsers require users to startAudioContext 1225 * with a user gesture, such as touchStarted in the example below.</p> 1226 * 1227 * @for p5 1228 * @method getAudioContext 1229 * @return {Object} AudioContext for this sketch 1230 * @example 1231 * <div><code> 1232 * function draw() { 1233 * background(255); 1234 * textAlign(CENTER); 1235 * 1236 * if (getAudioContext().state !== 'running') { 1237 * text('click to start audio', width/2, height/2); 1238 * } else { 1239 * text('audio is enabled', width/2, height/2); 1240 * } 1241 * } 1242 * 1243 * function touchStarted() { 1244 * if (getAudioContext().state !== 'running') { 1245 * getAudioContext().resume(); 1246 * } 1247 * var synth = new p5.MonoSynth(); 1248 * synth.play('A4', 0.5, 0, 0.2); 1249 * } 1250 * 1251 * </div></code> 1252 */ 1253 1254 p5.prototype.getAudioContext = function () { 1255 return audiocontext; 1256 }; 1257 /** 1258 * <p>It is not only a good practice to give users control over starting 1259 * audio. This policy is enforced by many web browsers, including iOS and 1260 * <a href="https://goo.gl/7K7WLu" title="Google Chrome's autoplay 1261 * policy">Google Chrome</a>, which create the Web Audio API's 1262 * <a href="https://developer.mozilla.org/en-US/docs/Web/API/AudioContext" 1263 * title="Audio Context @ MDN">Audio Context</a> 1264 * in a suspended state.</p> 1265 * 1266 * <p>In these browser-specific policies, sound will not play until a user 1267 * interaction event (i.e. <code>mousePressed()</code>) explicitly resumes
1268 * the AudioContext, or starts an audio node. This can be accomplished by 1269 * calling <code>start()</code> on a <code>p5.Oscillator</code>, 1270 * <code> play()</code> on a <code>p5.SoundFile</code>, or simply 1271 * <code>userStartAudio()</code>.</p> 1272 * 1273 * <p><code>userStartAudio()</code> starts the AudioContext on a user 1274 * gesture. The default behavior will enable audio on any 1275 * mouseUp or touchEnd event. It can also be placed in a specific 1276 * interaction function, such as <code>mousePressed()</code> as in the 1277 * example below. This method utilizes 1278 * <a href="https://github.com/tambien/StartAudioContext">StartAudioContext 1279 * </a>, a library by Yotam Mann (MIT Licence, 2016).</p> 1280 * @param {Element|Array} [element(s)] This argument can be an Element, 1281 * Selector String, NodeList, p5.Element, 1282 * jQuery Element, or an Array of any of those. 1283 * @param {Function} [callback] Callback to invoke when the AudioContext 1284 * has started 1285 * @return {Promise} Returns a Promise that resolves when 1286 * the AudioContext state is 'running' 1287 * @method userStartAudio 1288 * @for p5 1289 * @example 1290 * <div><code> 1291 * function setup() { 1292 * // mimics the autoplay policy 1293 * getAudioContext().suspend(); 1294 * 1295 * let mySynth = new p5.MonoSynth(); 1296 * 1297 * // This won't play until the context has resumed 1298 * mySynth.play('A6'); 1299 * } 1300 * function draw() { 1301 * background(220); 1302 * textAlign(CENTER, CENTER); 1303 * text(getAudioContext().state, width/2, height/2); 1304 * } 1305 * function mousePressed() { 1306 * userStartAudio(); 1307 * } 1308 * </code></div> 1309 */ 1310 1311 1312 p5.prototype.userStartAudio = function (elements, callback) { 1313 var elt = elements; 1314 1315 if (elements instanceof p5.Element) { 1316 elt = elements.elt; 1317 } else if (elements instanceof Array && elements[0] instanceof p5.Element) { 1318 elt = elements.map(function (e) { 1319 return e.elt; 1320 }); 1321 } 1322 1323 return StartAudioContext(audiocontext, elt, callback); 1324 }; 1325 1326 return audiocontext; 1327}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1328 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1329}.call(this, __webpack_require__(34))) 1330 1331 }), 1332 (function(module, exports, __webpack_require__) { 1333 1334var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(o){"use strict";return o.Emitter=function(){this._events={}},o.extend(o.Emitter),o.Emitter.prototype.on=function(t,e){for(var i=t.split(/\W+/),r=0;r<i.length;r++){var n=i[r];this._events.hasOwnProperty(n)||(this._events[n]=[]),this._events[n].push(e)}return this},o.Emitter.prototype.off=function(t,e){for(var i=t.split(/\W+/),r=0;r<i.length;r++)if(t=i[r],this._events.hasOwnProperty(t))if(o.prototype.isUndef(e))this._events[t]=[];else for(var n=this._events[t],s=0;s<n.length;s++)n[s]===e&&n.splice(s,1);return this},o.Emitter.prototype.emit=function(t){if(this._events){var e=Array.apply(null,arguments).slice(1);if(this._events.hasOwnProperty(t))for(var i=this._events[t],r=0,n=i.length;r<n;r++)i[r].apply(this,e)}return this},o.Emitter.mixin=function(t){var e=["on","off","emit"];t._events={};for(var i=0;i<e.length;i++){var r=e[i],n=o.Emitter.prototype[r];t[r]=n}},o.Emitter.prototype.dispose=function(){return o.prototype.dispose.call(this),this._events=null,this},o.Emitter}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1335 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1336 1337 }), 1338 (function(module, exports, __webpack_require__) { 1339 1340var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(c){"use strict";return c.SignalBase=function(){},c.extend(c.SignalBase),c.SignalBase.prototype.connect=function(e,n,a){return c.Signal&&c.Signal===e.constructor||c.Param&&c.Param===e.constructor||c.TimelineSignal&&c.TimelineSignal===e.constructor?(e._param.cancelScheduledValues(0),e._param.value=0,e.overridden=!0):e instanceof AudioParam&&(e.cancelScheduledValues(0),e.value=0),c.prototype.connect.call(this,e,n,a),this},c.SignalBase}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1341 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1342 1343 }), 1344 (function(module, exports, __webpack_require__) { 1345 1346var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(21)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(o){return o.Time=function(t,e){if(!(this instanceof o.Time))return new o.Time(t,e);this._plusNow=!1,o.TimeBase.call(this,t,e)},o.extend(o.Time,o.TimeBase),o.Time.prototype._unaryExpressions=Object.create(o.TimeBase.prototype._unaryExpressions),o.Time.prototype._unaryExpressions.quantize={regexp:/^@/,method:function(t){return o.Trans
1346port.nextSubdivision(t())}},o.Time.prototype._unaryExpressions.now={regexp:/^\+/,method:function(t){return this._plusNow=!0,t()}},o.Time.prototype.quantize=function(t,e){return e=this.defaultArg(e,1),this._expr=function(t,e,o){return t=t(),e=e.toSeconds(),t+(Math.round(t/e)*e-t)*o}.bind(this,this._expr,new this.constructor(t),e),this},o.Time.prototype.addNow=function(){return this._plusNow=!0,this},o.Time.prototype._defaultExpr=function(){return this._plusNow=!0,this._noOp},o.Time.prototype.copy=function(t){return o.TimeBase.prototype.copy.call(this,t),this._plusNow=t._plusNow,this},o.Time.prototype.toNotation=function(){var t=this.toSeconds(),e=this._toNotationHelper(t,["1m","2n","4n","8n","16n","32n","64n","128n"]),o=this._toNotationHelper(t,["1m","2n","2t","4n","4t","8n","8t","16n","16t","32n","32t","64n","64t","128n"]);return o.split("+").length<e.split("+").length?o:e},o.Time.prototype._toNotationHelper=function(t,e){for(var o=this._notationToUnits(e[e.length-1]),n="",i=0;i<e.length;i++){var r=this._notationToUnits(e[i]),s=t/r;if(1-s%1<1e-6&&(s+=1e-6),0<(s=Math.floor(s))){if(n+=1===s?e[i]:s.toString()+"*"+e[i],(t-=s*r)<o)break;n+=" + "}}return""===n&&(n="0"),n},o.Time.prototype._notationToUnits=function(t){for(var e=this._primaryExpressions,o=[e.n,e.t,e.m],n=0;n<o.length;n++){var i=o[n],r=t.match(i.regexp);if(r)return i.method.call(this,r[1])}},o.Time.prototype.toBarsBeatsSixteenths=function(){var t=this._beatsToUnits(1),e=this.toSeconds()/t,o=Math.floor(e/this._timeSignature()),n=e%1*4;return e=Math.floor(e)%this._timeSignature(),3<(n=n.toString()).length&&(n=parseFloat(n).toFixed(3)),[o,e,n].join(":")},o.Time.prototype.toTicks=function(){var t=this._beatsToUnits(1),e=this.valueOf()/t;return Math.floor(e*o.Transport.PPQ)},o.Time.prototype.toSamples=function(){return this.toSeconds()*this.context.sampleRate},o.Time.prototype.toFrequency=function(){return 1/this.toSeconds()},o.Time.prototype.toSeconds=function(){return this.valueOf()},o.Time.prototype.toMilliseconds=function(){return 1e3*this.toSeconds()},o.Time.prototype.valueOf=function(){return this._expr()+(this._plusNow?this.now():0)},o.Time}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1347 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1348 1349 }), 1350 (function(module, exports, __webpack_require__) { 1351 1352var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(n){return n.TimeBase=function(e,t){if(!(this instanceof n.TimeBase))return new n.TimeBase(e,t);if(this._expr=this._noOp,e instanceof n.TimeBase)this.copy(e);else if(!this.isUndef(t)||this.isNumber(e)){t=this.defaultArg(t,this._defaultUnits);var r=this._primaryExpressions[t].method;this._expr=r.bind(this,e)}else this.isString(e)?this.set(e):this.isUndef(e)&&(this._expr=this._defaultExpr())},n.extend(n.TimeBase),n.TimeBase.prototype.set=function(e){return this._expr=this._parseExprString(e),this},n.TimeBase.prototype.clone=function(){var e=new this.constructor;return e.copy(this),e},n.TimeBase.prototype.copy=function(e){var t=e._expr();return this.set(t)},n.TimeBase.prototype._primaryExpressions={n:{regexp:/^(\d+)n/i,method:function(e){return 1===(e=parseInt(e))?this._beatsToUnits(this._timeSignature()):this._beatsToUnits(4/e)}},t:{regexp:/^(\d+)t/i,method:function(e){return e=parseInt(e),this._beatsToUnits(8/(3*parseInt(e)))}},m:{regexp:/^(\d+)m/i,method:function(e){return this._beatsToUnits(parseInt(e)*this._timeSignature())}},i:{regexp:/^(\d+)i/i,method:function(e){return this._ticksToUnits(parseInt(e))}},hz:{regexp:/^(\d+(?:\.\d+)?)hz/i,method:function(e){return this._frequencyToUnits(parseFloat(e))}},tr:{regexp:/^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,method:function(e,t,r){var n=0;return e&&"0"!==e&&(n+=this._beatsToUnits(this._timeSignature()*parseFloat(e))),t&&"0"!==t&&(n+=this._beatsToUnits(parseFloat(t))),r&&"0"!==r&&(n+=this._beatsToUnits(parseFloat(r)/4)),n}},s:{regexp:/^(\d+(?:\.\d+)?s)/,method:function(e){return this._secondsToUnits(parseFloat(e))}},samples:{regexp:/^(\d+)samples/,method:function(e){return parseInt(e)/this.context.sampleRate}},default:{regexp:/^(\d+(?:\.\d+)?)/,method:function(e){return this._primaryExpressions[this._defaultUnits].method.call(this,e)}}},n.TimeBase.prototype._binaryExpressions={"+":{regexp:/^\+/,precedence:2,method:function(e,t){return e()+t()}},"-":{regexp:/^\-/,precedence:2,method:function(e,t){return e()-t()}},"*":{regexp:/^\*/,precedence:1,method:function(e,t){return e()*t()}},"/":{regexp:/^\//,precedence:1,method:function(e,t){return e()/t()}}},n.TimeBase.prototype._unaryExpressions={neg:{regexp:/^\-/,method:function(e){return-e()}}},n.TimeBase.prototype._syntaxGlue={"(":{regexp:/^\(/},")":{regexp:/^\)/}},n.TimeBase.prototype._tokenize=function(e){for(var t=-1,r=[];0<e.length;){var n=i(e=e.trim(),this);r.push(n),e=e.substr(n.value.length)}function i(e,t){for(var r=["_binaryExpressions","_unaryExpressions","_primaryExpressions","_syntaxGlue"],n=0;n<r.length;n++){var i=t[r[n]];for(var s in i){var o=i[s],p=o.regexp,a=e.match(p);if(null!==a)return{method:o.method,precedence:o.precedence,regexp:o.regexp,value:a[0]}}}throw new SyntaxError("Tone.TimeBase: Unexpected token "+e)}return{next:function(){return r[++t]},peek:function(){return r[t+1]}}},n.TimeBase.prototype._matchGroup=function(e,t,r){if(!this.isUndef(e))for(var n in t){var i=t[n];if(i.regexp.test(e.value)){if(this.isUndef(r))return i;if(i.precedence===r)return i}}return!1},n.TimeBase.prototype._parseBinary=function(e,t){var r;this.isUndef(t)&&(t=2),r=t<0?this._parseUnary(e):this._parseBinary(e,t-1);for(var n=e.peek();n&&this._matchGroup(n,this._binaryExpressions,t);)r=(n=e.next()).method.bind(this,r,this._parseBinary(e,t-1)),n=e.peek();return r},n.TimeBase.prototype._parseUnary=function(e){var t,r;t=e.peek();var n=this._matchGroup(t,this._unaryExpressions);return n?(t=e.next(),r=this._parseUnary(e),n.method.bind(this,r)):this._parsePrimary(e)},n.TimeBase.prototype._parsePrimary=function(e){var t,r;if(t=e.peek(),this.isUndef(t))throw new SyntaxError("Tone.TimeBase: Unexpected end of expression");if(this._matchGroup(t,this._primaryExpressions)){var n=(t=e.next()).value.match(t.regexp);return t.method.bind(this,n[1],n[2],n[3])}if(t&&"("===t.value){if(e.next(),r=this._parseBinary(e),!(t=e.next())||")"!==t.value)throw new SyntaxError("Expected )");return r}throw new SyntaxError("Tone.TimeBase: Cannot process token "+t.value)},n.TimeBase.prototype._parseExprString=function(e){this.isString(e)||(e=e.toString());var t=this._tokenize(e);return this._parseBinary(t)},n.TimeBase.prototype._noOp=function(){return 0},n.TimeBase.prototype._defaultExpr=function(){return this._noOp},n.TimeBase.prototype._defaultUnits="s",n.TimeBase.prototype._frequencyToUnits=function(e){return 1/e},n.TimeBase.prototype._beatsToUnits=function(e){return 60/n.Transport.bpm.value*e},n.TimeBase.prototype._secondsToUnits=function(e){return e},n.TimeBase.prototype._ticksToUnits=function(e){return e*(this._beatsToUnits(1)/n.Transport.PPQ)},n.TimeBase.prototype._timeSignature=function(){return n.Transport.timeSignature},n.TimeBase.prototype._pushExpr=function(e,t,r){return e instanceof n.TimeBase||(e=new this.constructor(e,r)),this._expr=this._binaryExpressions[t].method.bind(this,this._expr,e._expr),this},n.TimeBase.prototype.add=function(e,t){return this._pushExpr(e,"+",t)},n.TimeBase.prototype.sub=function(e,t){return this._pushExpr(e,"-",t)},n.TimeBase.prototype.mult=function(e,t){return this._pushExpr(e,"*",t)},n.TimeBase.prototype.div=function(e,t){return this._pushExpr(e,"/",t)},n.TimeBase.prototype.valueOf=function(){return this._expr()},n.TimeBase.prototype.dispose=function(){this._expr=null},n.TimeBase}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1353 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1354 1355 }), 1356 (function(module, exports, __webpack_require__) { 1357 1358var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(8)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(a){"use strict";
1358return a.Param=function(){var t=this.optionsObject(arguments,["param","units","convert"],a.Param.defaults);this._param=this.input=t.param,this.units=t.units,this.convert=t.convert,this.overridden=!1,this._lfo=null,this.isObject(t.lfo)?this.value=t.lfo:this.isUndef(t.value)||(this.value=t.value)},a.extend(a.Param),a.Param.defaults={units:a.Type.Default,convert:!0,param:void 0},Object.defineProperty(a.Param.prototype,"value",{get:function(){return this._toUnits(this._param.value)},set:function(t){if(this.isObject(t)){if(this.isUndef(a.LFO))throw new Error("Include 'Tone.LFO' to use an LFO as a Param value.");this._lfo&&this._lfo.dispose(),this._lfo=new a.LFO(t).start(),this._lfo.connect(this.input)}else{var e=this._fromUnits(t);this._param.cancelScheduledValues(0),this._param.value=e}}}),a.Param.prototype._fromUnits=function(t){if(!this.convert&&!this.isUndef(this.convert))return t;switch(this.units){case a.Type.Time:return this.toSeconds(t);case a.Type.Frequency:return this.toFrequency(t);case a.Type.Decibels:return this.dbToGain(t);case a.Type.NormalRange:return Math.min(Math.max(t,0),1);case a.Type.AudioRange:return Math.min(Math.max(t,-1),1);case a.Type.Positive:return Math.max(t,0);default:return t}},a.Param.prototype._toUnits=function(t){if(!this.convert&&!this.isUndef(this.convert))return t;switch(this.units){case a.Type.Decibels:return this.gainToDb(t);default:return t}},a.Param.prototype._minOutput=1e-5,a.Param.prototype.setValueAtTime=function(t,e){return t=this._fromUnits(t),(e=this.toSeconds(e))<=this.now()+this.blockTime?this._param.value=t:this._param.setValueAtTime(t,e),this},a.Param.prototype.setRampPoint=function(t){t=this.defaultArg(t,this.now());var e=this._param.value;return 0===e&&(e=this._minOutput),this._param.setValueAtTime(e,t),this},a.Param.prototype.linearRampToValueAtTime=function(t,e){return t=this._fromUnits(t),this._param.linearRampToValueAtTime(t,this.toSeconds(e)),this},a.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},a.Param.prototype.exponentialRampToValue=function(t,e,i){return i=this.toSeconds(i),this.setRampPoint(i),this.exponentialRampToValueAtTime(t,i+this.toSeconds(e)),this},a.Param.prototype.linearRampToValue=function(t,e,i){return i=this.toSeconds(i),this.setRampPoint(i),this.linearRampToValueAtTime(t,i+this.toSeconds(e)),this},a.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},a.Param.prototype.setValueCurveAtTime=function(t,e,i){for(var a=0;a<t.length;a++)t[a]=this._fromUnits(t[a]);return this._param.setValueCurveAtTime(t,this.toSeconds(e),this.toSeconds(i)),this},a.Param.prototype.cancelScheduledValues=function(t){return this._param.cancelScheduledValues(this.toSeconds(t)),this},a.Param.prototype.rampTo=function(t,e,i){return e=this.defaultArg(e,0),this.units===a.Type.Frequency||this.units===a.Type.BPM||this.units===a.Type.Decibels?this.exponentialRampToValue(t,e,i):this.linearRampToValue(t,e,i),this},Object.defineProperty(a.Param.prototype,"lfo",{get:function(){return this._lfo}}),a.Param.prototype.dispose=function(){return a.prototype.dispose.call(this),this._param=null,this._lfo&&(this._lfo.dispose(),this._lfo=null),this},a.Param}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1359 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1360 1361 }), 1362 (function(module, exports, __webpack_require__) { 1363 1364"use strict"; 1365var __WEBPACK_AMD_DEFINE_RESULT__; 1366 1367!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 1368 var p5sound = __webpack_require__(1); 1369 1370 var Add = __webpack_require__(7); 1371 1372 var Mult = __webpack_require__(3); 1373 1374 var Scale = __webpack_require__(13); 1375 /** 1376 * <p>Creates a signal that oscillates between -1.0 and 1.0. 1377 * By default, the oscillation takes the form of a sinusoidal 1378 * shape ('sine'). Additional types include 'triangle', 1379 * 'sawtooth' and 'square'. The frequency defaults to 1380 * 440 oscillations per second (440Hz, equal to the pitch of an 1381 * 'A' note).</p> 1382 * 1383 * <p>Set the type of oscillation with setType(), or by instantiating a 1384 * specific oscillator: <a href="/reference/#/p5.SinOsc">p5.SinOsc</a>, <a 1385 * href="/reference/#/p5.TriOsc">p5.TriOsc</a>, <a 1386 * href="/reference/#/p5.SqrOsc">p5.SqrOsc</a>, or <a 1387 * href="/reference/#/p5.SawOsc">p5.SawOsc</a>. 1388 * </p> 1389 * 1390 * @class p5.Oscillator 1391 * @constructor 1392 * @param {Number} [freq] frequency defaults to 440Hz 1393 * @param {String} [type] type of oscillator. Options: 1394 * 'sine' (default), 'triangle',
1395 * 'sawtooth', 'square' 1396 * @example 1397 * <div><code> 1398 * let osc, playing, freq, amp; 1399 * 1400 * function setup() { 1401 * let cnv = createCanvas(100, 100); 1402 * cnv.mousePressed(playOscillator); 1403 * osc = new p5.Oscillator('sine'); 1404 * } 1405 * 1406 * function draw() { 1407 * background(220) 1408 * freq = constrain(map(mouseX, 0, width, 100, 500), 100, 500); 1409 * amp = constrain(map(mouseY, height, 0, 0, 1), 0, 1); 1410 * 1411 * text('tap to play', 20, 20); 1412 * text('freq: ' + freq, 20, 40); 1413 * text('amp: ' + amp, 20, 60); 1414 * 1415 * if (playing) { 1416 * // smooth the transitions by 0.1 seconds 1417 * osc.freq(freq, 0.1); 1418 * osc.amp(amp, 0.1); 1419 * } 1420 * } 1421 * 1422 * function playOscillator() { 1423 * // starting an oscillator on a user gesture will enable audio 1424 * // in browsers that have a strict autoplay policy. 1425 * // See also: userStartAudio(); 1426 * osc.start(); 1427 * playing = true; 1428 * } 1429 * 1430 * function mouseReleased() { 1431 * // ramp amplitude to 0 over 0.5 seconds 1432 * osc.amp(0, 0.5); 1433 * playing = false; 1434 * } 1435 * </code> </div> 1436 */ 1437 1438 1439 p5.Oscillator = function (freq, type) { 1440 if (typeof freq === 'string') { 1441 var f = type; 1442 type = freq; 1443 freq = f; 1444 } 1445 1446 if (typeof type === 'number') { 1447 var f = type; 1448 type = freq; 1449 freq = f; 1450 } 1451 1452 this.started = false; 1453 1454 this.phaseAmount = undefined; 1455 this.oscillator = p5sound.audiocontext.createOscillator(); 1456 this.f = freq || 440.0; 1457 1458 this.oscillator.type = type || 'sine'; 1459 this.oscillator.frequency.setValueAtTime(this.f, p5sound.audiocontext.currentTime); 1460 1461 this.output = p5sound.audiocontext.createGain(); 1462 this._freqMods = []; 1463 1464 this.output.gain.value = 0.5; 1465 this.output.gain.setValueAtTime(0.5, p5sound.audiocontext.currentTime); 1466 this.oscillator.connect(this.output); 1467 1468 this.panPosition = 0.0; 1469 this.connection = p5sound.input; 1470 1471 this.panner = new p5.Panner(this.output, this.connection, 1); 1472 1473 this.mathOps = [this.output]; 1474 1475 p5sound.soundArray.push(this); 1476 }; 1477 /** 1478 * Start an oscillator. 1479 * 1480 * Starting an oscillator on a user gesture will enable audio in browsers 1481 * that have a strict autoplay policy, including Chrome and most mobile 1482 * devices. See also: `userStartAudio()`. 1483 * 1484 * @method start 1485 * @for p5.Oscillator 1486 * @param {Number} [time] startTime in seconds from now. 1487 * @param {Number} [frequency] frequency in Hz. 1488 */ 1489 1490 1491 p5.Oscillator.prototype.start = function (time, f) { 1492 if (this.started) { 1493 var now = p5sound.audiocontext.currentTime; 1494 this.stop(now); 1495 } 1496 1497 if (!this.started) { 1498 var freq = f || this.f; 1499 var type = this.oscillator.type; 1500 1501 if (this.oscillator) { 1502 this.oscillator.disconnect(); 1503 delete this.oscillator; 1504 } 1505 1506 1507 this.oscillator = p5sound.audiocontext.createOscillator(); 1508 this.oscillator.frequency.value = Math.abs(freq); 1509 this.oscillator.type = type; 1510 1511 this.oscillator.connect(this.output); 1512 time = time || 0; 1513 this.oscillator.start(time + p5sound.audiocontext.currentTime); 1514 this.freqNode = this.oscillator.frequency; 1515 1516 for (var i in this._freqMods) { 1517 if (typeof this._freqMods[i].connect !== 'undefined') { 1518 this._freqMods[i].connect(this.oscillator.frequency); 1519 } 1520 } 1521 1522 this.started = true; 1523 } 1524 }; 1525 /** 1526 * Stop an oscillator. Accepts an optional parameter 1527 * to determine how long (in seconds from now) until the 1528 * oscillator stops. 1529 * 1530 * @method stop 1531 * @for p5.Oscillator 1532 * @param {Number} secondsFromNow Time, in seconds from now. 1533 */ 1534 1535 1536 p5.Oscillator.prototype.stop = function (time) { 1537 if (this.started) { 1538 var t = time || 0; 1539 var now = p5sound.audiocontext.currentTime; 1540 this.oscillator.stop(t + now); 1541 this.started = false; 1542 } 1543 }; 1544 /** 1545 * Set the amplitude between 0 and 1.0. Or, pass in an object 1546 * such as an oscillator to modulate amplitude with an audio signal. 1547 * 1548 * @method amp 1549 * @for p5.Oscillator 1550 * @param {Number|Object} vol between 0 and 1.0 1551 * or a modulating signal/oscillator 1552 * @param {Number} [rampTime] create a fade that lasts rampTime 1553 * @param {Number} [timeFromNow] schedule this event to happen 1554 * seconds from now 1555 * @return {AudioParam} gain If no value is provided, 1556 * returns the Web Audio API
1557 * AudioParam that controls 1558 * this oscillator's 1559 * gain/amplitude/volume) 1560 */ 1561 1562 1563 p5.Oscillator.prototype.amp = function (vol, rampTime, tFromNow) { 1564 var self = this; 1565 1566 if (typeof vol === 'number') { 1567 var rampTime = rampTime || 0; 1568 var tFromNow = tFromNow || 0; 1569 var now = p5sound.audiocontext.currentTime; 1570 this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime); 1571 } else if (vol) { 1572 vol.connect(self.output.gain); 1573 } else { 1574 return this.output.gain; 1575 } 1576 }; 1577 1578 1579 p5.Oscillator.prototype.fade = p5.Oscillator.prototype.amp; 1580 1581 p5.Oscillator.prototype.getAmp = function () { 1582 return this.output.gain.value; 1583 }; 1584 /** 1585 * Set frequency of an oscillator to a value. Or, pass in an object 1586 * such as an oscillator to modulate the frequency with an audio signal. 1587 * 1588 * @method freq 1589 * @for p5.Oscillator 1590 * @param {Number|Object} Frequency Frequency
1590in Hz 1591 * or modulating signal/oscillator 1592 * @param {Number} [rampTime] Ramp time (in seconds) 1593 * @param {Number} [timeFromNow] Schedule this event to happen 1594 * at x seconds from now 1595 * @return {AudioParam} Frequency If no value is provided, 1596 * returns the Web Audio API 1597 * AudioParam that controls 1598 * this oscillator's frequency 1599 * @example 1600 * <div><code> 1601 * let osc; 1602 * 1603 * function setup() { 1604 * let cnv = createCanvas(100, 100); 1605 * cnv.mousePressed(playOscillator); 1606 * osc = new p5.Oscillator(300); 1607 * background(220); 1608 * text('tap to play', 20, 20); 1609 * } 1610 * 1611 * function playOscillator() { 1612 * osc.start(); 1613 * osc.amp(0.5); 1614 * // start at 700Hz 1615 * osc.freq(700); 1616 * // ramp to 60Hz over 0.7 seconds 1617 * osc.freq(60, 0.7); 1618 * osc.amp(0, 0.1, 0.7); 1619 * } 1620 * </code></div> 1621 */ 1622 1623 1624 p5.Oscillator.prototype.freq = function (val, rampTime, tFromNow) { 1625 if (typeof val === 'number' && !isNaN(val)) { 1626 this.f = val; 1627 var now = p5sound.audiocontext.currentTime; 1628 var rampTime = rampTime || 0; 1629 var tFromNow = tFromNow || 0; 1630 var t = now + tFromNow + rampTime; 1631 1632 if (rampTime === 0) { 1633 this.oscillator.frequency.setValueAtTime(val, tFromNow + now); 1634 } else { 1635 if (val > 0) { 1636 this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); 1637 } else { 1638 this.oscillator.frequency.linearRampToValueAtTime(val, tFromNow + rampTime + now); 1639 } 1640 } 1641 1642 1643 if (this.phaseAmount) { 1644 this.phase(this.phaseAmount); 1645 } 1646 } else if (val) { 1647 if (val.output) { 1648 val = val.output; 1649 } 1650 1651 val.connect(this.oscillator.frequency); 1652 1653 this._freqMods.push(val); 1654 } else { 1655 return this.oscillator.frequency; 1656 } 1657 }; 1658 1659 p5.Oscillator.prototype.getFreq = function () { 1660 return this.oscillator.frequency.value; 1661 }; 1662 /** 1663 * Set type to 'sine', 'triangle', 'sawtooth' or 'square'. 1664 * 1665 * @method setType 1666 * @for p5.Oscillator 1667 * @param {String} type 'sine', 'triangle', 'sawtooth' or 'square'. 1668 */ 1669 1670 1671 p5.Oscillator.prototype.setType = function (type) { 1672 this.oscillator.type = type; 1673 }; 1674 1675 p5.Oscillator.prototype.getType = function () { 1676 return this.oscillator.type; 1677 }; 1678 /** 1679 * Connect to a p5.sound / Web Audio object. 1680 * 1681 * @method connect 1682 * @for p5.Oscillator 1683 * @param {Object} unit A p5.sound or Web Audio object 1684 */ 1685 1686 1687 p5.Oscillator.prototype.connect = function (unit) { 1688 if (!unit) { 1689 this.panner.connect(p5sound.input); 1690 } else if (unit.hasOwnProperty('input')) { 1691 this.panner.connect(unit.input); 1692 this.connection = unit.input; 1693 } else { 1694 this.panner.connect(unit); 1695 this.connection = unit; 1696 } 1697 }; 1698 /** 1699 * Disconnect all outputs 1700 * 1701 * @method disconnect 1702 * @for p5.Oscillator 1703 */ 1704 1705 1706 p5.Oscillator.prototype.disconnect = function () { 1707 if (this.output) { 1708 this.output.disconnect(); 1709 } 1710 1711 if (this.panner) { 1712 this.panner.disconnect(); 1713 1714 if (this.output) { 1715 this.output.connect(this.panner); 1716 } 1717 } 1718 1719 this.oscMods = []; 1720 }; 1721 /** 1722 * Pan between Left (-1) and Right (1) 1723 * 1724 * @method pan 1725 * @for p5.Oscillator 1726 * @param {Number} panning Number between -1 and 1 1727 * @param {Number} timeFromNow schedule this event to happen 1728 * seconds from now 1729 */ 1730 1731 1732 p5.Oscillator.prototype.pan = function (pval, tFromNow) { 1733 this.panPosition = pval; 1734 this.panner.pan(pval, tFromNow); 1735 }; 1736 1737 p5.Oscillator.prototype.getPan = function () { 1738 return this.panPosition; 1739 }; 1740 1741 1742 p5.Oscillator.prototype.dispose = function () { 1743 var index = p5sound.soundArray.indexOf(this); 1744 p5sound.soundArray.splice(index, 1); 1745 1746 if (this.oscillator) { 1747 var now = p5sound.audiocontext.currentTime; 1748 this.stop(now); 1749 this.disconnect(); 1750 this.panner = null; 1751 this.oscillator = null; 1752 } 1753 1754 1755 if (this.osc2) { 1756 this.osc2.dispose(); 1757 } 1758 }; 1759 /** 1760 * Set the phase of an oscillator between 0.0 and 1.0. 1761 * In this implementation, phase is a delay time 1762 * based on the oscillator's current frequency. 1763 * 1764 * @method phase 1765 * @for p5.Oscillator 1766 * @param {Number}
1766 phase float between 0.0 and 1.0 1767 */ 1768 1769 1770 p5.Oscillator.prototype.phase = function (p) { 1771 var delayAmt = p5.prototype.map(p, 0, 1.0, 0, 1 / this.f); 1772 var now = p5sound.audiocontext.currentTime; 1773 this.phaseAmount = p; 1774 1775 if (!this.dNode) { 1776 this.dNode = p5sound.audiocontext.createDelay(); 1777 1778 this.oscillator.disconnect(); 1779 this.oscillator.connect(this.dNode); 1780 this.dNode.connect(this.output); 1781 } 1782 1783 1784 this.dNode.delayTime.setValueAtTime(delayAmt, now); 1785 }; 1786 1787 1788 var sigChain = function sigChain(o, mathObj, thisChain, nextChain, type) { 1789 var chainSource = o.oscillator; 1790 1791 for (var i in o.mathOps) { 1792 if (o.mathOps[i] instanceof type) { 1793 chainSource.disconnect(); 1794 o.mathOps[i].dispose(); 1795 thisChain = i; 1796 1797 if (thisChain < o.mathOps.length - 2) { 1798 nextChain = o.mathOps[i + 1]; 1799 } 1800 } 1801 } 1802 1803 if (thisChain === o.mathOps.length - 1) { 1804 o.mathOps.push(nextChain); 1805 } 1806 1807 1808 if (i > 0) { 1809 chainSource = o.mathOps[i - 1]; 1810 } 1811 1812 chainSource.disconnect(); 1813 chainSource.connect(mathObj); 1814 mathObj.connect(nextChain); 1815 o.mathOps[thisChain] = mathObj; 1816 return o; 1817 }; 1818 /** 1819 * Add a value to the p5.Oscillator's output amplitude, 1820 * and return the oscillator. Calling this method again 1821 * will override the initial add() with a new value. 1822 * 1823 * @method add 1824 * @for p5.Oscillator 1825 * @param {Number} number Constant number to add 1826 * @return {p5.Oscillator} Oscillator Returns this oscillator 1827 * with scaled output 1828 * 1829 */ 1830 1831 1832 p5.Oscillator.prototype.add = function (num) { 1833 var add = new Add(num); 1834 var thisChain = this.mathOps.length - 1; 1835 var nextChain = this.output; 1836 return sigChain(this, add, thisChain, nextChain, Add); 1837 }; 1838 /** 1839 * Multiply the p5.Oscillator's output amplitude 1840 * by a fixed value (i.e. turn it up!). Calling this method 1841 * again will override the initial mult() with a new value. 1842 * 1843 * @method mult 1844 * @for p5.Oscillator 1845 * @param {Number} number Constant number to multiply 1846 * @return {p5.Oscillator} Oscillator Returns this oscillator 1847 * with multiplied output 1848 */ 1849 1850 1851 p5.Oscillator.prototype.mult = function (num) { 1852 var mult = new Mult(num); 1853 var thisChain = this.mathOps.length - 1; 1854 var nextChain = this.output; 1855 return sigChain(this, mult, thisChain, nextChain, Mult); 1856 }; 1857 /** 1858 * Scale this oscillator's amplitude values to a given 1859 * range, and return the oscillator. Calling this method 1860 * again will override the initial scale() with new values. 1861 * 1862 * @method scale 1863 * @for p5.Oscillator 1864 * @param {Number} inMin input range minumum 1865 * @param {Number} inMax input range maximum 1866 * @param {Number} outMin input range minumum 1867 * @param {Number} outMax input range maximum 1868 * @return {p5.Oscillator} Oscillator Returns this oscillator 1869 * with scaled output 1870 */ 1871 1872 1873 p5.Oscillator.prototype.scale = function (inMin, inMax, outMin, outMax) { 1874 var mapOutMin, mapOutMax; 1875 1876 if (arguments.length === 4) { 1877 mapOutMin = p5.prototype.map(outMin, inMin, inMax, 0, 1) - 0.5; 1878 mapOutMax = p5.prototype.map(outMax, inMin, inMax, 0, 1) - 0.5; 1879 } else { 1880 mapOutMin = arguments[0]; 1881 mapOutMax = arguments[1]; 1882 } 1883 1884 var scale = new Scale(mapOutMin, mapOutMax); 1885 var thisChain = this.mathOps.length - 1; 1886 var nextChain = this.output; 1887 return sigChain(this, scale, thisChain, nextChain, Scale); 1888 }; 1889 1890 /** 1891 * Constructor: <code>new p5.SinOsc()</code>. 1892 * This creates a Sine Wave Oscillator and is 1893 * equivalent to <code> new p5.Oscillator('sine') 1894 * </code> or creating a p5.Oscillator and then calling 1895 * its method <code>setType('sine')</code>. 1896 * See p5.Oscillator for methods. 1897 * 1898 * @class p5.SinOsc 1899 * @constructor 1900 * @extends p5.Oscillator 1901 * @param {Number} [freq] Set the frequency 1902 */ 1903 1904 1905 p5.SinOsc = function (freq) { 1906 p5.Oscillator.call(this, freq, 'sine'); 1907 }; 1908 1909 p5.SinOsc.prototype = Object.create(p5.Oscillator.prototype); 1910 /** 1911 * Constructor: <code>new p5.TriOsc()</code>. 1912 * This creates a Triangle Wave Oscillator and is 1913 * equivalent to <code>new p5.Oscillator('triangle') 1914 * </code> or creating a p5.Oscillator and then calling 1915 * its method <code>
1915setType('triangle')</code>. 1916 * See p5.Oscillator for methods. 1917 * 1918 * @class p5.TriOsc 1919 * @constructor 1920 * @extends p5.Oscillator 1921 * @param {Number} [freq] Set the frequency 1922 */ 1923 1924 p5.TriOsc = function (freq) { 1925 p5.Oscillator.call(this, freq, 'triangle'); 1926 }; 1927 1928 p5.TriOsc.prototype = Object.create(p5.Oscillator.prototype); 1929 /** 1930 * Constructor: <code>new p5.SawOsc()</code>. 1931 * This creates a SawTooth Wave Oscillator and is 1932 * equivalent to <code> new p5.Oscillator('sawtooth') 1933 * </code> or creating a p5.Oscillator and then calling 1934 * its method <code>setType('sawtooth')</code>. 1935 * See p5.Oscillator for methods. 1936 * 1937 * @class p5.SawOsc 1938 * @constructor 1939 * @extends p5.Oscillator 1940 * @param {Number} [freq] Set the frequency 1941 */ 1942 1943 p5.SawOsc = function (freq) { 1944 p5.Oscillator.call(this, freq, 'sawtooth'); 1945 }; 1946 1947 p5.SawOsc.prototype = Object.create(p5.Oscillator.prototype); 1948 /** 1949 * Constructor: <code>new p5.SqrOsc()</code>. 1950 * This creates a Square Wave Oscillator and is 1951 * equivalent to <code> new p5.Oscillator('square') 1952 * </code> or creating a p5.Oscillator and then calling 1953 * its method <code>setType('square')</code>. 1954 * See p5.Oscillator for methods. 1955 * 1956 * @class p5.SqrOsc 1957 * @constructor 1958 * @extends p5.Oscillator 1959 * @param {Number} [freq] Set the frequency 1960 */ 1961 1962 p5.SqrOsc = function (freq) { 1963 p5.Oscillator.call(this, freq, 'square'); 1964 }; 1965 1966 p5.SqrOsc.prototype = Object.create(p5.Oscillator.prototype); 1967}).call(exports, __webpack_require__, exports, module), 1968 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1969 1970 }), 1971 (function(module, exports, __webpack_require__) { 1972 1973var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(8)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(i){"use strict";return i.Timeline=function(){var e=this.optionsObject(arguments,["memory"],i.Timeline.defaults);this._timeline=[],this._toRemove=[],this._iterating=!1,this.memory=e.memory},i.extend(i.Timeline),i.Timeline.defaults={memory:1/0},Object.defineProperty(i.Timeline.prototype,"length",{get:function(){return this._timeline.length}}),i.Timeline.prototype.add=function(e){if(this.isUndef(e.time))throw new Error("Tone.Timeline: events must have a time attribute");if(this._timeline.length){var i=this._search(e.time);this._timeline.splice(i+1,0,e)}else this._timeline.push(e);if(this.length>this.memory){var t=this.length-this.memory;this._timeline.splice(0,t)}return this},i.Timeline.prototype.remove=function(e){if(this._iterating)this._toRemove.push(e);else{var i=this._timeline.indexOf(e);-1!==i&&this._timeline.splice(i,1)}return this},i.Timeline.prototype.get=function(e){var i=this._search(e);return-1!==i?this._timeline[i]:null},i.Timeline.prototype.peek=function(){return this._timeline[0]},i.Timeline.prototype.shift=function(){return this._timeline.shift()},i.Timeline.prototype.getAfter=function(e){var i=this._search(e);return i+1<this._timeline.length?this._timeline[i+1]:null},i.Timeline.prototype.getBefore=function(e){var i=this._timeline.length;if(0<i&&this._timeline[i-1].time<e)return this._timeline[i-1];var t=this._search(e);return 0<=t-1?this._timeline[t-1]:null},i.Timeline.prototype.cancel=function(e){if(1<this._timeline.length){var i=this._search(e);if(0<=i)if(this._timeline[i].time===e){for(var t=i;0<=t&&this._timeline[t].time===e;t--)i=t;this._timeline=this._timeline.slice(0,i)}else this._timeline=this._timeline.slice(0,i+1);else this._timeline=[]}else 1===this._timeline.length&&this._timeline[0].time>=e&&(this._timeline=[]);return this},i.Timeline.prototype.cancelBefore=function(e){if(this._timeline.length){var i=this._search(e);0<=i&&(this._timeline=this._timeline.slice(i+1))}return this},i.Timeline.prototype._search=function(e){var i=0,t=this._timeline.length,n=t;if(0<t&&this._timeline[t-1].time<=e)return t-1;for(;i<n;){var r=Math.floor(i+(n-i)/2),s=this._timeline[r],h=this._timeline[r+1];if(s.time===e){for(var l=r;l<this._timeline.length;l++){this._timeline[l].time===e&&(r=l)}return r}if(s.time<e&&h.time>e)return r;s.time>e?n=r:s.time<e&&(i=r+1)}return-1},i.Timeline.prototype._iterate=function(e,i,t){this._iterating=!0,i=this.defaultArg(i,0),t=this.defaultArg(t,this._timeline.length-1);for(var n=i;n<=t;n++)e(this._timeline[n]);if(this._iterating=!1,0<this._toRemove.length){for(var r=0;r<this._toRemove.length;r++){var s=this._timeline.indexOf(this._toRemove[r]);-1!==s&&this._timeline.splice(s,1)}this._toRemove=[]}},i.Timeline.prototype.forEach=function(e){return this._iterate(e),this},i.Timeline.prototype.forEachBefore=function(e,i){var t=this._search(e);return-1!==t&&this._iterate(i,0,t),this},i.Timeline.prototype.forEachAfter=function(e,i){var t=this._search(e);return this._iterate(i,t+1),this},i.Timeline.prototype.forEachFrom=function(e,i){for(var t=this._search(e);0<=t&&this._timeline[t].time>=e;)t--;return this._iterate(i,t+1),this},i.Timeline.prototype.forEachAtTime=function(i,t){var e=this._search(i);return-1!==e&&this._iterate(function(e){e.time===i&&t(e)},0,e),this},i.Timeline.prototype.dispose=function(){i.prototype.dispose.call(this),this._timeline=null,this._toRemove=null},i.Timeline}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1974 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1975 1976 }), 1977 (function(module, exports, __webpack_require__) { 1978 1979var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(3),__webpack_require__(2)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(t){"use strict";return t.Negate=function(){this._multiply=this.input=this.output=new t.Multiply(-1)},t.extend(t.Negate,t.SignalBase),t.Negate.prototype.dispose=function(){return t.prototype.dispose.call(this),this._multiply.dispose(),this._multiply=null,this},t.Negate}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1980 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1981 1982 }), 1983 (function(module, exports, __webpack_require__) { 1984 1985var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(2),__webpack_require__(3),__webpack_require__(5)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(e){"use strict";return e.GreaterThanZero=function(){this._thresh=this.output=new e.WaveShaper(function(e){return e<=0?0:1},127),this._scale=this.input=new e.Multiply(1e4),this._scale.connect(this._thresh)},e.extend(e.GreaterThanZero,e.SignalBase),e.GreaterThanZero.prototype.dispose=function(){return e.prototype.dispose.call(this),this._scale.dispose(),this._scale=null,this._thresh.dispose(),this._thresh=null,this},e.GreaterThanZero}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1986 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1987 1988 }), 1989 (function(module, exports, __webpack_require__) { 1990 1991var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(14),__webpack_require__(66),__webpack_require__(18),__webpack_require__(12)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(o){"use strict";return o.Clock=function(){o.Emitter.call(this);var t=this.optionsObject(arguments,["callback","frequency"],o.Clock.defaults);this.callback=t.callback,this._nextTick=0,this._lastState=o.State.Stopped,this.frequency=new o.TimelineSignal(t.frequency,o.Type.Frequency),this._readOnly("frequency"),this.ticks=0,this._state=new o.TimelineState(o.State.Stopped),this._boundLoop=this._loop.bind(this),this.context.on("tick",this._boundLoop)},o.extend(o.Clock,o.Emitter),o.Clock.defaults={callback:o.noOp,frequency:1,lookAhead:"auto"},Object.defineProperty(o.Clock.prototype,"state",{get:function(){return this._state.getValueAtTime(this.now())}}),o.Clock.prototype.start=function(t,e){return t=this.toSeconds(t),this._state.getValueAtTime(t)!==o.State.Started&&this._state.add({state:o.State.Started,time:t,offset:e}),this},o.Clock.prototype.stop=function(t){return t=this.toSeconds(t),this._state.cancel(t),this._state.setStateAtTime(o.State.Stopped,t),this},o.Clock.prototype.pause=function(t){return t=this.toSeconds(t),this._state.getValueAtTime(t)===o.State.Started&&this._state.setStateAtTime(o.State.Paused,t),this},o.Clock.prototype._loop=function(){for(var t=this.now()+this.context.lookAhead+this.context.updateInterval+2*this.context.lag;t>this._nextTick&&this._state;){var e=this._state.getValueAtTime(this._nextTick);if(e!==this._lastState){this._lastState=e;var i=this._state.get(this._nextTick);e===o.State.Started?(this._nextTick=i.time,this.isUndef(i.offset)||(this.ticks=i.offset),this.emit
1991("start",i.time,this.ticks)):e===o.State.Stopped?(this.ticks=0,this.emit("stop",i.time)):e===o.State.Paused&&this.emit("pause",i.time)}var s=this._nextTick;this.frequency&&(this._nextTick+=1/this.frequency.getValueAtTime(this._nextTick),e===o.State.Started&&(this.callback(s),this.ticks++))}},o.Clock.prototype.getStateAtTime=function(t){return t=this.toSeconds(t),this._state.getValueAtTime(t)},o.Clock.prototype.dispose=function(){o.Emitter.prototype.dispose.call(this),this.context.off("tick",this._boundLoop),this._writable("frequency"),this.frequency.dispose(),this.frequency=null,this._boundLoop=null,this._nextTick=1/0,this.callback=null,this._state.dispose(),this._state=null},o.Clock}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1992 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1993 1994 }), 1995 (function(module, exports, __webpack_require__) { 1996 1997"use strict"; 1998var __WEBPACK_AMD_DEFINE_RESULT__; 1999 2000!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 2001 var p5sound = __webpack_require__(1); 2002 2003 var AudioVoice = __webpack_require__(29); 2004 2005 var noteToFreq = __webpack_require__(6).noteToFreq; 2006 2007 var DEFAULT_SUSTAIN = 0.15; 2008 /** 2009 * A MonoSynth is used as a single voice for sound synthesis. 2010 * This is a class to be used in conjunction with the PolySynth 2011 * class. Custom synthetisers should be built inheriting from 2012 * this class. 2013 * 2014 * @class p5.MonoSynth 2015 * @constructor 2016 * @example 2017 * <div><code> 2018 * let monoSynth; 2019 * 2020 * function setup() { 2021 * let cnv = createCanvas(100, 100); 2022 * cnv.mousePressed(playSynth); 2023 * background(220); 2024 * textAlign(CENTER); 2025 * text('tap to play', width/2, height/2); 2026 * 2027 * monoSynth = new p5.MonoSynth(); 2028 * } 2029 * 2030 * function playSynth() { 2031 * userStartAudio(); 2032 * 2033 * let note = random(['Fb4', 'G4']); 2034 * // note velocity (volume, from 0 to 1) 2035 * let velocity = random(); 2036 * // time from now (in seconds) 2037 * let time = 0; 2038 * // note duration (in seconds) 2039 * let dur = 1/6; 2040 * 2041 * monoSynth.play(note, velocity, time, dur); 2042 * } 2043 * </code></div> 2044 **/ 2045 2046 p5.MonoSynth = function () { 2047 AudioVoice.call(this); 2048 this.oscillator = new p5.Oscillator(); 2049 this.env = new p5.Envelope(); 2050 this.env.setRange(1, 0); 2051 this.env.setExp(true); 2052 2053 this.setADSR(0.02, 0.25, 0.05, 0.35); 2054 2055 this.oscillator.disconnect(); 2056 this.oscillator.connect(this.output); 2057 this.env.disconnect(); 2058 this.env.setInput(this.output.gain); 2059 2060 this.oscillator.output.gain.value = 1.0; 2061 this.oscillator.start(); 2062 this.connect(); 2063 p5sound.soundArray.push(this); 2064 }; 2065 2066 p5.MonoSynth.prototype = Object.create(p5.AudioVoice.prototype); 2067 /** 2068 * Play tells the MonoSynth to start playing a note. This method schedules 2069 * the calling of .triggerAttack and .triggerRelease. 2070 * 2071 * @method play 2072 * @for p5.MonoSynth 2073 * @param {String | Number} note the note you want to play, specified as a 2074 * frequency in Hertz (Number) or as a midi 2075 * value in Note/Octave format ("C4", "Eb3"...etc") 2076 * See <a href = "https://github.com/Tonejs/Tone.js/wiki/Instruments"> 2077 * Tone</a>. Defaults to 440 hz. 2078 * @param {Number} [velocity] velocity of the note to play (ranging from 0 to 1) 2079 * @param {Number} [secondsFromNow] time from now (in seconds) at which to play 2080 * @param {Number} [sustainTime] time to sustain before releasing the envelope. Defaults to 0.15 seconds. 2081 * @example 2082 * <div><code> 2083 * let monoSynth; 2084 * 2085 * function setup() { 2086 * let cnv = createCanvas(100, 100); 2087 * cnv.mousePressed(playSynth); 2088 * background(220); 2089 * textAlign(CENTER); 2090 * text('tap to play', width/2, height/2); 2091 * 2092 * monoSynth = new p5.MonoSynth(); 2093 * } 2094 * 2095 * function playSynth() { 2096 * userStartAudio(); 2097 * 2098 * let note = random(['Fb4', 'G4']); 2099 * // note velocity (volume, from 0 to 1) 2100 * let velocity = random(); 2101 * // time from now (in seconds) 2102 * let time = 0; 2103 * // note duration (in seconds) 2104 * let dur = 1/6; 2105 * 2106 * monoSynth.play(note, velocity, time, dur); 2107 * } 2108 * </code></div> 2109 * 2110 */ 2111 2112 p5.MonoSynth.prototype.play = function (note, velocity, secondsFromNow, susTime) { 2113 this.triggerAttack(note, velocity, ~~secondsFromNow); 2114 this.triggerRelease(~~secondsFromNow + (susTime || DEFAULT_SUSTAIN)); 2115 }; 2116 /** 2117 * Trigger the Attack, and Decay portion of the Envelope. 2118 * Similar to holding down a key on a piano, but it will 2119 * hold the sustain level until you let go. 2120 * 2121 * @param {String | Number} note the note you want to play, specified as a 2122 * frequency in Hertz (Number) or as a midi 2123 * value in Note/Octave format ("C4", "Eb3"...etc") 2124 * See <a href = "https://github.com/Tonejs/Tone.js/wiki/Instruments"> 2125 * Tone</a>. Defaults to 440 hz 2126 * @param {Number} [velocity] velocity of the note to play (ranging from 0 to 1) 2127 * @param {Number} [secondsFromNow] time from now (in seconds) at which to play 2128 * @method triggerAttack 2129 * @for p5.MonoSynth 2130 * @example 2131 * <div><code> 2132 * let monoSynth; 2133 * 2134 * function setup() {
2135 * let cnv = createCanvas(100, 100); 2136 * cnv.mousePressed(triggerAttack); 2137 * background(220); 2138 * text('tap here for attack, let go to release', 5, 20, width - 20); 2139 * monoSynth = new p5.MonoSynth(); 2140 * } 2141 * 2142 * function triggerAttack() { 2143 * userStartAudio(); 2144 * 2145 * monoSynth.triggerAttack("E3"); 2146 * } 2147 * 2148 * function mouseReleased() { 2149 * monoSynth.triggerRelease(); 2150 * } 2151 * </code></div> 2152 */ 2153 2154 2155 p5.MonoSynth.prototype.triggerAttack = function (note, velocity, secondsFromNow) { 2156 var secondsFromNow = ~~secondsFromNow; 2157 var freq = noteToFreq(note); 2158 var vel = velocity || 0.1; 2159 this.oscillator.freq(freq, 0, secondsFromNow); 2160 this.env.ramp(this.output.gain, secondsFromNow, vel); 2161 }; 2162 /** 2163 * Trigger the release of the Envelope. This is similar to releasing 2164 * the key on a piano and letting the sound fade according to the 2165 * release level and release time. 2166 * 2167 * @param {Number} secondsFromNow time to trigger the release 2168 * @method triggerRelease 2169 * @for p5.MonoSynth 2170 * @example 2171 * <div><code> 2172 * let monoSynth; 2173 * 2174 * function setup() { 2175 * let cnv = createCanvas(100, 100); 2176 * cnv.mousePressed(triggerAttack); 2177 * background(220); 2178 * text('tap here for attack, let go to release', 5, 20, width - 20); 2179 * monoSynth = new p5.MonoSynth(); 2180 * } 2181 * 2182 * function triggerAttack() { 2183 * userStartAudio(); 2184 * 2185 * monoSynth.triggerAttack("E3"); 2186 * } 2187 * 2188 * function mouseReleased() { 2189 * monoSynth.triggerRelease(); 2190 * } 2191 * </code></div> 2192 */ 2193 2194 2195 p5.MonoSynth.prototype.triggerRelease = function (secondsFromNow) { 2196 var secondsFromNow = secondsFromNow || 0; 2197 this.env.ramp(this.output.gain, secondsFromNow, 0); 2198 }; 2199 /** 2200 * Set values like a traditional 2201 * <a href="https://en.wikipedia.org/wiki/Synthesizer#/media/File:ADSR_parameter.svg"> 2202 * ADSR envelope 2203 * </a>. 2204 * 2205 * @method setADSR 2206 * @for p5.MonoSynth 2207 * @param {Number} attackTime Time (in seconds before envelope 2208 * reaches Attack Level 2209 * @param {Number} [decayTime] Time (in seconds) before envelope 2210 * reaches Decay/Sustain Level 2211 * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, 2212 * where 1.0 = attackLevel, 0.0 = releaseLevel. 2213 * The susRatio determines the decayLevel and the level at which the 2214 * sustain portion of the envelope will sustain. 2215 * For example, if attackLevel is 0.4, releaseLevel is 0, 2216 * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is 2217 * increased to 1.0 (using <code>setRange</code>), 2218 * then decayLevel would increase proportionally, to become 0.5. 2219 * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) 2220 */ 2221 2222 2223 p5.MonoSynth.prototype.setADSR = function (attack, decay, sustain, release) { 2224 this.env.setADSR(attack, decay, sustain, release); 2225 }; 2226 /** 2227 * Getters and Setters 2228 * @property {Number} attack 2229 * @for p5.MonoSynth 2230 */ 2231 2232 /** 2233 * @property {Number} decay 2234 * @for p5.MonoSynth 2235 */ 2236 2237 /** 2238 * @property {Number} sustain 2239 * @for p5.MonoSynth 2240 */ 2241 2242 /** 2243 * @property {Number} release 2244 * @for p5.MonoSynth 2245 */ 2246 2247 2248 Object.defineProperties(p5.MonoSynth.prototype, { 2249 'attack': { 2250 get: function get() { 2251 return this.env.aTime; 2252 }, 2253 set: function set(attack) { 2254 this.env.setADSR(attack, this.env.dTime, this.env.sPercent, this.env.rTime); 2255 } 2256 }, 2257 'decay': { 2258 get: function get() { 2259 return this.env.dTime; 2260 }, 2261 set: function set(decay) { 2262 this.env.setADSR(this.env.aTime, decay, this.env.sPercent, this.env.rTime); 2263 } 2264 }, 2265 'sustain': { 2266 get: function get() { 2267 return this.env.sPercent; 2268 }, 2269 set: function set(sustain) { 2270 this.env.setADSR(this.env.aTime, this.env.dTime, sustain, this.env.rTime); 2271 } 2272 }, 2273 'release': { 2274 get: function get() { 2275 return this.env.rTime; 2276 }, 2277 set: function set(release) { 2278 this.env.setADSR(this.env.aTime, this.env.dTime, this.env.sPercent, release); 2279 } 2280 } 2281 }); 2282 /** 2283 * MonoSynth amp 2284 * @method amp 2285 * @for p5.MonoSynth 2286 * @param {Number} vol desired volume 2287 * @param {Number} [rampTime] Time to reach new volume 2288 * @return {Number} new volume value 2289 */ 2290 2291 p5.MonoSynth.prototype.amp = function (vol, rampTime) { 2292 var t = rampTime || 0; 2293 2294 if (typeof vol !== 'undefined') { 2295 this.oscillator.amp(vol, t); 2296 } 2297 2298 return this.oscillator.amp().value; 2299 }; 2300 /** 2301 * Connect to a p5.sound / Web Audio object. 2302 * 2303 * @method connect 2304 * @for p5.MonoSynth 2305 * @param {Object} unit A p5.sound or Web Audio object 2306 */ 2307 2308 2309 p5.MonoSynth.prototype.connect = function (unit) { 2310 var u = unit || p5sound.input; 2311 this.output.connect(u.input ? u.input : u); 2312 }; 2313 /** 2314 * Disconnect all outputs 2315 * 2316 * @method disconnect 2317 * @for p5.MonoSynth 2318 */ 2319 2320 2321 p5.MonoSynth.prototype.disconnect = function () { 2322 if (this.output) { 2323 this.output.disconnect(); 2324 } 2325 }; 2326 /** 2327 * Get rid of the MonoSynth and free up its resources / memory. 2328 * 2329 * @method dispose 2330 * @for p5.MonoSynth 2331 */ 2332 2333 2334 p5.MonoSynth.prototype.dispose = function () { 2335 AudioVoice.prototype.dispose.apply(this); 2336 2337 if (this.env) { 2338 this.env.dispose(); 2339 } 2340 2341 if (this.oscillator) { 2342 this.oscillator.dispose(); 2343 } 2344 }; 2345}).call(exports, __webpack_require__, exports, module), 2346 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 2347 2348 }), 2349 (function(module, exports, __webpack_require__) { 2350 2351"use strict"; 2352var __WEBPACK_AMD_DEFINE_RESULT__; 2353 2354!(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { 2355 var p5sound = __webpack_require__(1); 2356 /** 2357 * Base class for monophonic synthesizers. Any extensions of this class 2358 * should follow the API and implement the methods below in order to 2359 * remain compatible with p5.PolySynth(); 2360 * 2361 * @class p5.AudioVoice 2362 * @constructor 2363 */ 2364 2365 2366 p5.AudioVoice = function () { 2367 this.ac = p5sound.audiocontext; 2368 this.output = this.ac.createGain(); 2369 this.connect(); 2370 p5sound.soundArray.push(this); 2371 }; 2372 2373 p5.AudioVoice.prototype.play = function (note, velocity, secondsFromNow, sustime) {}; 2374 2375 p5.AudioVoice.prototype.triggerAttack = function (note, velocity, secondsFromNow) {}; 2376 2377 p5.AudioVoice.prototype.triggerRelease = function (secondsFromNow) {}; 2378 2379 p5.AudioVoice.prototype.amp = function (vol, rampTime) {}; 2380 /** 2381 * Connect to p5 objects or Web Audio Nodes 2382 * @method connect 2383 * @for p5.AudioVoice 2384 * @param {Object} unit 2385 */ 2386 2387 2388 p5.AudioVoice.prototype.connect = function (unit) { 2389 var u = unit || p5sound.input; 2390 this.output.connect(u.input ? u.input : u); 2391 }; 2392 /** 2393 * Disconnect from soundOut 2394 * @method disconnect 2395 * @for p5.AudioVoice 2396 */ 2397 2398 2399 p5.AudioVoice.prototype.disconnect = function () { 2400 this.output.disconnect(); 2401 }; 2402 2403 p5.AudioVoice.prototype.dispose = function () { 2404 if (this.output) { 2405 this.output.disconnect(); 2406 delete this.output; 2407 } 2408 }; 2409 2410 return p5.AudioVoice; 2411}).call(exports, __webpack_require__, exports, module), 2412 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 2413 2414 }), 2415 (function(module, exports, __webpack_require__) { 2416 2417"use strict"; 2418var __WEBPACK_AMD_DEFINE_RESULT__; 2419 2420!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 2421 var p5sound = __webpack_require__(1); 2422 2423 var TimelineSignal = __webpack_require__(14); 2424 2425 var noteToFreq = __webpack_require__(6).noteToFreq; 2426 /** 2427 * An AudioVoice is used as a single voice for sound synthesis. 2428 * The PolySynth class holds an array of AudioVoice, and deals 2429 * with voices allocations, with setting notes to be played, and 2430 * parameters to be set. 2431 * 2432 * @class p5.PolySynth 2433 * @constructor 2434 * 2435 * @param {Number} [synthVoice] A monophonic synth voice inheriting 2436 * the AudioVoice class. Defaults to p5.MonoSynth 2437 * @param {Number} [maxVoices] Number of voices, defaults to 8; 2438 * @example 2439 * <div><code> 2440 * let polySynth; 2441 * 2442 * function setup() {
2443 * let cnv = createCanvas(100, 100); 2444 * cnv.mousePressed(playSynth); 2445 * background(220); 2446 * text('click to play', 20, 20); 2447 * 2448 * polySynth = new p5.PolySynth(); 2449 * } 2450 * 2451 * function playSynth() { 2452 * userStartAudio(); 2453 * 2454 * // note duration (in seconds) 2455 * let dur = 1.5; 2456 * 2457 * // time from now (in seconds) 2458 * let time = 0; 2459 * 2460 * // velocity (volume, from 0 to 1) 2461 * let vel = 0.1; 2462 * 2463 * // notes can overlap with each other 2464 * polySynth.play('G2', vel, 0, dur); 2465 * polySynth.play('C3', vel, time += 1/3, dur); 2466 * polySynth.play('G3', vel, time += 1/3, dur); 2467 * } 2468 * </code></div> 2469 **/ 2470 2471 2472 p5.PolySynth = function (audioVoice, maxVoices) { 2473 this.audiovoices = []; 2474 /** 2475 * An object that holds information about which notes have been played and 2476 * which notes are currently being played. New notes are added as keys 2477 * on the fly. While a note has been attacked, but not released, the value of the 2478 * key is the audiovoice which is generating that note. When notes are released, 2479 * the value of the key becomes undefined. 2480 * @property notes 2481 */ 2482 2483 this.notes = {}; 2484 2485 this._newest = 0; 2486 this._oldest = 0; 2487 /** 2488 * A PolySynth must have at least 1 voice, defaults to 8 2489 * @property polyvalue 2490 */ 2491 2492 this.maxVoices = maxVoices || 8; 2493 /** 2494 * Monosynth that generates the sound for each note that is triggered. The 2495 * p5.PolySynth defaults to using the p5.MonoSynth as its voice. 2496 * @property AudioVoice 2497 */ 2498 2499 this.AudioVoice = audioVoice === undefined ? p5.MonoSynth : audioVoice; 2500 /** 2501 * This value must only change as a note is attacked or released. Due to delay 2502 * and sustain times, Tone.TimelineSignal is required to schedule the change in value. 2503 * @private 2504 * @property {Tone.TimelineSignal} _voicesInUse 2505 */ 2506 2507 this._voicesInUse = new TimelineSignal(0); 2508 this.output = p5sound.audiocontext.createGain(); 2509 this.connect(); 2510 2511 this._allocateVoices(); 2512 2513 p5sound.soundArray.push(this); 2514 }; 2515 /** 2516 * Construct the appropriate number of audiovoices 2517 * @private 2518 * @for p5.PolySynth 2519 * @method _allocateVoices 2520 */ 2521 2522 2523 p5.PolySynth.prototype._allocateVoices = function () { 2524 for (var i = 0; i < this.maxVoices; i++) { 2525 this.audiovoices.push(new this.AudioVoice()); 2526 this.audiovoices[i].disconnect(); 2527 this.audiovoices[i].connect(this.output); 2528 } 2529 }; 2530 /** 2531 * Play a note by triggering noteAttack and noteRelease with sustain time 2532 * 2533 * @method play 2534 * @for p5.PolySynth 2535 * @param {Number} [note] midi note to play (ranging from 0 to 127 - 60 being a middle C) 2536 * @param {Number} [velocity] velocity of the note to play (ranging from 0 to 1) 2537 * @param {Number} [secondsFromNow] time from now (in seconds) at which to play 2538 * @param {Number} [sustainTime] time to sustain before releasing the envelope 2539 * @example 2540 * <div><code> 2541 * let polySynth; 2542 * 2543 * function setup() { 2544 * let cnv = createCanvas(100, 100); 2545 * cnv.mousePressed(playSynth); 2546 * background(220); 2547 * text('click to play', 20, 20); 2548 * 2549 * polySynth = new p5.PolySynth(); 2550 * } 2551 * 2552 * function playSynth() { 2553 * userStartAudio(); 2554 * 2555 * // note duration (in seconds) 2556 * let dur = 1.5; 2557 * 2558 * // time from now (in seconds) 2559 * let time = 0; 2560 * 2561 * // velocity (volume, from 0 to 1) 2562 * let vel = 0.1; 2563 * 2564 * // notes can overlap with each other 2565 * polySynth.play('G2', vel, 0, dur); 2566 * polySynth.play('C3', vel, time += 1/3, dur); 2567 * polySynth.play('G3', vel, time += 1/3, dur); 2568 * } 2569 * </code></div> 2570 */ 2571 2572 2573 p5.PolySynth.prototype.play = function (note, velocity, secondsFromNow, susTime) { 2574 var susTime = susTime || 1; 2575 this.noteAttack(note, velocity, secondsFromNow); 2576 this.noteRelease(note, secondsFromNow + susTime); 2577 }; 2578 /** 2579 * noteADSR sets the envelope for a specific note that has just been triggered. 2580 * Using this method modifies the envelope of whichever audiovoice is being used 2581 * to play the desired note. The envelope should be reset before noteRelease is called 2582 * in order to prevent the modified envelope from being used on other notes. 2583 * 2584 * @method noteADSR 2585 * @for p5.PolySynth 2586 * @param {Number} [note] Midi note on which ADSR should be set. 2587 * @param {Number} [attackTime] Time (in seconds before envelope 2588 * reaches Attack Level 2589 * @param {Number} [decayTime] Time (in seconds) before envelope 2590 * reaches Decay/Sustain Level 2591 * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, 2592 * where 1.0 = attackLevel, 0.0 = releaseLevel. 2593 * The susRatio determines the decayLevel and the level at which the 2594 * sustain portion of the envelope will sustain. 2595 * For example, if attackLevel is 0.4, releaseLevel is 0, 2596 * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is 2597 * increased to 1.0 (using <code>setRange</code>), 2598 * then decayLevel would increase proportionally, to become 0.5. 2599 * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) 2600 **/ 2601 2602 2603 p5.PolySynth.prototype.noteADSR = function (note, a, d, s, r, timeFromNow) { 2604 var now = p5sound.audiocontext.currentTime; 2605 var timeFromNow = timeFromNow || 0; 2606 var t = now + timeFromNow; 2607 this.audiovoices[this.notes[note].getValueAtTime(t)].setADSR(a, d, s, r); 2608 }; 2609 /** 2610 * Set the PolySynths global envelope. This method modifies the envelopes of each 2611 * monosynth so that all notes are played with this envelope. 2612 * 2613 * @method setADSR 2614 * @for p5.PolySynth 2615 * @param {Number} [attackTime] Time (in seconds before envelope 2616 * reaches Attack Level 2617 * @param {Number} [decayTime] Time (in seconds) before envelope 2618 * reaches Decay/Sustain Level 2619 * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, 2620 * where 1.0 = attackLevel, 0.0 = releaseLevel. 2621 * The susRatio determines the decayLevel and the level at which the 2622 * sustain portion of the envelope will sustain. 2623 * For example, if attackLevel is 0.4, releaseLevel is 0, 2624 * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is 2625 * increased to 1.0 (using <code>setRange</code>), 2626 * then decayLevel would increase proportionally, to become 0.5. 2627 * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) 2628 **/ 2629 2630 2631 p5.PolySynth.prototype.setADSR = function (a, d, s, r) {
2632 this.audiovoices.forEach(function (voice) { 2633 voice.setADSR(a, d, s, r); 2634 }); 2635 }; 2636 /** 2637 * Trigger the Attack, and Decay portion of a MonoSynth. 2638 * Similar to holding down a key on a piano, but it will 2639 * hold the sustain level until you let go. 2640 * 2641 * @method noteAttack 2642 * @for p5.PolySynth 2643 * @param {Number} [note] midi note on which attack should be triggered. 2644 * @param {Number} [velocity] velocity of the note to play (ranging from 0 to 1)/ 2645 * @param {Number} [secondsFromNow] time from now (in seconds) 2646 * @example 2647 * <div><code> 2648 * let polySynth = new p5.PolySynth(); 2649 * let pitches = ['G', 'D', 'G', 'C']; 2650 * let octaves = [2, 3, 4]; 2651 * 2652 * function setup() { 2653 * let cnv = createCanvas(100, 100); 2654 * cnv.mousePressed(playChord); 2655 * background(220); 2656 * text('tap to play', 20, 20); 2657 * } 2658 * 2659 * function playChord() { 2660 * userStartAudio(); 2661 * 2662 * // play a chord: multiple notes at the same time 2663 * for (let i = 0; i < 4; i++) { 2664 * let note = random(pitches) + random(octaves); 2665 * polySynth.noteAttack(note, 0.1); 2666 * } 2667 * } 2668 * 2669 * function mouseReleased() { 2670 * // release all voices 2671 * polySynth.noteRelease(); 2672 * } 2673 * </code></div> 2674 */ 2675 2676 2677 p5.PolySynth.prototype.noteAttack = function (_note, _velocity, secondsFromNow) { 2678 var secondsFromNow = ~~secondsFromNow; 2679 2680 var acTime = p5sound.audiocontext.currentTime + secondsFromNow; 2681 2682 var note = noteToFreq(_note); 2683 var velocity = _velocity || 0.1; 2684 var currentVoice; 2685 2686 if (this.notes[note] && this.notes[note].getValueAtTime(acTime) !== null) { 2687 this.noteRelease(note, 0); 2688 } 2689 2690 2691 if (this._voicesInUse.getValueAtTime(acTime) < this.maxVoices) { 2692 currentVoice = Math.max(~~this._voicesInUse.getValueAtTime(acTime), 0); 2693 } 2694 else { 2695 currentVoice = this._oldest; 2696 var oldestNote = p5.prototype.freqToMidi(this.audiovoices[this._oldest].oscillator.freq().value); 2697 this.noteRelease(oldestNote); 2698 this._oldest = (this._oldest + 1) % (this.maxVoices - 1); 2699 } 2700 2701 2702 this.notes[note] = new TimelineSignal(); 2703 this.notes[note].setValueAtTime(currentVoice, acTime); 2704 2705 var previousVal = this._voicesInUse._searchBefore(acTime) === null ? 0 : this._voicesInUse._searchBefore(acTime).value; 2706 2707 this._voicesInUse.setValueAtTime(previousVal + 1, acTime); 2708 2709 2710 this._updateAfter(acTime, 1); 2711 2712 this._newest = currentVoice; 2713 2714 if (typeof velocity === 'number') { 2715 var maxRange = 1 / this._voicesInUse.getValueAtTime(acTime) * 2; 2716 velocity = velocity > maxRange ? maxRange : velocity; 2717 } 2718 2719 this.audiovoices[currentVoice].triggerAttack(note, velocity, secondsFromNow); 2720 }; 2721 /** 2722 * Private method to ensure accurate values of this._voicesInUse 2723 * Any time a new value is scheduled, it is necessary to increment all subsequent 2724 * scheduledValues after attack, and decrement all subsequent 2725 * scheduledValues after release 2726 * 2727 * @private 2728 * @for p5.PolySynth 2729 * @param {[type]} time [description] 2730 * @param {[type]} value [description] 2731 * @return {[type]} [description] 2732 */ 2733 2734 2735 p5.PolySynth.prototype._updateAfter = function (time, value) { 2736 if (this._voicesInUse._searchAfter(time) === null) { 2737 return; 2738 } else { 2739 this._voicesInUse._searchAfter(time).value += value; 2740 2741 var nextTime = this._voicesInUse._searchAfter(time).time; 2742 2743 this._updateAfter(nextTime, value); 2744 } 2745 }; 2746 /** 2747 * Trigger the Release of an AudioVoice note. This is similar to releasing 2748 * the key on a piano and letting the sound fade according to the 2749 * release level and release time. 2750 * 2751 * @method noteRelease 2752 * @for p5.PolySynth 2753 * @param {Number} [note] midi note on which attack should be triggered. 2754 * If no value is provided, all notes will be released. 2755 * @param {Number} [secondsFromNow] time to trigger the release 2756 * @example 2757 * <div><code> 2758 * let polySynth = new p5.PolySynth(); 2759 * let pitches = ['G', 'D', 'G', 'C']; 2760 * let octaves = [2, 3, 4]; 2761 * 2762 * function setup() {
2763 * let cnv = createCanvas(100, 100); 2764 * cnv.mousePressed(playChord); 2765 * background(220); 2766 * text('tap to play', 20, 20); 2767 * } 2768 * 2769 * function playChord() { 2770 * userStartAudio(); 2771 * 2772 * // play a chord: multiple notes at the same time 2773 * for (let i = 0; i < 4; i++) { 2774 * let note = random(pitches) + random(octaves); 2775 * polySynth.noteAttack(note, 0.1); 2776 * } 2777 * } 2778 * 2779 * function mouseReleased() { 2780 * // release all voices 2781 * polySynth.noteRelease(); 2782 * } 2783 * </code></div> 2784 * 2785 */ 2786 2787 2788 p5.PolySynth.prototype.noteRelease = function (_note, secondsFromNow) { 2789 var now = p5sound.audiocontext.currentTime; 2790 var tFromNow = secondsFromNow || 0; 2791 var t = now + tFromNow; 2792 2793 if (!_note) { 2794 this.audiovoices.forEach(function (voice) { 2795 voice.triggerRelease(tFromNow); 2796 }); 2797 2798 this._voicesInUse.setValueAtTime(0, t); 2799 2800 for (var n in this.notes) { 2801 this.notes[n].dispose(); 2802 delete this.notes[n]; 2803 } 2804 2805 return; 2806 } 2807 2808 2809 var note = noteToFreq(_note); 2810 2811 if (!this.notes[note] || this.notes[note].getValueAtTime(t) === null) { 2812 console.warn('Cannot release a note that is not already playing'); 2813 } else { 2814 var previousVal = Math.max(~~this._voicesInUse.getValueAtTime(t).value, 1); 2815 2816 this._voicesInUse.setValueAtTime(previousVal - 1, t); 2817 2818 2819 if (previousVal > 0) { 2820 this._updateAfter(t, -1); 2821 } 2822 2823 this.audiovoices[this.notes[note].getValueAtTime(t)].triggerRelease(tFromNow); 2824 this.notes[note].dispose(); 2825 delete this.notes[note]; 2826 this._newest = this._newest === 0 ? 0 : (this._newest - 1) % (this.maxVoices - 1); 2827 } 2828 }; 2829 /** 2830 * Connect to a p5.sound / Web Audio object. 2831 * 2832 * @method connect 2833 * @for p5.PolySynth 2834 * @param {Object} unit A p5.sound or Web Audio object 2835 */ 2836 2837 2838 p5.PolySynth.prototype.connect = function (unit) { 2839 var u = unit || p5sound.input; 2840 this.output.connect(u.input ? u.input : u); 2841 }; 2842 /** 2843 * Disconnect all outputs 2844 * 2845 * @method disconnect 2846 * @for p5.PolySynth 2847 */ 2848 2849 2850 p5.PolySynth.prototype.disconnect = function () { 2851 if (this.output) { 2852 this.output.disconnect(); 2853 } 2854 }; 2855 /** 2856 * Get rid of the MonoSynth and free up its resources / memory. 2857 * 2858 * @method dispose 2859 * @for p5.PolySynth 2860 */ 2861 2862 2863 p5.PolySynth.prototype.dispose = function () { 2864 this.audiovoices.forEach(function (voice) { 2865 voice.dispose(); 2866 }); 2867 2868 if (this.output) { 2869 this.output.disconnect(); 2870 delete this.output; 2871 } 2872 }; 2873}).call(exports, __webpack_require__, exports, module), 2874 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 2875 2876 }), 2877 (function(module, exports, __webpack_require__) { 2878 2879"use strict"; 2880var __WEBPACK_AMD_DEFINE_RESULT__; 2881 2882!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 2883 __webpack_require__(32); 2884 2885 __webpack_require__(33); 2886 2887 __webpack_require__(17); 2888 2889 var p5SOUND = __webpack_require__(1); 2890 2891 __webpack_require__(6); 2892 2893 __webpack_require__(11); 2894 2895 __webpack_require__(36); 2896 2897 __webpack_require__(40); 2898 2899 __webpack_require__(41); 2900 2901 __webpack_require__(42); 2902 2903 __webpack_require__(43); 2904 2905 __webpack_require__(44); 2906 2907 __webpack_require__(23); 2908 2909 __webpack_require__(47); 2910 2911 __webpack_require__(48); 2912 2913 __webpack_require__(49); 2914 2915 __webpack_require__(50); 2916 2917 __webpack_require__(15); 2918 2919 __webpack_require__(59); 2920 2921 __webpack_require__(61); 2922 2923 __webpack_require__(62); 2924 2925 __webpack_require__(63); 2926 2927 __webpack_require__(64); 2928 2929 __webpack_require__(65); 2930 2931 __webpack_require__(67); 2932 2933 __webpack_require__(68); 2934 2935 __webpack_require__(69); 2936 2937 __webpack_require__(70); 2938 2939 __webpack_require__(71); 2940 2941 __webpack_require__(72); 2942 2943 __webpack_require__(28); 2944 2945 __webpack_require__(30); 2946 2947 __webpack_require__(73); 2948 2949 __webpack_require__(29); 2950 2951 __webpack_require__(28); 2952 2953 __webpack_require__(30); 2954 2955 return p5SOUND; 2956}).call(exports, __webpack_require__, exports, module), 2957 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 2958 2959 }),
2960 (function(module, exports) { 2961 2962!function(){var l,s=[];function p(e){var o=this,n={},i=-1;this.parameters.forEach(function(e,t){var r=s[++i]||(s[i]=new Float32Array(o.bufferSize));r.fill(e.value),n[t]=r}),this.processor.realm.exec("self.sampleRate=sampleRate="+this.context.sampleRate+";self.currentTime=currentTime="+this.context.currentTime);var t=a(e.inputBuffer),r=a(e.outputBuffer);this.instance.process([t],[r],n)}function a(e){for(var t=[],r=0;r<e.numberOfChannels;r++)t[r]=e.getChannelData(r);return t}function f(e){return e.$$processors||(e.$$processors={})}function e(e){this.$$context=e}"function"!=typeof AudioWorkletNode&&(self.AudioWorkletNode=function(e,t,r){var o=f(e)[t],n=e.createScriptProcessor(void 0,2,r&&r.outputChannelCount?r.outputChannelCount[0]:2);if(n.parameters=new Map,o.properties)for(var i=0;i<o.properties.length;i++){var s=o.properties[i],a=e.createGain().gain;a.value=s.defaultValue,n.parameters.set(s.name,a)}var u=new MessageChannel;l=u.port2;var c=new o.Processor(r||{});return l=null,n.port=u.port1,n.processor=o,n.instance=c,n.onaudioprocess=p,n},Object.defineProperty((self.AudioContext||self.webkitAudioContext).prototype,"audioWorklet",{get:function(){return this.$$audioWorklet||(this.$$audioWorklet=new self.AudioWorklet(this))}}),self.AudioWorklet=(e.prototype.addModule=function(e,t){var n=this;return fetch(e).then(function(e){if(!e.ok)throw Error(e.status);return e.text()}).then(function(e){var r={sampleRate:0,currentTime:0,AudioWorkletProcessor:function(){this.port=l},registerProcessor:function(e,t){f(n.$$context)[e]={realm:o,context:r,Processor:t,properties:t.parameterDescriptors||[]}}},o=new function(e,t){var r=document.createElement("iframe");r.style.cssText="position:absolute;left:0;top:-999px;width:1px;height:1px;",t.appendChild(r);var o=r.contentWindow,n=o.document,i="var window,$hook";for(var s in o)s in e||"eval"===s||(i+=",",i+=s);for(var a in e)i+=",",i+=a,i+="=self.",i+=a;var u=n.createElement("script");u.appendChild(n.createTextNode('function $hook(self,console) {"use strict";\n '+i+";return function() {return eval(arguments[0])}}")),n.body.appendChild(u),this.exec=o.$hook(e,console)}(r.self=r,document.documentElement);return o.exec((t&&t.transpile||String)(e)),null})},e))}(); 2963 2964 }), 2965 (function(module, exports, __webpack_require__) { 2966 2967"use strict"; 2968var __WEBPACK_AMD_DEFINE_RESULT__; 2969/** 2970 * This module has shims 2971 */ 2972 2973!(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { 2974 (function () { 2975 function fixSetTarget(param) { 2976 if (!param) 2977 return; 2978 if (!param.setTargetAtTime) param.setTargetAtTime = param.setTargetValueAtTime; 2979 } 2980 2981 if (window.hasOwnProperty('webkitAudioContext') && !window.hasOwnProperty('AudioContext')) { 2982 window.AudioContext = window.webkitAudioContext; 2983 if (typeof AudioContext.prototype.createGain !== 'function') AudioContext.prototype.createGain = AudioContext.prototype.createGainNode; 2984 if (typeof AudioContext.prototype.createDelay !== 'function') AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode; 2985 if (typeof AudioContext.prototype.createScriptProcessor !== 'function') AudioContext.prototype.createScriptProcessor = AudioContext.prototype.createJavaScriptNode; 2986 if (typeof AudioContext.prototype.createPeriodicWave !== 'function') AudioContext.prototype.createPeriodicWave = AudioContext.prototype.createWaveTable; 2987 AudioContext.prototype.internal_createGain = AudioContext.prototype.createGain; 2988 2989 AudioContext.prototype.createGain = function () { 2990 var node = this.internal_createGain(); 2991 fixSetTarget(node.gain); 2992 return node; 2993 }; 2994 2995 AudioContext.prototype.internal_createDelay = AudioContext.prototype.createDelay; 2996 2997 AudioContext.prototype.createDelay = function (maxDelayTime) { 2998 var node = maxDelayTime ? this.internal_createDelay(maxDelayTime) : this.internal_createDelay(); 2999 fixSetTarget(node.delayTime); 3000 return node; 3001 }; 3002 3003 AudioContext.prototype.internal_createBufferSource = AudioContext.prototype.createBufferSource; 3004 3005 AudioContext.prototype.createBufferSource = function () { 3006 var node = this.internal_createBufferSource(); 3007 3008 if (!node.start) { 3009 node.start = function (when, offset, duration) {
3010 if (offset || duration) this.noteGrainOn(when || 0, offset, duration);else this.noteOn(when || 0); 3011 }; 3012 } else { 3013 node.internal_start = node.start; 3014 3015 node.start = function (when, offset, duration) { 3016 if (typeof duration !== 'undefined') node.internal_start(when || 0, offset, duration);else node.internal_start(when || 0, offset || 0); 3017 }; 3018 } 3019 3020 if (!node.stop) { 3021 node.stop = function (when) { 3022 this.noteOff(when || 0); 3023 }; 3024 } else { 3025 node.internal_stop = node.stop; 3026 3027 node.stop = function (when) { 3028 node.internal_stop(when || 0); 3029 }; 3030 } 3031 3032 fixSetTarget(node.playbackRate); 3033 return node; 3034 }; 3035 3036 AudioContext.prototype.internal_createDynamicsCompressor = AudioContext.prototype.createDynamicsCompressor; 3037 3038 AudioContext.prototype.createDynamicsCompressor = function () { 3039 var node = this.internal_createDynamicsCompressor(); 3040 fixSetTarget(node.threshold); 3041 fixSetTarget(node.knee); 3042 fixSetTarget(node.ratio); 3043 fixSetTarget(node.reduction); 3044 fixSetTarget(node.attack); 3045 fixSetTarget(node.release); 3046 return node; 3047 }; 3048 3049 AudioContext.prototype.internal_createBiquadFilter = AudioContext.prototype.createBiquadFilter; 3050 3051 AudioContext.prototype.createBiquadFilter = function () { 3052 var node = this.internal_createBiquadFilter(); 3053 fixSetTarget(node.frequency); 3054 fixSetTarget(node.detune); 3055 fixSetTarget(node.Q); 3056 fixSetTarget(node.gain); 3057 return node; 3058 }; 3059 3060 if (typeof AudioContext.prototype.createOscillator !== 'function') { 3061 AudioContext.prototype.internal_createOscillator = AudioContext.prototype.createOscillator; 3062 3063 AudioContext.prototype.createOscillator = function () { 3064 var node = this.internal_createOscillator(); 3065 3066 if (!node.start) { 3067 node.start = function (when) { 3068 this.noteOn(when || 0); 3069 }; 3070 } else { 3071 node.internal_start = node.start; 3072 3073 node.start = function (when) { 3074 node.internal_start(when || 0); 3075 }; 3076 } 3077 3078 if (!node.stop) { 3079 node.stop = function (when) { 3080 this.noteOff(when || 0); 3081 }; 3082 } else { 3083 node.internal_stop = node.stop; 3084 3085 node.stop = function (when) { 3086 node.internal_stop(when || 0); 3087 }; 3088 } 3089 3090 if (!node.setPeriodicWave) node.setPeriodicWave = node.setWaveTable; 3091 fixSetTarget(node.frequency); 3092 fixSetTarget(node.detune); 3093 return node; 3094 }; 3095 } 3096 } 3097 3098 if (window.hasOwnProperty('webkitOfflineAudioContext') && !window.hasOwnProperty('OfflineAudioContext')) { 3099 window.OfflineAudioContext = window.webkitOfflineAudioContext; 3100 } 3101 })(window); 3102 3103 3104 navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; 3105 /** 3106 * Determine which filetypes are supported (inspired by buzz.js) 3107 * The audio element (el) will only be used to test browser support for various audio formats 3108 */ 3109 3110 var el = document.createElement('audio'); 3111 3112 p5.prototype.isSupported = function () { 3113 return !!el.canPlayType; 3114 }; 3115 3116 var isOGGSupported = function isOGGSupported() { 3117 return !!el.canPlayType && el.canPlayType('audio/ogg; codecs="vorbis"'); 3118 }; 3119 3120 var isMP3Supported = function isMP3Supported() { 3121 return !!el.canPlayType && el.canPlayType('audio/mpeg;'); 3122 }; 3123 3124 var isWAVSupported = function isWAVSupported() { 3125 return !!el.canPlayType && el.canPlayType('audio/wav; codecs="1"'); 3126 }; 3127 3128 var isAACSupported = function isAACSupported() { 3129 return !!el.canPlayType && (el.canPlayType('audio/x-m4a;') || el.canPlayType('audio/aac;')); 3130 }; 3131 3132 var isAIFSupported = function isAIFSupported() { 3133 return !!el.canPlayType && el.canPlayType('audio/x-aiff;'); 3134 }; 3135 3136 p5.prototype.isFileSupported = function (extension) { 3137 switch (extension.toLowerCase()) { 3138 case 'mp3': 3139 return isMP3Supported(); 3140 3141 case 'wav': 3142 return isWAVSupported(); 3143 3144 case 'ogg': 3145 return isOGGSupported(); 3146 3147 case 'aac': 3148 case 'm4a': 3149 case 'mp4': 3150 return isAACSupported(); 3151 3152 case 'aif': 3153 case 'aiff': 3154 return isAIFSupported(); 3155 3156 default: 3157 return false;
3158 } 3159 }; 3160}).call(exports, __webpack_require__, exports, module), 3161 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 3162 3163 }), 3164 (function(module, exports) { 3165 3166var g;g=function(){return this}();try{g=g||new Function("return this")()}catch(t){"object"==typeof window&&(g=window)}module.exports=g; 3167 3168 }), 3169 (function(module, exports, __webpack_require__) { 3170 3171var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!function(e,t){ true?!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (t), 3172 __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? 3173 (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), 3174 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)):undefined}(this,function(){var r=function(e,t){this._dragged=!1,this._element=e,this._bindedMove=this._moved.bind(this),this._bindedEnd=this._ended.bind(this,t),e.addEventListener("touchstart",this._bindedEnd),e.addEventListener("touchmove",this._bindedMove),e.addEventListener("touchend",this._bindedEnd),e.addEventListener("mouseup",this._bindedEnd)};function o(e){return"running"===e.state}return r.prototype._moved=function(e){this._dragged=!0},r.prototype._ended=function(e){this._dragged||function(e){var t=e.createBuffer(1,1,e.sampleRate),n=e.createBufferSource();n.buffer=t,n.connect(e.destination),n.start(0),e.resume&&e.resume()}(e),this._dragged=!1},r.prototype.dispose=function(){this._element.removeEventListener("touchstart",this._bindedEnd),this._element.removeEventListener("touchmove",this._bindedMove),this._element.removeEventListener("touchend",this._bindedEnd),this._element.removeEventListener("mouseup",this._bindedEnd),this._bindedMove=null,this._bindedEnd=null,this._element=null},function(t,e,n){var i=new Promise(function(e){!function(t,n){o(t)?n():function e(){o(t)?n():(requestAnimationFrame(e),t.resume&&t.resume())}()}(t,e)}),d=[];return function e(t,n,i){if(Array.isArray(t)||NodeList&&t instanceof NodeList)for(var d=0;d<t.length;d++)e(t[d],n,i);else if("string"==typeof t)e(document.querySelectorAll(t),n,i);else if(t.jquery&&"function"==typeof t.toArray)e(t.toArray(),n,i);else if(Element&&t instanceof Element){var o=new r(t,i);n.push(o)}}(e=e||document.body,d,t),i.then(function(){for(var e=0;e<d.length;e++)d[e].dispose();d=null,n&&n()}),i}}); 3175 3176 }), 3177 (function(module, exports, __webpack_require__) { 3178 3179var p5sound = __webpack_require__(1); 3180 3181var moduleSources = [__webpack_require__(37)["default"], __webpack_require__(38)["default"], __webpack_require__(39)["default"]]; 3182var ac = p5sound.audiocontext; 3183var initializedAudioWorklets = false; 3184 3185function loadAudioWorkletModules() { 3186 return Promise.all(moduleSources.map(function (moduleSrc) { 3187 var blob = new Blob([moduleSrc], { 3188 type: 'application/javascript' 3189 }); 3190 var objectURL = URL.createObjectURL(blob); 3191 return ac.audioWorklet.addModule(objectURL); 3192 })); 3193} 3194 3195p5.prototype.registerMethod('init', function () { 3196 if (initializedAudioWorklets) return; 3197 3198 if (!this.preload && !window.preload) { 3199 this.preload = function () {}; 3200 } 3201 3202 3203 this._incrementPreload(); 3204 3205 var onWorkletModulesLoad = function () { 3206 initializedAudioWorklets = true; 3207 3208 this._decrementPreload(); 3209 }.bind(this); 3210 3211 loadAudioWorkletModules().then(onWorkletModulesLoad); 3212}); 3213 3214 }), 3215 (function(module, __webpack_exports__, __webpack_require__) { 3216 3217"use strict"; 3218__webpack_require__.r(__webpack_exports__); 3219 __webpack_exports__["default"] = ("function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { c
3219onstructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _wrapNativeSuper(Class) { var _cache = typeof Map === \"function\" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== \"function\") { throw new TypeError(\"Super expression must either be null or a function\"); } if (typeof _cache !== \"undefined\") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }\n\nfunction isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }\n\nfunction _isNativeFunction(fn) { return Function.toString.call(fn).indexOf(\"[native code]\") !== -1; }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n// import dependencies via preval.require so that they're available as values at compile time\nvar processorNames = {\n \"recorderProcessor\": \"recorder-processor\",\n \"soundFileProcessor\": \"sound-file-processor\",\n \"amplitudeProcessor\": \"amplitude-processor\"\n};\nvar RingBuffer = {\n \"default\":\n /*#__PURE__*/\n function () {\n /**\n * @constructor\n * @param {number} length Buffer length in frames.\n * @param {number} channelCount Buffer channel count.\n */\n function RingBuffer(length, channelCount) {\n _classCallCheck(this, RingBuffer);\n\n this._readIndex = 0;\n this._writeIndex = 0;\n this._framesAvailable = 0;\n this._channelCount = channelCount;\n this._length = length;\n this._channelData = [];\n\n for (var i = 0; i < this._channelCount; ++i) {\n this._channelData[i] = new Float32Array(length);\n }\n }\n /**\n * Getter for Available frames in buffer.\n *\n * @return {number} Available frames in buffer.\n */\n\n\n _createClass(RingBuffer, [{\n key: \"push\",\n\n /**\n * Push a sequence of Float32Arrays to buffer.\n *\n * @param {array} arraySequence A sequence of Float32Arrays.\n */\n value: function push(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // Transfer data from the |arraySequence| storage to the internal buffer.\n var sourceLength = arraySequence[0].length;\n\n for (var i = 0; i < sourceLength;
3219 ++i) {\n var writeIndex = (this._writeIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n this._channelData[channel][writeIndex] = arraySequence[channel][i];\n }\n }\n\n this._writeIndex += sourceLength;\n\n if (this._writeIndex >= this._length) {\n this._writeIndex = 0;\n } // For excessive frames, the buffer will be overwritten.\n\n\n this._framesAvailable += sourceLength;\n\n if (this._framesAvailable > this._length) {\n this._framesAvailable = this._length;\n }\n }\n /**\n * Pull data out of buffer and fill a given sequence of Float32Arrays.\n *\n * @param {array} arraySequence An array of Float32Arrays.\n */\n\n }, {\n key: \"pull\",\n value: function pull(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // If the FIFO is completely empty, do nothing.\n if (this._framesAvailable === 0) {\n return;\n }\n\n var destinationLength = arraySequence[0].length; // Transfer data from the internal buffer to the |arraySequence| storage.\n\n for (var i = 0; i < destinationLength; ++i) {\n var readIndex = (this._readIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n arraySequence[channel][i] = this._channelData[channel][readIndex];\n }\n }\n\n this._readIndex += destinationLength;\n\n if (this._readIndex >= this._length) {\n this._readIndex = 0;\n }\n\n this._framesAvailable -= destinationLength;\n\n if (this._framesAvailable < 0) {\n this._framesAvailable = 0;\n }\n }\n }, {\n key: \"framesAvailable\",\n get: function get() {\n return this._framesAvailable;\n }\n }]);\n\n return RingBuffer;\n }()\n}[\"default\"];\n\nvar RecorderProcessor =\n/*#__PURE__*/\nfunction (_AudioWorkletProcesso) {\n _inherits(RecorderProcessor, _AudioWorkletProcesso);\n\n function RecorderProcessor(options) {\n var _this;\n\n _classCallCheck(this, RecorderProcessor);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(RecorderProcessor).call(this));\n var processorOptions = options.processorOptions || {};\n _this.numOutputChannels = options.outputChannelCount || 2;\n _this.numInputChannels = processorOptions.numInputChannels || 2;\n _this.bufferSize = processorOptions.bufferSize || 1024;\n _this.recording = false;\n\n _this.clear();\n\n _this.port.onmessage = function (event) {\n var data = event.data;\n\n if (data.name === 'start') {\n _this.record(data.duration);\n } else if (data.name === 'stop') {\n _this.stop();\n }\n };\n\n return _this;\n }\n\n _createClass(RecorderProcessor, [{\n key: \"process\",\n value: function process(inputs) {\n if (!this.recording) {\n return true;\n } else if (this.sampleLimit && this.recordedSamples >= this.sampleLimit) {\n this.stop();\n return true;\n }\n\n var input = inputs[0];\n this.inputRingBuffer.push(input);\n\n if (this.inputRingBuffer.framesAvailable >= this.bufferSize) {\n this.inputRingBuffer.pull(this.inputRingBufferArraySequence);\n\n for (var channel = 0; channel < this.numOutputChannels; ++channel) {\n var inputChannelCopy = this.inputRingBufferArraySequence[channel].slice();\n\n if (channel === 0) {\n this.leftBuffers.push(inputChannelCopy);\n\n if (this.numInputChannels === 1) {\n this.rightBuffers.push(inputChannelCopy);\n }\n } else if (channel === 1 && this.numInputChannels > 1) {\n this.rightBuffers.push(inputChannelCopy);\n }\n }\n\n this.recordedSamples += this.bufferSize;\n }\n\n return true;\n }\n }, {\n key: \"record\",\n value: function record(duration) {\n if (duration) {\n this.sampleLimit = Math.round(duration * sampleRate);\n }\n\n this.recording = true;\n }\n }, {\n key: \"stop\",\n value: function stop() {\n this.recording = false;\n var buffers = this.getBuffers();\n var leftBuffer = buffers[0].buffer;\n var rightBuffer = buffers[1].buffer;\n this.port.postMessage({\n name: 'buffers',\n leftBuffer: leftBuffer,\n rightBuffer: rightBuffer\n }, [leftBuffer, rightBuffer]);\n this.clear();\n }\n }, {\n key: \"getBuffers\",\n value: function getBuffers() {\n var buffers = [];\n buffers.push(this.mergeBuffers(this.leftBuffers));\n buffers.push(this.mergeBuffers(this.rightBuffers));\n return buffers;\n }\n }, {\n key: \"mergeBuffers\",\n value: function mergeBuffers(channelBuffer) {\n var result = new Float32Array(this.recordedSamples);\n var offset = 0;\n var lng = channelBuffer.length;\n\n for (var i = 0; i < lng;
3219 i++) {\n var buffer = channelBuffer[i];\n result.set(buffer, offset);\n offset += buffer.length;\n }\n\n return result;\n }\n }, {\n key: \"clear\",\n value: function clear() {\n var _this2 = this;\n\n this.leftBuffers = [];\n this.rightBuffers = [];\n this.inputRingBuffer = new RingBuffer(this.bufferSize, this.numInputChannels);\n this.inputRingBufferArraySequence = new Array(this.numInputChannels).fill(null).map(function () {\n return new Float32Array(_this2.bufferSize);\n });\n this.recordedSamples = 0;\n this.sampleLimit = null;\n }\n }]);\n\n return RecorderProcessor;\n}(_wrapNativeSuper(AudioWorkletProcessor));\n\nregisterProcessor(processorNames.recorderProcessor, RecorderProcessor);"); 3220 3221 }), 3222 (function(module, __webpack_exports__, __webpack_require__) { 3223 3224"use strict"; 3225__webpack_require__.r(__webpack_exports__); 3226 __webpack_exports__["default"] = ("function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _wrapNativeSuper(Class) { var _cache = typeof Map === \"function\" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== \"function\") { throw new TypeError(\"Super expression must either be null or a function\"); } if (typeof _cache !== \"undefined\") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }\n\nfunction isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }\n\nfunction _isNativeFunction(fn) { return Function.toString.call(fn).indexOf(\"[native code]\") !== -1; }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n// import dependencies via preval.require so that they're available as values at compile time\nvar processorNames = {\n \"recorderProcessor\": \"recorder-processor\",\n \"soundFileProcessor\": \"sound-file-processor\",\n \"amplitudeProcessor\": \"amplitude-processor\"\n};\nvar RingBuffer = {\n \"default\":\n /*#__PURE__*/\n function () {\n /**\n * @constructor\n * @param {number} length Buffer length in frames.\n * @param {number} channelCount Buffer channel count.\n */\n function RingBuffer(length, channelCount) {\n _classCallCheck(this, RingBuffer);\n\n this._readIndex = 0;\n this._writeIndex = 0;\n this._framesAvailable = 0;\n this._channelCount = channelCount;\n this._length = length;\n this._channelData = [];\n\n for (var i = 0; i < this._channelCount; ++i) {\n this._channelData[i] = new Float32Array(length);\n }\n }\n /**\n * Getter for Available frames in buffer.\n *\n * @return {number} Available frames in buffer.\n */\n\n\n _createClass(RingBuffer, [{\
3226n key: \"push\",\n\n /**\n * Push a sequence of Float32Arrays to buffer.\n *\n * @param {array} arraySequence A sequence of Float32Arrays.\n */\n value: function push(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // Transfer data from the |arraySequence| storage to the internal buffer.\n var sourceLength = arraySequence[0].length;\n\n for (var i = 0; i < sourceLength; ++i) {\n var writeIndex = (this._writeIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n this._channelData[channel][writeIndex] = arraySequence[channel][i];\n }\n }\n\n this._writeIndex += sourceLength;\n\n if (this._writeIndex >= this._length) {\n this._writeIndex = 0;\n } // For excessive frames, the buffer will be overwritten.\n\n\n this._framesAvailable += sourceLength;\n\n if (this._framesAvailable > this._length) {\n this._framesAvailable = this._length;\n }\n }\n /**\n * Pull data out of buffer and fill a given sequence of Float32Arrays.\n *\n * @param {array} arraySequence An array of Float32Arrays.\n */\n\n }, {\n key: \"pull\",\n value: function pull(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // If the FIFO is completely empty, do nothing.\n if (this._framesAvailable === 0) {\n return;\n }\n\n var destinationLength = arraySequence[0].length; // Transfer data from the internal buffer to the |arraySequence| storage.\n\n for (var i = 0; i < destinationLength; ++i) {\n var readIndex = (this._readIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n arraySequence[channel][i] = this._channelData[channel][readIndex];\n }\n }\n\n this._readIndex += destinationLength;\n\n if (this._readIndex >= this._length) {\n this._readIndex = 0;\n }\n\n this._framesAvailable -= destinationLength;\n\n if (this._framesAvailable < 0) {\n this._framesAvailable = 0;\n }\n }\n }, {\n key: \"framesAvailable\",\n get: function get() {\n return this._framesAvailable;\n }\n }]);\n\n return RingBuffer;\n }()\n}[\"default\"];\n\nvar SoundFileProcessor =\n/*#__PURE__*/\nfunction (_AudioWorkletProcesso) {\n _inherits(SoundFileProcessor, _AudioWorkletProcesso);\n\n function SoundFileProcessor(options) {\n var _this;\n\n _classCallCheck(this, SoundFileProcessor);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(SoundFileProcessor).call(this));\n var processorOptions = options.processorOptions || {};\n _this.bufferSize = processorOptions.bufferSize || 256;\n _this.inputRingBuffer = new RingBuffer(_this.bufferSize, 1);\n _this.inputRingBufferArraySequence = [new Float32Array(_this.bufferSize)];\n return _this;\n }\n\n _createClass(SoundFileProcessor, [{\n key: \"process\",\n value: function process(inputs) {\n var input = inputs[0]; // we only care about the first input channel, because that contains the position data\n\n this.inputRingBuffer.push([input[0]]);\n\n if (this.inputRingBuffer.framesAvailable >= this.bufferSize) {\n this.inputRingBuffer.pull(this.inputRingBufferArraySequence);\n var inputChannel = this.inputRingBufferArraySequence[0];\n var position = inputChannel[inputChannel.length - 1] || 0;\n this.port.postMessage({\n name: 'position',\n position: position\n });\n }\n\n return true;\n }\n }]);\n\n return SoundFileProcessor;\n}(_wrapNativeSuper(AudioWorkletProcessor));\n\nregisterProcessor(processorNames.soundFileProcessor, SoundFileProcessor);"); 3227 3228 }), 3229 (function(module, __webpack_exports__, __webpack_require__) { 3230 3231"use strict"; 3232__webpack_require__.r(__webpack_exports__); 3233 __webpack_exports__["default"] = ("function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { c
3233onstructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _wrapNativeSuper(Class) { var _cache = typeof Map === \"function\" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== \"function\") { throw new TypeError(\"Super expression must either be null or a function\"); } if (typeof _cache !== \"undefined\") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }\n\nfunction isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }\n\nfunction _isNativeFunction(fn) { return Function.toString.call(fn).indexOf(\"[native code]\") !== -1; }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n// import dependencies via preval.require so that they're available as values at compile time\nvar processorNames = {\n \"recorderProcessor\": \"recorder-processor\",\n \"soundFileProcessor\": \"sound-file-processor\",\n \"amplitudeProcessor\": \"amplitude-processor\"\n};\nvar RingBuffer = {\n \"default\":\n /*#__PURE__*/\n function () {\n /**\n * @constructor\n * @param {number} length Buffer length in frames.\n * @param {number} channelCount Buffer channel count.\n */\n function RingBuffer(length, channelCount) {\n _classCallCheck(this, RingBuffer);\n\n this._readIndex = 0;\n this._writeIndex = 0;\n this._framesAvailable = 0;\n this._channelCount = channelCount;\n this._length = length;\n this._channelData = [];\n\n for (var i = 0; i < this._channelCount; ++i) {\n this._channelData[i] = new Float32Array(length);\n }\n }\n /**\n * Getter for Available frames in buffer.\n *\n * @return {number} Available frames in buffer.\n */\n\n\n _createClass(RingBuffer, [{\n key: \"push\",\n\n /**\n * Push a sequence of Float32Arrays to buffer.\n *\n * @param {array} arraySequence A sequence of Float32Arrays.\n */\n value: function push(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // Transfer data from the |arraySequence| storage to the internal buffer.\n var sourceLength = arraySequence[0].length;\n\n for (var i = 0; i < sourceLength;
3233 ++i) {\n var writeIndex = (this._writeIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n this._channelData[channel][writeIndex] = arraySequence[channel][i];\n }\n }\n\n this._writeIndex += sourceLength;\n\n if (this._writeIndex >= this._length) {\n this._writeIndex = 0;\n } // For excessive frames, the buffer will be overwritten.\n\n\n this._framesAvailable += sourceLength;\n\n if (this._framesAvailable > this._length) {\n this._framesAvailable = this._length;\n }\n }\n /**\n * Pull data out of buffer and fill a given sequence of Float32Arrays.\n *\n * @param {array} arraySequence An array of Float32Arrays.\n */\n\n }, {\n key: \"pull\",\n value: function pull(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // If the FIFO is completely empty, do nothing.\n if (this._framesAvailable === 0) {\n return;\n }\n\n var destinationLength = arraySequence[0].length; // Transfer data from the internal buffer to the |arraySequence| storage.\n\n for (var i = 0; i < destinationLength; ++i) {\n var readIndex = (this._readIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n arraySequence[channel][i] = this._channelData[channel][readIndex];\n }\n }\n\n this._readIndex += destinationLength;\n\n if (this._readIndex >= this._length) {\n this._readIndex = 0;\n }\n\n this._framesAvailable -= destinationLength;\n\n if (this._framesAvailable < 0) {\n this._framesAvailable = 0;\n }\n }\n }, {\n key: \"framesAvailable\",\n get: function get() {\n return this._framesAvailable;\n }\n }]);\n\n return RingBuffer;\n }()\n}[\"default\"];\n\nvar AmplitudeProcessor =\n/*#__PURE__*/\nfunction (_AudioWorkletProcesso) {\n _inherits(AmplitudeProcessor, _AudioWorkletProcesso);\n\n function AmplitudeProcessor(options) {\n var _this;\n\n _classCallCheck(this, AmplitudeProcessor);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(AmplitudeProcessor).call(this));\n var processorOptions = options.processorOptions || {};\n _this.numOutputChannels = options.outputChannelCount || 1;\n _this.numInputChannels = processorOptions.numInputChannels || 2;\n _this.normalize = processorOptions.normalize || false;\n _this.smoothing = processorOptions.smoothing || 0;\n _this.bufferSize = processorOptions.bufferSize || 2048;\n _this.inputRingBuffer = new RingBuffer(_this.bufferSize, _this.numInputChannels);\n _this.outputRingBuffer = new RingBuffer(_this.bufferSize, _this.numOutputChannels);\n _this.inputRingBufferArraySequence = new Array(_this.numInputChannels).fill(null).map(function () {\n return new Float32Array(_this.bufferSize);\n });\n _this.stereoVol = [0, 0];\n _this.stereoVolNorm = [0, 0];\n _this.volMax = 0.001;\n\n _this.port.onmessage = function (event) {\n var data = event.data;\n\n if (data.name === 'toggleNormalize') {\n _this.normalize = data.normalize;\n } else if (data.name === 'smoothing') {\n _this.smoothing = Math.max(0, Math.min(1, data.smoothing));\n }\n };\n\n return _this;\n } // TO DO make this stereo / dependent on # of audio channels\n\n\n _createClass(AmplitudeProcessor, [{\n key: \"process\",\n value: function process(inputs, outputs) {\n var input = inputs[0];\n var output = outputs[0];\n var smoothing = this.smoothing;\n this.inputRingBuffer.push(input);\n\n if (this.inputRingBuffer.framesAvailable >= this.bufferSize) {\n this.inputRingBuffer.pull(this.inputRingBufferArraySequence);\n\n for (var channel = 0; channel < this.numInputChannels; ++channel) {\n var inputBuffer = this.inputRingBufferArraySequence[channel];\n var bufLength = inputBuffer.length;\n var sum = 0;\n\n for (var i = 0; i < bufLength;
3233 i++) {\n var x = inputBuffer[i];\n\n if (this.normalize) {\n sum += Math.max(Math.min(x / this.volMax, 1), -1) * Math.max(Math.min(x / this.volMax, 1), -1);\n } else {\n sum += x * x;\n }\n } // ... then take the square root of the sum.\n\n\n var rms = Math.sqrt(sum / bufLength);\n this.stereoVol[channel] = Math.max(rms, this.stereoVol[channel] * smoothing);\n this.volMax = Math.max(this.stereoVol[channel], this.volMax);\n } // calculate stero normalized volume and add volume from all channels together\n\n\n var volSum = 0;\n\n for (var index = 0; index < this.stereoVol.length; index++) {\n this.stereoVolNorm[index] = Math.max(Math.min(this.stereoVol[index] / this.volMax, 1), 0);\n volSum += this.stereoVol[index];\n } // volume is average of channels\n\n\n var volume = volSum / this.stereoVol.length; // normalized value\n\n var volNorm = Math.max(Math.min(volume / this.volMax, 1), 0);\n this.port.postMessage({\n name: 'amplitude',\n volume: volume,\n volNorm: volNorm,\n stereoVol: this.stereoVol,\n stereoVolNorm: this.stereoVolNorm\n }); // pass input through to output\n\n this.outputRingBuffer.push(this.inputRingBufferArraySequence);\n } // pull 128 frames out of the ring buffer\n // if the ring buffer does not have enough frames, the output will be silent\n\n\n this.outputRingBuffer.pull(output);\n return true;\n }\n }]);\n\n return AmplitudeProcessor;\n}(_wrapNativeSuper(AudioWorkletProcessor));\n\nregisterProcessor(processorNames.amplitudeProcessor, AmplitudeProcessor);"); 3234 3235 }), 3236 (function(module, exports, __webpack_require__) { 3237 3238"use strict"; 3239var __WEBPACK_AMD_DEFINE_RESULT__; 3240 3241function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 3242 3243!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 3244 var p5sound = __webpack_require__(1); 3245 3246 var ac = p5sound.audiocontext; 3247 3248 if (typeof ac.createStereoPanner !== 'undefined') { 3249 p5.Panner = function (input, output) { 3250 this.stereoPanner = this.input = ac.createStereoPanner(); 3251 input.connect(this.stereoPanner); 3252 this.stereoPanner.connect(output); 3253 }; 3254 3255 p5.Panner.prototype.pan = function (val, tFromNow) { 3256 var time = tFromNow || 0; 3257 var t = ac.currentTime + time; 3258 this.stereoPanner.pan.linearRampToValueAtTime(val, t); 3259 }; 3260 3261 3262 p5.Panner.prototype.inputChannels = function () {}; 3263 3264 p5.Panner.prototype.connect = function (obj) { 3265 this.stereoPanner.connect(obj); 3266 }; 3267 3268 p5.Panner.prototype.disconnect = function () { 3269 if (this.stereoPanner) { 3270 this.stereoPanner.disconnect(); 3271 } 3272 }; 3273 } else { 3274 p5.Panner = function (input, output, numInputChannels) { 3275 this.input = ac.createGain(); 3276 input.connect(this.input); 3277 this.left = ac.createGain(); 3278 this.right = ac.createGain(); 3279 this.left.channelInterpretation = 'discrete'; 3280 this.right.channelInterpretation = 'discrete'; 3281 3282 if (numInputChannels > 1) { 3283 this.splitter = ac.createChannelSplitter(2); 3284 this.input.connect(this.splitter); 3285 this.splitter.connect(this.left, 1); 3286 this.splitter.connect(this.right, 0); 3287 } else { 3288 this.input.connect(this.left); 3289 this.input.connect(this.right); 3290 } 3291 3292 this.output = ac.createChannelMerger(2); 3293 this.left.connect(this.output, 0, 1); 3294 this.right.connect(this.output, 0, 0); 3295 this.output.connect(output); 3296 }; 3297 3298 3299 p5.Panner.prototype.pan = function (val, tFromNow) { 3300 var time = tFromNow || 0; 3301 var t = ac.currentTime + time; 3302 var v = (val + 1) / 2;
3303 var rightVal = Math.cos(v * Math.PI / 2); 3304 var leftVal = Math.sin(v * Math.PI / 2); 3305 this.left.gain.linearRampToValueAtTime(leftVal, t); 3306 this.right.gain.linearRampToValueAtTime(rightVal, t); 3307 }; 3308 3309 p5.Panner.prototype.inputChannels = function (numChannels) { 3310 if (numChannels === 1) { 3311 this.input.disconnect(); 3312 this.input.connect(this.left); 3313 this.input.connect(this.right); 3314 } else if (numChannels === 2) { 3315 if (_typeof(this.splitter === 'undefined')) { 3316 this.splitter = ac.createChannelSplitter(2); 3317 } 3318 3319 this.input.disconnect(); 3320 this.input.connect(this.splitter); 3321 this.splitter.connect(this.left, 1); 3322 this.splitter.connect(this.right, 0); 3323 } 3324 }; 3325 3326 p5.Panner.prototype.connect = function (obj) { 3327 this.output.connect(obj); 3328 }; 3329 3330 p5.Panner.prototype.disconnect = function () { 3331 if (this.output) { 3332 this.output.disconnect(); 3333 } 3334 }; 3335 } 3336}).call(exports, __webpack_require__, exports, module), 3337 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 3338 3339 }), 3340 (function(module, exports, __webpack_require__) { 3341 3342"use strict"; 3343var __WEBPACK_AMD_DEFINE_RESULT__; 3344 3345function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 3346 3347!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 3348 var CustomError = __webpack_require__(11); 3349 3350 var p5sound = __webpack_require__(1); 3351 3352 var ac = p5sound.audiocontext; 3353 3354 var _require = __webpack_require__(6), 3355 midiToFreq = _require.midiToFreq, 3356 convertToWav = _require.convertToWav, 3357 safeBufferSize = _require.safeBufferSize; 3358 3359 var processorNames = __webpack_require__(10); 3360 /** 3361 * <p>SoundFile object with a path to a file.</p> 3362 * 3363 * <p>The p5.SoundFile may not be available immediately because 3364 * it loads the file information asynchronously.</p> 3365 * 3366 * <p>To do something with the sound as soon as it loads 3367 * pass the name of a function as the second parameter.</p> 3368 * 3369 * <p>Only one file path is required. However, audio file formats 3370 * (i.e. mp3, ogg, wav and m4a/aac) are not supported by all 3371 * web browsers. If you want to ensure compatability, instead of a single 3372 * file path, you may include an Array of filepaths, and the browser will 3373 * choose a format that works.</p> 3374 * 3375 * @class p5.SoundFile 3376 * @constructor 3377 * @param {String|Array} path path to a sound file (String). Optionally, 3378 * you may include multiple file formats in 3379 * an array. Alternately, accepts an object 3380 * from the HTML5 File API, or a p5.File. 3381 * @param {Function} [successCallback] Name of a function to call once file loads 3382 * @param {Function} [errorCallback] Name of a function to call if file fails to 3383 * load. This function will receive an error or 3384 * XMLHttpRequest object with information 3385 * about what went wrong. 3386 * @param {Function} [whileLoadingCallback] Name of a function to call while file 3387 * is loading. That function will 3388 * receive progress of the request to 3389 * load the sound file 3390 * (between 0 and 1) as its first 3391 * parameter. This progress 3392 * does not account for the additional 3393 * time needed to decode the audio data. 3394 * 3395 * @example 3396 * <div><code> 3397 * let mySound; 3398 * function preload() { 3399 * soundFormats('mp3', 'ogg'); 3400 * mySound = loadSound('assets/doorbell'); 3401 * } 3402 * 3403 * function setup() {
3404 * let cnv = createCanvas(100, 100); 3405 * cnv.mousePressed(canvasPressed); 3406 * background(220); 3407 * text('tap here to play', 10, 20); 3408 * } 3409 * 3410 * function canvasPressed() { 3411 * // playing a sound file on a user gesture 3412 * // is equivalent to `userStartAudio()` 3413 * mySound.play(); 3414 * } 3415 * </code></div> 3416 */ 3417 3418 3419 p5.SoundFile = function (paths, onload, onerror, whileLoading) { 3420 if (typeof paths !== 'undefined') { 3421 if (typeof paths === 'string' || typeof paths[0] === 'string') { 3422 var path = p5.prototype._checkFileFormats(paths); 3423 3424 this.url = path; 3425 } else if (_typeof(paths) === 'object') { 3426 if (!(window.File && window.FileReader && window.FileList && window.Blob)) { 3427 throw 'Unable to load file because the File API is not supported'; 3428 } 3429 } 3430 3431 3432 if (paths.file) { 3433 paths = paths.file; 3434 } 3435 3436 this.file = paths; 3437 } 3438 3439 3440 this._onended = function () {}; 3441 3442 this._looping = false; 3443 this._playing = false; 3444 this._paused = false; 3445 this._pauseTime = 0; 3446 3447 this._cues = []; 3448 this._cueIDCounter = 0; 3449 3450 this._lastPos = 0; 3451 this._counterNode = null; 3452 this._workletNode = null; 3453 3454 this.bufferSourceNodes = []; 3455 3456 this.bufferSourceNode = null; 3457 this.buffer = null; 3458 this.playbackRate = 1; 3459 this.input = p5sound.audiocontext.createGain(); 3460 this.output = p5sound.audiocontext.createGain(); 3461 this.reversed = false; 3462 3463 this.startTime = 0; 3464 this.endTime = null; 3465 this.pauseTime = 0; 3466 3467 this.mode = 'sustain'; 3468 3469 this.startMillis = null; 3470 3471 this.panPosition = 0.0; 3472 this.panner = new p5.Panner(this.output, p5sound.input, 2); 3473 3474 if (this.url || this.file) { 3475 this.load(onload, onerror); 3476 } 3477 3478 3479 p5sound.soundArray.push(this); 3480 3481 if (typeof whileLoading === 'function') { 3482 this._whileLoading = whileLoading; 3483 } else { 3484 this._whileLoading = function () {}; 3485 } 3486 3487 this._clearOnEnd = _clearOnEnd.bind(this); 3488 }; 3489 3490 3491 p5.prototype.registerPreloadMethod('loadSound', p5.prototype); 3492 /** 3493 * loadSound() returns a new p5.SoundFile from a specified 3494 * path. If called during preload(), the p5.SoundFile will be ready 3495 * to play in time for setup() and draw(). If called outside of 3496 * preload, the p5.SoundFile will not be ready immediately, so 3497 * loadSound accepts a callback as the second parameter. Using a 3498 * <a href="https://github.com/processing/p5.js/wiki/Local-server"> 3499 * local server</a> is recommended when loading external files. 3500 * 3501 * @method loadSound 3502 * @for p5 3503 * @param {String|Array} path Path to the sound file, or an array with 3504 * paths to soundfiles in multiple formats 3505 * i.e. ['sound.ogg', 'sound.mp3']. 3506 * Alternately, accepts an object: either 3507 * from the HTML5 File API, or a p5.File. 3508 * @param {Function} [successCallback] Name of a function to call once file loads 3509 * @param {Function} [errorCallback] Name of a function to call if there is 3510 * an error loading the file. 3511 * @param {Function} [whileLoading] Name of a function to call while file is loading. 3512 * This function will receive the percentage loaded 3513 * so far, from 0.0 to 1.0. 3514 * @return {SoundFile} Returns a p5.SoundFile 3515 * @example 3516 * <div><code> 3517 * let mySound; 3518 * function preload() { 3519 * soundFormats('mp3', 'ogg'); 3520 * mySound = loadSound('assets/doorbell'); 3521 * } 3522 * 3523 * function setup() { 3524 * let cnv = createCanvas(100, 100); 3525 * cnv.mousePressed(canvasPressed); 3526 * background(220); 3527 * text('tap here to play', 10, 20); 3528 * } 3529 * 3530 * function canvasPressed() { 3531 * // playing a sound file on a user gesture 3532 * // is equivalent to `userStartAudio()` 3533 * mySound.play(); 3534 * } 3535 * </code></div> 3536 */ 3537 3538 p5.prototype.loadSound = function (path, callback, onerror, whileLoading) { 3539 if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') { 3540 window.alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS'); 3541 } 3542 3543 var self = this; 3544 var s = new p5.SoundFile(path, function () { 3545 if (typeof callback === 'function') { 3546 callback.apply(self, arguments); 3547 } 3548 3549 if (typeof self._decrementPreload === 'function') { 3550 self._decrementPreload(); 3551 } 3552 }, onerror, whileLoading); 3553 return s; 3554 }; 3555 /** 3556 * This is a helper function that the p5.SoundFile calls to load 3557 * itself. Accepts a callback (the name of another function) 3558 * as an optional parameter. 3559 * 3560 * @private 3561 * @for p5.SoundFile 3562 * @param {Function} [successCallback] Name of a function to call once file loads 3563 * @param {Function} [errorCallback] Name of a function to call if there is an error 3564 */ 3565 3566 3567 p5.SoundFile.prototype.load = function (callback, errorCallback) { 3568 var self = this; 3569 var errorTrace = new Error().stack; 3570 3571 if (this.url !== undefined && this.url !== '') { 3572 var request = new XMLHttpRequest(); 3573 request.addEventListener('progress', function (evt) { 3574 self._updateProgress(evt); 3575 }, false); 3576 request.open('GET', this.url, true); 3577 request.responseType = 'arraybuffer'; 3578 3579 request.onload = function () { 3580 if (request.status === 200) { 3581 if (!self.panner) return; 3582 ac.decodeAudioData(request.response, 3583 function (buff) { 3584 if (!self.panner) return; 3585 self.buffer = buff; 3586 self.panner.inputChannels(buff.numberOfChannels); 3587 3588 if (callback) { 3589 callback(self); 3590 } 3591 }, 3592 function () { 3593 if (!self.panner) return; 3594 var err = new CustomError('decodeAudioData', errorTrace, self.url); 3595 var msg = 'AudioContext error at decodeAudioData for ' + self.url; 3596 3597 if (errorCallback) { 3598 err.msg = msg; 3599 errorCallback(err); 3600 } else { 3601 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 3602 } 3603 }); 3604 } 3605 else { 3606 if (!self.panner) return; 3607 var err = new CustomError('loadSound', errorTrace, self.url); 3608 var msg = 'Unable to load ' + self.url + '. The request status was: ' + request.status + ' (' + request.statusText + ')'; 3609 3610 if (errorCallback) { 3611 err.message = msg; 3612 errorCallback(err); 3613 } else { 3614 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 3615 } 3616 } 3617 }; 3618 3619 3620 request.onerror = function () { 3621 var err = new CustomError('loadSound', errorTrace, self.url); 3622 var msg = 'There was no response from the server at ' + self.url + '. Check the url and internet connectivity.';
3623 3624 if (errorCallback) { 3625 err.message = msg; 3626 errorCallback(err); 3627 } else { 3628 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 3629 } 3630 }; 3631 3632 request.send(); 3633 } else if (this.file !== undefined) { 3634 var reader = new FileReader(); 3635 3636 reader.onload = function () { 3637 if (!self.panner) return; 3638 ac.decodeAudioData(reader.result, function (buff) { 3639 if (!self.panner) return; 3640 self.buffer = buff; 3641 self.panner.inputChannels(buff.numberOfChannels); 3642 3643 if (callback) { 3644 callback(self); 3645 } 3646 }); 3647 }; 3648 3649 reader.onerror = function (e) { 3650 if (!self.panner) return; 3651 3652 if (onerror) { 3653 onerror(e); 3654 } 3655 }; 3656 3657 reader.readAsArrayBuffer(this.file); 3658 } 3659 }; 3660 3661 3662 p5.SoundFile.prototype._updateProgress = function (evt) { 3663 if (evt.lengthComputable) { 3664 var percentComplete = evt.loaded / evt.total * 0.99; 3665 3666 this._whileLoading(percentComplete, evt); 3667 3668 } else { 3669 this._whileLoading('size unknown'); 3670 } 3671 }; 3672 /** 3673 * Returns true if the sound file finished loading successfully. 3674 * 3675 * @method isLoaded 3676 * @for p5.SoundFile 3677 * @return {Boolean} 3678 */ 3679 3680 3681 p5.SoundFile.prototype.isLoaded = function () { 3682 if (this.buffer) { 3683 return true; 3684 } else { 3685 return false; 3686 } 3687 }; 3688 /** 3689 * Play the p5.SoundFile 3690 * 3691 * @method play 3692 * @for p5.SoundFile 3693 * @param {Number} [startTime] (optional) schedule playback to start (in seconds from now). 3694 * @param {Number} [rate] (optional) playback rate 3695 * @param {Number} [amp] (optional) amplitude (volume) 3696 * of playback 3697 * @param {Number} [cueStart] (optional) cue start time in seconds 3698 * @param {Number} [duration] (optional) duration of playback in seconds 3699 */ 3700 3701 3702 p5.SoundFile.prototype.play = function (startTime, rate, amp, _cueStart, duration) { 3703 if (!this.output) { 3704 console.warn('SoundFile.play() called after dispose'); 3705 return; 3706 } 3707 3708 var now = p5sound.audiocontext.currentTime; 3709 var cueStart, cueEnd; 3710 var time = startTime || 0; 3711 3712 if (time < 0) { 3713 time = 0; 3714 } 3715 3716 time = time + now; 3717 3718 if (typeof rate !== 'undefined') { 3719 this.rate(rate); 3720 } 3721 3722 if (typeof amp !== 'undefined') { 3723 this.setVolume(amp); 3724 } 3725 3726 3727 if (this.buffer) { 3728 this._pauseTime = 0; 3729 3730 if (this.mode === 'restart' && this.buffer && this.bufferSourceNode) { 3731 this.bufferSourceNode.stop(time); 3732 3733 this._counterNode.stop(time); 3734 } 3735 3736 3737 if (this.mode === 'untildone' && this.isPlaying()) { 3738 return; 3739 } 3740 3741 3742 this.bufferSourceNode = this._initSourceNode(); 3743 3744 delete this._counterNode; 3745 this._counterNode = this._initCounterNode(); 3746 3747 if (_cueStart) { 3748 if (_cueStart >= 0 && _cueStart < this.buffer.duration) { 3749 cueStart = _cueStart; 3750 } else { 3751 throw 'start time out of range'; 3752 } 3753 } else { 3754 cueStart = 0; 3755 } 3756 3757 if (duration) { 3758 duration = duration <= this.buffer.duration - cueStart ? duration : this.buffer.duration; 3759 } 3760 3761 3762 if (this._paused) { 3763 this.bufferSourceNode.start(time, this.pauseTime, duration); 3764 3765 this._counterNode.start(time, this.pauseTime, duration); 3766 } else { 3767 this.bufferSourceNode.start(time, cueStart, duration); 3768 3769 this._counterNode.start(time, cueStart, duration); 3770 } 3771 3772 this._playing = true; 3773 this._paused = false; 3774 3775 this.bufferSourceNodes.push(this.bufferSourceNode); 3776 this.bufferSourceNode._arrayIndex = this.bufferSourceNodes.length - 1; 3777 this.bufferSourceNode.addEventListener('ended', this._clearOnEnd); 3778 } 3779 else { 3780 throw 'not ready to play file, buffer has yet to load. Try preload()'; 3781 } 3782 3783 3784 this.bufferSourceNode.loop = this._looping; 3785 this._counterNode.loop = this._looping; 3786 3787 if (this._looping === true) { 3788 cueEnd = duration ? duration : cueStart - 0.000000000000001; 3789 this.bufferSourceNode.loopStart = cueStart; 3790 this.bufferSourceNode.loopEnd = cueEnd; 3791 this._counterNode.loopStart = cueStart; 3792 this._counterNode.loopEnd = cueEnd; 3793 } 3794 }; 3795 /** 3796 * p5.SoundFile has two play modes: <code>restart</code> and 3797 * <code>sustain</code>. Play Mode determines what happens to a 3798 * p5.SoundFile if it is triggered while in the middle of playback. 3799 * In sustain mode, playback will continue simultaneous to the 3800 * new playback. In restart mode, play() will stop playback 3801 * and start over. With untilDone, a sound will play only if it's 3802 * not already playing. Sustain is the default mode. 3803 * 3804 * @method playMode 3805 * @for p5.SoundFile 3806 * @param {String} str 'restart' or 'sustain' or 'untilDone' 3807 * @example 3808 * <div><code> 3809 * let mySound; 3810 * function preload(){ 3811 * mySound = loadSound('assets/Damscray_DancingTiger.mp3'); 3812 * } 3813 * function setup() {
3814 * let cnv = createCanvas(100, 100); 3815 * cnv.mousePressed(canvasPressed); 3816 * noFill(); 3817 * rect(0, height/2, width - 1, height/2 - 1); 3818 * rect(0, 0, width - 1, height/2); 3819 * textAlign(CENTER, CENTER); 3820 * fill(20); 3821 * text('restart', width/2, 1 * height/4); 3822 * text('sustain', width/2, 3 * height/4); 3823 * } 3824 * function canvasPressed() { 3825 * if (mouseX < height/2) { 3826 * mySound.playMode('restart'); 3827 * } else { 3828 * mySound.playMode('sustain'); 3829 * } 3830 * mySound.play(); 3831 * } 3832 * 3833 * </code></div> 3834 */ 3835 3836 3837 p5.SoundFile.prototype.playMode = function (str) { 3838 var s = str.toLowerCase(); 3839 3840 if (s === 'restart' && this.buffer && this.bufferSourceNode) { 3841 for (var i = 0; i < this.bufferSourceNodes.length - 1; i++) { 3842 var now = p5sound.audiocontext.currentTime; 3843 this.bufferSourceNodes[i].stop(now); 3844 } 3845 } 3846 3847 3848 if (s === 'restart' || s === 'sustain' || s === 'untildone') { 3849 this.mode = s; 3850 } else { 3851 throw 'Invalid play mode. Must be either "restart" or "sustain"'; 3852 } 3853 }; 3854 /** 3855 * Pauses a file that is currently playing. If the file is not 3856 * playing, then nothing will happen. 3857 * 3858 * After pausing, .play() will resume from the paused 3859 * position. 3860 * If p5.SoundFile had been set to loop before it was paused, 3861 * it will continue to loop after it is unpaused with .play(). 3862 * 3863 * @method pause 3864 * @for p5.SoundFile 3865 * @param {Number} [startTime] (optional) schedule event to occur 3866 * seconds from now 3867 * @example 3868 * <div><code> 3869 * let soundFile; 3870 * function preload() { 3871 * soundFormats('ogg', 'mp3'); 3872 * soundFile = loadSound('assets/Damscray_-_Dancing_Tiger_02.mp3'); 3873 * } 3874 * function setup() { 3875 * let cnv = createCanvas(100, 100); 3876 * cnv.mousePressed(canvasPressed); 3877 * background(220); 3878 * text('tap to play, release to pause', 10, 20, width - 20); 3879 * } 3880 * function canvasPressed() { 3881 * soundFile.loop(); 3882 * background(0, 200, 50); 3883 * } 3884 * function mouseReleased() { 3885 * soundFile.pause(); 3886 * background(220); 3887 * } 3888 * </code> 3889 * </div> 3890 */ 3891 3892 3893 p5.SoundFile.prototype.pause = function (startTime) { 3894 var now = p5sound.audiocontext.currentTime; 3895 var time = startTime || 0; 3896 var pTime = time + now; 3897 3898 if (this.isPlaying() && this.buffer && this.bufferSourceNode) { 3899 this._paused = true; 3900 this._playing = false; 3901 this.pauseTime = this.currentTime(); 3902 this.bufferSourceNode.stop(pTime); 3903 3904 this._counterNode.stop(pTime); 3905 3906 this._pauseTime = this.currentTime(); 3907 } else { 3908 this._pauseTime = 0; 3909 } 3910 }; 3911 /** 3912 * Loop the p5.SoundFile. Accepts optional parameters to set the 3913 * playback rate, playback volume, loopStart, loopEnd. 3914 * 3915 * @method loop 3916 * @for p5.SoundFile 3917 * @param {Number} [startTime] (optional) schedule event to occur 3918 * seconds from now 3919 * @param {Number} [rate] (optional) playback rate 3920 * @param {Number} [amp] (optional) playback volume 3921 * @param {Number} [cueLoopStart] (optional) startTime in seconds 3922 * @param {Number} [duration] (optional) loop duration in seconds 3923 * @example 3924 * <div><code> 3925 * let soundFile; 3926 * let loopStart = 0.5; 3927 * let loopDuration = 0.2; 3928 * function preload() { 3929 * soundFormats('ogg', 'mp3'); 3930 * soundFile = loadSound('assets/Damscray_-_Dancing_Tiger_02.mp3'); 3931 * } 3932 * function setup() { 3933 * let cnv = createCanvas(100, 100); 3934 * cnv.mousePressed(canvasPressed); 3935 * background(220); 3936 * text('tap to play, release to pause', 10, 20, width - 20); 3937 * } 3938 * function canvasPressed() { 3939 * soundFile.loop(); 3940 * background(0, 200, 50); 3941 * } 3942 * function mouseReleased() { 3943 * soundFile.pause(); 3944 * background(220); 3945 * } 3946 * </code> 3947 * </div> 3948 */ 3949 3950 3951 p5.SoundFile.prototype.loop = function (startTime, rate, amp, loopStart, duration) { 3952 this._looping = true; 3953 this.play(startTime, rate, amp, loopStart, duration); 3954 }; 3955 /** 3956 * Set a p5.SoundFile's looping flag to true or false. If the sound 3957 * is currently playing, this change will take effect when it 3958 * reaches the end of the current playback. 3959 * 3960 * @method setLoop 3961 * @for p5.SoundFile 3962 * @param {Boolean} Boolean set looping to true or false 3963 */ 3964 3965 3966 p5.SoundFile.prototype.setLoop = function (bool) { 3967 if (bool === true) { 3968 this._looping = true; 3969 } else if (bool === false) { 3970 this._looping = false;
3971 } else { 3972 throw 'Error: setLoop accepts either true or false'; 3973 } 3974 3975 if (this.bufferSourceNode) { 3976 this.bufferSourceNode.loop = this._looping; 3977 this._counterNode.loop = this._looping; 3978 } 3979 }; 3980 /** 3981 * Returns 'true' if a p5.SoundFile is currently looping and playing, 'false' if not. 3982 * 3983 * @method isLooping 3984 * @for p5.SoundFile 3985 * @return {Boolean} 3986 */ 3987 3988 3989 p5.SoundFile.prototype.isLooping = function () { 3990 if (!this.bufferSourceNode) { 3991 return false; 3992 } 3993 3994 if (this._looping === true && this.isPlaying() === true) { 3995 return true; 3996 } 3997 3998 return false; 3999 }; 4000 /** 4001 * Returns true if a p5.SoundFile is playing, false if not (i.e. 4002 * paused or stopped). 4003 * 4004 * @method isPlaying 4005 * @for p5.SoundFile 4006 * @return {Boolean} 4007 */ 4008 4009 4010 p5.SoundFile.prototype.isPlaying = function () { 4011 return this._playing; 4012 }; 4013 /** 4014 * Returns true if a p5.SoundFile is paused, false if not (i.e. 4015 * playing or stopped). 4016 * 4017 * @method isPaused 4018 * @for p5.SoundFile 4019 * @return {Boolean} 4020 */ 4021 4022 4023 p5.SoundFile.prototype.isPaused = function () { 4024 return this._paused; 4025 }; 4026 /** 4027 * Stop soundfile playback. 4028 * 4029 * @method stop 4030 * @for p5.SoundFile 4031 * @param {Number} [startTime] (optional) schedule event to occur 4032 * in seconds from now 4033 */ 4034 4035 4036 p5.SoundFile.prototype.stop = function (timeFromNow) { 4037 var time = timeFromNow || 0; 4038 4039 if (this.mode === 'sustain' || this.mode === 'untildone') { 4040 this.stopAll(time); 4041 this._playing = false; 4042 this.pauseTime = 0; 4043 this._paused = false; 4044 } else if (this.buffer && this.bufferSourceNode) { 4045 var now = p5sound.audiocontext.currentTime; 4046 var t = time || 0; 4047 this.pauseTime = 0; 4048 this.bufferSourceNode.stop(now + t); 4049 4050 this._counterNode.stop(now + t); 4051 4052 this._playing = false; 4053 this._paused = false; 4054 } 4055 }; 4056 /** 4057 * Stop playback on all of this soundfile's sources. 4058 * @private 4059 */ 4060 4061 4062 p5.SoundFile.prototype.stopAll = function (_time) { 4063 var now = p5sound.audiocontext.currentTime; 4064 var time = _time || 0; 4065 4066 if (this.buffer && this.bufferSourceNode) { 4067 for (var i in this.bufferSourceNodes) { 4068 var bufferSourceNode = this.bufferSourceNodes[i]; 4069 4070 if (!!bufferSourceNode) { 4071 try { 4072 bufferSourceNode.stop(now + time); 4073 } catch (e) { 4074 } 4075 } 4076 } 4077 4078 this._counterNode.stop(now + time); 4079 4080 this._onended(this); 4081 } 4082 }; 4083 /** 4084 * Multiply the output volume (amplitude) of a sound file 4085 * between 0.0 (silence) and 1.0 (full volume). 4086 * 1.0 is the maximum amplitude of a digital sound, so multiplying 4087 * by greater than 1.0 may cause digital distortion. To 4088 * fade, provide a <code>rampTime</code> parameter. For more 4089 * complex fades, see the Envelope class. 4090 * 4091 * Alternately, you can pass in a signal source such as an 4092 * oscillator to modulate the amplitude with an audio signal. 4093 * 4094 * @method setVolume 4095 * @for p5.SoundFile 4096 * @param {Number|Object} volume Volume (amplitude) between 0.0 4097 * and 1.0 or modulating signal/oscillator 4098 * @param {Number} [rampTime] Fade for t seconds 4099 * @param {Number} [timeFromNow] Schedule this event to happen at 4100 * t seconds in the future 4101 */ 4102 4103 4104 p5.SoundFile.prototype.setVolume = function (vol, _rampTime, _tFromNow) { 4105 if (typeof vol === 'number') { 4106 var rampTime = _rampTime || 0; 4107 var tFromNow = _tFromNow || 0; 4108 var now = p5sound.audiocontext.currentTime; 4109 var currentVol = this.output.gain.value; 4110 this.output.gain.cancelScheduledValues(now + tFromNow); 4111 this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow); 4112 this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime); 4113 } else if (vol) { 4114 vol.connect(this.output.gain); 4115 } else { 4116 return this.output.gain; 4117 } 4118 }; 4119 4120 4121 p5.SoundFile.prototype.amp = p5.SoundFile.prototype.setVolume; 4122 4123 p5.SoundFile.prototype.fade = p5.SoundFile.prototype.setVolume; 4124 4125 p5.SoundFile.prototype.getVolume = function () { 4126 return this.output.gain.value; 4127 }; 4128 /** 4129 * Set the stereo panning of a p5.sound object to 4130 * a floating point number between -1.0 (left) and 1.0 (right). 4131 * Default is 0.0 (center). 4132 * 4133 * @method pan 4134 * @for p5.SoundFile 4135 * @param {Number} [panValue] Set the stereo panner 4136 * @param {Number} [timeFromNow] schedule this event to happen 4137 * seconds from now 4138 * @example 4139 * <div><code> 4140 * let ballX = 0; 4141 * let soundFile; 4142 * 4143 * function preload() { 4144 * soundFormats('ogg', 'mp3'); 4145 * soundFile = loadSound('assets/beatbox.mp3'); 4146 * } 4147 * 4148 * function draw() {
4149 * let cnv = createCanvas(100, 100); 4150 * cnv.mousePressed(canvasPressed); 4151 * background(220); 4152 * ballX = constrain(mouseX, 0, width); 4153 * ellipse(ballX, height/2, 20, 20); 4154 * } 4155 * 4156 * function canvasPressed(){ 4157 * // map the ball's x location to a panning degree 4158 * // between -1.0 (left) and 1.0 (right) 4159 * let panning = map(ballX, 0., width,-1.0, 1.0); 4160 * soundFile.pan(panning); 4161 * soundFile.play(); 4162 * } 4163 * </div></code> 4164 */ 4165 4166 4167 p5.SoundFile.prototype.pan = function (pval, tFromNow) { 4168 this.panPosition = pval; 4169 this.panner.pan(pval, tFromNow); 4170 }; 4171 /** 4172 * Returns the current stereo pan position (-1.0 to 1.0) 4173 * 4174 * @method getPan 4175 * @for p5.SoundFile 4176 * @return {Number} Returns the stereo pan setting of the Oscillator 4177 * as a number between -1.0 (left) and 1.0 (right). 4178 * 0.0 is center and default. 4179 */ 4180 4181 4182 p5.SoundFile.prototype.getPan = function () { 4183 return this.panPosition; 4184 }; 4185 /** 4186 * Set the playback rate of a sound file. Will change the speed and the pitch. 4187 * Values less than zero will reverse the audio buffer. 4188 * 4189 * @method rate 4190 * @for p5.SoundFile 4191 * @param {Number} [playbackRate] Set the playback rate. 1.0 is normal, 4192 * .5 is half-speed, 2.0 is twice as fast. 4193 * Values less than zero play backwards. 4194 * @example 4195 * <div><code> 4196 * let mySound; 4197 * 4198 * function preload() { 4199 * mySound = loadSound('assets/Damscray_DancingTiger.mp3'); 4200 * } 4201 * 4202 * function setup() { 4203 * let cnv = createCanvas(100, 100); 4204 * cnv.mousePressed(canvasPressed); 4205 * } 4206 * function canvasPressed() { 4207 * mySound.loop(); 4208 * } 4209 * function mouseReleased() { 4210 * mySound.pause(); 4211 * } 4212 * function draw() { 4213 * background(220); 4214 * 4215 * // Set the rate to a range between 0.1 and 4 4216 * // Changing the rate also alters the pitch 4217 * let playbackRate = map(mouseY, 0.1, height, 2, 0); 4218 * playbackRate = constrain(playbackRate, 0.01, 4); 4219 * mySound.rate(playbackRate); 4220 * 4221 * line(0, mouseY, width, mouseY); 4222 * text('rate: ' + round(playbackRate * 100) + '%', 10, 20); 4223 * } 4224 * 4225 * </code> 4226 * </div> 4227 * 4228 */ 4229 4230 4231 p5.SoundFile.prototype.rate = function (playbackRate) { 4232 var reverse = false; 4233 4234 if (typeof playbackRate === 'undefined') { 4235 return this.playbackRate; 4236 } 4237 4238 this.playbackRate = playbackRate; 4239 4240 if (playbackRate === 0) { 4241 playbackRate = 0.0000000000001; 4242 } else if (playbackRate < 0 && !this.reversed) { 4243 playbackRate = Math.abs(playbackRate); 4244 reverse = true; 4245 } else if (playbackRate > 0 && this.reversed) { 4246 reverse = true; 4247 } 4248 4249 if (this.bufferSourceNode) { 4250 var now = p5sound.audiocontext.currentTime; 4251 this.bufferSourceNode.playbackRate.cancelScheduledValues(now); 4252 this.bufferSourceNode.playbackRate.linearRampToValueAtTime(Math.abs(playbackRate), now); 4253 4254 this._counterNode.playbackRate.cancelScheduledValues(now); 4255 4256 this._counterNode.playbackRate.linearRampToValueAtTime(Math.abs(playbackRate), now); 4257 } 4258 4259 if (reverse) { 4260 this.reverseBuffer(); 4261 } 4262 4263 return this.playbackRate; 4264 }; 4265 4266 4267 p5.SoundFile.prototype.setPitch = function (num) { 4268 var newPlaybackRate = midiToFreq(num) / midiToFreq(60); 4269 this.rate(newPlaybackRate); 4270 }; 4271 4272 p5.SoundFile.prototype.getPlaybackRate = function () { 4273 return this.playbackRate; 4274 }; 4275 /** 4276 * Returns the duration of a sound file in seconds. 4277 * 4278 * @method duration 4279 * @for p5.SoundFile 4280 * @return {Number} The duration of the soundFile in seconds. 4281 */ 4282 4283 4284 p5.SoundFile.prototype.duration = function () { 4285 if (this.buffer) { 4286 return this.buffer.duration; 4287 } else { 4288 return 0; 4289 } 4290 }; 4291 /** 4292 * Return the current position of the p5.SoundFile playhead, in seconds. 4293 * Time is relative to the normal buffer direction, so if `reverseBuffer` 4294 * has been called, currentTime will count backwards. 4295 * 4296 * @method currentTime 4297 * @for p5.SoundFile 4298 * @return {Number} currentTime of the soundFile in seconds. 4299 */ 4300 4301 4302 p5.SoundFile.prototype.currentTime = function () { 4303 return this.reversed ? Math.abs(this._lastPos - this.buffer.length) / ac.sampleRate : this._lastPos / ac.sampleRate; 4304 }; 4305 /** 4306 * Move the playhead of a soundfile that is currently playing to a 4307 * new position and a new duration, in seconds. 4308 * If none are given, will reset the file to play entire duration 4309 * from start to finish. To set the position of a soundfile that is 4310 * not currently playing, use the `play` or `loop` methods. 4311 * 4312 * @method jump 4313 * @for p5.SoundFile 4314 * @param {Number} cueTime cueTime of the soundFile in seconds. 4315 * @param {Number} duration duration in seconds. 4316 */ 4317 4318 4319 p5.SoundFile.prototype.jump = function (cueTime, duration) { 4320 if (cueTime < 0 || cueTime > this.buffer.duration) { 4321 throw 'jump time out of range'; 4322 } 4323 4324 if (duration > this.buffer.duration - cueTime) { 4325 throw 'end time out of range'; 4326 } 4327 4328 var cTime = cueTime || 0; 4329 var dur = duration || undefined; 4330 4331 if (this.isPlaying()) { 4332 this.stop(0); 4333 this.play(0, this.playbackRate, this.output.gain.value, cTime, dur); 4334 } 4335 }; 4336 /** 4337 * Return the number of channels in a sound file. 4338 * For example, Mono = 1, Stereo = 2. 4339 * 4340 * @method channels 4341 * @for p5.SoundFile 4342 * @return {Number} [channels] 4343 */ 4344 4345 4346 p5.SoundFile.prototype.channels = function () { 4347 return this.buffer.numberOfChannels; 4348 }; 4349 /** 4350 * Return the sample rate of the sound file. 4351 * 4352 * @method sampleRate 4353 * @for p5.SoundFile 4354 * @return {Number} [sampleRate] 4355 */ 4356 4357 4358 p5.SoundFile.prototype.sampleRate = function () { 4359 return this.buffer.sampleRate; 4360 }; 4361 /** 4362 * Return the number of samples in a sound file.
4363 * Equal to sampleRate * duration. 4364 * 4365 * @method frames 4366 * @for p5.SoundFile 4367 * @return {Number} [sampleCount] 4368 */ 4369 4370 4371 p5.SoundFile.prototype.frames = function () { 4372 return this.buffer.length; 4373 }; 4374 /** 4375 * Returns an array of amplitude peaks in a p5.SoundFile that can be 4376 * used to draw a static waveform. Scans through the p5.SoundFile's 4377 * audio buffer to find the greatest amplitudes. Accepts one 4378 * parameter, 'length', which determines size of the array. 4379 * Larger arrays result in more precise waveform visualizations. 4380 * 4381 * Inspired by Wavesurfer.js. 4382 * 4383 * @method getPeaks 4384 * @for p5.SoundFile 4385 * @params {Number} [length] length is the size of the returned array. 4386 * Larger length results in more precision. 4387 * Defaults to 5*width of the browser window. 4388 * @returns {Float32Array} Array of peaks. 4389 */ 4390 4391 4392 p5.SoundFile.prototype.getPeaks = function (length) { 4393 if (this.buffer) { 4394 if (!length) { 4395 length = window.width * 5; 4396 } 4397 4398 if (this.buffer) { 4399 var buffer = this.buffer; 4400 var sampleSize = buffer.length / length; 4401 var sampleStep = ~~(sampleSize / 10) || 1; 4402 var channels = buffer.numberOfChannels; 4403 var peaks = new Float32Array(Math.round(length)); 4404 4405 for (var c = 0; c < channels; c++) { 4406 var chan = buffer.getChannelData(c); 4407 4408 for (var i = 0; i < length; i++) { 4409 var start = ~~(i * sampleSize); 4410 var end = ~~(start + sampleSize); 4411 var max = 0; 4412 4413 for (var j = start; j < end; j += sampleStep) { 4414 var value = chan[j]; 4415 4416 if (value > max) { 4417 max = value; 4418 } else if (-value > max) { 4419 max = value; 4420 } 4421 } 4422 4423 if (c === 0 || Math.abs(max) > peaks[i]) { 4424 peaks[i] = max; 4425 } 4426 } 4427 } 4428 4429 return peaks; 4430 } 4431 } else { 4432 throw 'Cannot load peaks yet, buffer is not loaded'; 4433 } 4434 }; 4435 /** 4436 * Reverses the p5.SoundFile's buffer source. 4437 * Playback must be handled separately (see example). 4438 * 4439 * @method reverseBuffer 4440 * @for p5.SoundFile 4441 * @example 4442 * <div><code> 4443 * let drum; 4444 * function preload() { 4445 * drum = loadSound('assets/drum.mp3'); 4446 * } 4447 * 4448 * function setup() { 4449 * let cnv = createCanvas(100, 100); 4450 * cnv.mousePressed(canvasPressed); 4451 * background(220); 4452 * text('tap to play', 20, 20); 4453 * } 4454 * 4455 * function canvasPressed() { 4456 * drum.stop(); 4457 * drum.reverseBuffer(); 4458 * drum.play(); 4459 * } 4460 * </code> 4461 * </div> 4462 */ 4463 4464 4465 p5.SoundFile.prototype.reverseBuffer = function () { 4466 if (this.buffer) { 4467 var currentPos = this._lastPos / ac.sampleRate; 4468 var curVol = this.getVolume(); 4469 this.setVolume(0, 0.001); 4470 var numChannels = this.buffer.numberOfChannels; 4471 4472 for (var i = 0; i < numChannels; i++) { 4473 this.buffer.getChannelData(i).reverse(); 4474 } 4475 4476 4477 this.reversed = !this.reversed; 4478 4479 if (this.isPlaying() && currentPos) { 4480 this.jump(this.duration() - currentPos); 4481 } 4482 4483 this.setVolume(curVol, 0.001); 4484 } else { 4485 throw 'SoundFile is not done loading'; 4486 } 4487 }; 4488 /** 4489 * Schedule an event to be called when the soundfile 4490 * reaches the end of a buffer. If the soundfile is 4491 * playing through once, this will be called when it 4492 * ends. If it is looping, it will be called when 4493 * stop is called. 4494 * 4495 * @method onended 4496 * @for p5.SoundFile 4497 * @param {Function} callback function to call when the 4498 * soundfile has ended. 4499 */ 4500 4501 4502 p5.SoundFile.prototype.onended = function (callback) { 4503 this._onended = callback; 4504 return this; 4505 }; 4506 4507 p5.SoundFile.prototype.add = function () { 4508 }; 4509 4510 p5.SoundFile.prototype.dispose = function () { 4511 var now = p5sound.audiocontext.currentTime; 4512 4513 var index = p5sound.soundArray.indexOf(this); 4514 p5sound.soundArray.splice(index, 1); 4515 this.stop(now); 4516 4517 if (this.buffer && this.bufferSourceNode) { 4518 for (var i = 0; i < this.bufferSourceNodes.length - 1; i++) { 4519 if (this.bufferSourceNodes[i] !== null) { 4520 this.bufferSourceNodes[i].disconnect(); 4521 4522 try { 4523 this.bufferSourceNodes[i].stop(now); 4524 } catch (e) { 4525 console.warn('no buffer source node to dispose'); 4526 } 4527 4528 this.bufferSourceNodes[i] = null; 4529 } 4530 } 4531 4532 if (this.isPlaying()) { 4533 try { 4534 this._counterNode.stop(now); 4535 } catch (e) { 4536 console.log(e); 4537 } 4538 4539 this._counterNode = null; 4540 } 4541 } 4542 4543 if (this.output) { 4544 this.output.disconnect(); 4545 this.output = null; 4546 } 4547 4548 if (this.panner) { 4549 this.panner.disconnect(); 4550 this.panner = null; 4551 } 4552 }; 4553 /** 4554 * Connects the output of a p5sound object to input of another 4555 * p5.sound object. For example, you may connect a p5.SoundFile to an 4556 * FFT or an Effect. If no parameter is given, it will connect to 4557 * the master output. Most p5sound objects connect to the master 4558 * output when they are created. 4559 * 4560 * @method connect 4561 * @for p5.SoundFile 4562 * @param {Object} [object] Audio object that accepts an input 4563 */ 4564 4565 4566 p5.SoundFile.prototype.connect = function (unit) { 4567 if (!unit) { 4568 this.panner.connect(p5sound.input); 4569 } else { 4570 if (unit.hasOwnProperty('input')) {
4571 this.panner.connect(unit.input); 4572 } else { 4573 this.panner.connect(unit); 4574 } 4575 } 4576 }; 4577 /** 4578 * Disconnects the output of this p5sound object. 4579 * 4580 * @method disconnect 4581 * @for p5.SoundFile 4582 */ 4583 4584 4585 p5.SoundFile.prototype.disconnect = function () { 4586 if (this.panner) { 4587 this.panner.disconnect(); 4588 } 4589 }; 4590 /** 4591 */ 4592 4593 4594 p5.SoundFile.prototype.getLevel = function () { 4595 console.warn('p5.SoundFile.getLevel has been removed from the library. Use p5.Amplitude instead'); 4596 }; 4597 /** 4598 * Reset the source for this SoundFile to a 4599 * new path (URL). 4600 * 4601 * @method setPath 4602 * @for p5.SoundFile 4603 * @param {String} path path to audio file 4604 * @param {Function} callback Callback 4605 */ 4606 4607 4608 p5.SoundFile.prototype.setPath = function (p, callback) { 4609 var path = p5.prototype._checkFileFormats(p); 4610 4611 this.url = path; 4612 this.load(callback); 4613 }; 4614 /** 4615 * Replace the current Audio Buffer with a new Buffer. 4616 * 4617 * @method setBuffer 4618 * @for p5.SoundFile 4619 * @param {Array} buf Array of Float32 Array(s). 2 Float32 Arrays 4620 * will create a stereo source. 1 will create 4621 * a mono source. 4622 */ 4623 4624 4625 p5.SoundFile.prototype.setBuffer = function (buf) { 4626 var numChannels = buf.length; 4627 var size = buf[0].length; 4628 var newBuffer = ac.createBuffer(numChannels, size, ac.sampleRate); 4629 4630 if (!(buf[0] instanceof Float32Array)) { 4631 buf[0] = new Float32Array(buf[0]); 4632 } 4633 4634 for (var channelNum = 0; channelNum < numChannels; channelNum++) { 4635 var channel = newBuffer.getChannelData(channelNum); 4636 channel.set(buf[channelNum]); 4637 } 4638 4639 this.buffer = newBuffer; 4640 4641 this.panner.inputChannels(numChannels); 4642 }; 4643 4644 4645 var _createCounterBuffer = function _createCounterBuffer(buffer) { 4646 var len = buffer.length; 4647 var audioBuf = ac.createBuffer(1, buffer.length, ac.sampleRate); 4648 var arrayBuffer = audioBuf.getChannelData(0); 4649 4650 for (var index = 0; index < len; index++) { 4651 arrayBuffer[index] = index; 4652 } 4653 4654 return audioBuf; 4655 }; 4656 4657 4658 p5.SoundFile.prototype._initCounterNode = function () { 4659 var _this = this; 4660 4661 var self = this; 4662 var now = ac.currentTime; 4663 var cNode = ac.createBufferSource(); 4664 var workletBufferSize = safeBufferSize(256); 4665 4666 if (self._workletNode) { 4667 self._workletNode.disconnect(); 4668 4669 delete self._workletNode; 4670 } 4671 4672 self._workletNode = new AudioWorkletNode(ac, processorNames.soundFileProcessor, { 4673 processorOptions: { 4674 bufferSize: workletBufferSize 4675 } 4676 }); 4677 4678 self._workletNode.port.onmessage = function (event) { 4679 if (event.data.name === 'position') { 4680 if (event.data.position === 0) { 4681 return; 4682 } 4683 4684 _this._lastPos = event.data.position; 4685 4686 _this._onTimeUpdate(self._lastPos); 4687 } 4688 }; 4689 4690 4691 cNode.buffer = _createCounterBuffer(self.buffer); 4692 cNode.playbackRate.setValueAtTime(self.playbackRate, now); 4693 cNode.connect(self._workletNode); 4694 4695 self._workletNode.connect(p5.soundOut._silentNode); 4696 4697 return cNode; 4698 }; 4699 4700 4701 p5.SoundFile.prototype._initSourceNode = function () { 4702 var bufferSourceNode = ac.createBufferSource(); 4703 bufferSourceNode.buffer = this.buffer; 4704 bufferSourceNode.playbackRate.value = this.playbackRate; 4705 bufferSourceNode.connect(this.output); 4706 return bufferSourceNode; 4707 }; 4708 /** 4709 * processPeaks returns an array of timestamps where it thinks there is a beat. 4710 * 4711 * This is an asynchronous function that processes the soundfile in an offline audio context, 4712 * and sends the results to your callback function. 4713 * 4714 * The process involves running the soundfile through a lowpass filter, and finding all of the 4715 * peaks above the initial threshold. If the total number of peaks are below the minimum number of peaks, 4716 * it decreases the threshold and re-runs the analysis until either minPeaks or minThreshold are reached. 4717 * 4718 * @method processPeaks 4719 * @for p5.SoundFile 4720 * @param {Function} callback a function to call once this data is returned 4721 * @param {Number} [initThreshold] initial threshold defaults to 0.9 4722 * @param {Number} [minThreshold] minimum threshold defaults to 0.22 4723 * @param {Number} [minPeaks] minimum number of peaks defaults to 200 4724 * @return {Array} Array of timestamped peaks 4725 */ 4726 4727 4728 p5.SoundFile.prototype.processPeaks = function (callback, _initThreshold, _minThreshold, _minPeaks) { 4729 var bufLen = this.buffer.length; 4730 var sampleRate = this.buffer.sampleRate; 4731 var buffer = this.buffer; 4732 var allPeaks = []; 4733 var initialThreshold = _initThreshold || 0.9, 4734 threshold = initialThreshold, 4735 minThreshold = _minThreshold || 0.22, 4736 minPeaks = _minPeaks || 200; 4737 4738 var offlineContext = new window.OfflineAudioContext(1, bufLen, sampleRate); 4739 4740 var source = offlineContext.createBufferSource(); 4741 source.buffer = buffer; 4742 4743 var filter = offlineContext.createBiquadFilter(); 4744 filter.type = 'lowpass'; 4745 source.connect(filter); 4746 filter.connect(offlineContext.destination); 4747 4748 source.start(0); 4749 offlineContext.startRendering(); 4750 4751 offlineContext.oncomplete = function (e) { 4752 if (!self.panner) return; 4753 var filteredBuffer = e.renderedBuffer; 4754 var bufferData = filteredBuffer.getChannelData(0); 4755 4756 do { 4757 allPeaks = getPeaksAtThreshold(bufferData, threshold); 4758 threshold -= 0.005; 4759 } while (Object.keys(allPeaks).length < minPeaks && threshold >= minThreshold); 4760 4761 4762 var intervalCounts = countIntervalsBetweenNearbyPeaks(allPeaks); 4763 4764 var groups = groupNeighborsByTempo(intervalCounts, filteredBuffer.sampleRate); 4765 4766 var topTempos = groups.sort(function (intA, intB) { 4767 return intB.count - intA.count; 4768 }).splice(0, 5); 4769 4770 this.tempo = topTempos[0].tempo; 4771 4772 var bpmVariance = 5; 4773 var tempoPeaks = getPeaksAtTopTempo(allPeaks, topTempos[0].tempo, filteredBuffer.sampleRate, bpmVariance); 4774 callback(tempoPeaks); 4775 }; 4776 }; 4777 4778 4779 var Peak = function Peak(amp, i) { 4780 this.sampleIndex = i; 4781 this.amplitude = amp; 4782 this.tempos = []; 4783 this.intervals = []; 4784 }; 4785 4786 4787 function getPeaksAtThreshold(data, threshold) { 4788 var peaksObj = {}; 4789 var length = data.length; 4790 4791 for (var i = 0; i < length; i++) { 4792 if (data[i] > threshold) { 4793 var amp = data[i]; 4794 var peak = new Peak(amp, i); 4795 peaksObj[i] = peak; 4796 4797 i += 6000; 4798 } 4799 4800 i++; 4801 } 4802 4803 return peaksObj; 4804 } 4805 4806 4807 function countIntervalsBetweenNearbyPeaks(peaksObj) { 4808 var intervalCounts = []; 4809 var peaksArray = Object.keys(peaksObj).sort(); 4810 4811 for (var index = 0; index < peaksArray.length; index++) { 4812 for (var i = 0; i < 10; i++) { 4813 var startPeak = peaksObj[peaksArray[index]]; 4814 var endPeak = peaksObj[peaksArray[index + i]]; 4815 4816 if (startPeak && endPeak) { 4817 var startPos = startPeak.sampleIndex; 4818 var endPos = endPeak.sampleIndex; 4819 var interval = endPos - startPos; 4820 4821 if (interval > 0) { 4822 startPeak.intervals.push(interval); 4823 } 4824 4825 4826 var foundInterval = intervalCounts.some(function (intervalCount) { 4827 if (intervalCount.interval === interval) { 4828 intervalCount.count++; 4829 return intervalCount; 4830 } 4831 }); 4832 4833 if (!foundInterval) { 4834 intervalCounts.push({ 4835 interval: interval, 4836 count: 1 4837 }); 4838 } 4839 } 4840 } 4841 } 4842 4843 return intervalCounts; 4844 } 4845 4846 4847 function groupNeighborsByTempo(intervalCounts, sampleRate) { 4848 var tempoCounts = [];
4849 intervalCounts.forEach(function (intervalCount) { 4850 try { 4851 var theoreticalTempo = Math.abs(60 / (intervalCount.interval / sampleRate)); 4852 theoreticalTempo = mapTempo(theoreticalTempo); 4853 var foundTempo = tempoCounts.some(function (tempoCount) { 4854 if (tempoCount.tempo === theoreticalTempo) return tempoCount.count += intervalCount.count; 4855 }); 4856 4857 if (!foundTempo) { 4858 if (isNaN(theoreticalTempo)) { 4859 return; 4860 } 4861 4862 tempoCounts.push({ 4863 tempo: Math.round(theoreticalTempo), 4864 count: intervalCount.count 4865 }); 4866 } 4867 } catch (e) { 4868 throw e; 4869 } 4870 }); 4871 return tempoCounts; 4872 } 4873 4874 4875 function getPeaksAtTopTempo(peaksObj, tempo, sampleRate, bpmVariance) { 4876 var peaksAtTopTempo = []; 4877 var peaksArray = Object.keys(peaksObj).sort(); 4878 4879 for (var i = 0; i < peaksArray.length; i++) { 4880 var key = peaksArray[i]; 4881 var peak = peaksObj[key]; 4882 4883 for (var j = 0; j < peak.intervals.length; j++) { 4884 var intervalBPM = Math.round(Math.abs(60 / (peak.intervals[j] / sampleRate))); 4885 intervalBPM = mapTempo(intervalBPM); 4886 4887 if (Math.abs(intervalBPM - tempo) < bpmVariance) { 4888 peaksAtTopTempo.push(peak.sampleIndex / sampleRate); 4889 } 4890 } 4891 } 4892 4893 4894 peaksAtTopTempo = peaksAtTopTempo.filter(function (peakTime, index, arr) { 4895 var dif = arr[index + 1] - peakTime; 4896 4897 if (dif > 0.01) { 4898 return true; 4899 } 4900 }); 4901 return peaksAtTopTempo; 4902 } 4903 4904 4905 function mapTempo(theoreticalTempo) { 4906 if (!isFinite(theoreticalTempo) || theoreticalTempo === 0) { 4907 return; 4908 } 4909 4910 4911 while (theoreticalTempo < 90) { 4912 theoreticalTempo *= 2; 4913 } 4914 4915 while (theoreticalTempo > 180 && theoreticalTempo > 90) { 4916 theoreticalTempo /= 2; 4917 } 4918 4919 return theoreticalTempo; 4920 } 4921 4922 4923 var Cue = function Cue(callback, time, id, val) { 4924 this.callback = callback; 4925 this.time = time; 4926 this.id = id; 4927 this.val = val; 4928 }; 4929 /** 4930 * Schedule events to trigger every time a MediaElement 4931 * (audio/video) reaches a playback cue point. 4932 * 4933 * Accepts a callback function, a time (in seconds) at which to trigger 4934 * the callback, and an optional parameter for the callback. 4935 * 4936 * Time will be passed as the first parameter to the callback function, 4937 * and param will be the second parameter. 4938 * 4939 * 4940 * @method addCue 4941 * @for p5.SoundFile 4942 * @param {Number} time Time in seconds, relative to this media 4943 * element's playback. For example, to trigger 4944 * an event every time playback reaches two 4945 * seconds, pass in the number 2. This will be 4946 * passed as the first parameter to 4947 * the callback function. 4948 * @param {Function} callback Name of a function that will be 4949 * called at the given time. The callback will 4950 * receive time and (optionally) param as its 4951 * two parameters. 4952 * @param {Object} [value] An object to be passed as the 4953 * second parameter to the 4954 * callback function. 4955 * @return {Number} id ID of this cue, 4956 * useful for removeCue(id) 4957 * @example 4958 * <div><code> 4959 * let mySound; 4960 * function preload() { 4961 * mySound = loadSound('assets/Damscray_DancingTiger.mp3'); 4962 * } 4963 * 4964 * function setup() { 4965 * let cnv = createCanvas(100, 100); 4966 * cnv.mousePressed(canvasPressed); 4967 * background(220); 4968 * text('tap to play', 10, 20); 4969 * 4970 * // schedule calls to changeText 4971 * mySound.addCue(0, changeText, "hello" ); 4972 * mySound.addCue(0.5, changeText, "hello," ); 4973 * mySound.addCue(1, changeText, "hello, p5!"); 4974 * mySound.addCue(1.5, changeText, "hello, p5!!"); 4975 * mySound.addCue(2, changeText, "hello, p5!!!!!"); 4976 * } 4977 * 4978 * function changeText(val) { 4979 * background(220); 4980 * text(val, 10, 20); 4981 * } 4982 * 4983 * function canvasPressed() { 4984 * mySound.play(); 4985 * } 4986 * </code></div> 4987 */ 4988 4989 4990 p5.SoundFile.prototype.addCue = function (time, callback, val) { 4991 var id = this._cueIDCounter++; 4992 var cue = new Cue(callback, time, id, val); 4993 4994 this._cues.push(cue); 4995 4996 4997 return id; 4998 }; 4999 /** 5000 * Remove a callback based on its ID. The ID is returned by the 5001 * addCue method. 5002 * 5003 * @method removeCue 5004 * @for p5.SoundFile 5005 * @param {Number} id ID of the cue, as returned by addCue 5006 */ 5007 5008 5009 p5.SoundFile.prototype.removeCue = function (id) { 5010 var cueLength = this._cues.length; 5011 5012 for (var i = 0; i < cueLength; i++) { 5013 var cue = this._cues[i]; 5014 5015 if (cue.id === id) { 5016 this._cues.splice(i, 1); 5017 5018 break; 5019 } 5020 } 5021 5022 if (this._cues.length === 0) { 5023 } 5024 }; 5025 /** 5026 * Remove all of the callbacks that had originally been scheduled 5027 * via the addCue method. 5028 * 5029 * @method clearCues 5030 */ 5031 5032 5033 p5.SoundFile.prototype.clearCues = function () { 5034 this._cues = []; 5035 }; 5036 5037
5038 p5.SoundFile.prototype._onTimeUpdate = function (position) { 5039 var playbackTime = position / this.buffer.sampleRate; 5040 var cueLength = this._cues.length; 5041 5042 for (var i = 0; i < cueLength; i++) { 5043 var cue = this._cues[i]; 5044 var callbackTime = cue.time; 5045 var val = cue.val; 5046 5047 if (~~this._prevUpdateTime <= callbackTime && callbackTime <= playbackTime) { 5048 cue.callback(val); 5049 } 5050 } 5051 5052 this._prevUpdateTime = playbackTime; 5053 }; 5054 /** 5055 * Save a p5.SoundFile as a .wav file. The browser will prompt the user 5056 * to download the file to their device. To upload a file to a server, see 5057 * <a href="/docs/reference/#/p5.SoundFile/getBlob">getBlob</a> 5058 * 5059 * @method save 5060 * @for p5.SoundFile 5061 * @param {String} [fileName] name of the resulting .wav file. 5062 * @example 5063 * <div><code> 5064 * let mySound; 5065 * function preload() { 5066 * mySound = loadSound('assets/doorbell.mp3'); 5067 * } 5068 * function setup() { 5069 * let cnv = createCanvas(100, 100); 5070 * cnv.mousePressed(canvasPressed); 5071 * background(220); 5072 * text('tap to download', 10, 20); 5073 * } 5074 * 5075 * function canvasPressed() { 5076 * mySound.save('my cool filename'); 5077 * } 5078 * </code></div> 5079 */ 5080 5081 5082 p5.SoundFile.prototype.save = function (fileName) { 5083 p5.prototype.saveSound(this, fileName, 'wav'); 5084 }; 5085 /** 5086 * This method is useful for sending a SoundFile to a server. It returns the 5087 * .wav-encoded audio data as a "<a target="_blank" title="Blob reference at 5088 * MDN" href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>". 5089 * A Blob is a file-like data object that can be uploaded to a server 5090 * with an <a href="/docs/reference/#/p5/httpDo">http</a> request. We'll 5091 * use the `httpDo` options object to send a POST request with some 5092 * specific options: we encode the request as `multipart/form-data`, 5093 * and attach the blob as one of the form values using `FormData`. 5094 * 5095 * 5096 * @method getBlob 5097 * @for p5.SoundFile 5098 * @returns {Blob} A file-like data object 5099 * @example 5100 * <div><code> 5101 * function preload() { 5102 * mySound = loadSound('assets/doorbell.mp3'); 5103 * } 5104 * 5105 * function setup() { 5106 * noCanvas(); 5107 * let soundBlob = mySound.getBlob(); 5108 * 5109 * // Now we can send the blob to a server... 5110 * let serverUrl = 'https://jsonplaceholder.typicode.com/posts'; 5111 * let httpRequestOptions = { 5112 * method: 'POST', 5113 * body: new FormData().append('soundBlob', soundBlob), 5114 * headers: new Headers({ 5115 * 'Content-Type': 'multipart/form-data' 5116 * }) 5117 * }; 5118 * httpDo(serverUrl, httpRequestOptions); 5119 * 5120 * // We can also create an `ObjectURL` pointing to the Blob 5121 * let blobUrl = URL.createObjectURL(soundBlob); 5122 * 5123 * // The `<Audio>` Element accepts Object URL's 5124 * createAudio(blobUrl).showControls(); 5125 * 5126 * createDiv(); 5127 * 5128 * // The ObjectURL exists as long as this tab is open 5129 * let input = createInput(blobUrl); 5130 * input.attribute('readonly', true); 5131 * input.mouseClicked(function() { input.elt.select() }); 5132 * } 5133 * 5134 * </code></div> 5135 */ 5136 5137 5138 p5.SoundFile.prototype.getBlob = function () { 5139 var dataView = convertToWav(this.buffer); 5140 return new Blob([dataView], { 5141 type: 'audio/wav' 5142 }); 5143 }; 5144 5145 5146 function _clearOnEnd(e) { 5147 var thisBufferSourceNode = e.target; 5148 var soundFile = this; 5149 5150 thisBufferSourceNode._playing = false; 5151 thisBufferSourceNode.removeEventListener('ended', soundFile._clearOnEnd); 5152 5153 soundFile._onended(soundFile); 5154 5155 5156 soundFile.bufferSourceNodes.map(function (_, i) { 5157 return i; 5158 }).reverse().forEach(function (i) { 5159 var n = soundFile.bufferSourceNodes[i]; 5160 5161 if (n._playing === false) { 5162 soundFile.bufferSourceNodes.splice(i, 1); 5163 } 5164 }); 5165 5166 if (soundFile.bufferSourceNodes.length === 0) { 5167 soundFile._playing = false; 5168 } 5169 } 5170}).call(exports, __webpack_require__, exports, module), 5171 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 5172 5173 }), 5174 (function(module, exports, __webpack_require__) { 5175 5176"use strict"; 5177var __WEBPACK_AMD_DEFINE_RESULT__; 5178 5179!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 5180 var p5sound = __webpack_require__(1); 5181 5182 var _require = __webpack_require__(6), 5183 safeBufferSize = _require.safeBufferSize; 5184 5185 var processorNames = __webpack_require__(10); 5186 /** 5187 * Amplitude measures volume between 0.0 and 1.0. 5188 * Listens to all p5sound by default, or use setInput() 5189 * to listen to a specific sound source. Accepts an optional 5190 * smoothing value, which defaults to 0. 5191 * 5192 * @class p5.Amplitude 5193 * @constructor 5194 * @param {Number} [smoothing] between 0.0 and .999 to smooth 5195 * amplitude readings (defaults to 0) 5196 * @example 5197 * <div><code> 5198 * let sound, amplitude; 5199 * 5200 * function preload(){ 5201 * sound = loadSound('assets/beat.mp3'); 5202 * } 5203 * function setup() {
5204 * let cnv = createCanvas(100,100); 5205 * cnv.mouseClicked(toggleSound); 5206 * amplitude = new p5.Amplitude(); 5207 * } 5208 * 5209 * function draw() { 5210 * background(220); 5211 * text('tap to play', 20, 20); 5212 * 5213 * let level = amplitude.getLevel(); 5214 * let size = map(level, 0, 1, 0, 200); 5215 * ellipse(width/2, height/2, size, size); 5216 * } 5217 * 5218 * function toggleSound() { 5219 * if (sound.isPlaying() ){ 5220 * sound.stop(); 5221 * } else { 5222 * sound.play(); 5223 * } 5224 * } 5225 * 5226 * </code></div> 5227 */ 5228 5229 5230 p5.Amplitude = function (smoothing) { 5231 this.bufferSize = safeBufferSize(2048); 5232 5233 this.audiocontext = p5sound.audiocontext; 5234 this._workletNode = new AudioWorkletNode(this.audiocontext, processorNames.amplitudeProcessor, { 5235 outputChannelCount: [1], 5236 parameterData: { 5237 smoothing: smoothing || 0 5238 }, 5239 processorOptions: { 5240 normalize: false, 5241 smoothing: smoothing || 0, 5242 numInputChannels: 2, 5243 bufferSize: this.bufferSize 5244 } 5245 }); 5246 5247 this._workletNode.port.onmessage = function (event) { 5248 if (event.data.name === 'amplitude') { 5249 this.volume = event.data.volume; 5250 this.volNorm = event.data.volNorm; 5251 this.stereoVol = event.data.stereoVol; 5252 this.stereoVolNorm = event.data.stereoVolNorm; 5253 } 5254 }.bind(this); 5255 5256 5257 this.input = this._workletNode; 5258 this.output = this.audiocontext.createGain(); 5259 5260 this.volume = 0; 5261 this.volNorm = 0; 5262 this.stereoVol = [0, 0]; 5263 this.stereoVolNorm = [0, 0]; 5264 this.normalize = false; 5265 5266 this._workletNode.connect(this.output); 5267 5268 this.output.gain.value = 0; 5269 5270 this.output.connect(this.audiocontext.destination); 5271 5272 p5sound.meter.connect(this._workletNode); 5273 5274 p5sound.soundArray.push(this); 5275 }; 5276 /** 5277 * Connects to the p5sound instance (master output) by default. 5278 * Optionally, you can pass in a specific source (i.e. a soundfile). 5279 * 5280 * @method setInput 5281 * @for p5.Amplitude 5282 * @param {soundObject|undefined} [snd] set the sound source 5283 * (optional, defaults to 5284 * master output) 5285 * @param {Number|undefined} [smoothing] a range between 0.0 and 1.0 5286 * to smooth amplitude readings 5287 * @example 5288 * <div><code> 5289 * function preload(){ 5290 * sound1 = loadSound('assets/beat.mp3'); 5291 * sound2 = loadSound('assets/drum.mp3'); 5292 * } 5293 * function setup(){ 5294 * cnv = createCanvas(100, 100); 5295 * cnv.mouseClicked(toggleSound); 5296 * 5297 * amplitude = new p5.Amplitude(); 5298 * amplitude.setInput(sound2); 5299 * } 5300 * 5301 * function draw() { 5302 * background(220); 5303 * text('tap to play', 20, 20); 5304 * 5305 * let level = amplitude.getLevel(); 5306 * let size = map(level, 0, 1, 0, 200); 5307 * ellipse(width/2, height/2, size, size); 5308 * } 5309 * 5310 * function toggleSound(){ 5311 * if (sound1.isPlaying() && sound2.isPlaying()) { 5312 * sound1.stop(); 5313 * sound2.stop(); 5314 * } else { 5315 * sound1.play(); 5316 * sound2.play(); 5317 * } 5318 * } 5319 * </code></div> 5320 */ 5321 5322 5323 p5.Amplitude.prototype.setInput = function (source, smoothing) { 5324 p5sound.meter.disconnect(); 5325 5326 if (smoothing) { 5327 this._workletNode.parameters.get('smoothing').value = smoothing; 5328 } 5329 5330 5331 if (source == null) { 5332 console.log('Amplitude input source is not ready! Connecting to master output instead'); 5333 p5sound.meter.connect(this._workletNode); 5334 } 5335 else if (source instanceof p5.Signal) { 5336 source.output.connect(this._workletNode); 5337 } 5338 else if (source) { 5339 source.connect(this._workletNode); 5340 5341 this._workletNode.disconnect(); 5342 5343 this._workletNode.connect(this.output); 5344 } 5345 else { 5346 p5sound.meter.connect(this._workletNode); 5347 } 5348 }; 5349 5350 p5.Amplitude.prototype.connect = function (unit) { 5351 if (unit) { 5352 if (unit.hasOwnProperty('input')) { 5353 this.output.connect(unit.input); 5354 } else { 5355 this.output.connect(unit); 5356 } 5357 } else { 5358 this.output.connect(this.panner.connect(p5sound.input)); 5359 } 5360 }; 5361 5362 p5.Amplitude.prototype.disconnect = function () { 5363 if (this.output) { 5364 this.output.disconnect(); 5365 } 5366 }; 5367 /** 5368 * Returns a single Amplitude reading at the moment it is called. 5369 * For continuous readings, run in the draw loop. 5370 * 5371 * @method getLevel 5372 * @for p5.Amplitude 5373 * @param {Number} [channel] Optionally return only channel 0 (left) or 1 (right) 5374 * @return {Number} Amplitude as a number between 0.0 and 1.0 5375 * @example 5376 * <div><code> 5377 * function preload(){ 5378 * sound = loadSound('assets/beat.mp3'); 5379 * } 5380 * 5381 * function setup() {
5382 * let cnv = createCanvas(100, 100); 5383 * cnv.mouseClicked(toggleSound); 5384 * amplitude = new p5.Amplitude(); 5385 * } 5386 * 5387 * function draw() { 5388 * background(220, 150); 5389 * textAlign(CENTER); 5390 * text('tap to play', width/2, 20); 5391 * 5392 * let level = amplitude.getLevel(); 5393 * let size = map(level, 0, 1, 0, 200); 5394 * ellipse(width/2, height/2, size, size); 5395 * } 5396 * 5397 * function toggleSound(){ 5398 * if (sound.isPlaying()) { 5399 * sound.stop(); 5400 * } else { 5401 * sound.play(); 5402 * } 5403 * } 5404 * </code></div> 5405 */ 5406 5407 5408 p5.Amplitude.prototype.getLevel = function (channel) { 5409 if (typeof channel !== 'undefined') { 5410 if (this.normalize) { 5411 return this.stereoVolNorm[channel]; 5412 } else { 5413 return this.stereoVol[channel]; 5414 } 5415 } else if (this.normalize) { 5416 return this.volNorm; 5417 } else { 5418 return this.volume; 5419 } 5420 }; 5421 /** 5422 * Determines whether the results of Amplitude.process() will be 5423 * Normalized. To normalize, Amplitude finds the difference the 5424 * loudest reading it has processed and the maximum amplitude of 5425 * 1.0. Amplitude adds this difference to all values to produce 5426 * results that will reliably map between 0.0 and 1.0. However, 5427 * if a louder moment occurs, the amount that Normalize adds to 5428 * all the values will change. Accepts an optional boolean parameter 5429 * (true or false). Normalizing is off by default. 5430 * 5431 * @method toggleNormalize 5432 * @for p5.Amplitude 5433 * @param {boolean} [boolean] set normalize to true (1) or false (0) 5434 */ 5435 5436 5437 p5.Amplitude.prototype.toggleNormalize = function (bool) { 5438 if (typeof bool === 'boolean') { 5439 this.normalize = bool; 5440 } else { 5441 this.normalize = !this.normalize; 5442 } 5443 5444 this._workletNode.port.postMessage({ 5445 name: 'toggleNormalize', 5446 normalize: this.normalize 5447 }); 5448 }; 5449 /** 5450 * Smooth Amplitude analysis by averaging with the last analysis 5451 * frame. Off by default. 5452 * 5453 * @method smooth 5454 * @for p5.Amplitude 5455 * @param {Number} set smoothing from 0.0 <= 1 5456 */ 5457 5458 5459 p5.Amplitude.prototype.smooth = function (s) { 5460 if (s >= 0 && s < 1) { 5461 this._workletNode.port.postMessage({ 5462 name: 'smoothing', 5463 smoothing: s 5464 }); 5465 } else { 5466 console.log('Error: smoothing must be between 0 and 1'); 5467 } 5468 }; 5469 5470 p5.Amplitude.prototype.dispose = function () { 5471 var index = p5sound.soundArray.indexOf(this); 5472 p5sound.soundArray.splice(index, 1); 5473 5474 if (this.input) { 5475 this.input.disconnect(); 5476 delete this.input; 5477 } 5478 5479 if (this.output) { 5480 this.output.disconnect(); 5481 delete this.output; 5482 } 5483 5484 this._workletNode.disconnect(); 5485 5486 delete this._workletNode; 5487 }; 5488}).call(exports, __webpack_require__, exports, module), 5489 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 5490 5491 }), 5492 (function(module, exports, __webpack_require__) { 5493 5494"use strict"; 5495var __WEBPACK_AMD_DEFINE_RESULT__; 5496 5497!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 5498 var p5sound = __webpack_require__(1); 5499 /** 5500 * <p>FFT (Fast Fourier Transform) is an analysis algorithm that 5501 * isolates individual 5502 * <a href="https://en.wikipedia.org/wiki/Audio_frequency"> 5503 * audio frequencies</a> within a waveform.</p> 5504 * 5505 * <p>Once instantiated, a p5.FFT object can return an array based on 5506 * two types of analyses: <br> • <code>FFT.waveform()</code> computes 5507 * amplitude values along the time domain. The array indices correspond 5508 * to samples across a brief moment in time. Each value represents 5509 * amplitude of the waveform at that sample of time.<br> 5510 * • <code>FFT.analyze() </code> computes amplitude values along the 5511 * frequency domain. The array indices correspond to frequencies (i.e. 5512 * pitches), from the lowest to the highest that humans can hear. Each 5513 * value represents amplitude at that slice of the frequency spectrum. 5514 * Use with <code>getEnergy()</code> to measure amplitude at specific 5515 * frequencies, or within a range of frequencies. </p> 5516 * 5517 * <p>FFT analyzes a very short snapshot of sound called a sample 5518 * buffer. It returns an array of amplitude measurements, referred 5519 * to as <code>bins</code>. The array is 1024 bins long by default. 5520 * You can change the bin array length, but it must be a power of 2 5521 * between 16 and 1024 in order for the FFT algorithm to function 5522 * correctly. The actual size of the FFT buffer is twice the 5523 * number of bins, so given a standard sample rate, the buffer is 5524 * 2048/44100 seconds long.</p> 5525 * 5526 * 5527 * @class p5.FFT 5528 * @constructor 5529 * @param {Number} [smoothing] Smooth results of Freq Spectrum. 5530 * 0.0 < smoothing < 1.0. 5531 * Defaults to 0.8. 5532 * @param {Number} [bins] Length of resulting array. 5533 * Must be a power of two between 5534 * 16 and 1024. Defaults to 1024. 5535 * @example 5536 * <div><code> 5537 * function preload(){ 5538 * sound = loadSound('assets/Damscray_DancingTiger.mp3'); 5539 * } 5540 * 5541 * function setup(){
5542 * let cnv = createCanvas(100,100); 5543 * cnv.mouseClicked(togglePlay); 5544 * fft = new p5.FFT(); 5545 * sound.amp(0.2); 5546 * } 5547 * 5548 * function draw(){ 5549 * background(220); 5550 * 5551 * let spectrum = fft.analyze(); 5552 * noStroke(); 5553 * fill(255, 0, 255); 5554 * for (let i = 0; i< spectrum.length; i++){ 5555 * let x = map(i, 0, spectrum.length, 0, width); 5556 * let h = -height + map(spectrum[i], 0, 255, height, 0); 5557 * rect(x, height, width / spectrum.length, h ) 5558 * } 5559 * 5560 * let waveform = fft.waveform(); 5561 * noFill(); 5562 * beginShape(); 5563 * stroke(20); 5564 * for (let i = 0; i < waveform.length; i++){ 5565 * let x = map(i, 0, waveform.length, 0, width); 5566 * let y = map( waveform[i], -1, 1, 0, height); 5567 * vertex(x,y); 5568 * } 5569 * endShape(); 5570 * 5571 * text('tap to play', 20, 20); 5572 * } 5573 * 5574 * function togglePlay() { 5575 * if (sound.isPlaying()) { 5576 * sound.pause(); 5577 * } else { 5578 * sound.loop(); 5579 * } 5580 * } 5581 * </code></div> 5582 */ 5583 5584 5585 p5.FFT = function (smoothing, bins) { 5586 this.input = this.analyser = p5sound.audiocontext.createAnalyser();
5587 Object.defineProperties(this, { 5588 bins: { 5589 get: function get() { 5590 return this.analyser.fftSize / 2; 5591 }, 5592 set: function set(b) { 5593 this.analyser.fftSize = b * 2; 5594 }, 5595 configurable: true, 5596 enumerable: true 5597 }, 5598 smoothing: { 5599 get: function get() { 5600 return this.analyser.smoothingTimeConstant; 5601 }, 5602 set: function set(s) { 5603 this.analyser.smoothingTimeConstant = s; 5604 }, 5605 configurable: true, 5606 enumerable: true 5607 } 5608 }); 5609 5610 this.smooth(smoothing); 5611 this.bins = bins || 1024; 5612 5613 p5sound.fftMeter.connect(this.analyser); 5614 this.freqDomain = new Uint8Array(this.analyser.frequencyBinCount); 5615 this.timeDomain = new Uint8Array(this.analyser.frequencyBinCount); 5616 5617 this.bass = [20, 140]; 5618 this.lowMid = [140, 400]; 5619 this.mid = [400, 2600]; 5620 this.highMid = [2600, 5200]; 5621 this.treble = [5200, 14000]; 5622 5623 p5sound.soundArray.push(this); 5624 }; 5625 /** 5626 * Set the input source for the FFT analysis. If no source is 5627 * provided, FFT will analyze all sound in the sketch. 5628 * 5629 * @method setInput 5630 * @for p5.FFT 5631 * @param {Object} [source] p5.sound object (or web audio API source node) 5632 */ 5633 5634 5635 p5.FFT.prototype.setInput = function (source) { 5636 if (!source) { 5637 p5sound.fftMeter.connect(this.analyser); 5638 } else { 5639 if (source.output) { 5640 source.output.connect(this.analyser); 5641 } else if (source.connect) { 5642 source.connect(this.analyser); 5643 } 5644 5645 p5sound.fftMeter.disconnect(); 5646 } 5647 }; 5648 /** 5649 * Returns an array of amplitude values (between -1.0 and +1.0) that represent 5650 * a snapshot of amplitude readings in a single buffer. Length will be 5651 * equal to bins (defaults to 1024). Can be used to draw the waveform 5652 * of a sound. 5653 * 5654 * @method waveform 5655 * @for p5.FFT 5656 * @param {Number} [bins] Must be a power of two between 5657 * 16 and 1024. Defaults to 1024. 5658 * @param {String} [precision] If any value is provided, will return results 5659 * in a Float32 Array which is more precise 5660 * than a regular array. 5661 * @return {Array} Array Array of amplitude values (-1 to 1) 5662 * over time. Array length = bins. 5663 * 5664 */ 5665 5666 5667 p5.FFT.prototype.waveform = function () { 5668 var bins, mode, normalArray; 5669 5670 for (var i = 0; i < arguments.length; i++) { 5671 if (typeof arguments[i] === 'number') { 5672 bins = arguments[i]; 5673 this.analyser.fftSize = bins * 2; 5674 } 5675 5676 if (typeof arguments[i] === 'string') { 5677 mode = arguments[i]; 5678 } 5679 } 5680 5681 5682 if (mode && !p5.prototype._isSafari()) { 5683 timeToFloat(this, this.timeDomain); 5684 this.analyser.getFloatTimeDomainData(this.timeDomain); 5685 return this.timeDomain; 5686 } else { 5687 timeToInt(this, this.timeDomain); 5688 this.analyser.getByteTimeDomainData(this.timeDomain); 5689 var normalArray = new Array(); 5690 5691 for (var j = 0; j < this.timeDomain.length; j++) { 5692 var scaled = p5.prototype.map(this.timeDomain[j], 0, 255, -1, 1); 5693 normalArray.push(scaled); 5694 } 5695 5696 return normalArray; 5697 } 5698 }; 5699 /** 5700 * Returns an array of amplitude values (between 0 and 255) 5701 * across the frequency spectrum. Length is equal to FFT bins 5702 * (1024 by default). The array indices correspond to frequencies 5703 * (i.e. pitches), from the lowest to the highest that humans can 5704 * hear. Each value represents amplitude at that slice of the 5705 * frequency spectrum. Must be called prior to using 5706 * <code>getEnergy()</code>. 5707 * 5708 * @method analyze 5709 * @for p5.FFT 5710 * @param {Number} [bins] Must be a power of two between 5711 * 16 and 1024. Defaults to 1024. 5712 * @param {Number} [scale] If "dB," returns decibel 5713 * float measurements between 5714 * -140 and 0 (max). 5715 * Otherwise returns integers from 0-255. 5716 * @return {Array} spectrum Array of energy (amplitude/volume) 5717 * values across the frequency spectrum. 5718 * Lowest energy (silence) = 0, highe
5718st 5719 * possible is 255. 5720 * @example 5721 * <div><code> 5722 * let osc, fft; 5723 * 5724 * function setup(){ 5725 * let cnv = createCanvas(100,100); 5726 * cnv.mousePressed(startSound); 5727 * osc = new p5.Oscillator(); 5728 * osc.amp(0); 5729 * fft = new p5.FFT(); 5730 * } 5731 * 5732 * function draw(){ 5733 * background(220); 5734 * 5735 * let freq = map(mouseX, 0, windowWidth, 20, 10000); 5736 * freq = constrain(freq, 1, 20000); 5737 * osc.freq(freq); 5738 * 5739 * let spectrum = fft.analyze(); 5740 * noStroke(); 5741 * fill(255, 0, 255); 5742 * for (let i = 0; i< spectrum.length; i++){ 5743 * let x = map(i, 0, spectrum.length, 0, width); 5744 * let h = -height + map(spectrum[i], 0, 255, height, 0); 5745 * rect(x, height, width / spectrum.length, h ); 5746 * } 5747 * 5748 * stroke(255); 5749 * if (!osc.started) { 5750 * text('tap here and drag to change frequency', 10, 20, width - 20); 5751 * } else { 5752 * text(round(freq)+'Hz', 10, 20); 5753 * } 5754 * } 5755 * 5756 * function startSound() { 5757 * osc.start(); 5758 * osc.amp(0.5, 0.2); 5759 * } 5760 * 5761 * function mouseReleased() { 5762 * osc.amp(0, 0.2); 5763 * } 5764 * </code></div> 5765 * 5766 * 5767 */ 5768 5769 5770 p5.FFT.prototype.analyze = function () { 5771 var mode; 5772 5773 for (var i = 0; i < arguments.length; i++) { 5774 if (typeof arguments[i] === 'number') { 5775 this.bins = arguments[i]; 5776 this.analyser.fftSize = this.bins * 2; 5777 } 5778 5779 if (typeof arguments[i] === 'string') { 5780 mode = arguments[i]; 5781 } 5782 } 5783 5784 if (mode && mode.toLowerCase() === 'db') { 5785 freqToFloat(this); 5786 this.analyser.getFloatFrequencyData(this.freqDomain); 5787 return this.freqDomain; 5788 } else { 5789 freqToInt(this, this.freqDomain); 5790 this.analyser.getByteFrequencyData(this.freqDomain); 5791 var normalArray = Array.apply([], this.freqDomain); 5792 return normalArray; 5793 } 5794 }; 5795 /** 5796 * Returns the amount of energy (volume) at a specific 5797 * <a href="https://en.wikipedia.org/wiki/Audio_frequency" target="_blank"> 5798 * frequency</a>, or the average amount of energy between two 5799 * frequencies. Accepts Number(s) corresponding 5800 * to frequency (in Hz), or a String corresponding to predefined 5801 * frequency ranges ("bass", "lowMid", "mid", "highMid", "treble"). 5802 * Returns a range between 0 (no energy/volume at that frequency) and 5803 * 255 (maximum energy). 5804 * <em>NOTE: analyze() must be called prior to getEnergy(). Analyze() 5805 * tells the FFT to analyze frequency data, and getEnergy() uses 5806 * the results determine the value at a specific frequency or 5807 * range of frequencies.</em></p> 5808 * 5809 * @method getEnergy 5810 * @for p5.FFT 5811 * @param {Number|String} frequency1 Will return a value representing 5812 * energy at this frequency. Alternately, 5813 * the strings "bass", "lowMid" "mid", 5814 * "highMid", and "treble" will return 5815 * predefined frequency ranges. 5816 * @param {Number} [frequency2] If a second frequency is given, 5817 * will return average amount of 5818 * energy that exists between the 5819 * two frequencies. 5820 * @return {Number} Energy Energy (volume/amplitude) from 5821 * 0 and 255. 5822 * 5823 */ 5824 5825 5826 p5.FFT.prototype.getEnergy = function (frequency1, frequency2) { 5827 var nyquist = p5sound.audiocontext.sampleRate / 2; 5828 5829 if (frequency1 === 'bass') { 5830 frequency1 = this.bass[0]; 5831 frequency2 = this.bass[1]; 5832 } else if (frequency1 === 'lowMid') { 5833 frequency1 = this.lowMid[0]; 5834 frequency2 = this.lowMid[1]; 5835 } else if (frequency1 === 'mid') { 5836 frequency1 = this.mid[0]; 5837 frequency2 = this.mid[1]; 5838 } else if (frequency1 === 'highMid') { 5839 frequency1 = this.highMid[0]; 5840 frequency2 = this.highMid[1]; 5841 } else if (frequency1 === 'treble') { 5842 frequency1 = this.treble[0]; 5843 frequency2 = this.treble[1]; 5844 } 5845 5846 if (typeof frequency1 !== 'number') {
5847 throw 'invalid input for getEnergy()'; 5848 } else if (!frequency2) { 5849 var index = Math.round(frequency1 / nyquist * this.freqDomain.length); 5850 return this.freqDomain[index]; 5851 } else if (frequency1 && frequency2) { 5852 if (frequency1 > frequency2) { 5853 var swap = frequency2; 5854 frequency2 = frequency1; 5855 frequency1 = swap; 5856 } 5857 5858 var lowIndex = Math.round(frequency1 / nyquist * this.freqDomain.length); 5859 var highIndex = Math.round(frequency2 / nyquist * this.freqDomain.length); 5860 var total = 0; 5861 var numFrequencies = 0; 5862 5863 for (var i = lowIndex; i <= highIndex; i++) { 5864 total += this.freqDomain[i]; 5865 numFrequencies += 1; 5866 } 5867 5868 5869 var toReturn = total / numFrequencies; 5870 return toReturn; 5871 } else { 5872 throw 'invalid input for getEnergy()'; 5873 } 5874 }; 5875 5876 5877 p5.FFT.prototype.getFreq = function (freq1, freq2) { 5878 console.log('getFreq() is deprecated. Please use getEnergy() instead.'); 5879 var x = this.getEnergy(freq1, freq2); 5880 return x; 5881 }; 5882 /** 5883 * Returns the 5884 * <a href="http://en.wikipedia.org/wiki/Spectral_centroid" target="_blank"> 5885 * spectral centroid</a> of the input signal. 5886 * <em>NOTE: analyze() must be called prior to getCentroid(). Analyze() 5887 * tells the FFT to analyze frequency data, and getCentroid() uses 5888 * the results determine the spectral centroid.</em></p> 5889 * 5890 * @method getCentroid 5891 * @for p5.FFT 5892 * @return {Number} Spectral Centroid Frequency Frequency of the spectral centroid in Hz. 5893 * 5894 * 5895 * @example 5896 * <div><code> 5897 * function setup(){ 5898 * cnv = createCanvas(100,100); 5899 * cnv.mousePressed(userStartAudio); 5900 * sound = new p5.AudioIn(); 5901 * sound.start(); 5902 * fft = new p5.FFT(); 5903 * sound.connect(fft); 5904 *} 5905 * 5906 *function draw() { 5907 * if (getAudioContext().state !== 'running') { 5908 * background(220); 5909 * text('tap here and enable mic to begin', 10, 20, width - 20); 5910 * return; 5911 * } 5912 * let centroidplot = 0.0; 5913 * let spectralCentroid = 0; 5914 * 5915 * background(0); 5916 * stroke(0,255,0); 5917 * let spectrum = fft.analyze(); 5918 * fill(0,255,0); // spectrum is green 5919 * 5920 * //draw the spectrum 5921 * for (let i = 0; i < spectrum.length; i++){ 5922 * let x = map(log(i), 0, log(spectrum.length), 0, width); 5923 * let h = map(spectrum[i], 0, 255, 0, height); 5924 * let rectangle_width = (log(i+1)-log(i))*(width/log(spectrum.length)); 5925 * rect(x, height, rectangle_width, -h ) 5926 * } 5927 * let nyquist = 22050; 5928 * 5929 * // get the centroid 5930 * spectralCentroid = fft.getCentroid(); 5931 * 5932 * // the mean_freq_index calculation is for the display. 5933 * let mean_freq_index = spectralCentroid/(nyquist/spectrum.length); 5934 * 5935 * centroidplot = map(log(mean_freq_index), 0, log(spectrum.length), 0, width); 5936 * 5937 * stroke(255,0,0); // the line showing where the centroid is will be red 5938 * 5939 * rect(centroidplot, 0, width / spectrum.length, height) 5940 * noStroke(); 5941 * fill(255,255,255); // text is white 5942 * text('centroid: ', 10, 20); 5943 * text(round(spectralCentroid)+' Hz', 10, 40); 5944 *} 5945 * </code></div> 5946 */ 5947 5948 5949 p5.FFT.prototype.getCentroid = function () { 5950 var nyquist = p5sound.audiocontext.sampleRate / 2; 5951 var cumulative_sum = 0; 5952 var centroid_normalization = 0; 5953 5954 for (var i = 0; i < this.freqDomain.length; i++) { 5955 cumulative_sum += i * this.freqDomain[i]; 5956 centroid_normalization += this.freqDomain[i]; 5957 } 5958 5959 var mean_freq_index = 0; 5960 5961 if (centroid_normalization !== 0) { 5962 mean_freq_index = cumulative_sum / centroid_normalization; 5963 } 5964 5965 var spec_centroid_freq = mean_freq_index * (nyquist / this.freqDomain.length); 5966 return spec_centroid_freq; 5967 }; 5968 /** 5969 * Smooth FFT analysis by averaging with the last analysis frame. 5970 * 5971 * @method smooth 5972 * @param {Number} smoothing 0.0 < smoothing < 1.0. 5973 * Defaults to 0.8. 5974 */ 5975 5976 5977 p5.FFT.prototype.smooth = function (s) { 5978 if (typeof s !== 'undefined') { 5979 this.smoothing = s; 5980 } 5981 5982 return this.smoothing; 5983 }; 5984 5985 p5.FFT.prototype.dispose = function () { 5986 var index = p5sound.soundArray.indexOf(this); 5987 p5sound.soundArray.splice(index, 1); 5988 5989 if (this.analyser) { 5990 this.analyser.disconnect(); 5991 delete this.analyser; 5992 } 5993 }; 5994 /** 5995 * Returns an array of average amplitude values for a given number 5996 * of frequency bands split equally. N defaults to 16. 5997 * <em>NOTE: analyze() must be called prior to linAverages(). Analyze() 5998 * tells the FFT to analyze frequency data, and linAverages() uses 5999 * the results to group them into a smaller set of averages.</em></p> 6000 * 6001 * @method linAverages 6002 * @for p5.FFT 6003 * @param {Number} N Number of returned frequency groups 6004 * @return {Array} linearAverages Array of average amplitude values for each group 6005 */ 6006 6007 6008 p5.FFT.prototype.linAverages = function (N) { 6009 var N = N || 16; 6010 6011 var spectrum = this.freqDomain; 6012 var spectrumLength = spectrum.length; 6013 var spectrumStep = Math.floor(spectrumLength / N); 6014 var linearAverages = new Array(N); 6015 6016 var groupIndex = 0; 6017 6018 for (var specIndex = 0; specIndex < spectrumLength; specIndex++) { 6019 linearAverages[groupIndex] = linearAverages[groupIndex] !== undefined ? (linearAverages[groupIndex] + spectrum[specIndex]) / 2 : spectrum[specIndex]; 6020 6021 if (specIndex % spectrumStep === spectrumStep - 1) { 6022 groupIndex++; 6023 } 6024 } 6025 6026 return linearAverages; 6027 }; 6028 /** 6029 * Returns an array of average amplitude values of the spectrum, for a given 6030 * set of <a href="https://en.wikipedia.org/wiki/Octave_band" target="_blank"> 6031 * Octave Bands</a> 6032 * <em>NOTE: analyze() must be called prior to logAverages(). Analyze() 6033 * tells the FFT to analyze frequency data, and logAverages() uses 6034 * the results to group them into a smaller set of averages.</em></p> 6035 * 6036 * @method logAverages 6037 * @for p5.FFT 6038 * @param {Array} octaveBands Array of Octave Bands objects for grouping 6039 * @return {Array} logAverages Array of average amplitude values for each group 6040 */ 6041 6042 6043 p5.FFT.prototype.logAverages = function (octaveBands) { 6044 var nyquist = p5sound.audiocontext.sampleRate / 2; 6045 var spectrum = this.freqDomain; 6046 var spectrumLength = spectrum.length; 6047 var logAverages = new Array(octaveBands.length); 6048 6049 var octaveIndex = 0; 6050 6051 for (var specIndex = 0; specIndex < spectrumLength; specIndex++) { 6052 var specIndexFrequency = Math.round(specIndex * nyquist / this.freqDomain.length); 6053 6054 if (specIndexFrequency > octaveBands[octaveIndex].hi) { 6055 octaveIndex++; 6056 } 6057 6058 logAverages[octaveIndex] = logAverages[octaveIndex] !== undefined ? (logAverages[octaveIndex] + spectrum[specIndex]) / 2 : spectrum[specIndex]; 6059 } 6060 6061 return logAverages; 6062 }; 6063 /** 6064 * Calculates and Returns the 1/N 6065 * <a href="https://en.wikipedia.org/wiki/Octave_band" target="_blank">Octave Bands</a> 6066 * N defaults to 3 and minimum central frequency to 15.625Hz. 6067 * (1/3 Octave Bands ~= 31 Frequency Bands) 6068 * Setting fCtr0 to a central value of a higher octave will ignore the lower bands 6069 * and produce less frequency groups. 6070 * 6071 * @method getOctaveBands 6072 * @for p5.FFT 6073 * @param {Number} N Specifies the 1/N type of generated octave bands 6074 * @param {Number} fCtr0 Minimum central frequency for the lowest band 6075 * @return {Array} octaveBands Array of octave band objects with their bounds 6076 */ 6077 6078 6079 p5.FFT.prototype.getOctaveBands = function (N, fCtr0) { 6080 var N = N || 3; 6081 6082 var fCtr0 = fCtr0 || 15.625; 6083 6084 var octaveBands = []; 6085 var lastFrequencyBand = { 6086 lo: fCtr0 / Math.pow(2, 1 / (2 * N)), 6087 ctr: fCtr0, 6088 hi: fCtr0 * Math.pow(2, 1 / (2 * N)) 6089 }; 6090 octaveBands.push(lastFrequencyBand); 6091 var nyquist = p5sound.audiocontext.sampleRate / 2; 6092 6093 while (lastFrequencyBand.hi < nyquist) { 6094 var newFrequencyBand = {}; 6095 newFrequencyBand.lo = lastFrequencyBand.hi; 6096 newFrequencyBand.ctr = lastFrequencyBand.ctr * Math.pow(2, 1 / N); 6097 newFrequencyBand.hi = newFrequencyBand.ctr * Math.pow(2, 1 / (2 * N)); 6098 octaveBands.push(newFrequencyBand); 6099 lastFrequencyBand = newFrequencyBand; 6100 } 6101 6102 return octaveBands; 6103 }; 6104 6105 6106 var freqToFloat = function freqToFloat(fft) { 6107 if (fft.freqDomain instanceof Float32Array === false) { 6108 fft.freqDomain = new Float32Array(fft.analyser.frequencyBinCount); 6109 } 6110 }; 6111 6112 var freqToInt = function freqToInt(fft) { 6113 if (fft.freqDomain instanceof Uint8Array === false) { 6114 fft.freqDomain = new Uint8Array(fft.analyser.frequencyBinCount); 6115 } 6116 }; 6117 6118 var timeToFloat = function timeToFloat(fft) { 6119 if (fft.timeDomain instanceof Float32Array === false) { 6120 fft.timeDomain = new Float32Array(fft.analyser.frequencyBinCount); 6121 } 6122 }; 6123 6124 var timeToInt = function timeToInt(fft) { 6125 if (fft.timeDomain instanceof Uint8Array === false) { 6126 fft.timeDomain = new Uint8Array(fft.analyser.frequencyBinCount); 6127 } 6128 }; 6129}).call(exports, __webpack_require__, exports, module), 6130 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 6131 6132 }), 6133 (function(module, exports, __webpack_require__) { 6134 6135"use strict"; 6136var __WEBPACK_AMD_DEFINE_RESULT__; 6137 6138!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 6139 var Signal = __webpack_require__(2); 6140 6141 var Add = __webpack_require__(7); 6142 6143 var Mult = __webpack_require__(3); 6144 6145 var Scale = __webpack_require__(13); 6146 /** 6147 * <p>p5.Signal is a constant audio-rate signal used by p5.Oscillator 6148 * and p5.Envelope for modulation math.</p> 6149 * 6150 * <p>This is necessary because Web Audio is processed on a seprate clock. 6151 * For example, the p5 draw loop runs about 60 times per second. But 6152 * the audio clock must process samples 44100 times per second. If we 6153 * want to add a value to each of those samples, we can't do it in the 6154 * draw loop, but we can do it by adding a constant-rate audio signal.</p. 6155 * 6156 * <p>This class mostly functions behind the scenes in p5.sound, and returns 6157 * a Tone.Signal from the Tone.js library by Yotam Mann. 6158 * If you want to work directly with audio signals for modular 6159 * synthesis, check out 6160 * <a href='http://bit.ly/1oIoEng' target=_'blank'>tone.js.</a></p> 6161 * 6162 * @class p5.Signal 6163 * @constructor 6164 * @return {Tone.Signal} A Signal object from the Tone.js library 6165 * @example 6166 * <div><code> 6167 * let carrier, modulator; 6168 * 6169 * function setup() {
6170 * let cnv = createCanvas(100, 100); 6171 * cnv.mousePressed(canvasPressed); 6172 * background(220); 6173 * text('tap to play', 20, 20); 6174 * 6175 * carrier = new p5.Oscillator('sine'); 6176 * carrier.start(); 6177 * carrier.amp(1); // set amplitude 6178 * carrier.freq(220); // set frequency 6179 * 6180 * modulator = new p5.Oscillator('sawtooth'); 6181 * modulator.disconnect(); 6182 * modulator.start(); 6183 * modulator.amp(1); 6184 * modulator.freq(4); 6185 * 6186 * // Modulator's default amplitude range is -1 to 1. 6187 * // Multiply it by -200, so the range is -200 to 200 6188 * // then add 220 so the range is 20 to 420 6189 * carrier.freq( modulator.mult(-400).add(220) ); 6190 * } 6191 * 6192 * function canvasPressed() { 6193 * userStartAudio(); 6194 * carrier.amp(1.0); 6195 * } 6196 * 6197 * function mouseReleased() { 6198 * carrier.amp(0); 6199 * } 6200 * </code></div> 6201 */ 6202 6203 6204 p5.Signal = function (value) { 6205 var s = new Signal(value); 6206 6207 return s; 6208 }; 6209 /** 6210 * Fade to value, for smooth transitions 6211 * 6212 * @method fade 6213 * @for p5.Signal 6214 * @param {Number} value Value to set this signal 6215 * @param {Number} [secondsFromNow] Length of fade, in seconds from now 6216 */ 6217 6218 6219 Signal.prototype.fade = Signal.prototype.linearRampToValueAtTime; 6220 Mult.prototype.fade = Signal.prototype.fade; 6221 Add.prototype.fade = Signal.prototype.fade; 6222 Scale.prototype.fade = Signal.prototype.fade; 6223 /** 6224 * Connect a p5.sound object or Web Audio node to this 6225 * p5.Signal so that its amplitude values can be scaled. 6226 * 6227 * @method setInput 6228 * @for p5.Signal 6229 * @param {Object} input 6230 */ 6231 6232 Signal.prototype.setInput = function (_input) { 6233 _input.connect(this); 6234 }; 6235 6236 Mult.prototype.setInput = Signal.prototype.setInput; 6237 Add.prototype.setInput = Signal.prototype.setInput; 6238 Scale.prototype.setInput = Signal.prototype.setInput; 6239 6240 /** 6241 * Add a constant value to this audio signal, 6242 * and return the resulting audio signal. Does 6243 * not change the value of the original signal, 6244 * instead it returns a new p5.SignalAdd. 6245 * 6246 * @method add 6247 * @for p5.Signal 6248 * @param {Number} number 6249 * @return {p5.Signal} object 6250 */ 6251 6252 Signal.prototype.add = function (num) { 6253 var add = new Add(num); 6254 6255 this.connect(add); 6256 return add; 6257 }; 6258 6259 Mult.prototype.add = Signal.prototype.add; 6260 Add.prototype.add = Signal.prototype.add; 6261 Scale.prototype.add = Signal.prototype.add; 6262 /** 6263 * Multiply this signal by a constant value, 6264 * and return the resulting audio signal. Does 6265 * not change the value of the original signal, 6266 * instead it returns a new p5.SignalMult. 6267 * 6268 * @method mult 6269 * @for p5.Signal 6270 * @param {Number} number to multiply 6271 * @return {p5.Signal} object 6272 */ 6273 6274 Signal.prototype.mult = function (num) { 6275 var mult = new Mult(num); 6276 6277 this.connect(mult); 6278 return mult; 6279 }; 6280 6281 Mult.prototype.mult = Signal.prototype.mult; 6282 Add.prototype.mult = Signal.prototype.mult; 6283 Scale.prototype.mult = Signal.prototype.mult; 6284 /** 6285 * Scale this signal value to a given range, 6286 * and return the result as an audio signal. Does 6287 * not change the value of the original signal, 6288 * instead it returns a new p5.SignalScale. 6289 * 6290 * @method scale 6291 * @for p5.Signal 6292 * @param {Number} number to multiply 6293 * @param {Number} inMin input range minumum 6294 * @param {Number} inMax input range maximum 6295 * @param {Number} outMin input range minumum 6296 * @param {Number} outMax input range maximum 6297 * @return {p5.Signal} object 6298 */ 6299 6300 Signal.prototype.scale = function (inMin, inMax, outMin, outMax) { 6301 var mapOutMin, mapOutMax; 6302 6303 if (arguments.length === 4) { 6304 mapOutMin = p5.prototype.map(outMin, inMin, inMax, 0, 1) - 0.5; 6305 mapOutMax = p5.prototype.map(outMax, inMin, inMax, 0, 1) - 0.5; 6306 } else { 6307 mapOutMin = arguments[0]; 6308 mapOutMax = arguments[1]; 6309 } 6310 6311 var scale = new Scale(mapOutMin, mapOutMax); 6312 this.connect(scale); 6313 return scale; 6314 }; 6315 6316 Mult.prototype.scale = Signal.prototype.scale; 6317 Add.prototype.scale = Signal.prototype.scale; 6318 Scale.prototype.scale = Signal.prototype.scale; 6319}).call(exports, __webpack_require__, exports, module), 6320 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 6321 6322 }), 6323 (function(module, exports, __webpack_require__) { 6324 6325var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(21)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(o){o.Frequency=function(e,t){if(!(this instanceof o.Frequency))return new o.Frequency(e,t);o.TimeBase.call(this,e,t)},o.extend(o.Frequency,o.TimeBase),o.Frequency.prototype._primaryExpressions=Object.create(o.TimeBase.prototype._primaryExpressions),o.Frequency.prototype._primaryExpressions.midi={regexp:/^(\d+(?:\.\d+)?midi)/,method:function(e){return this.midiToFrequency(e)}},o.Frequency.prototype._primaryExpressions.note={regexp:/^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i,method:function(e,t){var r=n[e.toLowerCase()]+12*(parseInt(t)+1);return this.midiToFrequency(r)}},o.Frequency.prototype._primaryExpressions.tr={regexp:/^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,method:function(e,t,r){var n=1;return e&&"0"!==e&&(n*=this._beatsToUnits(this._timeSignature()*parseFloat(e))),t&&"0"!==t&&(n*=this._beatsToUnits(parseFloat(t))),r&&"0"!==r&&(n*=this._beatsToUnits(parseFloat(r)/4)),n}},o.Frequency.prototype.transpose=function(e){return this._expr=function(e,t){return e()*this.intervalToFrequencyRatio(t)}.bind(this,this._expr,e),this},o.Frequency.prototype.harmonize=function(e){return this._expr=function(e,t){for(var r=e(),n=[],o=0;o<t.length;o++)n[o]=r*this.intervalToFrequencyRatio(t[o]);return n}.bind(this,this._expr,e),this},o.Frequency.prototype.toMidi=function(){return this.frequencyToMidi(this.valueOf())},o.Frequency.prototype.toNote=function(){var e=this.valueOf(),t=Math.log(e/o.Frequency.A4)/Math.LN2,r=Math.round(12*t)+57,n=Math.floor(r/12);return n<0&&(r+=-12*n),i[r%12]+n.toString()},o.Frequency.prototype.toSeconds=function(){return 1/this.valueOf()},o.Frequency.prototype.toFrequency=function(){return this.valueOf()},o.Frequency.prototype.toTicks=function(){var e=this._beatsToUnits(1),t=this.valueOf()/e;return Math.floor(t*o.Transport.PPQ)},o.Frequency.prototype._frequencyToUnits=function(e){return e},o.Frequency.prototype._ticksToUnits=function(e){return 1/(60*e/(o.Transport.bpm.value*o.Transport.PPQ))},o.Frequency.prototype._beatsToUnits=function(e){return 1/o.TimeBase.prototype._beatsToUnits.call(this,e)},o.Frequency.prototype._secondsToUnits=function(e){return 1/e},o.Frequency.prototype._defaultUnits="hz";var n={cbb:-2,cb:-1,c:0,"c#":1,cx:2,dbb:0,db:1,d:2,"d#":3,dx:4,ebb:2,eb:3,e:4,"e#":5,ex:6,fbb:3,fb:4,f:5,"f#":6,fx:7,gbb:5,gb:6,g:7,"g#":8,gx:9,abb:7,ab:8,a:9,"a#":10,ax:11,bbb:9,bb:10,b:11,"b#":12,bx:13},i=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"];return o.Frequency.A4=440,o.Frequency.prototype.midiToFrequency=function(e){return o.Frequency.A4*Math.pow(2,(e-69)/12)},o.Frequency.prototype.frequencyToMidi=function(e){return 69+12*Math.log(e/o.Frequency.A4)/Math.LN2},o.Frequency}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 6326 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 6327 6328 }), 6329 (function(module, exports, __webpack_require__) { 6330 6331var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(20)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(o){return o.Trans
6331portTime=function(t,r){if(!(this instanceof o.TransportTime))return new o.TransportTime(t,r);o.Time.call(this,t,r)},o.extend(o.TransportTime,o.Time),o.TransportTime.prototype._unaryExpressions=Object.create(o.Time.prototype._unaryExpressions),o.TransportTime.prototype._unaryExpressions.quantize={regexp:/^@/,method:function(t){var r=this._secondsToTicks(t()),e=Math.ceil(o.Transport.ticks/r);return this._ticksToUnits(e*r)}},o.TransportTime.prototype._secondsToTicks=function(t){var r=t/this._beatsToUnits(1);return Math.round(r*o.Transport.PPQ)},o.TransportTime.prototype.valueOf=function(){return this._secondsToTicks(this._expr())+(this._plusNow?o.Transport.ticks:0)},o.TransportTime.prototype.toTicks=function(){return this.valueOf()},o.TransportTime.prototype.toSeconds=function(){return this._expr()+(this._plusNow?o.Transport.seconds:0)},o.TransportTime.prototype.toFrequency=function(){return 1/this.toSeconds()},o.TransportTime}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 6332 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 6333 6334 }), 6335 (function(module, exports, __webpack_require__) { 6336 6337"use strict"; 6338var __WEBPACK_AMD_DEFINE_RESULT__; 6339 6340!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 6341 var p5sound = __webpack_require__(1); 6342 6343 var Add = __webpack_require__(7); 6344 6345 var Mult = __webpack_require__(3); 6346 6347 var Scale = __webpack_require__(13); 6348 6349 var TimelineSignal = __webpack_require__(14); 6350 /** 6351 * <p>Envelopes are pre-defined amplitude distribution over time. 6352 * Typically, envelopes are used to control the output volume 6353 * of an object, a series of fades referred to as Attack, Decay, 6354 * Sustain and Release ( 6355 * <a href="https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg">ADSR</a> 6356 * ). Envelopes can also control other Web Audio Parameters—for example, a p5.Envelope can 6357 * control an Oscillator's frequency like this: <code>osc.freq(env)</code>.</p> 6358 * <p>Use <code><a href="#/p5.Envelope/setRange">setRange</a></code> to change the attack/release level. 6359 * Use <code><a href="#/p5.Envelope/setADSR">setADSR</a></code> to change attackTime, decayTime, sustainPercent and releaseTime.</p> 6360 * <p>Use the <code><a href="#/p5.Envelope/play">play</a></code> method to play the entire envelope, 6361 * the <code><a href="#/p5.Envelope/ramp">ramp</a></code> method for a pingable trigger, 6362 * or <code><a href="#/p5.Envelope/triggerAttack">triggerAttack</a></code>/ 6363 * <code><a href="#/p5.Envelope/triggerRelease">triggerRelease</a></code> to trigger noteOn/noteOff.</p> 6364 * 6365 * @class p5.Envelope 6366 * @constructor 6367 * @example 6368 * <div><code> 6369 * let t1 = 0.1;
6369 // attack time in seconds 6370 * let l1 = 0.7; // attack level 0.0 to 1.0 6371 * let t2 = 0.3; // decay time in seconds 6372 * let l2 = 0.1; // decay level 0.0 to 1.0 6373 * 6374 * let env; 6375 * let triOsc; 6376 * 6377 * function setup() { 6378 * let cnv = createCanvas(100, 100); 6379 * background(220); 6380 * text('tap to play', 20, 20); 6381 * cnv.mousePressed(playSound); 6382 * 6383 * env = new p5.Envelope(t1, l1, t2, l2); 6384 * triOsc = new p5.Oscillator('triangle'); 6385 * } 6386 * 6387 * function playSound() { 6388 * // starting the oscillator ensures that audio is enabled. 6389 * triOsc.start(); 6390 * env.play(triOsc); 6391 * } 6392 * </code></div> 6393 */ 6394 6395 6396 p5.Envelope = function (t1, l1, t2, l2, t3, l3) { 6397 /** 6398 * Time until envelope reaches attackLevel 6399 * @property attackTime 6400 */ 6401 this.aTime = t1 || 0.1; 6402 /** 6403 * Level once attack is complete. 6404 * @property attackLevel 6405 */ 6406 6407 this.aLevel = l1 || 1; 6408 /** 6409 * Time until envelope reaches decayLevel. 6410 * @property decayTime 6411 */ 6412 6413 this.dTime = t2 || 0.5; 6414 /** 6415 * Level after decay. The envelope will sustain here until it is released. 6416 * @property decayLevel 6417 */ 6418 6419 this.dLevel = l2 || 0; 6420 /** 6421 * Duration of the release portion of the envelope. 6422 * @property releaseTime 6423 */ 6424 6425 this.rTime = t3 || 0; 6426 /** 6427 * Level at the end of the release. 6428 * @property releaseLevel 6429 */ 6430 6431 this.rLevel = l3 || 0; 6432 this._rampHighPercentage = 0.98; 6433 this._rampLowPercentage = 0.02; 6434 this.output = p5sound.audiocontext.createGain(); 6435 this.control = new TimelineSignal(); 6436 6437 this._init(); 6438 6439 6440 this.control.connect(this.output); 6441 6442 this.connection = null; 6443 6444 this.mathOps = [this.control]; 6445 6446 this.isExponential = false; 6447 6448 this.sourceToClear = null; 6449 6450 this.wasTriggered = false; 6451 6452 p5sound.soundArray.push(this); 6453 }; 6454 6455 6456 p5.Envelope.prototype._init = function () { 6457 var now = p5sound.audiocontext.currentTime; 6458 var t = now; 6459 this.control.setTargetAtTime(0.00001, t, .001); 6460 6461 this._setRampAD(this.aTime, this.dTime); 6462 }; 6463 /** 6464 * Reset the envelope with a series of time/value pairs. 6465 * 6466 * @method set 6467 * @for p5.Envelope 6468 * @param {Number} attackTime Time (in seconds) before level 6469 * reaches attackLevel 6470 * @param {Number} attackLevel Typically an amplitude between 6471 * 0.0 and 1.0 6472 * @param {Number} decayTime Time 6473 * @param {Number} decayLevel Amplitude (In a standard ADSR envelope, 6474 * decayLevel = sustainLevel) 6475 * @param {Number} releaseTime Release Time (in seconds) 6476 * @param {Number} releaseLevel Amplitude 6477 * @example 6478 * <div><code> 6479 * let attackTime; 6480 * let l1 = 0.7; // attack level 0.0 to 1.0 6481 * let t2 = 0.3; // decay time in seconds 6482 * let l2 = 0.1; // decay level 0.0 to 1.0 6483 * let l3 = 0.2; // release time in seconds 6484 * 6485 * let env, triOsc; 6486 * 6487 * function setup() { 6488 * let cnv = createCanvas(100, 100); 6489 * cnv.mousePressed(playSound); 6490 * 6491 * env = new p5.Envelope(); 6492 * triOsc = new p5.Oscillator('triangle'); 6493 * } 6494 * 6495 * function draw() { 6496 * background(220); 6497 * text('tap here to play', 5, 20); 6498 * 6499 * attackTime = map(mouseX, 0, width, 0.0, 1.0); 6500 * text('attack time: ' + attackTime, 5, height - 20); 6501 * } 6502 * 6503 * // mouseClick triggers envelope if over canvas 6504 * function playSound() { 6505 * env.set(attackTime, l1, t2, l2, l3); 6506 * 6507 * triOsc.start(); 6508 * env.play(triOsc); 6509 * } 6510 * </code></div> 6511 * 6512 */ 6513 6514 6515 p5.Envelope.prototype.set = function (t1, l1, t2, l2, t3, l3) { 6516 this.aTime = t1; 6517 this.aLevel = l1; 6518 this.dTime = t2 || 0; 6519 this.dLevel = l2 || 0; 6520 this.rTime = t3 || 0; 6521 this.rLevel = l3 || 0; 6522 6523 this._setRampAD(t1, t2); 6524 }; 6525 /** 6526 * Set values like a traditional 6527 * <a href="https://en.wikipedia.org/wiki/Synthesizer#/media/File:ADSR_parameter.svg"> 6528 * ADSR envelope 6529 * </a>. 6530 * 6531 * @method setADSR 6532 * @for p5.Envelope 6533 * @param {Number} attackTime Time (in seconds before envelope 6534 * reaches Attack Level 6535 * @param {Number} [decayTime] Time (in seconds) before envelope 6536 * reaches Decay/Sustain Level 6537 * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, 6538 * where 1.0 = attackLevel, 0.0 = releaseLevel. 6539 * The susRatio determines the decayLevel and the level at which the 6540 * sustain portion of the envelope will sustain. 6541 * For example, if attackLevel is 0.4, releaseLevel is 0, 6542 * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is 6543 * increased to 1.0 (using <code>setRange</code>), 6544 * then decayLevel would increase proportionally, to become 0.5. 6545 * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) 6546 * @example 6547 * <div><code> 6548 * let attackLevel = 1.0; 6549 * let releaseLevel = 0; 6550 * 6551 * let attackTime = 0.001; 6552 * let decayTime = 0.2; 6553 * let susPercent = 0.2; 6554 * let releaseTime = 0.5; 6555 * 6556 * let env, triOsc; 6557 * 6558 * function setup() {
6559 * let cnv = createCanvas(100, 100); 6560 * cnv.mousePressed(playEnv); 6561 * 6562 * env = new p5.Envelope(); 6563 * triOsc = new p5.Oscillator('triangle'); 6564 * triOsc.amp(env); 6565 * triOsc.freq(220); 6566 * } 6567 * 6568 * function draw() { 6569 * background(220); 6570 * text('tap here to play', 5, 20); 6571 * attackTime = map(mouseX, 0, width, 0, 1.0); 6572 * text('attack time: ' + attackTime, 5, height - 40); 6573 * } 6574 * 6575 * function playEnv() { 6576 * triOsc.start(); 6577 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 6578 * env.play(); 6579 * } 6580 * </code></div> 6581 */ 6582 6583 6584 p5.Envelope.prototype.setADSR = function (aTime, dTime, sPercent, rTime) { 6585 this.aTime = aTime; 6586 this.dTime = dTime || 0; 6587 6588 this.sPercent = sPercent || 0; 6589 this.dLevel = typeof sPercent !== 'undefined' ? sPercent * (this.aLevel - this.rLevel) + this.rLevel : 0; 6590 this.rTime = rTime || 0; 6591 6592 this._setRampAD(aTime, dTime); 6593 }; 6594 /** 6595 * Set max (attackLevel) and min (releaseLevel) of envelope. 6596 * 6597 * @method setRange 6598 * @for p5.Envelope 6599 * @param {Number} aLevel attack level (defaults to 1) 6600 * @param {Number} rLevel release level (defaults to 0) 6601 * @example 6602 * <div><code> 6603 * let attackLevel = 1.0; 6604 * let releaseLevel = 0; 6605 * 6606 * let attackTime = 0.001; 6607 * let decayTime = 0.2; 6608 * let susPercent = 0.2; 6609 * let releaseTime = 0.5; 6610 * 6611 * let env, triOsc; 6612 * 6613 * function setup() { 6614 * let cnv = createCanvas(100, 100); 6615 * cnv.mousePressed(playEnv); 6616 * 6617 * env = new p5.Envelope(); 6618 * triOsc = new p5.Oscillator('triangle'); 6619 * triOsc.amp(env); 6620 * triOsc.freq(220); 6621 * } 6622 * 6623 * function draw() { 6624 * background(220); 6625 * text('tap here to play', 5, 20); 6626 * attackLevel = map(mouseY, height, 0, 0, 1.0); 6627 * text('attack level: ' + attackLevel, 5, height - 20); 6628 * } 6629 * 6630 * function playEnv() { 6631 * triOsc.start(); 6632 * env.setRange(attackLevel, releaseLevel); 6633 * env.play(); 6634 * } 6635 * </code></div> 6636 */ 6637 6638 6639 p5.Envelope.prototype.setRange = function (aLevel, rLevel) { 6640 this.aLevel = aLevel || 1; 6641 this.rLevel = rLevel || 0; 6642 }; 6643 6644 6645 p5.Envelope.prototype._setRampAD = function (t1, t2) { 6646 this._rampAttackTime = this.checkExpInput(t1); 6647 this._rampDecayTime = this.checkExpInput(t2); 6648 var TCDenominator = 1.0; 6649 6650 TCDenominator = Math.log(1.0 / this.checkExpInput(1.0 - this._rampHighPercentage)); 6651 this._rampAttackTC = t1 / this.checkExpInput(TCDenominator); 6652 TCDenominator = Math.log(1.0 / this._rampLowPercentage); 6653 this._rampDecayTC = t2 / this.checkExpInput(TCDenominator); 6654 }; 6655 6656 6657 p5.Envelope.prototype.setRampPercentages = function (p1, p2) { 6658 this._rampHighPercentage = this.checkExpInput(p1); 6659 this._rampLowPercentage = this.checkExpInput(p2); 6660 var TCDenominator = 1.0; 6661 6662 TCDenominator = Math.log(1.0 / this.checkExpInput(1.0 - this._rampHighPercentage)); 6663 this._rampAttackTC = this._rampAttackTime / this.checkExpInput(TCDenominator); 6664 TCDenominator = Math.log(1.0 / this._rampLowPercentage); 6665 this._rampDecayTC = this._rampDecayTime / this.checkExpInput(TCDenominator); 6666 }; 6667 /** 6668 * Assign a parameter to be controlled by this envelope. 6669 * If a p5.Sound object is given, then the p5.Envelope will control its 6670 * output gain. If multiple inputs are provided, the env will 6671 * control all of them. 6672 * 6673 * @method setInput 6674 * @for p5.Envelope 6675 * @param {Object} [...inputs] A p5.sound object or 6676 * Web Audio Param. 6677 */ 6678 6679 6680 p5.Envelope.prototype.setInput = function () { 6681 for (var i = 0; i < arguments.length; i++) { 6682 this.connect(arguments[i]); 6683 } 6684 }; 6685 /** 6686 * Set whether the envelope ramp is linear (default) or exponential. 6687 * Exponential ramps can be useful because we perceive amplitude 6688 * and frequency logarithmically. 6689 * 6690 * @method setExp 6691 * @for p5.Envelope 6692 * @param {Boolean} isExp true is exponential, false is linear 6693 */ 6694 6695 6696 p5.Envelope.prototype.setExp = function (isExp) { 6697 this.isExponential = isExp; 6698 }; 6699 6700 6701 p5.Envelope.prototype.checkExpInput = function (value) { 6702 if (value <= 0) { 6703 value = 0.00000001; 6704 } 6705 6706 return value; 6707 }; 6708 /** 6709 * <p>Play tells the envelope to start acting on a given input. 6710 * If the input is a p5.sound object (i.e. AudioIn, Oscillator,
6711 * SoundFile), then Envelope will control its output volume. 6712 * Envelopes can also be used to control any <a href=" 6713 * http://docs.webplatform.org/wiki/apis/webaudio/AudioParam"> 6714 * Web Audio Audio Param.</a></p> 6715 * 6716 * @method play 6717 * @for p5.Envelope 6718 * @param {Object} unit A p5.sound object or 6719 * Web Audio Param. 6720 * @param {Number} [startTime] time from now (in seconds) at which to play 6721 * @param {Number} [sustainTime] time to sustain before releasing the envelope 6722 * @example 6723 * <div><code> 6724 * let attackLevel = 1.0; 6725 * let releaseLevel = 0; 6726 * 6727 * let attackTime = 0.001; 6728 * let decayTime = 0.2; 6729 * let susPercent = 0.2; 6730 * let releaseTime = 0.5; 6731 * 6732 * let env, triOsc; 6733 * 6734 * function setup() { 6735 * let cnv = createCanvas(100, 100); 6736 * cnv.mousePressed(playEnv); 6737 * 6738 * env = new p5.Envelope(); 6739 * triOsc = new p5.Oscillator('triangle'); 6740 * triOsc.amp(env); 6741 * triOsc.freq(220); 6742 * triOsc.start(); 6743 * } 6744 * 6745 * function draw() { 6746 * background(220); 6747 * text('tap here to play', 5, 20); 6748 * attackTime = map(mouseX, 0, width, 0, 1.0); 6749 * attackLevel = map(mouseY, height, 0, 0, 1.0); 6750 * text('attack time: ' + attackTime, 5, height - 40); 6751 * text('attack level: ' + attackLevel, 5, height - 20); 6752 * } 6753 * 6754 * function playEnv() { 6755 * // ensure that audio is enabled 6756 * userStartAudio(); 6757 * 6758 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 6759 * env.setRange(attackLevel, releaseLevel); 6760 * env.play(); 6761 * } 6762 * </code></div> 6763 */ 6764 6765 6766 p5.Envelope.prototype.play = function (unit, secondsFromNow, susTime) { 6767 var tFromNow = secondsFromNow || 0; 6768 var susTime = susTime || 0; 6769 6770 if (unit) { 6771 if (this.connection !== unit) { 6772 this.connect(unit); 6773 } 6774 } 6775 6776 this.triggerAttack(unit, tFromNow); 6777 this.triggerRelease(unit, tFromNow + this.aTime + this.dTime + susTime); 6778 }; 6779 /** 6780 * Trigger the Attack, and Decay portion of the Envelope. 6781 * Similar to holding down a key on a piano, but it will 6782 * hold the sustain level until you let go. Input can be 6783 * any p5.sound object, or a <a href=" 6784 * http://docs.webplatform.org/wiki/apis/webaudio/AudioParam"> 6785 * Web Audio Param</a>. 6786 * 6787 * @method triggerAttack 6788 * @for p5.Envelope 6789 * @param {Object} unit p5.sound Object or Web Audio Param 6790 * @param {Number} secondsFromNow time from now (in seconds) 6791 * @example 6792 * <div><code> 6793 * let attackTime = 0.001; 6794 * let decayTime = 0.2; 6795 * let susPercent = 0.3; 6796 * let releaseTime = 0.4; 6797 * let env, triOsc; 6798 * 6799 * function setup() { 6800 * let cnv = createCanvas(100, 100); 6801 * background(220); 6802 * textAlign(CENTER); 6803 * textSize(10); 6804 * text('tap to triggerAttack', width/2, height/2); 6805 * 6806 * env = new p5.Envelope(); 6807 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 6808 * env.setRange(1.0, 0.0); 6809 * triOsc = new p5.Oscillator('triangle'); 6810 * triOsc.freq(220); 6811 * 6812 * cnv.mousePressed(envAttack); 6813 * } 6814 * 6815 * function envAttack() { 6816 * background(0, 255, 255); 6817 * text('release to release', width/2, height/2); 6818 * 6819 * // ensures audio is enabled. See also: `userStartAudio` 6820 * triOsc.start(); 6821 * 6822 * env.triggerAttack(triOsc); 6823 * } 6824 * 6825 * function mouseReleased() { 6826 * background(220); 6827 * text('tap to triggerAttack', width/2, height/2); 6828 * 6829 * env.triggerRelease(triOsc); 6830 * } 6831 * </code></div> 6832 */ 6833 6834 6835 p5.Envelope.prototype.triggerAttack = function (unit, secondsFromNow) { 6836 var now = p5sound.audiocontext.currentTime; 6837 var tFromNow = secondsFromNow || 0; 6838 var t = now + tFromNow; 6839 this.lastAttack = t; 6840 this.wasTriggered = true; 6841 6842 if (unit) { 6843 if (this.connection !== unit) { 6844 this.connect(unit); 6845 } 6846 } 6847 6848 6849 var valToSet = this.control.getValueAtTime(t); 6850 6851 if (this.isExponential === true) { 6852 this.control.exponentialRampToValueAtTime(this.checkExpInput(valToSet), t); 6853 } else { 6854 this.control.linearRampToValueAtTime(valToSet, t); 6855 } 6856 6857 6858 t += this.aTime; 6859 6860 if (this.isExponential === true) { 6861 this.control.exponentialRampToValueAtTime(this.checkExpInput(this.aLevel), t); 6862 valToSet = this.checkExpInput(this.control.getValueAtTime(t)); 6863 this.control.cancelScheduledValues(t); 6864 this.control.exponentialRampToValueAtTime(valToSet, t); 6865 } else { 6866 this.control.linearRampToValueAtTime(this.aLevel, t); 6867 valToSet = this.control.getValueAtTime(t); 6868 this.control.cancelScheduledValues(t); 6869 this.control.linearRampToValueAtTime(valToSet, t); 6870 } 6871 6872 6873 t += this.dTime; 6874 6875 if (this.isExponential === true) { 6876 this.control.exponentialRampToValueAtTime(this.checkExpInput(this.dLevel), t); 6877 valToSet = this.checkExpInput(this.control.getValueAtTime(t)); 6878 this.control.cancelScheduledValues(t); 6879 this.control.exponentialRampToValueAtTime(valToSet, t); 6880 } else { 6881 this.control.linearRampToValueAtTime(this.dLevel, t); 6882 valToSet = this.control.getValueAtTime(t); 6883 this.control.cancelScheduledValues(t); 6884 this.control.linearRampToValueAtTime(valToSet, t); 6885 } 6886 }; 6887 /** 6888 * Trigger the Release of the Envelope. This is similar to releasing 6889 * the key on a piano and letting the sound fade according to the 6890 * release level and release time. 6891 * 6892 * @method triggerRelease 6893 * @for p5.Envelope 6894 * @param {Object} unit p5.sound Object or Web Audio Param 6895 * @param {Number} secondsFromNow time to trigger the release 6896 * @example 6897 * <div><code> 6898 * let attackTime = 0.001; 6899 * let decayTime = 0.2; 6900 * let susPercent = 0.3; 6901 * let releaseTime = 0.4; 6902 * let env, triOsc; 6903 * 6904 * function setup() {
6905 * let cnv = createCanvas(100, 100); 6906 * background(220); 6907 * textAlign(CENTER); 6908 * textSize(10); 6909 * text('tap to triggerAttack', width/2, height/2); 6910 * 6911 * env = new p5.Envelope(); 6912 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 6913 * env.setRange(1.0, 0.0); 6914 * triOsc = new p5.Oscillator('triangle'); 6915 * triOsc.freq(220); 6916 * 6917 * cnv.mousePressed(envAttack); 6918 * } 6919 * 6920 * function envAttack() { 6921 * background(0, 255, 255); 6922 * text('release to release', width/2, height/2); 6923 * 6924 * // ensures audio is enabled. See also: `userStartAudio` 6925 * triOsc.start(); 6926 * 6927 * env.triggerAttack(triOsc); 6928 * } 6929 * 6930 * function mouseReleased() { 6931 * background(220); 6932 * text('tap to triggerAttack', width/2, height/2); 6933 * 6934 * env.triggerRelease(triOsc); 6935 * } 6936 * </code></div> 6937 */ 6938 6939 6940 p5.Envelope.prototype.triggerRelease = function (unit, secondsFromNow) { 6941 if (!this.wasTriggered) { 6942 return; 6943 } 6944 6945 var now = p5sound.audiocontext.currentTime; 6946 var tFromNow = secondsFromNow || 0; 6947 var t = now + tFromNow; 6948 6949 if (unit) { 6950 if (this.connection !== unit) { 6951 this.connect(unit); 6952 } 6953 } 6954 6955 6956 var valToSet = this.control.getValueAtTime(t); 6957 6958 if (this.isExponential === true) { 6959 this.control.exponentialRampToValueAtTime(this.checkExpInput(valToSet), t); 6960 } else { 6961 this.control.linearRampToValueAtTime(valToSet, t); 6962 } 6963 6964 6965 t += this.rTime; 6966 6967 if (this.isExponential === true) { 6968 this.control.exponentialRampToValueAtTime(this.checkExpInput(this.rLevel), t); 6969 valToSet = this.checkExpInput(this.control.getValueAtTime(t)); 6970 this.control.cancelScheduledValues(t); 6971 this.control.exponentialRampToValueAtTime(valToSet, t); 6972 } else { 6973 this.control.linearRampToValueAtTime(this.rLevel, t); 6974 valToSet = this.control.getValueAtTime(t); 6975 this.control.cancelScheduledValues(t); 6976 this.control.linearRampToValueAtTime(valToSet, t); 6977 } 6978 6979 this.wasTriggered = false; 6980 }; 6981 /** 6982 * Exponentially ramp to a value using the first two 6983 * values from <code><a href="#/p5.Envelope/setADSR">setADSR(attackTime, decayTime)</a></code> 6984 * as <a href="https://en.wikipedia.org/wiki/RC_time_constant"> 6985 * time constants</a> for simple exponential ramps. 6986 * If the value is higher than current value, it uses attackTime, 6987 * while a decrease uses decayTime. 6988 * 6989 * @method ramp 6990 * @for p5.Envelope 6991 * @param {Object} unit p5.sound Object or Web Audio Param 6992 * @param {Number} secondsFromNow When to trigger the ramp 6993 * @param {Number} v Target value 6994 * @param {Number} [v2] Second target value (optional) 6995 * @example 6996 * <div><code> 6997 * let env, osc, amp; 6998 * 6999 * let attackTime = 0.001; 7000 * let decayTime = 0.2; 7001 * let attackLevel = 1; 7002 * let decayLevel = 0; 7003 * 7004 * function setup() { 7005 * let cnv = createCanvas(100, 100); 7006 * fill(0,255,0); 7007 * noStroke(); 7008 * 7009 * env = new p5.Envelope(); 7010 * env.setADSR(attackTime, decayTime); 7011 * osc = new p5.Oscillator(); 7012 * osc.amp(env); 7013 * amp = new p5.Amplitude(); 7014 * 7015 * cnv.mousePressed(triggerRamp); 7016 * } 7017 * 7018 * function triggerRamp() { 7019 * // ensures audio is enabled. See also: `userStartAudio` 7020 * osc.start(); 7021 * 7022 * env.ramp(osc, 0, attackLevel, decayLevel); 7023 * } 7024 * 7025 * function draw() { 7026 * background(20); 7027 * text('tap to play', 10, 20); 7028 * let h = map(amp.getLevel(), 0, 0.4, 0, height);; 7029 * rect(0, height, width, -h); 7030 * } 7031 * </code></div> 7032 */ 7033 7034 7035 p5.Envelope.prototype.ramp = function (unit, secondsFromNow, v1, v2) { 7036 var now = p5sound.audiocontext.currentTime; 7037 var tFromNow = secondsFromNow || 0; 7038 var t = now + tFromNow; 7039 var destination1 = this.checkExpInput(v1); 7040 var destination2 = typeof v2 !== 'undefined' ? this.checkExpInput(v2) : undefined; 7041 7042 if (unit) { 7043 if (this.connection !== unit) { 7044 this.connect(unit); 7045 } 7046 } 7047 7048 7049 var currentVal = this.checkExpInput(this.control.getValueAtTime(t)); 7050 7051 if (destination1 > currentVal) { 7052 this.control.setTargetAtTime(destination1, t, this._rampAttackTC); 7053 t += this._rampAttackTime; 7054 } 7055 else if (destination1 < currentVal) { 7056 this.control.setTargetAtTime(destination1, t, this._rampDecayTC); 7057 t += this._rampDecayTime; 7058 } 7059 7060 7061 if (destination2 === undefined) return; 7062 7063 if (destination2 > destination1) { 7064 this.control.setTargetAtTime(destination2, t, this._rampAttackTC); 7065 } 7066 else if (destination2 < destination1) { 7067 this.control.setTargetAtTime(destination2, t, this._rampDecayTC); 7068 } 7069 }; 7070 7071 p5.Envelope.prototype.connect = function (unit) { 7072 this.connection = unit; 7073 7074 if (unit instanceof p5.Oscillator || unit instanceof p5.SoundFile || unit instanceof p5.AudioIn || unit instanceof p5.Reverb || unit instanceof p5.Noise || unit instanceof p5.Filter || unit instanceof p5.Delay) { 7075 unit = unit.output.gain; 7076 } 7077 7078 if (unit instanceof AudioParam) { 7079 unit.setValueAtTime(0, p5sound.audiocontext.currentTime); 7080 } 7081 7082 if (unit instanceof p5.Signal) { 7083 unit.setValue(0); 7084 } 7085 7086 this.output.connect(unit); 7087 }; 7088 7089 p5.Envelope.prototype.disconnect = function () { 7090 if (this.output) { 7091 this.output.disconnect(); 7092 } 7093 }; 7094 7095 /** 7096 * Add a value to the p5.Oscillator's output amplitude, 7097 * and return the oscillator. Calling this method 7098 * again will override the initial add() with new values. 7099 * 7100 * @method add 7101 * @for p5.Envelope 7102 * @param {Number}
7102 number Constant number to add 7103 * @return {p5.Envelope} Envelope Returns this envelope 7104 * with scaled output 7105 */ 7106 7107 7108 p5.Envelope.prototype.add = function (num) { 7109 var add = new Add(num); 7110 var thisChain = this.mathOps.length; 7111 var nextChain = this.output; 7112 return p5.prototype._mathChain(this, add, thisChain, nextChain, Add); 7113 }; 7114 /** 7115 * Multiply the p5.Envelope's output amplitude 7116 * by a fixed value. Calling this method 7117 * again will override the initial mult() with new values. 7118 * 7119 * @method mult 7120 * @for p5.Envelope 7121 * @param {Number} number Constant number to multiply 7122 * @return {p5.Envelope} Envelope Returns this envelope 7123 * with scaled output 7124 */ 7125 7126 7127 p5.Envelope.prototype.mult = function (num) { 7128 var mult = new Mult(num); 7129 var thisChain = this.mathOps.length; 7130 var nextChain = this.output; 7131 return p5.prototype._mathChain(this, mult, thisChain, nextChain, Mult); 7132 }; 7133 /** 7134 * Scale this envelope's amplitude values to a given 7135 * range, and return the envelope. Calling this method 7136 * again will override the initial scale() with new values. 7137 * 7138 * @method scale 7139 * @for p5.Envelope 7140 * @param {Number} inMin input range minumum 7141 * @param {Number} inMax input range maximum 7142 * @param {Number} outMin input range minumum 7143 * @param {Number} outMax input range maximum 7144 * @return {p5.Envelope} Envelope Returns this envelope 7145 * with scaled output 7146 */ 7147 7148 7149 p5.Envelope.prototype.scale = function (inMin, inMax, outMin, outMax) { 7150 var scale = new Scale(inMin, inMax, outMin, outMax); 7151 var thisChain = this.mathOps.length; 7152 var nextChain = this.output; 7153 return p5.prototype._mathChain(this, scale, thisChain, nextChain, Scale); 7154 }; 7155 7156 7157 p5.Envelope.prototype.dispose = function () { 7158 var index = p5sound.soundArray.indexOf(this); 7159 p5sound.soundArray.splice(index, 1); 7160 this.disconnect(); 7161 7162 if (this.control) { 7163 this.control.dispose(); 7164 this.control = null; 7165 } 7166 7167 for (var i = 1; i < this.mathOps.length; i++) { 7168 this.mathOps[i].dispose(); 7169 } 7170 }; 7171 7172 7173 p5.Env = function (t1, l1, t2, l2, t3, l3) { 7174 console.warn('WARNING: p5.Env is now deprecated and may be removed in future versions. ' + 'Please use the new p5.Envelope instead.'); 7175 p5.Envelope.call(this, t1, l1, t2, l2, t3, l3); 7176 }; 7177 7178 p5.Env.prototype = Object.create(p5.Envelope.prototype); 7179}).call(exports, __webpack_require__, exports, module), 7180 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7181 7182 }), 7183 (function(module, exports, __webpack_require__) { 7184 7185"use strict"; 7186var __WEBPACK_AMD_DEFINE_RESULT__; 7187 7188!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 7189 var p5sound = __webpack_require__(1); 7190 7191 __webpack_require__(23); 7192 /** 7193 * Creates a Pulse object, an oscillator that implements 7194 * Pulse Width Modulation. 7195 * The pulse is created with two oscillators. 7196 * Accepts a parameter for frequency, and to set the 7197 * width between the pulses. See <a href=" 7198 * http://p5js.org/reference/#/p5.Oscillator"> 7199 * <code>p5.Oscillator</code> for a full list of methods. 7200 * 7201 * @class p5.Pulse 7202 * @extends p5.Oscillator 7203 * @constructor 7204 * @param {Number} [freq] Frequency in oscillations per second (Hz) 7205 * @param {Number} [w] Width between the pulses (0 to 1.0, 7206 * defaults to 0) 7207 * @example 7208 * <div><code> 7209 * let pulse; 7210 * function setup() { 7211 * let cnv = createCanvas(100, 100); 7212 * cnv.mousePressed(startPulse); 7213 * background(220); 7214 * 7215 * pulse = new p5.Pulse(); 7216 * pulse.amp(0.5); 7217 * pulse.freq(220); 7218 * } 7219 * function startPulse() { 7220 * pulse.start(); 7221 * pulse.amp(0.5, 0.02); 7222 * } 7223 * function mouseReleased() { 7224 * pulse.amp(0, 0.2); 7225 * } 7226 * function draw() { 7227 * background(220); 7228 * text('tap to play', 5, 20, width - 20); 7229 * let w = map(mouseX, 0, width, 0, 1); 7230 * w = constrain(w, 0, 1); 7231 * pulse.width(w); 7232 * text('pulse width: ' + w, 5, height - 20); 7233 * } 7234 * </code></div> 7235 */ 7236 7237 7238 p5.Pulse = function (freq, w) { 7239 p5.Oscillator.call(this, freq, 'sawtooth'); 7240 7241 this.w = w || 0; 7242 7243 this.osc2 = new p5.SawOsc(freq); 7244 7245 this.dNode = p5sound.audiocontext.createDelay(); 7246 7247 this.dcOffset = createDCOffset(); 7248 this.dcGain = p5sound.audiocontext.createGain(); 7249 this.dcOffset.connect(this.dcGain); 7250 this.dcGain.connect(this.output); 7251 7252 this.f = freq || 440; 7253 var mW = this.w / this.oscillator.frequency.value; 7254 this.dNode.delayTime.value = mW; 7255 this.dcGain.gain.value = 1.7 * (0.5 - this.w); 7256 7257 this.osc2.disconnect(); 7258 this.osc2.panner.disconnect(); 7259 this.osc2.amp(-1); 7260 7261 this.osc2.output.connect(this.dNode); 7262 this.dNode.connect(this.output); 7263 this.output.gain.value = 1; 7264 this.output.connect(this.panner); 7265 }; 7266 7267 p5.Pulse.prototype = Object.create(p5.Oscillator.prototype); 7268 /** 7269 * Set the width of a Pulse object (an oscillator that implements 7270 * Pulse Width Modulation). 7271 * 7272 * @method width 7273 * @param {Number} [width] Width between the pulses (0 to 1.0, 7274 * defaults to 0) 7275 */ 7276 7277 p5.Pulse.prototype.width = function (w) { 7278 if (typeof w === 'number') { 7279 if (w <= 1.0 && w >= 0.0) { 7280 this.w = w; 7281 7282 var mW = this.w / this.oscillator.frequency.value; 7283 this.dNode.delayTime.value = mW; 7284 } 7285 7286 this.dcGain.gain.value = 1.7 * (0.5 - this.w); 7287 } else { 7288 w.connect(this.dNode.delayTime); 7289 var sig = new p5.SignalAdd(-0.5); 7290 sig.setInput(w); 7291 sig = sig.mult(-1); 7292 sig = sig.mult(1.7); 7293 sig.connect(this.dcGain.gain); 7294 } 7295 }; 7296 7297 p5.Pulse.prototype.start = function (f, time) { 7298 var now = p5sound.audiocontext.currentTime; 7299 var t = time || 0; 7300 7301 if (!this.started) { 7302 var freq = f || this.f; 7303 var type = this.oscillator.type; 7304 this.oscillator = p5sound.audiocontext.createOscillator(); 7305 this.oscillator.frequency.setValueAtTime(freq, now); 7306 this.oscillator.type = type; 7307 this.oscillator.connect(this.output); 7308 this.oscillator.start(t + now); 7309 7310 this.osc2.oscillator = p5sound.audiocontext.createOscillator(); 7311 this.osc2.oscillator.frequency.setValueAtTime(freq, t + now); 7312 this.osc2.oscillator.type = type; 7313 this.osc2.oscillator.connect(this.osc2.output); 7314 this.osc2.start(t + now); 7315 this.freqNode = [this.oscillator.frequency, this.osc2.oscillator.frequency]; 7316 7317 this.dcOffset = createDCOffset(); 7318 this.dcOffset.connect(this.dcGain); 7319 this.dcOffset.start(t + now); 7320 7321 if (this.mods !== undefined && this.mods.frequency !== undefined) { 7322 this.mods.frequency.connect(this.freqNode[0]); 7323 this.mods.frequency.connect(this.freqNode[1]); 7324 } 7325 7326 this.started = true; 7327 this.osc2.started = true; 7328 } 7329 }; 7330 7331 p5.Pulse.prototype.stop = function (time) { 7332 if (this.started) { 7333 var t = time || 0; 7334 var now = p5sound.audiocontext.currentTime; 7335 this.oscillator.stop(t + now); 7336 7337 if (this.osc2.oscillator) { 7338 this.osc2.oscillator.stop(t + now); 7339 } 7340 7341 this.dcOffset.stop(t + now); 7342 this.started = false;
7343 this.osc2.started = false; 7344 } 7345 }; 7346 7347 p5.Pulse.prototype.freq = function (val, rampTime, tFromNow) { 7348 if (typeof val === 'number') { 7349 this.f = val; 7350 var now = p5sound.audiocontext.currentTime; 7351 var rampTime = rampTime || 0; 7352 var tFromNow = tFromNow || 0; 7353 var currentFreq = this.oscillator.frequency.value; 7354 this.oscillator.frequency.cancelScheduledValues(now); 7355 this.oscillator.frequency.setValueAtTime(currentFreq, now + tFromNow); 7356 this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); 7357 this.osc2.oscillator.frequency.cancelScheduledValues(now); 7358 this.osc2.oscillator.frequency.setValueAtTime(currentFreq, now + tFromNow); 7359 this.osc2.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); 7360 7361 if (this.freqMod) { 7362 this.freqMod.output.disconnect(); 7363 this.freqMod = null; 7364 } 7365 } else if (val.output) { 7366 val.output.disconnect(); 7367 val.output.connect(this.oscillator.frequency); 7368 val.output.connect(this.osc2.oscillator.frequency); 7369 this.freqMod = val; 7370 } 7371 }; 7372 7373 7374 function createDCOffset() { 7375 var ac = p5sound.audiocontext; 7376 var buffer = ac.createBuffer(1, 2048, ac.sampleRate); 7377 var data = buffer.getChannelData(0); 7378 7379 for (var i = 0; i < 2048; i++) { 7380 data[i] = 1.0; 7381 } 7382 7383 var bufferSource = ac.createBufferSource(); 7384 bufferSource.buffer = buffer; 7385 bufferSource.loop = true; 7386 return bufferSource; 7387 } 7388}).call(exports, __webpack_require__, exports, module), 7389 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7390 7391 }), 7392 (function(module, exports, __webpack_require__) { 7393 7394"use strict"; 7395var __WEBPACK_AMD_DEFINE_RESULT__; 7396 7397!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 7398 var p5sound = __webpack_require__(1); 7399 /** 7400 * Noise is a type of oscillator that generates a buffer with random values. 7401 * 7402 * @class p5.Noise 7403 * @extends p5.Oscillator 7404 * @constructor 7405 * @param {String} type Type of noise can be 'white' (default), 7406 * 'brown' or 'pink'. 7407 */ 7408 7409 7410 p5.Noise = function (type) { 7411 var assignType; 7412 p5.Oscillator.call(this); 7413 delete this.f; 7414 delete this.freq; 7415 delete this.oscillator; 7416 7417 if (type === 'brown') { 7418 assignType = _brownNoise; 7419 } else if (type === 'pink') { 7420 assignType = _pinkNoise; 7421 } else { 7422 assignType = _whiteNoise; 7423 } 7424 7425 this.buffer = assignType; 7426 }; 7427 7428 p5.Noise.prototype = Object.create(p5.Oscillator.prototype); 7429 7430 var _whiteNoise = function () { 7431 var bufferSize = 2 * p5sound.audiocontext.sampleRate; 7432 var whiteBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate); 7433 var noiseData = whiteBuffer.getChannelData(0); 7434 7435 for (var i = 0; i < bufferSize; i++) { 7436 noiseData[i] = Math.random() * 2 - 1; 7437 } 7438 7439 whiteBuffer.type = 'white'; 7440 return whiteBuffer; 7441 }(); 7442 7443 var _pinkNoise = function () { 7444 var bufferSize = 2 * p5sound.audiocontext.sampleRate; 7445 var pinkBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate); 7446 var noiseData = pinkBuffer.getChannelData(0); 7447 var b0, b1, b2, b3, b4, b5, b6; 7448 b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0; 7449 7450 for (var i = 0; i < bufferSize; i++) { 7451 var white = Math.random() * 2 - 1; 7452 b0 = 0.99886 * b0 + white * 0.0555179; 7453 b1 = 0.99332 * b1 + white * 0.0750759; 7454 b2 = 0.96900 * b2 + white * 0.1538520; 7455 b3 = 0.86650 * b3 + white * 0.3104856; 7456 b4 = 0.55000 * b4 + white * 0.5329522; 7457 b5 = -0.7616 * b5 - white * 0.0168980; 7458 noiseData[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; 7459 noiseData[i] *= 0.11; 7460 7461 b6 = white * 0.115926; 7462 } 7463 7464 pinkBuffer.type = 'pink'; 7465 return pinkBuffer; 7466 }(); 7467 7468 var _brownNoise = function () { 7469 var bufferSize = 2 * p5sound.audiocontext.sampleRate; 7470 var brownBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate); 7471 var noiseData = brownBuffer.getChannelData(0); 7472 var lastOut = 0.0; 7473 7474 for (var i = 0; i < bufferSize; i++) { 7475 var white = Math.random() * 2 - 1; 7476 noiseData[i] = (lastOut + 0.02 * white) / 1.02; 7477 lastOut = noiseData[i]; 7478 noiseData[i] *= 3.5; 7479 } 7480 7481 brownBuffer.type = 'brown'; 7482 return brownBuffer; 7483 }(); 7484 /** 7485 * Set type of noise to 'white', 'pink' or 'brown'. 7486 * White is the default. 7487 * 7488 * @method setType 7489 * @param {String} [type] 'white', 'pink' or 'brown' 7490 */ 7491 7492 7493 p5.Noise.prototype.setType = function (type) { 7494 switch (type) { 7495 case 'white': 7496 this.buffer = _whiteNoise; 7497 break; 7498 7499 case 'pink': 7500 this.buffer = _pinkNoise; 7501 break; 7502 7503 case 'brown': 7504 this.buffer = _brownNoise; 7505 break; 7506 7507 default: 7508 this.buffer = _whiteNoise; 7509 } 7510 7511 if (this.started) { 7512 var now = p5sound.audiocontext.currentTime; 7513 this.stop(now); 7514 this.start(now + .01); 7515 } 7516 }; 7517 7518 p5.Noise.prototype.getType = function () { 7519 return this.buffer.type; 7520 }; 7521 7522 p5.Noise.prototype.start = function () { 7523 if (this.started) { 7524 this.stop(); 7525 } 7526 7527 this.noise = p5sound.audiocontext.createBufferSource(); 7528 this.noise.buffer = this.buffer; 7529 this.noise.loop = true; 7530 this.noise.connect(this.output); 7531 var now = p5sound.audiocontext.currentTime; 7532 this.noise.start(now); 7533 this.started = true; 7534 }; 7535 7536 p5.Noise.prototype.stop = function () { 7537 var now = p5sound.audiocontext.currentTime; 7538 7539 if (this.noise) { 7540 this.noise.stop(now); 7541 this.started = false;
7542 } 7543 }; 7544 7545 p5.Noise.prototype.dispose = function () { 7546 var now = p5sound.audiocontext.currentTime; 7547 7548 var index = p5sound.soundArray.indexOf(this); 7549 p5sound.soundArray.splice(index, 1); 7550 7551 if (this.noise) { 7552 this.noise.disconnect(); 7553 this.stop(now); 7554 } 7555 7556 if (this.output) { 7557 this.output.disconnect(); 7558 } 7559 7560 if (this.panner) { 7561 this.panner.disconnect(); 7562 } 7563 7564 this.output = null; 7565 this.panner = null; 7566 this.buffer = null; 7567 this.noise = null; 7568 }; 7569}).call(exports, __webpack_require__, exports, module), 7570 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7571 7572 }), 7573 (function(module, exports, __webpack_require__) { 7574 7575"use strict"; 7576var __WEBPACK_AMD_DEFINE_RESULT__; 7577 7578!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 7579 var p5sound = __webpack_require__(1); 7580 7581 7582 p5sound.inputSources = []; 7583 /** 7584 * <p>Get audio from an input, i.e. your computer's microphone.</p> 7585 * 7586 * <p>Turn the mic on/off with the start() and stop() methods. When the mic 7587 * is on, its volume can be measured with getLevel or by connecting an 7588 * FFT object.</p> 7589 * 7590 * <p>If you want to hear the AudioIn, use the .connect() method. 7591 * AudioIn does not connect to p5.sound output by default to prevent 7592 * feedback.</p> 7593 * 7594 * <p><em>Note: This uses the <a href="http://caniuse.com/stream">getUserMedia/ 7595 * Stream</a> API, which is not supported by certain browsers. Access in Chrome browser 7596 * is limited to localhost and https, but access over http may be limited.</em></p> 7597 * 7598 * @class p5.AudioIn 7599 * @constructor 7600 * @param {Function} [errorCallback] A function to call if there is an error 7601 * accessing the AudioIn. For example, 7602 * Safari and iOS devices do not 7603 * currently allow microphone access. 7604 * @example 7605 * <div><code> 7606 * let mic; 7607 * 7608 * function setup(){ 7609 * let cnv = createCanvas(100, 100); 7610 * cnv.mousePressed(userStartAudio); 7611 * textAlign(CENTER); 7612 * mic = new p5.AudioIn(); 7613 * mic.start(); 7614 * } 7615 * 7616 * function draw(){ 7617 * background(0); 7618 * fill(255); 7619 * text('tap to start', width/2, 20); 7620 * 7621 * micLevel = mic.getLevel(); 7622 * let y = height - micLevel * height; 7623 * ellipse(width/2, y, 10, 10); 7624 * } 7625 * </code></div> 7626 */ 7627 7628 p5.AudioIn = function (errorCallback) { 7629 7630 /** 7631 * @property {GainNode} input 7632 */ 7633 this.input = p5sound.audiocontext.createGain(); 7634 /** 7635 * @property {GainNode} output 7636 */ 7637 7638 this.output = p5sound.audiocontext.createGain(); 7639 /** 7640 * @property {MediaStream|null} stream 7641 */ 7642 7643 this.stream = null; 7644 /** 7645 * @property {MediaStreamAudioSourceNode|null} mediaStream 7646 */ 7647 7648 this.mediaStream = null; 7649 /** 7650 * @property {Number|null} currentSource 7651 */ 7652 7653 this.currentSource = null; 7654 /** 7655 * Client must allow browser to access their microphone / audioin source. 7656 * Default: false. Will become true when the client enables access. 7657 * 7658 * @property {Boolean} enabled 7659 */ 7660 7661 this.enabled = false; 7662 /** 7663 * Input amplitude, connect to it by default but not to master out 7664 * 7665 * @property {p5.Amplitude} amplitude 7666 */ 7667 7668 this.amplitude = new p5.Amplitude(); 7669 this.output.connect(this.amplitude.input); 7670 7671 if (!window.MediaStreamTrack || !window.navigator.mediaDevices || !window.navigator.mediaDevices.getUserMedia) { 7672 errorCallback ? errorCallback() : window.alert('This browser does not support MediaStreamTrack and mediaDevices'); 7673 } 7674 7675 7676 p5sound.soundArray.push(this); 7677 }; 7678 /** 7679 * Start processing audio input. This enables the use of other 7680 * AudioIn methods like getLevel(). Note that by default, AudioIn 7681 * is not connected to p5.sound's output. So you won't hear 7682 * anything unless you use the connect() method.<br/> 7683 * 7684 * Certain browsers limit access to the user's microphone. For example, 7685 * Chrome only allows access from localhost and over https. For this reason, 7686 * you may want to include an errorCallback—a function that is called
7686in case 7687 * the browser won't provide mic access. 7688 * 7689 * @method start 7690 * @for p5.AudioIn 7691 * @param {Function} [successCallback] Name of a function to call on 7692 * success. 7693 * @param {Function} [errorCallback] Name of a function to call if 7694 * there was an error. For example, 7695 * some browsers do not support 7696 * getUserMedia. 7697 */ 7698 7699 7700 p5.AudioIn.prototype.start = function (successCallback, errorCallback) { 7701 var self = this; 7702 7703 if (this.stream) { 7704 this.stop(); 7705 } 7706 7707 7708 var audioSource = p5sound.inputSources[self.currentSource]; 7709 var constraints = { 7710 audio: { 7711 sampleRate: p5sound.audiocontext.sampleRate, 7712 echoCancellation: false 7713 } 7714 }; 7715 7716 if (p5sound.inputSources[this.currentSource]) { 7717 constraints.audio.deviceId = audioSource.deviceId; 7718 } 7719 7720 window.navigator.mediaDevices.getUserMedia(constraints).then(function (stream) { 7721 self.stream = stream; 7722 self.enabled = true; 7723 7724 self.mediaStream = p5sound.audiocontext.createMediaStreamSource(stream); 7725 self.mediaStream.connect(self.output); 7726 7727 self.amplitude.setInput(self.output); 7728 if (successCallback) successCallback(); 7729 })["catch"](function (err) { 7730 if (errorCallback) errorCallback(err);else console.error(err); 7731 }); 7732 }; 7733 /** 7734 * Turn the AudioIn off. If the AudioIn is stopped, it cannot getLevel(). 7735 * If re-starting, the user may be prompted for permission access. 7736 * 7737 * @method stop 7738 * @for p5.AudioIn 7739 */ 7740 7741 7742 p5.AudioIn.prototype.stop = function () { 7743 if (this.stream) { 7744 this.stream.getTracks().forEach(function (track) { 7745 track.stop(); 7746 }); 7747 this.mediaStream.disconnect(); 7748 delete this.mediaStream; 7749 delete this.stream; 7750 } 7751 }; 7752 /** 7753 * Connect to an audio unit. If no parameter is provided, will 7754 * connect to the master output (i.e. your speakers).<br/> 7755 * 7756 * @method connect 7757 * @for p5.AudioIn 7758 * @param {Object} [unit] An object that accepts audio input, 7759 * such as an FFT 7760 */ 7761 7762 7763 p5.AudioIn.prototype.connect = function (unit) { 7764 if (unit) { 7765 if (unit.hasOwnProperty('input')) { 7766 this.output.connect(unit.input); 7767 } else if (unit.hasOwnProperty('analyser')) { 7768 this.output.connect(unit.analyser); 7769 } else { 7770 this.output.connect(unit); 7771 } 7772 } else { 7773 this.output.connect(p5sound.input); 7774 } 7775 }; 7776 /** 7777 * Disconnect the AudioIn from all audio units. For example, if 7778 * connect() had been called, disconnect() will stop sending 7779 * signal to your speakers.<br/> 7780 * 7781 * @method disconnect 7782 * @for p5.AudioIn 7783 */ 7784 7785 7786 p5.AudioIn.prototype.disconnect = function () { 7787 if (this.output) { 7788 this.output.disconnect(); 7789 7790 this.output.connect(this.amplitude.input); 7791 } 7792 }; 7793 /** 7794 * Read the Amplitude (volume level) of an AudioIn. The AudioIn 7795 * class contains its own instance of the Amplitude class to help 7796 * make it easy to get a microphone's volume level. Accepts an 7797 * optional smoothing value (0.0 < 1.0). <em>NOTE: AudioIn must 7798 * .start() before using .getLevel().</em><br/> 7799 * 7800 * @method getLevel 7801 * @for p5.AudioIn 7802 * @param {Number} [smoothing] Smoothing is 0.0 by default. 7803 * Smooths values based on previous values. 7804 * @return {Number} Volume level (between 0.0 and 1.0) 7805 */ 7806 7807 7808 p5.AudioIn.prototype.getLevel = function (smoothing) { 7809 if (smoothing) { 7810 this.amplitude.smoothing = smoothing; 7811 } 7812 7813 return this.amplitude.getLevel(); 7814 }; 7815 /** 7816 * Set amplitude (volume) of a mic input between 0 and 1.0. <br/> 7817 * 7818 * @method amp 7819 * @for p5.AudioIn 7820 * @param {Number} vol between 0 and 1.0 7821 * @param {Number} [time] ramp time (optional) 7822 */ 7823 7824 7825 p5.AudioIn.prototype.amp = function (vol, t) { 7826 if (t) { 7827 var rampTime = t || 0; 7828 var currentVol = this.output.gain.value; 7829 this.output.gain.cancelScheduledValues(p5sound.audiocontext.currentTime); 7830 this.output.gain.setValueAtTime(currentVol, p5sound.audiocontext.currentTime); 7831 this.output.gain.linearRampToValueAtTime(vol, rampTime + p5sound.audiocontext.currentTime); 7832 } else { 7833 this.output.gain.cancelScheduledValues(p5sound.audiocontext.currentTime); 7834 this.output.gain.setValueAtTime(vol, p5sound.audiocontext.currentTime); 7835 } 7836 }; 7837 /** 7838 * Returns a list of available input sources. This is a wrapper 7839 * for <a title="MediaDevices.enumerateDevices() - Web APIs | MDN" target="_blank" href= 7840 * "https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices" 7841 * > and it returns a Promise. 7842 * 7843 * @method getSources 7844 * @for p5.AudioIn 7845 * @param {Function} [successCallback] This callback function handles the sources when they 7846 * have been enumerated. The callback function 7847 * receives the deviceList array as its only argument 7848 * @param {Function} [errorCallback] This optional callback receives the error 7849 * message as its argument. 7850 * @returns {Promise} Returns a Promise that can be used in place of the callbacks, similar 7851 * to the enumerateDevices() method 7852 * @example 7853 * <div><code> 7854 * let audioIn; 7855 * 7856 * function setup(){ 7857 * text('getting sources...', 0, 20); 7858 * audioIn = new p5.AudioIn(); 7859 * audioIn.getSources(gotSources); 7860 * } 7861 * 7862 * function gotSources(deviceList) { 7863 * if (deviceList.length > 0) { 7864 * //set the source to the first item in the deviceList array 7865 * audioIn.setSource(0);
7866 * let currentSource = deviceList[audioIn.currentSource]; 7867 * text('set source to: ' + currentSource.deviceId, 5, 20, width); 7868 * } 7869 * } 7870 * </code></div> 7871 */ 7872 7873 7874 p5.AudioIn.prototype.getSources = function (onSuccess, onError) { 7875 return new Promise(function (resolve, reject) { 7876 window.navigator.mediaDevices.enumerateDevices().then(function (devices) { 7877 p5sound.inputSources = devices.filter(function (device) { 7878 return device.kind === 'audioinput'; 7879 }); 7880 resolve(p5sound.inputSources); 7881 7882 if (onSuccess) { 7883 onSuccess(p5sound.inputSources); 7884 } 7885 })["catch"](function (error) { 7886 reject(error); 7887 7888 if (onError) { 7889 onError(error); 7890 } else { 7891 console.error('This browser does not support MediaStreamTrack.getSources()'); 7892 } 7893 }); 7894 }); 7895 }; 7896 /** 7897 * Set the input source. Accepts a number representing a 7898 * position in the array returned by getSources(). 7899 * This is only available in browsers that support 7900 * <a title="MediaDevices.enumerateDevices() - Web APIs | MDN" target="_blank" href= 7901 * "https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices" 7902 * >navigator.mediaDevices.enumerateDevices()</a>.<br/> 7903 * 7904 * @method setSource 7905 * @for p5.AudioIn 7906 * @param {number} num position of input source in the array 7907 * @example 7908 * <div><code> 7909 * let audioIn; 7910 * 7911 * function setup(){ 7912 * text('getting sources...', 0, 20); 7913 * audioIn = new p5.AudioIn(); 7914 * audioIn.getSources(gotSources); 7915 * } 7916 * 7917 * function gotSources(deviceList) { 7918 * if (deviceList.length > 0) { 7919 * //set the source to the first item in the deviceList array 7920 * audioIn.setSource(0); 7921 * let currentSource = deviceList[audioIn.currentSource]; 7922 * text('set source to: ' + currentSource.deviceId, 5, 20, width); 7923 * } 7924 * } 7925 * </code></div> 7926 */ 7927 7928 7929 p5.AudioIn.prototype.setSource = function (num) { 7930 if (p5sound.inputSources.length > 0 && num < p5sound.inputSources.length) { 7931 this.currentSource = num; 7932 console.log('set source to ', p5sound.inputSources[this.currentSource]); 7933 } else { 7934 console.log('unable to set input source'); 7935 } 7936 7937 7938 if (this.stream && this.stream.active) { 7939 this.start(); 7940 } 7941 }; 7942 7943 7944 p5.AudioIn.prototype.dispose = function () { 7945 var index = p5sound.soundArray.indexOf(this); 7946 p5sound.soundArray.splice(index, 1); 7947 this.stop(); 7948 7949 if (this.output) { 7950 this.output.disconnect(); 7951 } 7952 7953 if (this.amplitude) { 7954 this.amplitude.disconnect(); 7955 } 7956 7957 delete this.amplitude; 7958 delete this.output; 7959 }; 7960}).call(exports, __webpack_require__, exports, module), 7961 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7962 7963 }), 7964 (function(module, exports, __webpack_require__) { 7965 7966var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(2),__webpack_require__(52),__webpack_require__(58),__webpack_require__(9)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(i){"use strict";return i.CrossFade=function(e){this.createInsOuts(2,1),this.a=this.input[0]=new i.Gain,this.b=this.input[1]=new i.Gain,this.fade=new i.Signal(this.defaultArg(e,.5),i.Type.NormalRange),this._equalPowerA=new i.EqualPowerGain,this._equalPowerB=new i.EqualPowerGain,this._invert=new i.Expr("1 - $0"),this.a.connect(this.output),this.b.connect(this.output),this.fade.chain(this._equalPowerB,this.b.gain),this.fade.chain(this._invert,this._equalPowerA,this.a.gain),this._readOnly("fade")},i.extend(i.CrossFade),i.CrossFade.prototype.dispose=function(){return i.prototype.dispose.call(this),this._writable("fade"),this._equalPowerA.dispose(),this._equalPowerA=null,this._equalPowerB.dispose(),this._equalPowerB=null,this.fade.dispose(),this.fade=null,this._invert.dispose(),this._invert=null,this.a.dispose(),this.a=null,this.b.dispose(),this.b=null,this},i.CrossFade}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 7967 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7968 7969 }), 7970 (function(module, exports, __webpack_require__) { 7971 7972var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(7),__webpack_require__(16),__webpack_require__(3),__webpack_require__(53),__webpack_require__(26),__webpack_require__(54),__webpack_require__(25),__webpack_require__(55),__webpack_require__(56),__webpack_require__(57)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(p){"use strict";function r(e,n,r){var t=new e;return r._eval(n[0]).connect(t,0,0),r._eval(n[1]).connect(t,0,1),t}function t(e,n,r){var t=new e;return r._eval(n[0]).connect(t,0,0),t}function o(e){return e?parseFloat(e):void 0}function i(e){return e&&e.args?parseFloat(e.args):void 0}return p.Expr=function(){var n=this._replacements(Array.prototype.slice.call(arguments)),e=this._parseInputs(n);this._nodes=[],this.input=new Array(e);for(var r=0;r<e;r++)this.input[r]=this.context.createGain();var t,o=this._parseTree(n);try{t=this._eval(o)}catch(e){throw this._disposeNodes(),new Error("Tone.Expr: Could evaluate expression: "+n)}this.output=t},p.extend(p.Expr,p.SignalBase),p.Expr._Expressions={value:{signal:{regexp:/^\d+\.\d+|^\d+/,method:function(e){return new p.Signal(o(e))}},input:{regexp:/^\$\d/,method:function(e,n){return n.input[o(e.substr(1))]}}},glue:{"(":{regexp:/^\(/},")":{regexp:/^\)/},",":{regexp:/^,/}},func:{abs:{regexp:/^abs/,method:t.bind(this,p.Abs)},mod:{regexp:/^mod/,method:function(e,n){var r=i(e[1]),t=new p.Modulo(r);return n._eval(e[0]).connect(t),t}},pow:{regexp:/^pow/,method:function(e,n){var r=i(e[1]),t=new p.Pow(r);return n._eval(e[0]).connect(t),t}},a2g:{regexp:/^a2g/,method:function(e,n){var r=new p.AudioToGain;return n._eval(e[0]).connect(r),r}}},binary:{"+":{regexp:/^\+/,precedence:1,method:r.bind(this,p.Add)},"-":{regexp:/^\-/,precedence:1,method:function(e,n){return 1===e.length?t(p.Negate,e,n):r(p.Subtract,e,n)}},"*":{regexp:/^\*/,precedence:0,method:r.bind(this,p.Multiply)}},unary:{"-":{regexp:/^\-/,method:t.bind(this,p.Negate)},"!":{regexp:/^\!/,method:t.bind(this,p.NOT)}}},p.Expr.prototype._parseInputs=function(e){var n=e.match(/\$\d/g),r=0;if(null!==n)for(var t=0;t<n.length;t++){var o=parseInt(n[t].substr(1))+1;r=Math.max(r,o)}return r},p.Expr.prototype._replacements=function(e){for(var n=e.shift(),r=0;r<e.length;r++)n=n.replace(/\%/i,e[r]);return n},p.Expr.prototype._tokenize=function(e){for(var n=-1,r=[];0<e.length;){var t=o(e=e.trim());r.push(t),e=e.substr(t.value.length)}function o(e){for(var n in p.Expr._Expressions){var r=p.Expr._Expressions[n];for(var t in r){var o=r[t],i=o.regexp,a=e.match(i);if(null!==a)return{type:n,value:a[0],method:o.method}}}throw new SyntaxError("Tone.Expr: Unexpected token "+e)}return{next:function(){return r[++n]},peek:function(){return r[n+1]}}},p.Expr.prototype._parseTree=function(e){var t=this._tokenize(e),a=this.isUndef.bind(this);function r(e,n){return!a(e)&&"glue"===e.type&&e.value===n}
7972function o(e,n,r){var t=p.Expr._Expressions[n];if(!a(e))for(var o in t){var i=t[o];if(i.regexp.test(e.value)){if(a(r))return!0;if(i.precedence===r)return!0}}return!1}function i(e){var n;a(e)&&(e=5),n=e<0?function e(){var n,r;n=t.peek();if(o(n,"unary"))return n=t.next(),r=e(),{operator:n.value,method:n.method,args:[r]};return s()}():i(e-1);for(var r=t.peek();o(r,"binary",e);)n={operator:(r=t.next()).value,method:r.method,args:[n,i(e-1)]},r=t.peek();return n}function s(){var e,n;if(e=t.peek(),a(e))throw new SyntaxError("Tone.Expr: Unexpected termination of expression");if("func"===e.type)return function(e){var n=[];if(!r(t.next(),"("))throw new SyntaxError('Tone.Expr: Expected ( in a function call "'+e.value+'"');r(t.peek(),")")||(n=function(){var e,n=[];for(;e=i(),!a(e)&&(n.push(e),r(t.peek(),","));)t.next();return n}());if(r(t.next(),")"))return{method:e.method,args:n,name:name};throw new SyntaxError('Tone.Expr: Expected ) in a function call "'+e.value+'"')}(e=t.next());if("value"===e.type)return{method:(e=t.next()).method,args:e.value};if(r(e,"(")){if(t.next(),n=i(),!r(e=t.next(),")"))throw new SyntaxError("Expected )");return n}throw new SyntaxError("Tone.Expr: Parse error, cannot process token "+e.value)}return i()},p.Expr.prototype._eval=function(e){if(!this.isUndef(e)){var n=e.method(e.args,this);return this._nodes.push(n),n}},p.Expr.prototype._disposeNodes=function(){for(var e=0;e<this._nodes.length;e++){var n=this._nodes[e];this.isFunction(n.dispose)?n.dispose():this.isFunction(n.disconnect)&&n.disconnect(),n=null,this._nodes[e]=null}this._nodes=null},p.Expr.prototype.dispose=function(){p.prototype.dispose.call(this),this._disposeNodes()},p.Expr}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 7973 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7974 7975 }), 7976 (function(module, exports, __webpack_require__) { 7977 7978var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(26),__webpack_require__(16),__webpack_require__(2)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(e){"use strict";return e.GreaterThan=function(t){this.createInsOuts(2,0),this._param=this.input[0]=new e.Subtract(t),this.input[1]=this._param.input[1],this._gtz=this.output=new e.GreaterThanZero,this._param.connect(this._gtz)},e.extend(e.GreaterThan,e.Signal),e.GreaterThan.prototype.dispose=function(){return e.prototype.dispose.call(this),this._param.dispose(),this._param=null,this._gtz.dispose(),this._gtz=null,this},e.GreaterThan}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 7979 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7980 7981 }), 7982 (function(module, exports, __webpack_require__) { 7983 7984var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(5),__webpack_require__(19)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(s){"use strict";return s.Abs=function(){this._abs=this.input=this.output=new s.WaveShaper(function(s){return 0===s?0:Math.abs(s)},127)},s.extend(s.Abs,s.SignalBase),s.Abs.prototype.dispose=function(){return s.prototype.dispose.call(this),this._abs.dispose(),this._abs=null,this},s.Abs}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 7985 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7986 7987 }), 7988 (function(module, exports, __webpack_require__) { 7989 7990var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(5),__webpack_require__(3),__webpack_require__(16)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(i){"use strict";return i.Modulo=function(t){this.createInsOuts(1,0),this._shaper=new i.WaveShaper(Math.pow(2,16)),this._multiply=new i.Multiply,this._subtract=this.output=new i.Subtract,this._modSignal=new i.Signal(t),this.input.fan(this._shaper,this._subtract),this._modSignal.connect(this._multiply,0,0),this._shaper.connect(this._multiply,0,1),this._multiply.connect(this._subtract,0,1),this._setWaveShaper(t)},i.extend(i.Modulo,i.SignalBase),i.Modulo.prototype._setWaveShaper=function(i){this._shaper.setMap(function(t){return Math.floor((t+1e-4)/i)})}
7990,Object.defineProperty(i.Modulo.prototype,"value",{get:function(){return this._modSignal.value},set:function(t){this._modSignal.value=t,this._setWaveShaper(t)}}),i.Modulo.prototype.dispose=function(){return i.prototype.dispose.call(this),this._shaper.dispose(),this._shaper=null,this._multiply.dispose(),this._multiply=null,this._subtract.dispose(),this._subtract=null,this._modSignal.dispose(),this._modSignal=null,this},i.Modulo}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 7991 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7992 7993 }), 7994 (function(module, exports, __webpack_require__) { 7995 7996var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(5)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(t){"use strict";return t.Pow=function(e){this._exp=this.defaultArg(e,1),this._expScaler=this.input=this.output=new t.WaveShaper(this._expFunc(this._exp),8192)},t.extend(t.Pow,t.SignalBase),Object.defineProperty(t.Pow.prototype,"value",{get:function(){return this._exp},set:function(e){this._exp=e,this._expScaler.setMap(this._expFunc(this._exp))}}),t.Pow.prototype._expFunc=function(t){return function(e){return Math.pow(Math.abs(e),t)}},t.Pow.prototype.dispose=function(){return t.prototype.dispose.call(this),this._expScaler.dispose(),this._expScaler=null,this},t.Pow}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 7997 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 7998 7999 }), 8000 (function(module, exports, __webpack_require__) { 8001 8002var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(5),__webpack_require__(2)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(n){"use strict";return n.AudioToGain=function(){this._norm=this.input=this.output=new n.WaveShaper(function(n){return(n+1)/2})},n.extend(n.AudioToGain,n.SignalBase),n.AudioToGain.prototype.dispose=function(){return n.prototype.dispose.call(this),this._norm.dispose(),this._norm=null,this},n.AudioToGain}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 8003 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 8004 8005 }), 8006 (function(module, exports, __webpack_require__) { 8007 8008var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(5)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(e){"use strict";return e.EqualPowerGain=function(){this._eqPower=this.input=this.output=new e.WaveShaper(function(e){return Math.abs(e)<.001?0:this.equalPowerScale(e)}.bind(this),4096)},e.extend(e.EqualPowerGain,e.SignalBase),e.EqualPowerGain.prototype.dispose=function(){return e.prototype.dispose.call(this),this._eqPower.dispose(),this._eqPower=null,this},e.EqualPowerGain}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 8009 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 8010 8011 }), 8012 (function(module, exports, __webpack_require__) { 8013 8014"use strict"; 8015var __WEBPACK_AMD_DEFINE_RESULT__; 8016 8017!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 8018 var Effect = __webpack_require__(4); 8019 8020 var EQFilter = __webpack_require__(60); 8021 /** 8022 * p5.EQ is an audio effect that performs the function of a multiband 8023 * audio equalizer. Equalization is used to adjust the balance of 8024 * frequency compoenents of an audio signal. This process is commonly used 8025 * in sound production and recording to change the waveform before it reaches 8026 * a sound output device. EQ can also be used as an audio effect to create 8027 * interesting distortions by filtering out parts of the spectrum. p5.EQ is 8028 * built using a chain of Web Audio Biquad Filter Nodes and can be 8029 * instantiated with 3 or 8 bands. Bands can be added or removed from 8030 * the EQ by directly modifying p5.EQ.bands (the array that stores filters). 8031 * 8032 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 8033 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 8034 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 8035 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 8036 * 8037 * @class p5.EQ 8038 * @constructor
8039 * @extends p5.Effect 8040 * @param {Number} [_eqsize] Constructor will accept 3 or 8, defaults to 3 8041 * @return {Object} p5.EQ object 8042 * 8043 * @example 8044 * <div><code> 8045 * let eq, soundFile 8046 * let eqBandIndex = 0; 8047 * let eqBandNames = ['lows', 'mids', 'highs']; 8048 * 8049 * function preload() { 8050 * soundFormats('mp3', 'ogg'); 8051 * soundFile = loadSound('assets/beat'); 8052 * } 8053 * 8054 * function setup() { 8055 * let cnv = createCanvas(100, 100); 8056 * cnv.mousePressed(toggleSound); 8057 * 8058 * eq = new p5.EQ(eqBandNames.length); 8059 * soundFile.disconnect(); 8060 * eq.process(soundFile); 8061 * } 8062 * 8063 * function draw() { 8064 * background(30); 8065 * noStroke(); 8066 * fill(255); 8067 * textAlign(CENTER); 8068 * text('filtering ', 50, 25); 8069 * 8070 * fill(255, 40, 255); 8071 * textSize(26); 8072 * text(eqBandNames[eqBandIndex], 50, 55); 8073 * 8074 * fill(255); 8075 * textSize(9); 8076 * 8077 * if (!soundFile.isPlaying()) { 8078 * text('tap to play', 50, 80); 8079 * } else { 8080 * text('tap to filter next band', 50, 80) 8081 * } 8082 * } 8083 * 8084 * function toggleSound() { 8085 * if (!soundFile.isPlaying()) { 8086 * soundFile.play(); 8087 * } else { 8088 * eqBandIndex = (eqBandIndex + 1) % eq.bands.length; 8089 * } 8090 * 8091 * for (let i = 0; i < eq.bands.length; i++) { 8092 * eq.bands[i].gain(0); 8093 * } 8094 * // filter the band we want to filter 8095 * eq.bands[eqBandIndex].gain(-40); 8096 * } 8097 * </code></div> 8098 */ 8099 8100 8101 p5.EQ = function (_eqsize) { 8102 Effect.call(this); 8103 8104 _eqsize = _eqsize === 3 || _eqsize === 8 ? _eqsize : 3; 8105 var factor; 8106 _eqsize === 3 ? factor = Math.pow(2, 3) : factor = 2; 8107 /** 8108 * The p5.EQ is built with abstracted p5.Filter objects. 8109 * To modify any bands, use methods of the <a 8110 * href="/reference/#/p5.Filter" title="p5.Filter reference"> 8111 * p5.Filter</a> API, especially `gain` and `freq`. 8112 * Bands are stored in an array, with indices 0 - 3, or 0 - 7 8113 * @property {Array} bands 8114 * 8115 */ 8116 8117 this.bands = []; 8118 var freq, res; 8119 8120 for (var i = 0; i < _eqsize; i++) { 8121 if (i === _eqsize - 1) { 8122 freq = 21000; 8123 res = .01; 8124 } else if (i === 0) { 8125 freq = 100; 8126 res = .1; 8127 } else if (i === 1) { 8128 freq = _eqsize === 3 ? 360 * factor : 360; 8129 res = 1; 8130 } else { 8131 freq = this.bands[i - 1].freq() * factor; 8132 res = 1; 8133 } 8134 8135 this.bands[i] = this._newBand(freq, res); 8136 8137 if (i > 0) { 8138 this.bands[i - 1].connect(this.bands[i].biquad); 8139 } else { 8140 this.input.connect(this.bands[i].biquad); 8141 } 8142 } 8143 8144 this.bands[_eqsize - 1].connect(this.output); 8145 }; 8146 8147 p5.EQ.prototype = Object.create(Effect.prototype); 8148 /** 8149 * Process an input by connecting it to the EQ 8150 * @method process 8151 * @param {Object} src Audio source 8152 */ 8153 8154 p5.EQ.prototype.process = function (src) { 8155 src.connect(this.input); 8156 }; 8157 // * Set the frequency and gain of each band in the EQ. This method should be 8158 // * called with 3 or 8 frequency and gain pairs, depending on the size of the EQ. 8159 // * ex. eq.set(freq0, gain0, freq1, gain1, freq2, gain2); 8160 // * 8161 // * @method set 8162 // * @for p5.EQ 8163 // * @param {Number} [freq0] Frequency value for band with index 0 8164 // * @param {Number} [gain0] Gain value for band with index 0 8165 // * @param {Number} [freq1] Frequency value for band with index 1 8166 // * @param {Number} [gain1] Gain value for band with index 1 8167 // * @param {Number} [freq2] Frequency value for band with index 2 8168 // * @param {Number} [gain2] Gain value for band with index 2 8169 // * @param {Number} [freq3] Frequency value for band with index 3 8170 // * @param {Number} [gain3] Gain value for band with index 3 8171 // * @param {Number} [freq4] Frequency value for band with index 4 8172 // * @param {Number} [gain4] Gain value for band with index 4 8173 // * @param {Number} [freq5] Frequency value for band with index 5 8174 // * @param {Number} [gain5] Gain value for band with index 5 8175 // * @param {Number} [freq6] Frequency value for band with index 6 8176 // * @param {Number} [gain6] Gain value for band with index 6 8177 // * @param {Number} [freq7] Frequency value for band with index 7 8178 // * @param {Number} [gain7] Gain value for band with index 7 8179 // */ 8180 8181 8182 p5.EQ.prototype.set = function () { 8183 if (arguments.length === this.bands.length * 2) { 8184 for (var i = 0; i < arguments.length; i += 2) { 8185 this.bands[i / 2].freq(arguments[i]); 8186 this.bands[i / 2].gain(arguments[i + 1]); 8187 } 8188 } else { 8189 console.error('Argument mismatch. .set() should be called with ' + this.bands.length * 2 + ' arguments. (one frequency and gain value pair for each band of the eq)'); 8190 } 8191 }; 8192 /** 8193 * Add a new band. Creates a p5.Filter and strips away everything but 8194 * the raw biquad filter. This method returns an abstracted p5.Filter, 8195 * which can be added to p5.EQ.bands, in order to create new EQ bands. 8196 * @private 8197 * @for p5.EQ 8198 * @method _newBand 8199 * @param {Number} freq 8200 * @param {Number} res 8201 * @return {Object} Abstracted Filter 8202 */ 8203 8204 8205 p5.EQ.prototype._newBand = function (freq, res) { 8206 return new EQFilter(freq, res); 8207 }; 8208 8209 p5.EQ.prototype.dispose = function () { 8210 Effect.prototype.dispose.apply(this); 8211 8212 if (this.bands) { 8213 while (this.bands.length > 0) { 8214 delete this.bands.pop().dispose(); 8215 } 8216 8217 delete this.bands; 8218 } 8219 }; 8220 8221 return p5.EQ; 8222}).call(exports, __webpack_require__, exports, module), 8223 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 8224 8225 }), 8226 (function(module, exports, __webpack_require__) { 8227 8228"use strict"; 8229var __WEBPACK_AMD_DEFINE_RESULT__; 8230 8231!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 8232 var Filter = __webpack_require__(15); 8233 8234 var p5sound = __webpack_require__(1); 8235 /** 8236 * EQFilter extends p5.Filter with constraints 8237 * necessary for the p5.EQ 8238 * 8239 * @private 8240 */ 8241 8242 8243 var EQFilter = function EQFilter(freq, res) { 8244 Filter.call(this, 'peaking'); 8245 this.disconnect(); 8246 this.set(freq, res); 8247 this.biquad.gain.value = 0; 8248 delete this.input; 8249 delete this.output; 8250 delete this._drywet; 8251 delete this.wet; 8252 }; 8253 8254 EQFilter.prototype = Object.create(Filter.prototype); 8255 8256 EQFilter.prototype.amp = function () { 8257 console.warn('`amp()` is not available for p5.EQ bands. Use `.gain()`'); 8258 }; 8259 8260 EQFilter.prototype.drywet = function () { 8261 console.warn('`drywet()` is not available for p5.EQ bands.'); 8262 }; 8263 8264 EQFilter.prototype.connect = function (unit) { 8265 var u = unit || p5.soundOut.input; 8266 8267 if (this.biquad) { 8268 this.biquad.connect(u.input ? u.input : u); 8269 } else { 8270 this.output.connect(u.input ? u.input : u); 8271 } 8272 }; 8273 8274 EQFilter.prototype.disconnect = function () { 8275 if (this.biquad) { 8276 this.biquad.disconnect(); 8277 } 8278 }; 8279 8280 EQFilter.prototype.dispose = function () { 8281 var index = p5sound.soundArray.indexOf(this); 8282 p5sound.soundArray.splice(index, 1); 8283 this.disconnect(); 8284 delete this.biquad; 8285 }; 8286 8287 return EQFilter; 8288}).call(exports, __webpack_require__, exports, module), 8289 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 8290 8291 }), 8292 (function(module, exports, __webpack_require__) { 8293 8294"use strict"; 8295var __WEBPACK_AMD_DEFINE_RESULT__; 8296 8297!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 8298 var p5sound = __webpack_require__(1); 8299 8300 var Effect = __webpack_require__(4); 8301 /** 8302 * Panner3D is based on the <a title="Web Audio Panner docs" href= 8303 * "https://developer.mozilla.org/en-US/docs/Web/API/PannerNode"> 8304 * Web Audio Spatial Panner Node</a>. 8305 * This panner is a spatial processing node that allows audio to be positioned 8306 * and oriented in 3D space. 8307 * 8308 * The position is relative to an <a title="Web Audio Listener docs" href= 8309 * "https://developer.mozilla.org/en-US/docs/Web/API/AudioListener"> 8310 * Audio Context Listener</a>, which can be accessed 8311 * by <code>p5.soundOut.audiocontext.listener</code> 8312 * 8313 * 8314 * @class p5.Panner3D 8315 * @constructor 8316 */ 8317 8318 8319 p5.Panner3D = function () { 8320 Effect.call(this); 8321 /** 8322 * <a title="Web Audio Panner docs" href= 8323 * "https://developer.mozilla.org/en-US/docs/Web/API/PannerNode"> 8324 * Web Audio Spatial Panner Node</a> 8325 * 8326 * Properties include 8327 * - <a title="w3 spec for Panning Model" 8328 * href="https://www.w3.org/TR/webaudio/#idl-def-PanningModelType" 8329 * >panningModel</a>: "equal power" or "HRTF" 8330 * - <a title="w3 spec for Distance Model" 8331 * href="https://www.w3.org/TR/webaudio/#idl-def-DistanceModelType" 8332 * >distanceModel</a>: "linear", "inverse", or "exponential" 8333 * 8334 * @property {AudioNode} panner 8335 * 8336 */ 8337 8338 this.panner = this.ac.createPanner(); 8339 this.panner.panningModel = 'HRTF'; 8340 this.panner.distanceModel = 'linear'; 8341 this.panner.connect(this.output); 8342 this.input.connect(this.panner); 8343 }; 8344 8345 p5.Panner3D.prototype = Object.create(Effect.prototype); 8346 /** 8347 * Connect an audio sorce 8348 * 8349 * @method process 8350 * @for p5.Panner3D 8351 * @param {Object} src Input source 8352 */ 8353 8354 p5.Panner3D.prototype.process = function (src) { 8355 src.connect(this.input); 8356 }; 8357 /** 8358 * Set the X,Y,Z position of the Panner 8359 * @method set 8360 * @for p5.Panner3D 8361 * @param {Number} xVal 8362 * @param {Number} yVal 8363 * @param {Number} zVal 8364 * @param {Number} time 8365 * @return {Array} Updated x, y, z values as an array 8366 */ 8367 8368 8369 p5.Panner3D.prototype.set = function (xVal, yVal, zVal, time) { 8370 this.positionX(xVal, time); 8371 this.positionY(yVal, time); 8372 this.positionZ(zVal, time); 8373 return [this.panner.positionX.value, this.panner.positionY.value, this.panner.positionZ.value]; 8374 }; 8375 /** 8376 * Getter and setter methods for position coordinates 8377 * @method positionX 8378 * @for p5.Panner3D 8379 * @return {Number} updated coordinate value 8380 */ 8381 8382 /** 8383 * Getter and setter methods for position coordinates 8384 * @method positionY 8385 * @for p5.Panner3D 8386 * @return {Number} updated coordinate value 8387 */ 8388 8389 /** 8390 * Getter and setter methods for position coordinates 8391 * @method positionZ 8392 * @for p5.Panner3D 8393 * @return {Number} updated coordinate value 8394 */ 8395 8396 8397 p5.Panner3D.prototype.positionX = function (xVal, time) { 8398 var t = time || 0; 8399 8400 if (typeof xVal === 'number') { 8401 this.panner.positionX.value = xVal; 8402 this.panner.positionX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8403 this.panner.positionX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 8404 } else if (xVal) { 8405 xVal.connect(this.panner.positionX); 8406 } 8407 8408 return this.panner.positionX.value; 8409 }; 8410 8411 p5.Panner3D.prototype.positionY = function (yVal, time) { 8412 var t = time || 0; 8413 8414 if (typeof yVal === 'number') { 8415 this.panner.positionY.value = yVal; 8416 this.panner.positionY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8417 this.panner.positionY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 8418 } else if (yVal) { 8419 yVal.connect(this.panner.positionY); 8420 } 8421 8422 return this.panner.positionY.value; 8423 }; 8424 8425 p5.Panner3D.prototype.positionZ = function (zVal, time) { 8426 var t = time || 0; 8427 8428 if (typeof zVal === 'number') { 8429 this.panner.positionZ.value = zVal; 8430 this.panner.positionZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8431 this.panner.positionZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 8432 } else if (zVal) {
8433 zVal.connect(this.panner.positionZ); 8434 } 8435 8436 return this.panner.positionZ.value; 8437 }; 8438 /** 8439 * Set the X,Y,Z position of the Panner 8440 * @method orient 8441 * @for p5.Panner3D 8442 * @param {Number} xVal 8443 * @param {Number} yVal 8444 * @param {Number} zVal 8445 * @param {Number} time 8446 * @return {Array} Updated x, y, z values as an array 8447 */ 8448 8449 8450 p5.Panner3D.prototype.orient = function (xVal, yVal, zVal, time) { 8451 this.orientX(xVal, time); 8452 this.orientY(yVal, time); 8453 this.orientZ(zVal, time); 8454 return [this.panner.orientationX.value, this.panner.orientationY.value, this.panner.orientationZ.value]; 8455 }; 8456 /** 8457 * Getter and setter methods for orient coordinates 8458 * @method orientX 8459 * @for p5.Panner3D 8460 * @return {Number} updated coordinate value 8461 */ 8462 8463 /** 8464 * Getter and setter methods for orient coordinates 8465 * @method orientY 8466 * @for p5.Panner3D 8467 * @return {Number} updated coordinate value 8468 */ 8469 8470 /** 8471 * Getter and setter methods for orient coordinates 8472 * @method orientZ 8473 * @for p5.Panner3D 8474 * @return {Number} updated coordinate value 8475 */ 8476 8477 8478 p5.Panner3D.prototype.orientX = function (xVal, time) { 8479 var t = time || 0; 8480 8481 if (typeof xVal === 'number') { 8482 this.panner.orientationX.value = xVal; 8483 this.panner.orientationX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8484 this.panner.orientationX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 8485 } else if (xVal) { 8486 xVal.connect(this.panner.orientationX); 8487 } 8488 8489 return this.panner.orientationX.value; 8490 }; 8491 8492 p5.Panner3D.prototype.orientY = function (yVal, time) { 8493 var t = time || 0; 8494 8495 if (typeof yVal === 'number') { 8496 this.panner.orientationY.value = yVal; 8497 this.panner.orientationY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8498 this.panner.orientationY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 8499 } else if (yVal) { 8500 yVal.connect(this.panner.orientationY); 8501 } 8502 8503 return this.panner.orientationY.value; 8504 }; 8505 8506 p5.Panner3D.prototype.orientZ = function (zVal, time) { 8507 var t = time || 0; 8508 8509 if (typeof zVal === 'number') { 8510 this.panner.orientationZ.value = zVal; 8511 this.panner.orientationZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8512 this.panner.orientationZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 8513 } else if (zVal) { 8514 zVal.connect(this.panner.orientationZ); 8515 } 8516 8517 return this.panner.orientationZ.value; 8518 }; 8519 /** 8520 * Set the rolloff factor and max distance 8521 * @method setFalloff 8522 * @for p5.Panner3D 8523 * @param {Number} [maxDistance] 8524 * @param {Number} [rolloffFactor] 8525 */ 8526 8527 8528 p5.Panner3D.prototype.setFalloff = function (maxDistance, rolloffFactor) { 8529 this.maxDist(maxDistance); 8530 this.rolloff(rolloffFactor); 8531 }; 8532 /** 8533 * Maxium distance between the source and the listener 8534 * @method maxDist 8535 * @for p5.Panner3D 8536 * @param {Number} maxDistance 8537 * @return {Number} updated value 8538 */ 8539 8540 8541 p5.Panner3D.prototype.maxDist = function (maxDistance) { 8542 if (typeof maxDistance === 'number') { 8543 this.panner.maxDistance = maxDistance; 8544 } 8545 8546 return this.panner.maxDistance; 8547 }; 8548 /** 8549 * How quickly the volume is reduced as the source moves away from the listener 8550 * @method rollof 8551 * @for p5.Panner3D 8552 * @param {Number} rolloffFactor 8553 * @return {Number} updated value 8554 */ 8555 8556 8557 p5.Panner3D.prototype.rolloff = function (rolloffFactor) { 8558 if (typeof rolloffFactor === 'number') { 8559 this.panner.rolloffFactor = rolloffFactor; 8560 } 8561 8562 return this.panner.rolloffFactor; 8563 }; 8564 8565 p5.Panner3D.dispose = function () { 8566 Effect.prototype.dispose.apply(this); 8567 8568 if (this.panner) { 8569 this.panner.disconnect(); 8570 delete this.panner; 8571 } 8572 }; 8573 8574 return p5.Panner3D; 8575}).call(exports, __webpack_require__, exports, module), 8576 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 8577 8578 }), 8579 (function(module, exports, __webpack_require__) { 8580 8581"use strict"; 8582var __WEBPACK_AMD_DEFINE_RESULT__; 8583 8584!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 8585 var p5sound = __webpack_require__(1); 8586 8587 var Effect = __webpack_require__(4); 8588 // * listener is a class that can construct both a Spatial Panner 8589 // * and a Spatial Listener. The panner is based on the 8590 // * Web Audio Spatial Panner Node 8591 // * https://www.w3.org/TR/webaudio/#the-listenernode-interface 8592 // * This panner is a spatial processing node that allows audio to be positioned 8593 // * and oriented in 3D space. 8594 // * 8595 // * The Listener modifies the properties of the Audio Context Listener. 8596 // * Both objects types use the same methods. The default is a spatial panner. 8597 // * 8598 // * <code>p5.Panner3D</code> - Constructs a Spatial Panner<br/> 8599 // * <code>p5.Listener3D</code> - Constructs a Spatial Listener<br/> 8600 // * 8601 // * @class listener 8602 // * @constructor 8603 // * @return {Object} p5.Listener3D Object 8604 // * 8605 // * @param {Web Audio Node} listener Web Audio Spatial Panning Node 8606 // * @param {AudioParam} listener.panningModel "equal power" or "HRTF" 8607 // * @param {AudioParam} listener.distanceModel "linear", "inverse", or "exponential" 8608 // * @param {String} [type] [Specify construction of a spatial panner or listener] 8609 // */ 8610 8611 8612 p5.Listener3D = function (type) { 8613 this.ac = p5sound.audiocontext; 8614 this.listener = this.ac.listener; 8615 }; 8616 // * Connect an audio sorce 8617 // * @param {Object} src Input source 8618 // */ 8619 8620 8621 p5.Listener3D.prototype.process = function (src) { 8622 src.connect(this.input); 8623 }; 8624 // * Set the X,Y,Z position of the Panner 8625 // * @param {[Number]} xVal 8626 // * @param {[Number]} yVal 8627 // * @param {[Number]} zVal 8628 // * @param {[Number]} time 8629 // * @return {[Array]} [Updated x, y, z values as an array] 8630 // */ 8631 8632 8633 p5.Listener3D.prototype.position = function (xVal, yVal, zVal, time) { 8634 this.positionX(xVal, time); 8635 this.positionY(yVal, time); 8636 this.positionZ(zVal, time); 8637 return [this.listener.positionX.value, this.listener.positionY.value, this.listener.positionZ.value]; 8638 }; 8639 // * Getter and setter methods for position coordinates 8640 // * @return {Number} [updated coordinate value] 8641 // */ 8642 8643 8644 p5.Listener3D.prototype.positionX = function (xVal, time) { 8645 var t = time || 0; 8646 8647 if (typeof xVal === 'number') { 8648 this.listener.positionX.value = xVal; 8649 this.listener.positionX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8650 this.listener.positionX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 8651 } else if (xVal) { 8652 xVal.connect(this.listener.positionX); 8653 } 8654 8655 return this.listener.positionX.value; 8656 }; 8657 8658 p5.Listener3D.prototype.positionY = function (yVal, time) { 8659 var t = time || 0; 8660 8661 if (typeof yVal === 'number') { 8662 this.listener.positionY.value = yVal; 8663 this.listener.positionY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8664 this.listener.positionY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 8665 } else if (yVal) { 8666 yVal.connect(this.listener.positionY); 8667 } 8668 8669 return this.listener.positionY.value; 8670 }; 8671 8672 p5.Listener3D.prototype.positionZ = function (zVal, time) { 8673 var t = time || 0; 8674 8675 if (typeof zVal === 'number') { 8676 this.listener.positionZ.value = zVal; 8677 this.listener.positionZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8678 this.listener.positionZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 8679 } else if (zVal) {
8680 zVal.connect(this.listener.positionZ); 8681 } 8682 8683 return this.listener.positionZ.value; 8684 }; 8685 // * Overrides the listener orient() method because Listener has slightly 8686 // * different params. In human terms, Forward vectors are the direction the 8687 // * nose is pointing. Up vectors are the direction of the top of the head. 8688 // * 8689 // * @method orient 8690 // * @param {Number} xValF Forward vector X direction 8691 // * @param {Number} yValF Forward vector Y direction 8692 // * @param {Number} zValF Forward vector Z direction 8693 // * @param {Number} xValU Up vector X direction 8694 // * @param {Number} yValU Up vector Y direction 8695 // * @param {Number} zValU Up vector Z direction 8696 // * @param {Number} time 8697 // * @return {Array} All orienation params 8698 // */ 8699 8700 8701 p5.Listener3D.prototype.orient = function (xValF, yValF, zValF, xValU, yValU, zValU, time) { 8702 if (arguments.length === 3 || arguments.length === 4) { 8703 time = arguments[3]; 8704 this.orientForward(xValF, yValF, zValF, time); 8705 } else if (arguments.length === 6 || arguments === 7) { 8706 this.orientForward(xValF, yValF, zValF); 8707 this.orientUp(xValU, yValU, zValU, time); 8708 } 8709 8710 return [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value, this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value]; 8711 }; 8712 8713 p5.Listener3D.prototype.orientForward = function (xValF, yValF, zValF, time) { 8714 this.forwardX(xValF, time); 8715 this.forwardY(yValF, time); 8716 this.forwardZ(zValF, time); 8717 return [this.listener.forwardX, this.listener.forwardY, this.listener.forwardZ]; 8718 }; 8719 8720 p5.Listener3D.prototype.orientUp = function (xValU, yValU, zValU, time) { 8721 this.upX(xValU, time); 8722 this.upY(yValU, time); 8723 this.upZ(zValU, time); 8724 return [this.listener.upX, this.listener.upY, this.listener.upZ]; 8725 }; 8726 // * Getter and setter methods for orient coordinates 8727 // * @return {Number} [updated coordinate value] 8728 // */ 8729 8730 8731 p5.Listener3D.prototype.forwardX = function (xVal, time) { 8732 var t = time || 0; 8733 8734 if (typeof xVal === 'number') { 8735 this.listener.forwardX.value = xVal; 8736 this.listener.forwardX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8737 this.listener.forwardX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 8738 } else if (xVal) { 8739 xVal.connect(this.listener.forwardX); 8740 } 8741 8742 return this.listener.forwardX.value; 8743 }; 8744 8745 p5.Listener3D.prototype.forwardY = function (yVal, time) { 8746 var t = time || 0; 8747 8748 if (typeof yVal === 'number') { 8749 this.listener.forwardY.value = yVal; 8750 this.listener.forwardY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8751 this.listener.forwardY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 8752 } else if (yVal) { 8753 yVal.connect(this.listener.forwardY); 8754 } 8755 8756 return this.listener.forwardY.value; 8757 }; 8758 8759 p5.Listener3D.prototype.forwardZ = function (zVal, time) { 8760 var t = time || 0; 8761 8762 if (typeof zVal === 'number') { 8763 this.listener.forwardZ.value = zVal; 8764 this.listener.forwardZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8765 this.listener.forwardZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 8766 } else if (zVal) { 8767 zVal.connect(this.listener.forwardZ); 8768 } 8769 8770 return this.listener.forwardZ.value; 8771 }; 8772 8773 p5.Listener3D.prototype.upX = function (xVal, time) { 8774 var t = time || 0; 8775 8776 if (typeof xVal === 'number') { 8777 this.listener.upX.value = xVal; 8778 this.listener.upX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8779 this.listener.upX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 8780 } else if (xVal) { 8781 xVal.connect(this.listener.upX); 8782 } 8783 8784 return this.listener.upX.value; 8785 }; 8786 8787 p5.Listener3D.prototype.upY = function (yVal, time) { 8788 var t = time || 0; 8789 8790 if (typeof yVal === 'number') { 8791 this.listener.upY.value = yVal; 8792 this.listener.upY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8793 this.listener.upY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 8794 } else if (yVal) { 8795 yVal.connect(this.listener.upY); 8796 } 8797 8798 return this.listener.upY.value; 8799 }; 8800 8801 p5.Listener3D.prototype.upZ = function (zVal, time) { 8802 var t = time || 0; 8803 8804 if (typeof zVal === 'number') { 8805 this.listener.upZ.value = zVal;
8806 this.listener.upZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 8807 this.listener.upZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 8808 } else if (zVal) { 8809 zVal.connect(this.listener.upZ); 8810 } 8811 8812 return this.listener.upZ.value; 8813 }; 8814 8815 return p5.Listener3D; 8816}).call(exports, __webpack_require__, exports, module), 8817 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 8818 8819 }), 8820 (function(module, exports, __webpack_require__) { 8821 8822"use strict"; 8823var __WEBPACK_AMD_DEFINE_RESULT__; 8824 8825!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 8826 var Filter = __webpack_require__(15); 8827 8828 var Effect = __webpack_require__(4); 8829 /** 8830 * Delay is an echo effect. It processes an existing sound source, 8831 * and outputs a delayed version of that sound. The p5.Delay can 8832 * produce different effects depending on the delayTime, feedback, 8833 * filter, and type. In the example below, a feedback of 0.5 (the 8834 * default value) will produce a looping delay that decreases in 8835 * volume by 50% each repeat. A filter will cut out the high 8836 * frequencies so that the delay does not sound as piercing as the 8837 * original source. 8838 * 8839 * 8840 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 8841 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 8842 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 8843 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 8844 * @class p5.Delay 8845 * @extends p5.Effect 8846 * @constructor 8847 * @example 8848 * <div><code> 8849 * let osc; 8850 * 8851 * function setup() { 8852 * let cnv = createCanvas(100, 100); 8853 * background(220); 8854 * textAlign(CENTER); 8855 * text('tap to play', width/2, height/2); 8856 * 8857 * osc = new p5.Oscillator('square'); 8858 * osc.amp(0.5); 8859 * delay = new p5.Delay(); 8860 * 8861 * // delay.process() accepts 4 parameters: 8862 * // source, delayTime (in seconds), feedback, filter frequency 8863 * delay.process(osc, 0.12, .7, 2300); 8864 * 8865 * cnv.mousePressed(oscStart); 8866 * } 8867 * 8868 * function oscStart() { 8869 * osc.start(); 8870 * } 8871 * 8872 * function mouseReleased() { 8873 * osc.stop(); 8874 * } 8875 * </code></div> 8876 */ 8877 8878 8879 p5.Delay = function () { 8880 Effect.call(this); 8881 this._split = this.ac.createChannelSplitter(2); 8882 this._merge = this.ac.createChannelMerger(2); 8883 this._leftGain = this.ac.createGain(); 8884 this._rightGain = this.ac.createGain(); 8885 /** 8886 * The p5.Delay is built with two 8887 * <a href="http://www.w3.org/TR/webaudio/#DelayNode"> 8888 * Web Audio Delay Nodes</a>, one for each stereo channel. 8889 * 8890 * @for p5.Delay 8891 * @property {DelayNode} leftDelay 8892 */ 8893 8894 this.leftDelay = this.ac.createDelay(); 8895 /** 8896 * The p5.Delay is built with two 8897 * <a href="http://www.w3.org/TR/webaudio/#DelayNode"> 8898 * Web Audio Delay Nodes</a>, one for each stereo channel. 8899 * @for p5.Delay 8900 * @property {DelayNode} rightDelay 8901 */ 8902 8903 this.rightDelay = this.ac.createDelay(); 8904 this._leftFilter = new Filter(); 8905 this._rightFilter = new Filter(); 8906 8907 this._leftFilter.disconnect(); 8908 8909 this._rightFilter.disconnect(); 8910 8911 this._leftFilter.biquad.frequency.setValueAtTime(1200, this.ac.currentTime); 8912 8913 this._rightFilter.biquad.frequency.setValueAtTime(1200, this.ac.currentTime); 8914 8915 this._leftFilter.biquad.Q.setValueAtTime(0.3, this.ac.currentTime); 8916 8917 this._rightFilter.biquad.Q.setValueAtTime(0.3, this.ac.currentTime); 8918 8919 8920 this.input.connect(this._split); 8921 this.leftDelay.connect(this._leftGain); 8922 this.rightDelay.connect(this._rightGain); 8923 8924 this._leftGain.connect(this._leftFilter.input); 8925 8926 this._rightGain.connect(this._rightFilter.input); 8927 8928 this._merge.connect(this.wet); 8929 8930 this._leftFilter.biquad.gain.setValueAtTime(1, this.ac.currentTime); 8931 8932 this._rightFilter.biquad.gain.setValueAtTime(1, this.ac.currentTime); 8933 8934 8935 this.setType(0); 8936 this._maxDelay = this.leftDelay.delayTime.maxValue; 8937 8938 this.feedback(0.5); 8939 }; 8940 8941 p5.Delay.prototype = Object.create(Effect.prototype); 8942 /** 8943 * Add delay to an audio signal according to a set 8944 * of delay parameters. 8945 * 8946 * @method process 8947 * @for p5.Delay 8948 * @param {Object} Signal An object that outputs audio 8949 * @param {Number} [delayTime] Time (in seconds) of the delay/echo. 8950 * Some browsers limit delayTime to 8951 * 1 second. 8952 * @param {Number} [feedback] sends the delay back through itself 8953 * in a loop that decreases in volume 8954 * each time. 8955 * @param {Number} [lowPass] Cutoff frequency. Only frequencies 8956 * below the lowPass will be part of the 8957 * delay. 8958 */ 8959 8960 p5.Delay.prototype.process = function (src, _delayTime, _feedback, _filter) { 8961 var feedback = _feedback || 0; 8962 var delayTime = _delayTime || 0; 8963 8964 if (feedback >= 1.0) { 8965 throw new Error('Feedback value will force a positive feedback loop.'); 8966 } 8967 8968 if (delayTime >= this._maxDelay) { 8969 throw new Error('Delay Time exceeds maximum delay time of ' + this._maxDelay + ' second.'); 8970 } 8971 8972 src.connect(this.input); 8973 this.leftDelay.delayTime.setValueAtTime(delayTime, this.ac.currentTime); 8974 this.rightDelay.delayTime.setValueAtTime(delayTime, this.ac.currentTime); 8975 this._leftGain.gain.value = feedback; 8976 this._rightGain.gain.value = feedback; 8977 8978 if (_filter) { 8979 this._leftFilter.freq(_filter); 8980 8981 this._rightFilter.freq(_filter); 8982 } 8983 }; 8984 /** 8985 * Set the delay (echo) time, in seconds. Usually this value will be 8986 * a floating point number between 0.0 and 1.0. 8987 * 8988 * @method delayTime 8989 * @for p5.Delay 8990 * @param {Number} delayTime Time (in seconds) of the delay 8991 */ 8992 8993 8994 p5.Delay.prototype.delayTime = function (t) { 8995 if (typeof t !== 'number') { 8996 t.connect(this.leftDelay.delayTime); 8997 t.connect(this.rightDelay.delayTime); 8998 } else { 8999 this.leftDelay.delayTime.cancelScheduledValues(this.ac.currentTime); 9000 this.rightDelay.delayTime.cancelScheduledValues(this.ac.currentTime); 9001 this.leftDelay.delayTime.linearRampToValueAtTime(t, this.ac.currentTime); 9002 this.rightDelay.delayTime.linearRampToValueAtTime(t, this.ac.currentTime); 9003 } 9004 }; 9005 /** 9006 * Feedback occurs when Delay sends its signal back through its input 9007 * in a loop. The feedback amount determines how much signal to send each 9008 * time through the loop. A feedback greater than 1.0 is not desirable because 9009 * it will increase the overall output each time through the loop, 9010 * creating an infinite feedback loop. The default value is 0.5 9011 * 9012 * @method feedback 9013 * @for p5.Delay 9014 * @param {Number|Object} feedback 0.0 to 1.0, or an object such as an 9015 * Oscillator that can be used to 9016 * modulate this param 9017 * @returns {Number} Feedback value 9018 * 9019 */ 9020 9021 9022 p5.Delay.prototype.feedback = function (f) { 9023 if (f && typeof f !== 'number') { 9024 f.connect(this._leftGain.gain); 9025 f.connect(this._rightGain.gain); 9026 } else if (f >= 1.0) { 9027 throw new Error('Feedback value will force a positive feedback loop.'); 9028 } else if (typeof f === 'number') { 9029 this._leftGain.gain.value = f; 9030 this._rightGain.gain.value = f; 9031 } 9032 9033 9034 return this._leftGain.gain.value; 9035 }; 9036 /** 9037 * Set a lowpass filter frequency for the delay. A lowpass filter 9038 * will cut off any frequencies higher than the filter frequency. 9039 * 9040 * @method filter 9041 * @for p5.Delay 9042 * @param {Number|Object} cutoffFreq A lowpass filter will cut off any 9043 * frequencies higher than the filter frequency. 9044 * @param {Number|Object} res Resonance of the filter frequency 9045 * cutoff, or an object (i.e. a p5.Oscillator) 9046 * that can be used to modulate this parameter. 9047 * High numbers (i.e. 15) will produce a resonance, 9048 * low numbers (i.e. .2) will produce a slope. 9049 */ 9050 9051 9052 p5.Delay.prototype.filter = function (freq, q) { 9053 this._leftFilter.set(freq, q); 9054 9055 this._rightFilter.set(freq, q); 9056 }; 9057 /** 9058 * Choose a preset type of delay. 'pingPong' bounces the signal 9059 * from the left to the right channel to produce a stereo effect.
9060 * Any other parameter will revert to the default delay setting. 9061 * 9062 * @method setType 9063 * @for p5.Delay 9064 * @param {String|Number} type 'pingPong' (1) or 'default' (0) 9065 */ 9066 9067 9068 p5.Delay.prototype.setType = function (t) { 9069 if (t === 1) { 9070 t = 'pingPong'; 9071 } 9072 9073 this._split.disconnect(); 9074 9075 this._leftFilter.disconnect(); 9076 9077 this._rightFilter.disconnect(); 9078 9079 this._split.connect(this.leftDelay, 0); 9080 9081 this._split.connect(this.rightDelay, 1); 9082 9083 switch (t) { 9084 case 'pingPong': 9085 this._rightFilter.setType(this._leftFilter.biquad.type); 9086 9087 this._leftFilter.output.connect(this._merge, 0, 0); 9088 9089 this._rightFilter.output.connect(this._merge, 0, 1); 9090 9091 this._leftFilter.output.connect(this.rightDelay); 9092 9093 this._rightFilter.output.connect(this.leftDelay); 9094 9095 break; 9096 9097 default: 9098 this._leftFilter.output.connect(this._merge, 0, 0); 9099 9100 this._rightFilter.output.connect(this._merge, 0, 1); 9101 9102 this._leftFilter.output.connect(this.leftDelay); 9103 9104 this._rightFilter.output.connect(this.rightDelay); 9105 9106 } 9107 }; 9108 9109 /** 9110 * Set the output level of the delay effect. 9111 * 9112 * @method amp 9113 * @for p5.Delay 9114 * @param {Number} volume amplitude between 0 and 1.0 9115 * @param {Number} [rampTime] create a fade that lasts rampTime 9116 * @param {Number} [timeFromNow] schedule this event to happen 9117 * seconds from now 9118 */ 9119 9120 /** 9121 * Send output to a p5.sound or web audio object 9122 * 9123 * @method connect 9124 * @for p5.Delay 9125 * @param {Object} unit 9126 */ 9127 9128 /** 9129 * Disconnect all output. 9130 * 9131 * @method disconnect 9132 * @for p5.Delay 9133 */ 9134 9135 9136 p5.Delay.prototype.dispose = function () { 9137 Effect.prototype.dispose.apply(this); 9138 9139 this._split.disconnect(); 9140 9141 this._leftFilter.dispose(); 9142 9143 this._rightFilter.dispose(); 9144 9145 this._merge.disconnect(); 9146 9147 this._leftGain.disconnect(); 9148 9149 this._rightGain.disconnect(); 9150 9151 this.leftDelay.disconnect(); 9152 this.rightDelay.disconnect(); 9153 this._split = undefined; 9154 this._leftFilter = undefined; 9155 this._rightFilter = undefined; 9156 this._merge = undefined; 9157 this._leftGain = undefined; 9158 this._rightGain = undefined; 9159 this.leftDelay = undefined; 9160 this.rightDelay = undefined; 9161 }; 9162}).call(exports, __webpack_require__, exports, module), 9163 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 9164 9165 }), 9166 (function(module, exports, __webpack_require__) { 9167 9168"use strict"; 9169var __WEBPACK_AMD_DEFINE_RESULT__; 9170 9171!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 9172 var CustomError = __webpack_require__(11); 9173 9174 var Effect = __webpack_require__(4); 9175 /** 9176 * Reverb adds depth to a sound through a large number of decaying 9177 * echoes. It creates the perception that sound is occurring in a 9178 * physical space. The p5.Reverb has paramters for Time (how long does the 9179 * reverb last) and decayRate (how much the sound decays with each echo) 9180 * that can be set with the .set() or .process() methods. The p5.Convolver 9181 * extends p5.Reverb allowing you to recreate the sound of actual physical 9182 * spaces through convolution. 9183 * 9184 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 9185 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 9186 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 9187 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 9188 * 9189 * @class p5.Reverb 9190 * @extends p5.Effect 9191 * @constructor 9192 * @example 9193 * <div><code> 9194 * let soundFile, reverb; 9195 * function preload() { 9196 * soundFile = loadSound('assets/Damscray_DancingTiger.mp3'); 9197 * } 9198 * 9199 * function setup() { 9200 * let cnv = createCanvas(100, 100); 9201 * cnv.mousePressed(playSound); 9202 * 9203 * reverb = new p5.Reverb(); 9204 * soundFile.disconnect(); // so we'll only hear reverb... 9205 * 9206 * // connect soundFile to reverb, process w/ 9207 * // 3 second reverbTime, decayRate of 2% 9208 * reverb.process(soundFile, 3, 2); 9209 * } 9210 * 9211 * function draw() { 9212 * let dryWet = constrain(map(mouseX, 0, width, 0, 1), 0, 1); 9213 * // 1 = all reverb, 0 = no reverb 9214 * reverb.drywet(dryWet); 9215 * 9216 * background(220); 9217 * text('tap to play', 10, 20); 9218 * text('dry/wet: ' + round(dryWet * 100) + '%', 10, height - 20); 9219 * } 9220 * 9221 * function playSound() { 9222 * soundFile.play(); 9223 * } 9224 * </code></div> 9225 */ 9226 9227 9228 p5.Reverb = function () { 9229 Effect.call(this); 9230 9231 this._initConvolverNode(); 9232 9233 9234 this.input.gain.value = 0.5; 9235 9236 this._seconds = 3; 9237 this._decay = 2; 9238 this._reverse = false;
9239 9240 this._buildImpulse(); 9241 }; 9242 9243 p5.Reverb.prototype = Object.create(Effect.prototype); 9244 9245 p5.Reverb.prototype._initConvolverNode = function () { 9246 this.convolverNode = this.ac.createConvolver(); 9247 this.input.connect(this.convolverNode); 9248 this.convolverNode.connect(this.wet); 9249 }; 9250 9251 p5.Reverb.prototype._teardownConvolverNode = function () { 9252 if (this.convolverNode) { 9253 this.convolverNode.disconnect(); 9254 delete this.convolverNode; 9255 } 9256 }; 9257 9258 p5.Reverb.prototype._setBuffer = function (audioBuffer) { 9259 this._teardownConvolverNode(); 9260 9261 this._initConvolverNode(); 9262 9263 this.convolverNode.buffer = audioBuffer; 9264 }; 9265 /** 9266 * Connect a source to the reverb, and assign reverb parameters. 9267 * 9268 * @method process 9269 * @for p5.Reverb 9270 * @param {Object} src p5.sound / Web Audio object with a sound 9271 * output. 9272 * @param {Number} [seconds] Duration of the reverb, in seconds. 9273 * Min: 0, Max: 10. Defaults to 3. 9274 * @param {Number} [decayRate] Percentage of decay with each echo. 9275 * Min: 0, Max: 100. Defaults to 2. 9276 * @param {Boolean} [reverse] Play the reverb backwards or forwards. 9277 */ 9278 9279 9280 p5.Reverb.prototype.process = function (src, seconds, decayRate, reverse) { 9281 src.connect(this.input); 9282 var rebuild = false; 9283 9284 if (seconds) { 9285 this._seconds = seconds; 9286 rebuild = true; 9287 } 9288 9289 if (decayRate) { 9290 this._decay = decayRate; 9291 } 9292 9293 if (reverse) { 9294 this._reverse = reverse; 9295 } 9296 9297 if (rebuild) { 9298 this._buildImpulse(); 9299 } 9300 }; 9301 /** 9302 * Set the reverb settings. Similar to .process(), but without 9303 * assigning a new input. 9304 * 9305 * @method set 9306 * @for p5.Reverb 9307 * @param {Number} [seconds] Duration of the reverb, in seconds. 9308 * Min: 0, Max: 10. Defaults to 3. 9309 * @param {Number} [decayRate] Percentage of decay with each echo. 9310 * Min: 0, Max: 100. Defaults to 2. 9311 * @param {Boolean} [reverse] Play the reverb backwards or forwards. 9312 */ 9313 9314 9315 p5.Reverb.prototype.set = function (seconds, decayRate, reverse) { 9316 var rebuild = false; 9317 9318 if (seconds) { 9319 this._seconds = seconds; 9320 rebuild = true; 9321 } 9322 9323 if (decayRate) { 9324 this._decay = decayRate; 9325 } 9326 9327 if (reverse) { 9328 this._reverse = reverse; 9329 } 9330 9331 if (rebuild) { 9332 this._buildImpulse(); 9333 } 9334 }; 9335 9336 /** 9337 * Set the output level of the reverb effect. 9338 * 9339 * @method amp 9340 * @for p5.Reverb 9341 * @param {Number} volume amplitude between 0 and 1.0 9342 * @param {Number} [rampTime] create a fade that lasts rampTime 9343 * @param {Number} [timeFromNow] schedule this event to happen 9344 * seconds from now 9345 */ 9346 9347 /** 9348 * Send output to a p5.sound or web audio object 9349 * 9350 * @method connect 9351 * @for p5.Reverb 9352 * @param {Object} unit 9353 */ 9354 9355 /** 9356 * Disconnect all output. 9357 * 9358 * @method disconnect 9359 * @for p5.Reverb 9360 */ 9361 9362 /** 9363 * Inspired by Simple Reverb by Jordan Santell 9364 * https://github.com/web-audio-components/simple-reverb/blob/master/index.js 9365 * 9366 * Utility function for building an impulse response 9367 * based on the module parameters. 9368 * 9369 * @private 9370 */ 9371 9372 9373 p5.Reverb.prototype._buildImpulse = function () { 9374 var rate = this.ac.sampleRate; 9375 var length = rate * this._seconds; 9376 var decay = this._decay; 9377 var impulse = this.ac.createBuffer(2, length, rate); 9378 var impulseL = impulse.getChannelData(0); 9379 var impulseR = impulse.getChannelData(1); 9380 var n, i; 9381 9382 for (i = 0; i < length; i++) { 9383 n = this._reverse ? length - i : i; 9384 impulseL[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, decay); 9385 impulseR[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, decay); 9386 } 9387 9388 this._setBuffer(impulse); 9389 }; 9390 9391 p5.Reverb.prototype.dispose = function () { 9392 Effect.prototype.dispose.apply(this); 9393 9394 this._teardownConvolverNode(); 9395 }; 9396 9397 /** 9398 * <p>p5.Convolver extends p5.Reverb. It can emulate the sound of real 9399 * physical spaces through a process called <a href=" 9400 * https://en.wikipedia.org/wiki/Convolution_reverb#Real_space_simulation"> 9401 * convolution</a>.</p> 9402 * 9403 * <p>Convolution multiplies any audio input by an "impulse response" 9404 * to simulate the dispersion of sound over time. The impulse response is 9405 * generated from an audio file that you provide. One way to 9406 * generate an impulse response is to pop a balloon in a reverberant space 9407 * and record the echo. Convolution can also be used to experiment with 9408 * sound.</p> 9409 * 9410 * <p>Use the method <code>createConvolution(path)</code> to instantiate a 9411 * p5.Convolver with a path to your impulse response audio file.</p> 9412 * 9413 * @class p5.Convolver
9414 * @extends p5.Effect 9415 * @constructor 9416 * @param {String} path path to a sound file 9417 * @param {Function} [callback] function to call when loading succeeds 9418 * @param {Function} [errorCallback] function to call if loading fails. 9419 * This function will receive an error or 9420 * XMLHttpRequest object with information 9421 * about what went wrong. 9422 * @example 9423 * <div><code> 9424 * let cVerb, sound; 9425 * function preload() { 9426 * // We have both MP3 and OGG versions of all sound assets 9427 * soundFormats('ogg', 'mp3'); 9428 * 9429 * // Try replacing 'bx-spring' with other soundfiles like 9430 * // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox' 9431 * cVerb = createConvolver('assets/bx-spring.mp3'); 9432 * 9433 * // Try replacing 'Damscray_DancingTiger' with 9434 * // 'beat', 'doorbell', lucky_dragons_-_power_melody' 9435 * sound = loadSound('assets/Damscray_DancingTiger.mp3'); 9436 * } 9437 * 9438 * function setup() { 9439 * let cnv = createCanvas(100, 100); 9440 * cnv.mousePressed(playSound); 9441 * background(220); 9442 * text('tap to play', 20, 20); 9443 * 9444 * // disconnect from master output... 9445 * sound.disconnect(); 9446 * 9447 * // ...and process with cVerb 9448 * // so that we only hear the convolution 9449 * cVerb.process(sound); 9450 * } 9451 * 9452 * function playSound() { 9453 * sound.play(); 9454 * } 9455 * </code></div> 9456 */ 9457 9458 9459 p5.Convolver = function (path, callback, errorCallback) { 9460 p5.Reverb.call(this); 9461 /** 9462 * Internally, the p5.Convolver uses the a 9463 * <a href="http://www.w3.org/TR/webaudio/#ConvolverNode"> 9464 * Web Audio Convolver Node</a>. 9465 * 9466 * @property {ConvolverNode} convolverNode 9467 */ 9468 9469 this._initConvolverNode(); 9470 9471 9472 this.input.gain.value = 0.5; 9473 9474 if (path) { 9475 this.impulses = []; 9476 9477 this._loadBuffer(path, callback, errorCallback); 9478 } else { 9479 this._seconds = 3; 9480 this._decay = 2; 9481 this._reverse = false; 9482 9483 this._buildImpulse(); 9484 } 9485 }; 9486 9487 p5.Convolver.prototype = Object.create(p5.Reverb.prototype); 9488 p5.prototype.registerPreloadMethod('createConvolver', p5.prototype); 9489 /** 9490 * Create a p5.Convolver. Accepts a path to a soundfile 9491 * that will be used to generate an impulse response. 9492 * 9493 * @method createConvolver 9494 * @for p5 9495 * @param {String} path path to a sound file 9496 * @param {Function} [callback] function to call if loading is successful. 9497 * The object will be passed in as the argument 9498 * to the callback function. 9499 * @param {Function} [errorCallback] function to call if loading is not successful. 9500 * A custom error will be passed in as the argument 9501 * to the callback function. 9502 * @return {p5.Convolver} 9503 * @example 9504 * <div><code> 9505 * let cVerb, sound; 9506 * function preload() { 9507 * // We have both MP3 and OGG versions of all sound assets 9508 * soundFormats('ogg', 'mp3'); 9509 * 9510 * // Try replacing 'bx-spring' with other soundfiles like 9511 * // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox' 9512 * cVerb = createConvolver('assets/bx-spring.mp3'); 9513 * 9514 * // Try replacing 'Damscray_DancingTiger' with 9515 * // 'beat', 'doorbell', lucky_dragons_-_power_melody' 9516 * sound = loadSound('assets/Damscray_DancingTiger.mp3'); 9517 * } 9518 * 9519 * function setup() { 9520 * let cnv = createCanvas(100, 100); 9521 * cnv.mousePressed(playSound); 9522 * background(220); 9523 * text('tap to play', 20, 20); 9524 * 9525 * // disconnect from master output... 9526 * sound.disconnect(); 9527 * 9528 * // ...and process with cVerb 9529 * // so that we only hear the convolution 9530 * cVerb.process(sound); 9531 * } 9532 * 9533 * function playSound() { 9534 * sound.play(); 9535 * } 9536 * </code></div> 9537 */ 9538 9539 p5.prototype.createConvolver = function (path, callback, errorCallback) { 9540 if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') { 9541 alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS'); 9542 } 9543 9544 var self = this; 9545 var cReverb = new p5.Convolver(path, function (buffer) { 9546 if (typeof callback === 'function') { 9547 callback(buffer); 9548 } 9549 9550 if (typeof self._decrementPreload === 'function') { 9551 self._decrementPreload(); 9552 } 9553 }, errorCallback); 9554 cReverb.impulses = []; 9555 return cReverb; 9556 }; 9557 /** 9558 * Private method to load a buffer as an Impulse Response, 9559 * assign it to the convolverNode, and add to the Array of .impulses. 9560 *
9561 * @param {String} path 9562 * @param {Function} callback 9563 * @param {Function} errorCallback 9564 * @private 9565 */ 9566 9567 9568 p5.Convolver.prototype._loadBuffer = function (path, callback, errorCallback) { 9569 var path = p5.prototype._checkFileFormats(path); 9570 9571 var self = this; 9572 var errorTrace = new Error().stack; 9573 var ac = p5.prototype.getAudioContext(); 9574 var request = new XMLHttpRequest(); 9575 request.open('GET', path, true); 9576 request.responseType = 'arraybuffer'; 9577 9578 request.onload = function () { 9579 if (request.status === 200) { 9580 ac.decodeAudioData(request.response, function (buff) { 9581 var buffer = {}; 9582 var chunks = path.split('/'); 9583 buffer.name = chunks[chunks.length - 1]; 9584 buffer.audioBuffer = buff; 9585 self.impulses.push(buffer); 9586 9587 self._setBuffer(buffer.audioBuffer); 9588 9589 if (callback) { 9590 callback(buffer); 9591 } 9592 }, 9593 function () { 9594 var err = new CustomError('decodeAudioData', errorTrace, self.url); 9595 var msg = 'AudioContext error at decodeAudioData for ' + self.url; 9596 9597 if (errorCallback) { 9598 err.msg = msg; 9599 errorCallback(err); 9600 } else { 9601 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 9602 } 9603 }); 9604 } 9605 else { 9606 var err = new CustomError('loadConvolver', errorTrace, self.url); 9607 var msg = 'Unable to load ' + self.url + '. The request status was: ' + request.status + ' (' + request.statusText + ')'; 9608 9609 if (errorCallback) { 9610 err.message = msg; 9611 errorCallback(err); 9612 } else { 9613 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 9614 } 9615 } 9616 }; 9617 9618 9619 request.onerror = function () { 9620 var err = new CustomError('loadConvolver', errorTrace, self.url); 9621 var msg = 'There was no response from the server at ' + self.url + '. Check the url and internet connectivity.'; 9622 9623 if (errorCallback) { 9624 err.message = msg; 9625 errorCallback(err); 9626 } else { 9627 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 9628 } 9629 }; 9630 9631 request.send(); 9632 }; 9633 9634 p5.Convolver.prototype.set = null; 9635 /** 9636 * Connect a source to the convolver. 9637 * 9638 * @method process 9639 * @for p5.Convolver 9640 * @param {Object} src p5.sound / Web Audio object with a sound 9641 * output. 9642 * @example 9643 * <div><code> 9644 * let cVerb, sound; 9645 * function preload() { 9646 * // We have both MP3 and OGG versions of all sound assets 9647 * soundFormats('ogg', 'mp3'); 9648 * 9649 * // Try replacing 'bx-spring' with other soundfiles like 9650 * // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox' 9651 * cVerb = createConvolver('assets/bx-spring.mp3'); 9652 * 9653 * // Try replacing 'Damscray_DancingTiger' with 9654 * // 'beat', 'doorbell', lucky_dragons_-_power_melody' 9655 * sound = loadSound('assets/Damscray_DancingTiger.mp3'); 9656 * } 9657 * 9658 * function setup() { 9659 * let cnv = createCanvas(100, 100); 9660 * cnv.mousePressed(playSound); 9661 * background(220); 9662 * text('tap to play', 20, 20); 9663 * 9664 * // disconnect from master output... 9665 * sound.disconnect(); 9666 * 9667 * // ...and process with cVerb 9668 * // so that we only hear the convolution 9669 * cVerb.process(sound); 9670 * } 9671 * 9672 * function playSound() { 9673 * sound.play(); 9674 * } 9675 * 9676 * </code></div> 9677 */ 9678 9679 p5.Convolver.prototype.process = function (src) { 9680 src.connect(this.input); 9681 }; 9682 /** 9683 * If you load multiple impulse files using the .addImpulse method, 9684 * they will be stored as Objects in this Array. Toggle between them 9685 * with the <code>toggleImpulse(id)</code> method. 9686 * 9687 * @property {Array} impulses 9688 * @for p5.Convolver 9689 */ 9690 9691 9692 p5.Convolver.prototype.impulses = []; 9693 /** 9694 * Load and assign a new Impulse Response to the p5.Convolver. 9695 * The impulse is added to the <code>.impulses</code> array. Previous 9696 * impulses can be accessed with the <code>.toggleImpulse(id)</code> 9697 * method. 9698 * 9699 * @method addImpulse 9700 * @for p5.Convolver 9701 * @param {String} path path to a sound file 9702 * @param {Function} callback function (optional) 9703 * @param {Function} errorCallback function (optional) 9704 */ 9705 9706 p5.Convolver.prototype.addImpulse = function (path, callback, errorCallback) { 9707 if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') { 9708 alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS'); 9709 } 9710 9711 this._loadBuffer(path, callback, errorCallback); 9712 }; 9713 /** 9714 * Similar to .addImpulse, except that the <code>.impulses</code> 9715 * Array is reset to save memory. A new <code>.impulses</code> 9716 * array is created with this impulse as the only item. 9717 * 9718 * @method resetImpulse 9719 * @for p5.Convolver 9720 * @param {String} path path to a sound file 9721 * @param {Function} callback function (optional) 9722 * @param {Function} errorCallback function (optional) 9723 */ 9724 9725 9726 p5.Convolver.prototype.resetImpulse = function (path, callback, errorCallback) { 9727 if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') { 9728 alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS'); 9729 } 9730 9731 this.impulses = []; 9732 9733 this._loadBuffer(path, callback, errorCallback); 9734 }; 9735 /** 9736 * If you have used <code>.addImpulse()</code> to add multiple impulses 9737 * to a p5.Convolver, then you can use this method to toggle between 9738 * the items in the <code>.impulses</code> Array. Accepts a parameter 9739 * to identify which impulse you wish to use, identified either by its 9740 * original filename (String) or by its position in the <code>.impulses 9741 * </code> Array (Number).<br/> 9742 * You can access the objects in the .impulses Array directly. Each 9743 * Object has two attributes: an <code>.audioBuffer</code> (type: 9744 * Web Audio <a href=" 9745 * http://webaudio.github.io/web-audio-api/#the-audiobuffer-interface"> 9746 * AudioBuffer)</a> and a <code>.name</code>, a String that corresponds 9747 * with the original filename. 9748 * 9749 * @method toggleImpulse 9750 * @for p5.Convolver 9751 * @param {String|Number} id Identify the impulse by its original filename 9752 * (String), or by its position in the 9753 * <code>.impulses</code> Array (Number). 9754 */ 9755 9756 9757 p5.Convolver.prototype.toggleImpulse = function (id) { 9758 if (typeof id === 'number' && id < this.impulses.length) { 9759 this._setBuffer(this.impulses[id].audioBuffer); 9760 } 9761 9762 if (typeof id === 'string') { 9763 for (var i = 0; i < this.impulses.length; i++) { 9764 if (this.impulses[i].name === id) { 9765 this._setBuffer(this.impulses[i].audioBuffer); 9766 9767 break; 9768 } 9769 } 9770 } 9771 }; 9772 9773 p5.Convolver.prototype.dispose = function () { 9774 p5.Reverb.prototype.dispose.apply(this); 9775 9776 for (var i in this.impulses) { 9777 if (this.impulses[i]) { 9778 this.impulses[i] = null; 9779 } 9780 } 9781 }; 9782}).call(exports, __webpack_require__, exports, module), 9783 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 9784 9785 }), 9786 (function(module, exports, __webpack_require__) { 9787 9788"use strict"; 9789var __WEBPACK_AMD_DEFINE_RESULT__; 9790 9791!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 9792 var p5sound = __webpack_require__(1); 9793 9794 9795 var Clock = __webpack_require__(27); 9796 9797 p5.Metro = function () { 9798 this.clock = new Clock({ 9799 'callback': this.ontick.bind(this) 9800 }); 9801 this.syncedParts = []; 9802 this.bpm = 120;
9803 9804 this._init(); 9805 9806 this.prevTick = 0; 9807 this.tatumTime = 0; 9808 9809 this.tickCallback = function () {}; 9810 }; 9811 9812 p5.Metro.prototype.ontick = function (tickTime) { 9813 var elapsedTime = tickTime - this.prevTick; 9814 var secondsFromNow = tickTime - p5sound.audiocontext.currentTime; 9815 9816 if (elapsedTime - this.tatumTime <= -0.02) { 9817 return; 9818 } else { 9819 this.prevTick = tickTime; 9820 9821 var self = this; 9822 this.syncedParts.forEach(function (thisPart) { 9823 if (!thisPart.isPlaying) return; 9824 thisPart.incrementStep(secondsFromNow); 9825 9826 thisPart.phrases.forEach(function (thisPhrase) { 9827 var phraseArray = thisPhrase.sequence; 9828 var bNum = self.metroTicks % phraseArray.length; 9829 9830 if (phraseArray[bNum] !== 0 && (self.metroTicks < phraseArray.length || !thisPhrase.looping)) { 9831 thisPhrase.callback(secondsFromNow, phraseArray[bNum]); 9832 } 9833 }); 9834 }); 9835 this.metroTicks += 1; 9836 this.tickCallback(secondsFromNow); 9837 } 9838 }; 9839 9840 p5.Metro.prototype.setBPM = function (bpm, rampTime) { 9841 var beatTime = 60 / (bpm * this.tatums); 9842 var now = p5sound.audiocontext.currentTime; 9843 this.tatumTime = beatTime; 9844 var rampTime = rampTime || 0; 9845 this.clock.frequency.setValueAtTime(this.clock.frequency.value, now); 9846 this.clock.frequency.linearRampToValueAtTime(bpm, now + rampTime); 9847 this.bpm = bpm; 9848 }; 9849 9850 p5.Metro.prototype.getBPM = function () { 9851 return this.clock.getRate() / this.tatums * 60; 9852 }; 9853 9854 p5.Metro.prototype._init = function () { 9855 this.metroTicks = 0; 9856 }; 9857 9858 9859 p5.Metro.prototype.resetSync = function (part) { 9860 this.syncedParts = [part]; 9861 }; 9862 9863 9864 p5.Metro.prototype.pushSync = function (part) { 9865 this.syncedParts.push(part); 9866 }; 9867 9868 p5.Metro.prototype.start = function (timeFromNow) { 9869 var t = timeFromNow || 0; 9870 var now = p5sound.audiocontext.currentTime; 9871 this.clock.start(now + t); 9872 this.setBPM(this.bpm); 9873 }; 9874 9875 p5.Metro.prototype.stop = function (timeFromNow) { 9876 var t = timeFromNow || 0; 9877 var now = p5sound.audiocontext.currentTime; 9878 this.clock.stop(now + t); 9879 }; 9880 9881 p5.Metro.prototype.beatLength = function (tatums) { 9882 this.tatums = 1 / tatums / 4; 9883 }; 9884}).call(exports, __webpack_require__, exports, module), 9885 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 9886 9887 }), 9888 (function(module, exports, __webpack_require__) { 9889 9890var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0),__webpack_require__(24),__webpack_require__(8)], __WEBPACK_AMD_DEFINE_RESULT__ = (function(t){"use strict";return t.TimelineState=function(e){t.Timeline.call(this),this._initial=e},t.extend(t.TimelineState,t.Timeline),t.TimelineState.prototype.getValueAtTime=function(e){var t=this.get(e);return null!==t?t.state:this._initial},t.TimelineState.prototype.setStateAtTime=function(e,t){this.add({state:e,time:t})},t.TimelineState}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 9891 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 9892 9893 }), 9894 (function(module, exports, __webpack_require__) { 9895 9896"use strict"; 9897var __WEBPACK_AMD_DEFINE_RESULT__; 9898 9899!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 9900 var p5sound = __webpack_require__(1); 9901 9902 var BPM = 120; 9903 /** 9904 * Set the global tempo, in beats per minute, for all 9905 * p5.Parts. This method will impact all active p5.Parts. 9906 * 9907 * @method setBPM 9908 * @for p5 9909 * @param {Number} BPM Beats Per Minute 9910 * @param {Number} rampTime Seconds from now 9911 */ 9912 9913 p5.prototype.setBPM = function (bpm, rampTime) { 9914 BPM = bpm; 9915 9916 for (var i in p5sound.parts) { 9917 if (p5sound.parts[i]) { 9918 p5sound.parts[i].setBPM(bpm, rampTime); 9919 } 9920 } 9921 }; 9922 /** 9923 * <p>A phrase is a pattern of musical events over time, i.e. 9924 * a series of notes and rests.</p> 9925 * 9926 * <p>Phrases must be added to a p5.Part for playback, and 9927 * each part can play multiple phrases at the same time. 9928 * For example, one Phrase might be a kick drum, another 9929 * could be a snare, and another could be the bassline.</p> 9930 * 9931 * <p>The first parameter is a name so that the phrase can be 9932 * modified or deleted later. The callback is a a function that 9933 * this phrase will call at every step—for example it might be 9934 * called <code>playNote(value){}</code>. The array determines 9935 * which value is passed into the callback at each step of the 9936 * phrase. It can be numbers, an object with multiple numbers, 9937 * or a zero (0) indicates a rest so the callback won't be called).</p> 9938 * 9939 * @class p5.Phrase 9940 * @constructor 9941 * @param {String} name Name so that you can access the Phrase. 9942 * @param {Function} callback The name of a function that this phrase 9943 * will call. Typically it will play a sound, 9944 * and accept two parameters: a time at which 9945 * to play the sound (in seconds from now), 9946 * and a value from the sequence array. The 9947 * time should be passed into the play() or 9948 * start() method to ensure precision. 9949 * @param {Array} sequence Array of values to pass into the callback 9950 * at each step of the phrase. 9951 * @example 9952 * <div><code> 9953 * let mySound, myPhrase, myPart; 9954 * let pattern = [1,0,0,2,0,2,0,0]; 9955 * 9956 * function preload() { 9957 * mySound = loadSound('assets/beatbox.mp3'); 9958 * } 9959 * 9960 * function setup() {
9961 * let cnv = createCanvas(100, 100); 9962 * cnv.mousePressed(playMyPart); 9963 * background(220); 9964 * text('tap to play', width/2, height/2); 9965 * textAlign(CENTER, CENTER); 9966 * 9967 * myPhrase = new p5.Phrase('bbox', onEachStep, pattern); 9968 * myPart = new p5.Part(); 9969 * myPart.addPhrase(myPhrase); 9970 * myPart.setBPM(60); 9971 * } 9972 * 9973 * function onEachStep(time, playbackRate) { 9974 * mySound.rate(playbackRate); 9975 * mySound.play(time); 9976 * } 9977 * 9978 * function playMyPart() { 9979 * userStartAudio(); 9980 * myPart.start(); 9981 * } 9982 * </code></div> 9983 */ 9984 9985 9986 p5.Phrase = function (name, callback, sequence) { 9987 this.phraseStep = 0; 9988 this.name = name; 9989 this.callback = callback; 9990 /** 9991 * Array of values to pass into the callback 9992 * at each step of the phrase. Depending on the callback 9993 * function's requirements, these values may be numbers, 9994 * strings, or an object with multiple parameters. 9995 * Zero (0) indicates a rest. 9996 * 9997 * @property {Array} sequence 9998 */ 9999 10000 this.sequence = sequence; 10001 }; 10002 /** 10003 * <p>A p5.Part plays back one or more p5.Phrases. Instantiate a part 10004 * with steps and tatums. By default, each step represents a 1/16th note.</p> 10005 * 10006 * <p>See p5.Phrase for more about musical timing.</p> 10007 * 10008 * @class p5.Part 10009 * @constructor 10010 * @param {Number} [steps] Steps in the part 10011 * @param {Number} [tatums] Divisions of a beat, e.g. use 1/4, or 0.25 for a quater note (default is 1/16, a sixteenth note) 10012 * @example 10013 * <div><code> 10014 * let box, drum, myPart; 10015 * let boxPat = [1,0,0,2,0,2,0,0]; 10016 * let drumPat = [0,1,1,0,2,0,1,0]; 10017 * 10018 * function preload() { 10019 * box = loadSound('assets/beatbox.mp3'); 10020 * drum = loadSound('assets/drum.mp3'); 10021 * } 10022 * 10023 * function setup() { 10024 * let cnv = createCanvas(100, 100); 10025 * cnv.mousePressed(playMyPart); 10026 * background(220); 10027 * textAlign(CENTER, CENTER); 10028 * text('tap to play', width/2, height/2); 10029 * 10030 * let boxPhrase = new p5.Phrase('box', playBox, boxPat); 10031 * let drumPhrase = new p5.Phrase('drum', playDrum, drumPat); 10032 * myPart = new p5.Part(); 10033 * myPart.addPhrase(boxPhrase); 10034 * myPart.addPhrase(drumPhrase); 10035 * myPart.setBPM(60); 10036 * } 10037 * 10038 * function playBox(time, playbackRate) { 10039 * box.rate(playbackRate); 10040 * box.play(time); 10041 * } 10042 * 10043 * function playDrum(time, playbackRate) { 10044 * drum.rate(playbackRate); 10045 * drum.play(time); 10046 * } 10047 * 10048 * function playMyPart() { 10049 * userStartAudio(); 10050 * 10051 * myPart.start(); 10052 * } 10053 * </code></div> 10054 */ 10055 10056 10057 p5.Part = function (steps, bLength) { 10058 this.length = steps || 0; 10059 10060 this.partStep = 0; 10061 this.phrases = []; 10062 this.isPlaying = false; 10063 this.noLoop(); 10064 this.tatums = bLength || 0.0625; 10065 10066 this.metro = new p5.Metro(); 10067 10068 this.metro._init(); 10069 10070 this.metro.beatLength(this.tatums); 10071 this.metro.setBPM(BPM); 10072 p5sound.parts.push(this); 10073 10074 this.callback = function () {}; 10075 }; 10076 /** 10077 * Set the tempo of this part, in Beats Per Minute. 10078 * 10079 * @method setBPM 10080 * @for p5.Part 10081 * @param {Number} BPM Beats Per Minute 10082 * @param {Number} [rampTime] Seconds from now 10083 */ 10084 10085 10086 p5.Part.prototype.setBPM = function (tempo, rampTime) { 10087 this.metro.setBPM(tempo, rampTime); 10088 }; 10089 /** 10090 * Returns the tempo, in Beats Per Minute, of this part. 10091 * 10092 * @method getBPM 10093 * @for p5.Part 10094 * @return {Number} 10095 */ 10096 10097 10098 p5.Part.prototype.getBPM = function () { 10099 return this.metro.getBPM(); 10100 }; 10101 /** 10102 * Start playback of this part. It will play 10103 * through all of its phrases at a speed 10104 * determined by setBPM. 10105 * 10106 * @method start 10107 * @for p5.Part 10108 * @param {Number} [time] seconds from now 10109 */ 10110 10111 10112 p5.Part.prototype.start = function (time) { 10113 if (!this.isPlaying) { 10114 this.isPlaying = true; 10115 this.metro.resetSync(this); 10116 var t = time || 0; 10117 this.metro.start(t); 10118 } 10119 }; 10120 /** 10121 * Loop playback of this part. It will begin 10122 * looping through all of its phrases at a speed 10123 * determined by setBPM. 10124 * 10125 * @method loop 10126 * @for p5.Part 10127 * @param {Number} [time] seconds from now 10128 */ 10129 10130 10131 p5.Part.prototype.loop = function (time) { 10132 this.looping = true; 10133 10134 this.onended = function () {
10135 this.partStep = 0; 10136 }; 10137 10138 var t = time || 0; 10139 this.start(t); 10140 }; 10141 /** 10142 * Tell the part to stop looping. 10143 * 10144 * @method noLoop 10145 * @for p5.Part 10146 */ 10147 10148 10149 p5.Part.prototype.noLoop = function () { 10150 this.looping = false; 10151 10152 this.onended = function () { 10153 this.stop(); 10154 }; 10155 }; 10156 /** 10157 * Stop the part and cue it to step 0. Playback will resume from the begining of the Part when it is played again. 10158 * 10159 * @method stop 10160 * @for p5.Part 10161 * @param {Number} [time] seconds from now 10162 */ 10163 10164 10165 p5.Part.prototype.stop = function (time) { 10166 this.partStep = 0; 10167 this.pause(time); 10168 }; 10169 /** 10170 * Pause the part. Playback will resume 10171 * from the current step. 10172 * 10173 * @method pause 10174 * @for p5.Part 10175 * @param {Number} time seconds from now 10176 */ 10177 10178 10179 p5.Part.prototype.pause = function (time) { 10180 this.isPlaying = false; 10181 var t = time || 0; 10182 this.metro.stop(t); 10183 }; 10184 /** 10185 * Add a p5.Phrase to this Part. 10186 * 10187 * @method addPhrase 10188 * @for p5.Part 10189 * @param {p5.Phrase} phrase reference to a p5.Phrase 10190 */ 10191 10192 10193 p5.Part.prototype.addPhrase = function (name, callback, array) { 10194 var p; 10195 10196 if (arguments.length === 3) { 10197 p = new p5.Phrase(name, callback, array); 10198 } else if (arguments[0] instanceof p5.Phrase) { 10199 p = arguments[0]; 10200 } else { 10201 throw 'invalid input. addPhrase accepts name, callback, array or a p5.Phrase'; 10202 } 10203 10204 this.phrases.push(p); 10205 10206 if (p.sequence.length > this.length) { 10207 this.length = p.sequence.length; 10208 } 10209 }; 10210 /** 10211 * Remove a phrase from this part, based on the name it was 10212 * given when it was created. 10213 * 10214 * @method removePhrase 10215 * @for p5.Part 10216 * @param {String} phraseName 10217 */ 10218 10219 10220 p5.Part.prototype.removePhrase = function (name) { 10221 for (var i in this.phrases) { 10222 if (this.phrases[i].name === name) { 10223 this.phrases.splice(i, 1); 10224 } 10225 } 10226 }; 10227 /** 10228 * Get a phrase from this part, based on the name it was 10229 * given when it was created. Now you can modify its array. 10230 * 10231 * @method getPhrase 10232 * @for p5.Part 10233 * @param {String} phraseName 10234 */ 10235 10236 10237 p5.Part.prototype.getPhrase = function (name) { 10238 for (var i in this.phrases) { 10239 if (this.phrases[i].name === name) { 10240 return this.phrases[i]; 10241 } 10242 } 10243 }; 10244 /** 10245 * Find all sequences with the specified name, and replace their patterns with the specified array. 10246 * 10247 * @method replaceSequence 10248 * @for p5.Part 10249 * @param {String} phraseName 10250 * @param {Array} sequence Array of values to pass into the callback 10251 * at each step of the phrase. 10252 */ 10253 10254 10255 p5.Part.prototype.replaceSequence = function (name, array) { 10256 for (var i in this.phrases) { 10257 if (this.phrases[i].name === name) { 10258 this.phrases[i].sequence = array; 10259 } 10260 } 10261 }; 10262 10263 p5.Part.prototype.incrementStep = function (time) { 10264 if (this.partStep < this.length - 1) { 10265 this.callback(time); 10266 this.partStep += 1; 10267 } else { 10268 if (!this.looping && this.partStep === this.length - 1) { 10269 this.onended(); 10270 } 10271 } 10272 }; 10273 /** 10274 * Set the function that will be called at every step. This will clear the previous function. 10275 * 10276 * @method onStep 10277 * @for p5.Part 10278 * @param {Function} callback The name of the callback 10279 * you want to fire 10280 * on every beat/tatum. 10281 */ 10282 10283 10284 p5.Part.prototype.onStep = function (callback) { 10285 this.callback = callback; 10286 }; 10287 10288 /** 10289 * A Score consists of a series of Parts. The parts will 10290 * be played back in order. For example, you could have an 10291 * A part, a B part, and a C part, and play them back in this order 10292 * <code>new p5.Score(a, a, b, a, c)</code> 10293 * 10294 * @class p5.Score 10295 * @constructor 10296 * @param {p5.Part} [...parts] One or multiple parts, to be played in sequence. 10297 */ 10298 10299 10300 p5.Score = function () { 10301 this.parts = []; 10302 this.currentPart = 0; 10303 var thisScore = this; 10304 10305 for (var i in arguments) { 10306 if (arguments[i] && this.parts[i]) { 10307 this.parts[i] = arguments[i]; 10308 this.parts[i].nextPart = this.parts[i + 1]; 10309 10310 this.parts[i].onended = function () { 10311 thisScore.resetPart(i); 10312 playNextPart(thisScore); 10313 }; 10314 } 10315 } 10316 10317 this.looping = false;
10318 }; 10319 10320 p5.Score.prototype.onended = function () { 10321 if (this.looping) { 10322 this.parts[0].start(); 10323 } else { 10324 this.parts[this.parts.length - 1].onended = function () { 10325 this.stop(); 10326 this.resetParts(); 10327 }; 10328 } 10329 10330 this.currentPart = 0; 10331 }; 10332 /** 10333 * Start playback of the score. 10334 * 10335 * @method start 10336 * @for p5.Score 10337 */ 10338 10339 10340 p5.Score.prototype.start = function () { 10341 this.parts[this.currentPart].start(); 10342 this.scoreStep = 0; 10343 }; 10344 /** 10345 * Stop playback of the score. 10346 * 10347 * @method stop 10348 * @for p5.Score 10349 */ 10350 10351 10352 p5.Score.prototype.stop = function () { 10353 this.parts[this.currentPart].stop(); 10354 this.currentPart = 0; 10355 this.scoreStep = 0; 10356 }; 10357 /** 10358 * Pause playback of the score. 10359 * 10360 * @method pause 10361 * @for p5.Score 10362 */ 10363 10364 10365 p5.Score.prototype.pause = function () { 10366 this.parts[this.currentPart].stop(); 10367 }; 10368 /** 10369 * Loop playback of the score. 10370 * 10371 * @method loop 10372 * @for p5.Score 10373 */ 10374 10375 10376 p5.Score.prototype.loop = function () { 10377 this.looping = true; 10378 this.start(); 10379 }; 10380 /** 10381 * Stop looping playback of the score. If it 10382 * is currently playing, this will go into effect 10383 * after the current round of playback completes. 10384 * 10385 * @method noLoop 10386 * @for p5.Score 10387 */ 10388 10389 10390 p5.Score.prototype.noLoop = function () { 10391 this.looping = false; 10392 }; 10393 10394 p5.Score.prototype.resetParts = function () { 10395 var self = this; 10396 this.parts.forEach(function (part) { 10397 self.resetParts[part]; 10398 }); 10399 }; 10400 10401 p5.Score.prototype.resetPart = function (i) { 10402 this.parts[i].stop(); 10403 this.parts[i].partStep = 0; 10404 10405 for (var p in this.parts[i].phrases) { 10406 if (this.parts[i]) { 10407 this.parts[i].phrases[p].phraseStep = 0; 10408 } 10409 } 10410 }; 10411 /** 10412 * Set the tempo for all parts in the score 10413 * 10414 * @method setBPM 10415 * @for p5.Score 10416 * @param {Number} BPM Beats Per Minute 10417 * @param {Number} rampTime Seconds from now 10418 */ 10419 10420 10421 p5.Score.prototype.setBPM = function (bpm, rampTime) { 10422 for (var i in this.parts) { 10423 if (this.parts[i]) { 10424 this.parts[i].setBPM(bpm, rampTime); 10425 } 10426 } 10427 }; 10428 10429 function playNextPart(aScore) { 10430 aScore.currentPart++; 10431 10432 if (aScore.currentPart >= aScore.parts.length) { 10433 aScore.scoreStep = 0; 10434 aScore.onended(); 10435 } else { 10436 aScore.scoreStep = 0; 10437 aScore.parts[aScore.currentPart - 1].stop(); 10438 aScore.parts[aScore.currentPart].start(); 10439 } 10440 } 10441}).call(exports, __webpack_require__, exports, module), 10442 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 10443 10444 }), 10445 (function(module, exports, __webpack_require__) { 10446 10447"use strict"; 10448var __WEBPACK_AMD_DEFINE_RESULT__; 10449 10450!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 10451 var p5sound = __webpack_require__(1); 10452 10453 var Clock = __webpack_require__(27); 10454 /** 10455 * SoundLoop 10456 * 10457 * @class p5.SoundLoop 10458 * @constructor 10459 * 10460 * @param {Function} callback this function will be called on each iteration of theloop 10461 * @param {Number|String} [interval] amount of time (if a number) or beats (if a string, following <a href = "https://github.com/Tonejs/Tone.js/wiki/Time">Tone.Time</a> convention) for each iteration of the loop. Defaults to 1 second. 10462 * 10463 * @example 10464 * <div><code> 10465 * let synth, soundLoop; 10466 * let notePattern = [60, 62, 64, 67, 69, 72]; 10467 * 10468 * function setup() { 10469 * let cnv = createCanvas(100, 100); 10470 * cnv.mousePressed(canvasPressed); 10471 * colorMode(HSB); 10472 * background(0, 0, 86); 10473 * text('tap to start/stop', 10, 20); 10474 * 10475 * //the looper's callback is passed the timeFromNow 10476 * //this value should be used as a reference point from 10477 * //which to schedule sounds 10478 * let intervalInSeconds = 0.2; 10479 * soundLoop = new p5.SoundLoop(onSoundLoop, intervalInSeconds); 10480 * 10481 * synth = new p5.MonoSynth(); 10482 * } 10483 * 10484 * function canvasPressed() { 10485 * // ensure audio is enabled 10486 * userStartAudio(); 10487 * 10488 * if (soundLoop.isPlaying) { 10489 * soundLoop.stop(); 10490 * } else { 10491 * // start the loop 10492 * soundLoop.start(); 10493 * } 10494 * } 10495 * 10496 * function onSoundLoop(timeFromNow) { 10497 * let noteIndex = (soundLoop.iterations - 1) % notePattern.length; 10498 * let note = midiToFreq(notePattern[noteIndex]); 10499 * synth.play(note, 0.5, timeFromNow); 10500 * background(noteIndex * 360 / notePattern.length, 50, 100); 10501 * } 10502 * </code></div> 10503 */ 10504 10505 10506 p5.SoundLoop = function (callback, interval) { 10507 this.callback = callback; 10508 /** 10509 * musicalTimeMode uses <a href = "https://github.com/Tonejs/Tone.js/wiki/Time">Tone.Time</a> convention 10510 * true if string, false if number 10511 * @property {Boolean} musicalTimeMode 10512 */ 10513 10514 this.musicalTimeMode = typeof this._interval === 'number' ? false : true; 10515 this._interval = interval || 1; 10516 /** 10517 * musicalTimeMode variables 10518 * modify these only when the interval is specified in musicalTime format as a string 10519 */ 10520 10521 this._timeSignature = 4; 10522 this._bpm = 60; 10523 this.isPlaying = false;
10524 /** 10525 * Set a limit to the number of loops to play. defaults to Infinity 10526 * @property {Number} maxIterations 10527 */ 10528 10529 this.maxIterations = Infinity; 10530 var self = this; 10531 this.clock = new Clock({ 10532 'callback': function callback(time) { 10533 var timeFromNow = time - p5sound.audiocontext.currentTime; 10534 /** 10535 * Do not initiate the callback if timeFromNow is < 0 10536 * This ususually occurs for a few milliseconds when the page 10537 * is not fully loaded 10538 * 10539 * The callback should only be called until maxIterations is reached 10540 */ 10541 10542 if (timeFromNow > 0 && self.iterations <= self.maxIterations) { 10543 self.callback(timeFromNow); 10544 } 10545 }, 10546 'frequency': this._calcFreq() 10547 }); 10548 }; 10549 /** 10550 * Start the loop 10551 * @method start 10552 * @for p5.SoundLoop 10553 * @param {Number} [timeFromNow] schedule a starting time 10554 */ 10555 10556 10557 p5.SoundLoop.prototype.start = function (timeFromNow) { 10558 var t = timeFromNow || 0; 10559 var now = p5sound.audiocontext.currentTime; 10560 10561 if (!this.isPlaying) { 10562 this.clock.start(now + t); 10563 this.isPlaying = true; 10564 } 10565 }; 10566 /** 10567 * Stop the loop 10568 * @method stop 10569 * @for p5.SoundLoop 10570 * @param {Number} [timeFromNow] schedule a stopping time 10571 */ 10572 10573 10574 p5.SoundLoop.prototype.stop = function (timeFromNow) { 10575 var t = timeFromNow || 0; 10576 var now = p5sound.audiocontext.currentTime; 10577 10578 if (this.isPlaying) { 10579 this.clock.stop(now + t); 10580 this.isPlaying = false; 10581 } 10582 }; 10583 /** 10584 * Pause the loop 10585 * @method pause 10586 * @for p5.SoundLoop 10587 * @param {Number} [timeFromNow] schedule a pausing time 10588 */ 10589 10590 10591 p5.SoundLoop.prototype.pause = function (timeFromNow) { 10592 var t = timeFromNow || 0; 10593 var now = p5sound.audiocontext.currentTime; 10594 10595 if (this.isPlaying) { 10596 this.clock.pause(now + t); 10597 this.isPlaying = false; 10598 } 10599 }; 10600 /** 10601 * Synchronize loops. Use this method to start two more more loops in synchronization 10602 * or to start a loop in synchronization with a loop that is already playing 10603 * This method will schedule the implicit loop in sync with the explicit master loop 10604 * i.e. loopToStart.syncedStart(loopToSyncWith) 10605 * 10606 * @method syncedStart 10607 * @for p5.SoundLoop 10608 * @param {Object} otherLoop a p5.SoundLoop to sync with 10609 * @param {Number} [timeFromNow] Start the loops in sync after timeFromNow seconds 10610 */ 10611 10612 10613 p5.SoundLoop.prototype.syncedStart = function (otherLoop, timeFromNow) { 10614 var t = timeFromNow || 0; 10615 var now = p5sound.audiocontext.currentTime; 10616 10617 if (!otherLoop.isPlaying) { 10618 otherLoop.clock.start(now + t); 10619 otherLoop.isPlaying = true; 10620 this.clock.start(now + t); 10621 this.isPlaying = true; 10622 } else if (otherLoop.isPlaying) { 10623 var time = otherLoop.clock._nextTick - p5sound.audiocontext.currentTime; 10624 this.clock.start(now + time); 10625 this.isPlaying = true; 10626 } 10627 }; 10628 /** 10629 * Updates frequency value, reflected in next callback 10630 * @private 10631 * @for p5.SoundLoop 10632 * @method _update 10633 */ 10634 10635 10636 p5.SoundLoop.prototype._update = function () { 10637 this.clock.frequency.value = this._calcFreq(); 10638 }; 10639 /** 10640 * Calculate the frequency of the clock's callback based on bpm, interval, and timesignature 10641 * @private 10642 * @for p5.SoundLoop 10643 * @method _calcFreq 10644 * @return {Number} new clock frequency value 10645 */ 10646 10647 10648 p5.SoundLoop.prototype._calcFreq = function () { 10649 if (typeof this._interval === 'number') { 10650 this.musicalTimeMode = false; 10651 return 1 / this._interval; 10652 } 10653 else if (typeof this._interval === 'string') { 10654 this.musicalTimeMode = true; 10655 return this._bpm / 60 / this._convertNotation(this._interval) * (this._timeSignature / 4); 10656 } 10657 }; 10658 /** 10659 * Convert notation from musical time format to seconds 10660 * Uses <a href = "https://github.com/Tonejs/Tone.js/wiki/Time">Tone.Time</a> convention 10661 * @private 10662 * @for p5.SoundLoop 10663 * @method _convertNotation 10664 * @param {String} value value to be converted 10665 * @return {Number} converted value in seconds 10666 */ 10667 10668 10669 p5.SoundLoop.prototype._convertNotation = function (value) { 10670 var type = value.slice(-1); 10671 value = Number(value.slice(0, -1)); 10672 10673 switch (type) { 10674 case 'm': 10675 return this._measure(value); 10676 10677 case 'n': 10678 return this._note(value); 10679 10680 default: 10681 console.warn('Specified interval is not formatted correctly. See Tone.js ' + 'timing reference for more info: https://github.com/Tonejs/Tone.js/wiki/Time'); 10682 } 10683 }; 10684 /** 10685 * Helper conversion methods of measure and note 10686 * @private 10687 * @for p5.SoundLoop 10688 * @method _measure 10689 */ 10690 10691 10692 p5.SoundLoop.prototype._measure = function (value) { 10693 return value * this._timeSignature; 10694 }; 10695 /** 10696 * @private 10697 * @method _note 10698 * @for p5.SoundLoop 10699 */ 10700 10701 10702 p5.SoundLoop.prototype._note = function (value) { 10703 return this._timeSignature / value; 10704 }; 10705 /** 10706 * Getters and Setters, setting any paramter will result in a change in the clock's 10707 * frequency, that will be reflected after the next callback 10708 * beats per minute (defaults to 60) 10709 * @property {Number} bpm 10710 * @for p5.SoundLoop 10711 */ 10712 10713 10714 Object.defineProperty(p5.SoundLoop.prototype, 'bpm', { 10715 get: function get() { 10716 return this._bpm; 10717 }, 10718 set: function set(bpm) { 10719 if (!this.musicalTimeMode) { 10720 console.warn('Changing the BPM in "seconds" mode has no effect. ' + 'BPM is only relevant in musicalTimeMode ' + 'when the interval is specified as a string ' + '("2n", "4n", "1m"...etc)'); 10721 } 10722 10723 this._bpm = bpm; 10724 10725 this._update(); 10726 } 10727 }); 10728 /** 10729 * number of quarter notes in a measure (defaults to 4) 10730 * @property {Number} timeSignature 10731 * @for p5.SoundLoop 10732 */ 10733 10734 Object.defineProperty(p5.SoundLoop.prototype, 'timeSignature', { 10735 get: function get() { 10736 return this._timeSignature; 10737 }, 10738 set: function set(timeSig) { 10739 if (!this.musicalTimeMode) { 10740 console.warn('Changing the timeSignature in "seconds" mode has no effect. ' + 'BPM is only relevant in musicalTimeMode ' + 'when the interval is specified as a string ' + '("2n", "4n", "1m"...etc)'); 10741 } 10742 10743 this._timeSignature = timeSig; 10744 10745 this._update(); 10746 } 10747 }); 10748 /** 10749 * length of the loops interval 10750 * @property {Number|String} interval 10751 * @for p5.SoundLoop 10752 */ 10753 10754 Object.defineProperty(p5.SoundLoop.prototype, 'interval', { 10755 get: function get() { 10756 return this._interval; 10757 }, 10758 set: function set(interval) { 10759 this.musicalTimeMode = typeof interval === 'Number' ? false : true; 10760 this._interval = interval; 10761 10762 this._update(); 10763 } 10764 }); 10765 /** 10766 * how many times the callback has been called so far 10767 * @property {Number} iterations 10768 * @for p5.SoundLoop 10769 * @readonly 10770 */ 10771 10772 Object.defineProperty(p5.SoundLoop.prototype, 'iterations', { 10773 get: function get() { 10774 return this.clock.ticks; 10775 } 10776 }); 10777 return p5.SoundLoop; 10778}).call(exports, __webpack_require__, exports, module), 10779 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 10780 10781 }), 10782 (function(module, exports, __webpack_require__) { 10783 10784var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 10785 'use strict'; 10786 10787 var p5sound = __webpack_require__(1); 10788 10789 var Effect = __webpack_require__(4); 10790 10791 var CustomError = __webpack_require__(11); 10792 /** 10793 * Compressor is an audio effect class that performs dynamics compression 10794 * on an audio input source. This is a very commonly used technique in music 10795 * and sound production. Compression creates an overall louder, richer, 10796 * and fuller sound by lowering the volume of louds and raising that of softs. 10797 * Compression can be used to avoid clipping (sound distortion due to 10798 * peaks in volume) and is especially useful when many sounds are played 10799 * at once. Compression can be used on indivudal sound sources in addition 10800 * to the master output. 10801 * 10802 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 10803 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 10804 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 10805 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 10806 * 10807 * @class p5.Compressor 10808 * @constructor
10809 * @extends p5.Effect 10810 * 10811 * 10812 */ 10813 10814 10815 p5.Compressor = function () { 10816 Effect.call(this); 10817 /** 10818 * The p5.Compressor is built with a <a href="https://www.w3.org/TR/webaudio/#the-dynamicscompressornode-interface" 10819 * target="_blank" title="W3 spec for Dynamics Compressor Node">Web Audio Dynamics Compressor Node 10820 * </a> 10821 * @property {AudioNode} compressor 10822 */ 10823 10824 this.compressor = this.ac.createDynamicsCompressor(); 10825 this.input.connect(this.compressor); 10826 this.compressor.connect(this.wet); 10827 }; 10828 10829 p5.Compressor.prototype = Object.create(Effect.prototype); 10830 /** 10831 * Performs the same function as .connect, but also accepts 10832 * optional parameters to set compressor's audioParams 10833 * @method process 10834 * @for p5.Compressor 10835 * 10836 * @param {Object} src Sound source to be connected 10837 * 10838 * @param {Number} [attack] The amount of time (in seconds) to reduce the gain by 10dB, 10839 * default = .003, range 0 - 1 10840 * @param {Number} [knee] A decibel value representing the range above the 10841 * threshold where the curve smoothly transitions to the "ratio" portion. 10842 * default = 30, range 0 - 40 10843 * @param {Number} [ratio] The amount of dB change in input for a 1 dB change in output 10844 * default = 12, range 1 - 20 10845 * @param {Number} [threshold] The decibel value above which the compression will start taking effect 10846 * default = -24, range -100 - 0 10847 * @param {Number} [release] The amount of time (in seconds) to increase the gain by 10dB 10848 * default = .25, range 0 - 1 10849 */ 10850 10851 p5.Compressor.prototype.process = function (src, attack, knee, ratio, threshold, release) { 10852 src.connect(this.input); 10853 this.set(attack, knee, ratio, threshold, release); 10854 }; 10855 /** 10856 * Set the paramters of a compressor. 10857 * @method set 10858 * @for p5.Compressor 10859 * @param {Number} attack The amount of time (in seconds) to reduce the gain by 10dB, 10860 * default = .003, range 0 - 1 10861 * @param {Number} knee A decibel value representing the range above the 10862 * threshold where the curve smoothly transitions to the "ratio" portion. 10863 * default = 30, range 0 - 40 10864 * @param {Number} ratio The amount of dB change in input for a 1 dB change in output 10865 * default = 12, range 1 - 20 10866 * @param {Number} threshold The decibel value above which the compression will start taking effect 10867 * default = -24, range -100 - 0 10868 * @param {Number} release The amount of time (in seconds) to increase the gain by 10dB 10869 * default = .25, range 0 - 1 10870 */ 10871 10872 10873 p5.Compressor.prototype.set = function (attack, knee, ratio, threshold, release) { 10874 if (typeof attack !== 'undefined') { 10875 this.attack(attack); 10876 } 10877 10878 if (typeof knee !== 'undefined') { 10879 this.knee(knee); 10880 } 10881 10882 if (typeof ratio !== 'undefined') { 10883 this.ratio(ratio); 10884 } 10885 10886 if (typeof threshold !== 'undefined') { 10887 this.threshold(threshold); 10888 } 10889 10890 if (typeof release !== 'undefined') { 10891 this.release(release); 10892 } 10893 }; 10894 /** 10895 * Get current attack or set value w/ time ramp 10896 * 10897 * 10898 * @method attack 10899 * @for p5.Compressor 10900 * @param {Number} [attack] Attack is the amount of time (in seconds) to reduce the gain by 10dB, 10901 * default = .003, range 0 - 1 10902 * @param {Number} [time] Assign time value to schedule the change in value 10903 */ 10904 10905 10906 p5.Compressor.prototype.attack = function (attack, time) { 10907 var t = time || 0; 10908 10909 if (typeof attack == 'number') { 10910 this.compressor.attack.value = attack; 10911 this.compressor.attack.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 10912 this.compressor.attack.linearRampToValueAtTime(attack, this.ac.currentTime + 0.02 + t); 10913 } else if (typeof attack !== 'undefined') { 10914 attack.connect(this.compressor.attack); 10915 } 10916 10917 return this.compressor.attack.value; 10918 }; 10919 /** 10920 * Get current knee or set value w/ time ramp 10921 * 10922 * @method knee 10923 * @for p5.Compressor 10924 * @param {Number} [knee] A decibel value representing the range above the 10925 * threshold where the curve smoothly transitions to the "ratio" portion. 10926 * default = 30, range 0 - 40 10927 * @param {Number} [time] Assign time value to schedule the change in value 10928 */ 10929 10930 10931 p5.Compressor.prototype.knee = function (knee, time) { 10932 var t = time || 0; 10933 10934 if (typeof knee == 'number') { 10935 this.compressor.knee.value = knee; 10936 this.compressor.knee.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 10937 this.compressor.knee.linearRampToValueAtTime(knee, this.ac.currentTime + 0.02 + t); 10938 } else if (typeof knee !== 'undefined') { 10939 knee.connect(this.compressor.knee); 10940 } 10941 10942 return this.compressor.knee.value; 10943 }; 10944 /** 10945 * Get current ratio or set value w/ time ramp 10946 * @method ratio 10947 * @for p5.Compressor 10948 * @param {Number} [ratio] The amount of dB change in input for a 1 dB change in output 10949 * default = 12, range 1 - 20 10950 * @param {Number} [time] Assign time value to schedule the change in value 10951 */ 10952 10953 10954 p5.Compressor.prototype.ratio = function (ratio, time) { 10955 var t = time || 0; 10956 10957 if (typeof ratio == 'number') { 10958 this.compressor.ratio.value = ratio; 10959 this.compressor.ratio.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 10960 this.compressor.ratio.linearRampToValueAtTime(ratio, this.ac.currentTime + 0.02 + t); 10961 } else if (typeof ratio !== 'undefined') { 10962 ratio.connect(this.compressor.ratio); 10963 } 10964 10965 return this.compressor.ratio.value; 10966 }; 10967 /** 10968 * Get current threshold or set value w/ time ramp 10969 * @method threshold 10970 * @for p5.Compressor 10971 * @param {Number} threshold The decibel value above which the compression will start taking effect 10972 * default = -24, range -100 - 0 10973 * @param {Number} [time] Assign time value to schedule the change in value 10974 */ 10975 10976 10977 p5.Compressor.prototype.threshold = function (threshold, time) { 10978 var t = time || 0; 10979 10980 if (typeof threshold == 'number') { 10981 this.compressor.threshold.value = threshold; 10982 this.compressor.threshold.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 10983 this.compressor.threshold.linearRampToValueAtTime(threshold, this.ac.currentTime + 0.02 + t); 10984 } else if (typeof threshold !== 'undefined') { 10985 threshold.connect(this.compressor.threshold); 10986 } 10987 10988 return this.compressor.threshold.value; 10989 }; 10990 /** 10991 * Get current release or set value w/ time ramp 10992 * @method release 10993 * @for p5.Compressor 10994 * @param {Number} release The amount of time (in seconds) to increase the gain by 10dB 10995 * default = .25, range 0 - 1 10996 * 10997 * @param {Number} [time] Assign time value to schedule the change in value 10998 */ 10999 11000 11001 p5.Compressor.prototype.release = function (release, time) { 11002 var t = time || 0; 11003 11004 if (typeof release == 'number') { 11005 this.compressor.release.value = release; 11006 this.compressor.release.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 11007 this.compressor.release.linearRampToValueAtTime(release, this.ac.currentTime + 0.02 + t); 11008 } else if (typeof number !== 'undefined') { 11009 release.connect(this.compressor.release); 11010 } 11011 11012 return this.compressor.release.value; 11013 }; 11014 /** 11015 * Return the current reduction value 11016 * 11017 * @method reduction 11018 * @for p5.Compressor 11019 * @return {Number} Value of the amount of gain reduction that is applied to the signal 11020 */ 11021 11022 11023 p5.Compressor.prototype.reduction = function () { 11024 return this.compressor.reduction.value; 11025 }; 11026 11027 p5.Compressor.prototype.dispose = function () { 11028 Effect.prototype.dispose.apply(this); 11029 11030 if (this.compressor) { 11031 this.compressor.disconnect(); 11032 delete this.compressor; 11033 } 11034 }; 11035 11036 return p5.Compressor; 11037}).call(exports, __webpack_require__, exports, module), 11038 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 11039 11040 }), 11041 (function(module, exports, __webpack_require__) { 11042 11043"use strict"; 11044var __WEBPACK_AMD_DEFINE_RESULT__; 11045 11046!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 11047 var p5sound = __webpack_require__(1); 11048 11049 var _require = __webpack_require__(6), 11050 convertToWav = _require.convertToWav, 11051 safeBufferSize = _require.safeBufferSize; 11052 11053 var processorNames = __webpack_require__(10); 11054 11055 var ac = p5sound.audiocontext; 11056 /** 11057 * <p>
11057Record sounds for playback and/or to save as a .wav file. 11058 * The p5.SoundRecorder records all sound output from your sketch, 11059 * or can be assigned a specific source with setInput().</p> 11060 * <p>The record() method accepts a p5.SoundFile as a parameter. 11061 * When playback is stopped (either after the given amount of time, 11062 * or with the stop() method), the p5.SoundRecorder will send its 11063 * recording to that p5.SoundFile for playback.</p> 11064 * 11065 * @class p5.SoundRecorder 11066 * @constructor 11067 * @example 11068 * <div><code> 11069 * let mic, recorder, soundFile; 11070 * let state = 0; 11071 * 11072 * function setup() { 11073 * let cnv = createCanvas(100, 100); 11074 * cnv.mousePressed(canvasPressed); 11075 * background(220); 11076 * textAlign(CENTER, CENTER); 11077 * 11078 * // create an audio in 11079 * mic = new p5.AudioIn(); 11080 * 11081 * // prompts user to enable their browser mic 11082 * mic.start(); 11083 * 11084 * // create a sound recorder 11085 * recorder = new p5.SoundRecorder(); 11086 * 11087 * // connect the mic to the recorder 11088 * recorder.setInput(mic); 11089 * 11090 * // this sound file will be used to 11091 * // playback & save the recording 11092 * soundFile = new p5.SoundFile(); 11093 * 11094 * text('tap to record', width/2, height/2); 11095 * } 11096 * 11097 * function canvasPressed() { 11098 * // ensure audio is enabled 11099 * userStartAudio(); 11100 * 11101 * // make sure user enabled the mic 11102 * if (state === 0 && mic.enabled) { 11103 * 11104 * // record to our p5.SoundFile 11105 * recorder.record(soundFile); 11106 * 11107 * background(255,0,0); 11108 * text('Recording!', width/2, height/2); 11109 * state++; 11110 * } 11111 * else if (state === 1) { 11112 * background(0,255,0); 11113 * 11114 * // stop recorder and 11115 * // send result to soundFile 11116 * recorder.stop(); 11117 * 11118 * text('Done! Tap to play and download', width/2, height/2, width - 20); 11119 * state++; 11120 * } 11121 * 11122 * else if (state === 2) { 11123 * soundFile.play(); // play the result! 11124 * save(soundFile, 'mySound.wav'); 11125 * state++; 11126 * } 11127 * } 11128 * </div></code> 11129 */ 11130 11131 p5.SoundRecorder = function () { 11132 this.input = ac.createGain(); 11133 this.output = ac.createGain(); 11134 this._inputChannels = 2; 11135 this._outputChannels = 2; 11136 11137 var workletBufferSize = safeBufferSize(1024); 11138 this._workletNode = new AudioWorkletNode(ac, processorNames.recorderProcessor, { 11139 outputChannelCount: [this._outputChannels], 11140 processorOptions: { 11141 numInputChannels: this._inputChannels, 11142 bufferSize: workletBufferSize 11143 } 11144 }); 11145 11146 this._workletNode.port.onmessage = function (event) { 11147 if (event.data.name === 'buffers') { 11148 var buffers = [new Float32Array(event.data.leftBuffer), new Float32Array(event.data.rightBuffer)]; 11149 11150 this._callback(buffers); 11151 } 11152 }.bind(this); 11153 /** 11154 * callback invoked when the recording is over 11155 * @private 11156 * @type Function(Float32Array) 11157 */ 11158 11159 11160 this._callback = function () {}; 11161 11162 11163 this._workletNode.connect(p5.soundOut._silentNode); 11164 11165 this.setInput(); 11166 11167 p5sound.soundArray.push(this); 11168 }; 11169 /** 11170 * Connect a specific device to the p5.SoundRecorder. 11171 * If no parameter is given, p5.SoundRecorer will record 11172 * all audible p5.sound from your sketch. 11173 * 11174 * @method setInput 11175 * @for p5.SoundRecorder 11176 * @param {Object} [unit] p5.sound object or a web audio unit 11177 * that outputs sound 11178 */ 11179 11180 11181 p5.SoundRecorder.prototype.setInput = function (unit) { 11182 this.input.disconnect(); 11183 this.input = null; 11184 this.input = ac.createGain(); 11185 this.input.connect(this._workletNode); 11186 this.input.connect(this.output); 11187 11188 if (unit) { 11189 unit.connect(this.input); 11190 } else { 11191 p5.soundOut.output.connect(this.input); 11192 } 11193 }; 11194 /** 11195 * Start recording. To access the recording, provide 11196 * a p5.SoundFile as the first parameter. The p5.SoundRecorder 11197 * will send its recording to that p5.SoundFile for playback once 11198 * recording is complete. Optional parameters include duration 11199 * (in seconds) of the recording, and a callback function that 11200 * will be called once the complete recording has been 11201 * transfered to the p5.SoundFile. 11202 * 11203 * @method record 11204 * @for p5.SoundRecorder 11205 * @param {p5.SoundFile} soundFile p5.SoundFile 11206 * @param {Number} [duration] Time (in seconds) 11207 * @param {Function} [callback] The name of a function that will be 11208 * called once the recording completes 11209 */ 11210 11211 11212 p5.SoundRecorder.prototype.record = function (sFile, duration, callback) { 11213 this._workletNode.port.postMessage({ 11214 name: 'start', 11215 duration: duration 11216 }); 11217 11218 if (sFile && callback) { 11219 this._callback = function (buffer) { 11220 sFile.setBuffer(buffer); 11221 callback(); 11222 }; 11223 } else if (sFile) { 11224 this._callback = function (buffer) { 11225 sFile.setBuffer(buffer); 11226 }; 11227 } 11228 }; 11229 /** 11230 * Stop the recording. Once the recording is stopped, 11231 * the results will be sent to the p5.SoundFile that 11232 * was given on .record(), and if a callback function 11233 * was provided on record, that function will be called. 11234 * 11235 * @method stop 11236 * @for p5.SoundRecorder 11237 */ 11238 11239 11240 p5.SoundRecorder.prototype.stop = function () { 11241 this._workletNode.port.postMessage({ 11242 name: 'stop' 11243 }); 11244 }; 11245 11246 p5.SoundRecorder.prototype.dispose = function () { 11247 var index = p5sound.soundArray.indexOf(this); 11248 p5sound.soundArray.splice(index, 1); 11249 11250 this._callback = function () {}; 11251 11252 if (this.input) { 11253 this.input.disconnect(); 11254 } 11255 11256 this.input = null; 11257 this._workletNode = null; 11258 }; 11259 /** 11260 * Save a p5.SoundFile as a .wav file. The browser will prompt the user 11261 * to download the file to their device. 11262 * For uploading audio to a server, use 11263 * <a href="/docs/reference/#/p5.SoundFile/saveBlob">`p5.SoundFile.saveBlob`</a>. 11264 * 11265 * @for p5 11266 * @method saveSound 11267 * @param {p5.SoundFile}
11267 soundFile p5.SoundFile that you wish to save 11268 * @param {String} fileName name of the resulting .wav file. 11269 */ 11270 11271 11272 p5.prototype.saveSound = function (soundFile, fileName) { 11273 var dataView = convertToWav(soundFile.buffer); 11274 p5.prototype.writeFile([dataView], fileName, 'wav'); 11275 }; 11276}).call(exports, __webpack_require__, exports, module), 11277 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 11278 11279 }), 11280 (function(module, exports, __webpack_require__) { 11281 11282"use strict"; 11283var __WEBPACK_AMD_DEFINE_RESULT__; 11284 11285!(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { 11286 /** 11287 * <p>PeakDetect works in conjunction with p5.FFT to 11288 * look for onsets in some or all of the frequency spectrum. 11289 * </p> 11290 * <p> 11291 * To use p5.PeakDetect, call <code>update</code> in the draw loop 11292 * and pass in a p5.FFT object. 11293 * </p> 11294 * <p> 11295 * You can listen for a specific part of the frequency spectrum by 11296 * setting the range between <code>freq1</code> and <code>freq2</code>. 11297 * </p> 11298 * 11299 * <p><code>threshold</code> is the threshold for detecting a peak, 11300 * scaled between 0 and 1. It is logarithmic, so 0.1 is half as loud 11301 * as 1.0.</p> 11302 * 11303 * <p> 11304 * The update method is meant to be run in the draw loop, and 11305 * <b>frames</b> determines how many loops must pass before 11306 * another peak can be detected. 11307 * For example, if the frameRate() = 60, you could detect the beat of a 11308 * 120 beat-per-minute song with this equation: 11309 * <code> framesPerPeak = 60 / (estimatedBPM / 60 );</code> 11310 * </p> 11311 * 11312 * <p> 11313 * Based on example contribtued by @b2renger, and a simple beat detection 11314 * explanation by <a 11315 * href="http://www.airtightinteractive.com/2013/10/making-audio-reactive-visuals/" 11316 * target="_blank">Felix Turner</a>. 11317 * </p> 11318 * 11319 * @class p5.PeakDetect 11320 * @constructor 11321 * @param {Number} [freq1] lowFrequency - defaults to 20Hz 11322 * @param {Number} [freq2] highFrequency - defaults to 20000 Hz 11323 * @param {Number} [threshold] Threshold for detecting a beat between 0 and 1 11324 * scaled logarithmically where 0.1 is 1/2 the loudness 11325 * of 1.0. Defaults to 0.35. 11326 * @param {Number} [framesPerPeak] Defaults to 20. 11327 * @example 11328 * <div><code> 11329 * 11330 * var cnv, soundFile, fft, peakDetect; 11331 * var ellipseWidth = 10; 11332 * 11333 * function preload() { 11334 * soundFile = loadSound('assets/beat.mp3'); 11335 * } 11336 * 11337 * function setup() { 11338 * background(0); 11339 * noStroke(); 11340 * fill(255); 11341 * textAlign(CENTER); 11342 * 11343 * // p5.PeakDetect requires a p5.FFT 11344 * fft = new p5.FFT(); 11345 * peakDetect = new p5.PeakDetect(); 11346 * } 11347 * 11348 * function draw() { 11349 * background(0); 11350 * text('click to play/pause', width/2, height/2); 11351 * 11352 * // peakDetect accepts an fft post-analysis 11353 * fft.analyze(); 11354 * peakDetect.update(fft); 11355 * 11356 * if ( peakDetect.isDetected ) { 11357 * ellipseWidth = 50; 11358 * } else { 11359 * ellipseWidth *= 0.95; 11360 * } 11361 * 11362 * ellipse(width/2, height/2, ellipseWidth, ellipseWidth); 11363 * } 11364 * 11365 * // toggle play/stop when canvas is clicked 11366 * function mouseClicked() { 11367 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 11368 * if (soundFile.isPlaying() ) { 11369 * soundFile.stop(); 11370 * } else { 11371 * soundFile.play(); 11372 * } 11373 * } 11374 * } 11375 * </code></div> 11376 */ 11377 p5.PeakDetect = function (freq1, freq2, threshold, _framesPerPeak) { 11378 this.framesPerPeak = _framesPerPeak || 20; 11379 this.framesSinceLastPeak = 0; 11380 this.decayRate = 0.95; 11381 this.threshold = threshold || 0.35; 11382 this.cutoff = 0; 11383 11384 this.cutoffMult = 1.5; 11385 this.energy = 0; 11386 this.penergy = 0; 11387 11388 this.currentValue = 0; 11389 /** 11390 * isDetected is set to true when a peak is detected. 11391 * 11392 * @attribute isDetected {Boolean} 11393 * @default false 11394 */ 11395 11396 this.isDetected = false; 11397 this.f1 = freq1 || 40; 11398 this.f2 = freq2 || 20000; 11399 11400 this._onPeak = function () {}; 11401 }; 11402 /** 11403 * The update method is run in the draw loop. 11404 * 11405 * Accepts an FFT object. You must call .analyze() 11406 * on the FFT object prior to updating the peakDetect 11407 * because it relies on a completed FFT analysis. 11408 * 11409 * @method update 11410 * @param {p5.FFT} fftObject A p5.FFT object 11411 */ 11412 11413 11414 p5.PeakDetect.prototype.update = function (fftObject) { 11415 var nrg = this.energy = fftObject.getEnergy(this.f1, this.f2) / 255; 11416 11417 if (nrg > this.cutoff && nrg > this.threshold && nrg - this.penergy > 0) { 11418 this._onPeak(); 11419 11420 this.isDetected = true; 11421 11422 this.cutoff = nrg * this.cutoffMult; 11423 this.framesSinceLastPeak = 0; 11424 } else { 11425 this.isDetected = false;
11426 11427 if (this.framesSinceLastPeak <= this.framesPerPeak) { 11428 this.framesSinceLastPeak++; 11429 } else { 11430 this.cutoff *= this.decayRate; 11431 this.cutoff = Math.max(this.cutoff, this.threshold); 11432 } 11433 } 11434 11435 this.currentValue = nrg; 11436 this.penergy = nrg; 11437 }; 11438 /** 11439 * onPeak accepts two arguments: a function to call when 11440 * a peak is detected. The value of the peak, 11441 * between 0.0 and 1.0, is passed to the callback. 11442 * 11443 * @method onPeak 11444 * @param {Function} callback Name of a function that will 11445 * be called when a peak is 11446 * detected. 11447 * @param {Object} [val] Optional value to pass 11448 * into the function when 11449 * a peak is detected. 11450 * @example 11451 * <div><code> 11452 * var cnv, soundFile, fft, peakDetect; 11453 * var ellipseWidth = 0; 11454 * 11455 * function preload() { 11456 * soundFile = loadSound('assets/beat.mp3'); 11457 * } 11458 * 11459 * function setup() { 11460 * cnv = createCanvas(100,100); 11461 * textAlign(CENTER); 11462 * 11463 * fft = new p5.FFT(); 11464 * peakDetect = new p5.PeakDetect(); 11465 * 11466 * setupSound(); 11467 * 11468 * // when a beat is detected, call triggerBeat() 11469 * peakDetect.onPeak(triggerBeat); 11470 * } 11471 * 11472 * function draw() { 11473 * background(0); 11474 * fill(255); 11475 * text('click to play', width/2, height/2); 11476 * 11477 * fft.analyze(); 11478 * peakDetect.update(fft); 11479 * 11480 * ellipseWidth *= 0.95; 11481 * ellipse(width/2, height/2, ellipseWidth, ellipseWidth); 11482 * } 11483 * 11484 * // this function is called by peakDetect.onPeak 11485 * function triggerBeat() { 11486 * ellipseWidth = 50; 11487 * } 11488 * 11489 * // mouseclick starts/stops sound 11490 * function setupSound() { 11491 * cnv.mouseClicked( function() { 11492 * if (soundFile.isPlaying() ) { 11493 * soundFile.stop(); 11494 * } else { 11495 * soundFile.play(); 11496 * } 11497 * }); 11498 * } 11499 * </code></div> 11500 */ 11501 11502 11503 p5.PeakDetect.prototype.onPeak = function (callback, val) { 11504 var self = this; 11505 11506 self._onPeak = function () { 11507 callback(self.energy, val); 11508 }; 11509 }; 11510}).call(exports, __webpack_require__, exports, module), 11511 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 11512 11513 }), 11514 (function(module, exports, __webpack_require__) { 11515 11516"use strict"; 11517var __WEBPACK_AMD_DEFINE_RESULT__; 11518 11519!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 11520 var p5sound = __webpack_require__(1); 11521 /** 11522 * A gain node is usefull to set the relative volume of sound. 11523 * It's typically used to build mixers. 11524 * 11525 * @class p5.Gain 11526 * @constructor 11527 * @example 11528 * <div><code> 11529 * 11530 * // load two soundfile and crossfade beetween them 11531 * let sound1,sound2; 11532 * let sound1Gain, sound2Gain, masterGain; 11533 * function preload(){ 11534 * soundFormats('ogg', 'mp3'); 11535 * sound1 = loadSound('assets/Damscray_-_Dancing_Tiger_01'); 11536 * sound2 = loadSound('assets/beat'); 11537 * } 11538 * function setup() { 11539 * let cnv = createCanvas(100, 100); 11540 * cnv.mousePressed(startSound); 11541 * // create a 'master' gain to which we will connect both soundfiles 11542 * masterGain = new p5.Gain(); 11543 * masterGain.connect(); 11544 * sound1.disconnect(); // diconnect from p5 output 11545 * sound1Gain = new p5.Gain(); // setup a gain node 11546 * sound1Gain.setInput(sound1); // connect the first sound to its input 11547 * sound1Gain.connect(masterGain); // connect its output to the 'master' 11548 * sound2.disconnect(); 11549 * sound2Gain = new p5.Gain(); 11550 * sound2Gain.setInput(sound2); 11551 * sound2Gain.connect(masterGain); 11552 * } 11553 * function startSound() { 11554 * sound1.loop(); 11555 * sound2.loop(); 11556 * loop(); 11557 * } 11558 * function mouseReleased() { 11559 * sound1.stop(); 11560 * sound2.stop(); 11561 * } 11562 * function draw(){ 11563 * background(220); 11564 * textAlign(CENTER); 11565 * textSize(11); 11566 * fill(0); 11567 * if (!sound1.isPlaying()) { 11568 * text('tap and drag to play', width/2, height/2); 11569 * return; 11570 * } 11571 * // map the horizontal position of the mouse to values useable for volume * control of sound1 11572 * var sound1Volume = constrain(map(mouseX,width,0,0,1), 0, 1); 11573 * var sound2Volume = 1-sound1Volume; 11574 * sound1Gain.amp(sound1Volume); 11575 * sound2Gain.amp(sound2Volume); 11576 * // map the vertical position of the mouse to values useable for 'master * volume control' 11577 * var masterVolume = constrain(map(mouseY,height,0,0,1), 0, 1); 11578 * masterGain.amp(masterVolume); 11579 * text('master', width/2, height - masterVolume * height * 0.9) 11580 * fill(255, 0, 255); 11581 * textAlign(LEFT); 11582 * text('sound1', 5, height - sound1Volume * height * 0.9); 11583 * textAlign(RIGHT); 11584 * text('sound2', width - 5, height - sound2Volume * height * 0.9); 11585 * } 11586 *</code></div> 11587 */ 11588 11589 11590 p5.Gain = function () { 11591 this.ac = p5sound.audiocontext; 11592 this.input = this.ac.createGain(); 11593 this.output = this.ac.createGain(); 11594 11595 this.input.gain.value = 0.5; 11596 this.input.connect(this.output); 11597 11598 p5sound.soundArray.push(this); 11599 }; 11600 /** 11601 * Connect a source to the gain node. 11602 * 11603 * @method setInput 11604 * @for p5.Gain 11605 * @param {Object} src p5.sound / Web Audio object with a sound 11606 * output. 11607 */ 11608 11609 11610 p5.Gain.prototype.setInput = function (src) { 11611 src.connect(this.input); 11612 }; 11613 /** 11614 * Send output to a p5.sound or web audio object 11615 * 11616 * @method connect 11617 * @for p5.Gain 11618 * @param {Object} unit 11619 */ 11620 11621 11622 p5.Gain.prototype.connect = function (unit) { 11623 var u = unit || p5.soundOut.input; 11624 this.output.connect(u.input ? u.input : u); 11625 }; 11626 /** 11627 * Disconnect all output. 11628 * 11629 * @method disconnect 11630 * @for p5.Gain 11631 */ 11632 11633 11634 p5.Gain.prototype.disconnect = function () { 11635 if (this.output) { 11636 this.output.disconnect(); 11637 } 11638 }; 11639 /** 11640 * Set the output level of the gain node. 11641 * 11642 * @method amp 11643 * @for p5.Gain 11644 * @param {Number} volume amplitude between 0 and 1.0 11645 * @param {Number} [rampTime] create a fade that lasts rampTime 11646 * @param {Number} [timeFromNow] schedule this event to happen 11647 * seconds from now 11648 */ 11649 11650 11651 p5.Gain.prototype.amp = function (vol, rampTime, tFromNow) { 11652 var rampTime = rampTime || 0; 11653 var tFromNow = tFromNow || 0; 11654 var now = p5sound.audiocontext.currentTime; 11655 var currentVol = this.output.gain.value; 11656 this.output.gain.cancelScheduledValues(now); 11657 this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow); 11658 this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime); 11659 }; 11660 11661 p5.Gain.prototype.dispose = function () { 11662 var index = p5sound.soundArray.indexOf(this); 11663 p5sound.soundArray.splice(index, 1); 11664 11665 if (this.output) { 11666 this.output.disconnect(); 11667 delete this.output; 11668 } 11669 11670 if (this.input) { 11671 this.input.disconnect(); 11672 delete this.input; 11673 } 11674 }; 11675}).call(exports, __webpack_require__, exports, module), 11676 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 11677 11678 }), 11679 (function(module, exports, __webpack_require__) { 11680 11681"use strict"; 11682var __WEBPACK_AMD_DEFINE_RESULT__; 11683 11684!(__WEBPACK_AMD_DEFINE_RESULT__ = (function (require) { 11685 var Effect = __webpack_require__(4); 11686 11687 11688 function makeDistortionCurve(amount) { 11689 var k = typeof amount === 'number' ? amount : 50; 11690 var numSamples = 44100; 11691 var curve = new Float32Array(numSamples); 11692 var deg = Math.PI / 180; 11693 var i = 0; 11694 var x; 11695 11696 for (; i < numSamples; ++i) { 11697 x = i * 2 / numSamples - 1; 11698 curve[i] = (3 + k) * x * 20 * deg / (Math.PI + k * Math.abs(x)); 11699 } 11700 11701 return curve; 11702 } 11703 /** 11704 * A Distortion effect created with a Waveshaper Node, 11705 * with an approach adapted from 11706 * [Kevin Ennis](http://stackoverflow.com/questions/22312841/waveshaper-node
11706-in-webaudio-how-to-emulate-distortion) 11707 * 11708 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 11709 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 11710 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 11711 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 11712 * 11713 * @class p5.Distortion 11714 * @extends p5.Effect 11715 * @constructor 11716 * @param {Number} [amount=0.25] Unbounded distortion amount. 11717 * Normal values range from 0-1. 11718 * @param {String} [oversample='none'] 'none', '2x', or '4x'. 11719 * 11720 */ 11721 11722 11723 p5.Distortion = function (amount, oversample) { 11724 Effect.call(this); 11725 11726 if (typeof amount === 'undefined') { 11727 amount = 0.25; 11728 } 11729 11730 if (typeof amount !== 'number') { 11731 throw new Error('amount must be a number'); 11732 } 11733 11734 if (typeof oversample === 'undefined') { 11735 oversample = '2x'; 11736 } 11737 11738 if (typeof oversample !== 'string') { 11739 throw new Error('oversample must be a String'); 11740 } 11741 11742 var curveAmount = p5.prototype.map(amount, 0.0, 1.0, 0, 2000); 11743 /** 11744 * The p5.Distortion is built with a 11745 * <a href="http://www.w3.org/TR/webaudio/#WaveShaperNode"> 11746 * Web Audio WaveShaper Node</a>. 11747 * 11748 * @property {AudioNode} WaveShaperNode 11749 */ 11750 11751 this.waveShaperNode = this.ac.createWaveShaper(); 11752 this.amount = curveAmount; 11753 this.waveShaperNode.curve = makeDistortionCurve(curveAmount); 11754 this.waveShaperNode.oversample = oversample; 11755 this.input.connect(this.waveShaperNode); 11756 this.waveShaperNode.connect(this.wet); 11757 }; 11758 11759 p5.Distortion.prototype = Object.create(Effect.prototype); 11760 /** 11761 * Process a sound source, optionally specify amount and oversample values. 11762 * 11763 * @method process 11764 * @for p5.Distortion 11765 * @param {Number} [amount=0.25] Unbounded distortion amount. 11766 * Normal values range from 0-1. 11767 * @param {String} [oversample='none'] 'none', '2x', or '4x'. 11768 */ 11769 11770 p5.Distortion.prototype.process = function (src, amount, oversample) { 11771 src.connect(this.input); 11772 this.set(amount, oversample); 11773 }; 11774 /** 11775 * Set the amount and oversample of the waveshaper distortion. 11776 * 11777 * @method set 11778 * @for p5.Distortion 11779 * @param {Number} [amount=0.25] Unbounded distortion amount. 11780 * Normal values range from 0-1. 11781 * @param {String} [oversample='none'] 'none', '2x', or '4x'. 11782 */ 11783 11784 11785 p5.Distortion.prototype.set = function (amount, oversample) { 11786 if (amount) { 11787 var curveAmount = p5.prototype.map(amount, 0.0, 1.0, 0, 2000); 11788 this.amount = curveAmount; 11789 this.waveShaperNode.curve = makeDistortionCurve(curveAmount); 11790 } 11791 11792 if (oversample) { 11793 this.waveShaperNode.oversample = oversample; 11794 } 11795 }; 11796 /** 11797 * Return the distortion amount, typically between 0-1. 11798 * 11799 * @method getAmount 11800 * @for p5.Distortion 11801 * @return {Number} Unbounded distortion amount. 11802 * Normal values range from 0-1. 11803 */ 11804 11805 11806 p5.Distortion.prototype.getAmount = function () { 11807 return this.amount; 11808 }; 11809 /** 11810 * Return the oversampling. 11811 * 11812 * @method getOversample 11813 * @for p5.Distortion 11814 * @return {String} Oversample can either be 'none', '2x', or '4x'. 11815 */ 11816 11817 11818 p5.Distortion.prototype.getOversample = function () { 11819 return this.waveShaperNode.oversample; 11820 }; 11821 11822 p5.Distortion.prototype.dispose = function () { 11823 Effect.prototype.dispose.apply(this); 11824 11825 if (this.waveShaperNode) { 11826 this.waveShaperNode.disconnect(); 11827 this.waveShaperNode = null; 11828 } 11829 }; 11830}).call(exports, __webpack_require__, exports, module), 11831 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 11832 11833 }) 11834 ]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.