Yet another fix - please use this version.
I found a bug in the logic controlling the outlet designed to switch~ the parent patch; the delay for setting this outlet to zero (timed to coincide with the end of release) wasn't getting cleared on attack. So, on retriggers (i.e. new triggers before the former envelope completes), this flag was going '0' when it wasn't supposed to. I noticed this when I got into some heavy voice-stealing on my setup.
It should work fine now. I hope this is it for a while -- I should have been numbering these as beta-versions!
Phil Stone
P.S. Roman - I gave a shot at implementing independent curves for Attack and Decay/Release, but it was harder than I thought. Such a design would require multiple [vline~]s spliced correctly, which becomes much more complicated. I don't think its impossible, but pretty complex.
#N canvas 28 72 469 579 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 218 graph; #X obj 304 -173 loadbang; #X obj 136 -30 nbx 5 14 0 100 0 1 empty empty Level 0 -8 0 10 -262144 -1 -1 1 256; #X obj 169 -1 nbx 5 14 0 3000 0 1 empty empty A 0 -8 0 10 -262144 -1 -1 60 256; #X obj 199 30 nbx 5 14 0 2000 0 1 empty empty D 0 -8 0 10 -262144 -1 -1 20 256; #X obj 231 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 188 tabwrite~ envelope; #X obj 293 125 nbx 5 14 0 20 0 1 empty empty curve_factor 0 -6 0 10 -262144 -1 -1 0 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 159 multiCurveAdsr 0.98 10 20 99 20; #X floatatom 316 194 5 0 0 0 - - -; #X text 350 190 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;
#N canvas 507 117 673 600 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 199 stop; #X text 75 304 ATTACK; #X obj 240 525 outlet~; #X text 54 74 if zero; #X text 55 91 release; #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 113 182 s $0-activate; #X msg 110 158 1; #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 48 202 (*); #X text 388 53 < 1 - "quartic-like" (hollow) curve , C=-0.214; #N canvas 547 29 545 431 2571-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 178 60 484 586 correctSustain 1; #X obj 204 343 f; #X obj 252 343 + 1; #X obj 159 404 tabread $0-envCurve; #X obj 28 7 inlet sustain; #X obj 72 547 outlet correctedSustain; #X obj 188 489 f; #X obj 143 7 inlet curve; #X obj 159 305 t f f; #X obj 204 319 b; #X obj 159 342 / 100; #X obj 159 459 sel 0; #X obj 159 281 spigot; #X msg 160 237 0; #X msg 192 237 1; #X obj 315 282 spigot; #X msg 316 238 0; #X msg 348 238 1; #X obj 361 344 f; #X obj 316 405 tabread $0-envCurve; #X obj 345 490 f; #X obj 316 306 t f f; #X obj 361 320 b; #X obj 316 343 / 100; #X obj 410 323 - 1; #X obj 159 433 <=; #X obj 316 460 sel 1; #X obj 361 369 t f f f; #X obj 204 368 t f f f; #X obj 48 160 sel 0; #X msg 56 272 0; #X obj 237 191 moses 1; #X obj 316 434 <=; #X obj 62 187 moses 100; #X msg 84 298 100; #X obj 155 157 sel 1; #X obj 23 253 f; #X obj 155 186 t b b b; #X text 237 19 Finds the input sustain value in the envelope; #X obj 143 103 t b f; #X obj 28 79 change; #X obj 143 79 change; #X obj 155 128 f; #X obj 28 131 t f f b; #X text 238 36 curve table , and outputs the index of it.; #X obj 62 30 loadbang; #X obj 28 103 f 0; #X msg 62 52 -1; #X connect 0 0 27 0; #X connect 1 0 0 1; #X connect 2 0 24 0; #X connect 3 0 39 0; #X connect 5 0 4 0; #X connect 6 0 40 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 45 0; #X connect 38 1 41 1; #X connect 39 0 45 0; #X connect 40 0 38 0; #X connect 41 0 34 0; #X connect 42 0 35 1; #X connect 42 1 28 0; #X connect 42 2 41 0; #X connect 44 0 46 0; #X connect 45 0 42 0; #X connect 46 0 40 0; #X connect 46 0 39 0; #X restore 334 146 pd correctSustain; #X text 60 112 else attack; #X obj 66 132 t b b b b; #X text 35 394 (*) cancel any leftover delays ,; #X connect 0 0 2 0; #X connect 2 0 52 0; #X connect 2 1 58 0; #X connect 3 0 4 0; #X connect 4 0 12 0; #X connect 5 0 3 0; #X connect 5 0 31 0; #X connect 11 0 26 0; #X connect 12 0 11 0; #X connect 13 0 7 0; #X connect 14 0 3 1; #X connect 14 0 40 1; #X connect 15 0 12 1; #X connect 16 0 56 0; #X connect 17 0 25 1; #X connect 17 0 31 1; #X connect 23 0 43 0; #X connect 25 0 11 0; #X connect 26 0 13 0; #X connect 27 0 24 0; #X connect 29 0 28 0; #X connect 30 0 31 0; #X connect 30 1 25 0; #X connect 31 0 32 0; #X connect 32 0 24 0; #X connect 37 0 23 1; #X connect 38 0 55 0; #X connect 39 0 48 0; #X connect 40 0 11 0; #X connect 42 0 13 1; #X connect 46 0 38 0; #X connect 46 0 56 1; #X connect 48 0 38 0; #X connect 52 0 30 0; #X connect 52 1 5 0; #X connect 56 0 4 1; #X connect 58 0 3 0; #X connect 58 0 40 0; #X connect 58 1 23 0; #X connect 58 2 29 0; #X connect 58 3 5 0;