code wiki / _hdl_build / nx_audio_enhance_gate.nx

nx_audio_enhance_gate.nx source

↩ module page · 81 lines · 4945 B

1// nx_audio_enhance_gate.nx -- proves + MEASURES sovereign audio enhancement (nx_audio_enhance), the bad-mic fix. 2// Native nx_cc->nxasm, no node. 3// 1) BAD MIC (AGC boost): a quiet signal is boosted toward the target level (capped), MEASURED 4// 2) limiter: a loud signal is brought down to target and NEVER clips (|out| <= FULL) 5// 3) NOISE GATE: background-noise frames between speech are attenuated; speech frames preserved, MEASURED 6// 4) silence safety (neg): pure silence isn't blown up into noise; speech isn't gated 7// license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_gate_emit_lib.nx" 10import "nx_audio_enhance.nx" 11import "nx_gate_verdict.nx" 12 13func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 14// a triangle wave of given peak amplitude into s[base..base+len) 15func fill_tri(s: *i64, base: i64, len: i64, peak: i64) -> i64 { 16 var i: i64 = 0 17 while i < len { let p: i64 = ((i % 16) - 8) * peak / 8; s[base + i] = p; i = i + 1 } 18 return 0 19} 20func maxabs(s: *i64, n: i64) -> i64 { var m: i64=0; var i: i64=0; while i<n { let a: i64=g_abs(s[i]); if a>m { m=a } i=i+1 } return m } 21 22func main() -> i64 { 23 g_puts("nx_audio_enhance gate (sovereign bad-mic AGC + noise gate, MEASURED)\n" as *u8) 24 var pass: i64 = 0; var total: i64 = 0 25 let TARGET: i64 = 6000 26 let MAXG: i64 = 800 // 8x max boost 27 let n: i64 = 768 28 let s: *i64 = sys_mmap(n*8) as *i64 29 30 // 1) BAD MIC: a quiet signal (peak ~800) boosted toward target 31 fill_tri(s, 0, n, 800) 32 let rms_in: i64 = ae_rms(s, n) 33 let g: i64 = ae_agc(s, n, TARGET, MAXG) 34 let rms_out: i64 = ae_rms(s, n) 35 g_puts(" [measure] bad mic: rms " as *u8); g_pn(rms_in); g_puts(" -> " as *u8); g_pn(rms_out); g_puts(" (gain x" as *u8); g_pn(g); g_puts("/100, target " as *u8); g_pn(TARGET); g_puts(")\n" as *u8) 36 pass = pass + g_check("AGC boosts a quiet bad mic (rms_out >> rms_in)" as *u8, rms_out > rms_in * 3); total=total+1 37 38 // 2) limiter: a loud signal -> down to ~target, never clips 39 fill_tri(s, 0, n, 30000) 40 ae_agc(s, n, TARGET, MAXG) 41 let mx: i64 = maxabs(s, n) 42 let rms_loud: i64 = ae_rms(s, n) 43 g_puts(" [measure] loud input: out rms=" as *u8); g_pn(rms_loud); g_puts(" peak=" as *u8); g_pn(mx); g_puts(" (<= 32767, no clip)\n" as *u8) 44 pass = pass + g_check("AGC attenuates loud + never clips" as *u8, (mx <= 32767) & (rms_loud < TARGET * 2)); total=total+1 45 46 // 3) NOISE GATE: noise frames (low) around speech frames (high) -> noise attenuated, speech kept 47 fill_tri(s, 0, 256, 300) // frames 0-3: background noise 48 fill_tri(s, 256, 256, 9000) // frames 4-7: speech 49 fill_tri(s, 512, 256, 300) // frames 8-11: background noise 50 let noise_before: i64 = ae_rms(s, 256) // first noise region 51 let speech_before: i64 = ae_rms(((s as i64) + 2048) as *i64, 256) 52 let gated: i64 = ae_noise_gate(s, n, 64, 4, 12) 53 let noise_after: i64 = ae_rms(s, 256) 54 let speech_after: i64 = ae_rms(((s as i64) + 2048) as *i64, 256) 55 g_puts(" [measure] noise region rms " as *u8); g_pn(noise_before); g_puts("->" as *u8); g_pn(noise_after); g_puts(" speech rms " as *u8); g_pn(speech_before); g_puts("->" as *u8); g_pn(speech_after); g_puts(" (frames gated=" as *u8); g_pn(gated); g_puts(")\n" as *u8) 56 var r3: i64 = 1 57 if noise_after * 3 > noise_before { r3 = 0 } // noise cut to < 1/3 58 if speech_after < speech_before - speech_before/8 { r3 = 0 } // speech preserved (within 12.5%) 59 pass = pass + g_check("noise gate: background attenuated, speech preserved" as *u8, r3); total=total+1 60 61 // 4) silence safety: all-zero -> AGC leaves it (no blowup); a pure-speech buffer is NOT gated 62 var i: i64 = 0; while i < n { s[i] = 0; i = i + 1 } 63 let gs: i64 = ae_agc(s, n, TARGET, MAXG) 64 var r4: i64 = 1 65 if gs != 100 { r4 = 0 } // silence -> gain 1.0, not max-boost-into-noise 66 if maxabs(s, n) != 0 { r4 = 0 } 67 fill_tri(s, 0, n, 9000) // uniform speech, no quiet frames 68 if ae_noise_gate(s, n, 64, 4, 12) != 0 { r4 = 0 } // nothing gated (all speech) 69 pass = pass + g_check("safety: silence not blown up; uniform speech not gated (neg)" as *u8, r4); total=total+1 70 71 g_puts("---- audio-enhance gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 72 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 73 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 74 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 75 let ctr__dry: *i64 = gv_ctr() 76 ctr__dry[0] = pass 77 ctr__dry[1] = total 78 let rc__dry: i64 = gv_verdict("AUDIO-ENHANCE-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 79 sys_exit(rc__dry) 80 return rc__dry 81}