Add sound effects and ambience
Two kinds of sound, handled differently:
- Spot effects: one event on picture (a door creaks open, a cup is set down, a title pops). Cue to the frame.
- Ambience: a bed under a whole scene (birds in a garden, wind, city hum, room tone). Loops and crossfades, sits low, changes only at cuts.
If hn4a offers ElevenLabs' sound-effects model, realistic effects come from text
(elevenlabs-sound-effects, which checks). Otherwise pick a route per sound:
| Route | Use for | Cost | Realism |
|---|---|---|---|
| A. The person's own files (a library they license, recordings, downloads they have rights to) | Anything that must sound real: doors, footsteps, nature, crowds | Free to place | Best |
B. Sound baked into a generated shot (Veo 3.1, Seedance 2.5 <sound>, Kling v3 Background audio line, H3 Max soundscape) | Shots you are generating anyway; ambience and diegetic sound that should match the picture | Part of the shot's price | Good, but can't be re-mixed separately |
| C. Synthesized locally (numpy/scipy) | Graphics sounds (pops, whooshes, squashes), stylized or cartoony effects, simple beds (wind, rain, room tone, stylized birdsong, a creak) | Free | Stylized, not photoreal |
Ask which route when realism matters and it's unclear; don't present synthesized birds
or doors as real recordings. Route B: put the sound in that model's prompt grammar (load
its …-prompt-format leaf) and keep the shot's audio when splicing.
Place sounds against picture
- Cue spot effects from the picture: a 6 fps contact sheet of the moment, then frame-step.
Transients land about 10 ms before the visual contact. For composited graphics, read
cues from the compose spec instead (
python-synth-sfx-for-motion-graphics). - Pan toward where the source is in frame. Equal-power pan:
L*=sqrt((1-p)/2),R*=sqrt((1+p)/2); for movement, ramppin 10 ms slices. - Ambience: trim a seamless loop (crossfade the loop point over 0.5-1 s), run it under the whole scene, fade in/out over 0.3-1 s at scene edges, and change it only at cuts.
- Levels: dialogue first. Ambience about 18-25 dB under dialogue peaks; spot effects under or level with dialogue. Duck ambience 6-10 dB under speech if it fights.
- Mix: build the track in Python at 48 kHz stereo, normalize the peak to about -1 dBFS,
write
audio/sfx.wav, and either list it in a compose spec'saudio(with the original sound as another entry at lower volume if it stays) or mux with ffmpeg (-map 0:v -map 1:a -c:v copy -c:a aac). Final loudness for delivery is inguide-prepare-renders-for-delivery.
Route C recipes
Seed the noise generator so rebuilds match; butter(..., output='sos') + sosfilt.
- Pop, whoosh, squash, splat, thwack:
python-synth-sfx-for-motion-graphics. - Birdsong (stylized): a bird is a phrase of 3-7 chirps; a chirp is a sine whose
pitch glides between 2-6 kHz over 40-120 ms (
f0+(f1-f0)*(t/d)**0.7, optional 35 Hz trill of a few hundred Hz), shaped bysin(pi*t/d)**2, with 20-80 ms gaps. Schedule phrases at random (exponential gaps, ~1 per second), each with its own base pitch, pan in ±0.8 and gain 0.2-0.6. Add a short reverb or a little band-passed noise for air. Keep it well under dialogue. - Door creak (stick-slip): an impulse train whose rate glides (e.g. 40 to 140 Hz over 1-1.5 s) with ~25% wobble and jitter, exciting four narrow band-passes (~420, 960, 1750, 3100 Hz at gains 1, 0.7, 0.45, 0.2). Slower glide for a heavy door, higher bands for a small hinge. Add a low thud (60-90 Hz decaying) if it closes.
- Wind: noise band-passed 150-900 Hz, amplitude driven by noise low-passed under 2 Hz (gusts). Rain: dense random clicks (band-passed 2-8 kHz) over pink-ish noise. Room tone: brown noise low-passed at 400 Hz, very quiet.
- Things synthesis does badly: voices, crowds, music, footsteps on specific surfaces, anything the audience knows the real sound of up close. Use route A or B for those.
Check
- You can't hear. Measure what you can (
volumedetecton a silent span; peaks per cue) and put the result on a review page with each sound listed at its time in the row'sbody, and send the MP4 into the chat as well. Ask the person to listen; adjust gain, timing or the recipe from their notes and rebuild from the script (scripts/make_sfx.py), never by hand. - If the person wants real recordings and has none, say plainly that hn4a can't generate realistic effects yet and offer the routes above.


