code wiki / (root) / nx_pitch_grade_gate.nx

nx_pitch_grade_gate.nx source

↩ module page · 131 lines · 4952 B

1// nx_pitch_grade_gate.nx -- REFEREE for the singing-tutor grader (nx_pitch_grade). 2// 3// Generates pure impulse-train test "notes" at exact frequencies (fs/period) and 4// grades them against a target note (125 Hz): 5// ON : sung at 125 Hz (period 64) -> |cents| <= 25, verdict ON 6// SHARP : sung at 129 Hz (period 62) -> cents > 25, verdict SHARP 7// FLAT : sung at 121 Hz (period 66) -> cents < -25, verdict FLAT 8// MELODY: three on-pitch notes 100/125/160 Hz all grade ON (a sung phrase) 9// NEG-CONTROL: white noise -> NO_PITCH (never a false on-pitch grade) 10// 11// Every value PRINTED. Evidence -> stdout + knowledge/status/pitch_grade_gate.log. 12// Exit 0 GREEN / 1 RED. Sovereign x86_64 throughout. 13// license_tier: ORIGINAL 14import "nx_syscalls_x86_64.nx" 15import "nx_pitch_grade.nx" 16 17const FS: i64 = 8000 18const MINLAG: i64 = 25 19const MAXLAG: i64 = 114 20const WIN: i64 = 480 21const NS: i64 = 1024 22 23func gp(logfd: i64, s: *u8) -> i64 { 24 var n: i64 = 0 25 while s[n] != (0 as u8) { n = n + 1 } 26 sys_write(1, s, n) 27 if logfd > 0 { sys_write(logfd, s, n) } 28 return 0 29} 30func gn(logfd: i64, v: i64) -> i64 { 31 let bb: *u8 = sys_mmap(28) 32 var m: i64 = v 33 if m < 0 { sys_write(1, "-\x00" as *u8, 1); if logfd > 0 { sys_write(logfd, "-\x00" as *u8, 1) } m = 0 - m } 34 let t: *u8 = sys_mmap(28) 35 var k: i64 = 0 36 if m == 0 { t[0] = 48 as u8; k = 1 } 37 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 38 var i: i64 = 0 39 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 40 sys_write(1, bb, k) 41 if logfd > 0 { sys_write(logfd, bb, k) } 42 return 0 43} 44 45// pure impulse train at `period` -> exactly periodic -> F0 = fs/period exactly 46func gen_tone(out_pcm: *u8, nsamp: i64, period: i64) -> i64 { 47 var i: i64 = 0 48 while i < nsamp { out_pcm[i * 2] = 0 as u8; out_pcm[i * 2 + 1] = 0 as u8; i = i + 1 } 49 i = 0 50 while i < nsamp { 51 let x: i64 = 8000 52 out_pcm[i * 2] = (x & 0xff) as u8 53 out_pcm[i * 2 + 1] = ((x >> 8) & 0xff) as u8 54 i = i + period 55 } 56 return 0 57} 58func gen_noise(out_pcm: *u8, nsamp: i64) -> i64 { 59 var s: i64 = 305419896 60 var i: i64 = 0 61 while i < nsamp { 62 s = (s * 1103515245 + 12345) & 0x7fffffff 63 var v: i64 = (s & 0xffff) - 32768 64 var x: i64 = v 65 if x < 0 { x = x + 0x10000 } 66 out_pcm[i * 2] = (x & 0xff) as u8 67 out_pcm[i * 2 + 1] = ((x >> 8) & 0xff) as u8 68 i = i + 1 69 } 70 return 0 71} 72 73// grade one tone; print "<label> f0=.. cents=.. verdict=.."; returns verdict. 74func grade1(logfd: i64, label: *u8, pcm: *u8, target: i64, out: *i64) -> i64 { 75 let cents: i64 = nx_pitch_grade(pcm, 200, WIN, FS, MINLAG, MAXLAG, target, out) 76 gp(logfd, label) 77 gp(logfd, " tgt=\x00" as *u8); gn(logfd, target) 78 gp(logfd, " f0=\x00" as *u8); gn(logfd, out[1]) 79 gp(logfd, " cents=\x00" as *u8); gn(logfd, cents) 80 gp(logfd, " verdict=\x00" as *u8); gn(logfd, out[0]) 81 gp(logfd, "\n\x00" as *u8) 82 return out[0] 83} 84 85func main() -> i64 { 86 let logfd: i64 = sys_openat_append("knowledge/status/pitch_grade_gate.log\x00" as *u8, 0x1a4) 87 gp(logfd, "PITCH-GRADE-GATE singing-tutor tol=\x00" as *u8); gn(logfd, PG_TOL_CENTS); gp(logfd, "cents\n\x00" as *u8) 88 89 let out: *i64 = sys_mmap(16) as *i64 90 let buf: *u8 = sys_mmap(NS * 2) 91 92 // target note 125 Hz (period 64) 93 gen_tone(buf, NS, 64) 94 let v_on: i64 = grade1(logfd, " ON \x00" as *u8, buf, 125, out) 95 gen_tone(buf, NS, 62) // 129 Hz 96 let v_sharp: i64 = grade1(logfd, " SHARP\x00" as *u8, buf, 125, out) 97 gen_tone(buf, NS, 66) // 121 Hz 98 let v_flat: i64 = grade1(logfd, " FLAT \x00" as *u8, buf, 125, out) 99 100 // melody: three on-pitch notes 101 gen_tone(buf, NS, 80) // 100 Hz 102 let v_m1: i64 = grade1(logfd, " MEL1 \x00" as *u8, buf, 100, out) 103 gen_tone(buf, NS, 64) // 125 Hz 104 let v_m2: i64 = grade1(logfd, " MEL2 \x00" as *u8, buf, 125, out) 105 gen_tone(buf, NS, 50) // 160 Hz 106 let v_m3: i64 = grade1(logfd, " MEL3 \x00" as *u8, buf, 160, out) 107 108 // neg-control: noise must NOT grade as a pitch 109 gen_noise(buf, NS) 110 let v_noise: i64 = grade1(logfd, " NOISE\x00" as *u8, buf, 125, out) 111 112 var ok: i64 = 1 113 if v_on != PG_ON { ok = 0 } 114 if v_sharp != PG_SHARP { ok = 0 } 115 if v_flat != PG_FLAT { ok = 0 } 116 if v_m1 != PG_ON { ok = 0 } 117 if v_m2 != PG_ON { ok = 0 } 118 if v_m3 != PG_ON { ok = 0 } 119 if v_noise != PG_NOPITCH { ok = 0 } 120 121 if ok == 1 { 122 gp(logfd, "PITCH-GRADE-GATE result=ALL-PASS verdict=GREEN\n\x00" as *u8) 123 if logfd > 0 { sys_close(logfd) } 124 sys_exit(0) 125 return 0 126 } 127 gp(logfd, "PITCH-GRADE-GATE result=FAIL verdict=RED\n\x00" as *u8) 128 if logfd > 0 { sys_close(logfd) } 129 sys_exit(1) 130 return 1 131}