Tutorials

Building Synth Voices

Now that you know oscillators and filters, let's combine them into complete synthesizer voices with amplitude envelopes.

Now that you know oscillators and filters, let’s combine them into complete synthesizer voices with amplitude envelopes.

The Problem with Raw Oscillators

A raw oscillator plays constantly:

osc("saw", 220) |> out(%, %)

For musical notes, we need the sound to start and stop - that’s what envelopes do.

Attack-Release Envelopes

The ar envelope creates a simple shape triggered by a clock:

// Envelope only (no sound)
ar(trigger(2)) |> out(%, %)

Multiply your oscillator by the envelope:

// Plucky synth - envelope controls volume
osc("saw", 220) * ar(trigger(2)) |> out(%, %)

Shaping the Envelope

The ar function takes attack and release times:

// Fast attack, short release - percussive
osc("saw", 220) * ar(trigger(4), 0.001, 0.1) |> out(%, %)
// Slow attack, long release - pad-like
osc("saw", 220) * ar(trigger(1), 0.3, 1.0) |> out(%, %)

A Complete Synth Voice

Combine oscillator, filter, and envelope:

// Classic subtractive synth
osc("saw", 110)
    |> lp(%, 800)
    * ar(trigger(2), 0.01, 0.3)
    |> out(%, %)

Filter Envelope

Make the filter open and close with each note:

// Filter follows its own envelope
osc("saw", 110)
    |> lp(%, 200 + ar(trigger(2), 0.01, 0.2) * 2000)
    * ar(trigger(2), 0.01, 0.5)
    |> out(%, %)

Layering Oscillators

Combine multiple oscillators for richer sounds:

// Two detuned saws
(osc("saw", 110) + osc("saw", 110.5)) * 0.5
    |> lp(%, 1000)
    * ar(trigger(2))
    |> out(%, %)
// Octave layering
(osc("saw", 110) + osc("saw", 220) * 0.5) * 0.5
    |> moog(%, 600, 2)
    * ar(trigger(2))
    |> out(%, %)

Adding Sub Bass

Layer a sine wave an octave below for weight:

// Main oscillator plus sub
osc = osc("saw", 110) + osc("sin", 55) * 0.5
osc |> lp(%, 800) * ar(trigger(2)) |> out(%, %)

ADSR Envelopes

For more control, use adsr with attack, decay, sustain, and release:

// Sustained pad with ADSR
osc("saw", 220) * adsr(trigger(0.5), 0.1, 0.2) |> out(%, %)

Building a Bass Patch

Let’s build a complete bass sound:

// Punchy bass
bass_freq = 55
filter_env = ar(trigger(2), 0.01, 0.15)
amp_env = ar(trigger(2), 0.005, 0.3)

osc("saw", bass_freq)
    |> moog(%, 200 + filter_env * 1500, 2)
    * amp_env
    |> saturate(%, 2)
    |> out(%, %)

Building a Lead Patch

A bright, cutting lead sound:

// Screaming lead
lead_freq = 440
(osc("saw", lead_freq) + osc("sqr", lead_freq) * 0.3)
    |> lp(%, 2000 + ar(trigger(4)) * 3000, 4)
    * ar(trigger(4), 0.01, 0.2)
    |> out(%, %)

Storing Voices as Variables

Keep your patches organized:

// Define the voice
synth = osc("saw", 220) |> lp(%, 800) * ar(trigger(2))

// Use it
synth |> out(%, %)

Next Steps

You now know the fundamentals of synthesis! Continue to:

You’re making real synthesizer sounds with Akkado!