1 ! Copyright (C) 2007 Adam Wendt.
2 ! See http://factorcode.org/license.txt for BSD license.
4 USING: arrays combinators io io.binary io.files io.paths
5 io.encodings.utf16 kernel math math.parser namespaces sequences
6 splitting strings assocs unicode.categories io.encodings.binary ;
10 TUPLE: tag header frames ;
13 TUPLE: header version revision flags size extended-header ;
16 TUPLE: frame id size flags data ;
19 TUPLE: extended-header size flags update crc restrictions ;
20 C: <extended-header> extended-header
22 : debug-stream ( msg -- )
23 ! global [ . flush ] bind ;
26 : >hexstring ( str -- hex )
27 >array [ >hex 2 CHAR: 0 pad-left ] map concat ;
29 : good-frame-id? ( id -- ? )
30 [ [ LETTER? ] keep digit? or ] all? ;
32 ! 4 byte syncsafe integer (28 effective bits)
33 : >syncsafe ( seq -- int )
34 0 [ >r 7 shift r> bitor ] reduce ;
36 : read-size ( -- size )
39 : read-frame-id ( -- id )
42 : read-frame-flags ( -- flags )
45 : read-frame-size ( -- size )
48 : text-frame? ( id -- ? )
51 : read-text ( size -- text )
52 read1 swap 1 - read swap 1 = [ decode-utf16 ] [ ] if
53 "\0" ?tail drop ; ! remove null terminator
55 : read-popm ( size -- popm )
58 : read-frame-data ( id size -- data )
61 { [ dup text-frame? ] [ drop read-text ] }
62 { [ "POPM" = ] [ read-popm ] }
66 : (read-frame) ( id -- frame )
67 read-frame-size read-frame-flags 2over read-frame-data <frame> ;
69 : read-frame ( -- frame/f )
70 read-frame-id dup good-frame-id? [ (read-frame) ] [ drop f ] if ;
72 : (read-frames) ( vector -- frames )
73 read-frame [ over push (read-frames) ] when* ;
75 : read-frames ( -- frames )
76 V{ } clone (read-frames) ;
78 : read-eh-flags ( -- flags )
81 : read-eh-data ( size -- data )
84 : read-crc ( flags -- crc )
85 5 bit? [ read1 read >syncsafe ] [ f ] if ;
87 : tag-is-update? ( flags -- ? )
88 6 bit? dup [ read1 drop ] [ ] if ;
90 : (read-tag-restrictions) ( -- restrictions )
93 : read-tag-restrictions ( flags -- restrictions/f )
94 4 bit? [ (read-tag-restrictions) ] [ f ] if ;
96 : (read-extended-header) ( -- extended-header )
97 read-size read-eh-flags dup tag-is-update? over dup
98 read-crc swap read-tag-restrictions <extended-header> ;
100 : read-extended-header ( flags -- extended-header/f )
101 6 bit? [ (read-extended-header) ] [ f ] if ;
103 : read-header ( version -- header )
104 read1 read1 read-size over read-extended-header <header> ;
106 : (read-id3v2) ( version -- tag )
107 read-header read-frames <tag> ;
109 : supported-version? ( version -- ? )
112 : read-id3v2 ( -- tag/f )
113 read1 dup supported-version?
114 [ (read-id3v2) ] [ drop f ] if ;
117 3 read "ID3" sequence= ;
119 : read-tag ( stream -- tag/f )
120 id3v2? [ read-id3v2 ] [ f ] if ;
122 : id3v2 ( filename -- tag/f )
123 binary [ read-tag ] with-file-reader ;
125 : file? ( path -- ? )
128 : files ( paths -- files )
134 : mp3s ( paths -- mp3s )
138 binary [ id3v2? ] with-file-reader ;
140 : id3s ( files -- id3s )