code wiki / (root) / nx_song_grade_gate.nx

nx_song_grade_gate.nx source

↩ module page · 129 lines · 4852 B

1// nx_song_grade_gate.nx -- REFEREE for the learn-game grader (LG-2, nx_song_grade). 2// 3// SONG = 4 target notes [A2=45, A3=57, E2=40, E3=52] at 1024-sample slots. 4// Three performances are synthesized (impulse-train tones in each slot) and graded: 5// GOOD : correct note in every slot -> score 1000, all HIT 6// BAD : a wrong note in every slot -> score low, all WRONG (neg-control) 7// PARTIAL : correct, SILENT, correct, wrong -> score 500, verdicts HIT/MISS/HIT/WRONG 8// The BAD case is the neg-control: a wrong performance MUST score low, or the 9// grader can't tell right from wrong. 10// 11// Evidence -> stdout + knowledge/status/song_grade_gate.log. Exit 0 GREEN / 1 RED. 12// Sovereign x86_64 throughout. license_tier: ORIGINAL 13import "nx_syscalls_x86_64.nx" 14import "nx_song_grade.nx" 15import "nx_note.nx" 16 17const SLOT: i64 = 1024 18const NSAMP: i64 = 4096 19 20func gp(logfd: i64, s: *u8) -> i64 { 21 var n: i64 = 0 22 while s[n] != (0 as u8) { n = n + 1 } 23 sys_write(1, s, n) 24 if logfd > 0 { sys_write(logfd, s, n) } 25 return 0 26} 27func gn(logfd: i64, v: i64) -> i64 { 28 let bb: *u8 = sys_mmap(28) 29 var m: i64 = v 30 if m < 0 { sys_write(1, "-\x00" as *u8, 1); if logfd > 0 { sys_write(logfd, "-\x00" as *u8, 1) } m = 0 - m } 31 let t: *u8 = sys_mmap(28) 32 var k: i64 = 0 33 if m == 0 { t[0] = 48 as u8; k = 1 } 34 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 35 var i: i64 = 0 36 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 37 sys_write(1, bb, k) 38 if logfd > 0 { sys_write(logfd, bb, k) } 39 return 0 40} 41func setnote(sc: *i64, i: i64, midi: i64, start: i64, dur: i64) -> i64 { 42 sc[i * 3 + 0] = midi 43 sc[i * 3 + 1] = start 44 sc[i * 3 + 2] = dur 45 return 0 46} 47// impulse-train tone of given period into player[start .. start+dur) 48func put_tone(player: *u8, start: i64, dur: i64, period: i64) -> i64 { 49 var i: i64 = start 50 while i < start + dur { 51 player[i * 2] = (8000 & 0xff) as u8 52 player[i * 2 + 1] = ((8000 >> 8) & 0xff) as u8 53 i = i + period 54 } 55 return 0 56} 57func report(logfd: i64, label: *u8, score: i64, verdicts: *i64, n: i64) -> i64 { 58 gp(logfd, label) 59 gp(logfd, " score=\x00" as *u8); gn(logfd, score) 60 gp(logfd, "/1000 verdicts=[\x00" as *u8) 61 var i: i64 = 0 62 while i < n { gn(logfd, verdicts[i]); gp(logfd, " \x00" as *u8); i = i + 1 } 63 gp(logfd, "] (0=HIT 1=WRONG 2=MISS)\n\x00" as *u8) 64 return 0 65} 66 67func main() -> i64 { 68 let logfd: i64 = sys_openat_append("knowledge/status/song_grade_gate.log\x00" as *u8, 0x1a4) 69 gp(logfd, "SONG-GRADE-GATE LG-2 (learn-game)\n\x00" as *u8) 70 71 let tbl: *i64 = sys_mmap(128 * 8) as *i64 72 nx_note_table(tbl) 73 74 // SONG: A2 A3 E2 E3 75 let sc: *i64 = sys_mmap(4 * 3 * 8) as *i64 76 setnote(sc, 0, 45, 0, SLOT) 77 setnote(sc, 1, 57, SLOT, SLOT) 78 setnote(sc, 2, 40, 2 * SLOT, SLOT) 79 setnote(sc, 3, 52, 3 * SLOT, SLOT) 80 81 let vG: *i64 = sys_mmap(4 * 8) as *i64 82 let vB: *i64 = sys_mmap(4 * 8) as *i64 83 let vP: *i64 = sys_mmap(4 * 8) as *i64 84 85 // GOOD: correct periods (73->A2, 36->A3, 97->E2, 49->E3) 86 let pG: *u8 = sys_mmap(NSAMP * 2) 87 put_tone(pG, 0, SLOT, 73); put_tone(pG, SLOT, SLOT, 36); put_tone(pG, 2 * SLOT, SLOT, 97); put_tone(pG, 3 * SLOT, SLOT, 49) 88 let sG: i64 = nx_song_grade(sc, 4, pG, 8000, tbl, vG) 89 report(logfd, " GOOD \x00" as *u8, sG, vG, 4) 90 91 // BAD: wrong periods everywhere 92 let pB: *u8 = sys_mmap(NSAMP * 2) 93 put_tone(pB, 0, SLOT, 60); put_tone(pB, SLOT, SLOT, 30); put_tone(pB, 2 * SLOT, SLOT, 80); put_tone(pB, 3 * SLOT, SLOT, 40) 94 let sB: i64 = nx_song_grade(sc, 4, pB, 8000, tbl, vB) 95 report(logfd, " BAD \x00" as *u8, sB, vB, 4) 96 97 // PARTIAL: correct, SILENT, correct, wrong 98 let pP: *u8 = sys_mmap(NSAMP * 2) 99 put_tone(pP, 0, SLOT, 73); put_tone(pP, 2 * SLOT, SLOT, 97); put_tone(pP, 3 * SLOT, SLOT, 40) 100 let sP: i64 = nx_song_grade(sc, 4, pP, 8000, tbl, vP) 101 report(logfd, " PARTIAL\x00" as *u8, sP, vP, 4) 102 103 var ok: i64 = 1 104 // GOOD: perfect 105 if sG != 1000 { ok = 0 } 106 if vG[0] != SG_HIT { ok = 0 } 107 if vG[1] != SG_HIT { ok = 0 } 108 if vG[2] != SG_HIT { ok = 0 } 109 if vG[3] != SG_HIT { ok = 0 } 110 // BAD: must score low (neg-control) 111 if sB > 250 { ok = 0 } 112 // PARTIAL: 2/4 = 500, with the expected per-note pattern 113 if sP != 500 { ok = 0 } 114 if vP[0] != SG_HIT { ok = 0 } 115 if vP[1] != SG_MISS { ok = 0 } 116 if vP[2] != SG_HIT { ok = 0 } 117 if vP[3] != SG_WRONG { ok = 0 } 118 119 if ok == 1 { 120 gp(logfd, "SONG-GRADE-GATE result=ALL-PASS verdict=GREEN\n\x00" as *u8) 121 if logfd > 0 { sys_close(logfd) } 122 sys_exit(0) 123 return 0 124 } 125 gp(logfd, "SONG-GRADE-GATE result=FAIL verdict=RED\n\x00" as *u8) 126 if logfd > 0 { sys_close(logfd) } 127 sys_exit(1) 128 return 1 129}