Layering Sounds
A single sine wave is the plainest sound a speaker can make. It is fine for a tick and not much else.
A layer is another source that plays along with the first: a different wave shape, an octave up or down, a little quieter, and a few milliseconds late. Stack three or four and the note stops sounding like a test tone. Play the note below, then add layers.
Each bar is one layer on a timeline. Two things make the stack read as
one sound instead of several: the layers start within about 40ms of each
other, and each one is quieter than the one before it, from a gain of
0.08 down to 0.02. Push the spacing to 80ms and you start to hear
the seams.
Every layer should add something the others don't. Two copies of the same wave at the same pitch mostly just make it louder. A triangle adds softer harmonics, an octave up adds air, an octave down adds weight.
From chord to arpeggio
Layers don't have to share a pitch. This site's success sound is four
square waves on C, E, G, and C, each starting 60ms after the last.
Drag the spacing to hear where a chord turns into an arpeggio.
At 0ms all four notes land together, which is heavier than a
confirmation needs to be. Between 40ms and 80ms you hear one rising
gesture. Past 120ms it becomes a melody, and a cue that takes half a
second asks for more attention than a copy button deserves.
Mixing textures
Not every layer is a note. A short burst of filtered noise has no pitch, but it has an attack, and that is what makes a sound feel like something was pressed. Flip the switch with each texture selected.
The tone on its own is a beep. The noise on its own is a tap. Together
they make a click with a pitch. The noise layer is under 30ms long and
passes through a bandpass filter at 2600Hz, so it adds edge without
hiss.
Usage
import { definePatch } from "@web-kits/audio";
export const patch = definePatch({
name: "ui",
sounds: {
// one note, three layers
note: {
layers: [
{
source: { type: "sine", frequency: 523 },
envelope: { attack: 0.002, decay: 0.09, sustain: 0, release: 0.03 },
gain: 0.08,
},
{
source: { type: "triangle", frequency: 523 },
envelope: { attack: 0.002, decay: 0.09, sustain: 0, release: 0.03 },
gain: 0.05,
delay: 0.04,
},
{
source: { type: "noise", color: "white" },
filter: { type: "bandpass", frequency: 2600 },
envelope: { attack: 0, decay: 0.018, sustain: 0, release: 0.01 },
gain: 0.06,
},
],
},
},
});
// patch.play("note") from a click handlerBuild one layer at a time. Get the first one right on its own, then add the next at a lower gain and keep it only if you can hear what it adds. If muting a layer changes nothing, delete it.
Resources
@web-kits/audio - Raphael Salaja's synth library, where layers, envelopes, and delays are plain objects.
Retro patch - The 8-bit patch this site's success sound is adapted from.
OscillatorNode - The sine, square, sawtooth, and triangle waves behind every pitched layer.
BiquadFilterNode - The bandpass filter that turns white noise into a short tap.
Learning Synths - Ableton's hands-on intro to oscillators, envelopes, and filters.