1 ! (c)2009 Joe Groff bsd license
2 USING: accessors alien alien.c-types alien.data audio
3 audio.chunked-file classes.struct combinators
4 combinators.short-circuit endian io io.binary
5 io.encodings.binary io.files kernel locals math sequences
9 CONSTANT: FORM-MAGIC "FORM"
10 CONSTANT: AIFF-MAGIC "AIFF"
11 CONSTANT: COMM-MAGIC "COMM"
12 CONSTANT: SSND-MAGIC "SSND"
14 STRUCT: aiff-chunk-header
19 { header aiff-chunk-header }
20 { form-type char[4] } ;
23 { header aiff-chunk-header }
24 { num-channels uchar[2] }
25 { num-sample-frames uchar[4] }
26 { sample-size uchar[2] }
27 { sample-rate uchar[10] } ;
29 STRUCT: sound-data-chunk
30 { header aiff-chunk-header }
32 { block-size uchar[4] }
33 { waveform-data uchar[0] } ;
35 ! cheesy long-double>integer converter that assumes the long double is a positive integer
36 : sample-rate>integer ( byte[10] -- sample-rate )
38 [ 2 head-slice be> 16383 - 63 - ] bi shift ;
40 : read-form-chunk ( -- byte-array/f )
41 form-chunk heap-size ensured-read* ;
43 : verify-aiff ( chunk -- )
46 [ form-chunk memory>struct form-type>> 4 memory>byte-array AIFF-MAGIC id= ]
48 [ invalid-audio-file ] unless ;
50 :: read-aiff-chunks ( -- comm ssnd )
52 [ { [ comm ssnd and not ] [ read-chunk ] } 0&& dup ]
55 [ dup COMM-MAGIC common-chunk check-chunk ]
56 [ common-chunk memory>struct comm! ]
59 [ dup SSND-MAGIC sound-data-chunk check-chunk ]
60 [ sound-data-chunk memory>struct ssnd! ]
64 comm ssnd 2dup and [ invalid-audio-file ] unless ;
66 : (read-aiff) ( -- audio )
69 [ num-channels>> 2 memory>byte-array be> ]
70 [ sample-size>> 2 memory>byte-array be> ]
71 [ sample-rate>> sample-rate>integer ] tri
73 [ header>> size>> 4 memory>byte-array be> 8 - dup ]
74 [ waveform-data>> >c-ptr ] bi swap memory>byte-array
76 <audio> convert-data-endian ;
78 : read-aiff ( filename -- audio )
81 read-form-chunk verify-aiff (read-aiff)
85 "aif" [ read-aiff ] register-audio-extension
86 "aiff" [ read-aiff ] register-audio-extension