synth
Eight ambience beds, synthesised from raw f32 PCM and baked into `.soundClip` assets. Nothing here reaches a network or spends a credit, so Ashbloom's soundscape stands whatever happens to a generation service.
ashbloom.sound.synth — the world's own noise, computed
Eight ambience beds, synthesised from raw f32 PCM and baked into .soundClip
assets. Nothing here reaches a network or spends a credit, so Ashbloom's
soundscape stands whatever happens to a generation service.
require("ashbloom.sound.synth").bakeAll() -- writes /source/ashbloom/sound/*.soundClip
Baking is idempotent — every clip is created with overwrite = true under a
stable name, so a re-bake replaces the payload and keeps the guid the scene
references. The generator is a fixed LCG seeded per bed, so the same call
produces the same bytes.
| clip | length | what it is |
|---|---|---|
ab_amb_wind | 12 s | three gusts of filtered noise at different lengths, with a whistle that only appears at the top of a gust |
ab_amb_ash | 10 s | dry granular hiss with eighteen grain-slips down a ripple face |
ab_amb_rain | 8 s | broadband hiss with 130 individual drops striking through it |
ab_sfx_drops | 6 s | 23 heavy first drops cratering dry ash — noise burst plus a low thud |
ab_sfx_channel | 8 s | bandpassed flow with 96 bubbles breaking in it |
ab_sfx_pool | 10 s | low lapping with fourteen drips falling into it |
ab_sfx_moths | 4 s | a wingbeat is amplitude modulation, not a tone: narrow noise chopped at 42 Hz |
ab_amb_bloom | 12 s | seven glassy partials, every one closing a whole number of cycles over the loop |
Every bed is a seamless loop, end to end
A .soundClip's loopStart / loopEnd are stored and read by no playback
surface, so the only loop the engine plays is the whole clip repeating — and any
step at the seam is heard once per period for the length of the film.
Two ways out of that, both used here:
M.loopifysynthesises the bed LONGER than it is kept and folds the extra tail back over the head with a 100 ms crossfade, so the last sample runs into the first without a step. This is what the noise beds use.- exact periodicity —
M.partialtakes a whole number of CYCLES over the loop rather than a frequency, so a tonal bed closes on itself with no crossfade at all.ab_amb_bloomis built entirely this way.
Codecs
The noise beds are stored as opus: a broadband seam is inaudible and the
payload is around twelve times smaller. ab_sfx_moths and ab_amb_bloom are
stored as pcm, because an opus clip loses its first few milliseconds on
decode and that IS audible as a tick in a sustained pad or a steady wingbeat.
Compression settings go inside opts.settings on asset.create — the same schema
clipRef:setSettings takes. A codec spelled at the top level of opts is refused,
and the refusal lists every creation parameter the type does accept.
The primitives
M.rng (deterministic), M.coeff (one-pole cutoff), M.loopify,
M.normalise, M.burst (decaying filtered noise — an impact, a splash, a grain
landing), M.bubble (a sine whose pitch sweeps as it decays — what makes running
water read as water rather than as hiss) and M.partial (an exactly-periodic
voice with tremolo).
Scoped to this part · feeds back into the world's score.