Unified · Split
| @@ -0,0 +1,79 @@ | ||
| 1 | +#+TITLE: Env | |
| 2 | +* Overview | |
| 3 | +This document describes =env=, a trigger based envelope | |
| 4 | +generator with adjustable attack, hold, and release times. | |
| 5 | +This envelope is produced by feeding a gate signal into | |
| 6 | +a smoothing filter. The output returns an exponetial | |
| 7 | +envelope with very nice-sounding curves: a convex rise, | |
| 8 | +and a concave fall. | |
| 9 | + | |
| 10 | +This sort of envelope is very ideal for percussive sounds | |
| 11 | +and for mimicking analogue synthesizers. The drawbacks | |
| 12 | +mainly have to do with precision. Attack and release | |
| 13 | +times are specified as time constants, which are a little | |
| 14 | +bit less intuitive than using seconds. The signal | |
| 15 | +generated is in range 0 to 1, but it will never reach 1 | |
| 16 | +exactly. | |
| 17 | +* Tangled Files | |
| 18 | +=env.c= and =env.h=, respectively. | |
| 19 | +* Components | |
| 20 | +** Timer | |
| 21 | +A timer is used to produce a gate signal of a particular | |
| 22 | +duration. This kicks on during the hold portion of | |
| 23 | +the signal. | |
| 24 | + | |
| 25 | +This timer is stored in a @!(ref "normalized_range" | |
| 26 | +"normalized range")!@, and is updated by a normalized | |
| 27 | +floating-point incrementor value. | |
| 28 | +** Filter | |
| 29 | +The filter used is a pretty typical | |
| 30 | +@!(ref "smoother" "one-pole lowpass filter")!@, but with | |
| 31 | +two parameters for the release and attack portions of | |
| 32 | +the envelope. | |
| 33 | +** State Management | |
| 34 | +The envelope has three main states: attack, hold, and | |
| 35 | +release. There is also a zero state to inidicate that | |
| 36 | +envelope is not playing anything. | |
| 37 | +** Previous Output | |
| 38 | +The output from the previous sample is stored. | |
| 39 | +* Parameters | |
| 40 | +** Attack Time (in tau units) | |
| 41 | +** Release Time (in tau units) | |
| 42 | +** Hold Time (in seconds) | |
| 43 | +* A Decent Epsilon Value | |
| 44 | +To break out of attack mode, and to have a clean silence | |
| 45 | +after release mode, a very small value known as an =epsilon= | |
| 46 | +will be used. This value should be small enough to be | |
| 47 | +perceptually perfect, and large enough to be numerically | |
| 48 | +stable. | |
| 49 | + | |
| 50 | +High-quality tends to be 24-bit, so anything less than | |
| 51 | +=1/2^24= can be ignored, which is roughly =5e-8= (rounded | |
| 52 | +down), which | |
| 53 | +I *think* should be reasonable enough for 32-bit | |
| 54 | +floating-point numbers. | |
| 55 | +* Computation | |
| 56 | +The envelope will wait for a trigger. A trigger at any | |
| 57 | +point will cause a retrigger. Some work will be done to | |
| 58 | +write in behavior that will prevent clicks from happening. | |
| 59 | + | |
| 60 | +When the trigger occurs, the state is set to attack, | |
| 61 | +and the gate signal is turned on. The attack time parameters | |
| 62 | +are updated at this point, and the filter is configured | |
| 63 | +to use the attack time parameters. | |
| 64 | + | |
| 65 | +In attack mode, the on-gate signal is put through the | |
| 66 | +filter. The output is checked to see if exceeds a threshold | |
| 67 | +reasonably close to 1. If it does, that value is held, | |
| 68 | +and the state is set to be hold mode. | |
| 69 | + | |
| 70 | +The timer is stored in a @!(ref "normalized_range" | |
| 71 | +"normalized range")!@, which allows the hold time to be | |
| 72 | +adjustable while it is in hold mode. During the period | |
| 73 | +in hold mode, the output signal will be the last returned | |
| 74 | +value of the attack envelope. | |
| 75 | + | |
| 76 | +When timer reaches the end, the envelope goes into release | |
| 77 | +mode. This is very similar to to attack mode, except that | |
| 78 | +it uses release time coefficients and the input | |
| 79 | +signal is a off-gate. | |