code wiki / (root) / nx_note_gate.nx

nx_note_gate.nx source

↩ module page · 117 lines · 4779 B

1// nx_note_gate.nx -- REFEREE for instrument-learn-game rung LG-0 (nx_note). 2// 3// Direct F0->note checks spanning the instrument range (bass low E to high E), 4// including adjacent-semitone discrimination, plus one END-TO-END chain 5// (synth tone -> nx_pitch with instrument-range lags -> nx_note). 6// 7// Evidence -> stdout + knowledge/status/note_gate.log. Exit 0 GREEN / 1 RED. 8// Sovereign x86_64 throughout. license_tier: ORIGINAL 9import "nx_syscalls_x86_64.nx" 10import "nx_note.nx" 11import "nx_pitch.nx" 12 13func gp(logfd: i64, s: *u8) -> i64 { 14 var n: i64 = 0 15 while s[n] != (0 as u8) { n = n + 1 } 16 sys_write(1, s, n) 17 if logfd > 0 { sys_write(logfd, s, n) } 18 return 0 19} 20func gn(logfd: i64, v: i64) -> i64 { 21 let bb: *u8 = sys_mmap(28) 22 var m: i64 = v 23 if m < 0 { sys_write(1, "-\x00" as *u8, 1); if logfd > 0 { sys_write(logfd, "-\x00" as *u8, 1) } m = 0 - m } 24 let t: *u8 = sys_mmap(28) 25 var k: i64 = 0 26 if m == 0 { t[0] = 48 as u8; k = 1 } 27 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 28 var i: i64 = 0 29 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 30 sys_write(1, bb, k) 31 if logfd > 0 { sys_write(logfd, bb, k) } 32 return 0 33} 34func pname(logfd: i64, pc: i64) -> i64 { 35 if pc == 0 { gp(logfd, "C\x00" as *u8) } 36 if pc == 1 { gp(logfd, "C#\x00" as *u8) } 37 if pc == 2 { gp(logfd, "D\x00" as *u8) } 38 if pc == 3 { gp(logfd, "D#\x00" as *u8) } 39 if pc == 4 { gp(logfd, "E\x00" as *u8) } 40 if pc == 5 { gp(logfd, "F\x00" as *u8) } 41 if pc == 6 { gp(logfd, "F#\x00" as *u8) } 42 if pc == 7 { gp(logfd, "G\x00" as *u8) } 43 if pc == 8 { gp(logfd, "G#\x00" as *u8) } 44 if pc == 9 { gp(logfd, "A\x00" as *u8) } 45 if pc == 10 { gp(logfd, "A#\x00" as *u8) } 46 if pc == 11 { gp(logfd, "B\x00" as *u8) } 47 return 0 48} 49 50func gen_tone(out_pcm: *u8, nsamp: i64, period: i64) -> i64 { 51 var i: i64 = 0 52 while i < nsamp { out_pcm[i * 2] = 0 as u8; out_pcm[i * 2 + 1] = 0 as u8; i = i + 1 } 53 i = 0 54 while i < nsamp { 55 out_pcm[i * 2] = (8000 & 0xff) as u8 56 out_pcm[i * 2 + 1] = ((8000 >> 8) & 0xff) as u8 57 i = i + period 58 } 59 return 0 60} 61 62// check one F0->note; print; return 1 if midi matches expected 63func chk(logfd: i64, f0: i64, exp: i64, tbl: *i64, out: *i64) -> i64 { 64 let midi: i64 = nx_note_of(f0, tbl, out) 65 gp(logfd, " f0=\x00" as *u8); gn(logfd, f0) 66 gp(logfd, "Hz -> midi=\x00" as *u8); gn(logfd, midi) 67 gp(logfd, " note=\x00" as *u8); pname(logfd, out[2]); gn(logfd, out[3]) 68 gp(logfd, " cents=\x00" as *u8); gn(logfd, out[1]) 69 if midi == exp { gp(logfd, " OK\n\x00" as *u8); return 1 } 70 gp(logfd, " MISMATCH(exp \x00" as *u8); gn(logfd, exp); gp(logfd, ")\n\x00" as *u8) 71 return 0 72} 73 74func main() -> i64 { 75 let logfd: i64 = sys_openat_append("knowledge/status/note_gate.log\x00" as *u8, 0x1a4) 76 gp(logfd, "NOTE-GATE LG-0 (F0 -> musical note)\n\x00" as *u8) 77 78 let tbl: *i64 = sys_mmap(128 * 8) as *i64 79 nx_note_table(tbl) 80 let out: *i64 = sys_mmap(32) as *i64 81 82 var ok: i64 = 1 83 // guitar/bass/piano range; MIDI: E1=28 E2=40 A2=45 A3=57 C4=60 E4=64 A4=69 E6=88 84 if chk(logfd, 41, 28, tbl, out) == 0 { ok = 0 } // bass low E (E1) 85 if chk(logfd, 82, 40, tbl, out) == 0 { ok = 0 } // guitar low E (E2) 86 if chk(logfd, 87, 41, tbl, out) == 0 { ok = 0 } // F2 -- adjacent-semitone discrimination 87 if chk(logfd, 110, 45, tbl, out) == 0 { ok = 0 } // A2 88 if chk(logfd, 220, 57, tbl, out) == 0 { ok = 0 } // A3 89 if chk(logfd, 261, 60, tbl, out) == 0 { ok = 0 } // middle C (C4) 90 if chk(logfd, 330, 64, tbl, out) == 0 { ok = 0 } // guitar high E (E4) 91 if chk(logfd, 440, 69, tbl, out) == 0 { ok = 0 } // A440 (cents must be 0) 92 if chk(logfd, 1318, 88, tbl, out) == 0 { ok = 0 } // E6 93 // A440 must be dead-on 94 nx_note_of(440, tbl, out) 95 if out[1] != 0 { ok = 0 } 96 97 // END-TO-END: synth ~222 Hz tone -> nx_pitch (instrument lags) -> nx_note -> A3 98 let buf: *u8 = sys_mmap(2048 * 2) 99 gen_tone(buf, 2048, 36) 100 let pout: *i64 = sys_mmap(16) as *i64 101 let f0e: i64 = nx_pitch_f0(buf, 100, 600, 8000, 12, 200, pout) 102 let midie: i64 = nx_note_of(f0e, tbl, out) 103 gp(logfd, " [e2e] tone~222Hz detected f0=\x00" as *u8); gn(logfd, f0e) 104 gp(logfd, " -> midi=\x00" as *u8); gn(logfd, midie); gp(logfd, " note=\x00" as *u8); pname(logfd, out[2]); gn(logfd, out[3]); gp(logfd, "\n\x00" as *u8) 105 if midie != 57 { ok = 0 } 106 107 if ok == 1 { 108 gp(logfd, "NOTE-GATE result=ALL-PASS verdict=GREEN\n\x00" as *u8) 109 if logfd > 0 { sys_close(logfd) } 110 sys_exit(0) 111 return 0 112 } 113 gp(logfd, "NOTE-GATE result=FAIL verdict=RED\n\x00" as *u8) 114 if logfd > 0 { sys_close(logfd) } 115 sys_exit(1) 116 return 1 117}