Envelopes
Shaping the amplitude contour of a signal is a common need and the envelope functions are there to help you with that. Of these, perhaps the most useful is adsr which can be live controlled in addition to being of a pre-determined shape and duration.
Synth.line — Functionline(v1 :: Real, duration_secs :: Real, v2 :: Real)Makes a signal that produces v1 for t < 0.0 and v2 for t > duration_secs. In between the two times, it produces a linearly varying value between v1 and v2. This signal is infinite in extent. Use clip to limit its extent.
Synth.expon — Functionexpon(v1 :: Real, duration_secs :: Real, v2 :: Real)Similar to line, but does exponential interpolation from v1 to v2 over duration_secs. Note that both values must be > 0.0 for this to be valid. The resultant signal is infinite in extent. Use clip to limit its extent.
Synth.adsr — Functionadsr(suslevel :: Real, sus_secs :: Real;
attack_factor = 2.0, attack_secs = 0.002,
decay_secs = 0.01, release_secs = 0.2)Makes an "attack-decay-sustain-release" envelope. The decay and release phases are treated as exponential and the others stay linear. The arguments are arranged such that mostly you specify the suslevel and sus_secs, which control the amplitude and duration of a note controlled by the ADSR. The rest are given defaults that you can change if needed.
suslevelis the sustain levelsus_secsis the duration of the sustain portionattack_factordetermines the peak of the attack and multiplies the sustain level.attack_secsis the duration of the linear attack portiondecay_secsis the duration of the exponential decay portion after the attack.release_secsis the "half life" of the release portion of the envelope.release_factoris the number of "releasesecs" it takes to drop the amplitude to 0. When the amplitude drops below 1/32767, the signal will stop. If we let the decay happen at a steady logarithmic pace of a factor of 2 every `releasesecs, it can take a full 3 seconds for it to stop even whenreleasesecs == 0.2. This can cause computational cost to go up because voices will remain alive for longer without actually being audible. So we accelerate the drop instead of using a steady logarithmic drop velocity, so that the signal will end within aboutreleasefactor * releasesecsafter release phase begins. Thisreleasefactordefaults to 4. This "acceleration" tends to 0 as thereleasefactorbecomes larger. So if you strictly want thereleasesecsto be the "half life" of the signal, set this factor to be 15.0. Setting it to any value above 15.0 will cause the signal to linger on and decay at a slower rate than indicated byrelease_secs`.
Synth.decay — Functiondecay(rate :: Signal)Produces a decaying exponential signal with a "half life" determined by 1/rate. It starts with 1.0. The signal includes a short attack at the start to prevent glitchy sounds.
Synth.follow — Functionfollow(s :: Signal, rate :: Signal)
follow(s :: Signal, rate :: Real)Follows a signal on the rise and decays on the fall. This means if the input signal is an impulse, then you'll get a series of exponential decays on each of the impulses.
Synth.Gen — TypeA "Gen" is a process for producing signals. The proc(::Gen,::AbstractBus,t) which returns Tuple{Float64,Gen} needs to be defined for a gen to be usable by the Bus.
The Gen returned by the proc call semantically replaces the gen that produced it. That way, we get recursive generation.