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}