Expand description
A parametric sound-effect generator in the style of the synth
module. Requires the sfx feature, which enables synth.
An Effect is a small set of numbers: a waveform, a pitch with slides, vibrato
and an arpeggio step, an envelope with punch, a duty sweep, swept low- and
high-pass filters, a repeat period and a volume. It renders deterministically
into mono Audio, reads and writes a short text form, and can be drawn from a
seed by a Preset.
use audiobox::sfx::{Effect, Preset};
let coin: Effect = "wave=pulse duty=50 frequency=1046.5 sustain=0.04 punch=0.5
decay=0.25 arpeggio=5 arpeggio-time=0.06".parse()?;
let audio = coin.render(44_100)?;
assert_eq!(audio.frames(), 12_789);
// Try seeds until one sounds right, then keep its text.
let jump = Effect::preset(Preset::Jump, 7);
assert_eq!(jump.to_string().parse::<Effect>()?, jump);§Parameters and text form
The text form is whitespace-separated key=value pairs, in any order, on one
line or several; ; starts a comment that runs to the end of the line. Missing
keys keep their defaults. Effect’s Display writes the same form, and
parsing it gives back an equal effect: numbers are written in Rust’s shortest
form that reads back to the same f64.
| Key | Field | Unit | Range | Default |
|---|---|---|---|---|
wave | waveform | pulse, triangle, saw, noise | pulse | |
duty | waveform | pulse duty in percent | 12.5, 25, 50, 75 | 50 |
noise | waveform | noise mode | long, short | long |
frequency | frequency | Hz | 10..=20000 | 440 |
slide | slide | octaves per second | -64..=64 | 0 |
slide-change | slide_change | octaves per second, per second | -256..=256 | 0 |
vibrato-depth | vibrato_depth | semitones | 0..=24 | 0 |
vibrato-speed | vibrato_speed | Hz | 0..=100 | 0 |
attack | attack | seconds | 0..=10 | 0 |
sustain | sustain | seconds | 0..=10 | 0.1 |
punch | punch | extra level at the start of the sustain | 0..=1 | 0 |
decay | decay | seconds | 0..=10 | 0.2 |
duty-sweep | duty_sweep | duty change per second (pulse only) | -10..=10 | 0 |
low-pass | low_pass | cutoff in Hz, 0 for off | 0 or 10..=20000 | 0 |
low-pass-sweep | low_pass_sweep | octaves per second | -16..=16 | 0 |
high-pass | high_pass | cutoff in Hz, 0 for off | 0 or 10..=20000 | 0 |
high-pass-sweep | high_pass_sweep | octaves per second | -16..=16 | 0 |
arpeggio | arpeggio | semitones | -48..=48 | 0 |
arpeggio-time | arpeggio_time | seconds | 0..=10 | 0 |
repeat | repeat | seconds, 0 for off | 0 or 0.01..=10 | 0 |
volume | volume | linear | 0..=1 | 0.5 |
attack + sustain + decay is the effect’s duration. It must be more than 0 and
at most MAX_DURATION seconds. Values out of range, and duty or duty-sweep
without a pulse or noise without noise, are rejected with
ErrorCode::InvalidArgument; in text, the error is a
ParseError with the line and column of the value.
§Sound
At time t seconds since the start, or since the last repeat, the frequency is
frequency × 2^(slide·t + slide_change·t²/2), raised by arpeggio semitones once
t ≥ arpeggio_time, and modulated by a vibrato of vibrato_depth semitones at
vibrato_speed Hz. It is limited to 0..=sample_rate / 2. The pulse duty starts at
duty and changes by duty_sweep per second, limited to 1..=99%. Noise uses the
synthesizer’s shift register, clocked at 93 times the frequency.
repeat restarts the pitch, slides, arpeggio and duty every repeat seconds;
the envelope, the vibrato and the filters continue.
The envelope rises linearly from 0 to 1 over attack, then holds for sustain
starting at 1 + punch and falling linearly to 1, then falls linearly to 0 over
decay. Each stage is rounded to whole samples, so an effect lasts
round(attack·rate) + round(sustain·rate) + round(decay·rate) frames. The output
is the filtered oscillator times the envelope times volume, so it peaks at
volume × (1 + punch).
Both filters are 2-pole (12 dB per octave) Butterworth state-variable filters: the low-pass passes frequencies below its cutoff and the high-pass those above, and each attenuates its cutoff by 3 dB. A sweep moves a cutoff by that many octaves per second from the start of the effect, within 10 Hz..=0.45 × the sample rate.
Like the synthesizer, rendering uses only basic IEEE arithmetic and the crate’s own
series for 2^x, sine and tangent, so an effect gives the same samples on every
platform.
Re-exports§
pub use crate::synth::ParseError;
Structs§
- Effect
- The parameters of a sound effect. See the module documentation for their units, ranges and meaning.
Enums§
- Preset
- Kinds of effect that
Effect::presetdraws from a seed.
Constants§
- MAX_
DURATION - The longest effect, in seconds.