1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
//! Pure-Rust Dolby AC-4 audio decoder foundation.
//!
//! AC-4 is a complex, hierarchical codec — multiple presentations,
//! nested substream descriptors, ASF/ASF-A2/A-SPX coefficient streams
//! driven by huffman-coded scalefactor data, plus an EMDF metadata
//! sidecar carrying DRC / downmix / dialog-norm info. Full decode is
//! weeks of work.
//!
//! What this crate lands today (per ETSI TS 103 190-1 V1.4.1):
//!
//! * **Sync framing** — `ac4_syncframe()` from Annex G: `0xAC40` plain
//! and `0xAC41` CRC-protected, 16-bit `frame_size()` with 24-bit
//! escape, plus a standalone CRC-16 helper. See [`sync`].
//! * **Table of contents** — full `ac4_toc()` walker in [`toc`]:
//! bitstream_version, sequence_counter, fs_index, frame_rate_index,
//! b_iframe_global, payload_base, per-presentation
//! `ac4_presentation_info()` (single / multi-substream, configs 0..=5
//! plus extension escape, HSF extension, pre-virtualised flag, extra
//! EMDF substreams), per-substream `ac4_substream_info()`
//! (channel_mode prefix decoder, sf_multiplier, bitrate_indicator,
//! content_type w/ language tag, b_iframe),
//! `substream_index_table()` byte sizes, and the `variable_bits(n)`
//! codec.
//! * **Decoder** — [`decoder::Ac4Decoder`] accepts either a sync-wrapped
//! packet (`0xAC40` / `0xAC41` prefix) or a bare MP4-style
//! `raw_ac4_frame` payload, parses the TOC, and emits a silent S16
//! `AudioFrame` with the correct channel count, sample rate, and
//! samples-per-frame for the stream configuration.
//!
//! * **ASF substream walker** — [`asf::walk_ac4_substream`] reads
//! `ac4_substream()` (audio_size + variable_bits extension), the
//! mono/stereo outer `audio_data()` layers (mono_codec_mode /
//! stereo_codec_mode, spec_frontend, b_enable_mdct_stereo_proc),
//! `asf_transform_info()` (Tables 99 / 100 / 103) and
//! `asf_psy_info()` (Table 106 n_msfb_bits + Tables 109/110
//! n_grp_bits). Surfaces the result through
//! [`decoder::Ac4Decoder::last_substream`] so downstream tooling can
//! see the frame's tool mix and MDCT window grouping without touching
//! Huffman state.
//!
//! * **Coefficient pipeline** — [`huffman`] carries the normative
//! ASF_HCB_SCALEFAC / ASF_HCB_SNF / ASF_HCB_1..11 tables from Annex
//! A (plus CB_DIM / UNSIGNED_CB); [`sfb_offset`] carries the
//! Annex B.4-B.7 scale-factor-band offset vectors for the 48 kHz
//! family. [`asf_data`] walks `asf_section_data()`,
//! `asf_spectral_data()` (with Pseudocode-19 dim=2/dim=4 split and
//! Pseudocode-20 codebook-11 extension code),
//! `asf_scalefac_data()` (dpcm-over-reference scale factors with
//! `sf_gain = 2^((sf-100)/4)`), and `asf_snf_data()`.
//! `dequantise_and_scale()` applies `rec_spec = sign(q)|q|^(4/3)`
//! then multiplies by the band gain.
//! * **MDCT** — [`mdct`] implements the reference AC-4 IMDCT (§5.5.2
//! pseudocodes 60-64, naive O(N^2) complex DFT) plus the KBD
//! window family (§5.5.3, alphas from Table 186) with overlap-add.
//!
//! * **A-SPX configuration** — [`aspx::parse_aspx_config`] implements
//! the 15-bit `aspx_config()` element (Table 50, §4.2.12.1) and
//! [`aspx::parse_companding_control`] the `companding_control()`
//! element (Table 49, §4.2.11). The outer `audio_data()` walker in
//! [`asf`] now consumes these for the mono ASPX, stereo ASPX, and
//! stereo ASPX_ACPL_{1,2} I-frame paths. For ASPX_ACPL_{1,2} it now
//! also reads the trailing `acpl_config_1ch(PARTIAL)` /
//! `acpl_config_1ch(FULL)` element (§4.2.13.1 Table 59) via
//! [`acpl::parse_acpl_config_1ch`]. Exposes the parsed
//! `AspxConfig` through
//! [`decoder::Ac4Decoder::last_substream`]`.tools.aspx_config` and
//! the A-CPL configs through `acpl_config_1ch_partial` /
//! `acpl_config_1ch_full` on [`asf::SubstreamTools`].
//! * **A-SPX framing** — [`aspx::parse_aspx_framing`] implements
//! `aspx_framing()` (Table 53, §4.2.12.4) end-to-end for all four
//! interval classes (FIXFIX / FIXVAR / VARFIX / VARVAR) including
//! the 1/2/3-bit `aspx_int_class` prefix code, the envelope-count
//! derivation for FIXFIX (`1 << tmp_num_env` with
//! `envbits = aspx_num_env_bits_fixfix + 1`), Note-1 1-vs-2-bit
//! field widths driven by `num_aspx_timeslots`, the
//! `aspx_tsg_ptr` sizing via `ceil(log2(num_env + 2))`, and the
//! I-frame gate on `aspx_var_bord_left` for VARFIX / VARVAR.
//! Returns the full [`aspx::AspxFraming`] (int_class, num_env,
//! num_noise, freq_res vector, border fields, tsg_ptr). Wired into
//! `asf::walk_ac4_substream` for both the mono ASPX and stereo
//! ASPX I-frame paths: after `companding_control()` and the
//! `mono_data()` / `stereo_data()` body the walker reads
//! `aspx_xover_subband_offset` (3 bits) and then `aspx_framing(0)`
//! (and, for stereo, `aspx_balance` + conditional
//! `aspx_framing(1)`). `num_aspx_timeslots` for the Note-1 field
//! width comes from the TOC's `frame_length` via
//! [`aspx::num_aspx_timeslots`] (Table 189 × Table 192).
//! * **A-SPX delta direction** — [`aspx::parse_aspx_delta_dir`]
//! implements `aspx_delta_dir(ch)` (Table 54, §4.2.12.5): one bit
//! per signal envelope plus one bit per noise envelope. The per-
//! channel `AspxDeltaDir` drives which `ASPX_HCB_*_{F0,DF,DT}`
//! codebook the matching `aspx_ec_data()` path will pull from.
//! * **A-SPX HF generation / interleaved-waveform coding (mono)** —
//! [`aspx::parse_aspx_hfgen_iwc_1ch`] implements Table 55
//! (§4.2.12.6): per-subband-group `tna_mode`, `ah_present` +
//! conditional `add_harmonic[]`, `fic_present` + conditional
//! `fic_used_in_sfb[]`, and `tic_present` + conditional
//! `tic_used_in_slot[]`. Takes `num_sbg_noise`,
//! `num_sbg_sig_highres`, `num_aspx_timeslots` from the caller.
//! * **A-SPX HF generation / interleaved-waveform coding (stereo)** —
//! [`aspx::parse_aspx_hfgen_iwc_2ch`] implements Table 56
//! (§4.2.12.7). Adds per-channel `tna_mode[ch][]` (with
//! `aspx_balance == 1` mirroring channel 0 into channel 1),
//! per-channel `aspx_ah_left` / `_right` gates, `aspx_fic_present`
//! plus per-channel `fic_left` / `fic_right` gates, and the
//! `aspx_tic_copy` / `aspx_tic_left` / `aspx_tic_right` TIC
//! gating (including mirroring left-channel TIC into right when
//! `tic_copy` is set).
//!
//! * **A-SPX Huffman infrastructure** — [`aspx::AspxHcb`] is a
//! `(len[], cw[], cb_off)` codebook helper: the symbol decoder walks
//! one bit at a time until a `(len == width, cw == code)` match
//! lands, then returns `symbol_index - cb_off` as the delta. All 18
//! Annex A.2 codebooks (Tables A.16..=A.33) are transcribed in
//! [`aspx_huffman`] — six `(F0, DF, DT)` triples covering
//! envelope-LEVEL / envelope-BALANCE @ 1.5 dB / 3 dB plus
//! noise-LEVEL / noise-BALANCE. A [`aspx::HuffmanCodebookId`] enum
//! plus [`aspx::lookup_aspx_hcb`] resolve the
//! `get_aspx_hcb(data_type, quant_mode, stereo_mode, hcb_type)`
//! tuple from §5.7.6.3.4 Pseudocode 79.
//! * **A-SPX entropy coded data** — [`aspx::parse_aspx_ec_data`]
//! implements `aspx_ec_data()` (Table 57, §4.2.12.8) on top of
//! [`aspx::parse_aspx_huff_data`] (Table 58) — per-envelope loop
//! that picks F0/DF/DT codebook per direction and returns a vector
//! of [`aspx::AspxHuffEnv`]s.
//! * **A-SPX master freq-scale derivation** —
//! [`aspx::derive_aspx_frequency_tables`] implements §5.7.6.3.1
//! Pseudocodes 67, 68, 69 and 70: picks between
//! [`aspx::ASPX_SBG_TEMPLATE_HIGHRES`] and
//! [`aspx::ASPX_SBG_TEMPLATE_LOWRES`] by `aspx_master_freq_scale`,
//! trims with `aspx_start_freq` / `aspx_stop_freq` into the master
//! subband-group table, then applies `aspx_xover_subband_offset` to
//! produce the high-res / low-res signal tables. The noise
//! subband-group table follows Pseudocode 70's `max(1,
//! floor(aspx_noise_sbg * log2(sbz/sbx) + 0.5))` count rule and is
//! clamped to `num_sbg_noise <= 5`. Returns
//! [`aspx::AspxFrequencyTables`] containing master / high-res /
//! low-res / noise border tables plus `sba`, `sbz`, `sbx`,
//! `num_sb_aspx` and an [`aspx::AspxSbgCounts`] ready to feed
//! [`aspx::parse_aspx_ec_data`].
//! * **Full A-SPX data-path wiring** — `asf::walk_ac4_substream` now
//! runs the whole `aspx_data_1ch()` / `aspx_data_2ch()` body on
//! I-frame ASPX substreams: `aspx_xover_subband_offset` →
//! `aspx_framing` (+ stereo `aspx_balance` / second framing) →
//! `aspx_delta_dir` → derived [`aspx::AspxFrequencyTables`] →
//! `aspx_hfgen_iwc_1ch()` / `aspx_hfgen_iwc_2ch()` →
//! `aspx_ec_data()` SIGNAL and NOISE per channel. All parsed data
//! lands on [`asf::SubstreamTools`] alongside the existing framing /
//! delta-dir / qmode fields.
//!
//! * **QMF analysis + synthesis filter bank** — [`qmf::QWIN`] carries
//! the 640-coefficient QMF prototype window from Annex D.3.
//! [`qmf::qmf_analysis_slot`] + [`qmf::QmfAnalysisBank`] implement
//! the §5.7.3.2 Pseudocode 65 forward transform (windowing +
//! 5-fold time-fold to vector u + 64-point complex modulation);
//! [`qmf::qmf_synthesis_slot`] + [`qmf::QmfSynthesisBank`] implement
//! the matching §5.7.4.2 Pseudocode 66 inverse transform (shifted
//! 1 280-sample `qsyn_filt` delay line + 128-point modulation +
//! folded-tap 64-way tap sum). The analysis/synthesis pair achieves
//! ~80 dB PSNR end-to-end roundtrip on sine and noise test signals
//! (unit tests in [`qmf`]).
//! * **A-SPX HF regeneration scaffold** — [`aspx::derive_patch_tables`]
//! implements §5.7.6.3.1.4 Pseudocode 71 (patch subband-group table
//! derivation). [`aspx::hf_tile_copy`] implements a simplified
//! §5.7.6.4.1.4 Pseudocode 89 high-band tile copy via the patch
//! table (no chirp/alpha0/alpha1 tonal adjust). The full TNS body
//! lives in the dedicated [`aspx_tns`] module — see below.
//! [`aspx::apply_flat_envelope_gain`] is a one-gain scaffold kept as
//! a fallback for the §5.7.6.4.2 HF envelope adjustment tool.
//! Together with the QMF bank these form an end-to-end bandwidth-
//! extension pipeline: PCM → QMF analysis → low-band truncate → HF
//! tile-copy → QMF synthesis → non-silent PCM.
//! * **A-SPX TNS (chirp + α0 + α1)** — [`aspx_tns`] implements the
//! full §5.7.6.4.1.2 / .1.3 / .1.4 complex-covariance Temporal
//! Noise Shaping path: pre-flatten gain vector
//! ([`aspx_tns::compute_preflat_gains`], Pseudocode 85), complex
//! covariance matrix over `Q_low_ext`
//! ([`aspx_tns::compute_covariance`], Pseudocode 86), α0 / α1 LPC
//! coefficients with the EPSILON_INV slack and the |α|≥4 fallback
//! ([`aspx_tns::compute_alphas`], Pseudocode 87), per-noise-subband-
//! group chirp factors via the Table 195 `tabNewChirp` lookup with
//! attack / decay smoothing ([`aspx_tns::chirp_factors`],
//! Pseudocode 88), and the full HF signal creation that adds
//! `chirp * α0 * Q_low[n-2]` + `chirp² * α1 * Q_low[n-4]` plus the
//! optional pre-flatten divide ([`aspx_tns::hf_tile_tns`],
//! Pseudocode 89). Per-channel state ([`aspx_tns::AspxTnsState`])
//! carries `aspx_tna_mode_prev[]` / `prev_chirp_array[]` plus the
//! tail of the previous interval's `Q_low` for the
//! `ts_offset_hfadj = 4` look-back. The decoder auto-selects the
//! TNS path when the parsed `aspx_hfgen_iwc_*` provides
//! `aspx_tna_mode[ch][]` and the framing is FIXFIX; otherwise it
//! falls back to the bare tile copy.
//! * **A-SPX HF envelope adjustment (per-envelope gain)** —
//! [`aspx::AspxEnvelopeAdjuster`] implements §5.7.6.4.2 Pseudocodes
//! 90 + 91 + 95 (non-harmonic, non-limited path): delta-decode
//! `aspx_data_sig` / `aspx_data_noise` (Pseudocodes 80 / 81) via
//! [`aspx::delta_decode_sig`] / [`aspx::delta_decode_noise`],
//! dequantize to `scf_sig_sbg` / `scf_noise_sbg` (Pseudocodes 82 / 83)
//! via [`aspx::dequantize_sig_scf`] / [`aspx::dequantize_noise_scf`],
//! estimate the actual HF envelope energy
//! ([`aspx::estimate_envelope_energy`]), map subband-group scale
//! factors onto QMF subbands ([`aspx::map_scf_to_qmf_subbands`]),
//! then compute per-subband compensatory gains
//! ([`aspx::compute_sig_gains`]) = `sqrt(scf_sig / ((1 + est) *
//! (1 + scf_noise)))`. The per-envelope gains are applied via
//! [`aspx::apply_envelope_gains`] using the FIXFIX Table-194
//! `atsg_sig` / `atsg_noise` borders derived by
//! [`aspx::derive_fixfix_atsg`]. The decoder auto-selects the
//! per-envelope path when the substream parsed FIXFIX framing
//! plus matching envelope deltas, and falls back to
//! `apply_flat_envelope_gain(0.5)` otherwise.
//! * **ASPX decoder wiring** — [`decoder::Ac4Decoder`] now routes
//! ASPX substreams through the extension pipeline: when an I-frame
//! ASPX substream produces derived `aspx_frequency_tables`, the
//! decoder takes the IMDCT low-band PCM, runs QMF analysis →
//! tile-copy HF regen → per-envelope gain (or flat-gain fallback)
//! → QMF synthesis, and emits bandwidth-extended PCM instead of
//! silence.
//!
//! * **Dialogue Enhancement (DE) parser** —
//! [`de::parse_dialog_enhancement`] walks the
//! `dialog_enhancement(b_iframe)` element (§4.2.14.11 Table 76)
//! end-to-end: `b_de_data_present` gate, optional I-frame
//! `de_config()` (§4.2.14.12 Table 77, `de_method` /
//! `de_max_gain` / `de_channel_config`), and the per-frame
//! `de_data()` payload (§4.2.14.13 Table 78) including the
//! cross-channel `de_keep_pos_flag` + `de_mix_coef[12]_idx` panning
//! parameters, the `de_keep_data_flag` re-use gate, the
//! `de_ms_proc_flag` M/S processing flag, and the per-channel
//! per-band `de_par[ch][band]` matrix decoded via the Annex A.4
//! Huffman codebooks ([`de_huffman::de_abs_huffman`] /
//! [`de_huffman::de_diff_huffman`], Tables A.58..A.61). The four
//! codebooks (`DE_HCB_ABS_0` / `DE_HCB_DIFF_0` / `DE_HCB_ABS_1` /
//! `DE_HCB_DIFF_1`) are transcribed verbatim from the normative ETSI
//! accompaniment file `ts_10319001v010401p0-tables.c` and are
//! verified by Kraft-sum = 1 and prefix-code unit tests.
//!
//! * **DRC metadata parser** — [`drc::parse_drc_frame`] walks the
//! `drc_frame()` element (§4.2.14.5 Table 70) end-to-end:
//! `b_drc_present` gate, optional I-frame `drc_config()` (§4.2.14.6
//! Table 71) including up to eight `drc_decoder_mode_config()` blocks
//! with all three branches (`drc_repeat_profile_flag`,
//! `drc_default_profile_flag`, explicit `drc_compression_curve()`),
//! the full `drc_compression_curve()` with optional boost / cut
//! sections and per-mode time-constant block (§4.2.14.8 Table 73),
//! and the per-frame `drc_data()` payload (§4.2.14.9 Table 74) that
//! pulls one `drc_gains()` entry per gainset mode.
//! [`drc::parse_drc_gains`] decodes the seven-bit `drc_gain_val`
//! seed plus all `(ch, band, sf)` deltas through the Annex A.5
//! `DRC_HCB` Huffman codebook (`huff_decode_diff` per §4.3.10.8.3),
//! with the per-band / per-channel `ref_drc_gain` reset semantics
//! from Table 75 honoured. The Annex A.5 codebook itself
//! ([`drc_huffman::DRC_HCB_LEN`] / [`drc_huffman::DRC_HCB_CW`]) is
//! transcribed verbatim from the ETSI accompaniment file
//! `ts_10319001v010401p0-tables.c` and is verified by a Kraft-sum
//! = 1 unit test (complete prefix code) plus an explicit prefix-
//! code check.
//!
//! * **Metadata walker** — [`metadata::parse_metadata`] implements the
//! outer `metadata(b_iframe)` element (§4.2.14.1 Table 66) end-to-end:
//! `basic_metadata(channel_mode)` (§4.2.14.2 Table 67) including the
//! `b_more_basic_metadata` block with optional `further_loudness_info`
//! (§4.2.14.3 Table 68), the stereo / multi-channel downmix info
//! tracks, the 5.x-only `pre_dmixtyp_5ch` / `pre_upmixtyp_5ch` and
//! 7.x-only `pre_upmixtyp_3_4` / `pre_upmixtyp_3_2_2` paths, and the
//! `b_dc_blocking` flag; `extended_metadata(channel_mode,
//! b_associated, b_dialog)` (§4.2.14.4 Table 69) including the
//! per-channel `b_*_active` / `b_*_has_dialog` channels-classifier
//! block; the `tools_metadata_size_value` (7-bit + optional
//! `variable_bits(3) << 7` extension) hint; dispatch into
//! [`drc::parse_drc_frame`] and [`de::parse_dialog_enhancement`]; and
//! the trailing `b_emdf_payloads_substream` flag. The walker chains a
//! [`metadata::MetadataState`] forward across frames so non-I frames
//! re-use the most recent `drc_config()` / `de_config()` per the
//! bitstream's gating semantics. After DRC + DE consume their bytes
//! the walker reconciles against `tools_metadata_size` and skips any
//! trailing reserved bits inside the announced envelope, providing
//! forward compatibility against future tools-metadata extensions.
//!
//! * **A-CPL parameter↔QMF subband mapping** —
//! [`acpl::sb_to_pb`] implements §5.7.7.2 Table 197 for all four
//! `acpl_num_param_bands` configurations (15 / 12 / 9 / 7), the last
//! piece needed to wire `acpl_data_*ch()` parameters through to QMF
//! subbands during synthesis.
//!
//! * **A-CPL synthesis math** — [`acpl_synth`] implements the §5.7.7
//! QMF-domain synthesis pipeline end-to-end:
//! [`acpl_synth::differential_decode`] (§5.7.7.7 Pseudocode 121)
//! recovers absolute `acpl_<SET>_q` arrays from the Huffman deltas
//! produced by [`acpl::parse_acpl_data_1ch`] /
//! [`acpl::parse_acpl_data_2ch`], with state carried across
//! parameter sets and AC-4 frames via [`acpl_synth::AcplDiffState`];
//! [`acpl_synth::dequantize_alpha_beta`] /
//! [`acpl_synth::dequantize_beta3`] / [`acpl_synth::dequantize_gamma`]
//! apply Tables 203-208 (with the cross-coupled Tables 203/204 and
//! 205/206 `ibeta` linkage); [`acpl_synth::interpolate`] (§5.7.7.3
//! Pseudocode 109) covers both smooth (linear-between-borders) and
//! steep (timeslot-keyed) per-QMF-subsample interpolation;
//! [`acpl_synth::InputSignalModifier`] (§5.7.7.4.2 Pseudocode 111)
//! implements the three frequency-region all-pass IIR decorrelators
//! `D0` / `D1` / `D2` over Tables 198-201;
//! [`acpl_synth::TransientDucker`] (§5.7.7.4.3 Pseudocodes 112-114)
//! carries the per-pb peak-decay / smooth state and emits
//! `duck_gain[pb]`; [`acpl_synth::acpl_module`] (§5.7.7.5
//! Pseudocode 116) and [`acpl_synth::run_pseudocode_115_pair`]
//! (Pseudocode 115) wire the channel-pair element together
//! end-to-end with the `acpl_qmf_band` M/S split below the
//! threshold and the alpha/beta-modulated decorrelator mix above.
//!
//! * **A-CPL decoder wiring** — [`asf::walk_ac4_substream`] now consumes
//! the full `aspx_data_1ch()` (Table 51) + `acpl_data_1ch()` (Table
//! 61) tail of the `ASPX_ACPL_2` stereo path: the mono MDCT body
//! parser ([`asf::parse_aspx_acpl2_mdct_body`] internal) walks the
//! `spec_frontend; sf_info; sf_data` shape, then the shared
//! [`asf::parse_aspx_data_1ch_body`] helper reads the leading
//! xover-offset + framing + delta-dir + hfgen + ec_data, and finally
//! [`acpl::parse_acpl_data_1ch`] is invoked with `num_bands` =
//! `acpl_num_param_bands` and `start_band` =
//! `sb_to_pb(acpl_qmf_band, num_param_bands)` per Table 61.
//! The parsed payload lands on [`asf::SubstreamTools::acpl_data_1ch`].
//! [`decoder::Ac4Decoder`] now drives
//! [`acpl_synth::run_acpl_1ch_pcm`] (mono PCM → QMF analysis →
//! §5.7.7.5 channel-pair element → QMF synthesis × 2) when the
//! substream provides an `acpl_config_1ch` plus `acpl_data_1ch`,
//! emitting two PCM channels in place of the duplicate-of-primary
//! fallback. Per-substream
//! [`acpl_synth::AcplSubstreamState`] (alpha-diff + beta-diff +
//! `AcplCpeState` decorrelator + ducker) lives on the decoder so
//! IIR delay-lines and `acpl_<SET>_q_prev` survive across frames.
//! ASPX_ACPL_1's joint-MDCT residual layer (b_dual_maxsfb = 1 with
//! `chparam_info()`) now walks end-to-end as of round-18:
//! [`asf::parse_chparam_info`] (§4.2.10.1 Table 47) +
//! [`asf::parse_sap_data`] (Table 48) drive the joint shell,
//! `parse_aspx_acpl1_mdct_body` walks the dual M/S residuals (long
//! frame + single window group), and the decoder feeds both into
//! [`acpl_synth::run_acpl_1ch_pcm_stereo`] (x0 = M, x1 = S into
//! Pseudocode 116) for the full stereo synth.
//!
//! * **Speech Spectral Frontend (SSF) tables + arithmetic decoder
//! core** — the full Annex C scalar-table inventory now lands in
//! [`ssf_tables`]: `POST_GAIN_LUT` (C.1), `PRED_GAIN_QUANT_TAB`
//! (C.3), `PRED_RFS_TABLE` / `PRED_RTS_TABLE` (C.4 / C.5), the
//! 705-entry `CDF_TABLE` (C.7), `PREDICTOR_GAIN_CDF_LUT` (C.8),
//! `ENVELOPE_CDF_LUT` (C.9), the 256-entry `DITHER_TABLE` (C.10)
//! and `RANDOM_NOISE_TABLE` (C.11), `STEP_SIZES_Q4_15` (C.12),
//! `AC_COEFF_MAX_INDEX` (C.13), and the four `SLOPES_*` /
//! `OFFSETS_*` dB↔linear LUTs (C.14). The 37 SSF prediction-
//! coefficient matrices from Annex C.6 (~22 KB total) live in
//! [`ssf_pred_coeff`] addressable via
//! [`ssf_pred_coeff::ssf_pred_coeff_mat`]. Every byte in every
//! table is validated against the ETSI accompaniment file by the
//! `validate_ssf_*` integration tests. The arithmetic decoder
//! itself ([`ssf_ac::AcState`]) implements §5.2.8 Pseudocodes 41-47
//! (`AcDecoderInit` / `AcDecodeTarget` / `AcDecode` /
//! `AcDecodeSymbolExtCdf` / `AcDecodeFinish`) plus Pseudocode 51-53
//! (`Idx2Reconstruction` + `CdfEst` for the computed-CDF
//! transform-coefficient path) and the §5.2.8.3 random-number
//! generator ([`ssf_ac::SsfRandGenState`], Pseudocodes 54-57).
//! Wired-up convenience functions: [`ssf_ac::decode_envelope_indices`]
//! (Pseudocode 48), [`ssf_ac::decode_predictor_gain`] (Pseudocode 49),
//! [`ssf_ac::decode_coefficient_indices`] (Pseudocode 50). The
//! `ssf_data()` / `ssf_granule()` / `ssf_st_data()` / `ssf_ac_data()`
//! bitstream walkers (Tables 43-46) are the next round's scope —
//! the AC decoder building blocks are now in place.
//!
//! * **SSF bitstream walker** — [`ssf::parse_ssf_data`] /
//! [`ssf::parse_ssf_granule`] / [`ssf::parse_ssf_st_data`] /
//! [`ssf::parse_ssf_ac_data`] implement Tables 43-46 end-to-end. The
//! walker derives the SSF block layout per Table 112 (48 kHz family)
//! via [`ssf::SsfFrameConfig::from_frame_len_base`], builds
//! `start_bin[]` / `end_bin[]` / `num_bins` from the Annex C.1
//! bandwidths matrix ([`ssf::SSF_BANDWIDTHS`]) per §4.3.7.5
//! Pseudocode 7, drains the per-block predictor / static fields, and
//! drives the §5.2.8 arithmetic decoder ([`ssf_ac::AcState`]) for
//! `env_curr_ac_bits` / `env_startup_ac_bits` /
//! `predictor_gain_ac_bits[block]` /
//! `q_mdct_coefficients_ac_bits[block]`. Per-channel
//! [`ssf::SsfChannelState`] carries forward dither / noise RNG state
//! (reset per SSF-I-frame per Pseudocode 55) plus
//! `prev_pred_lag_idx` / `last_num_bands` / `env_prev[]`. The walker
//! is wired into `asf::walk_ac4_substream` for both the mono path
//! (`spec_frontend == SSF` no longer returns `Unsupported`) and the
//! split-MDCT stereo + ASPX_ACPL_1 paths (per-channel SSF/ASF
//! selection). Parsed payload lands on
//! [`asf::SubstreamTools::ssf_data_primary`] /
//! `ssf_data_secondary` for downstream synthesis.
//!
//! Known gaps (Unsupported or stubbed):
//!
//! * Short / grouped frames (`num_window_groups > 1`) — round 28 lands
//! the mono / stereo `sf_data(ASF)` walker per Tables 39-42 (each
//! `asf_*_data()` body has its own outer `for (g; ...)` loop, with a
//! single `reference_scale_factor` and single `b_snf_data_exists` at
//! the head). Multichannel layouts (5.X / 7.X) still use the r24
//! per-group interleaved walker. MDCT synthesis for the per-group
//! spectra (concatenated group-major in
//! `tools.scaled_spec_primary` / `tools.scaled_spec_secondary`) is
//! not yet hooked through the decoder.
//! * Remaining §5.7.6.4 A-SPX HF regeneration — non-FIXFIX interval
//! classes (FIXVAR / VARFIX / VARVAR) still fall back to the
//! flat-gain scaffold; the limiter (§5.7.6.4.2.2) and TNS
//! (§5.7.6.4.1) paths only run on FIXFIX framing today. The TNS
//! pipeline is fully implemented in [`aspx_tns`] but per-channel
//! `master_reset` semantics (resetting `prev_chirp_array` / the
//! `Q_low_prev` history) when a new substream starts mid-stream
//! isn't surfaced through the decoder API yet.
//! * A-CPL data-path decoder hookup — `ASPX_ACPL_2` (mono MDCT body)
//! was fully wired in round-17, and `ASPX_ACPL_1` (joint-MDCT body
//! with `chparam_info()` driving M/S coupling) is now wired in
//! round-18: parser walks the full dual-residual body, decoder
//! IMDCTs both M and S spectra and feeds them as `x0` / `x1` into
//! the §5.7.7.5 channel-pair element. Round-21 lands the §5.7.7.6.2
//! ASPX_ACPL_3 transform-matrix synthesis math (`Transform()`,
//! `ACplModule2()`, `ACplModule3()`, `run_pseudocode_118_5x()` —
//! Pseudocodes 118 / 119); the 5_X-walker glue from the bitstream
//! into the new transform synthesis is the next round's scope.
//! Multichannel `5_X_codec_mode = ASPX_ACPL_1` / `ASPX_ACPL_2`
//! wrappers (Pseudocode 117) are still pending — the building blocks
//! are all in place but the 5-input wrapper is not wired.
//! * **Speech Spectral Frontend (SSF) PCM synthesis** — round 31 lands
//! the §5.2.3-5.2.7 chain in [`ssf_synth`]: envelope decoder
//! ([`ssf_synth::decode_envelope`] / [`ssf_synth::interpolate_envelope`] /
//! [`ssf_synth::decode_gains`] / [`ssf_synth::refine_envelope`] —
//! Pseudocodes 4a-4d), predictor parameter calculation
//! ([`ssf_synth::decode_predictor`] — Pseudocode 4e), helper
//! variables and lossless-decoding allocation table
//! ([`ssf_synth::compute_helpers`] / [`ssf_synth::build_alloc_table`] —
//! Pseudocodes 26 + 31 no-rfu path), inverse quantizer
//! ([`ssf_synth::inverse_quantize_block`] /
//! [`ssf_synth::mmse_laplace`] — Pseudocodes 32 / 33), inverse
//! heuristic scaling ([`ssf_synth::inverse_heuristic_scale`] —
//! Pseudocode 34), C-matrix reconstruction
//! ([`ssf_synth::build_c_matrix`] — Pseudocode 39), subband
//! predictor ([`ssf_synth::SubbandPredictorState::run`] —
//! Pseudocodes 35-37) and inverse flattening
//! ([`ssf_synth::inverse_flatten`] — Pseudocode 38). The decoder
//! ([`decoder::Ac4Decoder::receive_frame`]) now consumes
//! `tools.ssf_data_primary` / `tools.ssf_data_secondary` and runs
//! `synthesize_ssf_data` → IMDCT → KBD overlap-add per channel,
//! producing real PCM in place of silence for SSF substreams. The
//! heuristic-scaling helpers (§5.2.5.2.2 Pseudocodes 27 / 28 /
//! 29 / 30) are deferred — the spec's `f_rfu == 0` short-circuit
//! short-circuits to the no-heuristic path the synth already
//! supports, covering any block with the predictor disabled.
//! * Spectral noise fill synthesis — `asf_snf_data()` parses the
//! Huffman-coded indices but doesn't inject shaped noise into
//! zero bands yet.
//! * `emdf_payloads_substream()` parsing — the outer
//! [`metadata::parse_metadata`] walker errors out when
//! `b_emdf_payloads_substream == 1` rather than mis-aligning the
//! bitstream. Implementing §4.2.4.4 / §4.2.14.14 EMDF payloads is the
//! next step before real-bitstream metadata can fully round-trip.
//! `walk_ac4_substream` itself doesn't yet invoke the metadata walker
//! — that wiring is the follow-up to this round.
//! * TS 103 190-2 IFM (immersive / object) decoding — round 47 lands the
//! v2 TOC walker (`bitstream_version >= 2` dispatch in
//! [`toc::parse_ac4_toc`] running `ac4_presentation_v1_info()` per
//! §6.2.1.3 + `ac4_substream_group_info()` per §6.3.2.5 +
//! `ac4_substream_info_chan()` per §6.2.1.8) and the matching
//! [`encoder_ims::Ac4ImsEncoder`] tone-encoder
//! ([`encoder_ims::Ac4ImsEncoder::encode_frame_mono_tone`] /
//! [`encoder_ims::Ac4ImsEncoder::encode_frame_mono_tone_at_hz`])
//! that produces a v2 frame whose mono SIMPLE/ASF audio body
//! round-trips through [`decoder::Ac4Decoder`] to non-silent PCM.
//! Object / a-joc substream parsing inside
//! `ac4_substream_group_info()` is still deferred — the walker
//! surfaces `Unsupported` on the first object substream.
//! * Encoder for arbitrary PCM input — round 47 ships a closed-form
//! canned-tone encoder
//! ([`encoder_ims::build_mono_simple_asf_tone_body`]). MDCT analysis,
//! scalefactor selection, and ASF entropy coding for arbitrary input
//! PCM are the next step.
//!
//! The decoder emits real PCM for long-frame, single-window-group
//! mono and stereo SIMPLE/ASF streams. The stereo path covers both
//! the split-MDCT layout (two independent ASF spectra) and the joint
//! `b_enable_mdct_stereo_proc == 1` mode (shared sections +
//! scalefactors, two residuals, per-sfb `ms_used[]` inverse
//! L = M + S / R = M - S per §7.5). Everything else falls back to
//! silence with a correctly-shaped AudioFrame.
use ;
use ;
/// Canonical codec id.
pub const CODEC_ID_STR: &str = "ac4";
/// Register the AC-4 decoder in a codec registry.
/// Unified registration entry point — installs AC-4 into the codec
/// sub-registry of the supplied [`oxideav_core::RuntimeContext`].
register!;