VOLTAlearn

Learn Volta / Write your own DSP

The effect declaration

Package a kernel as a named effect with live, addressable parameters.

lesson 35 of 39 · about 12 minutes

Open this lesson in the workbench →

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.

  1. Declare it: effect echo (…) on track = …
  2. Call it with a record: |> echo { feedback = 0.6 }
  3. 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.