code wiki / (root) / nx_audio_pan.nx

nx_audio_pan.nx source

↩ module page · 43 lines · 1518 B

1// nx_audio_pan.nx -- SOVEREIGN AUDIO ENGINE rung R2: stereo + constant-power pan. 2// 3// Places a mono source in the stereo field. Uses CONSTANT-POWER pan (gL^2+gR^2 4// ~= 1) so loudness is steady across the pan -- the law real engines use, baked as 5// a Q8 table (constants computed offline, no runtime trig). Mixes panned sources 6// additively into stereo L/R buses, clamped (reuses R0 ae_clamp). Continuous-pan 7// interpolation + sovereign trig come in a later rung. license_tier: ORIGINAL. 8 9import "nx_syscalls.nx" 10import "nx_audio_mix.nx" 11 12// 5 pan positions, constant-power, Q8 (256 = 1.0). gL^2+gR^2 ~= 65536 each row. 13// 0 hardL | 1 midL | 2 center | 3 midR | 4 hardR 14const AP_NPAN: i64 = 5 15func ap_gl(i: i64) -> i64 { 16 if i == 0 { return 256 } 17 if i == 1 { return 236 } 18 if i == 2 { return 181 } 19 if i == 3 { return 98 } 20 if i == 4 { return 0 } 21 return 181 22} 23func ap_gr(i: i64) -> i64 { 24 if i == 0 { return 0 } 25 if i == 1 { return 98 } 26 if i == 2 { return 181 } 27 if i == 3 { return 236 } 28 if i == 4 { return 256 } 29 return 181 30} 31 32// pan a mono source (Q8 gain g, pan position p) ADDITIVELY into stereo outL/outR 33func ap_pan_into(inb: *i64, n: i64, g: i64, p: i64, outL: *i64, outR: *i64) -> i64 { 34 let gl: i64 = (g * ap_gl(p)) / 256 35 let gr: i64 = (g * ap_gr(p)) / 256 36 var i: i64 = 0 37 while i < n { 38 outL[i] = ae_clamp(outL[i] + (inb[i] * gl) / 256) 39 outR[i] = ae_clamp(outR[i] + (inb[i] * gr) / 256) 40 i = i + 1 41 } 42 return n 43}