I found and fixed a condition that kept some sustain changes from being propagated. I cleaned other stuff up a little, too.
(tweaked text from previous announcement:)
I have been working on envelopes lately, and I have come up with something that I'd like to share. I started out with the basic ADSR in Miller's examples; I wanted variable envelope curves, but I didn't want the overhead of on-the-fly sqrt's or complex expr's. Therefore, [multiCurveAdsr] uses table-lookup for enveloping, with just one multiplication for level-scaling. The lookup table only needs to be computed when the "curve factor" is changed.
Three basic curve types are possible. C (curve factor) = 1 gives the basic linear envelope. C > 1 gives a continuous range of fatter, "ead"-like envelopes. C < 1 is a special case; for any value of C less than 1, you get one "quartic"-like, hollow curve. (I really like the way this one sounds, by the way).
The math in the [pd makeCurve] subpatch is not elegant -- I took an empirical approach, tweaking things until I got the shapes I wanted -- but it works well enough. One little hitch I ran into was that sustain level varied with different curve factors, so I made a corrective subpatch that keeps sustain values consistent across the different curves. This subpatch only comes into play when the sustain value or curve factor changes.
The right output emits 1 on attack, and 0 after release is complete. I use this to switch~ the voice being enveloped, for further CPU-cycle economy.
The help patch shows the effect of the different curve factors graphically. I don't think there are any dependencies outside of "Miller Vanilla" PD.
I use [multiCurveAdsr] for my own synthesis abstractions, and find that it sounds pretty good, plus it's thrifty on CPU-usage, even with many voices. I hope somebody else finds it useful. Any suggestions for improvement will be greatly appreciated.
Phil Stone
#N canvas 507 117 649 576 10; #X obj 17 84 inlet; #X text 13 63 trigger; #X obj 17 132 sel 0; #X obj 221 316 del $2; #X obj 240 342 f $4; #X msg 17 192 stop; #X text 75 304 ATTACK; #X obj 240 525 outlet~; #X text 54 74 if zero; #X text 55 91 release; #X text 44 109 bang if attack; #X text 320 2 When you send this patch a nonzero trigger it schedules a line~ to do an attack and decay , and if zero , it starts the release ramp.; #X obj 240 413 vline~; #X obj 240 370 pack 0 0; #X obj 240 497 *~; #X obj 267 107 inlet A; #X obj 317 107 inlet D; #X obj 368 107 inlet S; #X obj 419 107 inlet R; #N canvas 0 22 490 340 graph1 0; #X array $0-envCurve 102 float 0; #X coords 0 1 101 0 100 100 1; #X restore 500 272 graph; #X text 604 364 0; #X text 603 264 1; #X text 192 341 DECAY; #X text 347 275 RELEASE; #X obj 141 130 f; #X obj 422 454 outlet switch; #X obj 389 322 pack 0 $5; #X obj 240 447 tabread4~ $0-envCurve; #X obj 422 428 r $0-activate; #X obj 133 182 s $0-activate; #X msg 105 156 1; #X obj 66 132 t b b b; #X obj 362 296 t b b; #X obj 363 357 del $5; #X msg 363 382 0; #X text 385 506 - when finished (i.e. , end of release) ,; #X text 386 490 - on attack: send "on" for dsp of parent voice; #X text 395 520 send "off" for dsp of parent voice; #X text 384 475 This outlet may be used as follows:; #X obj 156 107 inlet attackLevel; #X obj 492 189 change; #X obj 502 136 loadbang; #X obj 67 325 pack 100 $2; #X text 17 1 Multi-curve ADSR; #X obj 255 474 r $0-levelmult; #X obj 141 153 s $0-levelmult; #X text 452 36 Curve Factors; #X text 17 19 arguments: level , attack time , decay time , sustain level (proportion of overall level 0 - 100) , release time; #X obj 492 107 inlet curveFactor; #X text 388 83 > 1 - exponential (fat) curves , varying with C; #X msg 502 159 1; #X text 118 58 This adsr uses table-lookup for envelope curves ,; #X text 119 73 so it should be pretty cpu-efficient.; #X text 399 68 1 - linear; #X obj 17 162 t b b; #X text 36 409 and left-over release switch~; #X text 48 195 (*); #X text 35 394 (*) cancel decay ,; #X text 388 53 < 1 - "quartic-like" (hollow) curve , C=-0.214; #N canvas 547 29 545 431 6886-makeCurve 0; #X msg 21 315 0; #X obj 104 115 - 1; #X msg 142 94 0; #X obj 142 120 f; #X obj 167 120 + 1; #X obj 71 224 f; #X obj 318 313 expr 1 - (pow( ($f1 / 102) , $f2) ); #X obj 285 158 t b f; #X obj 382 156 t b f; #X obj 318 287 spigot; #X obj 71 289 spigot; #X obj 325 262 0; #X obj 351 262 1; #X obj 78 265 1; #X obj 104 265 0; #X obj 71 314 expr pow( ($f1 / 102) , $f2) -1; #X text 361 294 exponential "fat" curve; #X msg 285 133 -0.214; #X obj 130 392 tabwrite $0-envCurve; #X obj 71 200 b; #X obj 130 363 f; #X obj 38 8 inlet curveFactor; #X msg 38 93 102; #X obj 29 118 sel 0; #X obj 69 116 f; #X obj 69 93 until; #X obj 48 142 t f f b f; #X obj 38 34 t b b b b f; #X obj 226 110 sel 1; #X obj 227 255 spigot; #X obj 232 229 0; #X obj 260 229 1; #X obj 142 148 t f f f f; #X obj 227 279 / 100; #X obj 307 108 moses 1; #X text 115 296 "quartic-like" curve; #X obj 20 176 moses 2; #X connect 0 0 20 0; #X connect 1 0 24 1; #X connect 2 0 3 1; #X connect 3 0 32 0; #X connect 4 0 3 1; #X connect 5 0 9 0; #X connect 5 0 10 0; #X connect 6 0 20 0; #X connect 7 0 11 0; #X connect 7 0 30 0; #X connect 7 0 13 0; #X connect 7 1 15 1; #X connect 8 0 12 0; #X connect 8 0 14 0; #X connect 8 0 30 0; #X connect 8 1 6 1; #X connect 9 0 6 0; #X connect 10 0 15 0; #X connect 11 0 9 1; #X connect 12 0 9 1; #X connect 13 0 10 1; #X connect 14 0 10 1; #X connect 15 0 20 0; #X connect 17 0 7 0; #X connect 19 0 5 0; #X connect 20 0 18 0; #X connect 21 0 27 0; #X connect 22 0 24 0; #X connect 23 0 25 1; #X connect 24 0 26 0; #X connect 25 0 24 0; #X connect 26 0 23 0; #X connect 26 1 5 1; #X connect 26 2 3 0; #X connect 26 3 1 0; #X connect 27 0 25 0; #X connect 27 1 22 0; #X connect 27 2 3 0; #X connect 27 3 2 0; #X connect 27 4 28 0; #X connect 28 0 31 0; #X connect 28 0 11 0; #X connect 28 0 14 0; #X connect 28 1 34 0; #X connect 29 0 33 0; #X connect 30 0 29 1; #X connect 31 0 29 1; #X connect 32 0 36 0; #X connect 32 1 29 0; #X connect 32 2 18 1; #X connect 32 3 4 0; #X connect 33 0 20 0; #X connect 34 0 17 0; #X connect 34 1 8 0; #X connect 36 0 0 0; #X connect 36 1 19 0; #X restore 492 220 pd $0-makeCurve; #N canvas 204 22 488 551 correctSustain 1; #X obj 204 294 f; #X obj 252 294 + 1; #X obj 159 355 tabread $0-envCurve; #X obj 28 7 inlet sustain; #X obj 72 498 outlet correctedSustain; #X obj 188 440 f; #X obj 143 7 inlet curve; #X obj 159 256 t f f; #X obj 204 270 b; #X obj 159 293 / 100; #X obj 159 410 sel 0; #X obj 159 232 spigot; #X msg 160 188 0; #X msg 192 188 1; #X obj 315 233 spigot; #X msg 316 189 0; #X msg 348 189 1; #X obj 361 295 f; #X obj 316 356 tabread $0-envCurve; #X obj 345 441 f; #X obj 316 257 t f f; #X obj 361 271 b; #X obj 316 294 / 100; #X obj 410 274 - 1; #X obj 159 384 <=; #X obj 316 411 sel 1; #X obj 361 320 t f f f; #X obj 204 319 t f f f; #X obj 53 114 sel 0; #X msg 60 228 0; #X obj 237 142 moses 1; #X obj 316 385 <=; #X obj 62 138 moses 100; #X msg 84 249 100; #X obj 152 113 sel 1; #X obj 23 204 f; #X obj 152 137 t b b b; #X text 237 19 Finds the input sustain value in the envelope; #X obj 28 55 f; #X obj 143 54 t b f; #X obj 28 31 change; #X obj 143 30 change; #X obj 155 77 f; #X obj 28 83 t f f b; #X text 238 36 curve table , and outputs the index of it.; #X connect 0 0 27 0; #X connect 1 0 0 1; #X connect 2 0 24 0; #X connect 3 0 40 0; #X connect 5 0 4 0; #X connect 6 0 41 0; #X connect 7 0 0 0; #X connect 7 1 9 0; #X connect 8 0 0 0; #X connect 9 0 24 1; #X connect 10 0 5 0; #X connect 10 1 8 0; #X connect 11 0 7 0; #X connect 12 0 11 1; #X connect 13 0 11 1; #X connect 14 0 20 0; #X connect 15 0 14 1; #X connect 16 0 14 1; #X connect 17 0 26 0; #X connect 18 0 31 0; #X connect 19 0 4 0; #X connect 20 0 17 0; #X connect 20 1 22 0; #X connect 21 0 17 0; #X connect 22 0 31 1; #X connect 23 0 17 1; #X connect 24 0 10 0; #X connect 25 0 19 0; #X connect 25 1 21 0; #X connect 26 0 18 0; #X connect 26 1 19 1; #X connect 26 2 23 0; #X connect 27 0 2 0; #X connect 27 1 5 1; #X connect 27 2 1 0; #X connect 28 0 29 0; #X connect 28 1 32 0; #X connect 29 0 4 0; #X connect 30 0 13 0; #X connect 30 0 15 0; #X connect 30 1 16 0; #X connect 30 1 12 0; #X connect 31 0 25 0; #X connect 32 0 11 0; #X connect 32 0 14 0; #X connect 32 1 33 0; #X connect 33 0 4 0; #X connect 34 0 36 0; #X connect 34 1 30 0; #X connect 35 0 4 0; #X connect 36 0 35 0; #X connect 36 1 12 0; #X connect 36 2 15 0; #X connect 38 0 43 0; #X connect 39 0 38 0; #X connect 39 1 42 1; #X connect 40 0 38 0; #X connect 41 0 39 0; #X connect 42 0 34 0; #X connect 43 0 35 1; #X connect 43 1 28 0; #X connect 43 2 42 0; #X restore 334 146 pd correctSustain; #X connect 0 0 2 0; #X connect 2 0 54 0; #X connect 2 1 31 0; #X connect 3 0 4 0; #X connect 4 0 13 0; #X connect 5 0 3 0; #X connect 5 0 33 0; #X connect 12 0 27 0; #X connect 13 0 12 0; #X connect 14 0 7 0; #X connect 15 0 3 1; #X connect 15 0 42 1; #X connect 16 0 13 1; #X connect 17 0 60 0; #X connect 18 0 26 1; #X connect 18 0 33 1; #X connect 24 0 45 0; #X connect 26 0 12 0; #X connect 27 0 14 0; #X connect 28 0 25 0; #X connect 30 0 29 0; #X connect 31 0 3 0; #X connect 31 0 42 0; #X connect 31 1 24 0; #X connect 31 2 30 0; #X connect 32 0 33 0; #X connect 32 1 26 0; #X connect 33 0 34 0; #X connect 34 0 25 0; #X connect 39 0 24 1; #X connect 40 0 59 0; #X connect 41 0 50 0; #X connect 42 0 12 0; #X connect 44 0 14 1; #X connect 48 0 40 0; #X connect 48 0 60 1; #X connect 50 0 40 0; #X connect 54 0 32 0; #X connect 54 1 5 0; #X connect 60 0 4 1;
#N canvas 158 75 478 554 10; #N canvas 0 22 458 308 (subpatch) 0; #X array envelope 10000 float 2; #X coords 0 1 10000 0 400 140 1; #X restore 22 180 graph; #X obj 304 -173 loadbang; #X obj 138 -30 nbx 5 14 0 100 0 1 empty empty Level 0 -8 0 10 -262144 -1 -1 1 256; #X obj 170 -1 nbx 5 14 0 3000 0 1 empty empty A 0 -8 0 10 -262144 -1 -1 60 256; #X obj 200 30 nbx 5 14 0 2000 0 1 empty empty D 0 -8 0 10 -262144 -1 -1 20 256; #X obj 232 60 nbx 5 14 0 100 0 1 empty empty S 0 -8 0 10 -262144 -1 -1 50 256; #X obj 262 89 nbx 5 14 0 100 0 1 empty empty R 0 -8 0 10 -262144 -1 -1 79 256; #X msg 304 -147 ; pd dsp 1; #X obj 41 -177 bng 15 250 50 0 empty empty empty 0 -6 0 10 -262144 -1 -1; #X msg 80 -41 0; #X obj 80 -65 delay 200; #X obj 131 -88 nbx 5 14 -1e+37 1e+37 0 1 empty empty hold_time 0 -6 0 10 -262144 -1 -1 138 256; #X msg 41 -41 1; #X obj 96 153 tabwrite~ envelope; #X obj 311 122 nbx 5 14 0 20 0 1 empty empty curve_factor 0 -6 0 10 -262144 -1 -1 1 256; #X obj 106 -185 notein; #X obj 106 -162 sel 0; #X obj 41 -159 t b b; #X obj 41 -4 t f b; #X obj 133 -139 t b f; #X obj 212 -97 / 127; #X obj 12 -201 loadbang; #X text 91 -208 Hit bang or MIDI key to see current envelope; #X text 293 -79 Curve Factors; #X text 240 -47 1 - linear; #X text 229 -32 > 1 - exponential (fat) curves , varying with C; #X obj 110 124 multiCurveAdsr 0.98 10 20 99 20; #X floatatom 316 159 5 0 0 0 - - -; #X text 350 155 for switch~ing parent; #X text 229 -62 < 1 - "quartic-like" (hollow) curve , C=-0.214; #X connect 1 0 7 0; #X connect 2 0 26 1; #X connect 3 0 26 2; #X connect 4 0 26 3; #X connect 5 0 26 4; #X connect 6 0 26 5; #X connect 8 0 17 0; #X connect 9 0 26 0; #X connect 10 0 9 0; #X connect 11 0 10 1; #X connect 12 0 18 0; #X connect 14 0 26 6; #X connect 15 1 16 0; #X connect 16 0 9 0; #X connect 16 1 19 0; #X connect 17 0 12 0; #X connect 17 1 10 0; #X connect 18 0 26 0; #X connect 18 1 13 0; #X connect 19 0 12 0; #X connect 19 1 20 0; #X connect 20 0 2 0; #X connect 21 0 17 0; #X connect 26 0 13 0; #X connect 26 1 27 0;
cool work! thanks for sharing it!
personally, i like a logarithmic curve the most for decay and release (this is also, how decays happen to be in nature [e.g a bell]), though otoh, a logarithmic curve doesn't make much sense for attack, if applied to the amplitude (nothing happens for a long period and then suddenly the sound comes). how about using a separate c parameter for the attack, so that one could have fat (for attack) and hollow (for decay) at the same time?
roman
On Fri, 2007-05-18 at 14:35 -0700, Phil Stone wrote:
I found and fixed a condition that kept some sustain changes from being propagated. I cleaned other stuff up a little, too.
(tweaked text from previous announcement:)
I have been working on envelopes lately, and I have come up with something that I'd like to share. I started out with the basic ADSR in Miller's examples; I wanted variable envelope curves, but I didn't want the overhead of on-the-fly sqrt's or complex expr's. Therefore, [multiCurveAdsr] uses table-lookup for enveloping, with just one multiplication for level-scaling. The lookup table only needs to be computed when the "curve factor" is changed.
Three basic curve types are possible. C (curve factor) = 1 gives the basic linear envelope. C > 1 gives a continuous range of fatter, "ead"-like envelopes. C < 1 is a special case; for any value of C less than 1, you get one "quartic"-like, hollow curve. (I really like the way this one sounds, by the way).
The math in the [pd makeCurve] subpatch is not elegant -- I took an empirical approach, tweaking things until I got the shapes I wanted -- but it works well enough. One little hitch I ran into was that sustain level varied with different curve factors, so I made a corrective subpatch that keeps sustain values consistent across the different curves. This subpatch only comes into play when the sustain value or curve factor changes.
The right output emits 1 on attack, and 0 after release is complete. I use this to switch~ the voice being enveloped, for further CPU-cycle economy.
The help patch shows the effect of the different curve factors graphically. I don't think there are any dependencies outside of "Miller Vanilla" PD.
I use [multiCurveAdsr] for my own synthesis abstractions, and find that it sounds pretty good, plus it's thrifty on CPU-usage, even with many voices. I hope somebody else finds it useful. Any suggestions for improvement will be greatly appreciated.
Phil Stone
plain text document attachment (multiCurveAdsr.pd) #N canvas 507 117 649 576 10; #X obj 17 84 inlet; #X text 13 63 trigger; #X obj 17 132 sel 0; #X obj 221 316 del $2; #X obj 240 342 f $4; #X msg 17 192 stop; #X text 75 304 ATTACK; #X obj 240 525 outlet~; #X text 54 74 if zero; #X text 55 91 release; #X text 44 109 bang if attack; #X text 320 2 When you send this patch a nonzero trigger it schedules a line~ to do an attack and decay , and if zero , it starts the release ramp.; #X obj 240 413 vline~; #X obj 240 370 pack 0 0; #X obj 240 497 *~; #X obj 267 107 inlet A; #X obj 317 107 inlet D; #X obj 368 107 inlet S; #X obj 419 107 inlet R; #N canvas 0 22 490 340 graph1 0; #X array $0-envCurve 102 float 0; #X coords 0 1 101 0 100 100 1; #X restore 500 272 graph; #X text 604 364 0; #X text 603 264 1; #X text 192 341 DECAY; #X text 347 275 RELEASE; #X obj 141 130 f; #X obj 422 454 outlet switch; #X obj 389 322 pack 0 $5; #X obj 240 447 tabread4~ $0-envCurve; #X obj 422 428 r $0-activate; #X obj 133 182 s $0-activate; #X msg 105 156 1; #X obj 66 132 t b b b; #X obj 362 296 t b b; #X obj 363 357 del $5; #X msg 363 382 0; #X text 385 506 - when finished (i.e. , end of release) ,; #X text 386 490 - on attack: send "on" for dsp of parent voice; #X text 395 520 send "off" for dsp of parent voice; #X text 384 475 This outlet may be used as follows:; #X obj 156 107 inlet attackLevel; #X obj 492 189 change; #X obj 502 136 loadbang; #X obj 67 325 pack 100 $2; #X text 17 1 Multi-curve ADSR; #X obj 255 474 r $0-levelmult; #X obj 141 153 s $0-levelmult; #X text 452 36 Curve Factors; #X text 17 19 arguments: level , attack time , decay time , sustain level (proportion of overall level 0 - 100) , release time; #X obj 492 107 inlet curveFactor; #X text 388 83 > 1 - exponential (fat) curves , varying with C; #X msg 502 159 1; #X text 118 58 This adsr uses table-lookup for envelope curves ,; #X text 119 73 so it should be pretty cpu-efficient.; #X text 399 68 1 - linear; #X obj 17 162 t b b; #X text 36 409 and left-over release switch~; #X text 48 195 (*); #X text 35 394 (*) cancel decay ,; #X text 388 53 < 1 - "quartic-like" (hollow) curve , C=-0.214; #N canvas 547 29 545 431 6886-makeCurve 0; #X msg 21 315 0; #X obj 104 115 - 1; #X msg 142 94 0; #X obj 142 120 f; #X obj 167 120 + 1; #X obj 71 224 f; #X obj 318 313 expr 1 - (pow( ($f1 / 102) , $f2) ); #X obj 285 158 t b f; #X obj 382 156 t b f; #X obj 318 287 spigot; #X obj 71 289 spigot; #X obj 325 262 0; #X obj 351 262 1; #X obj 78 265 1; #X obj 104 265 0; #X obj 71 314 expr pow( ($f1 / 102) , $f2) -1; #X text 361 294 exponential "fat" curve; #X msg 285 133 -0.214; #X obj 130 392 tabwrite $0-envCurve; #X obj 71 200 b; #X obj 130 363 f; #X obj 38 8 inlet curveFactor; #X msg 38 93 102; #X obj 29 118 sel 0; #X obj 69 116 f; #X obj 69 93 until; #X obj 48 142 t f f b f; #X obj 38 34 t b b b b f; #X obj 226 110 sel 1; #X obj 227 255 spigot; #X obj 232 229 0; #X obj 260 229 1; #X obj 142 148 t f f f f; #X obj 227 279 / 100; #X obj 307 108 moses 1; #X text 115 296 "quartic-like" curve; #X obj 20 176 moses 2; #X connect 0 0 20 0; #X connect 1 0 24 1; #X connect 2 0 3 1; #X connect 3 0 32 0; #X connect 4 0 3 1; #X connect 5 0 9 0; #X connect 5 0 10 0; #X connect 6 0 20 0; #X connect 7 0 11 0; #X connect 7 0 30 0; #X connect 7 0 13 0; #X connect 7 1 15 1; #X connect 8 0 12 0; #X connect 8 0 14 0; #X connect 8 0 30 0; #X connect 8 1 6 1; #X connect 9 0 6 0; #X connect 10 0 15 0; #X connect 11 0 9 1; #X connect 12 0 9 1; #X connect 13 0 10 1; #X connect 14 0 10 1; #X connect 15 0 20 0; #X connect 17 0 7 0; #X connect 19 0 5 0; #X connect 20 0 18 0; #X connect 21 0 27 0; #X connect 22 0 24 0; #X connect 23 0 25 1; #X connect 24 0 26 0; #X connect 25 0 24 0; #X connect 26 0 23 0; #X connect 26 1 5 1; #X connect 26 2 3 0; #X connect 26 3 1 0; #X connect 27 0 25 0; #X connect 27 1 22 0; #X connect 27 2 3 0; #X connect 27 3 2 0; #X connect 27 4 28 0; #X connect 28 0 31 0; #X connect 28 0 11 0; #X connect 28 0 14 0; #X connect 28 1 34 0; #X connect 29 0 33 0; #X connect 30 0 29 1; #X connect 31 0 29 1; #X connect 32 0 36 0; #X connect 32 1 29 0; #X connect 32 2 18 1; #X connect 32 3 4 0; #X connect 33 0 20 0; #X connect 34 0 17 0; #X connect 34 1 8 0; #X connect 36 0 0 0; #X connect 36 1 19 0; #X restore 492 220 pd $0-makeCurve; #N canvas 204 22 488 551 correctSustain 1; #X obj 204 294 f; #X obj 252 294 + 1; #X obj 159 355 tabread $0-envCurve; #X obj 28 7 inlet sustain; #X obj 72 498 outlet correctedSustain; #X obj 188 440 f; #X obj 143 7 inlet curve; #X obj 159 256 t f f; #X obj 204 270 b; #X obj 159 293 / 100; #X obj 159 410 sel 0; #X obj 159 232 spigot; #X msg 160 188 0; #X msg 192 188 1; #X obj 315 233 spigot; #X msg 316 189 0; #X msg 348 189 1; #X obj 361 295 f; #X obj 316 356 tabread $0-envCurve; #X obj 345 441 f; #X obj 316 257 t f f; #X obj 361 271 b; #X obj 316 294 / 100; #X obj 410 274 - 1; #X obj 159 384 <=; #X obj 316 411 sel 1; #X obj 361 320 t f f f; #X obj 204 319 t f f f; #X obj 53 114 sel 0; #X msg 60 228 0; #X obj 237 142 moses 1; #X obj 316 385 <=; #X obj 62 138 moses 100; #X msg 84 249 100; #X obj 152 113 sel 1; #X obj 23 204 f; #X obj 152 137 t b b b; #X text 237 19 Finds the input sustain value in the envelope; #X obj 28 55 f; #X obj 143 54 t b f; #X obj 28 31 change; #X obj 143 30 change; #X obj 155 77 f; #X obj 28 83 t f f b; #X text 238 36 curve table , and outputs the index of it.; #X connect 0 0 27 0; #X connect 1 0 0 1; #X connect 2 0 24 0; #X connect 3 0 40 0; #X connect 5 0 4 0; #X connect 6 0 41 0; #X connect 7 0 0 0; #X connect 7 1 9 0; #X connect 8 0 0 0; #X connect 9 0 24 1; #X connect 10 0 5 0; #X connect 10 1 8 0; #X connect 11 0 7 0; #X connect 12 0 11 1; #X connect 13 0 11 1; #X connect 14 0 20 0; #X connect 15 0 14 1; #X connect 16 0 14 1; #X connect 17 0 26 0; #X connect 18 0 31 0; #X connect 19 0 4 0; #X connect 20 0 17 0; #X connect 20 1 22 0; #X connect 21 0 17 0; #X connect 22 0 31 1; #X connect 23 0 17 1; #X connect 24 0 10 0; #X connect 25 0 19 0; #X connect 25 1 21 0; #X connect 26 0 18 0; #X connect 26 1 19 1; #X connect 26 2 23 0; #X connect 27 0 2 0; #X connect 27 1 5 1; #X connect 27 2 1 0; #X connect 28 0 29 0; #X connect 28 1 32 0; #X connect 29 0 4 0; #X connect 30 0 13 0; #X connect 30 0 15 0; #X connect 30 1 16 0; #X connect 30 1 12 0; #X connect 31 0 25 0; #X connect 32 0 11 0; #X connect 32 0 14 0; #X connect 32 1 33 0; #X connect 33 0 4 0; #X connect 34 0 36 0; #X connect 34 1 30 0; #X connect 35 0 4 0; #X connect 36 0 35 0; #X connect 36 1 12 0; #X connect 36 2 15 0; #X connect 38 0 43 0; #X connect 39 0 38 0; #X connect 39 1 42 1; #X connect 40 0 38 0; #X connect 41 0 39 0; #X connect 42 0 34 0; #X connect 43 0 35 1; #X connect 43 1 28 0; #X connect 43 2 42 0; #X restore 334 146 pd correctSustain; #X connect 0 0 2 0; #X connect 2 0 54 0; #X connect 2 1 31 0; #X connect 3 0 4 0; #X connect 4 0 13 0; #X connect 5 0 3 0; #X connect 5 0 33 0; #X connect 12 0 27 0; #X connect 13 0 12 0; #X connect 14 0 7 0; #X connect 15 0 3 1; #X connect 15 0 42 1; #X connect 16 0 13 1; #X connect 17 0 60 0; #X connect 18 0 26 1; #X connect 18 0 33 1; #X connect 24 0 45 0; #X connect 26 0 12 0; #X connect 27 0 14 0; #X connect 28 0 25 0; #X connect 30 0 29 0; #X connect 31 0 3 0; #X connect 31 0 42 0; #X connect 31 1 24 0; #X connect 31 2 30 0; #X connect 32 0 33 0; #X connect 32 1 26 0; #X connect 33 0 34 0; #X connect 34 0 25 0; #X connect 39 0 24 1; #X connect 40 0 59 0; #X connect 41 0 50 0; #X connect 42 0 12 0; #X connect 44 0 14 1; #X connect 48 0 40 0; #X connect 48 0 60 1; #X connect 50 0 40 0; #X connect 54 0 32 0; #X connect 54 1 5 0; #X connect 60 0 4 1;
plain text document attachment (multiCurveAdsr-help.pd) #N canvas 158 75 478 554 10; #N canvas 0 22 458 308 (subpatch) 0; #X array envelope 10000 float 2; #X coords 0 1 10000 0 400 140 1; #X restore 22 180 graph; #X obj 304 -173 loadbang; #X obj 138 -30 nbx 5 14 0 100 0 1 empty empty Level 0 -8 0 10 -262144 -1 -1 1 256; #X obj 170 -1 nbx 5 14 0 3000 0 1 empty empty A 0 -8 0 10 -262144 -1 -1 60 256; #X obj 200 30 nbx 5 14 0 2000 0 1 empty empty D 0 -8 0 10 -262144 -1 -1 20 256; #X obj 232 60 nbx 5 14 0 100 0 1 empty empty S 0 -8 0 10 -262144 -1 -1 50 256; #X obj 262 89 nbx 5 14 0 100 0 1 empty empty R 0 -8 0 10 -262144 -1 -1 79 256; #X msg 304 -147 ; pd dsp 1; #X obj 41 -177 bng 15 250 50 0 empty empty empty 0 -6 0 10 -262144 -1 -1; #X msg 80 -41 0; #X obj 80 -65 delay 200; #X obj 131 -88 nbx 5 14 -1e+37 1e+37 0 1 empty empty hold_time 0 -6 0 10 -262144 -1 -1 138 256; #X msg 41 -41 1; #X obj 96 153 tabwrite~ envelope; #X obj 311 122 nbx 5 14 0 20 0 1 empty empty curve_factor 0 -6 0 10 -262144 -1 -1 1 256; #X obj 106 -185 notein; #X obj 106 -162 sel 0; #X obj 41 -159 t b b; #X obj 41 -4 t f b; #X obj 133 -139 t b f; #X obj 212 -97 / 127; #X obj 12 -201 loadbang; #X text 91 -208 Hit bang or MIDI key to see current envelope; #X text 293 -79 Curve Factors; #X text 240 -47 1 - linear; #X text 229 -32 > 1 - exponential (fat) curves , varying with C; #X obj 110 124 multiCurveAdsr 0.98 10 20 99 20; #X floatatom 316 159 5 0 0 0 - - -; #X text 350 155 for switch~ing parent; #X text 229 -62 < 1 - "quartic-like" (hollow) curve , C=-0.214; #X connect 1 0 7 0; #X connect 2 0 26 1; #X connect 3 0 26 2; #X connect 4 0 26 3; #X connect 5 0 26 4; #X connect 6 0 26 5; #X connect 8 0 17 0; #X connect 9 0 26 0; #X connect 10 0 9 0; #X connect 11 0 10 1; #X connect 12 0 18 0; #X connect 14 0 26 6; #X connect 15 1 16 0; #X connect 16 0 9 0; #X connect 16 1 19 0; #X connect 17 0 12 0; #X connect 17 1 10 0; #X connect 18 0 26 0; #X connect 18 1 13 0; #X connect 19 0 12 0; #X connect 19 1 20 0; #X connect 20 0 2 0; #X connect 21 0 17 0; #X connect 26 0 13 0; #X connect 26 1 27 0;
PD-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
___________________________________________________________ Der frühe Vogel fängt den Wurm. Hier gelangen Sie zum neuen Yahoo! Mail: http://mail.yahoo.de
Hi Roman,
It would be pretty easy to modify this to have a separate C (curve) parameter for attack and decay/release (or even separate C's for decay and release as well, if one were so inclined). I considered doing this, but didn't do it for the selfish reason that my envelope UI's are getting pretty cluttered as it is! Maybe I could do a thing where if you didn't specify values for C(decay) and C(release), they'd be equal to C(attack) by default.
The quartic(ish) curve I use for C of < 1 actually sounds pretty good for attack, actually. It is thinner and sharper for fast values of A, and has a nice, natural rise for slower attacks. I like using the "fatter" (C > 1) envelopes for contrast; they carry a lot more energy under the curve. Poor old linear sounds pretty boring, but it comes in handy as a reference.
Thanks for writing, Roman.
Phil
Roman Haefeli wrote:
cool work! thanks for sharing it!
personally, i like a logarithmic curve the most for decay and release (this is also, how decays happen to be in nature [e.g a bell]), though otoh, a logarithmic curve doesn't make much sense for attack, if applied to the amplitude (nothing happens for a long period and then suddenly the sound comes). how about using a separate c parameter for the attack, so that one could have fat (for attack) and hollow (for decay) at the same time?
roman
Hallo, Phil Stone hat gesagt: // Phil Stone wrote:
It would be pretty easy to modify this to have a separate C (curve) parameter for attack and decay/release (or even separate C's for decay and release as well, if one were so inclined).
Actually I believe that it's not that easy at all, if you want to get retriggered envelopes right. If you need to enter a release phase with a concave curve, while your still in an attacke phase with a convex curve, it's tricky to do this in a clickless way
Frank Barknecht _ ______footils.org_ __goto10.org__
You're right, Frank. I was just working on this, and as I wrote in a separate post, I gave up. You need independent [vline~]s, and matching up endpoints becomes extremely tricky.
Phil
Frank Barknecht wrote:
Hallo, Phil Stone hat gesagt: // Phil Stone wrote:
It would be pretty easy to modify this to have a separate C (curve) parameter for attack and decay/release (or even separate C's for decay and release as well, if one were so inclined).
Actually I believe that it's not that easy at all, if you want to get retriggered envelopes right. If you need to enter a release phase with a concave curve, while your still in an attacke phase with a convex curve, it's tricky to do this in a clickless way
Ciao
Frank Barknecht wrote:
Hallo, Phil Stone hat gesagt: // Phil Stone wrote:
It would be pretty easy to modify this to have a separate C (curve) parameter for attack and decay/release (or even separate C's for decay and release as well, if one were so inclined).
Actually I believe that it's not that easy at all, if you want to get retriggered envelopes right. If you need to enter a release phase with a concave curve, while your still in an attacke phase with a convex curve, it's tricky to do this in a clickless way
Ciao
Agreed, and given that an abstraction I made for something similar using fexpr~ used 20% of my CPU for just one instance, I went the C route and made my first DSP external, which is around 10 times faster.
Source code here:
https://devel.goto10.org/listing.php?repname=maximus&path=%2Fanalogue%2F...
It operates completely in the signal domain.
inlets: ~ trigger (rising edge triggers attack, falling edge triggers release) ~ attack time ~ peak level ~ decay time ~ sustain level ~ release time ~ threshold (when the output rises above the threshold (values just below 1 work best), the mode switches from attack to decay+sustain)
output: ~ curved envelope (true exponential decay shapes for all phases, as documented here: http://www.music.mcgill.ca/~gary/306/week11/envelopes.html )