main.bend
emerging-ezaudio@0.4.0.0 · 238 lines · 34 definitions
1
2
3
4
5
6import Base
7import emerging-ezaudio@0.4.0.0/src/wav.bend as Wav
8import emerging-ezaudio@0.4.0.0/src/mp3.bend as Mp3
9
10
11type Format is Data:
12 S16{}
13 Flt{}
14
15
16type Clip is Data:
17 Clip{hz: U32, nch: U32, fmt: Format, pcm: List<&2, U32>}
18
19
20def s16() -> Format:
21 S16{}
22
23
24def f32() -> Format:
25 Flt{}
26
27def kind.of(fmt: Format) -> U32:
28 match fmt:
29 case S16{}:
30 1
31 case Flt{}:
32 3
33
34def fmt.of(+kind: U32) -> Format:
35 match kind:
36 case 1:
37 S16{}
38 case _:
39 Flt{}
40
41def wav.clip(w: Wav.Wav) -> Clip:
42 match w:
43 case Wav.Wav{+rate, +channels, +kind, frames}:
44 Clip{rate, channels, fmt.of(kind), frames}
45
46def fmt.same(aa: Format, bb: Format) -> Bool:
47 match aa bb:
48 case S16{} S16{}:
49 True{}
50 case Flt{} Flt{}:
51 True{}
52 case S16{} Flt{}:
53 False{}
54 case Flt{} S16{}:
55 False{}
56
57
58def clip(+rate: U32, +channels: U32, format: Format, frames: List<&2, U32>) -> Clip:
59 Clip{rate, channels, format, frames}
60
61
62def rate(c: Clip) -> U32:
63 match c:
64 case Clip{+hz, _nch, _fmt, _pcm}:
65 hz
66
67
68def channels(c: Clip) -> U32:
69 match c:
70 case Clip{_hz, +nch, _fmt, _pcm}:
71 nch
72
73
74def format(c: Clip) -> Format:
75 match c:
76 case Clip{_hz, _nch, +fmt, _pcm}:
77 fmt
78
79
80def frames(c: Clip) -> List<&2, U32>:
81 match c:
82 case Clip{_hz, _nch, _fmt, +pcm}:
83 pcm
84
85def count.of(+channels: U32, +nsamples: U32) -> U32:
86 match channels:
87 case 0:
88 0
89 case _:
90 U32.div(nsamples, channels)
91
92
93def count(c: Clip) -> U32:
94 match c:
95 case Clip{_hz, +nch, _fmt, +pcm}:
96 count.of(nch, U32.from_nat(List.length(&2, U32, pcm)))
97
98
99def fill(+rate: U32, +channels: U32, format: Format, +sample: U32, +nframes: U32) -> Clip:
100 Clip{rate, channels, format, List.replicate(U32, U32.to_nat((nframes * channels : U32)), sample)}
101
102def ls.drop(hop: Nat, xs: List<&2, U32>) -> List<&2, U32>:
103 match hop:
104 case 0n:
105 xs
106 case 1n+p:
107 match xs:
108 case Nil{}:
109 []
110 case _hd <> tl:
111 ls.drop(p, tl)
112
113def ls.take(hop: Nat, xs: List<&2, U32>, acc: List<&2, U32>) -> List<&2, U32>:
114 match hop:
115 case 0n:
116 List.reverse(&2, U32, acc)
117 case 1n+p:
118 match xs:
119 case Nil{}:
120 List.reverse(&2, U32, acc)
121 case +hd <> tl:
122 ls.take(p, tl, hd <> acc)
123
124def ls.slice(xs: List<&2, U32>, +dropn: U32, +taken: U32) -> List<&2, U32>:
125 ls.take(U32.to_nat(taken), ls.drop(U32.to_nat(dropn), xs), [])
126
127def trim.go(
128 ok: Bool,
129 +rate: U32,
130 +channels: U32,
131 format: Format,
132 frames: List<&2, U32>,
133 +start: U32,
134 +nframes: U32
135) -> Maybe<&2, Clip>:
136 match ok:
137 case False{}:
138 None{}
139 case True{}:
140 Some{Clip{rate, channels, format,
141 ls.slice(frames, (start * channels : U32), (nframes * channels : U32))}}
142
143
144def trim(c: Clip, +start: U32, +nframes: U32) -> Maybe<&2, Clip>:
145 match c:
146 case Clip{+hz, +nch, fmt, +pcm}:
147 trim.go(U32.is_le((start + nframes : U32), count.of(nch, U32.from_nat(List.length(&2, U32, pcm)))), hz, nch,
148 fmt, pcm, start, nframes)
149
150def eq.all(ar: Bool, ac: Bool, af: Bool) -> Bool:
151 match ar:
152 case False{}:
153 False{}
154 case True{}:
155 match ac:
156 case False{}:
157 False{}
158 case True{}:
159 af
160
161def concat.go(
162 ok: Bool,
163 +rate: U32,
164 +channels: U32,
165 format: Format,
166 left: List<&2, U32>,
167 right: List<&2, U32>
168) -> Maybe<&2, Clip>:
169 match ok:
170 case False{}:
171 None{}
172 case True{}:
173 Some{Clip{rate, channels, format, List.append(&2, U32, left, right)}}
174
175def concat.pair(+rate: U32, +channels: U32, +format: Format, left: List<&2, U32>, other: Clip) -> Maybe<&2, Clip>:
176 match other:
177 case Clip{+rb, +cb, fb, right}:
178 concat.go(eq.all(U32.is_eq(rate, rb), U32.is_eq(channels, cb), fmt.same(format, fb)), rate, channels, format,
179 left, right)
180
181
182def concat(left: Clip, right: Clip) -> Maybe<&2, Clip>:
183 match left:
184 case Clip{+hz, +nch, +fmt, pcm}:
185 concat.pair(hz, nch, fmt, pcm, right)
186
187def list.empty(xs: List<&2, U32>) -> Bool:
188 match xs:
189 case Nil{}:
190 True{}
191 case _hd <> _tl:
192 False{}
193
194def wav.bytes(empty: Bool, +rate: U32, +channels: U32, +kind: U32, frames: List<&2, U32>) -> Maybe<&2, List<&2, U32>>:
195 match empty:
196 case True{}:
197 None{}
198 case False{}:
199 Wav.wav.write(rate, channels, kind, frames)
200
201def wav.parsed(got: Maybe<&2, Wav.Wav>) -> Maybe<&2, Clip>:
202 match got:
203 case None{}:
204 None{}
205 case Some{w}:
206 Some{wav.clip(w)}
207
208
209def decode_wav(xs: List<&2, U32>) -> Maybe<&2, Clip>:
210 wav.parsed(Wav.wav.parse(xs))
211
212
213def encode_wav(c: Clip) -> Maybe<&2, List<&2, U32>>:
214 match c:
215 case Clip{+hz, +nch, fmt, +pcm}:
216 wav.bytes(list.empty(pcm), hz, nch, kind.of(fmt), pcm)
217
218def mp3.clip(p: Mp3.Pcm) -> Clip:
219 match p:
220 case Mp3.Pcm{+hz, +ch, pcm}:
221 Clip{hz, ch, Flt{}, pcm}
222
223def mp3.parsed(got: Maybe<&2, Mp3.Pcm>) -> Maybe<&2, Clip>:
224 match got:
225 case None{}:
226 None{}
227 case Some{p}:
228 Some{mp3.clip(p)}
229
230
231def decode_mp3(xs: List<&2, U32>) -> Maybe<&2, Clip>:
232 mp3.parsed(Mp3.mp3.decode(xs))
233
234
235def encode_mp3(c: Clip) -> Maybe<&2, List<&2, U32>>:
236 match c:
237 case Clip{+hz, +nch, fmt, pcm}:
238 Mp3.mp3.encode(hz, nch, kind.of(fmt), pcm)