nx_audio_wav.nx source
↩ module page · 76 lines · 2853 B
1// nx_audio_wav.nx -- SOVEREIGN AUDIO ENGINE rung R4: render to a real .wav file.
2//
3// Makes the engine produce a PLAYABLE artifact (the live-testable principle for
4// audio: the file is the proof). WAV/RIFF is a STANDARD format -> sovereign
5// implementation, proven byte-exact vs the spec in the gate (per the non-novel
6// verification doctrine). 16-bit PCM, little-endian, interleaved stereo. Only
7// % and / used (no reliance on bitwise). license_tier: ORIGINAL.
8
9import "nx_syscalls.nx"
10const K_MAGIC_65536: i64 = 65536
11const K_MAGIC_16777216: i64 = 16777216
12
13// little-endian writers (header values are non-negative)
14func wav_put_u32(buf: *u8, off: i64, v: i64) -> i64 {
15 buf[off] = (v % 256) as u8
16 buf[off + 1] = ((v / 256) % 256) as u8
17 buf[off + 2] = ((v / K_MAGIC_65536) % 256) as u8
18 buf[off + 3] = ((v / K_MAGIC_16777216) % 256) as u8
19 return 0
20}
21func wav_put_u16(buf: *u8, off: i64, v: i64) -> i64 {
22 buf[off] = (v % 256) as u8
23 buf[off + 1] = ((v / 256) % 256) as u8
24 return 0
25}
26// signed 16-bit sample (handles negatives by wrapping into 0..65535 first)
27func wav_put_i16(buf: *u8, off: i64, v: i64) -> i64 {
28 let u: i64 = ((v % K_MAGIC_65536) + K_MAGIC_65536) % K_MAGIC_65536
29 buf[off] = (u % 256) as u8
30 buf[off + 1] = ((u / 256) % 256) as u8
31 return 0
32}
33func wav_put_str(buf: *u8, off: i64, s: *u8) -> i64 {
34 var i: i64 = 0
35 while s[i] != (0 as u8) { buf[off + i] = s[i]; i = i + 1 }
36 return i
37}
38
39// render n frames of 16-bit interleaved stereo WAV into out; returns total bytes
40func wav_render_stereo(L: *i64, R: *i64, n: i64, rate: i64, out: *u8) -> i64 {
41 let channels: i64 = 2
42 let bits: i64 = 16
43 let block_align: i64 = channels * (bits / 8) // 4
44 let byte_rate: i64 = rate * block_align
45 let data_size: i64 = n * block_align
46 wav_put_str(out, 0, "RIFF" as *u8)
47 wav_put_u32(out, 4, 36 + data_size)
48 wav_put_str(out, 8, "WAVE" as *u8)
49 wav_put_str(out, 12, "fmt " as *u8)
50 wav_put_u32(out, 16, 16) // fmt chunk size
51 wav_put_u16(out, 20, 1) // PCM
52 wav_put_u16(out, 22, channels)
53 wav_put_u32(out, 24, rate)
54 wav_put_u32(out, 28, byte_rate)
55 wav_put_u16(out, 32, block_align)
56 wav_put_u16(out, 34, bits)
57 wav_put_str(out, 36, "data" as *u8)
58 wav_put_u32(out, 40, data_size)
59 var off: i64 = 44
60 var i: i64 = 0
61 while i < n {
62 wav_put_i16(out, off, L[i]); off = off + 2
63 wav_put_i16(out, off, R[i]); off = off + 2
64 i = i + 1
65 }
66 return off
67}
68
69func wav_save(path: *u8, buf: *u8, len: i64) -> i64 {
70 let fd: i64 = sys_openat_wr(path, 420)
71 if fd < 0 { return 0 - 1 }
72 var wr: i64 = 0
73 while wr < len { let c: i64 = sys_write(fd, buf + wr, len - wr); if c <= 0 { break } wr = wr + c }
74 sys_close(fd)
75 return wr
76}