code wiki / (root) / nx_pitch_gate.nx

nx_pitch_gate.nx source

↩ module page · 146 lines · 5848 B

1// nx_pitch_gate.nx -- REFEREE for VOICE-CLONE-001 rung 0 (sovereign F0). 2// 3// POSITIVE (voiced, real-ish): nx_voiced_vowel.wav is a glottal pitch glide 4// 120 -> 100 Hz @ 8 kHz. The detector MUST (a) report ~120 Hz in an early 5// window and ~100 Hz in a late window, (b) TRACK the downward glide 6// (early_f0 > late_f0), and (c) flag both windows VOICED. 7// NEG-CONTROL #1 (synthetic): a deterministic white-noise buffer MUST read 8// UNVOICED. If noise reads voiced the detector is worthless -> RED. 9// NEG-CONTROL #2 (real data): nx_speech_mixed.wav is voiced->unvoiced->voiced. 10// The middle (unvoiced) third MUST read UNVOICED while the outer thirds 11// read VOICED -- a discrimination the synthetic noise control can't give. 12// 13// Every measured value is PRINTED (no fabricated greens). Evidence -> 14// stdout + knowledge/status/pitch_gate.log. Exit 0 GREEN / 1 RED. 15// Sovereign: nx_syscalls + nx_pitch only. 16// license_tier: ORIGINAL 17import "nx_syscalls.nx" 18import "nx_pitch.nx" 19 20const FS: i64 = 8000 21const MINLAG: i64 = 25 // fs / 320 Hz 22const MAXLAG: i64 = 114 // fs / 70 Hz 23const WIN: i64 = 480 24const HDR: i64 = 44 // canonical RIFF/WAVE header bytes 25 26// dual-sink string write: stdout (fd 1) + the evidence log fd 27func gp(logfd: i64, s: *u8) -> i64 { 28 var n: i64 = 0 29 while s[n] != (0 as u8) { n = n + 1 } 30 sys_write(1, s, n) 31 if logfd > 0 { sys_write(logfd, s, n) } 32 return 0 33} 34// dual-sink decimal write 35func gn(logfd: i64, v: i64) -> i64 { 36 let bb: *u8 = sys_mmap(28) 37 var m: i64 = v 38 if m < 0 { sys_write(1, "-\x00" as *u8, 1); if logfd > 0 { sys_write(logfd, "-\x00" as *u8, 1) } m = 0 - m } 39 let t: *u8 = sys_mmap(28) 40 var k: i64 = 0 41 if m == 0 { t[0] = 48 as u8; k = 1 } 42 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 43 var i: i64 = 0 44 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 45 sys_write(1, bb, k) 46 if logfd > 0 { sys_write(logfd, bb, k) } 47 return 0 48} 49 50// analyze one window; print "<label> f0=.. tau=.. conf=.. voiced=.."; return 51// F0 (Hz). Writes voicing flag into vflag[0]. 52func analyze(logfd: i64, label: *u8, pcm: *u8, start: i64, vflag: *i64) -> i64 { 53 let out: *i64 = sys_mmap(16) as *i64 54 let f0: i64 = nx_pitch_f0(pcm, start, WIN, FS, MINLAG, MAXLAG, out) 55 let conf: i64 = out[0] 56 let tau: i64 = out[1] 57 let voiced: i64 = nx_pitch_is_voiced(conf) 58 gp(logfd, label) 59 gp(logfd, " f0=\x00" as *u8); gn(logfd, f0) 60 gp(logfd, "Hz tau=\x00" as *u8); gn(logfd, tau) 61 gp(logfd, " conf=\x00" as *u8); gn(logfd, conf) 62 gp(logfd, " voiced=\x00" as *u8); gn(logfd, voiced) 63 gp(logfd, "\n\x00" as *u8) 64 vflag[0] = voiced 65 return f0 66} 67 68// deterministic white-noise (LCG) -> i16-LE into buf, nsamp samples 69func gen_noise(buf: *u8, nsamp: i64) -> i64 { 70 var s: i64 = 305419896 71 var i: i64 = 0 72 while i < nsamp { 73 s = (s * 1103515245 + 12345) & 0x7fffffff 74 var v: i64 = (s & 0xffff) - 32768 75 var x: i64 = v 76 if x < 0 { x = x + 0x10000 } 77 buf[i * 2] = (x & 0xff) as u8 78 buf[i * 2 + 1] = ((x >> 8) & 0xff) as u8 79 i = i + 1 80 } 81 return 0 82} 83 84func main() -> i64 { 85 let logfd: i64 = sys_openat_append("knowledge/status/pitch_gate.log\x00" as *u8, 0x1a4) 86 gp(logfd, "PITCH-GATE VOICE-CLONE-001 rung0 epoch=\x00" as *u8) 87 gn(logfd, sys_now_realtime_sec()) 88 gp(logfd, " fs=\x00" as *u8); gn(logfd, FS) 89 gp(logfd, " win=\x00" as *u8); gn(logfd, WIN) 90 gp(logfd, " lags=[\x00" as *u8); gn(logfd, MINLAG); gp(logfd, ",\x00" as *u8); gn(logfd, MAXLAG); gp(logfd, "]\n\x00" as *u8) 91 92 let vf: *i64 = sys_mmap(16) as *i64 93 94 // ---- POSITIVE: voiced vowel pitch glide 120 -> 100 Hz ---- 95 let szp: *i64 = sys_mmap(16) as *i64 96 let b1: *u8 = sys_read_file("bench/nx_voiced_vowel.wav\x00" as *u8, szp) 97 gp(logfd, "[voiced_vowel.wav bytes=\x00" as *u8); gn(logfd, szp[0]); gp(logfd, "]\n\x00" as *u8) 98 let pcm1: *u8 = (b1 as i64 + HDR) as *u8 99 let early_f0: i64 = analyze(logfd, " early\x00" as *u8, pcm1, 200, vf) 100 let early_v: i64 = vf[0] 101 let late_f0: i64 = analyze(logfd, " late \x00" as *u8, pcm1, 3300, vf) 102 let late_v: i64 = vf[0] 103 104 // ---- NEG-CONTROL #1: synthetic white noise ---- 105 let noise: *u8 = sys_mmap(4096) 106 gen_noise(noise, 1024) 107 analyze(logfd, " noise\x00" as *u8, noise, 0, vf) 108 let noise_v: i64 = vf[0] 109 110 // ---- NEG-CONTROL #2 + voiced confirmation: mixed voiced/unvoiced ---- 111 let szp2: *i64 = sys_mmap(16) as *i64 112 let b2: *u8 = sys_read_file("bench/nx_speech_mixed.wav\x00" as *u8, szp2) 113 gp(logfd, "[speech_mixed.wav bytes=\x00" as *u8); gn(logfd, szp2[0]); gp(logfd, "]\n\x00" as *u8) 114 let pcm2: *u8 = (b2 as i64 + HDR) as *u8 115 analyze(logfd, " seg1(voiced) \x00" as *u8, pcm2, 400, vf) 116 let seg1_v: i64 = vf[0] 117 analyze(logfd, " seg2(unvoiced)\x00" as *u8, pcm2, 2300, vf) 118 let seg2_v: i64 = vf[0] 119 analyze(logfd, " seg3(voiced) \x00" as *u8, pcm2, 4200, vf) 120 let seg3_v: i64 = vf[0] 121 122 // ---- verdict ---- 123 var ok: i64 = 1 124 if early_v != 1 { ok = 0 } 125 if late_v != 1 { ok = 0 } 126 if early_f0 < 105 { ok = 0 } 127 if early_f0 > 135 { ok = 0 } 128 if late_f0 < 90 { ok = 0 } 129 if late_f0 > 112 { ok = 0 } 130 if early_f0 <= late_f0 { ok = 0 } // must track the downward glide 131 if noise_v != 0 { ok = 0 } // neg-control #1 132 if seg1_v != 1 { ok = 0 } 133 if seg2_v != 0 { ok = 0 } // neg-control #2 (real unvoiced) 134 if seg3_v != 1 { ok = 0 } 135 136 if ok == 1 { 137 gp(logfd, "PITCH-GATE result=ALL-PASS verdict=GREEN\n\x00" as *u8) 138 if logfd > 0 { sys_close(logfd) } 139 sys_exit(0) 140 return 0 141 } 142 gp(logfd, "PITCH-GATE result=FAIL verdict=RED\n\x00" as *u8) 143 if logfd > 0 { sys_close(logfd) } 144 sys_exit(1) 145 return 1 146}