code wiki / _hdl_build / nx_ns.nx

nx_ns.nx source

↩ module page · 159 lines · 9368 B

1// nx_ns.nx -- R4b: sovereign single-channel Noise Suppressor (the other reserved nx_ns slot). 2// Integer 3-band Wiener-gain suppressor (NO-FLOAT). A moving-average filterbank splits the 3// signal into low / mid / high subbands (perfect reconstruction: low+mid+high == input); a 4// noise-only lead-in estimates per-band noise power; each frame attenuates a band by a Wiener 5// gain g = max(floor, (band_power - noise_power)/band_power). Bands dominated by noise (e.g. 6// broadband hiss in the high band where speech has little energy) collapse toward the floor; 7// speech-bearing bands pass -> noise down, speech preserved -> SNR up. 8// 9// MEASURED metric = SNR improvement: distance of the OUTPUT to the clean reference vs distance 10// of the NOISY INPUT to the clean reference. Negative control: gains forced to 1 (suppressor 11// OFF) -> output == input -> no improvement (the gains are load-bearing). 12// 13// HONEST SCOPE: in-band noise under speech is NOT removed (single-channel limit -- same as the 14// classic spectral-subtraction tradeoff); a perceptual/DNN suppressor + musical-noise control = 15// deeper rung. main() is the SELF-VALIDATING GATE. Evidence -> knowledge/status/ns.log. 16// license_tier: ORIGINAL 17import "nx_syscalls.nx" 18const NS_MAGIC_6000: i64 = 6000 19const NS_MAGIC_8000: i64 = 8000 20const NS_MAGIC_1500: i64 = 1500 21const NS_MAGIC_3000: i64 = 3000 22const NS_MAGIC_99991: i64 = 99991 23const NS_MAGIC_1103515245: i64 = 1103515245 24const NS_MAGIC_12345: i64 = 12345 25const NS_MAGIC_6001: i64 = 6001 26 27const NS_LOG: *u8 = "knowledge/status/ns.log" 28const QG: i64 = 12 // gain fixed-point (4096 = 1.0) 29const GFLOOR: i64 = 256 // minimum gain ~0.0625 (residual-noise floor, avoids musical noise) 30const FR: i64 = 256 // frame length 31 32func nw(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 33func nwn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(fd,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(fd,bb,k); return 0 } 34 35// causal moving average of window W into out 36func ma(x: *i64, out: *i64, N: i64, W: i64) -> i64 { 37 var run: i64=0; var i: i64=0 38 while i < N { 39 run = run + x[i] 40 if i >= W { run = run - x[i-W] } 41 var cnt: i64 = W; if i+1 < W { cnt = i+1 } 42 out[i] = run / cnt 43 i = i + 1 44 } 45 return 0 46} 47func powwin(a: *i64, start: i64, n: i64) -> i64 { var s: i64=0; var i: i64=start; while i<start+n { s=s+a[i]*a[i]; i=i+1 } return s } 48func powdiff(a: *i64, b: *i64, start: i64, n: i64) -> i64 { var s: i64=0; var i: i64=start; while i<start+n { let d: i64=a[i]-b[i]; s=s+d*d; i=i+1 } return s } 49func bandval(which: i64, L: i64, Lm: i64, xv: i64) -> i64 { if which==0 { return L } if which==1 { return Lm - L } return xv - Lm } 50 51// per-band Wiener gain from frame power vs noise power 52func wiener(fp: i64, np: i64) -> i64 { 53 if fp <= 0 { return GFLOOR } 54 var g: i64 = ((fp - np) * (1 << QG)) / fp 55 if g < GFLOOR { g = GFLOOR } 56 if g > (1 << QG) { g = 1 << QG } 57 return g 58} 59 60// suppress: x -> y, estimating noise over [0,P). enable=0 forces gains=1 (neg-control). 61func ns_run(x: *i64, y: *i64, L: *i64, Lm: *i64, N: i64, P: i64, enable: i64) -> i64 { 62 ma(x, L, N, 32) 63 ma(x, Lm, N, 8) 64 // per-band noise power over the noise-only lead-in 65 var np0: i64=0; var np1: i64=0; var np2: i64=0 66 var i: i64=0 67 while i < P { let b0: i64=bandval(0,L[i],Lm[i],x[i]); let b1: i64=bandval(1,L[i],Lm[i],x[i]); let b2: i64=bandval(2,L[i],Lm[i],x[i]); np0=np0+b0*b0; np1=np1+b1*b1; np2=np2+b2*b2; i=i+1 } 68 np0=np0/P; np1=np1/P; np2=np2/P 69 // process frame by frame 70 var f: i64=0 71 while f < N { 72 var flen: i64 = FR; if f+FR > N { flen = N - f } 73 // band frame powers 74 var fp0: i64=0; var fp1: i64=0; var fp2: i64=0 75 var j: i64=0 76 while j < flen { let ii: i64=f+j; let b0: i64=bandval(0,L[ii],Lm[ii],x[ii]); let b1: i64=bandval(1,L[ii],Lm[ii],x[ii]); let b2: i64=bandval(2,L[ii],Lm[ii],x[ii]); fp0=fp0+b0*b0; fp1=fp1+b1*b1; fp2=fp2+b2*b2; j=j+1 } 77 fp0=fp0/flen; fp1=fp1/flen; fp2=fp2/flen 78 var g0: i64 = 1<<QG; var g1: i64 = 1<<QG; var g2: i64 = 1<<QG 79 if enable==1 { g0=wiener(fp0,np0); g1=wiener(fp1,np1); g2=wiener(fp2,np2) } 80 j=0 81 while j < flen { let ii: i64=f+j; let b0: i64=bandval(0,L[ii],Lm[ii],x[ii]); let b1: i64=bandval(1,L[ii],Lm[ii],x[ii]); let b2: i64=bandval(2,L[ii],Lm[ii],x[ii]); y[ii] = (g0*b0 + g1*b1 + g2*b2) >> QG; j=j+1 } 82 f = f + FR 83 } 84 return 0 85} 86 87func tri(i: i64) -> i64 { let ph: i64=i % 256; if ph>=128 { return NS_MAGIC_6000 - (ph-128)*94 } return ph*94 - NS_MAGIC_6000 } 88 89func main() -> i64 { 90 let N: i64 = NS_MAGIC_8000 91 let P: i64 = NS_MAGIC_1500 // noise-only lead-in 92 let W0: i64 = NS_MAGIC_3000 // measurement window start (post lead-in + warmup) 93 let WN: i64 = N - W0 94 let cleanS: *i64 = sys_mmap(8*N) as *i64 95 let noise: *i64 = sys_mmap(8*N) as *i64 96 let x: *i64 = sys_mmap(8*N) as *i64 97 let y: *i64 = sys_mmap(8*N) as *i64 98 let L: *i64 = sys_mmap(8*N) as *i64 99 let Lm: *i64 = sys_mmap(8*N) as *i64 100 101 // clean speech = low-freq triangle (concentrated low/mid band); zero during the lead-in 102 var i: i64=0 103 while i < N { if i < P { cleanS[i]=0 } else { cleanS[i]=tri(i) } i=i+1 } 104 // noise = broadband white +-3000 (spreads across all bands incl high) 105 var seed: i64=NS_MAGIC_99991 106 i=0 107 while i < N { seed=(seed*NS_MAGIC_1103515245+NS_MAGIC_12345) & 0x7fffffff; noise[i]=((seed>>9) % NS_MAGIC_6001) - NS_MAGIC_3000; i=i+1 } 108 i=0; while i < N { x[i]=cleanS[i]+noise[i]; i=i+1 } 109 110 // --- ON: suppress --- 111 ns_run(x, y, L, Lm, N, P, 1) 112 let err_in: i64 = powwin(noise, W0, WN) // ||x - cleanS|| = ||noise|| 113 let err_out: i64 = powdiff(y, cleanS, W0, WN) // ||y - cleanS|| 114 let snr_ratio: i64 = err_in / (err_out + 1) // >1 => closer to clean => SNR improved 115 116 // --- OFF (neg-control): gains forced to 1 --- 117 ns_run(x, y, L, Lm, N, P, 0) 118 let err_off: i64 = powdiff(y, cleanS, W0, WN) 119 120 // --- noise-only attenuation (input = pure noise) --- 121 ns_run(noise, y, L, Lm, N, P, 1) 122 let pin_noise: i64 = powwin(noise, W0, WN) 123 let pout_noise: i64 = powwin(y, W0, WN) 124 let noise_red: i64 = pin_noise / (pout_noise + 1) 125 126 // --- speech preservation (input = clean speech only) --- 127 ns_run(cleanS, y, L, Lm, N, P, 1) 128 let p_speech: i64 = powwin(cleanS, W0, WN) 129 let p_distort: i64 = powdiff(y, cleanS, W0, WN) 130 131 var ok: i64 = 1 132 // T1: SNR improved -- output strictly closer to clean than the noisy input was 133 if err_out >= err_in { ok = 0 } 134 // T2 NEG: suppressor OFF reproduces the noisy input (gains load-bearing) 135 if err_off < err_in { ok = 0 } // off must NOT improve 136 if err_out >= err_off { ok = 0 } // on must beat off 137 // T3: pure noise is attenuated (>=2x power reduction) 138 if noise_red < 2 { ok = 0 } 139 // T4: speech preserved -- distortion small vs speech power (<25%) 140 if (p_distort * 4) >= p_speech { ok = 0 } 141 142 nw(1, "=== nx_ns -- sovereign integer 3-band Wiener noise suppressor ===\n" as *u8) 143 nw(1, " bands=3 (MA filterbank) frame=" as *u8); nwn(1, FR); nw(1, " floor=1/16 (NO-FLOAT, Q12)\n" as *u8) 144 nw(1, " T1 SNR improved: ||noisy-clean||=" as *u8); nwn(1, err_in); nw(1, " -> ||out-clean||=" as *u8); nwn(1, err_out); nw(1, " (" as *u8); nwn(1, snr_ratio); nw(1, "x closer): " as *u8); if err_out<err_in { nw(1,"PASS" as *u8) } else { nw(1,"FAIL" as *u8) } 145 nw(1, "\n T2 NEG suppressor OFF: ||out-clean||=" as *u8); nwn(1, err_off); nw(1, " == noisy (gains load-bearing): " as *u8); if err_off>=err_in { if err_out<err_off { nw(1,"PASS" as *u8) } else { nw(1,"FAIL" as *u8) } } else { nw(1,"FAIL" as *u8) } 146 nw(1, "\n T3 pure-noise attenuation: " as *u8); nwn(1, noise_red); nw(1, "x power reduction: " as *u8); if noise_red>=2 { nw(1,"PASS" as *u8) } else { nw(1,"FAIL" as *u8) } 147 nw(1, "\n T4 speech preserved: distortion " as *u8); nwn(1, p_distort); nw(1, " vs speech power " as *u8); nwn(1, p_speech); nw(1, " (<25%): " as *u8); if (p_distort*4)<p_speech { nw(1,"PASS" as *u8) } else { nw(1,"FAIL" as *u8) } 148 nw(1, "\n HONEST SCOPE: in-band noise under speech is NOT removed (single-channel limit); perceptual/DNN suppressor + musical-noise control = deeper rung.\n" as *u8) 149 if ok==1 { nw(1, "VERDICT: GREEN (measured SNR improvement; noise attenuated; speech preserved; gains load-bearing)\n" as *u8) } else { nw(1, "VERDICT: RED\n" as *u8) } 150 151 let lfd: i64 = sys_openat_append(NS_LOG, 420) 152 if lfd >= 0 { 153 nw(lfd, "NS err_in=" as *u8); nwn(lfd, err_in); nw(lfd, " err_out=" as *u8); nwn(lfd, err_out); nw(lfd, " snr_x=" as *u8); nwn(lfd, snr_ratio); nw(lfd, " noise_red=" as *u8); nwn(lfd, noise_red); nw(lfd, " distort=" as *u8); nwn(lfd, p_distort); nw(lfd, " speechpow=" as *u8); nwn(lfd, p_speech) 154 if ok==1 { nw(lfd, " verdict=GREEN\n" as *u8) } else { nw(lfd, " verdict=RED\n" as *u8) } 155 sys_close(lfd) 156 } 157 if ok==1 { sys_exit(0) } else { sys_exit(1) } 158 return 0 159}