code wiki / (root) / nx_audio_song_test.nx

nx_audio_song_test.nx source

↩ module page · 70 lines · 2820 B

1// nx_audio_song_test.nx -- MUSICAL artifact: render a C-major arpeggio (3 sine 2// notes, each ADSR-shaped) to /tmp/song.wav. Composes synth(R3b) + wav(R4) into 3// real music -- the live-testable proof the engine makes tones, not just a buzz. 4// expect_exit: 0. 5 6import "nx_syscalls.nx" 7import "nx_audio_mix.nx" 8import "nx_audio_synth.nx" 9import "nx_audio_wav.nx" 10 11func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 12func wn(v: i64) -> i64 { 13 let b: *u8 = sys_mmap(28); var m: i64 = v 14 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } 15 let t: *u8 = sys_mmap(28); var k: i64 = 0 16 if m == 0 { t[0] = 48 as u8; k = 1 } 17 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 18 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 } 19 sys_write(1, b, k); return 0 20} 21func chk(cond: i64, pass: *i64, fail: *i64, label: *u8) -> i64 { 22 if cond == 1 { pass[0] = pass[0] + 1; w(" ok " as *u8); w(label); w("\n" as *u8) } 23 else { fail[0] = fail[0] + 1; w(" XX " as *u8); w(label); w("\n" as *u8) } 24 return 0 25} 26 27func freq_of(k: i64) -> i64 { 28 if k == 0 { return 262 } // C4 29 if k == 1 { return 330 } // E4 30 return 392 // G4 31} 32 33func main() -> i64 { 34 let pass: *i64 = (sys_mmap(8)) as *i64 35 let fail: *i64 = (sys_mmap(8)) as *i64 36 pass[0] = 0 37 fail[0] = 0 38 w("=== nx_audio_song: C-major arpeggio sine+ADSR -> /tmp/song.wav ===\n" as *u8) 39 40 let rate: i64 = 8000 41 let nlen: i64 = 2400 // 0.3s per note 42 let total_n: i64 = nlen * 3 43 let song: *i64 = (sys_mmap(total_n * 8 + 64)) as *i64 44 let tmp: *i64 = (sys_mmap(nlen * 8 + 64)) as *i64 45 46 var k: i64 = 0 47 while k < 3 { 48 osc_sine(tmp, nlen, freq_of(k), rate, 9000) 49 adsr_apply(tmp, nlen, 200, 400, 180, 1400, 400) 50 var i: i64 = 0 51 while i < nlen { song[k * nlen + i] = tmp[i]; i = i + 1 } 52 k = k + 1 53 } 54 55 let out: *u8 = sys_mmap(total_n * 4 + 128) 56 let tb: i64 = wav_render_stereo(song, song, total_n, rate, out) 57 let wr: i64 = wav_save("/tmp/song.wav" as *u8, out, tb) 58 w("rendered /tmp/song.wav bytes=" as *u8); wn(wr); w("\n" as *u8) 59 60 chk(wr == tb, pass, fail, "song.wav written fully" as *u8) 61 chk(tb == 44 + total_n * 4, pass, fail, "size = 44 + 7200*4" as *u8) 62 chk(song[0] == 0, pass, fail, "note 1 starts silent (ADSR attack)" as *u8) 63 chk(song[600] != 0, pass, fail, "note 1 sounding mid-attack" as *u8) 64 chk(song[nlen + 600] != 0, pass, fail, "note 2 (E4) sounding" as *u8) 65 chk(song[2 * nlen + 600] != 0, pass, fail, "note 3 (G4) sounding" as *u8) 66 67 w("=== VERDICT pass=" as *u8); wn(pass[0]); w(" fail=" as *u8); wn(fail[0]); w(" ===\n" as *u8) 68 if fail[0] == 0 { return 0 } 69 return 1 70}