Synthesis and effects

Make sound from nothing with oscillators, noise, envelopes and drums, then shape it with filters, echo and reverb.

On this page

Sounds are made from code, with no samples to download or license. Generators return mono buffers at a known level, so they mix predictably.

Oscillators and notes

audioFreq turns a note name or MIDI number into Hz (A4 is 440). audioOsc makes a tone. sine, saw, square and triangle are band limited, so they do not alias; pulse is the naive digital pulse that arcade chips used, and width picks the duty cycle (0.125, 0.25 and 0.5 are the classic ones).

note = audioOsc( shape="saw", freq=audioFreq( "A3" ), seconds=1 );     // 220 Hz
sub  = audioOsc( shape="sine", freq=audioFreq( 33 ), seconds=1 );      // MIDI 33 is A1
nes  = audioOsc( shape="pulse", freq=audioFreq( "C5" ), seconds=0.5, width=0.25 );

println( audioFreq( "A4" ) & " " & audioFreq( 60.1 ) );               // 440 and ten cents above C4
audioSave( audioMix( [ note, sub ] ), "tone.wav" );

audioOsc with shape="additive" takes partials, a list of [ multiple, amplitude ] pairs, for organs and bells.

Shape it

An envelope gives a tone a start and an end. audioEnvelope is a quick linear attack followed by an exponential decay, which is how plucks and drums behave. Filters take away the highs or lows.

pluck = audioOsc( "saw", audioFreq( "A1" ), 0.4 );
pluck = audioEnvelope( pluck, 0.003, 0.12 );               // attack 3 ms, decay time constant 120 ms
pluck = audioFilter( pluck, "lowpass", 900, 2 );           // darker, with a resonant edge
audioSave( pluck, "pluck.wav" );
FilterDoes
lowpassRemoves highs above the cutoff
highpassRemoves lows below the cutoff
bandpassKeeps a band around the cutoff
notchRemoves a narrow band around the cutoff

q sets the resonance: 0.7071 is flat, higher peaks at the cutoff, and for bandpass and notch it sets how narrow they are.

Noise, sweeps and drums

audioNoise is white, pink, brown or blue and repeatable with a seed. audioSweep glides between two pitches, the core of a kick or a laser. audioDrum makes kick, snare, hat, openhat, clap, tom, crash and riser.

kick  = audioDrum( type="kick", decay=0.9 );
snare = audioDrum( type="snare", seed=3 );
wind  = audioFade( audioNoise( seconds=3, color="pink", seed=7 ), 1, 1, "smooth" );
laser = audioSweep( 1800, 200, 0.25 );

Edit

FunctionDoes
audioGain( audio, db )Change the volume
audioPan( audio, pan )Place from -1 (left) to 1 (right) with a constant power law
audioFade( audio, fadeIn, fadeOut, curve )Fade in and out, linear or smooth
audioTrim( audio, start, end )Cut a section, in seconds
audioConcat( audios )Join buffers end to end
audioMix( audios )Play buffers at the same time
audioReverse( audio )Play it backwards
audioChannels( audio, n ) / audioResample( audio, rate )Convert mono and stereo, or the sample rate

Effects

Echo and reverb return a longer buffer so the tail rings out instead of being cut off. mix is a dry and wet balance from 0 to 1.

snare = audioChannels( audioDrum( type="snare" ), 2 );
echoed = audioDelay( audio=snare, time=0.28, feedback=0.45, mix=0.3, pingPong=true );
hall   = audioReverb( audio=echoed, room=0.7, damp=0.4, mix=0.25 );
wide   = audioChorus( audio=hall, rate=0.8, depth=0.003, mix=0.4 );
audioSave( audioSaturate( wide ), "snare-hall.wav" );

audioDelay repeats until they are 60 dB down, at most ten seconds, unless you give a tail. audioReverb is a Freeverb design: eight damped combs into four allpass filters with a stereo spread. A large room builds level on sustained sounds, so lower the mix. audioSaturate rounds off peaks with a tanh curve, a warm limiter for the final mix.

Where to go from here

The examples are complete pieces, each a single readable script. Timeline mixing puts sounds in time.

Edit this page Download Markdown Last updated Oct 16, 2026, 11:59:46 AM Report an issue