1
+ REBOL [
2
+ title: "REBOL 3 codec for WAV file format"
3
+ name: 'codec-WAV
4
+ author: "Oldes"
5
+ version: 0.1.0
6
+ date: 11-Oct-2018
7
+ history: [
8
+ 0.1.0 11-Oct-2018 "Oldes" {
9
+ Initial version with DECODE and IDENTIFY functions.
10
+ Not all chunks are parsed.
11
+ }
12
+ ]
13
+ ]
14
+
15
+ register-codec [
16
+ name: 'WAV
17
+ title: "Waveform Audio File Format"
18
+ suffixes: [%.wav %.wave ]
19
+
20
+ decode : function [
21
+ data [binary! ]
22
+ ] [
23
+ if verbose > 0 [
24
+ print ["^[ [1;32mDecode WAV data^[ [m (^[ [1m" length? data "^[ [mbytes )" ]
25
+ ; count maximal bytes width (used for padding)
26
+ w: 1 + length? form length? data
27
+ ]
28
+
29
+ bin: binary data
30
+ binary/read bin [
31
+ chunkId: BYTES 4
32
+ chunkSize: UI32LE
33
+ format: BYTES 4
34
+ ]
35
+
36
+ if all [
37
+ chunkId = #{ 52494646 } ;RIFF
38
+ format = #{ 57415645 } ;WAVE
39
+ ][
40
+ ; looks like valid WAVE file
41
+ data: copy []
42
+ chunks: copy []
43
+
44
+ while [not tail? bin/buffer ][
45
+ binary/read bin [
46
+ id: BYTES 4
47
+ size: UI32LE
48
+ starts: INDEX
49
+ ]
50
+ ends: starts + size
51
+ chunk: any [ try [to tag! id] id ]
52
+ if verbose > 0 [
53
+ printf [
54
+ $32
55
+ "CHUNK: " $1 7 $0
56
+ "at: " $1 w $0
57
+ "bytes: " $1 w $0
58
+ ] reduce [mold chunk starts size]
59
+ ]
60
+ append chunks chunk
61
+ switch /default chunk [
62
+ <fmt > [
63
+ format: binary/read bin [
64
+ UI16LE ; compression
65
+ UI16LE ; channels
66
+ UI32LE ; sampleRate
67
+ UI32LE ; bytesPerSec
68
+ UI16LE ; blockAlign
69
+ UI16LE ; bitsPerSample
70
+ ]
71
+ if size > 16 [
72
+ size: size - 16
73
+ append format copy/part bin/buffer size
74
+ bin/buffer: skip bin/buffer size
75
+ ]
76
+ append /only chunks format
77
+ ]
78
+ <data > [
79
+ binary/read/into bin [BYTES :size ] tail data
80
+ append chunks size ; so one could reconstruct the data chunk in encoding
81
+ ]
82
+ <smpl > [
83
+ sampler: binary/read bin [
84
+ UI32LE ; Manufacturer
85
+ UI32LE ; Product
86
+ UI32LE ; Sample Period
87
+ UI32LE ; MIDI Unity Note
88
+ UI32LE ; MIDI Pitch Fraction
89
+ UI32LE ; SMPTE Format
90
+ UI32LE ; SMPTE Offset
91
+ count: UI32LE ; Num Sample Loops
92
+ UI32LE ; Sampler Data
93
+ ]
94
+ append /only sampler loops: copy []
95
+ loop count [
96
+ binary/read/into bin [
97
+ UI32LE ; Cue Point ID
98
+ UI32LE ; Type
99
+ UI32LE ; Start
100
+ UI32LE ; End
101
+ UI32LE ; Fraction
102
+ UI32LE ; Play Count
103
+ ] loops
104
+ ]
105
+ append /only chunks sampler
106
+ ]
107
+ <fact > [
108
+ binary/read/into bin [BYTES :size ] tail chunks
109
+ ]
110
+ <cue > [
111
+ count: binary/read bin 'UI32LE
112
+ append chunks cues: copy []
113
+ loop count [
114
+ binary/read/into bin [
115
+ UI32LE ; id - unique identification value
116
+ UI32LE ; Position - play order position
117
+ UI32LE ; Data Chunk ID - RIFF ID of corresponding data chunk
118
+ UI32LE ; Chunk Start - Byte Offset of Data Chunk *
119
+ UI32LE ; Block Start - Byte Offset to sample of First Channel
120
+ UI32LE ; Sample Offset - Byte Offset to sample byte of First Channel
121
+ ] tail cues
122
+ ]
123
+ new-line /skip cues true 6
124
+ ]
125
+ <_PMX > [
126
+ ; Extensible Metadata Platform (XMP) data
127
+ ;@@ https://www.adobe.com/products/xmp.html
128
+ binary/read bin [tmp: BYTES :size ]
129
+ try [tmp: to string! tmp]
130
+ append chunks tmp
131
+ if verbose > 1 [printf [$33 tmp $0] "" ]
132
+ ]
133
+ ][
134
+ binary/read/into bin [BYTES :size ] tail chunks
135
+ ]
136
+ if ends <> index? bin/buffer [
137
+ cause-error 'script 'bad-bad ["WAV decode" "invalid chunk end" ]
138
+ ]
139
+ ]
140
+ ]
141
+ either any [empty? chunks none? format] [
142
+ none
143
+ ][
144
+ new-line /skip chunks true 2
145
+ object compose /only [
146
+ type: 'wave
147
+ rate: (format/3 )
148
+ channels: (format/2 )
149
+ bits: (format/6 )
150
+ chunks: (chunks)
151
+ data: (either empty? data [none][rejoin data])
152
+ ]
153
+ ]
154
+ ]
155
+ identify : func [
156
+ "Returns TRUE if binary looks like WAV data"
157
+ data [binary! ]
158
+ ] [
159
+ parse data [#{ 52494646 } 4 skip #{ 57415645 } to end]
160
+ ]
161
+
162
+ verbose: 0
163
+ ]
0 commit comments