code wiki / _hdl_build / nx_mp3_fixture.nx
nx_mp3_fixture.nx source
↩ module page · 50 lines · 3312 B
1// nx_mp3_fixture.nx -- write a tiny sovereign DRM-free MP3 with an ID3v2.3 tag (TIT2 title, TPE1 artist/narrator,
2// TALB album) + a minimal MP3 audio frame, so the audio->.nmz rung can be gated end-to-end (nx_audio_book parses
3// the ID3 metadata + carries the audio bytes -> .nmz @kind=audio). ID3v2.3: 10-byte header ("ID3" ver flags
4// syncsafe-size) then frames (id(4) plain-BE-size(4) flags(2) enc(1) text). expect_exit: 0 license_tier: ORIGINAL
5import "nx_syscalls.nx"
6const K_MAGIC_8859: i64 = 8859
7const K_MAGIC_8192: i64 = 8192
8
9func mf_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
10func mf_p(s: *u8) -> i64 { sys_write(1, s, mf_slen(s)); return 0 }
11func mf_n(v: i64) -> i64 { let b: *u8=sys_mmap(24); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(24); var k: i64=0; if m==0{t[0]=48 as u8;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1}; sys_write(1,b,k); return 0 }
12func ensure_dir(path: *u8) -> i64 { __syscall(258, 0-100, path, 0x1ed, 0, 0, 0); return 0 }
13func put32be(m: *u8, o: i64, v: i64) -> i64 { m[o]=((v>>24)&0xff) as u8; m[o+1]=((v>>16)&0xff) as u8; m[o+2]=((v>>8)&0xff) as u8; m[o+3]=(v&0xff) as u8; return o+4 }
14func puts(m: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ m[o+i]=s[i]; i=i+1 } return o+i }
15
16// emit one ID3v2.3 text frame: id(4) + plain-BE size(4) + flags(2)=0 + encoding(0=ISO-8859-1) + text. ret new off.
17func text_frame(m: *u8, o: i64, id: *u8, text: *u8) -> i64 {
18 var p: i64 = puts(m, o, id)
19 let tn: i64 = mf_slen(text)
20 let dlen: i64 = 1 + tn // encoding byte + text
21 p = put32be(m, p, dlen)
22 m[p]=0 as u8; m[p+1]=0 as u8; p=p+2 // frame flags
23 m[p]=0 as u8; p=p+1 // text encoding = ISO-K_MAGIC_8859-1
24 p = puts(m, p, text)
25 return p
26}
27
28func main() -> i64 {
29 ensure_dir("knowledge/fixtures" as *u8)
30 let m: *u8 = sys_mmap(K_MAGIC_8192)
31 m[0]=0x49 as u8; m[1]=0x44 as u8; m[2]=0x33 as u8 // "ID3"
32 m[3]=0x03 as u8; m[4]=0x00 as u8 // v2.3.0
33 m[5]=0x00 as u8 // flags
34 var o: i64 = 10
35 o = text_frame(m, o, "TIT2" as *u8, "The Hobbit (Nishi Audio Fixture)" as *u8)
36 o = text_frame(m, o, "TPE1" as *u8, "J.R.R. Tolkien" as *u8)
37 o = text_frame(m, o, "TALB" as *u8, "Middle-earth Audiobook" as *u8)
38 let framebytes: i64 = o - 10
39 // ID3v2 header size is SYNCSAFE (7 bits per byte)
40 m[6]=((framebytes>>21)&0x7f) as u8; m[7]=((framebytes>>14)&0x7f) as u8; m[8]=((framebytes>>7)&0x7f) as u8; m[9]=(framebytes&0x7f) as u8
41 // minimal MP3 audio frame after the tag (0xFF 0xFB = MPEG1 Layer III sync) + a little data
42 m[o]=0xff as u8; m[o+1]=0xfb as u8; m[o+2]=0x90 as u8; m[o+3]=0x64 as u8; o=o+4
43 var z: i64=0; while z<28 { m[o]=0x00 as u8; o=o+1; z=z+1 }
44
45 let fd: i64 = sys_openat_wr("knowledge/fixtures/nishi_audio.mp3" as *u8, 0x1a4)
46 if fd < 0 { mf_p("MP3-FIXTURE-FAIL open\n" as *u8); sys_exit(1); return 1 }
47 sys_write(fd, m, o); sys_close(fd)
48 mf_p("MP3-FIXTURE bytes=" as *u8); mf_n(o); mf_p(" id3_framebytes=" as *u8); mf_n(framebytes); mf_p(" -> knowledge/fixtures/nishi_audio.mp3\n" as *u8)
49 mf_p("MP3-FIXTURE-OK\n" as *u8); sys_exit(0); return 0
50}