music.adsr¶
- music.adsr(duration=2, attack_ms=20, decay_ms=20, sustain_level=-5, release_ms=50, transition='exp', alpha=1, db_dev=-80, to_zero_ms=1, number_of_samples=None, sonic_vector=0, sample_rate=None, **renamed)[source]¶
Synthesize an ADSR envelope.
ADSR (Attack, Decay, Sustain, Release) is a very traditional loudness envelope in sound synthesis [1].
- Parameters:
- durationscalar
The duration of the envelope in seconds.
- attack_msscalar
The duration of the Attack in milliseconds.
- decay_msscalar
The duration of the Decay in milliseconds.
- sustain_levelscalar
The Sustain level after the Decay in decibels. Usually negative.
- release_msscalar
The duration of the Release in milliseconds.
- transition
str “exp” or “exponential” for exponential transitions of amplitude (linear loudness); “lin” or “linear” for linear transitions of amplitude.
- alphascalar or array_like
An index to make the exponential fade slower or faster [1]. Ignored if transition=”linear” or alpha=1. One value for every stage, or three: for the Attack, the Decay and the Release.
- db_devscalar or array_like
The decibels deviation to reach before using a linear fade to reach zero amplitude. One value for both, or two: for the Attack and the Release. Ignored if transition=”linear”.
- to_zero_msscalar or array_like
The duration in milliseconds for linearly departing from zero in the Attack and reaching the value of zero at the end of the Release. One value for both, or two: for the Attack and the Release. Longer than its stage, it is the whole stage. Ignored if transition=”linear”.
- number_of_samples
integerorNone The number of samples of the envelope. If given, duration is ignored, and zero is an envelope of no samples.
- sonic_vectorarray_like
Samples for the ADSR envelope to be applied to: mono, or of shape
(nchannels, nsamples), every channel shaped alike. If supplied, duration and number_of_samples are ignored.- sample_rate
integerorNone The sample rate. None, the default, is the rate
music.get_sample_rate()returns.- **renamed
attack_duration,decay_duration,release_durationandto_zero, the names these milliseconds had before they said their unit among parameters in seconds, andenvelope_duration, whatdurationwas called before it took the name every other envelope gives it. Still accepted, with aDeprecationWarning.
- Returns:
ndarrayThe envelope, a value for each sample; or, when sonic_vector is given, the sound with the envelope applied to it.
- Raises:
ValueErrorIf transition is not one of the four names above. It is checked here because a stage of zero length never reaches
fade()orloud(), so an envelope of no stages accepted any name.If alpha holds other than one or three values, or db_dev or to_zero_ms other than one or two. The per-stage forms were documented since MASS and implemented in neither it nor here, so a sequence reached numpy as a broadcast error.
If alpha is negative and the transition exponential: it bends a transition from zero, where a negative power has no finite value, and the envelope came back holding infinity.
If a duration in milliseconds is negative. A negative attack, release or to_zero_ms was refused by
fade()in words about a percentage, and a negative decay made the envelope longer than it was asked to be.TypeErrorIf a keyword is neither a parameter nor one of the old names.
Notes
The envelope is the article’s
eq:adsr[1] in its exponential form. With \(\xi = 10^{d/20}\), the level db_dev names, and \(a_S = 10^{S/20}\), sustain_level’s, over the attack’s \(\Lambda_A\) samples, the decay’s \(\Lambda_D\) and the release’s \(\Lambda_R\), each bent by its alpha:\[ \begin{align}\begin{aligned}a_i = \xi^{\left(1 - \frac{i}{\Lambda_A - 1}\right)^{\alpha_A}}, \qquad a_{\Lambda_A + k} = a_S^{\left(\frac{k}{\Lambda_D - 1} \right)^{\alpha_D}},\\a_S \text{ while it sustains}, \qquad a_{\Lambda - \Lambda_R + k} = a_S \, \xi^{\left( \frac{k}{\Lambda_R - 1}\right)^{\alpha_R}}.\end{aligned}\end{align} \]At \(\alpha = 1\) the attack is the article’s \(\xi (1/\xi)^{i / (\Lambda_A - 1)}\). The sustain lasts what the other three stages leave, and they are shortened in proportion when they would outlast the envelope. Two things the article does not have: the release falls by \(\xi\) from the sustain level, as the MASS reference has it, where the article’s ends at \(\xi\) itself (DISCREPANCIES.md); and over the attack’s first to_zero_ms and the release’s last, a straight line meets zero, which an exponential never reaches.
transition="lin"makes each stage a straight line. Given a sonic_vector \(t\), it returns \(t_i a_i\) (eq:adsrApl).Cite the following article whenever you use this function.
References
[1]Fabbri, Renato, et al. “Musical elements in the discrete-time representation of sound.” arXiv preprint arXiv:abs/1412.6853 (2017)
Examples
>>> write_wav_mono(note_with_vibrato() * adsr()) >>> s = horizontal_stack(*[note_with_vibrato() * ... adsr(attack_ms=i, release_ms=j) ... for i, j in zip([6, 50, 300], [100, 10, 200])]) >>> s = horizontal_stack(*[adsr(attack_ms=i, release_ms=j, ... sonic_vector=note_with_vibrato()) ... for i, j in zip([6, 15, 100], [2, 2, 20])]) >>> envelope = adsr(duration=10, attack_ms=3e3, ... decay_ms=0, release_ms=5e3) >>> stereo = localize(note(duration=1)) >>> adsr(sonic_vector=stereo).shape == stereo.shape # each channel True >>> soft_attack = adsr(alpha=(3, 1, 1), to_zero_ms=(5, 1)) # per stage