src/mp3_syn.bend
emerging-ezaudio@0.4.0.0 · 1,661 lines · 0 definitions
1# MPEG-1 Layer III synthesis: antialias, IMDCT-36, sign flip, DCT-II, polyphase.
2import Base
3import emerging-ezaudio@0.4.0.0/src/mp3_tab.bend as Tab
4import emerging-ezaudio@0.4.0.0/src/mp3_enc.bend as Enc
5
6# add two binary32 values
7def f.add(+aa: F32, +bb: F32) -> F32:
8 (aa + bb : F32)
9
10# subtract two binary32 values
11def f.sub(+aa: F32, +bb: F32) -> F32:
12 (aa - bb : F32)
13
14# multiply two binary32 values
15def f.mul(+aa: F32, +bb: F32) -> F32:
16 (aa * bb : F32)
17
18# sample at an index, or 0 past the end
19def f.at(+xs: List<&2, F32>, +ii: U32) -> F32:
20 Enc.f.nth(xs, ii)
21
22# replace one sample
23def f.set(xs: List<&2, F32>, +ii: U32, +vv: F32) -> List<&2, F32>:
24 Enc.f.put(xs, ii, vv)
25
26# unsigned add
27def u.add(+aa: U32, +bb: U32) -> U32:
28 (aa + bb : U32)
29
30# unsigned subtract
31def u.sub(+aa: U32, +bb: U32) -> U32:
32 (aa - bb : U32)
33
34# unsigned multiply
35def u.mul(+aa: U32, +bb: U32) -> U32:
36 (aa * bb : U32)
37
38# low bit
39def u.and(+kk: U32) -> U32:
40 (kk .&. 1 : U32)
41
42# 0.5
43def c.half() -> F32:
44 Enc.f32.bits(1056964608)
45
46# 0.93969262
47def c.c939() -> F32:
48 Enc.f32.bits(1064341426)
49
50# 0.76604444
51def c.c766() -> F32:
52 Enc.f32.bits(1061428093)
53
54# 0.17364818
55def c.c173() -> F32:
56 Enc.f32.bits(1043452116)
57
58# 0.86602540
59def c.c866() -> F32:
60 Enc.f32.bits(1063105495)
61
62# 0.98480775
63def c.c984() -> F32:
64 Enc.f32.bits(1065098332)
65
66# 0.34202014
67def c.c342() -> F32:
68 Enc.f32.bits(1051663684)
69
70# 0.64278761
71def c.c642() -> F32:
72 Enc.f32.bits(1059360187)
73
74# 0.70710677
75def c.c707() -> F32:
76 Enc.f32.bits(1060439283)
77
78# 0.198912367
79def c.c198() -> F32:
80 Enc.f32.bits(1045147567)
81
82# 0.382683432
83def c.c382() -> F32:
84 Enc.f32.bits(1053028117)
85
86# 0.50979561
87def c.c509() -> F32:
88 Enc.f32.bits(1057128951)
89
90# 0.54119611
91def c.c541() -> F32:
92 Enc.f32.bits(1057655764)
93
94# 0.60134488
95def c.c601() -> F32:
96 Enc.f32.bits(1058664893)
97
98# 0.89997619
99def c.c899() -> F32:
100 Enc.f32.bits(1063675095)
101
102# 1.30656302
103def c.c130() -> F32:
104 Enc.f32.bits(1067924853)
105
106# 2.56291556
107def c.c256() -> F32:
108 Enc.f32.bits(1076102863)
109
110# 1/32768, the polyphase scale
111def c.inv() -> F32:
112 Enc.f32.bits(939524096)
113
114# drop a prefix
115def ls.drop(hop: Nat, xs: List<&2, F32>) -> List<&2, F32>:
116 match hop xs:
117 case 0n ys:
118 ys
119 case _ Nil{}:
120 []
121 case 1n+p _hd <> tl:
122 ls.drop(p, tl)
123
124# take a prefix, reversed into acc
125def ls.take(hop: Nat, xs: List<&2, F32>, acc: List<&2, F32>) -> List<&2, F32>:
126 match hop xs:
127 case 0n _:
128 List.reverse(&2, F32, acc)
129 case _ Nil{}:
130 List.reverse(&2, F32, acc)
131 case 1n+p +hd <> tl:
132 ls.take(p, tl, hd <> acc)
133
134# a slice of length hop starting at an index
135def ls.slice(+xs: List<&2, F32>, +at: U32, hop: Nat) -> List<&2, F32>:
136 ls.take(hop, ls.drop(U32.to_nat(at), xs), [])
137
138# write a short list over a destination starting at an index
139def ls.poke(hop: Nat, dst: List<&2, F32>, src: List<&2, F32>, +at: U32) -> List<&2, F32>:
140 match hop src:
141 case 0n _:
142 dst
143 case _ Nil{}:
144 dst
145 case 1n+p +hd <> tl:
146 ls.poke(p, f.set(dst, at, hd), tl, u.add(at, 1))
147
148# nine samples, index 0 first
149def cs.pack(
150 +v0: F32, +v1: F32, +v2: F32, +v3: F32, +v4: F32, +v5: F32, +v6: F32, +v7: F32, +v8: F32
151) -> List<&2, F32>:
152 v0 <> (v1 <> (v2 <> (v3 <> (v4 <> (v5 <> (v6 <> (v7 <> (v8 <> []))))))))
153
154# cosine half of one IMDCT-36 band
155def cs.co(+gg: List<&2, F32>) -> List<&2, F32>:
156 cs.pack(F32.neg(f.at(gg, 0)), f.add(f.at(gg, 1), f.at(gg, 2)),
157 F32.neg(f.add(f.at(gg, 3), f.at(gg, 4))), f.add(f.at(gg, 5), f.at(gg, 6)),
158 F32.neg(f.add(f.at(gg, 7), f.at(gg, 8))), f.add(f.at(gg, 9), f.at(gg, 10)),
159 F32.neg(f.add(f.at(gg, 11), f.at(gg, 12))), f.add(f.at(gg, 13), f.at(gg, 14)),
160 F32.neg(f.add(f.at(gg, 15), f.at(gg, 16))))
161
162# sine half of one IMDCT-36 band
163def cs.si(+gg: List<&2, F32>) -> List<&2, F32>:
164 cs.pack(f.at(gg, 17), f.sub(f.at(gg, 16), f.at(gg, 15)), f.sub(f.at(gg, 13), f.at(gg, 14)),
165 f.sub(f.at(gg, 12), f.at(gg, 11)), f.sub(f.at(gg, 9), f.at(gg, 10)),
166 f.sub(f.at(gg, 8), f.at(gg, 7)), f.sub(f.at(gg, 5), f.at(gg, 6)),
167 f.sub(f.at(gg, 4), f.at(gg, 3)), f.sub(f.at(gg, 1), f.at(gg, 2)))
168
169# even-part sum used by the 9-point DCT
170def d9.t0(+y0: F32, +y6: F32) -> F32:
171 f.add(y0, f.mul(y6, c.half()))
172
173# even-part difference
174def d9.s0(+y0: F32, +y6: F32) -> F32:
175 f.sub(y0, y6)
176
177# twiddle on bins 4 and 2
178def d9.t4(+y4: F32, +y2: F32) -> F32:
179 f.mul(f.add(y4, y2), c.c939())
180
181# twiddle on bins 8 and 2
182def d9.t2(+y8: F32, +y2: F32) -> F32:
183 f.mul(f.add(y8, y2), c.c766())
184
185# twiddle on bins 4 and 8
186def d9.s6(+y4: F32, +y8: F32) -> F32:
187 f.mul(f.sub(y4, y8), c.c173())
188
189# even residual
190def d9.s4(+y4: F32, +y8: F32, +y2: F32) -> F32:
191 f.sub(f.add(y4, y8), y2)
192
193# scaled residual
194def d9.s2(+s0: F32, +s4: F32) -> F32:
195 f.sub(s0, f.mul(s4, c.half()))
196
197# centre bin of the even DCT
198def d9.y4(+s4: F32, +s0: F32) -> F32:
199 f.add(s4, s0)
200
201# high even output
202def d9.s8c(+t0: F32, +t2: F32, +s6: F32) -> F32:
203 f.add(f.sub(t0, t2), s6)
204
205# low even output
206def d9.s0c(+t0: F32, +t4: F32, +t2: F32) -> F32:
207 f.add(f.sub(t0, t4), t2)
208
209# mid even output
210def d9.s4c(+t0: F32, +t4: F32, +s6: F32) -> F32:
211 f.sub(f.add(t0, t4), s6)
212
213# odd centre
214def d9.s3(+y3: F32) -> F32:
215 f.mul(y3, c.c866())
216
217# odd low twiddle
218def d9.tb0(+y5: F32, +y1: F32) -> F32:
219 f.mul(f.add(y5, y1), c.c984())
220
221# odd high twiddle
222def d9.tb4(+y5: F32, +y7: F32) -> F32:
223 f.mul(f.sub(y5, y7), c.c342())
224
225# odd mid twiddle
226def d9.tb2(+y1: F32, +y7: F32) -> F32:
227 f.mul(f.add(y1, y7), c.c642())
228
229# odd residual
230def d9.s1(+y1: F32, +y5: F32, +y7: F32) -> F32:
231 f.mul(f.sub(f.sub(y1, y5), y7), c.c866())
232
233# odd combination
234def d9.s5c(+t0: F32, +s3: F32, +t2: F32) -> F32:
235 f.sub(f.sub(t0, s3), t2)
236
237# odd combination
238def d9.s7c(+t4: F32, +s3: F32, +t0: F32) -> F32:
239 f.sub(f.sub(t4, s3), t0)
240
241# odd combination
242def d9.s3c(+t4: F32, +s3: F32, +t2: F32) -> F32:
243 f.sub(f.add(t4, s3), t2)
244
245# even and odd 9-point DCT results, ready to interleave
246type D9 is Data:
247 D9{
248 s2b: F32, y4o: F32, s8c: F32, s0c: F32, s4c: F32, s1b: F32, s5c: F32, s7c: F32, s3c: F32
249 }
250
251# assemble the nine DCT outputs from the even and odd parts
252def d9.from(
253 +t0: F32, +s0: F32, +t4: F32, +t2: F32, +s6: F32, +s4: F32, +s3: F32, +u0: F32, +u4: F32,
254 +u2: F32, +s1: F32
255) -> D9:
256 D9{d9.s2(s0, s4), d9.y4(s4, s0), d9.s8c(t0, t2, s6), d9.s0c(t0, t4, t2), d9.s4c(t0, t4, s6), s1,
257 d9.s5c(u0, s3, u2), d9.s7c(u4, s3, u0), d9.s3c(u4, s3, u2)}
258
259# 9-point DCT of one half
260def d9.build(
261 +y0: F32, +y1: F32, +y2: F32, +y3: F32, +y4: F32, +y5: F32, +y6: F32, +y7: F32, +y8: F32
262) -> D9:
263 d9.from(d9.t0(y0, y6), d9.s0(y0, y6), d9.t4(y4, y2), d9.t2(y8, y2), d9.s6(y4, y8),
264 d9.s4(y4, y8, y2), d9.s3(y3), d9.tb0(y5, y1), d9.tb4(y5, y7), d9.tb2(y1, y7), d9.s1(y1, y5, y7))
265
266# nine DCT outputs in bin order
267def d9.list(dd: D9) -> List<&2, F32>:
268 match dd:
269 case D9{+s2b, +y4o, +s8c, +s0c, +s4c, +s1b, +s5c, +s7c, +s3c}:
270 cs.pack(f.sub(s4c, s7c), f.add(s2b, s1b), f.sub(s0c, s3c), f.add(s8c, s5c), y4o,
271 f.sub(s8c, s5c), f.add(s0c, s3c), f.sub(s2b, s1b), f.add(s4c, s7c))
272
273# 9-point DCT
274def d9.run(+ys: List<&2, F32>) -> List<&2, F32>:
275 d9.list(d9.build(f.at(ys, 0), f.at(ys, 1), f.at(ys, 2), f.at(ys, 3), f.at(ys, 4), f.at(ys, 5),
276 f.at(ys, 6), f.at(ys, 7), f.at(ys, 8)))
277
278# negate the odd bins of a sine DCT
279def d9.neg(+ys: List<&2, F32>) -> List<&2, F32>:
280 f.set(f.set(f.set(f.set(ys, 1, F32.neg(f.at(ys, 1))), 3, F32.neg(f.at(ys, 3))), 5,
281 F32.neg(f.at(ys, 5))), 7, F32.neg(f.at(ys, 7)))
282
283# one windowed band: 18 time samples and 9 new overlap samples
284type Wn is Data:
285 Wn{out: List<&2, F32>, nov: List<&2, F32>}
286
287# window product and the overlap it saves
288type Ws is Data:
289 Ws{sm: F32, nv: F32}
290
291# aliasing pair for one window index
292def wn.pair(+co: List<&2, F32>, +si: List<&2, F32>, +tw: List<&2, F32>, +ii: U32) -> Ws:
293 Ws{f.add(f.mul(f.at(co, ii), f.at(tw, u.add(ii, 9))), f.mul(f.at(si, ii), f.at(tw, ii))),
294 f.sub(f.mul(f.at(co, ii), f.at(tw, ii)), f.mul(f.at(si, ii), f.at(tw, u.add(ii, 9))))}
295
296# write one window index into the band
297def wn.put(st: Wn, +ov: List<&2, F32>, +win: List<&2, F32>, +ii: U32, ws: Ws) -> Wn:
298 match st ws:
299 case Wn{out, nov} Ws{+sm, +nv}:
300 Wn{f.set(f.set(out, ii, f.sub(f.mul(f.at(ov, ii), f.at(win, ii)), f.mul(sm, f.at(win, u.add(ii, 9))))),
301 u.sub(17, ii), f.add(f.mul(f.at(ov, ii), f.at(win, u.add(ii, 9))), f.mul(sm, f.at(win, ii)))),
302 f.set(nov, ii, nv)}
303
304# one of the nine window steps
305def wn.one(
306 st: Wn, +co: List<&2, F32>, +si: List<&2, F32>, +ov: List<&2, F32>, +tw: List<&2, F32>,
307 +win: List<&2, F32>, +ii: U32
308) -> Wn:
309 wn.put(st, ov, win, ii, wn.pair(co, si, tw, ii))
310
311# window all nine indices
312def wn.go(
313 hop: Nat, st: Wn, +co: List<&2, F32>, +si: List<&2, F32>, +ov: List<&2, F32>, +tw: List<&2, F32>,
314 +win: List<&2, F32>, +ii: U32
315) -> Wn:
316 match hop:
317 case 0n:
318 st
319 case 1n+p:
320 wn.go(p, wn.one(st, co, si, ov, tw, win, ii), co, si, ov, tw, win, u.add(ii, 1))
321
322# IMDCT-36 of one 18-point band
323def im.band(+gg: List<&2, F32>, +ov: List<&2, F32>, +tw: List<&2, F32>, +win: List<&2, F32>) -> Wn:
324 wn.go(9n, Wn{List.replicate(F32, 18n, 0.0), List.replicate(F32, 9n, 0.0)}, d9.run(cs.co(gg)),
325 d9.neg(d9.run(cs.si(gg))), ov, tw, win, 0)
326
327# one F32 read from the IMDCT/DCT spectrum Array
328type Dx is Type:
329 Dx{acc: Array<F32>, +v: F32}
330
331def dx.of(got: Array<F32> & F32) -> Dx:
332 (acc, v) = got
333 Dx{acc, v}
334
335def dx.at(acc: Array<F32>, +ii: U32) -> Dx:
336 dx.of(Array.get(F32, acc, ii))
337
338# spectrum Array beside the samples just read
339type Il is Type:
340 Il{acc: Array<F32>, xs: List<&2, F32>}
341
342# pull one sample; hop is remaining after this read
343def ix.pull(hop: Nat, got: Dx, +ii: U32, ys: List<&2, F32>) -> Il:
344 match hop got:
345 case 0n Dx{acc, +cur}:
346 Il{acc, List.reverse(&2, F32, cur <> ys)}
347 case 1n+p Dx{acc, +cur}:
348 ix.pull(p, dx.at(acc, u.add(ii, 1)), u.add(ii, 1), cur <> ys)
349
350# hop+1 samples starting at `at`. The spectrum Array is handed back.
351def ix.take(acc: Array<F32>, +at: U32, hop: Nat) -> Il:
352 ix.pull(hop, dx.at(acc, at), at, [])
353
354# write a short list into the spectrum Array
355def ix.poke(hop: Nat, acc: Array<F32>, src: List<&2, F32>, +at: U32) -> Array<F32>:
356 match hop src:
357 case 0n _:
358 acc
359 case _ Nil{}:
360 acc
361 case 1n+p +hd <> tl:
362 ix.poke(p, Array.set(F32, acc, at, hd), tl, u.add(at, 1))
363
364# 576 lines in the spectrum Array, and 288 overlap samples
365type Im is Type:
366 Im{buf: Array<F32>, ov: List<&2, F32>}
367
368# write one band back into the spectrum Array and the overlap
369def im.store(buf: Array<F32>, +ov: List<&2, F32>, ww: Wn, +jj: U32, +base: U32) -> Im:
370 match ww:
371 case Wn{out, nov}:
372 Im{ix.poke(18n, buf, out, u.add(base, u.mul(jj, 18))), ls.poke(9n, ov, nov, u.mul(jj, 9))}
373
374# band samples in hand; window them and store
375def im.got(
376 got: Il, +ov: List<&2, F32>, +tw: List<&2, F32>, +win: List<&2, F32>, +jj: U32, +base: U32
377) -> Im:
378 match got:
379 case Il{buf, gg}:
380 im.store(buf, ov, im.band(gg, ls.slice(ov, u.mul(jj, 9), 9n), tw, win), jj, base)
381
382# IMDCT-36 of band jj. Each of the 18 samples is an Array.get.
383def im.one(st: Im, +tw: List<&2, F32>, +win: List<&2, F32>, +jj: U32, +base: U32) -> Im:
384 match st:
385 case Im{buf, +ov}:
386 im.got(ix.take(buf, u.add(base, u.mul(jj, 18)), 17n), ov, tw, win, jj, base)
387
388# IMDCT-36 over 32 bands. base is the channel offset in the spectrum Array.
389def im.go(hop: Nat, st: Im, +tw: List<&2, F32>, +win: List<&2, F32>, +jj: U32, +base: U32) -> Im:
390 match hop:
391 case 0n:
392 st
393 case 1n+p:
394 im.go(p, im.one(st, tw, win, jj, base), tw, win, u.add(jj, 1), base)
395
396# high index of one aliasing pair
397def aa.ixh(+base: U32, +bb: U32, +ii: U32) -> U32:
398 u.add(base, u.add(u.mul(u.add(bb, 1), 18), ii))
399
400# low index of one aliasing pair
401def aa.ixl(+base: U32, +bb: U32, +ii: U32) -> U32:
402 u.add(base, u.add(u.mul(bb, 18), u.sub(17, ii)))
403
404# spectrum Array beside the two aliasing samples
405type Ia is Type:
406 Ia{acc: Array<F32>, +up: F32, +dp: F32}
407
408# low sample, then both indices are in hand
409def aa.lo(got: Dx, +up: F32) -> Ia:
410 match got:
411 case Dx{acc, dp}:
412 Ia{acc, up, dp}
413
414# high sample in hand; read the low sample next
415def aa.rd1(got: Dx, +lo: U32) -> Ia:
416 match got:
417 case Dx{acc, up}:
418 aa.lo(dx.at(acc, lo), up)
419
420# read both samples of one aliasing pair. Each read is an Array.get.
421def aa.rd(acc: Array<F32>, +hi: U32, +lo: U32) -> Ia:
422 aa.rd1(dx.at(acc, hi), lo)
423
424# butterfly of one aliasing pair. c0 and c1 are the two cosine rows.
425def aa.wr(
426 acc: Array<F32>, +up: F32, +dp: F32, +c0: F32, +c1: F32, +hi: U32, +lo: U32
427) -> Array<F32>:
428 Array.set(F32, Array.set(F32, acc, hi, f.sub(f.mul(c0, up), f.mul(c1, dp))), lo,
429 f.add(f.mul(c1, up), f.mul(c0, dp)))
430
431# write the pair once both samples have been read
432def aa.use(got: Ia, +c0: F32, +c1: F32, +hi: U32, +lo: U32) -> Array<F32>:
433 match got:
434 case Ia{acc, up, dp}:
435 aa.wr(acc, up, dp, c0, c1, hi, lo)
436
437# one butterfly at index ii of band bb
438def aa.one(acc: Array<F32>, +aa: List<&2, F32>, +bb: U32, +ii: U32, +base: U32) -> Array<F32>:
439 aa.use(aa.rd(acc, aa.ixh(base, bb, ii), aa.ixl(base, bb, ii)), f.at(aa, ii), f.at(aa, u.add(ii, 8)),
440 aa.ixh(base, bb, ii), aa.ixl(base, bb, ii))
441
442# eight butterflies between band bb and the next
443def aa.i(hop: Nat, acc: Array<F32>, +aa: List<&2, F32>, +bb: U32, +ii: U32, +base: U32) -> Array<F32>:
444 match hop:
445 case 0n:
446 acc
447 case 1n+p:
448 aa.i(p, aa.one(acc, aa, bb, ii, base), aa, bb, u.add(ii, 1), base)
449
450# antialias from low bands toward high bands
451def aa.b(hop: Nat, acc: Array<F32>, +aa: List<&2, F32>, +bb: U32, +base: U32) -> Array<F32>:
452 match hop:
453 case 0n:
454 acc
455 case 1n+p:
456 aa.b(p, aa.i(8n, acc, aa, bb, 0, base), aa, u.add(bb, 1), base)
457
458# 31 long-block aliasing pairs. base is the channel offset in the spectrum Array.
459def aa.run(acc: Array<F32>, +aa: List<&2, F32>, +base: U32) -> Array<F32>:
460 aa.b(31n, acc, aa, 0, base)
461
462# negate the sample just read
463def sg.neg(got: Dx, +at: U32) -> Array<F32>:
464 match got:
465 case Dx{acc, v}:
466 Array.set(F32, acc, at, F32.neg(v))
467
468# negate one odd sample of an odd band
469def sg.i(hop: Nat, acc: Array<F32>, +base: U32, +ii: U32) -> Array<F32>:
470 match hop:
471 case 0n:
472 acc
473 case 1n+p:
474 sg.i(p, sg.neg(dx.at(acc, u.add(base, ii)), u.add(base, ii)), base, u.add(ii, 2))
475
476# odd samples of 16 odd bands, starting at sample 18
477def sg.b(hop: Nat, acc: Array<F32>, +base: U32) -> Array<F32>:
478 match hop:
479 case 0n:
480 acc
481 case 1n+p:
482 sg.b(p, sg.i(9n, acc, base, 1), u.add(base, 36))
483
484# frequency inversion after the IMDCT. base is the channel offset.
485def im.sign(st: Im, +base: U32) -> Im:
486 match st:
487 case Im{buf, ov}:
488 Im{sg.b(16n, buf, u.add(base, 18)), ov}
489
490# four DCT-II column results
491type Q4 is Data:
492 Q4{a0: F32, a1: F32, a2: F32, a3: F32}
493
494# column sample i of the 32-band vector
495def dc.x0(acc: Array<F32>, +kk: U32, +ii: U32) -> Dx:
496 dx.at(acc, u.add(kk, u.mul(ii, 18)))
497
498# mirrored column
499def dc.x1(acc: Array<F32>, +kk: U32, +ii: U32) -> Dx:
500 dx.at(acc, u.add(kk, u.mul(u.sub(15, ii), 18)))
501
502# upper column
503def dc.x2(acc: Array<F32>, +kk: U32, +ii: U32) -> Dx:
504 dx.at(acc, u.add(kk, u.mul(u.add(16, ii), 18)))
505
506# upper mirror
507def dc.x3(acc: Array<F32>, +kk: U32, +ii: U32) -> Dx:
508 dx.at(acc, u.add(kk, u.mul(u.sub(31, ii), 18)))
509
510# finish the column butterfly
511def dc.q2(+t0: F32, +t1: F32, +t2: F32, +t3: F32, +s2: F32) -> Q4:
512 Q4{f.add(t0, t1), f.mul(f.sub(t0, t1), s2), f.add(t3, t2), f.mul(f.sub(t3, t2), s2)}
513
514# one DCT-II column from four samples and three secants
515def dc.q(+x0: F32, +x1: F32, +x2: F32, +x3: F32, +s0: F32, +s1: F32, +s2: F32) -> Q4:
516 dc.q2(f.add(x0, x3), f.add(x1, x2), f.mul(f.sub(x1, x2), s0), f.mul(f.sub(x0, x3), s1), s2)
517
518# spectrum Array beside one finished column
519type Dq is Type:
520 Dq{acc: Array<F32>, q: Q4}
521
522# fourth sample, then the column butterfly
523def dc.rd3(got: Dx, +x0: F32, +x1: F32, +x2: F32, +s0: F32, +s1: F32, +s2: F32) -> Dq:
524 match got:
525 case Dx{acc, x3}:
526 Dq{acc, dc.q(x0, x1, x2, x3, s0, s1, s2)}
527
528# third sample and the three secants
529def dc.rd2(got: Dx, +sec: List<&2, F32>, +kk: U32, +ii: U32, +x0: F32, +x1: F32) -> Dq:
530 match got:
531 case Dx{acc, x2}:
532 dc.rd3(dc.x3(acc, kk, ii), x0, x1, x2, f.at(sec, u.mul(ii, 3)),
533 f.at(sec, u.add(u.mul(ii, 3), 1)), f.at(sec, u.add(u.mul(ii, 3), 2)))
534
535# second sample
536def dc.rd1(got: Dx, +sec: List<&2, F32>, +kk: U32, +ii: U32, +x0: F32) -> Dq:
537 match got:
538 case Dx{acc, x1}:
539 dc.rd2(dc.x2(acc, kk, ii), sec, kk, ii, x0, x1)
540
541# read column ii. Each of the four samples is an Array.get.
542def dc.cell(got: Dx, +sec: List<&2, F32>, +kk: U32, +ii: U32) -> Dq:
543 match got:
544 case Dx{acc, x0}:
545 dc.rd1(dc.x1(acc, kk, ii), sec, kk, ii, x0)
546
547# store one column into the 4 by 8 working Array
548def dc.store(xs: Array<F32>, qq: Q4, +ii: U32) -> Array<F32>:
549 match qq:
550 case Q4{a0, a1, a2, a3}:
551 Array.set(F32, Array.set(F32, Array.set(F32, Array.set(F32, xs, ii, a0), u.add(ii, 8), a1),
552 u.add(ii, 16), a2), u.add(ii, 24), a3)
553
554# spectrum Array beside the 4 by 8 working rows
555type Dr is Type:
556 Dr{acc: Array<F32>, xs: Array<F32>}
557
558# write one gathered column and keep both Arrays
559def dc.stored(got: Dq, xs: Array<F32>, +ii: U32) -> Dr:
560 match got:
561 case Dq{acc, q}:
562 Dr{acc, dc.store(xs, q, ii)}
563
564# gather all eight columns before any write-back
565def dc.cols(hop: Nat, got: Dr, +sec: List<&2, F32>, +kk: U32, +ii: U32) -> Dr:
566 match hop got:
567 case 0n Dr{acc, xs}:
568 Dr{acc, xs}
569 case 1n+p Dr{acc, xs}:
570 dc.cols(p, dc.stored(dc.cell(dc.x0(acc, kk, ii), sec, kk, ii), xs, ii), sec, kk, u.add(ii, 1))
571
572# eight floats carried through the DCT-II row butterfly
573type E8 is Data:
574 E8{z0: F32, z1: F32, z2: F32, z3: F32, z4: F32, z5: F32, z6: F32, z7: F32}
575
576# finish the first stage
577def but.sum2(
578 +xt: F32, +y0: F32, +y7: F32, +y1: F32, +y6: F32, +y2: F32, +y5: F32, +y3: F32
579) -> E8:
580 E8{f.add(y0, y3), f.add(y1, y2), y6, f.sub(y1, y2), f.sub(y0, y3), y5, y7, xt}
581
582# first add/sub stage of a DCT-II row
583def but.sum(+x0: F32, +x1: F32, +x2: F32, +x3: F32, +x4: F32, +x5: F32, +x6: F32, +x7: F32) -> E8:
584 but.sum2(f.sub(x0, x7), f.add(x0, x7), f.sub(x1, x6), f.add(x1, x6), f.sub(x2, x5), f.add(x2, x5),
585 f.sub(x3, x4), f.add(x3, x4))
586
587# second stage: the 45-degree rotations
588def but.mid(ee: E8) -> E8:
589 match ee:
590 case E8{+z0, +z1, +z2, +z3, +z4, +z5, +z6, +z7}:
591 E8{f.add(z0, z1), f.mul(f.add(z3, z4), c.c707()), f.mul(f.add(z2, z6), c.c707()), z4,
592 f.mul(f.sub(z0, z1), c.c707()), f.add(z5, z2), f.add(z6, z7), z7}
593
594# last rotation update
595def but.rot3(
596 +o0: F32, +w3: F32, +w6: F32, +y4: F32, +o4: F32, +p5: F32, +p7: F32, +xt: F32
597) -> E8:
598 E8{o0, p7, w3, y4, o4, f.sub(p5, f.mul(p7, c.c198())), f.sub(xt, w6), f.add(xt, w6)}
599
600# complete the rotation
601def but.rot2(
602 +o0: F32, +w3: F32, +w6: F32, +y4: F32, +o4: F32, +p5: F32, +w7: F32, +xt: F32
603) -> E8:
604 but.rot3(o0, w3, w6, y4, o4, p5, f.add(w7, f.mul(p5, c.c382())), xt)
605
606# third stage: the small-angle rotation, using the updated values
607def but.rot(ee: E8) -> E8:
608 match ee:
609 case E8{+z0, +z1, +z2, +z3, +z4, +z5, +z6, +z7}:
610 but.rot2(z0, z1, z2, z3, z4, f.sub(z5, f.mul(z6, c.c198())), z6, z7)
611
612# eight row outputs
613def but.end(ee: E8) -> List<&2, F32>:
614 match ee:
615 case E8{+z0, +z1, +z2, +z3, +z4, +z5, +z6, +z7}:
616 cs.pack(z0, f.mul(f.add(z7, z1), c.c509()), f.mul(f.add(z3, z2), c.c541()),
617 f.mul(f.sub(z6, z5), c.c601()), z4, f.mul(f.add(z6, z5), c.c899()),
618 f.mul(f.sub(z3, z2), c.c130()), f.mul(f.sub(z7, z1), c.c256()), 0.0)
619
620# cs.pack takes 9; the row is 8. Drop the padding below.
621def but.out(ee: E8) -> List<&2, F32>:
622 ls.take(8n, but.end(ee), [])
623
624# butterfly the eight samples and write the row back
625def but.sum8(acc: Array<F32>, +ys: List<&2, F32>, +base: U32) -> Array<F32>:
626 ix.poke(8n, acc, but.out(but.rot(but.mid(but.sum(f.at(ys, 0), f.at(ys, 1), f.at(ys, 2),
627 f.at(ys, 3), f.at(ys, 4), f.at(ys, 5), f.at(ys, 6), f.at(ys, 7))))), base)
628
629# butterfly one row. The eight inputs are one slice of the working Array.
630def but.use(got: Il, +base: U32) -> Array<F32>:
631 match got:
632 case Il{acc, ys}:
633 but.sum8(acc, ys, base)
634
635# butterfly one row of eight and write it back
636def but.row(xs: Array<F32>, +base: U32) -> Array<F32>:
637 but.use(ix.take(xs, base, 7n), base)
638
639# butterfly all four rows
640def dc.fly(hop: Nat, xs: Array<F32>, +base: U32) -> Array<F32>:
641 match hop:
642 case 0n:
643 xs
644 case 1n+p:
645 dc.fly(p, but.row(xs, base), u.add(base, 8))
646
647# seven samples of one scatter column, row-major
648type Sv is Type:
649 Sv{xs: Array<F32>, +p0: F32, +p1: F32, +p2: F32, +p3: F32, +p4: F32, +p5: F32, +p6: F32}
650
651# row 3, column ii+1
652def sc.v6(got: Dx, +r0: F32, +r1: F32, +r1n: F32, +r2: F32, +r2n: F32, +r3: F32) -> Sv:
653 match got:
654 case Dx{acc, r3n}:
655 Sv{acc, r0, r1, r1n, r2, r2n, r3, r3n}
656
657# row 3, column ii
658def sc.v5(got: Dx, +ii: U32, +r0: F32, +r1: F32, +r1n: F32, +r2: F32, +r2n: F32) -> Sv:
659 match got:
660 case Dx{acc, r3}:
661 sc.v6(dx.at(acc, u.add(ii, 25)), r0, r1, r1n, r2, r2n, r3)
662
663# row 2, column ii+1
664def sc.v4(got: Dx, +ii: U32, +r0: F32, +r1: F32, +r1n: F32, +r2: F32) -> Sv:
665 match got:
666 case Dx{acc, r2n}:
667 sc.v5(dx.at(acc, u.add(ii, 24)), ii, r0, r1, r1n, r2, r2n)
668
669# row 2, column ii
670def sc.v3(got: Dx, +ii: U32, +r0: F32, +r1: F32, +r1n: F32) -> Sv:
671 match got:
672 case Dx{acc, r2}:
673 sc.v4(dx.at(acc, u.add(ii, 17)), ii, r0, r1, r1n, r2)
674
675# row 1, column ii+1
676def sc.v2(got: Dx, +ii: U32, +r0: F32, +r1: F32) -> Sv:
677 match got:
678 case Dx{acc, r1n}:
679 sc.v3(dx.at(acc, u.add(ii, 16)), ii, r0, r1, r1n)
680
681# row 1, column ii
682def sc.v1(got: Dx, +ii: U32, +r0: F32) -> Sv:
683 match got:
684 case Dx{acc, r1}:
685 sc.v2(dx.at(acc, u.add(ii, 9)), ii, r0, r1)
686
687# row 0, column ii, then the six neighbour slots
688def sc.v0(got: Dx, +ii: U32) -> Sv:
689 match got:
690 case Dx{acc, r0}:
691 sc.v1(dx.at(acc, u.add(ii, 8)), ii, r0)
692
693# the seven samples of column ii, each an Array.get
694def sc.vals(xs: Array<F32>, +ii: U32) -> Sv:
695 sc.v0(dx.at(xs, ii), ii)
696
697# spectrum Array beside the rows Array
698type Sc is Type:
699 Sc{acc: Array<F32>, xs: Array<F32>}
700
701# four band values from the seven column samples
702def sc.bands(
703 +p0: F32, +p1: F32, +p2: F32, +p3: F32, +p4: F32, +p5: F32, +p6: F32
704) -> Q4:
705 Q4{p0, f.add(f.add(p3, p5), p6), f.add(p1, p2), f.add(f.add(p4, p5), p6)}
706
707# store the four bands and hand both Arrays back
708def sc.put4(xs: Array<F32>, acc: Array<F32>, qq: Q4, +yy: U32) -> Sc:
709 match qq:
710 case Q4{a0, a1, a2, a3}:
711 Sc{Array.set(F32, Array.set(F32, Array.set(F32, Array.set(F32, acc, yy, a0), u.add(yy, 18), a1),
712 u.add(yy, 36), a2), u.add(yy, 54), a3), xs}
713
714# write one scatter group from the seven samples
715def sc.put(got: Sv, acc: Array<F32>, +yy: U32) -> Sc:
716 match got:
717 case Sv{xs, p0, p1, p2, p3, p4, p5, p6}:
718 sc.put4(xs, acc, sc.bands(p0, p1, p2, p3, p4, p5, p6), yy)
719
720# scatter one group of four bands into the spectrum Array
721def sc.one(acc: Array<F32>, xs: Array<F32>, +yy: U32, +ii: U32) -> Sc:
722 sc.put(sc.vals(xs, ii), acc, yy)
723
724# seven scatter steps; the eighth is the tail
725def sc.go(hop: Nat, got: Sc, +yy: U32, +ii: U32) -> Sc:
726 match hop got:
727 case 0n Sc{acc, xs}:
728 Sc{acc, xs}
729 case 1n+p Sc{acc, xs}:
730 sc.go(p, sc.one(acc, xs, yy, ii), u.add(yy, 72), u.add(ii, 1))
731
732# row 0, 1, 2 and 3 of column 7
733type Sf is Type:
734 Sf{xs: Array<F32>, +r0: F32, +r1: F32, +r2: F32, +r3: F32}
735
736# fourth tail sample, index 31
737def sc.e3(got: Dx, +r0: F32, +r1: F32, +r2: F32) -> Sf:
738 match got:
739 case Dx{acc, r3}:
740 Sf{acc, r0, r1, r2, r3}
741
742# third tail sample, index 23
743def sc.e2(got: Dx, +r0: F32, +r1: F32) -> Sf:
744 match got:
745 case Dx{acc, r2}:
746 sc.e3(dx.at(acc, 31), r0, r1, r2)
747
748# second tail sample, index 15
749def sc.e1(got: Dx, +r0: F32) -> Sf:
750 match got:
751 case Dx{acc, r1}:
752 sc.e2(dx.at(acc, 23), r0, r1)
753
754# first tail sample, index 7, then the other three rows
755def sc.e0(got: Dx) -> Sf:
756 match got:
757 case Dx{acc, r0}:
758 sc.e1(dx.at(acc, 15), r0)
759
760# four tail bands. r3 is both the high sum and the last band.
761def sc.tset(acc: Array<F32>, +r0: F32, +r1: F32, +r2: F32, +r3: F32, +yy: U32) -> Array<F32>:
762 Array.set(F32, Array.set(F32, Array.set(F32, Array.set(F32, acc, yy, r0), u.add(yy, 18),
763 f.add(r2, r3)), u.add(yy, 36), r1), u.add(yy, 54), r3)
764
765# drop the rows Array once the four tail samples have been read
766def sc.tend(got: Sf, acc: Array<F32>, +yy: U32) -> Array<F32>:
767 match got:
768 case Sf{xs, r0, r1, r2, r3}:
769 match xs:
770 case _xs:
771 sc.tset(acc, r0, r1, r2, r3, yy)
772
773# last scatter group, which has no i+1 neighbour. The rows Array ends here.
774def sc.tail(got: Sc, +yy: U32) -> Array<F32>:
775 match got:
776 case Sc{acc, xs}:
777 sc.tend(sc.e0(dx.at(xs, 7)), acc, yy)
778
779# scatter every band of frequency bin kk
780def sc.run(acc: Array<F32>, xs: Array<F32>, +kk: U32) -> Array<F32>:
781 sc.tail(sc.go(7n, Sc{acc, xs}, kk, 0), u.add(kk, 504))
782
783# butterfly the gathered rows, then scatter them back into the spectrum
784def dc.rows(got: Dr) -> Dr:
785 match got:
786 case Dr{acc, xs}:
787 Dr{acc, dc.fly(4n, xs, 0)}
788
789# scatter one frequency bin. The working rows are consumed here.
790def dc.scat(got: Dr, +kk: U32) -> Array<F32>:
791 match got:
792 case Dr{acc, xs}:
793 sc.run(acc, xs, kk)
794
795# one frequency bin of the 32-point DCT-II. The working rows stay an Array.
796def dc.one(acc: Array<F32>, +sec: List<&2, F32>, +kk: U32) -> Array<F32>:
797 dc.scat(dc.rows(dc.cols(8n, Dr{acc, Array.new(F32, 5n, 0.0)}, sec, kk, 0)), kk)
798
799# DCT-II of 18 frequency bins. kk is the first bin's index in the spectrum Array.
800def dc.run(hop: Nat, acc: Array<F32>, +sec: List<&2, F32>, +kk: U32) -> Array<F32>:
801 match hop:
802 case 0n:
803 acc
804 case 1n+p:
805 dc.run(p, dc.one(acc, sec, kk), sec, u.add(kk, 1))
806
807# one F32 read from the polyphase delay Array
808type La is Type:
809 La{lin: Array<F32>, +v: F32}
810
811def la.of(got: Array<F32> & F32) -> La:
812 (lin, v) = got
813 La{lin, v}
814
815def ln.at(lin: Array<F32>, +ii: U32) -> La:
816 la.of(Array.get(F32, lin, ii))
817
818def ln.set(lin: Array<F32>, +ii: U32, +vv: F32) -> Array<F32>:
819 Array.set(F32, lin, ii, vv)
820
821def ln.fill(xs: List<&2, F32>, a: Array<F32>, +ii: U32) -> Array<F32>:
822 match xs:
823 case Nil{}:
824 a
825 case +hd <> tl:
826 ln.fill(tl, Array.set(F32, a, ii, hd), u.add(ii, 1))
827
828# pull one sample into an accumulator; hop is remaining after this read
829def ln.pull(hop: Nat, got: La, +ii: U32, acc: List<&2, F32>) -> List<&2, F32>:
830 match hop got:
831 case 0n La{lin, +cur}:
832 match lin:
833 case _l:
834 List.reverse(&2, F32, cur <> acc)
835 case 1n+p La{lin, +cur}:
836 ln.pull(p, ln.at(lin, u.add(ii, 1)), u.add(ii, 1), cur <> acc)
837
838# first hop+1 slots of an Array as a list
839def ln.list(a: Array<F32>, hop: Nat) -> List<&2, F32>:
840 ln.pull(hop, ln.at(a, 0), 0, [])
841
842# four running polyphase sums, a and b
843type Mac is Data:
844 Mac{aa: List<&2, F32>, bb: List<&2, F32>}
845
846# MAC state plus the delay line handle mac.* only reads
847type Mk is Type:
848 Mk{st: Mac, lin: Array<F32>}
849
850# mode 0 replaces, mode 2 flips the a product, otherwise both add
851def mac.av(+mode: U32, +zv: F32, +yv: F32, +w0: F32, +w1: F32) -> F32:
852 match mode:
853 case 2:
854 f.sub(f.mul(yv, w1), f.mul(zv, w0))
855 case _:
856 f.sub(f.mul(zv, w0), f.mul(yv, w1))
857
858# apply one lane of a window load
859def mac.wr(
860 +aa: List<&2, F32>, +bb: List<&2, F32>, +mode: U32, +jj: U32, +bv: F32, +av: F32
861) -> Mac:
862 match mode:
863 case 0:
864 Mac{f.set(aa, jj, av), f.set(bb, jj, bv)}
865 case _:
866 Mac{f.set(aa, jj, f.add(f.at(aa, jj), av)), f.set(bb, jj, f.add(f.at(bb, jj), bv))}
867
868# one of the four lanes, y slot
869def mac.jy(
870 st: Mac, got: La, +w0: F32, +w1: F32, +mode: U32, +jj: U32, +zv: F32
871) -> Mk:
872 match st got:
873 case Mac{aa, bb} La{lin2, yv}:
874 Mk{mac.wr(aa, bb, mode, jj, f.add(f.mul(zv, w1), f.mul(yv, w0)), mac.av(mode, zv, yv, w0, w1)), lin2}
875
876# one of the four lanes, z slot
877def mac.jz(
878 st: Mac, got: La, +w0: F32, +w1: F32, +vy: U32, +mode: U32, +jj: U32
879) -> Mk:
880 match got:
881 case La{lin1, zv}:
882 mac.jy(st, ln.at(lin1, u.add(vy, jj)), w0, w1, mode, jj, zv)
883
884# one of the four lanes
885def mac.j(
886 st: Mac, lin: Array<F32>, +w0: F32, +w1: F32, +vz: U32, +vy: U32, +mode: U32, +jj: U32
887) -> Mk:
888 mac.jz(st, ln.at(lin, u.add(vz, jj)), w0, w1, vy, mode, jj)
889
890# four lanes of one load, advance one lane
891def mac.js_next(mk: Mk, +w0: F32, +w1: F32, +vz: U32, +vy: U32, +mode: U32, +jj: U32) -> Mk:
892 match mk:
893 case Mk{st, lin}:
894 mac.j(st, lin, w0, w1, vz, vy, mode, jj)
895
896# four lanes of one load
897def mac.js(
898 hop: Nat, mk: Mk, +w0: F32, +w1: F32, +vz: U32, +vy: U32, +mode: U32, +jj: U32
899) -> Mk:
900 match hop:
901 case 0n:
902 mk
903 case 1n+p:
904 mac.js(p, mac.js_next(mk, w0, w1, vz, vy, mode, jj), w0, w1, vz, vy, mode, u.add(jj, 1))
905
906# odd or even load
907def mac.mode3(odd: Bool) -> U32:
908 match odd:
909 case True{}:
910 2
911 case False{}:
912 1
913
914# pick the load mode
915def mac.mode2(zero: Bool, odd: Bool) -> U32:
916 match zero:
917 case True{}:
918 0
919 case False{}:
920 mac.mode3(odd)
921
922# k = 0 replaces, odd k uses mode 2, other even k uses mode 1
923def mac.mode(+kk: U32) -> U32:
924 mac.mode2(U32.is_eq(kk, 0), U32.is_eq(u.and(kk), 1))
925
926# window-coefficient index for block row ii and load kk
927def mac.pos(+ii: U32, +kk: U32) -> U32:
928 u.add(u.mul(u.sub(14, ii), 16), u.mul(kk, 2))
929
930# one window coefficient handed back beside the table Array.get just read
931type Sw is Type:
932 Sw{syn: Array<F32>, +w: F32}
933
934def sw.of(got: Array<F32> & F32) -> Sw:
935 (syn, w) = got
936 Sw{syn, w}
937
938def sw.at(syn: Array<F32>, +ii: U32) -> Sw:
939 sw.of(Array.get(F32, syn, ii))
940
941# 242 synthesis-window coefficients. 256 slots cover every mac.pos index.
942def sw.tab() -> Array<F32>:
943 ln.fill(Enc.f.of(Tab.tab.syn()), Array.new(F32, 8n, 0.0), 0)
944
945# MAC state plus the window table the next load still reads
946type Mw is Type:
947 Mw{mk: Mk, syn: Array<F32>}
948
949# second coefficient, then the eight-lane load
950def mac.step2(mk: Mk, got: Sw, +w0: F32, +zlin: U32, +ii: U32, +kk: U32) -> Mw:
951 match mk got:
952 case Mk{st, lin} Sw{syn, w1}:
953 Mw{mac.js(4n, Mk{st, lin}, w0, w1, u.sub(u.add(zlin, u.mul(ii, 4)), u.mul(kk, 64)),
954 u.sub(u.add(zlin, u.mul(ii, 4)), u.mul(u.sub(15, kk), 64)), mac.mode(kk), 0), syn}
955
956# first coefficient, then its neighbour
957def mac.step1(mk: Mk, got: Sw, +pos: U32, +zlin: U32, +ii: U32, +kk: U32) -> Mw:
958 match got:
959 case Sw{syn, w0}:
960 mac.step2(mk, sw.at(syn, u.add(pos, 1)), w0, zlin, ii, kk)
961
962# one of the eight loads. Each tap reads the window Array.
963def mac.step(mk: Mk, syn: Array<F32>, +zlin: U32, +ii: U32, +kk: U32) -> Mw:
964 mac.step1(mk, sw.at(syn, mac.pos(ii, kk)), mac.pos(ii, kk), zlin, ii, kk)
965
966# eight loads
967def mac.k(hop: Nat, got: Mw, +zlin: U32, +ii: U32, +kk: U32) -> Mw:
968 match hop got:
969 case 0n Mw{mk, syn}:
970 Mw{mk, syn}
971 case 1n+p Mw{mk, syn}:
972 mac.k(p, mac.step(mk, syn, zlin, ii, kk), zlin, ii, u.add(kk, 1))
973
974# scale a polyphase sum into a sample
975def mac.sc(+vv: F32) -> F32:
976 f.mul(vv, c.inv())
977
978# write the eight samples this row produces
979def mac.p8(
980 pcm: Array<F32>, +aa: List<&2, F32>, +bb: List<&2, F32>, +nch: U32, +pcmi: U32, +ii: U32
981) -> Array<F32>:
982 ln.set(ln.set(ln.set(ln.set(ln.set(ln.set(ln.set(ln.set(pcm,
983 u.add(pcmi, u.add(u.mul(u.sub(15, ii), nch), u.sub(nch, 1))), mac.sc(f.at(aa, 1))),
984 u.add(pcmi, u.add(u.mul(u.add(17, ii), nch), u.sub(nch, 1))), mac.sc(f.at(bb, 1))),
985 u.add(pcmi, u.mul(u.sub(15, ii), nch)), mac.sc(f.at(aa, 0))),
986 u.add(pcmi, u.mul(u.add(17, ii), nch)), mac.sc(f.at(bb, 0))),
987 u.add(pcmi, u.add(u.mul(u.sub(47, ii), nch), u.sub(nch, 1))), mac.sc(f.at(aa, 3))),
988 u.add(pcmi, u.add(u.mul(u.add(49, ii), nch), u.sub(nch, 1))), mac.sc(f.at(bb, 3))),
989 u.add(pcmi, u.mul(u.sub(47, ii), nch)), mac.sc(f.at(aa, 2))),
990 u.add(pcmi, u.mul(u.add(49, ii), nch)), mac.sc(f.at(bb, 2)))
991
992# store the row
993def mac.put(pcm: Array<F32>, st: Mac, +nch: U32, +pcmi: U32, +ii: U32) -> Array<F32>:
994 match st:
995 case Mac{+aa, +bb}:
996 mac.p8(pcm, aa, bb, nch, pcmi, ii)
997
998# fresh accumulators
999def mac.z() -> Mac:
1000 Mac{List.replicate(F32, 4n, 0.0), List.replicate(F32, 4n, 0.0)}
1001
1002# channel offset: the right channel starts at 576 when there are two
1003def blk.off(+nch: U32, right: Bool) -> U32:
1004 match right:
1005 case False{}:
1006 0
1007 case True{}:
1008 u.mul(u.sub(nch, 1), 576)
1009
1010# one F32 read from the post-DCT granule Array
1011type Ga is Type:
1012 Ga{gr: Array<F32>, +v: F32}
1013
1014def ga.of(got: Array<F32> & F32) -> Ga:
1015 (gr, v) = got
1016 Ga{gr, v}
1017
1018def ga.at(gr: Array<F32>, +ii: U32) -> Ga:
1019 ga.of(Array.get(F32, gr, ii))
1020
1021# delay line handed back beside the granule Array a write just read
1022type Lg is Type:
1023 Lg{lin: Array<F32>, gr: Array<F32>}
1024
1025# subband index. right selects the second channel, which starts at 576.
1026def blk.ix(+nch: U32, +band: U32, +tm: U32, right: Bool) -> U32:
1027 u.add(u.add(blk.off(nch, right), u.mul(band, 18)), tm)
1028
1029def blk.rd(gr: Array<F32>, +nch: U32, +band: U32, +tm: U32, right: Bool) -> Ga:
1030 ga.at(gr, blk.ix(nch, band, tm, right))
1031
1032# fourth sample of a four-lane write
1033def blk.w4d(g: Ga, lin: Array<F32>, +at: U32, +v0: F32, +v1: F32, +v2: F32) -> Lg:
1034 match g:
1035 case Ga{gr, v3}:
1036 Lg{ln.set(ln.set(ln.set(ln.set(lin, at, v0), u.add(at, 1), v1), u.add(at, 2), v2), u.add(at, 3), v3),
1037 gr}
1038
1039# third sample: band 0, this channel's left slot
1040def blk.w4c(g: Ga, lin: Array<F32>, +nch: U32, +at: U32, +tm: U32, +v0: F32, +v1: F32) -> Lg:
1041 match g:
1042 case Ga{gr, v2}:
1043 blk.w4d(blk.rd(gr, nch, 0, tm, True{}), lin, at, v0, v1, v2)
1044
1045# second sample: the right channel of this band
1046def blk.w4b(g: Ga, lin: Array<F32>, +nch: U32, +at: U32, +tm: U32, +v0: F32) -> Lg:
1047 match g:
1048 case Ga{gr, v1}:
1049 blk.w4c(blk.rd(gr, nch, 0, tm, False{}), lin, nch, at, tm, v0, v1)
1050
1051# first sample: the left channel of this band
1052def blk.w4a(g: Ga, lin: Array<F32>, +nch: U32, +at: U32, +band: U32, +tm: U32) -> Lg:
1053 match g:
1054 case Ga{gr, v0}:
1055 blk.w4b(blk.rd(gr, nch, band, tm, True{}), lin, nch, at, tm, v0)
1056
1057# write the four samples at zlin + 4*slot
1058def blk.w4(
1059 lin: Array<F32>, gr: Array<F32>, +nch: U32, +at: U32, +band: U32, +tm: U32
1060) -> Lg:
1061 blk.w4a(blk.rd(gr, nch, band, tm, False{}), lin, nch, at, band, tm)
1062
1063# right channel of a two-lane write
1064def blk.w2b(g: Ga, lin: Array<F32>, +at: U32, +v0: F32) -> Lg:
1065 match g:
1066 case Ga{gr, v1}:
1067 Lg{ln.set(ln.set(lin, at, v0), u.add(at, 1), v1), gr}
1068
1069# left channel of a two-lane write
1070def blk.w2a(g: Ga, lin: Array<F32>, +nch: U32, +at: U32, +band: U32, +tm: U32) -> Lg:
1071 match g:
1072 case Ga{gr, v0}:
1073 blk.w2b(blk.rd(gr, nch, band, tm, True{}), lin, at, v0)
1074
1075# the second write of a row uses band (1+ii), not band 0
1076def blk.w2(
1077 lin: Array<F32>, gr: Array<F32>, +nch: U32, +at: U32, +band: U32, +tm: U32
1078) -> Lg:
1079 blk.w2a(blk.rd(gr, nch, band, tm, False{}), lin, nch, at, band, tm)
1080
1081# second preamble write: band 16 at the next time
1082def blk.pre2(got: Lg, +nch: U32, +zlin: U32, +tm: U32) -> Lg:
1083 match got:
1084 case Lg{lin, gr}:
1085 blk.w4(lin, gr, nch, u.add(zlin, 124), 16, u.add(tm, 1))
1086
1087# preamble: bands 16 and 0 at the current and next time
1088def blk.pre(
1089 lin: Array<F32>, gr: Array<F32>, +nch: U32, +zlin: U32, +tm: U32
1090) -> Lg:
1091 blk.pre2(blk.w4(lin, gr, nch, u.add(zlin, 60), 16, tm), nch, zlin, tm)
1092
1093# index of the history write, which steps back 16 slots
1094def blk.hist(+zlin: U32, +ii: U32) -> U32:
1095 u.add(u.sub(zlin, u.mul(u.sub(16, ii), 4)), 2)
1096
1097# fourth lane: this band at the next time, right channel
1098def blk.wsd(g: Ga, lin: Array<F32>, +at: U32, +v0: F32, +v1: F32, +v2: F32) -> Lg:
1099 match g:
1100 case Ga{gr, v3}:
1101 Lg{ln.set(ln.set(ln.set(ln.set(lin, at, v0), u.add(at, 1), v1), u.add(at, 2), v2), u.add(at, 3), v3),
1102 gr}
1103
1104# third lane: this band at the next time, left channel
1105def blk.wsc(
1106 g: Ga, lin: Array<F32>, +nch: U32, +at: U32, +band: U32, +tm: U32, +v0: F32, +v1: F32
1107) -> Lg:
1108 match g:
1109 case Ga{gr, v2}:
1110 blk.wsd(blk.rd(gr, nch, band, u.add(tm, 1), True{}), lin, at, v0, v1, v2)
1111
1112# second lane: this band at this time, right channel
1113def blk.wsb(g: Ga, lin: Array<F32>, +nch: U32, +at: U32, +band: U32, +tm: U32, +v0: F32) -> Lg:
1114 match g:
1115 case Ga{gr, v1}:
1116 blk.wsc(blk.rd(gr, nch, band, u.add(tm, 1), False{}), lin, nch, at, band, tm, v0, v1)
1117
1118# first lane: this band at this time, left channel
1119def blk.wsa(g: Ga, lin: Array<F32>, +nch: U32, +at: U32, +band: U32, +tm: U32) -> Lg:
1120 match g:
1121 case Ga{gr, v0}:
1122 blk.wsb(blk.rd(gr, nch, band, tm, True{}), lin, nch, at, band, tm, v0)
1123
1124# same band at this time and the next, four lanes
1125def blk.ws(
1126 lin: Array<F32>, gr: Array<F32>, +nch: U32, +at: U32, +band: U32, +tm: U32
1127) -> Lg:
1128 blk.wsa(blk.rd(gr, nch, band, tm, False{}), lin, nch, at, band, tm)
1129
1130# current-slot writes for row ii
1131def blk.i1(
1132 lin: Array<F32>, gr: Array<F32>, +nch: U32, +zlin: U32, +tm: U32, +ii: U32
1133) -> Lg:
1134 blk.ws(lin, gr, nch, u.add(zlin, u.mul(ii, 4)), u.sub(31, ii), tm)
1135
1136# history write, after the next-slot write has returned the granule
1137def blk.i2b(got: Lg, +nch: U32, +zlin: U32, +tm: U32, +ii: U32) -> Lg:
1138 match got:
1139 case Lg{lin, gr}:
1140 blk.w2(lin, gr, nch, blk.hist(zlin, ii), u.add(1, ii), tm)
1141
1142# next-slot and history writes for row ii
1143def blk.i2(
1144 lin: Array<F32>, gr: Array<F32>, +nch: U32, +zlin: U32, +tm: U32, +ii: U32
1145) -> Lg:
1146 blk.i2b(blk.w2(lin, gr, nch, u.add(u.add(zlin, u.mul(ii, 4)), 64), u.add(1, ii), u.add(tm, 1)), nch,
1147 zlin, tm, ii)
1148
1149# history writes, after the current-slot write has returned the granule
1150def blk.ib(got: Lg, +nch: U32, +zlin: U32, +tm: U32, +ii: U32) -> Lg:
1151 match got:
1152 case Lg{lin, gr}:
1153 blk.i2(lin, gr, nch, zlin, tm, ii)
1154
1155# both writes for row ii
1156def blk.i(
1157 lin: Array<F32>, gr: Array<F32>, +nch: U32, +zlin: U32, +tm: U32, +ii: U32
1158) -> Lg:
1159 blk.ib(blk.i1(lin, gr, nch, zlin, tm, ii), nch, zlin, tm, ii)
1160
1161# (z+896) - z, times 29
1162def sp.a1a3(g1: La, +v896: F32) -> La:
1163 match g1:
1164 case La{lin2, vz}:
1165 La{lin2, f.mul(f.sub(v896, vz), Enc.f32.bits(1105723392))}
1166
1167def sp.a1a2(g0: La, +zz: U32) -> La:
1168 match g0:
1169 case La{lin1, v896}:
1170 sp.a1a3(ln.at(lin1, zz), v896)
1171
1172def sp.a1a(lin: Array<F32>, +zz: U32) -> La:
1173 sp.a1a2(ln.at(lin, u.add(zz, 896)), zz)
1174
1175# slots 1 and 13, times 213
1176def sp.a1b2(g1: La, +acc: F32, +v64: F32) -> La:
1177 match g1:
1178 case La{lin2, v832}:
1179 La{lin2, f.add(acc, f.mul(f.add(v64, v832), Enc.f32.bits(1129644032)))}
1180
1181def sp.a1b1(g0: La, +acc: F32, +zz: U32) -> La:
1182 match g0:
1183 case La{lin1, v64}:
1184 sp.a1b2(ln.at(lin1, u.add(zz, 832)), acc, v64)
1185
1186def sp.a1b(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1187 sp.a1b1(ln.at(lin, u.add(zz, 64)), acc, zz)
1188
1189# slots 12 and 2, times 459
1190def sp.a1c2(g1: La, +acc: F32, +v768: F32) -> La:
1191 match g1:
1192 case La{lin2, v128}:
1193 La{lin2, f.add(acc, f.mul(f.sub(v768, v128), Enc.f32.bits(1139113984)))}
1194
1195def sp.a1c1(g0: La, +acc: F32, +zz: U32) -> La:
1196 match g0:
1197 case La{lin1, v768}:
1198 sp.a1c2(ln.at(lin1, u.add(zz, 128)), acc, v768)
1199
1200def sp.a1c(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1201 sp.a1c1(ln.at(lin, u.add(zz, 768)), acc, zz)
1202
1203# slots 3 and 11, times 2037
1204def sp.a1d2(g1: La, +acc: F32, +v192: F32) -> La:
1205 match g1:
1206 case La{lin2, v704}:
1207 La{lin2, f.add(acc, f.mul(f.add(v192, v704), Enc.f32.bits(1157537792)))}
1208
1209def sp.a1d1(g0: La, +acc: F32, +zz: U32) -> La:
1210 match g0:
1211 case La{lin1, v192}:
1212 sp.a1d2(ln.at(lin1, u.add(zz, 704)), acc, v192)
1213
1214def sp.a1d(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1215 sp.a1d1(ln.at(lin, u.add(zz, 192)), acc, zz)
1216
1217# slots 10 and 4, times 5153
1218def sp.a1e2(g1: La, +acc: F32, +v640: F32) -> La:
1219 match g1:
1220 case La{lin2, v256}:
1221 La{lin2, f.add(acc, f.mul(f.sub(v640, v256), Enc.f32.bits(1168181248)))}
1222
1223def sp.a1e1(g0: La, +acc: F32, +zz: U32) -> La:
1224 match g0:
1225 case La{lin1, v640}:
1226 sp.a1e2(ln.at(lin1, u.add(zz, 256)), acc, v640)
1227
1228def sp.a1e(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1229 sp.a1e1(ln.at(lin, u.add(zz, 640)), acc, zz)
1230
1231# slots 5 and 9, times 6574
1232def sp.a1f2(g1: La, +acc: F32, +v320: F32) -> La:
1233 match g1:
1234 case La{lin2, v576}:
1235 La{lin2, f.add(acc, f.mul(f.add(v320, v576), Enc.f32.bits(1171091456)))}
1236
1237def sp.a1f1(g0: La, +acc: F32, +zz: U32) -> La:
1238 match g0:
1239 case La{lin1, v320}:
1240 sp.a1f2(ln.at(lin1, u.add(zz, 576)), acc, v320)
1241
1242def sp.a1f(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1243 sp.a1f1(ln.at(lin, u.add(zz, 320)), acc, zz)
1244
1245# slots 8 and 6, times 37489, then slot 7 times 75038
1246def sp.a1g4(g2: La, +acc: F32, +v512: F32, +v384: F32) -> La:
1247 match g2:
1248 case La{lin3, v448}:
1249 La{lin3,
1250 f.add(f.add(acc, f.mul(f.sub(v512, v384), Enc.f32.bits(1192390912))),
1251 f.mul(v448, Enc.f32.bits(1200787200)))}
1252
1253def sp.a1g3(g1: La, +acc: F32, +v512: F32, +zz: U32) -> La:
1254 match g1:
1255 case La{lin2, v384}:
1256 sp.a1g4(ln.at(lin2, u.add(zz, 448)), acc, v512, v384)
1257
1258def sp.a1g2(g0: La, +acc: F32, +zz: U32) -> La:
1259 match g0:
1260 case La{lin1, v512}:
1261 sp.a1g3(ln.at(lin1, u.add(zz, 384)), acc, v512, zz)
1262
1263def sp.a1g(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1264 sp.a1g2(ln.at(lin, u.add(zz, 512)), acc, zz)
1265
1266def sp.a1go6(g: La, +zz: U32) -> La:
1267 match g:
1268 case La{lin6, acc6}:
1269 sp.a1g(acc6, lin6, zz)
1270
1271def sp.a1go5(g: La, +zz: U32) -> La:
1272 match g:
1273 case La{lin5, acc5}:
1274 sp.a1go6(sp.a1f(acc5, lin5, zz), zz)
1275
1276def sp.a1go4(g: La, +zz: U32) -> La:
1277 match g:
1278 case La{lin4, acc4}:
1279 sp.a1go5(sp.a1e(acc4, lin4, zz), zz)
1280
1281def sp.a1go3(g: La, +zz: U32) -> La:
1282 match g:
1283 case La{lin3, acc3}:
1284 sp.a1go4(sp.a1d(acc3, lin3, zz), zz)
1285
1286def sp.a1go2(g: La, +zz: U32) -> La:
1287 match g:
1288 case La{lin2, acc2}:
1289 sp.a1go3(sp.a1c(acc2, lin2, zz), zz)
1290
1291def sp.a1go1(g: La, +zz: U32) -> La:
1292 match g:
1293 case La{lin1, acc1}:
1294 sp.a1go2(sp.a1b(acc1, lin1, zz), zz)
1295
1296# first grouped window sum
1297def sp.a1(lin: Array<F32>, +zz: U32) -> La:
1298 sp.a1go1(sp.a1a(lin, zz), zz)
1299
1300# taps 898, 770, 642, 514
1301def sp.a2a4(g3: La, +v898: F32, +v770: F32, +v642: F32) -> La:
1302 match g3:
1303 case La{lin4, v514}:
1304 La{lin4,
1305 f.add(f.add(f.add(f.mul(v898, Enc.f32.bits(1120927744)), f.mul(v770, Enc.f32.bits(1153687552))),
1306 f.mul(v642, Enc.f32.bits(1175976960))), f.mul(v514, Enc.f32.bits(1199182592)))}
1307
1308def sp.a2a3(g2: La, +v898: F32, +v770: F32, +zz: U32) -> La:
1309 match g2:
1310 case La{lin3, v642}:
1311 sp.a2a4(ln.at(lin3, u.add(zz, 514)), v898, v770, v642)
1312
1313def sp.a2a2(g1: La, +v898: F32, +zz: U32) -> La:
1314 match g1:
1315 case La{lin2, v770}:
1316 sp.a2a3(ln.at(lin2, u.add(zz, 642)), v898, v770, zz)
1317
1318def sp.a2a1(g0: La, +zz: U32) -> La:
1319 match g0:
1320 case La{lin1, v898}:
1321 sp.a2a2(ln.at(lin1, u.add(zz, 770)), v898, zz)
1322
1323def sp.a2a(lin: Array<F32>, +zz: U32) -> La:
1324 sp.a2a1(ln.at(lin, u.add(zz, 898)), zz)
1325
1326# taps 386 and 258
1327def sp.a2b2(g1: La, +acc: F32, +v386: F32) -> La:
1328 match g1:
1329 case La{lin2, v258}:
1330 La{lin2, f.add(f.add(acc, f.mul(v386, Enc.f32.bits(3323714560))), f.mul(v258, Enc.f32.bits(3258187776)))}
1331
1332def sp.a2b1(g0: La, +acc: F32, +zz: U32) -> La:
1333 match g0:
1334 case La{lin1, v386}:
1335 sp.a2b2(ln.at(lin1, u.add(zz, 258)), acc, v386)
1336
1337def sp.a2b(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1338 sp.a2b1(ln.at(lin, u.add(zz, 386)), acc, zz)
1339
1340# tap 130
1341def sp.a2c1(g: La, +acc: F32) -> La:
1342 match g:
1343 case La{lin1, v130}:
1344 La{lin1, f.add(acc, f.mul(v130, Enc.f32.bits(1125253120)))}
1345
1346def sp.a2c(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1347 sp.a2c1(ln.at(lin, u.add(zz, 130)), acc)
1348
1349# tap 2
1350def sp.a2d1(g: La, +acc: F32) -> La:
1351 match g:
1352 case La{lin1, v2}:
1353 La{lin1, f.add(acc, f.mul(v2, Enc.f32.bits(3231711232)))}
1354
1355def sp.a2d(+acc: F32, lin: Array<F32>, +zz: U32) -> La:
1356 sp.a2d1(ln.at(lin, u.add(zz, 2)), acc)
1357
1358def sp.a2go3(g: La, +zz: U32) -> La:
1359 match g:
1360 case La{lin3, acc3}:
1361 sp.a2d(acc3, lin3, zz)
1362
1363def sp.a2go2(g: La, +zz: U32) -> La:
1364 match g:
1365 case La{lin2, acc2}:
1366 sp.a2go3(sp.a2c(acc2, lin2, zz), zz)
1367
1368def sp.a2go1(g: La, +zz: U32) -> La:
1369 match g:
1370 case La{lin1, acc1}:
1371 sp.a2go2(sp.a2b(acc1, lin1, zz), zz)
1372
1373# second window sum, eight weighted taps
1374def sp.a2(lin: Array<F32>, +zz: U32) -> La:
1375 sp.a2go1(sp.a2a(lin, zz), zz)
1376
1377# PCM and delay line while pairing synth samples
1378type Pp is Type:
1379 Pp{pcm: Array<F32>, lin: Array<F32>}
1380
1381# one synth pair: two scaled samples
1382def sp.pair2(g2: La, pcm: Array<F32>, +pcmi: U32, +nch: U32) -> Pp:
1383 match g2:
1384 case La{lin2, v2}:
1385 Pp{ln.set(pcm, u.add(pcmi, u.mul(16, nch)), mac.sc(v2)), lin2}
1386
1387def sp.pair1(g1: La, pcm: Array<F32>, +pcmi: U32, +nch: U32, +zz: U32) -> Pp:
1388 match g1:
1389 case La{lin1, v1}:
1390 sp.pair2(sp.a2(lin1, zz), ln.set(pcm, pcmi, mac.sc(v1)), pcmi, nch)
1391
1392def sp.pair(st: Pp, +pcmi: U32, +nch: U32, +zz: U32) -> Pp:
1393 match st:
1394 case Pp{pcm, lin}:
1395 sp.pair1(sp.a1(lin, zz), pcm, pcmi, nch, zz)
1396
1397# four synth pairs that open a block
1398def blk.pairs(st: Pp, +nch: U32, +pcmi: U32, +z0: U32) -> Pp:
1399 sp.pair(sp.pair(sp.pair(sp.pair(st, u.add(pcmi, u.sub(nch, 1)), nch, u.add(z0, 1)), u.add(u.add(pcmi,
1400 u.mul(32, nch)), u.sub(nch, 1)), nch, u.add(z0, 65)), pcmi, nch, z0), u.add(pcmi, u.mul(32, nch)), nch,
1401 u.add(z0, 64))
1402
1403# delay line and the PCM written so far
1404type Sb is Type:
1405 Sb{lin: Array<F32>, pcm: Array<F32>}
1406
1407def blk.armed1(got: Pp) -> Sb:
1408 match got:
1409 case Pp{pcm2, lin2}:
1410 Sb{lin2, pcm2}
1411
1412# pairs read the delay line the preamble just wrote
1413def blk.armed(lin: Array<F32>, pcm: Array<F32>, +nch: U32, +tm: U32) -> Sb:
1414 blk.armed1(blk.pairs(Pp{pcm, lin}, nch, u.mul(u.mul(32, nch), tm), u.add(u.mul(tm, 64), 60)))
1415
1416# polyphase state, the granule Array the rows still read, and the window table
1417type Bg is Type:
1418 Bg{st: Sb, gr: Array<F32>, syn: Array<F32>}
1419
1420# preamble done: the pairs read the delay line, the granule and window stay put
1421def blk.arm2(got: Lg, pcm: Array<F32>, syn: Array<F32>, +nch: U32, +tm: U32) -> Bg:
1422 match got:
1423 case Lg{lin, gr}:
1424 Bg{blk.armed(lin, pcm, nch, tm), gr, syn}
1425
1426# open a block: preamble, then the four pairs
1427def blk.arm(got: Bg, +nch: U32, +tm: U32) -> Bg:
1428 match got:
1429 case Bg{st, gr, syn}:
1430 match st:
1431 case Sb{lin, pcm}:
1432 blk.arm2(blk.pre(lin, gr, nch, u.add(u.mul(tm, 64), 960), tm), pcm, syn, nch, tm)
1433
1434# a finished row, with the window table the next row still reads
1435type Sr is Type:
1436 Sr{st: Sb, syn: Array<F32>}
1437
1438def blk.row1(got: Mw, pcm: Array<F32>, +nch: U32, +tm: U32, +ii: U32) -> Sr:
1439 match got:
1440 case Mw{mk, syn}:
1441 match mk:
1442 case Mk{st, lin2}:
1443 Sr{Sb{lin2, mac.put(pcm, st, nch, u.mul(u.mul(32, nch), tm), ii)}, syn}
1444
1445def blk.row3(got: Sr, gr: Array<F32>) -> Bg:
1446 match got:
1447 case Sr{st, syn}:
1448 Bg{st, gr, syn}
1449
1450# window the row just written
1451def blk.row(
1452 lin: Array<F32>, pcm: Array<F32>, syn: Array<F32>, +nch: U32, +tm: U32, +ii: U32
1453) -> Sr:
1454 blk.row1(mac.k(8n, Mw{Mk{mac.z(), lin}, syn}, u.add(u.mul(tm, 64), 960), ii, 0), pcm, nch, tm, ii)
1455
1456# window the row, keeping the granule for the rows still to come
1457def blk.step2(
1458 got: Lg, pcm: Array<F32>, syn: Array<F32>, +nch: U32, +tm: U32, +ii: U32
1459) -> Bg:
1460 match got:
1461 case Lg{lin, gr}:
1462 blk.row3(blk.row(lin, pcm, syn, nch, tm, ii), gr)
1463
1464# one row of the block, from i = 14 down to 0
1465def blk.step(got: Bg, +nch: U32, +tm: U32, +ii: U32) -> Bg:
1466 match got:
1467 case Bg{st, gr, syn}:
1468 match st:
1469 case Sb{lin, pcm}:
1470 blk.step2(blk.i(lin, gr, nch, u.add(u.mul(tm, 64), 960), tm, ii), pcm, syn, nch, tm, ii)
1471
1472# fifteen rows
1473def blk.i.go(hop: Nat, got: Bg, +nch: U32, +tm: U32, +ii: U32) -> Bg:
1474 match hop got:
1475 case 0n Bg{st, gr, syn}:
1476 Bg{st, gr, syn}
1477 case 1n+p Bg{st, gr, syn}:
1478 blk.i.go(p, blk.step(Bg{st, gr, syn}, nch, tm, ii), nch, tm, u.sub(ii, 1))
1479
1480# one time block
1481def blk.one(got: Bg, +nch: U32, +tm: U32) -> Bg:
1482 blk.i.go(15n, blk.arm(got, nch, tm), nch, tm, 14)
1483
1484# nine time blocks, time = 0, 2, ..., 16
1485def blk.go(hop: Nat, got: Bg, +nch: U32, +tm: U32) -> Bg:
1486 match hop got:
1487 case 0n Bg{st, gr, syn}:
1488 Bg{st, gr, syn}
1489 case 1n+p Bg{st, gr, syn}:
1490 blk.go(p, blk.one(Bg{st, gr, syn}, nch, tm), nch, u.add(tm, 2))
1491
1492# one even delay sample and the odd slot kept from the carried tail.
1493# hop is the pairs still to come after this one. The sample was read at ii.
1494def qmf.ev(hop: Nat, old: List<&2, F32>, got: La, +ii: U32, acc: List<&2, F32>) -> List<&2, F32>:
1495 match hop old got:
1496 case 0n +_e <> +odd <> _tl La{lin, +cur}:
1497 match lin:
1498 case _lin:
1499 List.reverse(&2, F32, odd <> (cur <> acc))
1500 case 1n+p +_e <> +odd <> tl La{lin, +cur}:
1501 qmf.ev(p, tl, ln.at(lin, u.add(ii, 2)), u.add(ii, 2), odd <> (cur <> acc))
1502 case _ _ La{lin, _v}:
1503 match lin:
1504 case _lin:
1505 List.reverse(&2, F32, acc)
1506
1507# stereo tail: 960 delay-Array samples in one pull. The old list is dropped.
1508def qmf.st(+old: List<&2, F32>, lin: Array<F32>) -> List<&2, F32>:
1509 match old:
1510 case _old:
1511 ln.pull(959n, ln.at(lin, 1152), 1152, [])
1512
1513# mono keeps odd slots; stereo replaces the whole tail from the delay Array
1514def qmf.pick(mono: Bool, +qmf: List<&2, F32>, lin: Array<F32>) -> List<&2, F32>:
1515 match mono:
1516 case True{}:
1517 qmf.ev(479n, qmf, ln.at(lin, 1152), 1152, [])
1518 case False{}:
1519 qmf.st(qmf, lin)
1520
1521# save the 15-block tail off the delay Array, one pass, no List.set
1522def qmf.save(lin: Array<F32>, +qmf: List<&2, F32>, +nch: U32) -> List<&2, F32>:
1523 qmf.pick(U32.is_eq(nch, 1), qmf, lin)
1524
1525# PCM, the overlap to carry, and the polyphase delay
1526type Pc is Data:
1527 Pc{pcm: List<&2, F32>, ov: List<&2, F32>, qmf: List<&2, F32>}
1528
1529# zero overlap, 288 samples, one channel
1530def syn.zov() -> List<&2, F32>:
1531 List.replicate(F32, 288n, 0.0)
1532
1533# zero polyphase delay
1534def syn.zqmf() -> List<&2, F32>:
1535 List.replicate(F32, 960n, 0.0)
1536
1537# antialias, IMDCT, and the sign flip for one channel
1538def ch.prep(
1539 acc: Array<F32>, +ov: List<&2, F32>, +aa: List<&2, F32>, +tw: List<&2, F32>, +win: List<&2, F32>,
1540 +base: U32
1541) -> Im:
1542 im.sign(im.go(32n, Im{aa.run(acc, aa, base), ov}, tw, win, 0, base), base)
1543
1544# append the second channel's overlap. The spectrum Array already holds both.
1545def syn.st2(+ova: List<&2, F32>, bb: Im) -> Im:
1546 match bb:
1547 case Im{buf, ovb}:
1548 Im{buf, List.append(&2, F32, ova, ovb)}
1549
1550# join two channel states. The right channel starts at bin 576.
1551def syn.st(
1552 aa: Im, +ovb: List<&2, F32>, +cs: List<&2, F32>, +tw: List<&2, F32>, +win: List<&2, F32>
1553) -> Im:
1554 match aa:
1555 case Im{buf, ova}:
1556 syn.st2(ova, ch.prep(buf, ovb, cs, tw, win, 576))
1557
1558# prepare one or two channels
1559def syn.ch(
1560 mono: Bool, acc: Array<F32>, +ov: List<&2, F32>, +aa: List<&2, F32>, +tw: List<&2, F32>,
1561 +win: List<&2, F32>
1562) -> Im:
1563 match mono:
1564 case True{}:
1565 ch.prep(acc, ov, aa, tw, win, 0)
1566 case False{}:
1567 syn.st(ch.prep(acc, ls.slice(ov, 0, 288n), aa, tw, win, 0), ls.slice(ov, 288, 288n), aa, tw, win)
1568
1569# tables shared by a granule. 2048 slots cover mono 576 and stereo 1152.
1570def syn.ready(+spec: List<&2, F32>, +ov: List<&2, F32>, +nch: U32) -> Im:
1571 syn.ch(U32.is_eq(nch, 1), ln.fill(spec, Array.new(F32, 11n, 0.0), 0), ov,
1572 Enc.f.of(Tab.tab.aa()), Enc.f.of(Tab.tab.tw()), Enc.f.of(Tab.tab.winl()))
1573
1574# second channel starts at bin 576
1575def sy.dct2(mono: Bool, acc: Array<F32>, +sec: List<&2, F32>) -> Array<F32>:
1576 match mono:
1577 case True{}:
1578 dc.run(18n, acc, sec, 0)
1579 case False{}:
1580 dc.run(18n, dc.run(18n, acc, sec, 0), sec, 576)
1581
1582# DCT-II of each channel. The spectrum Array is the one IMDCT just wrote.
1583def sy.dct(mono: Bool, acc: Array<F32>, +sec: List<&2, F32>) -> Array<F32>:
1584 sy.dct2(mono, acc, sec)
1585
1586# delay line: the carried tail, then zeros (4096-slot Array starts at 0.0)
1587def sy.lin(+qmf: List<&2, F32>) -> Array<F32>:
1588 ln.fill(qmf, Array.new(F32, 12n, 0.0), 0)
1589
1590# empty PCM for one granule (2048-slot Array covers mono 576 and stereo 1152)
1591def sy.pcm() -> Array<F32>:
1592 Array.new(F32, 11n, 0.0)
1593
1594# PCM Array back to a list of length 576*nch
1595def sy.pcm.list(+nch: U32, pcm: Array<F32>) -> List<&2, F32>:
1596 ln.list(pcm, U32.to_nat(u.sub(u.mul(576, nch), 1)))
1597
1598# the granule Array is finished once the nine blocks have read it
1599def syn.drop(gr: Array<F32>, st: Sb, +ov: List<&2, F32>, +qmf: List<&2, F32>, +nch: U32) -> Pc:
1600 match gr:
1601 case _gr:
1602 match st:
1603 case Sb{lin, pcm}:
1604 Pc{sy.pcm.list(nch, pcm), ov, qmf.save(lin, qmf, nch)}
1605
1606# run the polyphase and keep the overlap from the IMDCT
1607def syn.out(got: Bg, +ov: List<&2, F32>, +qmf: List<&2, F32>, +nch: U32) -> Pc:
1608 match got:
1609 case Bg{st, gr, syn}:
1610 match syn:
1611 case _syn:
1612 syn.drop(gr, st, ov, qmf, nch)
1613
1614# DCT-II then nine polyphase blocks. The spectrum Array is what the polyphase reads.
1615def syn.pcm(buf: Array<F32>, +ov: List<&2, F32>, +qmf: List<&2, F32>, +nch: U32) -> Pc:
1616 syn.out(blk.go(9n, Bg{Sb{sy.lin(qmf), sy.pcm()}, sy.dct(U32.is_eq(nch, 1), buf,
1617 Enc.f.of(Tab.tab.sec())), sw.tab()}, nch, 0), ov, qmf, nch)
1618
1619# synthesis of a prepared granule
1620def syn.finish(st: Im, +qmf: List<&2, F32>, +nch: U32) -> Pc:
1621 match st:
1622 case Im{buf, ov}:
1623 syn.pcm(buf, ov, qmf, nch)
1624
1625# one granule to PCM. spec is 576 samples per channel. ov is 288 per channel.
1626def syn.gran(+spec: List<&2, F32>, +ov: List<&2, F32>, +qmf: List<&2, F32>, +nch: U32) -> Pc:
1627 syn.finish(syn.ready(spec, ov, nch), qmf, nch)
1628
1629# IMDCT only, 32 bands, no antialias. Used to check the unit impulse.
1630def syn.im(+buf: List<&2, F32>, +ov: List<&2, F32>) -> Im:
1631 im.go(32n, Im{ln.fill(buf, Array.new(F32, 11n, 0.0), 0), ov}, Enc.f.of(Tab.tab.tw()),
1632 Enc.f.of(Tab.tab.winl()), 0, 0)
1633
1634# one PCM sample of a granule, as a binary32 word
1635def syn.nth(st: Pc, +ii: U32) -> U32:
1636 match st:
1637 case Pc{pcm, _ov, _qmf}:
1638 Enc.f32.word(f.at(pcm, ii))
1639
1640# drop the spectrum Array once sample 0 has been read
1641def syn.word1(got: Dx) -> U32:
1642 match got:
1643 case Dx{acc, v}:
1644 match acc:
1645 case _acc:
1646 Enc.f32.word(v)
1647
1648# first sample of an IMDCT buffer, as a binary32 word
1649def syn.word(st: Im) -> U32:
1650 match st:
1651 case Im{buf, _ov}:
1652 syn.word1(dx.at(buf, 0))
1653
1654# PCM word ii of one granule whose spectrum is a unit impulse at bin 0.
1655def syn.probe(+ii: U32) -> U32:
1656 syn.nth(syn.gran(f.set(List.replicate(F32, 576n, 0.0), 0, Enc.f32.bits(1065353216)), syn.zov(),
1657 syn.zqmf(), 1), ii)
1658
1659# unit impulse at bin 0. The first sample is the float32 word 1022453915.
1660def syn.impulse() -> U32:
1661 syn.word(syn.im(f.set(List.replicate(F32, 576n, 0.0), 0, Enc.f32.bits(1065353216)), syn.zov()))