Build a tone from individual sine-wave partials, then let their strengths and frequencies change independently.
Hear it and change it#
Listen for: a steady, hollow tone made by adding selected sine-wave partials. There is no filter removing the missing harmonics; they are absent from the recipe.
tempo = 120bpm
timingVersion = 2
drawbars = patch {
source = additive (freq pitch) [1, 0, 0.5, 0, 0.25],
ampEnv = adsr 8ms 0ms 0.8 100ms,
gain = vel * 0.25
}
play drawbars "c4 eb4 g4 bb4"
Make it yours: put 0.4 in the second slot. That adds the second harmonic, one octave above the fundamental. Additive synthesis lets those partials move independently, too.
What it is#
A live additive oscillator: a bank of sine partials summed live, where every partial's amplitude — and optionally its phase and frequency ratio — is its own control signal. The evolving counterpart of the wavetableOf table (Wavetable synthesis) — a wavetable bakes a fixed spectrum, additive lets each harmonic move while the note sounds.
Surface#
-- a fixed drawbar registration (static spectrum)
organ = additive (freq pitch) [const 1, const 0, const 0.7, const 1]
-- harmonics that breathe: each partial on its own LFO / envelope
swell = additive (freq pitch) [
const 1,
lfoSine @ 1/5c |> scale [0, 0.6],
adsr 300ms 400ms 0.3 300ms * 0.4,
]
-- per-partial phase offset: each entry is an [amp, phase] pair
hollow = additive (freq pitch) [[const 1, const 0], [const 0.5, const 0.25]]
-- inharmonic bank: [ratio, amp, phase?] — the Risset-bell surface
bell = additiveAt (freq pitch) [
[0.56, const 1 |> withDecay 1.6s],
[0.92, const 0.7 |> withDecay 1.2s],
[1.19, const 0.6 |> withDecay 0.9s],
]
-- Railsback stretch: bend a harmonic bank sharp in the top
epiano = additive (freq pitch) [const 1, const 0.6, const 0.4] |> inharmonic 0.0009
-- procedural spectra: a generator instead of an explicit list
sawish = additive (freq pitch) (sawSpectrum 64)
pw = macro 0.35 -- `width` is a builtin
pwm = additive (freq pitch) (pulseSpectrum 48 pw)
vox = additive (freq pitch) (formantSpectrum 96 [700Hz, 1100Hz, 2600Hz])
center = lfoSine @ 1/8c |> scale [1, 4] -- center in octaves
shep = additive (freq pitch) (gaussSpectrum 96 center 1.2)
-- per-partial drift: one oscillator → a choir
solina = additive (freq pitch) (sawSpectrum 48) |> ensemble 0.06
-- additive resynthesis: analyse a sample, replay it repitched
voice = additiveOf (sample "ah-vowel") (freq pitch)
additive : Sig Control Hz -> (Hole) -> Sig Audio Bipolar. The first argument is the fundamental frequency (freq pitch, plus any + nCents / + fm … terms — it routes exactly like an oscillator's freq port). The second argument is either:
- an explicit partial list —
1..=32entries, each an amplitude signal or an[amp, phase]pair (a mix is allowed; bare entries default phase to 0); or - a procedural spectrum generator (
sawSpectrum count,squareSpectrum,triangleSpectrum,pulseSpectrum count width,formantSpectrum count [Hz…],gaussSpectrum count center bw) —1..=512partials.pulseSpectrum'swidth,gaussSpectrum'scenterand itsbwall take a live control signal, so a Gaussian bump can wander and breathe at once.
additiveAt freq [[ratio, amp, phase?], …] is the inharmonic sibling (1..=64 partials). |> inharmonic B Railsback-stretches a harmonic bank; |> ensemble depth adds per-partial drift (the depth may be a live macro or control signal — the string machine's half of the Vintage/slop knob, see below); |> tuned [amount] snaps every partial's pitch class onto the ambient tuning's cents lattice — timbre matched to intonation, and the one post-op that also works on a spectrum generator (expanded to an explicit table) and on additiveOf (Match timbre to tuning); additiveOf (sample …) freq resynths a recording — either spelling of its sample slot, a bank string or an inline sample "…", at a fixed 48 partials (a compile-time constant with no surface port; a bounceOf/sampleOf/comp handle is not accepted here). Spectral morph is automatic: morph a b t of two explicit additive banks blends them per partial into one oscillator.
Showcase songs: examples/songs/additive.volta and examples/songs/additivepro.volta (extended synthesis examples).
Notes & limits#
- The old browser caps are gone with the Web Audio compat path — the engine renders full spectra and moving centres identically on every target.
- Explicit lists: ≤ 32 partials (
additive), ≤ 64 (additiveAt). Procedural spectra: ≤ 512 partials. - The recurrence is harmonic-only. Inharmonic banks (
additiveAt,|> inharmonic,|> ensemble) pay for a phase accumulator per partial. - Resynthesis is native-only and offline. A harmonic STFT analysis estimates the fundamental by autocorrelation and tracks
countharmonic amplitude/phase frames; there is no live microphone → additive (that would be a real-time phase vocoder). Analysis is currently per-voice on the first block — fine for held notes; repeating the analysis for many notes can increase processing cost. - Band-limiting is automatic and free everywhere: partials above Nyquist are not summed, and the native engine fades the top 15 % so a glide doesn't pop.