acron.audiospace

Runtime acoustic space over baked sources.

A game whose sounds are baked WAVs (acron.dsp.WavBakeCache) cannot change its reverb at runtime — the room is convolved into the samples. What it CAN do is bake each looping source once per acoustic zone (a dry stem plus per-zone wet stems, all playing in sync) and move the gains: entering a new zone crossfades the wet stems while the dry level eases to the zone’s own. This module is that mechanism — zones, one shared fade clock, an equal-power law, changed-only gain writes — and nothing else: zone geometry, stem baking, levels and sound design are the game’s.

The law: a gain moving g0 -> g1 over progress x follows

g(x) = sqrt(g0^2 + (g1^2 - g0^2) * sin^2(x * pi/2))

which keeps summed power constant across a complementary pair (the outgoing and incoming wet stems of the same source), is monotone for a lone gain, and holds a constant target perfectly still. A set_zone mid-fade captures the current gains as the new start — the fade chases, never jumps.

Gains leave through sink(voice_id, bank, gain) — bank is the zone id of a wet stem or DRY — which a game binds to its player handles’ set_volume. Each voice’s gains are stated once on the first AudioSpace.tick() after it is added, then written only when they change, so an idle space costs comparisons.

One-shots route positionally through the existing machinery: SpatialOneshots picks the current zone’s variant of a one-shot and plays it through acron.audio.SoundBank.play_3d().

AudioSpace(*[, fade_s, sink])

Zone-crossfaded gains for baked dry/wet stems, on one fade clock.

SpatialOneshots(bank, space)

One-shots routed by zone and played positionally.

Global Functions

equal_power(g0: float, g1: float, x: float) → float

The constant-power gain path from g0 to g1 at progress x.