Comparing version 0.4.0 to 0.4.1
@@ -65,2 +65,6 @@ (function(root) { | ||
isAudioBufferSourceNode: function(audioNode) { | ||
return (audioNode && audioNode.toString() === "[object AudioBufferSourceNode]"); | ||
}, | ||
isEffect: function(effect) { | ||
@@ -213,3 +217,4 @@ for (var key in Pizzicato.Effects) | ||
this.fadeNode = Pizzicato.context.createGain(); | ||
this.fadeNode.gain.value = 0; | ||
if (!hasOptions || !description.options.detached) | ||
@@ -290,2 +295,4 @@ this.masterVolume.connect(Pizzicato.masterGainNode); | ||
this.sourceNode = this.getRawSourceNode(); | ||
this.sourceNode.gainSuccessor = Pz.context.createGain(); | ||
this.sourceNode.connect(this.sourceNode.gainSuccessor); | ||
@@ -337,4 +344,5 @@ if (util.isFunction(callback)) | ||
if (request.readyState === 4 && request.status !== 200) | ||
if (request.readyState === 4 && request.status !== 200) { | ||
console.error('Error while fetching ' + paths[0] + '. ' + request.statusText); | ||
} | ||
}; | ||
@@ -458,3 +466,3 @@ request.send(); | ||
var elapsedTime = Pz.context.currentTime - this.lastTimePlayed; | ||
// If we are using a buffer node - potentially in loop mode - we need to | ||
@@ -498,7 +506,15 @@ // know where to re-start the sound independently of the loop it is in. | ||
value: function() { | ||
if (this.playing) | ||
this.stop(); | ||
if (!this.paused) | ||
this.trigger('end'); | ||
value: function(node) { | ||
return function() { | ||
// This function may've been called from the release | ||
// end. If in that time the Sound has been played again, | ||
// no action should be taken. | ||
if (!!this.sourceNode && this.sourceNode !== node) | ||
return; | ||
if (this.playing) | ||
this.stop(); | ||
if (!this.paused) | ||
this.trigger('end'); | ||
}; | ||
} | ||
@@ -647,3 +663,3 @@ }, | ||
* Returns the node that produces the sound. For example, an oscillator | ||
* if the Sound object was initialized with a wave option. | ||
* if the Sound object was initialized with a wave option. | ||
*/ | ||
@@ -654,11 +670,30 @@ getSourceNode: { | ||
value: function() { | ||
if (!!this.sourceNode) | ||
this.sourceNode.disconnect(); | ||
if (!!this.sourceNode) { | ||
// Directly disconnecting the previous source node causes a | ||
// 'click' noise, especially noticeable if the sound is played | ||
// while the release is ongoing. To address this, we fadeout the | ||
// old source node before disonnecting it. | ||
var previousSourceNode = this.sourceNode; | ||
previousSourceNode.gainSuccessor.gain.setValueAtTime(previousSourceNode.gainSuccessor.gain.value, Pz.context.currentTime); | ||
previousSourceNode.gainSuccessor.gain.linearRampToValueAtTime(0.0001, Pz.context.currentTime + 0.2); | ||
setTimeout(function() { | ||
previousSourceNode.disconnect(); | ||
previousSourceNode.gainSuccessor.disconnect(); | ||
}, 200); | ||
} | ||
var sourceNode = this.getRawSourceNode(); | ||
sourceNode.connect(this.fadeNode); | ||
sourceNode.onended = this.onEnded.bind(this); | ||
// A gain node will be placed after the source node to avoid | ||
// clicking noises (by fading out the sound) | ||
sourceNode.gainSuccessor = Pz.context.createGain(); | ||
sourceNode.connect(sourceNode.gainSuccessor); | ||
sourceNode.gainSuccessor.connect(this.fadeNode); | ||
this.fadeNode.connect(this.getInputNode()); | ||
if (Pz.Util.isAudioBufferSourceNode(sourceNode)) | ||
sourceNode.onended = this.onEnded(sourceNode).bind(this); | ||
return sourceNode; | ||
@@ -717,7 +752,14 @@ } | ||
value: function() { | ||
if (!this.attack) | ||
var currentValue = this.fadeNode.gain.value; | ||
this.fadeNode.gain.cancelScheduledValues(Pz.context.currentTime); | ||
this.fadeNode.gain.setValueAtTime(currentValue, Pz.context.currentTime); | ||
if (!this.attack) { | ||
this.fadeNode.gain.setValueAtTime(1.0, Pizzicato.context.currentTime); | ||
return; | ||
} | ||
this.fadeNode.gain.setValueAtTime(0.00001, Pizzicato.context.currentTime); | ||
this.fadeNode.gain.linearRampToValueAtTime(1, Pizzicato.context.currentTime + this.attack); | ||
var remainingAttackTime = (1 - this.fadeNode.gain.value) * this.attack; | ||
this.fadeNode.gain.setValueAtTime(this.fadeNode.gain.value, Pizzicato.context.currentTime); | ||
this.fadeNode.gain.linearRampToValueAtTime(1, Pizzicato.context.currentTime + remainingAttackTime); | ||
} | ||
@@ -741,10 +783,18 @@ }, | ||
if (!this.release) | ||
var currentValue = this.fadeNode.gain.value; | ||
this.fadeNode.gain.cancelScheduledValues(Pz.context.currentTime); | ||
this.fadeNode.gain.setValueAtTime(currentValue, Pz.context.currentTime); | ||
if (!this.release) { | ||
stopSound(); | ||
return; | ||
} | ||
var remainingReleaseTime = this.fadeNode.gain.value * this.release; | ||
this.fadeNode.gain.setValueAtTime(this.fadeNode.gain.value, Pizzicato.context.currentTime); | ||
this.fadeNode.gain.linearRampToValueAtTime(0.00001, Pizzicato.context.currentTime + this.release); | ||
this.fadeNode.gain.linearRampToValueAtTime(0.00001, Pizzicato.context.currentTime + remainingReleaseTime); | ||
window.setTimeout(function() { | ||
stopSound(); | ||
}, this.release * 1000); | ||
}, remainingReleaseTime * 1000); | ||
} | ||
@@ -1369,3 +1419,3 @@ } | ||
for (var key in defaults) { | ||
@@ -1380,3 +1430,3 @@ this[key] = options[key]; | ||
} | ||
request.open('GET', options.impulse, true); | ||
@@ -1391,3 +1441,3 @@ request.responseType = 'arraybuffer'; | ||
if (self.callback && Pz.Util.isFunction(self.callback)) | ||
if (self.callback && Pz.Util.isFunction(self.callback)) | ||
self.callback(); | ||
@@ -1405,4 +1455,5 @@ | ||
request.onreadystatechange = function(event) { | ||
if (request.readyState === 4 && request.status !== 200) | ||
if (request.readyState === 4 && request.status !== 200) { | ||
console.error('Error while fetching ' + options.impulse + '. ' + request.statusText); | ||
} | ||
}; | ||
@@ -1417,3 +1468,3 @@ | ||
enumerable: true, | ||
get: function() { | ||
@@ -1420,0 +1471,0 @@ return this.options.mix; |
@@ -1,1 +0,1 @@ | ||
!function(e){"use strict";function t(e,t){this.options={},e=e||this.options;var i={frequency:350,peak:1};this.inputNode=this.filterNode=o.context.createBiquadFilter(),this.filterNode.type=t,this.outputNode=n.context.createGain(),this.filterNode.connect(this.outputNode);for(var s in i)this[s]=e[s],this[s]=void 0===this[s]||null===this[s]?i[s]:this[s]}function i(){var e,t,i=o.context.sampleRate*this.time,s=n.context.createBuffer(2,i,o.context.sampleRate),a=s.getChannelData(0),r=s.getChannelData(1);for(t=0;i>t;t++)e=this.reverse?i-t:t,a[t]=(2*Math.random()-1)*Math.pow(1-e/i,this.decay),r[t]=(2*Math.random()-1)*Math.pow(1-e/i,this.decay);this.reverbNode.buffer=s}var n={},o=n,s="object"==typeof module&&module.exports,a="function"==typeof define&&define.amd;s?module.exports=n:a?define([],n):e.Pizzicato=e.Pz=n;var r=e.AudioContext||e.webkitAudioContext;if(!r)return void console.error("No AudioContext found in this environment. Please ensure your window or global object contains a working AudioContext constructor function.");n.context=new r;var c=n.context.createGain();c.connect(n.context.destination),n.Util={isString:function(e){return"[object String]"===toString.call(e)},isObject:function(e){return"[object Object]"===toString.call(e)},isFunction:function(e){return"[object Function]"===toString.call(e)},isNumber:function(e){return"[object Number]"===toString.call(e)&&e===+e},isArray:function(e){return"[object Array]"===toString.call(e)},isInRange:function(e,t,i){return o.Util.isNumber(e)&&o.Util.isNumber(t)&&o.Util.isNumber(i)?e>=t&&i>=e:!1},isBool:function(e){return"boolean"==typeof e},isOscillator:function(e){return e&&"[object OscillatorNode]"===e.toString()},isEffect:function(e){for(var t in n.Effects)if(e instanceof n.Effects[t])return!0;return!1},normalize:function(e,t,i){return o.Util.isNumber(e)&&o.Util.isNumber(t)&&o.Util.isNumber(i)?(i-t)*e/1+t:void 0},getDryLevel:function(e){return!o.Util.isNumber(e)||e>1||0>e?0:.5>=e?1:1-2*(e-.5)},getWetLevel:function(e){return!o.Util.isNumber(e)||e>1||0>e?0:e>=.5?1:1-2*(.5-e)}};var h=n.context.createGain(),u=Object.getPrototypeOf(Object.getPrototypeOf(h)),d=u.connect;u.connect=function(e){var t=o.Util.isEffect(e)?e.inputNode:e;return d.call(this,t),e},Object.defineProperty(n,"volume",{enumerable:!0,get:function(){return c.gain.value},set:function(e){o.Util.isInRange(e,0,1)&&c&&(c.gain.value=e)}}),Object.defineProperty(n,"masterGainNode",{enumerable:!1,get:function(){return c},set:function(e){console.error("Can't set the master gain node")}}),n.Events={on:function(e,t,i){if(e&&t){this._events=this._events||{};var n=this._events[e]||(this._events[e]=[]);n.push({callback:t,context:i||this,handler:this})}},trigger:function(e){if(e){var t,i,n,o;if(this._events=this._events||{},t=this._events[e]||(this._events[e]=[])){for(i=Math.max(0,arguments.length-1),n=[],o=0;i>o;o++)n[o]=arguments[o+1];for(o=0;o<t.length;o++)t[o].callback.apply(t[o].context,n)}}},off:function(e){e?this._events[e]=void 0:this._events={}}},n.Sound=function(e,t){function i(e){var t=["wave","file","input","script","sound"];if(e&&!d.isFunction(e)&&!d.isString(e)&&!d.isObject(e))return"Description type not supported. Initialize a sound using an object, a function or a string.";if(d.isObject(e)){if(!d.isString(e.source)||-1===t.indexOf(e.source))return"Specified source not supported. Sources can be wave, file, input or script";if(!("file"!==e.source||e.options&&e.options.path))return"A path is needed for sounds with a file source";if(!("script"!==e.source||e.options&&e.options.audioFunction))return"An audio function is needed for sounds with a script source"}}function s(e,t){e=e||{},this.getRawSourceNode=function(){var t=this.sourceNode?this.sourceNode.frequency.value:e.frequency,i=n.context.createOscillator();return i.type=e.type||"sine",i.frequency.value=t||440,i},this.sourceNode=this.getRawSourceNode(),d.isFunction(t)&&t()}function a(e,t){e=d.isArray(e)?e:[e];var i=new XMLHttpRequest;i.open("GET",e[0],!0),i.responseType="arraybuffer",i.onload=function(i){n.context.decodeAudioData(i.target.response,function(e){u.getRawSourceNode=function(){var t=n.context.createBufferSource();return t.loop=this.loop,t.buffer=e,t},d.isFunction(t)&&t()}.bind(u),function(i){return console.error("Error decoding audio file "+e[0]),e.length>1?(e.shift(),void a(e,t)):(i=i||new Error("Error decoding audio file "+e[0]),void(d.isFunction(t)&&t(i)))}.bind(u))},i.onreadystatechange=function(t){4===i.readyState&&200!==i.status&&console.error("Error while fetching "+e[0]+". "+i.statusText)},i.send()}function r(e,t){navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia,navigator.getUserMedia&&navigator.getUserMedia({audio:!0},function(e){u.getRawSourceNode=function(){return n.context.createMediaStreamSource(e)},d.isFunction(t)&&t()}.bind(u),function(e){d.isFunction(t)&&t(e)})}function c(e,t){var i=d.isFunction(e)?e:e.audioFunction,o=d.isObject(e)&&e.bufferSize?e.bufferSize:null;if(!o)try{n.context.createScriptProcessor()}catch(s){o=2048}this.getRawSourceNode=function(){var e=n.context.createScriptProcessor(o,1,1);return e.onaudioprocess=i,e}}function h(e,t){this.getRawSourceNode=e.sound.getRawSourceNode,e.sound.sourceNode&&o.Util.isOscillator(e.sound.sourceNode)&&(this.sourceNode=this.getRawSourceNode(),this.frequency=e.sound.frequency)}var u=this,d=n.Util,l=i(e),f=d.isObject(e)&&d.isObject(e.options),p=.04,v=.04;if(l)throw console.error(l),new Error("Error initializing Pizzicato Sound: "+l);this.masterVolume=n.context.createGain(),this.fadeNode=n.context.createGain(),f&&e.options.detached||this.masterVolume.connect(n.masterGainNode),this.lastTimePlayed=0,this.effects=[],this.playing=this.paused=!1,this.loop=f&&e.options.loop,this.attack=f&&d.isNumber(e.options.attack)?e.options.attack:p,this.volume=f&&d.isNumber(e.options.volume)?e.options.volume:1,f&&d.isNumber(e.options.release)?this.release=e.options.release:f&&d.isNumber(e.options.sustain)?(console.warn("'sustain' is deprecated. Use 'release' instead."),this.release=e.options.sustain):this.release=v,e?d.isString(e)?a.bind(this)(e,t):d.isFunction(e)?c.bind(this)(e,t):"file"===e.source?a.bind(this)(e.options.path,t):"wave"===e.source?s.bind(this)(e.options,t):"input"===e.source?r.bind(this)(e,t):"script"===e.source?c.bind(this)(e.options,t):"sound"===e.source&&h.bind(this)(e.options,t):s.bind(this)({},t)},n.Sound.prototype=Object.create(n.Events,{play:{enumerable:!0,value:function(e,t){this.playing||(o.Util.isNumber(t)||(t=this.offsetTime||0),o.Util.isNumber(e)||(e=0),this.playing=!0,this.paused=!1,this.sourceNode=this.getSourceNode(),this.applyAttack(),o.Util.isFunction(this.sourceNode.start)&&(this.lastTimePlayed=n.context.currentTime-t,this.sourceNode.start(o.context.currentTime+e,t)),this.trigger("play"))}},stop:{enumerable:!0,value:function(){(this.paused||this.playing)&&(this.paused=this.playing=!1,this.stopWithRelease(),this.offsetTime=0,this.trigger("stop"))}},pause:{enumerable:!0,value:function(){if(!this.paused&&this.playing){this.paused=!0,this.playing=!1,this.stopWithRelease();var e=o.context.currentTime-this.lastTimePlayed;this.sourceNode.buffer?this.offsetTime=e%(this.sourceNode.buffer.length/o.context.sampleRate):this.offsetTime=e,this.trigger("pause")}}},clone:{enumerable:!0,value:function(){for(var e=new n.Sound({source:"sound",options:{loop:this.loop,attack:this.attack,release:this.release,volume:this.volume,sound:this}}),t=0;t<this.effects.length;t++)e.addEffect(this.effects[t]);return e}},onEnded:{enumerable:!0,value:function(){this.playing&&this.stop(),this.paused||this.trigger("end")}},addEffect:{enumerable:!0,value:function(e){return e&&o.Util.isEffect(e)?(this.effects.push(e),this.connectEffects(),void(this.sourceNode&&(this.fadeNode.disconnect(),this.fadeNode.connect(this.getInputNode())))):void console.warn("Invalid effect.")}},removeEffect:{enumerable:!0,value:function(e){var t=this.effects.indexOf(e);if(-1===t)return void console.warn("Cannot remove effect that is not applied to this sound.");var i=this.playing;i&&this.pause(),this.fadeNode.disconnect();for(var n=0;n<this.effects.length;n++)this.effects[n].outputNode.disconnect();this.effects.splice(t,1),this.connectEffects(),i&&this.play()}},connect:{enumerable:!0,value:function(e){this.masterVolume.connect(e)}},disconnect:{enumerable:!0,value:function(e){this.masterVolume.disconnect(e)}},connectEffects:{enumerable:!0,value:function(){for(var e=0;e<this.effects.length;e++){var t=e===this.effects.length-1,i=t?this.masterVolume:this.effects[e+1].inputNode;this.effects[e].outputNode.disconnect(),this.effects[e].outputNode.connect(i)}}},volume:{enumerable:!0,get:function(){return this.masterVolume?this.masterVolume.gain.value:void 0},set:function(e){o.Util.isInRange(e,0,1)&&this.masterVolume&&(this.masterVolume.gain.value=e)}},frequency:{enumerable:!0,get:function(){return this.sourceNode&&o.Util.isOscillator(this.sourceNode)?this.sourceNode.frequency.value:null},set:function(e){this.sourceNode&&o.Util.isOscillator(this.sourceNode)&&(this.sourceNode.frequency.value=e)}},sustain:{enumerable:!0,get:function(){return console.warn("'sustain' is deprecated. Use 'release' instead."),this.release},set:function(e){console.warn("'sustain' is deprecated. Use 'release' instead."),o.Util.isInRange(e,0,10)&&(this.release=e)}},getSourceNode:{enumerable:!0,value:function(){this.sourceNode&&this.sourceNode.disconnect();var e=this.getRawSourceNode();return e.connect(this.fadeNode),e.onended=this.onEnded.bind(this),this.fadeNode.connect(this.getInputNode()),e}},getInputNode:{enumerable:!0,value:function(){return this.effects.length>0?this.effects[0].inputNode:this.masterVolume}},getAnalyser:{enumerable:!0,value:function(){return console.warn("This method is deprecated. You should manually create an AnalyserNode and use connect() on the Pizzicato Sound."),this.analyser?this.analyser:(this.analyser=n.context.createAnalyser(),this.masterVolume.disconnect(),this.masterVolume.connect(this.analyser),this.analyser.connect(n.masterGainNode),this.analyser)}},applyAttack:{enumerable:!1,value:function(){this.attack&&(this.fadeNode.gain.setValueAtTime(1e-5,n.context.currentTime),this.fadeNode.gain.linearRampToValueAtTime(1,n.context.currentTime+this.attack))}},stopWithRelease:{enumerable:!1,value:function(e){var t=this.sourceNode,i=function(){return o.Util.isFunction(t.stop)?t.stop(0):t.disconnect()};this.release||i(),this.fadeNode.gain.setValueAtTime(this.fadeNode.gain.value,n.context.currentTime),this.fadeNode.gain.linearRampToValueAtTime(1e-5,n.context.currentTime+this.release),window.setTimeout(function(){i()},1e3*this.release)}}}),n.Effects={};var l=Object.create(null,{connect:{enumerable:!0,value:function(e){this.outputNode.connect(e)}},disconnect:{enumerable:!0,value:function(e){this.outputNode.disconnect(e)}}});n.Effects.Delay=function(e){this.options={},e=e||this.options;var t={feedback:.5,time:.3,mix:.5};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.feedbackGainNode=n.context.createGain(),this.delayNode=n.context.createDelay(),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.delayNode.connect(this.feedbackGainNode),this.feedbackGainNode.connect(this.delayNode),this.inputNode.connect(this.delayNode),this.delayNode.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Delay.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},time:{enumerable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,0,180)&&(this.options.time=e,this.delayNode.delayTime.value=e)}},feedback:{enumerable:!0,get:function(){return this.options.feedback},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.feedback=parseFloat(e,10),this.feedbackGainNode.gain.value=this.feedback)}}}),n.Effects.Compressor=function(e){this.options={},e=e||this.options;var t={threshold:-24,knee:30,attack:.003,release:.25,ratio:12};this.inputNode=this.compressorNode=n.context.createDynamicsCompressor(),this.outputNode=n.context.createGain(),this.compressorNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Compressor.prototype=Object.create(l,{threshold:{enumerable:!0,get:function(){return this.compressorNode.threshold.value},set:function(e){n.Util.isInRange(e,-100,0)&&(this.compressorNode.threshold.value=e)}},knee:{enumerable:!0,get:function(){return this.compressorNode.knee.value},set:function(e){n.Util.isInRange(e,0,40)&&(this.compressorNode.knee.value=e)}},attack:{enumerable:!0,get:function(){return this.compressorNode.attack.value},set:function(e){n.Util.isInRange(e,0,1)&&(this.compressorNode.attack.value=e)}},release:{enumerable:!0,get:function(){return this.compressorNode.release.value},set:function(e){n.Util.isInRange(e,0,1)&&(this.compressorNode.release.value=e)}},ratio:{enumerable:!0,get:function(){return this.compressorNode.ratio.value},set:function(e){n.Util.isInRange(e,1,20)&&(this.compressorNode.ratio.value=e)}},getCurrentGainReduction:function(){return this.compressorNode.reduction}}),n.Effects.LowPassFilter=function(e){t.call(this,e,"lowpass")},n.Effects.HighPassFilter=function(e){t.call(this,e,"highpass")};var f=Object.create(l,{frequency:{enumerable:!0,get:function(){return this.filterNode.frequency.value},set:function(e){n.Util.isInRange(e,10,22050)&&(this.filterNode.frequency.value=e)}},peak:{enumerable:!0,get:function(){return this.filterNode.Q.value},set:function(e){n.Util.isInRange(e,1e-4,1e3)&&(this.filterNode.Q.value=e)}}});n.Effects.LowPassFilter.prototype=f,n.Effects.HighPassFilter.prototype=f,n.Effects.Distortion=function(e){this.options={},e=e||this.options;var t={gain:.5};this.waveShaperNode=n.context.createWaveShaper(),this.inputNode=this.outputNode=this.waveShaperNode;for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Distortion.prototype=Object.create(l,{gain:{enumerable:!0,get:function(){return this.options.gain},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.gain=e,this.adjustGain())}},adjustGain:{writable:!1,configurable:!1,enumerable:!1,value:function(){for(var e,t=o.Util.isNumber(this.options.gain)?parseInt(100*this.options.gain,10):50,i=44100,n=new Float32Array(i),s=Math.PI/180,a=0;i>a;++a)e=2*a/i-1,n[a]=(3+t)*e*20*s/(Math.PI+t*Math.abs(e));this.waveShaperNode.curve=n}}}),n.Effects.Flanger=function(e){this.options={},e=e||this.options;var t={time:.45,speed:.2,depth:.1,feedback:.1,mix:.5};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.inputFeedbackNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.delayNode=n.context.createDelay(),this.oscillatorNode=n.context.createOscillator(),this.gainNode=n.context.createGain(),this.feedbackNode=n.context.createGain(),this.oscillatorNode.type="sine",this.inputNode.connect(this.inputFeedbackNode),this.inputNode.connect(this.dryGainNode),this.inputFeedbackNode.connect(this.delayNode),this.inputFeedbackNode.connect(this.wetGainNode),this.delayNode.connect(this.wetGainNode),this.delayNode.connect(this.feedbackNode),this.feedbackNode.connect(this.inputFeedbackNode),this.oscillatorNode.connect(this.gainNode),this.gainNode.connect(this.delayNode.delayTime),this.dryGainNode.connect(this.outputNode),this.wetGainNode.connect(this.outputNode),this.oscillatorNode.start(0);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Flanger.prototype=Object.create(l,{time:{enumberable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.time=e,this.delayNode.delayTime.value=o.Util.normalize(e,.001,.02))}},speed:{enumberable:!0,get:function(){return this.options.speed},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.speed=e,this.oscillatorNode.frequency.value=o.Util.normalize(e,.5,5))}},depth:{enumberable:!0,get:function(){return this.options.depth},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.depth=e,this.gainNode.gain.value=o.Util.normalize(e,5e-4,.005))}},feedback:{enumberable:!0,get:function(){return this.options.feedback},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.feedback=e,this.feedbackNode.gain.value=o.Util.normalize(e,0,.8))}},mix:{enumberable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}}}),n.Effects.StereoPanner=function(e){this.options={},e=e||this.options;var t={pan:0};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),n.context.createStereoPanner?(this.pannerNode=n.context.createStereoPanner(),this.inputNode.connect(this.pannerNode),this.pannerNode.connect(this.outputNode)):this.inputNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.StereoPanner.prototype=Object.create(l,{pan:{enumerable:!0,get:function(){return this.options.pan},set:function(e){o.Util.isInRange(e,-1,1)&&(this.options.pan=e,this.pannerNode&&(this.pannerNode.pan.value=e))}}}),n.Effects.Convolver=function(e,t){this.options={},e=e||this.options;var i=this,s=new XMLHttpRequest,a={mix:.5};this.callback=t,this.inputNode=n.context.createGain(),this.convolverNode=n.context.createConvolver(),this.outputNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.inputNode.connect(this.convolverNode),this.convolverNode.connect(this.wetGainNode),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.wetGainNode.connect(this.outputNode);for(var r in a)this[r]=e[r],this[r]=void 0===this[r]||null===this[r]?a[r]:this[r];return e.impulse?(s.open("GET",e.impulse,!0),s.responseType="arraybuffer",s.onload=function(e){var t=e.target.response;n.context.decodeAudioData(t,function(e){i.convolverNode.buffer=e,i.callback&&o.Util.isFunction(i.callback)&&i.callback()},function(e){e=e||new Error("Error decoding impulse file"),i.callback&&o.Util.isFunction(i.callback)&&i.callback(e)})},s.onreadystatechange=function(t){4===s.readyState&&200!==s.status&&console.error("Error while fetching "+e.impulse+". "+s.statusText)},void s.send()):void console.error("No impulse file specified.")},n.Effects.Convolver.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}}}),n.Effects.PingPongDelay=function(e){this.options={},e=e||this.options;var t={feedback:.5,time:.3,mix:.5};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.delayNodeLeft=n.context.createDelay(),this.delayNodeRight=n.context.createDelay(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.feedbackGainNode=n.context.createGain(),this.channelMerger=n.context.createChannelMerger(2),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.delayNodeLeft.connect(this.channelMerger,0,0),this.delayNodeRight.connect(this.channelMerger,0,1),this.delayNodeLeft.connect(this.delayNodeRight),this.feedbackGainNode.connect(this.delayNodeLeft),this.delayNodeRight.connect(this.feedbackGainNode),this.inputNode.connect(this.feedbackGainNode),this.channelMerger.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.PingPongDelay.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},time:{enumerable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,0,180)&&(this.options.time=e,this.delayNodeLeft.delayTime.value=e,this.delayNodeRight.delayTime.value=e)}},feedback:{enumerable:!0,get:function(){return this.options.feedback},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.feedback=parseFloat(e,10),this.feedbackGainNode.gain.value=this.feedback)}}}),n.Effects.Reverb=function(e){this.options={},e=e||this.options;var t={mix:.5,time:.01,decay:.01,reverse:!1};this.inputNode=n.context.createGain(),this.reverbNode=n.context.createConvolver(),this.outputNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.inputNode.connect(this.reverbNode),this.reverbNode.connect(this.wetGainNode),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.wetGainNode.connect(this.outputNode);for(var o in t)this[o]=e[o],this[o]=void 0===this[o]||null===this[o]?t[o]:this[o];i.bind(this)()},n.Effects.Reverb.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},time:{enumerable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,1e-4,10)&&(this.options.time=e,i.bind(this)())}},decay:{enumerable:!0,get:function(){return this.options.decay},set:function(e){o.Util.isInRange(e,1e-4,10)&&(this.options.decay=e,i.bind(this)())}},reverse:{enumerable:!0,get:function(){return this.options.reverse},set:function(e){o.Util.isBool(e)&&(this.options.reverse=e,i.bind(this)())}}}),n.Effects.Tremolo=function(e){this.options={},e=e||this.options;var t={speed:4,depth:1,mix:.8};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.tremoloGainNode=n.context.createGain(),this.tremoloGainNode.gain.value=0,this.lfoNode=n.context.createOscillator(),this.shaperNode=n.context.createWaveShaper(),this.shaperNode.curve=new Float32Array([0,1]),this.shaperNode.connect(this.tremoloGainNode.gain),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.lfoNode.connect(this.shaperNode),this.lfoNode.type="sine",this.lfoNode.start(0),this.inputNode.connect(this.tremoloGainNode),this.tremoloGainNode.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Tremolo.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},speed:{enumerable:!0,get:function(){return this.options.speed},set:function(e){o.Util.isInRange(e,0,20)&&(this.options.speed=e,this.lfoNode.frequency.value=e)}},depth:{enumerable:!0,get:function(){return this.options.depth},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.depth=e,this.shaperNode.curve=new Float32Array([1-e,1]))}}}),n.Effects.DubDelay=function(e){this.options={},e=e||this.options;var t={feedback:.6,time:.7,mix:.5,cutoff:700};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.feedbackGainNode=n.context.createGain(),this.delayNode=n.context.createDelay(),this.bqFilterNode=n.context.createBiquadFilter(),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.inputNode.connect(this.wetGainNode),this.inputNode.connect(this.feedbackGainNode),this.feedbackGainNode.connect(this.bqFilterNode),this.bqFilterNode.connect(this.delayNode),this.delayNode.connect(this.feedbackGainNode),this.delayNode.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.DubDelay.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},time:{enumerable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,0,180)&&(this.options.time=e,this.delayNode.delayTime.value=e)}},feedback:{enumerable:!0,get:function(){return this.options.feedback},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.feedback=parseFloat(e,10),this.feedbackGainNode.gain.value=this.feedback)}},cutoff:{enumerable:!0,get:function(){return this.options.cutoff},set:function(e){o.Util.isInRange(e,0,4e3)&&(this.options.cutoff=e,this.bqFilterNode.frequency.value=this.cutoff)}}}),n.Effects.RingModulator=function(e){this.options={},e=e||this.options;var t={speed:30,distortion:1,mix:.5};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.vIn=n.context.createOscillator(),this.vIn.start(0),this.vInGain=n.context.createGain(),this.vInGain.gain.value=.5,this.vInInverter1=n.context.createGain(),this.vInInverter1.gain.value=-1,this.vInInverter2=n.context.createGain(),this.vInInverter2.gain.value=-1,this.vInDiode1=new p(n.context),this.vInDiode2=new p(n.context),this.vInInverter3=n.context.createGain(),this.vInInverter3.gain.value=-1,this.vcInverter1=n.context.createGain(),this.vcInverter1.gain.value=-1,this.vcDiode3=new p(n.context),this.vcDiode4=new p(n.context),this.outGain=n.context.createGain(),this.outGain.gain.value=3,this.compressor=n.context.createDynamicsCompressor(),this.compressor.threshold.value=-24,this.compressor.ratio.value=16,this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.inputNode.connect(this.vcInverter1),this.inputNode.connect(this.vcDiode4.node),this.vcInverter1.connect(this.vcDiode3.node),this.vIn.connect(this.vInGain),this.vInGain.connect(this.vInInverter1),this.vInGain.connect(this.vcInverter1),this.vInGain.connect(this.vcDiode4.node),this.vInInverter1.connect(this.vInInverter2),this.vInInverter1.connect(this.vInDiode2.node),this.vInInverter2.connect(this.vInDiode1.node),this.vInDiode1.connect(this.vInInverter3),this.vInDiode2.connect(this.vInInverter3),this.vInInverter3.connect(this.compressor),this.vcDiode3.connect(this.compressor),this.vcDiode4.connect(this.compressor),this.compressor.connect(this.outGain),this.outGain.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]};var p=function(e){this.context=e,this.node=this.context.createWaveShaper(),this.vb=.2,this.vl=.4,this.h=1,this.setCurve()};return p.prototype.setDistortion=function(e){return this.h=e,this.setCurve()},p.prototype.setCurve=function(){var e,t,i,n,o,s,a,r;for(t=1024,o=new Float32Array(t),e=s=0,a=o.length;a>=0?a>s:s>a;e=a>=0?++s:--s)i=(e-t/2)/(t/2),i=Math.abs(i),n=i<=this.vb?0:this.vb<i&&i<=this.vl?this.h*(Math.pow(i-this.vb,2)/(2*this.vl-2*this.vb)):this.h*i-this.h*this.vl+this.h*(Math.pow(this.vl-this.vb,2)/(2*this.vl-2*this.vb)),o[e]=n;return r=this.node.curve=o},p.prototype.connect=function(e){return this.node.connect(e)},n.Effects.RingModulator.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},speed:{enumerable:!0,get:function(){return this.options.speed},set:function(e){o.Util.isInRange(e,0,2e3)&&(this.options.speed=e,this.vIn.frequency.value=e)}},distortion:{enumerable:!0,get:function(){return this.options.distortion},set:function(e){if(o.Util.isInRange(e,.2,50)){this.options.distortion=parseFloat(e,10);for(var t=[this.vInDiode1,this.vInDiode2,this.vcDiode3,this.vcDiode4],i=0,n=t.length;n>i;i++)t[i].setDistortion(e)}}}}),n}("undefined"!=typeof window?window:global); | ||
!function(e){"use strict";function t(e,t){this.options={},e=e||this.options;var i={frequency:350,peak:1};this.inputNode=this.filterNode=o.context.createBiquadFilter(),this.filterNode.type=t,this.outputNode=n.context.createGain(),this.filterNode.connect(this.outputNode);for(var s in i)this[s]=e[s],this[s]=void 0===this[s]||null===this[s]?i[s]:this[s]}function i(){var e,t,i=o.context.sampleRate*this.time,s=n.context.createBuffer(2,i,o.context.sampleRate),a=s.getChannelData(0),r=s.getChannelData(1);for(t=0;i>t;t++)e=this.reverse?i-t:t,a[t]=(2*Math.random()-1)*Math.pow(1-e/i,this.decay),r[t]=(2*Math.random()-1)*Math.pow(1-e/i,this.decay);this.reverbNode.buffer=s}var n={},o=n,s="object"==typeof module&&module.exports,a="function"==typeof define&&define.amd;s?module.exports=n:a?define([],n):e.Pizzicato=e.Pz=n;var r=e.AudioContext||e.webkitAudioContext;if(!r)return void console.error("No AudioContext found in this environment. Please ensure your window or global object contains a working AudioContext constructor function.");n.context=new r;var c=n.context.createGain();c.connect(n.context.destination),n.Util={isString:function(e){return"[object String]"===toString.call(e)},isObject:function(e){return"[object Object]"===toString.call(e)},isFunction:function(e){return"[object Function]"===toString.call(e)},isNumber:function(e){return"[object Number]"===toString.call(e)&&e===+e},isArray:function(e){return"[object Array]"===toString.call(e)},isInRange:function(e,t,i){return o.Util.isNumber(e)&&o.Util.isNumber(t)&&o.Util.isNumber(i)?e>=t&&i>=e:!1},isBool:function(e){return"boolean"==typeof e},isOscillator:function(e){return e&&"[object OscillatorNode]"===e.toString()},isAudioBufferSourceNode:function(e){return e&&"[object AudioBufferSourceNode]"===e.toString()},isEffect:function(e){for(var t in n.Effects)if(e instanceof n.Effects[t])return!0;return!1},normalize:function(e,t,i){return o.Util.isNumber(e)&&o.Util.isNumber(t)&&o.Util.isNumber(i)?(i-t)*e/1+t:void 0},getDryLevel:function(e){return!o.Util.isNumber(e)||e>1||0>e?0:.5>=e?1:1-2*(e-.5)},getWetLevel:function(e){return!o.Util.isNumber(e)||e>1||0>e?0:e>=.5?1:1-2*(.5-e)}};var u=n.context.createGain(),h=Object.getPrototypeOf(Object.getPrototypeOf(u)),d=h.connect;h.connect=function(e){var t=o.Util.isEffect(e)?e.inputNode:e;return d.call(this,t),e},Object.defineProperty(n,"volume",{enumerable:!0,get:function(){return c.gain.value},set:function(e){o.Util.isInRange(e,0,1)&&c&&(c.gain.value=e)}}),Object.defineProperty(n,"masterGainNode",{enumerable:!1,get:function(){return c},set:function(e){console.error("Can't set the master gain node")}}),n.Events={on:function(e,t,i){if(e&&t){this._events=this._events||{};var n=this._events[e]||(this._events[e]=[]);n.push({callback:t,context:i||this,handler:this})}},trigger:function(e){if(e){var t,i,n,o;if(this._events=this._events||{},t=this._events[e]||(this._events[e]=[])){for(i=Math.max(0,arguments.length-1),n=[],o=0;i>o;o++)n[o]=arguments[o+1];for(o=0;o<t.length;o++)t[o].callback.apply(t[o].context,n)}}},off:function(e){e?this._events[e]=void 0:this._events={}}},n.Sound=function(e,t){function i(e){var t=["wave","file","input","script","sound"];if(e&&!d.isFunction(e)&&!d.isString(e)&&!d.isObject(e))return"Description type not supported. Initialize a sound using an object, a function or a string.";if(d.isObject(e)){if(!d.isString(e.source)||-1===t.indexOf(e.source))return"Specified source not supported. Sources can be wave, file, input or script";if(!("file"!==e.source||e.options&&e.options.path))return"A path is needed for sounds with a file source";if(!("script"!==e.source||e.options&&e.options.audioFunction))return"An audio function is needed for sounds with a script source"}}function s(e,t){e=e||{},this.getRawSourceNode=function(){var t=this.sourceNode?this.sourceNode.frequency.value:e.frequency,i=n.context.createOscillator();return i.type=e.type||"sine",i.frequency.value=t||440,i},this.sourceNode=this.getRawSourceNode(),this.sourceNode.gainSuccessor=o.context.createGain(),this.sourceNode.connect(this.sourceNode.gainSuccessor),d.isFunction(t)&&t()}function a(e,t){e=d.isArray(e)?e:[e];var i=new XMLHttpRequest;i.open("GET",e[0],!0),i.responseType="arraybuffer",i.onload=function(i){n.context.decodeAudioData(i.target.response,function(e){h.getRawSourceNode=function(){var t=n.context.createBufferSource();return t.loop=this.loop,t.buffer=e,t},d.isFunction(t)&&t()}.bind(h),function(i){return console.error("Error decoding audio file "+e[0]),e.length>1?(e.shift(),void a(e,t)):(i=i||new Error("Error decoding audio file "+e[0]),void(d.isFunction(t)&&t(i)))}.bind(h))},i.onreadystatechange=function(t){4===i.readyState&&200!==i.status&&console.error("Error while fetching "+e[0]+". "+i.statusText)},i.send()}function r(e,t){navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia,navigator.getUserMedia&&navigator.getUserMedia({audio:!0},function(e){h.getRawSourceNode=function(){return n.context.createMediaStreamSource(e)},d.isFunction(t)&&t()}.bind(h),function(e){d.isFunction(t)&&t(e)})}function c(e,t){var i=d.isFunction(e)?e:e.audioFunction,o=d.isObject(e)&&e.bufferSize?e.bufferSize:null;if(!o)try{n.context.createScriptProcessor()}catch(s){o=2048}this.getRawSourceNode=function(){var e=n.context.createScriptProcessor(o,1,1);return e.onaudioprocess=i,e}}function u(e,t){this.getRawSourceNode=e.sound.getRawSourceNode,e.sound.sourceNode&&o.Util.isOscillator(e.sound.sourceNode)&&(this.sourceNode=this.getRawSourceNode(),this.frequency=e.sound.frequency)}var h=this,d=n.Util,l=i(e),f=d.isObject(e)&&d.isObject(e.options),p=.04,v=.04;if(l)throw console.error(l),new Error("Error initializing Pizzicato Sound: "+l);this.masterVolume=n.context.createGain(),this.fadeNode=n.context.createGain(),this.fadeNode.gain.value=0,f&&e.options.detached||this.masterVolume.connect(n.masterGainNode),this.lastTimePlayed=0,this.effects=[],this.playing=this.paused=!1,this.loop=f&&e.options.loop,this.attack=f&&d.isNumber(e.options.attack)?e.options.attack:p,this.volume=f&&d.isNumber(e.options.volume)?e.options.volume:1,f&&d.isNumber(e.options.release)?this.release=e.options.release:f&&d.isNumber(e.options.sustain)?(console.warn("'sustain' is deprecated. Use 'release' instead."),this.release=e.options.sustain):this.release=v,e?d.isString(e)?a.bind(this)(e,t):d.isFunction(e)?c.bind(this)(e,t):"file"===e.source?a.bind(this)(e.options.path,t):"wave"===e.source?s.bind(this)(e.options,t):"input"===e.source?r.bind(this)(e,t):"script"===e.source?c.bind(this)(e.options,t):"sound"===e.source&&u.bind(this)(e.options,t):s.bind(this)({},t)},n.Sound.prototype=Object.create(n.Events,{play:{enumerable:!0,value:function(e,t){this.playing||(o.Util.isNumber(t)||(t=this.offsetTime||0),o.Util.isNumber(e)||(e=0),this.playing=!0,this.paused=!1,this.sourceNode=this.getSourceNode(),this.applyAttack(),o.Util.isFunction(this.sourceNode.start)&&(this.lastTimePlayed=n.context.currentTime-t,this.sourceNode.start(o.context.currentTime+e,t)),this.trigger("play"))}},stop:{enumerable:!0,value:function(){(this.paused||this.playing)&&(this.paused=this.playing=!1,this.stopWithRelease(),this.offsetTime=0,this.trigger("stop"))}},pause:{enumerable:!0,value:function(){if(!this.paused&&this.playing){this.paused=!0,this.playing=!1,this.stopWithRelease();var e=o.context.currentTime-this.lastTimePlayed;this.sourceNode.buffer?this.offsetTime=e%(this.sourceNode.buffer.length/o.context.sampleRate):this.offsetTime=e,this.trigger("pause")}}},clone:{enumerable:!0,value:function(){for(var e=new n.Sound({source:"sound",options:{loop:this.loop,attack:this.attack,release:this.release,volume:this.volume,sound:this}}),t=0;t<this.effects.length;t++)e.addEffect(this.effects[t]);return e}},onEnded:{enumerable:!0,value:function(e){return function(){this.sourceNode&&this.sourceNode!==e||(this.playing&&this.stop(),this.paused||this.trigger("end"))}}},addEffect:{enumerable:!0,value:function(e){return e&&o.Util.isEffect(e)?(this.effects.push(e),this.connectEffects(),void(this.sourceNode&&(this.fadeNode.disconnect(),this.fadeNode.connect(this.getInputNode())))):void console.warn("Invalid effect.")}},removeEffect:{enumerable:!0,value:function(e){var t=this.effects.indexOf(e);if(-1===t)return void console.warn("Cannot remove effect that is not applied to this sound.");var i=this.playing;i&&this.pause(),this.fadeNode.disconnect();for(var n=0;n<this.effects.length;n++)this.effects[n].outputNode.disconnect();this.effects.splice(t,1),this.connectEffects(),i&&this.play()}},connect:{enumerable:!0,value:function(e){this.masterVolume.connect(e)}},disconnect:{enumerable:!0,value:function(e){this.masterVolume.disconnect(e)}},connectEffects:{enumerable:!0,value:function(){for(var e=0;e<this.effects.length;e++){var t=e===this.effects.length-1,i=t?this.masterVolume:this.effects[e+1].inputNode;this.effects[e].outputNode.disconnect(),this.effects[e].outputNode.connect(i)}}},volume:{enumerable:!0,get:function(){return this.masterVolume?this.masterVolume.gain.value:void 0},set:function(e){o.Util.isInRange(e,0,1)&&this.masterVolume&&(this.masterVolume.gain.value=e)}},frequency:{enumerable:!0,get:function(){return this.sourceNode&&o.Util.isOscillator(this.sourceNode)?this.sourceNode.frequency.value:null},set:function(e){this.sourceNode&&o.Util.isOscillator(this.sourceNode)&&(this.sourceNode.frequency.value=e)}},sustain:{enumerable:!0,get:function(){return console.warn("'sustain' is deprecated. Use 'release' instead."),this.release},set:function(e){console.warn("'sustain' is deprecated. Use 'release' instead."),o.Util.isInRange(e,0,10)&&(this.release=e)}},getSourceNode:{enumerable:!0,value:function(){if(this.sourceNode){var e=this.sourceNode;e.gainSuccessor.gain.setValueAtTime(e.gainSuccessor.gain.value,o.context.currentTime),e.gainSuccessor.gain.linearRampToValueAtTime(1e-4,o.context.currentTime+.2),setTimeout(function(){e.disconnect(),e.gainSuccessor.disconnect()},200)}var t=this.getRawSourceNode();return t.gainSuccessor=o.context.createGain(),t.connect(t.gainSuccessor),t.gainSuccessor.connect(this.fadeNode),this.fadeNode.connect(this.getInputNode()),o.Util.isAudioBufferSourceNode(t)&&(t.onended=this.onEnded(t).bind(this)),t}},getInputNode:{enumerable:!0,value:function(){return this.effects.length>0?this.effects[0].inputNode:this.masterVolume}},getAnalyser:{enumerable:!0,value:function(){return console.warn("This method is deprecated. You should manually create an AnalyserNode and use connect() on the Pizzicato Sound."),this.analyser?this.analyser:(this.analyser=n.context.createAnalyser(),this.masterVolume.disconnect(),this.masterVolume.connect(this.analyser),this.analyser.connect(n.masterGainNode),this.analyser)}},applyAttack:{enumerable:!1,value:function(){var e=this.fadeNode.gain.value;if(this.fadeNode.gain.cancelScheduledValues(o.context.currentTime),this.fadeNode.gain.setValueAtTime(e,o.context.currentTime),!this.attack)return void this.fadeNode.gain.setValueAtTime(1,n.context.currentTime);var t=(1-this.fadeNode.gain.value)*this.attack;this.fadeNode.gain.setValueAtTime(this.fadeNode.gain.value,n.context.currentTime),this.fadeNode.gain.linearRampToValueAtTime(1,n.context.currentTime+t)}},stopWithRelease:{enumerable:!1,value:function(e){var t=this.sourceNode,i=function(){return o.Util.isFunction(t.stop)?t.stop(0):t.disconnect()},s=this.fadeNode.gain.value;if(this.fadeNode.gain.cancelScheduledValues(o.context.currentTime),this.fadeNode.gain.setValueAtTime(s,o.context.currentTime),!this.release)return void i();var a=this.fadeNode.gain.value*this.release;this.fadeNode.gain.setValueAtTime(this.fadeNode.gain.value,n.context.currentTime),this.fadeNode.gain.linearRampToValueAtTime(1e-5,n.context.currentTime+a),window.setTimeout(function(){i()},1e3*a)}}}),n.Effects={};var l=Object.create(null,{connect:{enumerable:!0,value:function(e){this.outputNode.connect(e)}},disconnect:{enumerable:!0,value:function(e){this.outputNode.disconnect(e)}}});n.Effects.Delay=function(e){this.options={},e=e||this.options;var t={feedback:.5,time:.3,mix:.5};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.feedbackGainNode=n.context.createGain(),this.delayNode=n.context.createDelay(),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.delayNode.connect(this.feedbackGainNode),this.feedbackGainNode.connect(this.delayNode),this.inputNode.connect(this.delayNode),this.delayNode.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Delay.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},time:{enumerable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,0,180)&&(this.options.time=e,this.delayNode.delayTime.value=e)}},feedback:{enumerable:!0,get:function(){return this.options.feedback},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.feedback=parseFloat(e,10),this.feedbackGainNode.gain.value=this.feedback)}}}),n.Effects.Compressor=function(e){this.options={},e=e||this.options;var t={threshold:-24,knee:30,attack:.003,release:.25,ratio:12};this.inputNode=this.compressorNode=n.context.createDynamicsCompressor(),this.outputNode=n.context.createGain(),this.compressorNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Compressor.prototype=Object.create(l,{threshold:{enumerable:!0,get:function(){return this.compressorNode.threshold.value},set:function(e){n.Util.isInRange(e,-100,0)&&(this.compressorNode.threshold.value=e)}},knee:{enumerable:!0,get:function(){return this.compressorNode.knee.value},set:function(e){n.Util.isInRange(e,0,40)&&(this.compressorNode.knee.value=e)}},attack:{enumerable:!0,get:function(){return this.compressorNode.attack.value},set:function(e){n.Util.isInRange(e,0,1)&&(this.compressorNode.attack.value=e)}},release:{enumerable:!0,get:function(){return this.compressorNode.release.value},set:function(e){n.Util.isInRange(e,0,1)&&(this.compressorNode.release.value=e)}},ratio:{enumerable:!0,get:function(){return this.compressorNode.ratio.value},set:function(e){n.Util.isInRange(e,1,20)&&(this.compressorNode.ratio.value=e)}},getCurrentGainReduction:function(){return this.compressorNode.reduction}}),n.Effects.LowPassFilter=function(e){t.call(this,e,"lowpass")},n.Effects.HighPassFilter=function(e){t.call(this,e,"highpass")};var f=Object.create(l,{frequency:{enumerable:!0,get:function(){return this.filterNode.frequency.value},set:function(e){n.Util.isInRange(e,10,22050)&&(this.filterNode.frequency.value=e)}},peak:{enumerable:!0,get:function(){return this.filterNode.Q.value},set:function(e){n.Util.isInRange(e,1e-4,1e3)&&(this.filterNode.Q.value=e)}}});n.Effects.LowPassFilter.prototype=f,n.Effects.HighPassFilter.prototype=f,n.Effects.Distortion=function(e){this.options={},e=e||this.options;var t={gain:.5};this.waveShaperNode=n.context.createWaveShaper(),this.inputNode=this.outputNode=this.waveShaperNode;for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Distortion.prototype=Object.create(l,{gain:{enumerable:!0,get:function(){return this.options.gain},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.gain=e,this.adjustGain())}},adjustGain:{writable:!1,configurable:!1,enumerable:!1,value:function(){for(var e,t=o.Util.isNumber(this.options.gain)?parseInt(100*this.options.gain,10):50,i=44100,n=new Float32Array(i),s=Math.PI/180,a=0;i>a;++a)e=2*a/i-1,n[a]=(3+t)*e*20*s/(Math.PI+t*Math.abs(e));this.waveShaperNode.curve=n}}}),n.Effects.Flanger=function(e){this.options={},e=e||this.options;var t={time:.45,speed:.2,depth:.1,feedback:.1,mix:.5};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.inputFeedbackNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.delayNode=n.context.createDelay(),this.oscillatorNode=n.context.createOscillator(),this.gainNode=n.context.createGain(),this.feedbackNode=n.context.createGain(),this.oscillatorNode.type="sine",this.inputNode.connect(this.inputFeedbackNode),this.inputNode.connect(this.dryGainNode),this.inputFeedbackNode.connect(this.delayNode),this.inputFeedbackNode.connect(this.wetGainNode),this.delayNode.connect(this.wetGainNode),this.delayNode.connect(this.feedbackNode),this.feedbackNode.connect(this.inputFeedbackNode),this.oscillatorNode.connect(this.gainNode),this.gainNode.connect(this.delayNode.delayTime),this.dryGainNode.connect(this.outputNode),this.wetGainNode.connect(this.outputNode),this.oscillatorNode.start(0);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Flanger.prototype=Object.create(l,{time:{enumberable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.time=e,this.delayNode.delayTime.value=o.Util.normalize(e,.001,.02))}},speed:{enumberable:!0,get:function(){return this.options.speed},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.speed=e,this.oscillatorNode.frequency.value=o.Util.normalize(e,.5,5))}},depth:{enumberable:!0,get:function(){return this.options.depth},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.depth=e,this.gainNode.gain.value=o.Util.normalize(e,5e-4,.005))}},feedback:{enumberable:!0,get:function(){return this.options.feedback},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.feedback=e,this.feedbackNode.gain.value=o.Util.normalize(e,0,.8))}},mix:{enumberable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}}}),n.Effects.StereoPanner=function(e){this.options={},e=e||this.options;var t={pan:0};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),n.context.createStereoPanner?(this.pannerNode=n.context.createStereoPanner(),this.inputNode.connect(this.pannerNode),this.pannerNode.connect(this.outputNode)):this.inputNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.StereoPanner.prototype=Object.create(l,{pan:{enumerable:!0,get:function(){return this.options.pan},set:function(e){o.Util.isInRange(e,-1,1)&&(this.options.pan=e,this.pannerNode&&(this.pannerNode.pan.value=e))}}}),n.Effects.Convolver=function(e,t){this.options={},e=e||this.options;var i=this,s=new XMLHttpRequest,a={mix:.5};this.callback=t,this.inputNode=n.context.createGain(),this.convolverNode=n.context.createConvolver(),this.outputNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.inputNode.connect(this.convolverNode),this.convolverNode.connect(this.wetGainNode),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.wetGainNode.connect(this.outputNode);for(var r in a)this[r]=e[r],this[r]=void 0===this[r]||null===this[r]?a[r]:this[r];return e.impulse?(s.open("GET",e.impulse,!0),s.responseType="arraybuffer",s.onload=function(e){var t=e.target.response;n.context.decodeAudioData(t,function(e){i.convolverNode.buffer=e,i.callback&&o.Util.isFunction(i.callback)&&i.callback()},function(e){e=e||new Error("Error decoding impulse file"),i.callback&&o.Util.isFunction(i.callback)&&i.callback(e)})},s.onreadystatechange=function(t){4===s.readyState&&200!==s.status&&console.error("Error while fetching "+e.impulse+". "+s.statusText)},void s.send()):void console.error("No impulse file specified.")},n.Effects.Convolver.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}}}),n.Effects.PingPongDelay=function(e){this.options={},e=e||this.options;var t={feedback:.5,time:.3,mix:.5};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.delayNodeLeft=n.context.createDelay(),this.delayNodeRight=n.context.createDelay(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.feedbackGainNode=n.context.createGain(),this.channelMerger=n.context.createChannelMerger(2),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.delayNodeLeft.connect(this.channelMerger,0,0),this.delayNodeRight.connect(this.channelMerger,0,1),this.delayNodeLeft.connect(this.delayNodeRight),this.feedbackGainNode.connect(this.delayNodeLeft),this.delayNodeRight.connect(this.feedbackGainNode),this.inputNode.connect(this.feedbackGainNode),this.channelMerger.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.PingPongDelay.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},time:{enumerable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,0,180)&&(this.options.time=e,this.delayNodeLeft.delayTime.value=e,this.delayNodeRight.delayTime.value=e)}},feedback:{enumerable:!0,get:function(){return this.options.feedback},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.feedback=parseFloat(e,10),this.feedbackGainNode.gain.value=this.feedback)}}}),n.Effects.Reverb=function(e){this.options={},e=e||this.options;var t={mix:.5,time:.01,decay:.01,reverse:!1};this.inputNode=n.context.createGain(),this.reverbNode=n.context.createConvolver(),this.outputNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.inputNode.connect(this.reverbNode),this.reverbNode.connect(this.wetGainNode),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.wetGainNode.connect(this.outputNode);for(var o in t)this[o]=e[o],this[o]=void 0===this[o]||null===this[o]?t[o]:this[o];i.bind(this)()},n.Effects.Reverb.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},time:{enumerable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,1e-4,10)&&(this.options.time=e,i.bind(this)())}},decay:{enumerable:!0,get:function(){return this.options.decay},set:function(e){o.Util.isInRange(e,1e-4,10)&&(this.options.decay=e,i.bind(this)())}},reverse:{enumerable:!0,get:function(){return this.options.reverse},set:function(e){o.Util.isBool(e)&&(this.options.reverse=e,i.bind(this)())}}}),n.Effects.Tremolo=function(e){this.options={},e=e||this.options;var t={speed:4,depth:1,mix:.8};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.tremoloGainNode=n.context.createGain(),this.tremoloGainNode.gain.value=0,this.lfoNode=n.context.createOscillator(),this.shaperNode=n.context.createWaveShaper(),this.shaperNode.curve=new Float32Array([0,1]),this.shaperNode.connect(this.tremoloGainNode.gain),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.lfoNode.connect(this.shaperNode),this.lfoNode.type="sine",this.lfoNode.start(0),this.inputNode.connect(this.tremoloGainNode),this.tremoloGainNode.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.Tremolo.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},speed:{enumerable:!0,get:function(){return this.options.speed},set:function(e){o.Util.isInRange(e,0,20)&&(this.options.speed=e,this.lfoNode.frequency.value=e)}},depth:{enumerable:!0,get:function(){return this.options.depth},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.depth=e,this.shaperNode.curve=new Float32Array([1-e,1]))}}}),n.Effects.DubDelay=function(e){this.options={},e=e||this.options;var t={feedback:.6,time:.7,mix:.5,cutoff:700};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.feedbackGainNode=n.context.createGain(),this.delayNode=n.context.createDelay(),this.bqFilterNode=n.context.createBiquadFilter(),this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.inputNode.connect(this.wetGainNode),this.inputNode.connect(this.feedbackGainNode),this.feedbackGainNode.connect(this.bqFilterNode),this.bqFilterNode.connect(this.delayNode),this.delayNode.connect(this.feedbackGainNode),this.delayNode.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]},n.Effects.DubDelay.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},time:{enumerable:!0,get:function(){return this.options.time},set:function(e){o.Util.isInRange(e,0,180)&&(this.options.time=e,this.delayNode.delayTime.value=e)}},feedback:{enumerable:!0,get:function(){return this.options.feedback},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.feedback=parseFloat(e,10),this.feedbackGainNode.gain.value=this.feedback)}},cutoff:{enumerable:!0,get:function(){return this.options.cutoff},set:function(e){o.Util.isInRange(e,0,4e3)&&(this.options.cutoff=e,this.bqFilterNode.frequency.value=this.cutoff)}}}),n.Effects.RingModulator=function(e){this.options={},e=e||this.options;var t={speed:30,distortion:1,mix:.5};this.inputNode=n.context.createGain(),this.outputNode=n.context.createGain(),this.dryGainNode=n.context.createGain(),this.wetGainNode=n.context.createGain(),this.vIn=n.context.createOscillator(),this.vIn.start(0),this.vInGain=n.context.createGain(),this.vInGain.gain.value=.5,this.vInInverter1=n.context.createGain(),this.vInInverter1.gain.value=-1,this.vInInverter2=n.context.createGain(),this.vInInverter2.gain.value=-1,this.vInDiode1=new p(n.context),this.vInDiode2=new p(n.context),this.vInInverter3=n.context.createGain(),this.vInInverter3.gain.value=-1,this.vcInverter1=n.context.createGain(),this.vcInverter1.gain.value=-1,this.vcDiode3=new p(n.context),this.vcDiode4=new p(n.context),this.outGain=n.context.createGain(),this.outGain.gain.value=3,this.compressor=n.context.createDynamicsCompressor(),this.compressor.threshold.value=-24,this.compressor.ratio.value=16,this.inputNode.connect(this.dryGainNode),this.dryGainNode.connect(this.outputNode),this.inputNode.connect(this.vcInverter1),this.inputNode.connect(this.vcDiode4.node),this.vcInverter1.connect(this.vcDiode3.node),this.vIn.connect(this.vInGain),this.vInGain.connect(this.vInInverter1),this.vInGain.connect(this.vcInverter1),this.vInGain.connect(this.vcDiode4.node),this.vInInverter1.connect(this.vInInverter2),this.vInInverter1.connect(this.vInDiode2.node),this.vInInverter2.connect(this.vInDiode1.node),this.vInDiode1.connect(this.vInInverter3),this.vInDiode2.connect(this.vInInverter3),this.vInInverter3.connect(this.compressor),this.vcDiode3.connect(this.compressor),this.vcDiode4.connect(this.compressor),this.compressor.connect(this.outGain),this.outGain.connect(this.wetGainNode),this.wetGainNode.connect(this.outputNode);for(var i in t)this[i]=e[i],this[i]=void 0===this[i]||null===this[i]?t[i]:this[i]};var p=function(e){this.context=e,this.node=this.context.createWaveShaper(),this.vb=.2,this.vl=.4,this.h=1,this.setCurve()};return p.prototype.setDistortion=function(e){return this.h=e,this.setCurve()},p.prototype.setCurve=function(){var e,t,i,n,o,s,a,r;for(t=1024,o=new Float32Array(t),e=s=0,a=o.length;a>=0?a>s:s>a;e=a>=0?++s:--s)i=(e-t/2)/(t/2),i=Math.abs(i),n=i<=this.vb?0:this.vb<i&&i<=this.vl?this.h*(Math.pow(i-this.vb,2)/(2*this.vl-2*this.vb)):this.h*i-this.h*this.vl+this.h*(Math.pow(this.vl-this.vb,2)/(2*this.vl-2*this.vb)),o[e]=n;return r=this.node.curve=o},p.prototype.connect=function(e){return this.node.connect(e)},n.Effects.RingModulator.prototype=Object.create(l,{mix:{enumerable:!0,get:function(){return this.options.mix},set:function(e){o.Util.isInRange(e,0,1)&&(this.options.mix=e,this.dryGainNode.gain.value=n.Util.getDryLevel(this.mix),this.wetGainNode.gain.value=n.Util.getWetLevel(this.mix))}},speed:{enumerable:!0,get:function(){return this.options.speed},set:function(e){o.Util.isInRange(e,0,2e3)&&(this.options.speed=e,this.vIn.frequency.value=e)}},distortion:{enumerable:!0,get:function(){return this.options.distortion},set:function(e){if(o.Util.isInRange(e,.2,50)){this.options.distortion=parseFloat(e,10);for(var t=[this.vInDiode1,this.vInDiode2,this.vcDiode3,this.vcDiode4],i=0,n=t.length;n>i;i++)t[i].setDistortion(e)}}}}),n}("undefined"!=typeof window?window:global); |
{ | ||
"name": "pizzicato", | ||
"description": "A web-audio library to simplify using and manipulating sounds.", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"license": "MIT", | ||
@@ -6,0 +6,0 @@ "homepage": "https://alemangui.github.io/pizzicato/", |
<img align="center" src="https://alemangui.github.io/pizzicato/img/horizontal-logo.svg" alt="Pizzicato.js"> | ||
[![Build Status](https://travis-ci.org/alemangui/pizzicato.svg?branch=master)](https://travis-ci.org/alemangui/pizzicato) [![npm](https://img.shields.io/npm/v/pizzicato.svg?maxAge=2592000)](https://www.npmjs.com/package/pizzicato) [![Bower](https://img.shields.io/bower/v/pizzicato.svg?maxAge=2592000)]() | ||
[![Build Status](https://travis-ci.org/alemangui/pizzicato.svg?branch=master)](https://travis-ci.org/alemangui/pizzicato) [![npm](https://img.shields.io/npm/v/pizzicato.svg?maxAge=2592000)](https://www.npmjs.com/package/pizzicato) [![Bower](https://img.shields.io/bower/v/pizzicato.svg?maxAge=2592000)]() [![CDNJS](https://img.shields.io/cdnjs/v/pizzicato.svg)]() | ||
@@ -11,2 +11,6 @@ ##A Web Audio library | ||
- [Get Pizzicato](#get-pizzicato) | ||
- [npm](#npm) | ||
- [bower](#bower) | ||
- [cdnjs](#cdnjs) | ||
- [Installing and testing](#installing-and-testing) | ||
- [TL;DR: How does it work?](#tldr) | ||
@@ -56,7 +60,32 @@ - [Create a sound](#create-a-sound) | ||
You can use bower to get Pizzicato | ||
<a name="npm"/> | ||
### npm | ||
``` | ||
npm install pizzicato | ||
``` | ||
<a name="bower"/> | ||
### bower | ||
``` | ||
bower install pizzicato | ||
``` | ||
<a name="cdnjs"/> | ||
### cdnjs | ||
Full source code: | ||
```html | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pizzicato/0.4.0/Pizzicato.js"></script> | ||
``` | ||
Minified: | ||
```html | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pizzicato/0.4.0/Pizzicato.min.js"></script> | ||
``` | ||
<a name="installing-and-testing"/> | ||
### Installing and testing | ||
Or checkout the project, install dependencies with | ||
@@ -409,3 +438,7 @@ ``` | ||
### Dub Delay ([example](https://alemangui.github.io/pizzicato/#dub-delay)) | ||
The dub delay effect is similar to a regular [Delay](#delay) effect, however on each feedback loop the output is routed through a biquad filter. The following options are available when creating a delay effect: | ||
The dub delay effect is similar to a regular [Delay](#delay) effect, however on each feedback loop the output is routed through a biquad filter. | ||
This effect is based on [Chris Lowis'](https://twitter.com/chrislowis) article [Creating dub delay effects with the Web Audio API](http://blog.chrislowis.co.uk/2014/07/23/dub-delay-web-audio-api.html). | ||
The following options are available when creating a delay effect: | ||
* ```feedback``` _(min: 0, max: 1, defaults to 0.5)_: The intensity with which the input will echo back. A larger value will result in more echo repetitions. | ||
@@ -430,5 +463,4 @@ * ```time``` _(min: 0, max: 180, defaults to 0.3)_: Interval time in seconds. | ||
### Distortion ([example](https://alemangui.github.io/pizzicato/#distortion)) | ||
The distortion effect adds an "override" to the sound, similar to the ones found in guitar amps. The distortion effect only takes one parameter: | ||
The distortion effect adds a basic "override" to the sound. The distortion effect only takes one parameter: | ||
* ```gain``` _(min: 0, max: 1, defaults to 0.5)_: Amount of distortion applied. | ||
* ```mix``` _(min: 0, max: 1, defaults to 0.5)_: Volume balance between the original audio and the effected output. | ||
@@ -602,4 +634,6 @@ Example: | ||
### Ring Modulator ([example](https://alemangui.github.io/pizzicato/#ring-modulator)) | ||
The ring modulator effect combines two input signals, where one of the inputs is a sine wave modulating the other. [This article from the BBC](http://webaudio.prototyping.bbc.co.uk/ring-modulator/) - from where this effect was inspired from - goes into deeper detail and explains how to recreate it. The 'ring' in this effect derives from the layout of diode nodes in the original analogue equipment, and also refers to the sound being increasingly modulated as it travels through the ring of diodes. | ||
The ring modulator effect combines two input signals, where one of the inputs is a sine wave modulating the other. | ||
[This article from the BBC](http://webaudio.prototyping.bbc.co.uk/ring-modulator/) - from where this effect was based from - goes into deeper detail and explains how to recreate it. The 'ring' in this effect derives from the layout of diode nodes in the original analogue equipment, and also refers to the sound being increasingly modulated as it travels through the ring of diodes. | ||
* ```distortion``` _(min: 0.2, max: 50, defaults to 1)_: Level of distortion applied to the diode nodes. | ||
@@ -606,0 +640,0 @@ * ```speed``` _(min: 0, max: 2000, defaults to 30)_: The frequency of the modulating signal. |
@@ -29,3 +29,3 @@ Pizzicato.Effects.Convolver = function(options, callback) { | ||
for (var key in defaults) { | ||
@@ -40,3 +40,3 @@ this[key] = options[key]; | ||
} | ||
request.open('GET', options.impulse, true); | ||
@@ -51,3 +51,3 @@ request.responseType = 'arraybuffer'; | ||
if (self.callback && Pz.Util.isFunction(self.callback)) | ||
if (self.callback && Pz.Util.isFunction(self.callback)) | ||
self.callback(); | ||
@@ -65,4 +65,5 @@ | ||
request.onreadystatechange = function(event) { | ||
if (request.readyState === 4 && request.status !== 200) | ||
if (request.readyState === 4 && request.status !== 200) { | ||
console.error('Error while fetching ' + options.impulse + '. ' + request.statusText); | ||
} | ||
}; | ||
@@ -77,3 +78,3 @@ | ||
enumerable: true, | ||
get: function() { | ||
@@ -80,0 +81,0 @@ return this.options.mix; |
@@ -16,3 +16,4 @@ Pizzicato.Sound = function(description, callback) { | ||
this.fadeNode = Pizzicato.context.createGain(); | ||
this.fadeNode.gain.value = 0; | ||
if (!hasOptions || !description.options.detached) | ||
@@ -93,2 +94,4 @@ this.masterVolume.connect(Pizzicato.masterGainNode); | ||
this.sourceNode = this.getRawSourceNode(); | ||
this.sourceNode.gainSuccessor = Pz.context.createGain(); | ||
this.sourceNode.connect(this.sourceNode.gainSuccessor); | ||
@@ -140,4 +143,5 @@ if (util.isFunction(callback)) | ||
if (request.readyState === 4 && request.status !== 200) | ||
if (request.readyState === 4 && request.status !== 200) { | ||
console.error('Error while fetching ' + paths[0] + '. ' + request.statusText); | ||
} | ||
}; | ||
@@ -261,3 +265,3 @@ request.send(); | ||
var elapsedTime = Pz.context.currentTime - this.lastTimePlayed; | ||
// If we are using a buffer node - potentially in loop mode - we need to | ||
@@ -301,7 +305,15 @@ // know where to re-start the sound independently of the loop it is in. | ||
value: function() { | ||
if (this.playing) | ||
this.stop(); | ||
if (!this.paused) | ||
this.trigger('end'); | ||
value: function(node) { | ||
return function() { | ||
// This function may've been called from the release | ||
// end. If in that time the Sound has been played again, | ||
// no action should be taken. | ||
if (!!this.sourceNode && this.sourceNode !== node) | ||
return; | ||
if (this.playing) | ||
this.stop(); | ||
if (!this.paused) | ||
this.trigger('end'); | ||
}; | ||
} | ||
@@ -450,3 +462,3 @@ }, | ||
* Returns the node that produces the sound. For example, an oscillator | ||
* if the Sound object was initialized with a wave option. | ||
* if the Sound object was initialized with a wave option. | ||
*/ | ||
@@ -457,11 +469,30 @@ getSourceNode: { | ||
value: function() { | ||
if (!!this.sourceNode) | ||
this.sourceNode.disconnect(); | ||
if (!!this.sourceNode) { | ||
// Directly disconnecting the previous source node causes a | ||
// 'click' noise, especially noticeable if the sound is played | ||
// while the release is ongoing. To address this, we fadeout the | ||
// old source node before disonnecting it. | ||
var previousSourceNode = this.sourceNode; | ||
previousSourceNode.gainSuccessor.gain.setValueAtTime(previousSourceNode.gainSuccessor.gain.value, Pz.context.currentTime); | ||
previousSourceNode.gainSuccessor.gain.linearRampToValueAtTime(0.0001, Pz.context.currentTime + 0.2); | ||
setTimeout(function() { | ||
previousSourceNode.disconnect(); | ||
previousSourceNode.gainSuccessor.disconnect(); | ||
}, 200); | ||
} | ||
var sourceNode = this.getRawSourceNode(); | ||
sourceNode.connect(this.fadeNode); | ||
sourceNode.onended = this.onEnded.bind(this); | ||
// A gain node will be placed after the source node to avoid | ||
// clicking noises (by fading out the sound) | ||
sourceNode.gainSuccessor = Pz.context.createGain(); | ||
sourceNode.connect(sourceNode.gainSuccessor); | ||
sourceNode.gainSuccessor.connect(this.fadeNode); | ||
this.fadeNode.connect(this.getInputNode()); | ||
if (Pz.Util.isAudioBufferSourceNode(sourceNode)) | ||
sourceNode.onended = this.onEnded(sourceNode).bind(this); | ||
return sourceNode; | ||
@@ -520,7 +551,14 @@ } | ||
value: function() { | ||
if (!this.attack) | ||
var currentValue = this.fadeNode.gain.value; | ||
this.fadeNode.gain.cancelScheduledValues(Pz.context.currentTime); | ||
this.fadeNode.gain.setValueAtTime(currentValue, Pz.context.currentTime); | ||
if (!this.attack) { | ||
this.fadeNode.gain.setValueAtTime(1.0, Pizzicato.context.currentTime); | ||
return; | ||
} | ||
this.fadeNode.gain.setValueAtTime(0.00001, Pizzicato.context.currentTime); | ||
this.fadeNode.gain.linearRampToValueAtTime(1, Pizzicato.context.currentTime + this.attack); | ||
var remainingAttackTime = (1 - this.fadeNode.gain.value) * this.attack; | ||
this.fadeNode.gain.setValueAtTime(this.fadeNode.gain.value, Pizzicato.context.currentTime); | ||
this.fadeNode.gain.linearRampToValueAtTime(1, Pizzicato.context.currentTime + remainingAttackTime); | ||
} | ||
@@ -544,12 +582,20 @@ }, | ||
if (!this.release) | ||
var currentValue = this.fadeNode.gain.value; | ||
this.fadeNode.gain.cancelScheduledValues(Pz.context.currentTime); | ||
this.fadeNode.gain.setValueAtTime(currentValue, Pz.context.currentTime); | ||
if (!this.release) { | ||
stopSound(); | ||
return; | ||
} | ||
var remainingReleaseTime = this.fadeNode.gain.value * this.release; | ||
this.fadeNode.gain.setValueAtTime(this.fadeNode.gain.value, Pizzicato.context.currentTime); | ||
this.fadeNode.gain.linearRampToValueAtTime(0.00001, Pizzicato.context.currentTime + this.release); | ||
this.fadeNode.gain.linearRampToValueAtTime(0.00001, Pizzicato.context.currentTime + remainingReleaseTime); | ||
window.setTimeout(function() { | ||
stopSound(); | ||
}, this.release * 1000); | ||
}, remainingReleaseTime * 1000); | ||
} | ||
} | ||
}); |
@@ -38,2 +38,6 @@ Pizzicato.Util = { | ||
isAudioBufferSourceNode: function(audioNode) { | ||
return (audioNode && audioNode.toString() === "[object AudioBufferSourceNode]"); | ||
}, | ||
isEffect: function(effect) { | ||
@@ -40,0 +44,0 @@ for (var key in Pizzicato.Effects) |
@@ -284,3 +284,3 @@ describe('Sound', function() { | ||
it('should trigger \'end\' when ended', function(done) { | ||
it('should trigger \'end\' when buffer ended', function(done) { | ||
var endCallback = jasmine.createSpy('endCallback'); | ||
@@ -287,0 +287,0 @@ |
@@ -93,2 +93,13 @@ describe('Util', function() { | ||
it('contains a working isAudioBufferSourceNode function', function() { | ||
var context = new window.AudioContext(); | ||
var bufferNode = context.createBufferSource(); | ||
var pannerNode = context.createPanner(); | ||
var isAudioBufferSourceNode = Pizzicato.Util.isAudioBufferSourceNode; | ||
expect(isAudioBufferSourceNode(bufferNode)).toBe(true); | ||
expect(isAudioBufferSourceNode(pannerNode)).toBe(false); | ||
}); | ||
it('contains a working isEffect function', function() { | ||
@@ -95,0 +106,0 @@ var isEffect = Pizzicato.Util.isEffect; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
718943
4627
753