A hard clip makes sharp corners, and sharp corners are made of harmonics far above anything a 48 kHz stream can hold. Those that do not fit fold back down as aliases — inharmonic tones that do not follow the note. Builtin distortions fight this internally; your own law gets the same weapon with one word.
sig |> oversample 4 (process hard) runs the stage at four times the sample rate: the input is interpolated up, your law runs on four sub-samples, and a steep halfband filter removes everything above the original Nyquist before decimating back. The aliases that would have folded down are filtered away first.
Inside the stage sampleRate reads the oversampled rate, so a filter written against it keeps its cutoff. The price is CPU (the law runs 2, 4 or 8 times) and a little latency (31, 39 or 42 samples), which the engine compensates automatically.
Measured on a 6.13 kHz sine, a hard clip's alias power falls from −16.9 dB at 1× to −49.1 dB at 4× (reference/user-kernels, Oversampling). Play a high note: the difference is the difference between a tone and a tone plus a wrong melody underneath it.
The other weapon is antiderivative anti-aliasing (ADAA): output the average of the curve between the last input and this one instead of its value at this one. import "kernels" (adaaTanh) gives it to you for one cell of state; it stacks with oversampling.
The starting point#
The lesson opens with this song in the editor. Every edit recompiles and plays.
-- Oversampling: a hard clipper written as a law. Play the high notes —
-- listen for tones underneath that do not follow the melody.
hard = \x -> max (0.0 - 0.4) (min 0.4 (x * 3.0))
lead = patch {
source = saw (freq pitch) |> process hard,
ampEnv = adsr 5ms 150ms 0.6 120ms,
gain = vel * 0.2
}
high = play lead !"c6 eb6 g6 bb6 c7 bb6 g6 eb6"
What to watch#
Play the high notes and watch the spectrum between the harmonics: at 1× it is littered with bars that do not belong to the note; wrap the stage in oversample 4 and the gaps go quiet.
Goals#
The workbench checks these as you work; the solution is there when you want it.
- Wrap the clipper in
oversample 2,4or8 - Keep it your own: no builtin shaper
- Stretch: antiderivative anti-aliasing from
kernels
Make it yours#
Compare oversample 2, 4 and 8 on the top notes of the riff, then try adaaClip 0.4 at 1× and inside oversample 2. Which combination is clean enough that you stop hearing the aliases?
Further reading#
Write a custom audio processor in the reference.