Onda

Expressive and performant JIT-compiled audio programming language

Code example

A stereo subtractive synth with resonant filters and oversampled saturation

import std/filter
import std/osc
import std/pitch

proc Saturator:
  params:
    amount = 1.0

  sample 4:
    out1 = tanh(in1 * amount)

params:
  note = 45 {24, 84}
  cutoff = 1000.0 {80.0, 9000.0, log, "Hz"}
  resonance = 1.5 {0.5, 10.0}
  motion = 0.5 {0.0, 1.0}
  drive = 2.0 {1.0, 6.0}
  level = 0.5 {0.0, 1.0}

init:
  saw_a = std::osc::Saw()
  saw_b = std::osc::Saw()
  sub = std::osc::Square()
  lfo = std::osc::KSine(freq = 0.1)
  filter_l = std::filter::Svf()
  filter_r = std::filter::Svf()
  saturator_l = Saturator()
  saturator_r = Saturator()

block:
  freq = std::pitch::note_to_hz(f32(note))
  saw_a.freq = freq * 0.997
  saw_b.freq = freq * 1.503
  sub.freq = freq * 0.5

  movement = lfo() * 0.5 + 0.5
  max_cutoff = SAMPLE_RATE * 0.5
  cutoff_l = clamp(cutoff * (1.0 + movement * motion * 5.0), 40.0, max_cutoff)
  cutoff_r = clamp(cutoff * (1.0 + (1.0 - movement) * motion * 5.0), 40.0, max_cutoff)
  filter_l.update_coeffs(cutoff_l, resonance)
  filter_r.update_coeffs(cutoff_r, resonance)

  sample:
    bass = sub()
    a = saw_a()
    b = saw_b()
    left = filter_l(a * 0.6 + b * 0.2 + bass * 0.2)
    right = filter_r(a * 0.2 - b * 0.6 + bass * 0.2)
    out1 = saturator_l(left, amount = drive) * level
    out2 = saturator_r(right, amount = drive) * level
Open in playground