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.lineFunction
line(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.

source
Synth.exponFunction
expon(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.

source
Synth.adsrFunction
adsr(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.

  • suslevel is the sustain level
  • sus_secs is the duration of the sustain portion
  • attack_factor determines the peak of the attack and multiplies the sustain level.
  • attack_secs is the duration of the linear attack portion
  • decay_secs is the duration of the exponential decay portion after the attack.
  • release_secs is the "half life" of the release portion of the envelope.
  • release_factor is 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`.
source
Synth.decayFunction
decay(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.

source
Synth.followFunction
follow(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.

source
Synth.GenType

A "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.

source