Skip to content

Commit dbc5723

Browse files
committed
FEAT: WAV codec updated (vector support)
Now loaded WAV sound data are as a vector instead of raw binary. WAV encoder was improved for vector data input. Example of simple sine WAV file generator: ``` samples: #[si16! 10000] repeat i 10000 [ samples/:i: 16000 * (sine i * 7.2) ] save %sine.wav samples ; by default mono with 44100Hz ```
1 parent 6512190 commit dbc5723

File tree

2 files changed

+79
-28
lines changed

2 files changed

+79
-28
lines changed

src/mezz/codec-wav.r

+67-26
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ REBOL [
22
title: "REBOL 3 codec for WAV file format"
33
name: 'codec-WAV
44
author: "Oldes"
5-
version: 0.1.0
6-
date: 11-Oct-2018
5+
version: 0.2.0
6+
date: 2-Mar-2020
77
history: [
88
0.1.0 11-Oct-2018 "Oldes" {
99
Initial version with DECODE and IDENTIFY functions.
10-
Not all chunks are parsed.
11-
}
10+
Not all chunks are parsed.}
11+
0.2.0 2-Mar-2020 "Oldes" {
12+
Sound data are now as a vector! instead of raw binary!
13+
Support for encoding wav data.}
1214
]
1315
]
1416

@@ -148,44 +150,85 @@ register-codec [
148150
channels: (format/2)
149151
bits: (format/6)
150152
chunks: (chunks)
151-
data: (either empty? data [none][rejoin data])
153+
data: (either empty? data [none][make vector! reduce ['integer! format/6 rejoin data]])
152154
]
153155
]
154156
]
155157

156158
encode: function [
157-
spec [object!]
159+
spec [object! vector!]
158160
][
159-
if 'wave <> select spec 'type [ return none ]
160-
out: binary (128 + length? spec/data)
161-
binary/write out [
162-
#{52494646 00000000 57415645}
161+
case [
162+
vector? spec [
163+
bitsPerSample: spec/size
164+
data: to binary! spec
165+
spec: []
166+
]
167+
vector? spec/data [
168+
bitsPerSample: spec/data/size
169+
data: to binary! spec/data
170+
]
171+
binary? spec/data [
172+
bitsPerSample: select spec 'bits
173+
data: spec/data
174+
]
175+
'else [
176+
print "*** Unsupported data!"
177+
return none
178+
]
163179
]
164-
165-
index: index? spec/data ; stores original data position
166180

167-
foreach [tag value] spec/chunks [
181+
out: binary (128 + length? data)
182+
binary/write out [ #{52494646 00000000 57415645} ]
183+
184+
if bitsPerSample [blockAlign: bitsPerSample / 8]
185+
chunks: select spec 'chunks
186+
187+
unless chunks [
188+
;- creates main WAV chunks (format & data length) if not provided by user
189+
channels: any [select spec 'channels 1]
190+
sampleRate: any [select spec 'rate 44100]
191+
bitsPerSample: any [bitsPerSample 16]
192+
blockAlign: bitsPerSample / 8
193+
194+
chunks: reduce [
195+
<fmt > reduce [
196+
1
197+
channels
198+
sampleRate
199+
(channels * sampleRate * blockAlign) ; bytesPerSec
200+
blockAlign
201+
bitsPerSample
202+
]
203+
<data> length? data
204+
]
205+
]
206+
207+
foreach [tag value] chunks [
168208
switch tag [
169209
<fmt > [
170210
binary/write out reduce [
171211
'BYTES "fmt "
172-
'UI32LE 16 + length? value/7
173-
'UI16LE value/1 ; compression
174-
'UI16LE value/2 ; channels
175-
'UI32LE value/3 ; sampleRate
176-
'UI32LE value/4 ; bytesPerSec
177-
'UI16LE value/5 ; blockAlign
178-
'UI16LE value/6 ; bitsPerSample
179-
'BYTES value/7
212+
'UI32LE 16 + any [length? value/7 0]
213+
'UI16LE value/1 ; compression
214+
'UI16LE value/2 ; channels
215+
'UI32LE value/3 ; sampleRate
216+
'UI32LE value/4 ; bytesPerSec
217+
'UI16LE value/2 * any [blockAlign value/5] ; uses real values where possible
218+
'UI16LE any [bitsPerSample value/6]
219+
'BYTES any [value/7 #{}]
180220
]
181221
]
182222
<data> [
223+
; not using `value` directly as a reported length, because it can be wrong.
224+
value: copy/part data value
225+
bytes: length? value
183226
binary/write out reduce [
184227
'BYTES "data"
185-
'UI32LE value
186-
'BYTES copy/part spec/data value
228+
'UI32LE bytes
229+
'BYTES value
187230
]
188-
spec/data: skip spec/data value
231+
data: skip data bytes
189232
]
190233
<fact> [
191234
value: to binary! value
@@ -198,8 +241,6 @@ register-codec [
198241
]
199242
]
200243

201-
spec/data: at head spec/data index ;resets the data series to original position
202-
203244
bytes: (length? out/buffer) - 8
204245
binary/write out reduce ['at 5 'UI32LE bytes]
205246
out/buffer

src/tests/units/codecs-test.r3

+12-2
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,24 @@ if find codecs 'wav [
7777
--assert 44100 = snd/rate
7878
--assert 1 = snd/channels
7979
--assert 16 = snd/bits
80-
--assert 3097828 = checksum snd/data
80+
--assert 3097828 = checksum to-binary snd/data
8181
snd: none
8282
--test-- "Decode WAV data"
8383
--assert binary? bin: read %units/files/zblunk_02.wav
8484
--assert object? snd: decode 'WAV bin
85-
--assert 4283614 = checksum snd/data
85+
--assert 4283614 = checksum to-binary snd/data
8686
snd: none
8787
bin: none
88+
89+
--test-- "Encode WAV"
90+
samples: #[si16! [0 -1000 -2000 -1000 0 1000 2000 1000 0]]
91+
--assert binary? bin: encode 'wav :samples
92+
--assert object? snd: decode 'wav :bin
93+
--assert 'wave = snd/type
94+
--assert 44100 = snd/rate
95+
--assert 1 = snd/channels
96+
--assert 16 = snd/bits
97+
--assert samples = snd/data
8898

8999
===end-group===
90100
codecs/wav/verbose: 0

0 commit comments

Comments
 (0)