An inline audioFx lambda works, but it is anonymous: nothing else can use it, and its numbers are frozen in the call. The effect declaration gives your processor a name, a documented parameter list with defaults, and a seat — and makes every parameter as live as a builtin's.
effect echo (seconds: Float = 0.375, feedback: Normalized = 0.5) on track = \bus -> bus |> process2 (echoLaw seconds feedback) [dline 1s] declares a track insert. The parameter list is a record with defaults: |> echo {} takes them all, |> echo { feedback = 0.7 } changes one.
on track makes a stereo insert for tracks, buses and the master; on voice makes a stage for a patch's source chain. @doc "…" above it becomes the hover text, just like a builtin's.
Every parameter is live. Pass a macro (echo { feedback = fb }) and the knob rides inside the kernel. Or address it by name from a scene: with { melody.echo.feedback = ramp 0.3 0.8 } — <track>.<effect>.<param> — with no macro declared at all.
Declare latency N (… on track latency 96 = …) when your effect delays its output: the mixer compensates for it like a builtin's. Put your effects in a file with no song and import them anywhere — that is how dsplib is built.
The starting point#
The lesson opens with this song in the editor. Every edit recompiles and plays.
-- The effect declaration: the echo works, but it is an anonymous lambda
-- with its numbers frozen inside the call. Name it.
echoLaw = \seconds fb x line ->
let delayed = dtapi line (floor (seconds * sampleRate)) in
[x + 0.4 * delayed, x + fb * delayed]
pluck = patch {
source = pulse (freq pitch) 0.3,
ampEnv = adsr 1ms 160ms 0 60ms,
gain = vel * 0.3
}
melody = play pluck !"e4 ~ g4 ~ b4 ~ ~ ~"
|> audioFx (\bus -> bus |> process2 (echoLaw 0.375 0.5) [dline 1s])
What to watch#
Run the scene and watch the scope's echo train: as the scene's ramp raises the feedback, the repeats stop dying away and start stacking.
Goals#
The workbench checks these as you work; the solution is there when you want it.
- Declare it:
effect echo (…) on track = … - Call it with a record:
|> echo { feedback = 0.6 } - Stretch: ride a parameter from a scene by its address
Make it yours#
Give your echo a second, on voice sibling that saturates each note before it reaches the track, and document both with @doc. Hover the call sites to see your docs.
Further reading#
Write a custom audio processor in the reference.