nx_chord_grade_gate.nx source
↩ module page · 181 lines · 6498 B
1// nx_chord_grade_gate.nx -- REFEREE for LG-4 chord-aware grading (nx_chord_grade).
2//
3// SONG (4 slots): A3 | A-major(A3,C#4,E4) | power-5th(A3,E4) | C-major(C4,E4,G4).
4// Three performances are synthesized (sum-of-sine chords per slot) and graded:
5// GOOD : every slot played correctly -> 1000, all HIT
6// BAD : disjoint wrong notes every slot -> 0, all WRONG (neg-control)
7// PARTIAL : A3 | only 2 of 3 | SILENT | C-maj -> 666, [HIT,PARTIAL,MISS,HIT]
8//
9// Evidence -> stdout + knowledge/status/chord_grade_gate.log. Exit 0 GREEN / 1 RED.
10// Sovereign x86_64 throughout. license_tier: ORIGINAL
11import "nx_syscalls_x86_64.nx"
12import "nx_chord_grade.nx"
13import "nx_polypitch.nx"
14import "nx_note.nx"
15
16const SLOT: i64 = 1536
17const NS: i64 = 6144
18const FS: i64 = 8000
19const AMP: i64 = 10000
20const TWO_PI: i64 = 411775
21
22func gp(logfd: i64, s: *u8) -> i64 {
23 var n: i64 = 0
24 while s[n] != (0 as u8) { n = n + 1 }
25 sys_write(1, s, n)
26 if logfd > 0 { sys_write(logfd, s, n) }
27 return 0
28}
29func gn(logfd: i64, v: i64) -> i64 {
30 let bb: *u8 = sys_mmap(28)
31 var m: i64 = v
32 if m < 0 { sys_write(1, "-\x00" as *u8, 1); if logfd > 0 { sys_write(logfd, "-\x00" as *u8, 1) } m = 0 - m }
33 let t: *u8 = sys_mmap(28)
34 var k: i64 = 0
35 if m == 0 { t[0] = 48 as u8; k = 1 }
36 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
37 var i: i64 = 0
38 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
39 sys_write(1, bb, k)
40 if logfd > 0 { sys_write(logfd, bb, k) }
41 return 0
42}
43
44func add_sine_region(acc: *i64, start: i64, dur: i64, f: i64, amp: i64) -> i64 {
45 if f <= 0 { return 0 }
46 let dph: i64 = (TWO_PI * f) / FS
47 var ph: i64 = 0
48 var n: i64 = 0
49 while n < dur {
50 acc[start + n] = acc[start + n] + ((amp * nx_pp_sinfull(ph)) >> 16)
51 ph = ph + dph
52 if ph >= TWO_PI { ph = ph - TWO_PI }
53 n = n + 1
54 }
55 return 0
56}
57// add a note (by MIDI) into a slot region
58func add_note(acc: *i64, tbl: *i64, slotstart: i64, midi: i64) -> i64 {
59 add_sine_region(acc, slotstart, SLOT, tbl[midi] / 100, AMP)
60 return 0
61}
62func normalize(acc: *i64, buf: *u8, total: i64) -> i64 {
63 var mx: i64 = 1
64 var n: i64 = 0
65 while n < total { var v: i64 = acc[n]; if v < 0 { v = 0 - v } if v > mx { mx = v } n = n + 1 }
66 n = 0
67 while n < total {
68 var s: i64 = acc[n] * 16000 / mx
69 if s > 32000 { s = 32000 }
70 if s < -32000 { s = -32000 }
71 var x: i64 = s
72 if x < 0 { x = x + 0x10000 }
73 buf[n * 2] = (x & 0xff) as u8
74 buf[n * 2 + 1] = ((x >> 8) & 0xff) as u8
75 n = n + 1
76 }
77 return 0
78}
79func zero(acc: *i64, total: i64) -> i64 {
80 var n: i64 = 0
81 while n < total { acc[n] = 0; n = n + 1 }
82 return 0
83}
84func setslot(song: *i64, s: i64, start: i64, nt: i64, m0: i64, m1: i64, m2: i64) -> i64 {
85 song[s * 9 + 0] = start
86 song[s * 9 + 1] = SLOT
87 song[s * 9 + 2] = nt
88 song[s * 9 + 3] = m0
89 song[s * 9 + 4] = m1
90 song[s * 9 + 5] = m2
91 return 0
92}
93func report(logfd: i64, label: *u8, score: i64, v: *i64) -> i64 {
94 gp(logfd, label)
95 gp(logfd, " score=\x00" as *u8); gn(logfd, score)
96 gp(logfd, " verdicts=[\x00" as *u8)
97 var i: i64 = 0
98 while i < 4 { gn(logfd, v[i]); gp(logfd, " \x00" as *u8); i = i + 1 }
99 gp(logfd, "] (0=HIT 1=PARTIAL 2=WRONG 3=MISS)\n\x00" as *u8)
100 return 0
101}
102
103func main() -> i64 {
104 let logfd: i64 = sys_openat_append("knowledge/status/chord_grade_gate.log\x00" as *u8, 0x1a4)
105 gp(logfd, "CHORD-GRADE-GATE LG-4 (chord-aware learn-game)\n\x00" as *u8)
106
107 let tbl: *i64 = sys_mmap(128 * 8) as *i64
108 nx_note_table(tbl)
109
110 // SONG: A3 | A-maj(57,61,64) | power-5th(57,64) | C-maj(60,64,67)
111 let song: *i64 = sys_mmap(4 * 9 * 8) as *i64
112 setslot(song, 0, 0, 1, 57, 0, 0)
113 setslot(song, 1, SLOT, 3, 57, 61, 64)
114 setslot(song, 2, 2 * SLOT, 2, 57, 64, 0)
115 setslot(song, 3, 3 * SLOT, 3, 60, 64, 67)
116
117 let acc: *i64 = sys_mmap(NS * 8) as *i64
118 let vG: *i64 = sys_mmap(4 * 8) as *i64
119 let vB: *i64 = sys_mmap(4 * 8) as *i64
120 let vP: *i64 = sys_mmap(4 * 8) as *i64
121
122 // GOOD
123 let pG: *u8 = sys_mmap(NS * 2)
124 zero(acc, NS)
125 add_note(acc, tbl, 0, 57)
126 add_note(acc, tbl, SLOT, 57); add_note(acc, tbl, SLOT, 61); add_note(acc, tbl, SLOT, 64)
127 add_note(acc, tbl, 2 * SLOT, 57); add_note(acc, tbl, 2 * SLOT, 64)
128 add_note(acc, tbl, 3 * SLOT, 60); add_note(acc, tbl, 3 * SLOT, 64); add_note(acc, tbl, 3 * SLOT, 67)
129 normalize(acc, pG, NS)
130 let sG: i64 = nx_chord_grade(song, 4, pG, FS, tbl, vG)
131 report(logfd, " GOOD \x00" as *u8, sG, vG)
132
133 // BAD: disjoint wrong notes (avoid {57,60,61,64,67})
134 let pB: *u8 = sys_mmap(NS * 2)
135 zero(acc, NS)
136 add_note(acc, tbl, 0, 56)
137 add_note(acc, tbl, SLOT, 55); add_note(acc, tbl, SLOT, 58); add_note(acc, tbl, SLOT, 62)
138 add_note(acc, tbl, 2 * SLOT, 55); add_note(acc, tbl, 2 * SLOT, 62)
139 add_note(acc, tbl, 3 * SLOT, 55); add_note(acc, tbl, 3 * SLOT, 59); add_note(acc, tbl, 3 * SLOT, 63)
140 normalize(acc, pB, NS)
141 let sB: i64 = nx_chord_grade(song, 4, pB, FS, tbl, vB)
142 report(logfd, " BAD \x00" as *u8, sB, vB)
143
144 // PARTIAL: A3 | only 57,61 (miss 64) | SILENT | C-maj correct
145 let pP: *u8 = sys_mmap(NS * 2)
146 zero(acc, NS)
147 add_note(acc, tbl, 0, 57)
148 add_note(acc, tbl, SLOT, 57); add_note(acc, tbl, SLOT, 61)
149 add_note(acc, tbl, 3 * SLOT, 60); add_note(acc, tbl, 3 * SLOT, 64); add_note(acc, tbl, 3 * SLOT, 67)
150 normalize(acc, pP, NS)
151 let sP: i64 = nx_chord_grade(song, 4, pP, FS, tbl, vP)
152 report(logfd, " PARTIAL\x00" as *u8, sP, vP)
153
154 var ok: i64 = 1
155 if sG != 1000 { ok = 0 }
156 if vG[0] != CG_HIT { ok = 0 }
157 if vG[1] != CG_HIT { ok = 0 }
158 if vG[2] != CG_HIT { ok = 0 }
159 if vG[3] != CG_HIT { ok = 0 }
160 if sB != 0 { ok = 0 }
161 if vB[0] != CG_WRONG { ok = 0 }
162 if vB[1] != CG_WRONG { ok = 0 }
163 if vB[2] != CG_WRONG { ok = 0 }
164 if vB[3] != CG_WRONG { ok = 0 }
165 if sP != 666 { ok = 0 }
166 if vP[0] != CG_HIT { ok = 0 }
167 if vP[1] != CG_PARTIAL { ok = 0 }
168 if vP[2] != CG_MISS { ok = 0 }
169 if vP[3] != CG_HIT { ok = 0 }
170
171 if ok == 1 {
172 gp(logfd, "CHORD-GRADE-GATE result=ALL-PASS verdict=GREEN\n\x00" as *u8)
173 if logfd > 0 { sys_close(logfd) }
174 sys_exit(0)
175 return 0
176 }
177 gp(logfd, "CHORD-GRADE-GATE result=FAIL verdict=RED\n\x00" as *u8)
178 if logfd > 0 { sys_close(logfd) }
179 sys_exit(1)
180 return 1
181}