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}