code wiki / _hdl_build / nx_gamemusic_gate.nx

nx_gamemusic_gate.nx source

↩ module page · 213 lines · 9372 B

1// nx_gamemusic_gate.nx -- CERTIFICATION of nx_gamemusic, completing `audio-sfx-music`. 2// The SFX half is already proven by nx_game_audio_gate (3/3, real WAV). This gate proves the MUSIC half so 3// the capability can honestly be called HAVE rather than inferred from SFX alone. 4// T1 EXACT equal-temperament octaves: A4=440 -> A5=880 -> A3=220, no drift 5// T2 DETERMINISTIC render: same song rendered twice -> byte-identical samples 6// T3 DATA-DRIVEN: a different song array produces different audio (melody is data, not code) 7// T4 SATURATING MIX: layering loud tracks clamps instead of wrapping (no integer-overflow crackle) 8// T5 PER-NOTE ENVELOPE: a note attacks then decays (it does not click on at full amplitude) 9// T6 ★ANTI-VACUITY: output is non-silent AND pitch is real -- a high note has strictly more 10// zero-crossings than a low note. Silence or a constant would satisfy T2/T4 vacuously. 11// T7 REAL ARTIFACT: a playable WAV is written to disk via the existing nx_audio_wav writer 12// T8 composes with nx_gamesave: the song DATA round-trips through save/load 13// license_tier: ORIGINAL expect_exit: 0 14import "nx_syscalls.nx" 15import "nx_gamemusic.nx" 16import "nx_audio_wav.nx" 17import "nx_gamesave.nx" 18 19func mw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 20func mn(v: i64) -> i64 { 21 if v==0 { sys_write(1,"0" as *u8,1); return 0 } 22 var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m } 23 let t: *u8=sys_mmap(32); var k: i64=0 24 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 25 let o: *u8=sys_mmap(32); var q: i64=k-1; var i: i64=0 26 while q>=0 { o[i]=t[q]; i=i+1; q=q-1 } 27 sys_write(1,o,i); return 0 28} 29func zerocross(b: *i64, n: i64) -> i64 { 30 var c: i64 = 0 31 var i: i64 = 1 32 while i < n { 33 if b[i-1] < 0 { if b[i] >= 0 { c = c + 1 } } 34 if b[i-1] >= 0 { if b[i] < 0 { c = c + 1 } } 35 i = i + 1 36 } 37 return c 38} 39func clearbuf(b: *i64, n: i64) -> i64 { var i: i64=0; while i<n { b[i]=0; i=i+1 } return 0 } 40 41func main() -> i64 { 42 mw("=== nx_gamemusic_gate: is the MUSIC half of audio-sfx-music real? ===\n\n") 43 var pass: i64 = 0 44 var checks: i64 = 0 45 let RATE: i64 = 22050 46 let TICK: i64 = 2756 // ~1/8 s per tick 47 48 // ---------- T1 exact equal temperament ---------- 49 checks = checks + 1 50 let a4: i64 = mus_note_freq(9,4) 51 let a5: i64 = mus_note_freq(9,5) 52 let a3: i64 = mus_note_freq(9,3) 53 let c4: i64 = mus_note_freq(0,4) 54 var t1: i64 = 0 55 if a4==440 { if a5==880 { if a3==220 { if c4==262 { t1=1 } } } } 56 if t1==1 { 57 mw("T1 GREEN exact octaves: A3="); mn(a3); mw(" A4="); mn(a4); mw(" A5="); mn(a5) 58 mw(" C4="); mn(c4); mw(" (integer doubling, zero drift)\n"); pass=pass+1 59 } else { mw("T1 RED pitch table wrong: A3/A4/A5="); mn(a3); mw("/"); mn(a4); mw("/"); mn(a5); mw("\n") } 60 61 // ---------- song data (DATA, not code): a simple C-major phrase + a bass line ---------- 62 let NN: i64 = 8 63 let song: *i64 = sys_mmap(NN*3*8) as *i64 64 // (semi, octave, ticks) 65 song[0]=0; song[1]=4; song[2]=2 // C4 66 song[3]=2; song[4]=4; song[5]=2 // D4 67 song[6]=4; song[7]=4; song[8]=2 // E4 68 song[9]=5; song[10]=4; song[11]=2 // F4 69 song[12]=7; song[13]=4; song[14]=2 // G4 70 song[15]=MUS_REST; song[16]=4; song[17]=1 71 song[18]=9; song[19]=4; song[20]=2 // A4 72 song[21]=11; song[22]=4; song[23]=3 // B4 73 let NS: i64 = mus_song_samples(song, NN, TICK) 74 75 // ---------- T2 deterministic render ---------- 76 checks = checks + 1 77 let b1: *i64 = sys_mmap(NS*8+64) as *i64 78 let b2: *i64 = sys_mmap(NS*8+64) as *i64 79 clearbuf(b1, NS); clearbuf(b2, NS) 80 mus_render(b1, NS, song, NN, RATE, 9000, TICK) 81 mus_render(b2, NS, song, NN, RATE, 9000, TICK) 82 var det: i64 = 1 83 var i: i64 = 0 84 while i < NS { if b1[i]!=b2[i] { det=0 } i=i+1 } 85 if det==1 { 86 mw("T2 GREEN deterministic: identical song -> byte-identical "); mn(NS); mw(" samples\n"); pass=pass+1 87 } else { mw("T2 RED render diverged between runs\n") } 88 89 // ---------- T3 data-driven ---------- 90 checks = checks + 1 91 let song2: *i64 = sys_mmap(NN*3*8) as *i64 92 i = 0 93 while i < NN*3 { song2[i]=song[i]; i=i+1 } 94 song2[0]=11; song2[1]=5 // change only the first note 95 let b3: *i64 = sys_mmap(NS*8+64) as *i64 96 clearbuf(b3, NS) 97 mus_render(b3, NS, song2, NN, RATE, 9000, TICK) 98 var diff: i64 = 0 99 i = 0 100 while i < NS { if b3[i]!=b1[i] { diff = diff + 1 } i=i+1 } 101 if diff > 100 { 102 mw("T3 GREEN data-driven: changing ONE note changed "); mn(diff) 103 mw(" samples -- melody is data, not code\n"); pass=pass+1 104 } else { mw("T3 RED changing the song changed only "); mn(diff); mw(" samples\n") } 105 106 // ---------- T4 saturating mix ---------- 107 checks = checks + 1 108 let b4: *i64 = sys_mmap(NS*8+64) as *i64 109 clearbuf(b4, NS) 110 // layer the same loud track four times; without saturation this wraps negative 111 mus_render(b4, NS, song, NN, RATE, 30000, TICK) 112 mus_render(b4, NS, song, NN, RATE, 30000, TICK) 113 mus_render(b4, NS, song, NN, RATE, 30000, TICK) 114 mus_render(b4, NS, song, NN, RATE, 30000, TICK) 115 var over: i64 = 0 116 var peak: i64 = 0 117 i = 0 118 while i < NS { 119 var v: i64 = b4[i] 120 if v < 0 { v = 0 - v } 121 if v > peak { peak = v } 122 if b4[i] > MUS_SAMPMAX { over = over + 1 } 123 if b4[i] < 0 - MUS_SAMPMAX { over = over + 1 } 124 i = i + 1 125 } 126 if over==0 { if peak > 0 { 127 mw("T4 GREEN saturating mix: 4 layers at amp 30000 -> peak "); mn(peak) 128 mw(", 0 samples past the ceiling (no overflow crackle)\n"); pass=pass+1 129 } } 130 if over>0 { mw("T4 RED "); mn(over); mw(" samples exceeded the sample ceiling\n") } 131 if over==0 { if peak==0 { mw("T4 RED mix produced silence\n") } } 132 133 // ---------- T5 per-note envelope ---------- 134 checks = checks + 1 135 let e0: i64 = mus_env(0, 1000, 125) 136 let emid: i64 = mus_env(125, 1000, 125) 137 let eend: i64 = mus_env(999, 1000, 125) 138 var t5: i64 = 0 139 if e0 < emid { if eend < emid { if e0 >= 0 { t5=1 } } } 140 if t5==1 { 141 mw("T5 GREEN envelope attacks then decays: env(0)="); mn(e0); mw(" env(peak)="); mn(emid) 142 mw(" env(end)="); mn(eend); mw("\n"); pass=pass+1 143 } else { mw("T5 RED envelope not attack-decay shaped\n") } 144 145 // ---------- T6 anti-vacuity: non-silent + real pitch ---------- 146 checks = checks + 1 147 var nonzero: i64 = 0 148 i = 0 149 while i < NS { if b1[i]!=0 { nonzero = nonzero + 1 } i=i+1 } 150 // a low note must cross zero far less often than a high note over the same span 151 let SPAN: i64 = 4000 152 let lo: *i64 = sys_mmap(SPAN*8+64) as *i64 153 let hi: *i64 = sys_mmap(SPAN*8+64) as *i64 154 clearbuf(lo, SPAN); clearbuf(hi, SPAN) 155 let slo: *i64 = sys_mmap(3*8) as *i64 156 let shi: *i64 = sys_mmap(3*8) as *i64 157 slo[0]=9; slo[1]=2; slo[2]=1 // A2 = 110Hz 158 shi[0]=9; shi[1]=6; shi[2]=1 // A6 = 1760Hz 159 mus_render(lo, SPAN, slo, 1, RATE, 9000, SPAN) 160 mus_render(hi, SPAN, shi, 1, RATE, 9000, SPAN) 161 let zlo: i64 = zerocross(lo, SPAN) 162 let zhi: i64 = zerocross(hi, SPAN) 163 var t6: i64 = 0 164 if nonzero > NS/4 { if zhi > zlo*4 { t6=1 } } 165 if t6==1 { 166 mw("T6 GREEN anti-vacuity: "); mn(nonzero); mw("/"); mn(NS) 167 mw(" non-silent; A2 crossings="); mn(zlo); mw(" vs A6="); mn(zhi) 168 mw(" -- real pitch, not a constant\n"); pass=pass+1 169 } else { 170 mw("T6 RED vacuous audio: nonzero="); mn(nonzero); mw(" zlo="); mn(zlo); mw(" zhi="); mn(zhi); mw("\n") 171 } 172 173 // ---------- T7 real playable artifact ---------- 174 checks = checks + 1 175 let MP: *u8 = "knowledge/nx_gamemusic.wav" as *u8 176 sys_unlinkat(MP) 177 let wbuf: *u8 = sys_mmap(NS*4 + 4096) 178 let wlen: i64 = wav_render_stereo(b1, b1, NS, RATE, wbuf) 179 wav_save(MP, wbuf, wlen) 180 let lp: *i64 = sys_mmap(8) as *i64 181 lp[0]=0 182 let chk: *u8 = sys_read_file(MP, lp) 183 var t7: i64 = 0 184 if (chk as i64)!=0 { if lp[0] > 1000 { 185 if chk[0]==(82 as u8) { if chk[1]==(73 as u8) { if chk[2]==(70 as u8) { if chk[3]==(70 as u8) { t7=1 } } } } 186 } } 187 if t7==1 { 188 mw("T7 GREEN real artifact: knowledge/nx_gamemusic.wav written, RIFF header verified, ") 189 mn(lp[0]); mw(" bytes playable\n"); pass=pass+1 190 } else { mw("T7 RED WAV not written or not RIFF, bytes="); mn(lp[0]); mw("\n") } 191 192 // ---------- T8 composes with nx_gamesave ---------- 193 checks = checks + 1 194 let SP: *u8 = "knowledge/nx_gamemusic_song.sav" as *u8 195 sys_unlinkat(SP) 196 let wrote: i64 = gs_save(SP, 5150, song, NN*3, 1784579000) 197 let rd: *i64 = sys_mmap(NN*3*8) as *i64 198 let got: i64 = gs_load(SP, rd, NN*3, 0 as *i64) 199 var t8: i64 = 1 200 if got != NN*3 { t8=0 } 201 if wrote <= 0 { t8=0 } 202 i = 0 203 while i < NN*3 { if rd[i]!=song[i] { t8=0 } i=i+1 } 204 if t8==1 { 205 mw("T8 GREEN composes with nx_gamesave: "); mn(NN); mw("-note song round-tripped ("); mn(wrote) 206 mw("B) -- soundtracks persist with the save\n"); pass=pass+1 207 } else { mw("T8 RED song data did not survive save/load, rc="); mn(got); mw("\n") } 208 209 mw("\n=== nx_gamemusic_gate "); mn(pass); mw("/"); mn(checks) 210 if pass == checks { mw(" GREEN ===\n"); return 0 } 211 mw(" RED ===\n") 212 return 1 213}