nx_audio_spatial.nx source
↩ module page · 34 lines · 1492 B
1// nx_audio_spatial.nx -- SOVEREIGN AUDIO ENGINE rung R6: 3D positional audio.
2//
3// Places a mono source at (sx,sy) relative to a listener at the origin: distance
4// drives a linear rolloff attenuation over max_dist, horizontal offset drives the
5// L/R balance. This is what makes game audio spatial (footsteps to your left,
6// etc.). Includes a sovereign integer sqrt (Newton's method). Reuses ae_clamp.
7// license_tier: ORIGINAL.
8
9import "nx_syscalls.nx"
10import "nx_audio_mix.nx"
11import "nx_isqrt.nx" // CANONICAL integer sqrt -- removed a local Newton duplicate (DRY)
12
13// place mono[0..n) at (sx,sy) into stereo outL/outR; atten by distance, pan by sx
14func spatial_place(mono: *i64, n: i64, sx: i64, sy: i64, max_dist: i64, outL: *i64, outR: *i64) -> i64 {
15 let d: i64 = nx_isqrt(sx * sx + sy * sy)
16 var atten: i64 = 0 // Q8 distance gain
17 if d < max_dist { atten = ((max_dist - d) * 256) / max_dist }
18 var gl: i64 = 128 // Q8 L/R balance (centered default)
19 var gr: i64 = 128
20 if d > 0 {
21 let frac: i64 = (sx * 256) / d // -256..256 (left..right)
22 gr = (frac + 256) / 2 // 0..256
23 gl = 256 - gr
24 }
25 let fl: i64 = (atten * gl) / 256
26 let fr: i64 = (atten * gr) / 256
27 var i: i64 = 0
28 while i < n {
29 outL[i] = ae_clamp((mono[i] * fl) / 256)
30 outR[i] = ae_clamp((mono[i] * fr) / 256)
31 i = i + 1
32 }
33 return n
34}