@@ -5,6 +5,7 @@ define(function (require) {
55 var Add = require ( 'Tone/signal/Add' ) ;
66 var Mult = require ( 'Tone/signal/Multiply' ) ;
77 var Scale = require ( 'Tone/signal/Scale' ) ;
8+ var TimelineSignal = require ( 'Tone/signal/TimelineSignal' ) ;
89
910 var Tone = require ( 'Tone/core/Tone' ) ;
1011 Tone . setContext ( p5sound . audiocontext ) ;
@@ -69,6 +70,7 @@ define(function (require) {
6970 * </code></div>
7071 */
7172 p5 . Env = function ( t1 , l1 , t2 , l2 , t3 , l3 , t4 , l4 ) {
73+ var now = p5sound . audiocontext . currentTime ;
7274
7375 /**
7476 * @property attackTime
@@ -82,38 +84,34 @@ define(function (require) {
8284 * @property decayTime
8385 */
8486 this . dTime = t2 || 0 ;
85- /**
86- * @property decayLevel
87- */
88- this . dLevel = l2 || 0 ;
89- /**
90- * @property sustainTime
91- */
92- this . sTime = t3 || 0 ;
9387 /**
9488 * @property sustainLevel
9589 */
96- this . sLevel = l3 || 0 ;
90+ this . sLevel = l2 || 0 ;
9791 /**
9892 * @property releaseTime
9993 */
100- this . rTime = t4 || 0 ;
94+ this . rTime = t3 || 0 ;
10195 /**
10296 * @property releaseLevel
10397 */
104- this . rLevel = l4 || 0 ;
98+ this . rLevel = l3 || 0 ;
99+
105100
106101 this . output = p5sound . audiocontext . createGain ( ) ; ;
107102
108- this . control = new p5 . Signal ( ) ;
109-
103+ this . control = new TimelineSignal ( ) ;
110104 this . control . connect ( this . output ) ;
105+ this . control . setValueAtTime ( 0 , now ) ;
111106
112107 this . connection = null ; // store connection
113108
114109 //array of math operation signal chaining
115110 this . mathOps = [ this . control ] ;
116111
112+ //whether envelope should be linear or exponential curve
113+ this . isExponential = false ;
114+
117115 // oscillator or buffer source to clear on env complete
118116 // to save resources if/when it is retriggered
119117 this . sourceToClear = null ;
@@ -135,22 +133,19 @@ define(function (require) {
135133 * @param {Number } aLevel Typically an amplitude between
136134 * 0.0 and 1.0
137135 * @param {Number } dTime Time
138- * @param {Number } [dLevel ] Amplitude (In a standard ADSR envelope,
136+ * @param {Number } [sLevel ] Amplitude (In a standard ADSR envelope,
139137 * decayLevel = sustainLevel)
140- * @param {Number } [sTime] Time (in seconds)
141- * @param {Number } [sLevel] Amplitude 0.0 to 1.0
142- * @param {Number } [rTime] Time (in seconds)
138+ * @param {Number } [rTime] Release Time (in seconds)
143139 * @param {Number } [rLevel] Amplitude 0.0 to 1.0
140+
144141 */
145- p5 . Env . prototype . set = function ( t1 , l1 , t2 , l2 , t3 , l3 , t4 , l4 ) {
142+ p5 . Env . prototype . set = function ( t1 , l1 , t2 , l2 , t3 , l3 ) {
146143 this . aTime = t1 ;
147144 this . aLevel = l1 ;
148145 this . dTime = t2 || 0 ;
149- this . dLevel = l2 || 0 ;
150- this . sTime = t3 || 0 ;
151- this . sLevel = l3 || 0 ;
152- this . rTime = t4 || 0 ;
153- this . rLevel = l4 || 0 ;
146+ this . sLevel = l2 || 0 ;
147+ this . rTime = t3 || 0 ;
148+ this . rLevel = l3 || 0 ;
154149 } ;
155150
156151 /**
@@ -169,6 +164,19 @@ define(function (require) {
169164 }
170165 } ;
171166
167+ p5 . Env . prototype . setExp = function ( isExp ) {
168+ this . isExponential = isExp ;
169+ }
170+
171+ //protect against zero values being sent to exponential functions
172+ p5 . Env . prototype . checkExpInput = function ( value ) {
173+ if ( value <= 0 )
174+ {
175+ value = 0.0001 ;
176+ }
177+ return value ;
178+ } ;
179+
172180 p5 . Env . prototype . ctrl = function ( unit ) {
173181 this . connect ( unit ) ;
174182 } ;
@@ -197,21 +205,8 @@ define(function (require) {
197205 }
198206 }
199207
200- var currentVal = this . control . getValue ( ) ;
201- this . control . cancelScheduledValues ( t ) ;
202- this . control . linearRampToValueAtTime ( currentVal , t ) ;
203-
204- // attack
205- this . control . linearRampToValueAtTime ( this . aLevel , t + this . aTime ) ;
206- // decay to decay level
207- this . control . linearRampToValueAtTime ( this . dLevel , t + this . aTime + this . dTime ) ;
208- // hold sustain level
209- this . control . linearRampToValueAtTime ( this . sLevel , t + this . aTime + this . dTime + this . sTime ) ;
210- // release
211- this . control . linearRampToValueAtTime ( this . rLevel , t + this . aTime + this . dTime + this . sTime + this . rTime ) ;
212-
213- var clearTime = ( t + this . aTime + this . dTime + this . sTime + this . rTime ) ; //* 1000;
214-
208+ this . triggerAttack ( unit , secondsFromNow ) ;
209+ this . triggerRelease ( unit , secondsFromNow + this . aTime + this . dTime ) ;
215210 } ;
216211
217212 /**
@@ -233,27 +228,62 @@ define(function (require) {
233228 this . lastAttack = t ;
234229 this . wasTriggered = true ;
235230
236- // we should set current value, but this is not working on Firefox
237- var currentVal = this . control . getValue ( ) ;
238- console . log ( currentVal ) ;
239- this . control . cancelScheduledValues ( t ) ;
240- this . control . linearRampToValueAtTime ( currentVal , t ) ;
241-
242231 if ( unit ) {
243232 if ( this . connection !== unit ) {
244233 this . connect ( unit ) ;
245234 }
246235 }
247236
248- this . control . linearRampToValueAtTime ( this . aLevel , t + this . aTime ) ;
237+ // get and set value (with linear ramp) to anchor automation
238+ var valToSet = this . control . getValueAtTime ( t ) ;
239+ if ( this . isExponential == true )
240+ {
241+ this . control . exponentialRampToValueAtTime ( this . checkExpInput ( valToSet ) , t ) ;
242+ }
243+ else
244+ {
245+ this . control . linearRampToValueAtTime ( valToSet , t ) ;
246+ }
247+
248+ // after each ramp completes, cancel scheduled values
249+ // (so they can be overridden in case env has been re-triggered)
250+ // then, set current value (with linearRamp to avoid click)
251+ // then, schedule the next automation...
249252
250253 // attack
251- this . control . linearRampToValueAtTime ( this . aLevel , t + this . aTime ) ;
252- // decay to sustain level
253- this . control . linearRampToValueAtTime ( this . dLevel , t + this . aTime + this . dTime ) ;
254-
255- this . control . linearRampToValueAtTime ( this . sLevel , t + this . aTime + this . dTime + this . sTime ) ;
254+ t += this . aTime ;
255+
256+ if ( this . isExponential == true )
257+ {
258+ this . control . exponentialRampToValueAtTime ( this . checkExpInput ( this . aLevel ) , t ) ;
259+ valToSet = this . checkExpInput ( this . control . getValueAtTime ( t ) ) ;
260+ this . control . cancelScheduledValues ( t ) ;
261+ this . control . exponentialRampToValueAtTime ( valToSet , t ) ;
262+ }
263+ else
264+ {
265+ this . control . linearRampToValueAtTime ( this . aLevel , t ) ;
266+ valToSet = this . control . getValueAtTime ( t ) ;
267+ this . control . cancelScheduledValues ( t ) ;
268+ this . control . linearRampToValueAtTime ( valToSet , t ) ;
269+ }
256270
271+ // decay to decay level
272+ t += this . dTime ;
273+ if ( this . isExponential == true )
274+ {
275+ this . control . exponentialRampToValueAtTime ( this . checkExpInput ( this . sLevel ) , t ) ;
276+ valToSet = this . checkExpInput ( this . control . getValueAtTime ( t ) ) ;
277+ this . control . cancelScheduledValues ( t ) ;
278+ this . control . exponentialRampToValueAtTime ( valToSet , t ) ;
279+ }
280+ else
281+ {
282+ this . control . linearRampToValueAtTime ( this . sLevel , t ) ;
283+ valToSet = this . control . getValueAtTime ( t ) ;
284+ this . control . cancelScheduledValues ( t ) ;
285+ this . control . linearRampToValueAtTime ( valToSet , t ) ;
286+ }
257287 } ;
258288
259289 /**
@@ -275,57 +305,40 @@ define(function (require) {
275305 var now = p5sound . audiocontext . currentTime ;
276306 var tFromNow = secondsFromNow || 0 ;
277307 var t = now + tFromNow ;
278- var relTime ;
279308
280309 if ( unit ) {
281310 if ( this . connection !== unit ) {
282311 this . connect ( unit ) ;
283312 }
284313 }
285314
286- this . control . cancelScheduledValues ( t ) ;
287-
288- // ideally would get & set currentValue here,
289- // but this.control._scalar.gain.value not working in firefox
290-
291- // release based on how much time has passed since this.lastAttack
292- if ( ( t - this . lastAttack ) < ( this . aTime ) ) {
293- var a = this . aTime - ( t - this . lastAttack ) ;
294- this . control . linearRampToValueAtTime ( this . aLevel , t + a ) ;
295- this . control . linearRampToValueAtTime ( this . dLevel , t + a + this . dTime ) ;
296- this . control . linearRampToValueAtTime ( this . sLevel , t + a + this . dTime + this . sTime ) ;
297- this . control . linearRampToValueAtTime ( this . rLevel , t + a + this . dTime + this . sTime + this . rTime ) ;
298- relTime = t + this . dTime + this . sTime + this . rTime ;
315+ // get and set value (with linear or exponential ramp) to anchor automation
316+ var valToSet = this . control . getValueAtTime ( t ) ;
317+ if ( this . isExponential == true )
318+ {
319+ this . control . exponentialRampToValueAtTime ( this . checkExpInput ( valToSet ) , t ) ;
299320 }
300- else if ( ( t - this . lastAttack ) < ( this . aTime + this . dTime ) ) {
301- var d = this . aTime + this . dTime - ( now - this . lastAttack ) ;
302- this . control . linearRampToValueAtTime ( this . dLevel , t + d ) ;
303- // this.control.linearRampToValueAtTime(this.sLevel, t + d + this.sTime);
304- this . control . linearRampToValueAtTime ( this . sLevel , t + d + 0.01 ) ;
305- this . control . linearRampToValueAtTime ( this . rLevel , t + d + 0.01 + this . rTime ) ;
306- relTime = t + this . sTime + this . rTime ;
307- }
308- else if ( ( t - this . lastAttack ) < ( this . aTime + this . dTime + this . sTime ) ) {
309- var s = this . aTime + this . dTime + this . sTime - ( now - this . lastAttack ) ;
310- this . control . linearRampToValueAtTime ( this . sLevel , t + s ) ;
311- this . control . linearRampToValueAtTime ( this . rLevel , t + s + this . rTime ) ;
312- relTime = t + this . rTime ;
321+ else
322+ {
323+ this . control . linearRampToValueAtTime ( valToSet , t ) ;
313324 }
314- else {
315- this . control . linearRampToValueAtTime ( this . sLevel , t ) ;
316- this . control . linearRampToValueAtTime ( this . rLevel , t + this . rTime ) ;
317- relTime = t + this . dTime + this . sTime + this . rTime ;
325+
326+ // release
327+ t += this . rTime ;
328+
329+ if ( this . isExponential == true )
330+ {
331+ this . control . exponentialRampToValueAtTime ( this . checkExpInput ( this . rLevel ) , t ) ;
332+ valToSet = this . checkExpInput ( this . control . getValueAtTime ( t ) ) ;
333+ this . control . cancelScheduledValues ( t ) ;
334+ this . control . exponentialRampToValueAtTime ( valToSet , t ) ;
318335 }
319-
320- // clear osc / sources
321- var clearTime = ( t + this . aTime + this . dTime + this . sTime + this . rTime ) ; // * 1000;
322-
323- if ( this . connection && this . connection . hasOwnProperty ( 'oscillator' ) ) {
324- this . sourceToClear = this . connection . oscillator ;
325- this . sourceToClear . stop ( clearTime + .01 ) ;
326- } else if ( this . connect && this . connection . hasOwnProperty ( 'source' ) ) {
327- this . sourceToClear = this . connection . source ;
328- this . sourceToClear . stop ( clearTime + .01 ) ;
336+ else
337+ {
338+ this . control . linearRampToValueAtTime ( this . rLevel , t ) ;
339+ valToSet = this . control . getValueAtTime ( t ) ;
340+ this . control . cancelScheduledValues ( t ) ;
341+ this . control . linearRampToValueAtTime ( valToSet , t ) ;
329342 }
330343
331344 this . wasTriggered = false ;
@@ -360,6 +373,8 @@ define(function (require) {
360373 this . output . disconnect ( ) ;
361374 } ;
362375
376+
377+
363378 // Signal Math
364379
365380 /**
@@ -419,6 +434,10 @@ define(function (require) {
419434
420435 // get rid of the oscillator
421436 p5 . Env . prototype . dispose = function ( ) {
437+ // remove reference from soundArray
438+ var index = p5sound . soundArray . indexOf ( this ) ;
439+ p5sound . soundArray . splice ( index , 1 ) ;
440+
422441 var now = p5sound . audiocontext . currentTime ;
423442 this . disconnect ( ) ;
424443 try {
0 commit comments