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()))