Skip to main content

oxideav_opus/
lib.rs

1//! # oxideav-opus
2//!
3//! **Status:** orphan-rebuild scaffold (post 2026-05-20 audit).
4//!
5//! The prior implementation was retired under the workspace clean-room
6//! policy. The crate is being re-implemented from scratch against
7//! RFC 6716 + RFC 8251 + RFC 7587 + RFC 7845 using only material under
8//! `docs/` and black-box validator binaries (`opusdec` / `opusenc`).
9//!
10//! ## Current surface
11//!
12//! * Round 1 lands the [`OpusTocByte`] parser per RFC 6716 §3.1
13//!   (Table 2, Table 3, Table 4 — the 32-config × stereo-flag ×
14//!   frame-count-code triple that prefixes every well-formed Opus
15//!   packet).
16//! * Round 2 lands the [`OpusPacket`] §3.2 frame-packing parser for
17//!   all four `c` codes (code 0 single frame; code 1 two equal-size;
18//!   code 2 two unequal with §3.2.1 length encoding; code 3 signalled
19//!   frame count with optional VBR per-frame lengths and Opus
20//!   padding). The returned slices borrow from the input packet, so
21//!   the SILK / CELT decoders can be hooked up against them in a
22//!   subsequent round without copying.
23//! * Round 3 lands the [`RangeDecoder`] RFC 6716 §4.1 range coder —
24//!   the shared entropy primitive consumed by both the SILK and CELT
25//!   layers. The sibling `oxideav-celt` crate owns an independent
26//!   clean-room copy of the same primitive; both crates carry their
27//!   own copy until a shared low-level primitives crate exists.
28//! * Round 4 lands the [`SilkFrameHeader`] decoder for RFC 6716
29//!   §4.2.7.1 (stereo prediction weights), §4.2.7.2 (mid-only flag),
30//!   §4.2.7.3 (frame type / quantization-offset type), and §4.2.7.5.1
31//!   (normalized LSF stage-1 codebook index `I1`). These are the four
32//!   structural decisions that gate every subsequent SILK stage
33//!   (gains, LSF stage-2, LTP, excitation). Implemented as
34//!   inverse-CDF reads against the range decoder, with the PDFs
35//!   transcribed from Tables 6, 8, 9, and 14.
36//! * Round 5 lands the [`SubframeGains`] decoder for RFC 6716
37//!   §4.2.7.4 — per-subframe quantization gains for the two- or
38//!   four-subframe SILK frame. The first subframe is **independently**
39//!   coded (Table 11 signal-type-conditioned MSB PDF + Table 12
40//!   uniform LSB PDF + the `max(gain_index, previous_log_gain - 16)`
41//!   clamp from §4.2.7.4) when the §4.2.7.4 enumeration triggers;
42//!   otherwise it's coded as a 41-symbol delta (Table 13) against
43//!   the previous coded subframe gain via the `clamp(0,
44//!   max(2*delta - 16, prev + delta - 4), 63)` rule. All subsequent
45//!   subframes in the frame use the delta path. Output is integer
46//!   `log_gain` in `0..=63`; the §4.2.7.4 tail-end `gain_Q16`
47//!   conversion (`silk_log2lin`) is part of the excitation stage
48//!   and not wired up yet.
49//!
50//! * Round 6 lands the [`LsfStage2`] decoder for RFC 6716 §4.2.7.5.2 —
51//!   the per-coefficient stage-2 residual indices `I2[k] ∈ [-10, 10]`
52//!   plus the backwards-prediction-undone `res_Q10[k]`. Tables 15
53//!   (NB/MB) and 16 (WB) are the eight signal-shape codebooks; Tables
54//!   17 (NB/MB) and 18 (WB) map `(I1, k)` → codebook letter; Table 19
55//!   is the 7-cell extension PDF for the `|I2| == 4` saturation case;
56//!   Table 20 holds the four prediction-weight lists (A/B for NB/MB,
57//!   C/D for WB); Tables 21 (NB/MB) and 22 (WB) map `(I1, k)` →
58//!   weight-list. Output stops at `res_Q10[]`.
59//!
60//! * Round 7 lands the [`NlsfReconstructed`] decoder for RFC 6716
61//!   §4.2.7.5.3 — the stage-1 codebook lookup (Tables 23 NB/MB and
62//!   24 WB carrying `cb1_Q8[]` for each `I1 ∈ 0..32`), the
63//!   low-complexity Inverse Harmonic Mean Weighting (IHMW) derivation
64//!   of `w_Q9[k]` from `cb1_Q8[]` via
65//!   `w2_Q18[k] = (1024/(cb1_Q8[k]-cb1_Q8[k-1]) + 1024/(cb1_Q8[k+1]-cb1_Q8[k])) << 16`
66//!   reduced through the spec's square-root approximation, and the
67//!   final reconstructed
68//!   `NLSF_Q15[k] = clamp(0, (cb1_Q8[k]<<7) + (res_Q10[k]<<14)/w_Q9[k], 32767)`.
69//!   The §4.2.7.5.5 interpolation step that consumes the stabilized
70//!   `NLSF_Q15[]` is deferred to a later round.
71//!
72//! * Round 8 lands the [`NlsfStabilized`] decoder for RFC 6716
73//!   §4.2.7.5.4 — the normalized-LSF stabilization that enforces the
74//!   Table 25 minimum spacing between consecutive `NLSF_Q15[]` entries.
75//!   Up to 20 distortion-minimizing re-centring passes run first
76//!   (finding the smallest-spacing pair, then the `min_center` /
77//!   `max_center` / `center_freq` re-centring, with special handling
78//!   for the implicit `NLSF_Q15[-1] = 0` and `NLSF_Q15[d_LPC] = 32768`
79//!   edges), falling back after the 20th pass to a guaranteed sort +
80//!   forward-`max` + backward-`min` sweep. The fallback's forward sweep
81//!   uses 16-bit saturating addition per the RFC 8251 §7 erratum.
82//!
83//! * Round 9 lands the [`LsfInterpolated`] decoder for RFC 6716
84//!   §4.2.7.5.5 — the normalized-LSF interpolation that produces the
85//!   first-half coefficients of a 20 ms SILK frame. A Q2 factor
86//!   `w_Q2 ∈ 0..=4` is decoded from the Table 26 PDF and
87//!   `n1_Q15[k] = n0_Q15[k] + (w_Q2*(n2_Q15[k] - n0_Q15[k]) >> 2)` blends
88//!   the prior coded frame's NLSF vector (`n0`) with the current
89//!   stabilized one (`n2`). After a decoder reset or an uncoded regular
90//!   side-channel SILK frame the factor is still decoded (to keep the
91//!   range coder in sync) but discarded and `4` is used instead; for a
92//!   10 ms SILK frame no factor is present at all.
93//!
94//! * Round 10 lands the [`LpcQ17`] core converter for RFC 6716
95//!   §4.2.7.5.6 — the NLSF → LPC reconstruction (`silk_NLSF2A`). The
96//!   Table 28 Q12 cosine table with linear interpolation produces the
97//!   re-ordered Q17 cosine vector `c_Q17[]` per Table 27, the
98//!   `silk_NLSF2A_find_poly` P/Q recurrence runs in i64 to absorb the
99//!   "up to 48 bits of intermediate precision" the spec calls out, and
100//!   the last-row sum/difference assembly produces the 32-bit
101//!   `a32_Q17[]`.
102//!
103//! * Round 11 lands the §4.2.7.5.7 range-limiting bandwidth expansion
104//!   ([`LpcQ17::range_limited`]) — up to 10 rounds of `silk_bwexpander_32`
105//!   chirping (`maxabs_Q12 = min((maxabs_Q17 + 16) >> 5, 163838)`, chirp
106//!   factor `sc_Q16[0] = 65470 - ((maxabs_Q12 - 32767) << 14) /
107//!   ((maxabs_Q12 * (k+1)) >> 2)`) that shrink the raw `a32_Q17[]` until
108//!   it fits a signed 16-bit Q12 value, followed by the documented
109//!   post-loop Q12 saturation `clamp(-32768, (a + 16) >> 5, 32767) << 5`.
110//!   The result is held in the Q17 domain for the §4.2.7.5.8
111//!   prediction-gain limiting that follows.
112//!
113//! * Round 12 lands the §4.2.7.5.8 prediction-gain limiting
114//!   ([`LpcQ17::prediction_gain_limited`] → [`LpcQ12`]) — the
115//!   `silk_LPC_inverse_pred_gain_QA()` stability test (DC-response check
116//!   plus the fixed-point Levinson recurrence on the Q24-widened Q12
117//!   coefficients, with the `abs(a32_Q24[k][k]) > 16773022` and
118//!   `inv_gain_Q30[k] < 107374` instability bounds) driving up to 16
119//!   rounds of bandwidth expansion with `sc_Q16[0] = 65536 - (2<<i)`.
120//!   The result is the final stable Q12 filter `a_Q12[k]` consumed by the
121//!   §4.2.7.9.2 LPC synthesis.
122//!
123//! * Round 13 lands the §4.2.7.6 Long-Term Prediction parameters
124//!   ([`LtpParameters`]) — the primary pitch lag (§4.2.7.6.1; absolute via
125//!   Table 29 high part + Table 30 bandwidth-conditioned low part, or
126//!   relative via the Table 31 delta with a zero-delta fallback to
127//!   absolute), the pitch-contour VQ index (Table 32 PDF; Tables 33–36
128//!   codebooks) that refines the primary lag into per-subframe pitch lags
129//!   clamped to `[lag_min, lag_max]`, the §4.2.7.6.2 periodicity index
130//!   (Table 37) and per-subframe 5-tap Q7 LTP filter taps (Table 38 PDFs;
131//!   Tables 39–41 codebooks), and the §4.2.7.6.3 optional Q14 LTP scaling
132//!   factor (Table 42 → `{15565, 12288, 8192}`; default `15565` when not
133//!   coded). Non-voiced frames consume no LTP bits.
134//!
135//! * Round 14 lands the §4.2.7.7 LCG seed ([`decode_lcg_seed`]) and the
136//!   §4.2.7.8 SILK excitation decoder ([`Excitation`] / [`ExcitationConfig`]).
137//!   The excitation is decoded in six substeps: §4.2.7.8.1 rate level
138//!   (Table 45 PDFs, one symbol per SILK frame), §4.2.7.8.2 per-shell-block
139//!   pulse count (Table 46 PDFs at one of 11 rate levels; the "extra LSB"
140//!   value 17 chains into rate level 9, then 10), §4.2.7.8.3 recursive
141//!   pulse-location partition (16 → 8 → 4 → 2 → 1; Tables 47–50 select
142//!   the split PDF by partition size + remaining pulse count),
143//!   §4.2.7.8.4 per-coefficient LSB decoding (Table 51), §4.2.7.8.5
144//!   sign decoding (Table 52, picked by signal type × quantization
145//!   offset type × pulse count bin with 6+ saturating), and §4.2.7.8.6
146//!   reconstruction with the LCG `seed' = 196314165*seed + 907633515
147//!   mod 2^32` plus the Table 53 Q23 quantization offset. The result is
148//!   the final Q23 excitation `e_Q23[]` consumed by the §4.2.7.9 LTP
149//!   and LPC synthesis filters.
150//!
151//! * Round 15 lands the §4.2.7.9.2 SILK LPC synthesis filter
152//!   ([`lpc_synthesis_subframe`] / [`lpc_synthesis_frame`] /
153//!   [`LpcSynthState`]). The short-term predictor combines the §4.2.7.4
154//!   Q16 gain, the §4.2.7.9.1 residual `res[i]`, and the §4.2.7.5.8 Q12
155//!   stabilised filter `a_Q12[k]` into the unclamped `lpc[i]` and its
156//!   clamped output `out[i] = clamp(-1.0, lpc[i], 1.0)`; the per-subframe
157//!   `d_LPC` unclamped history is carried across subframes via the
158//!   stateful [`LpcSynthState`] (cleared to zero on a decoder reset).
159//!
160//! * Round 16 lands the §4.2.7.9.1 SILK LTP synthesis filter
161//!   ([`ltp_synthesis_subframe`] / [`ltp_synth_commit_subframe`] /
162//!   [`LtpSynthState`]). Unvoiced subframes produce `res[i] = e_Q23[i] /
163//!   2^23` (a normalised excitation copy). Voiced subframes go through the
164//!   §4.2.7.6 5-tap Q7 LTP convolution `res[i] = e_Q23[i]/2^23 + Σ
165//!   res[i - pitch_lag + 2 - k] * b_Q7[k]/128`, with the prior-subframe
166//!   `out[]` history rewhitened via `4*LTP_scale_Q14/gain_Q16 *
167//!   clamp(out[i] - Σ out[i-k-1] * a_Q12[k]/4096, -1, 1)` (region A) and
168//!   the prior-subframe unclamped `lpc[]` rewhitened via `65536/gain_Q16 *
169//!   (lpc[i] - Σ lpc[i-k-1] * a_Q12[k]/4096)` (region B). `out_end` and
170//!   the effective `LTP_scale_Q14` (= 16384 fresh-LPC override) follow the
171//!   §4.2.7.9.1 third/fourth-subframe LSF-interpolation-split branch. The
172//!   stateful [`LtpSynthState`] carries 306 samples of out[] and 256
173//!   samples of lpc[] history (the spec-stated WB worst cases) across
174//!   subframes and across SILK frame boundaries, cleared to zero on a
175//!   decoder reset per §4.5.2.
176//!
177//! * Round 17 lands the §4.2.8 SILK stereo unmixing
178//!   ([`stereo_ms_to_lr`] / [`StereoUnmixState`] / [`StereoWeightsQ13`] /
179//!   [`StereoFrame`]) — the `silk_stereo_MS_to_LR` conversion that turns
180//!   the decoded mid/side `out[]` signals into left/right. The side
181//!   channel is predicted from a low-passed mid term
182//!   (`p0 = (mid[i-2] + 2*mid[i-1] + mid[i]) / 4`) and the unfiltered
183//!   one-sample-delayed mid (`mid[i-1]`) via the §4.2.7.1 Q13 weights:
184//!   `left[i] = clamp(-1, (1+w1)*mid[i-1] + side[i-1] + w0*p0, 1)` and
185//!   `right[i] = clamp(-1, (1-w1)*mid[i-1] - side[i-1] - w0*p0, 1)`. The
186//!   first `n1` samples (64 NB / 96 MB / 128 WB) interpolate the weights
187//!   from the previous frame's `(prev_w0_Q13, prev_w1_Q13)` to the
188//!   current frame's; the remainder use the current weights. An uncoded
189//!   side channel (§4.2.7.2) is treated as all-zero. The two trailing
190//!   mid samples, one trailing side sample, and previous-frame weights
191//!   carry across the frame boundary via [`StereoUnmixState`], cleared
192//!   to zero on a decoder reset per §4.2.8.
193//!
194//! * Round 19 lands the §4.2.9 SILK resampler delay budget and the
195//!   internal-vs-output sample-rate accounting ([`silk_resampler_delay_ms`] /
196//!   [`silk_resampler_delay_samples_at`] / [`silk_internal_rate_hz`] /
197//!   [`silk_frame_samples_internal`] / [`silk_frame_samples_at_output`] /
198//!   [`is_supported_output_rate`] / [`SUPPORTED_OUTPUT_RATES_HZ`]).
199//!   The §4.2.9 resampler itself is non-normative ("a decoder can use
200//!   any method it wants"); what IS normative is the Table 54 maximum
201//!   delay allocation (NB = 0.538 ms, MB = 0.692 ms, WB = 0.706 ms) so
202//!   the encoder can apply a matching pre-delay to keep SILK and CELT
203//!   aligned across a §4.5 mode switch. This module owns Table 54 plus
204//!   the implied SILK internal rates (NB = 8000 Hz, MB = 12000 Hz,
205//!   WB = 16000 Hz) and the §4.2.9 supported output rates (8 / 12 / 16 /
206//!   24 / 48 kHz). SWB and FB never reach the §4.2.9 SILK stage and are
207//!   rejected with `None`.
208//!
209//! * Round 18 lands the §4.2.3 SILK packet-level header bits and the
210//!   §4.2.4 per-frame LBRR flags ([`SilkHeaderBits`] / [`silk_frame_count`]).
211//!   For each channel (mono: 1; stereo: 2), the decoder reads N uniform
212//!   `dec_bit_logp(1)` VAD bits (N = SILK-frame count from §4.2.2: 1 for
213//!   10/20 ms Opus frames, 2 for 40 ms, 3 for 60 ms) followed by a single
214//!   global LBRR flag. For Opus frames longer than 20 ms, each channel
215//!   whose global LBRR flag is set then contributes one Table 4 symbol
216//!   (`{0, 53, 53, 150}/256` for 40 ms / `{0, 41, 20, 29, 41, 15, 28,
217//!   82}/256` for 60 ms) carrying a per-SILK-frame LBRR bitmap, packed
218//!   LSB-to-MSB. For 10/20 ms Opus frames the global LBRR flag itself
219//!   implies a single LBRR frame. Output is a [`SilkHeaderBits`]
220//!   carrying the per-channel VAD bitmap, global LBRR flag, and the
221//!   fully expanded per-channel × per-SILK-frame [`PerFrameLbrr`]
222//!   bitmap consumed by the downstream §4.2.5 LBRR / §4.2.6 regular
223//!   SILK frame loop.
224//!
225//! * Round 20 lands the first CELT-layer fragment ([`CeltHeaderPrefix`] /
226//!   [`CeltPostFilter`]) — the §4.3, Table 56 pre-band header symbols
227//!   that every CELT-bearing Opus frame opens with: `silence`
228//!   (`{32767, 1}/32768`), the §4.3.7.1 pitch post-filter parameter
229//!   group (logp=1 enable bit, then `octave` uniform[0,6), `period =
230//!   (16<<octave) + fine_pitch - 1` from `4+octave` raw bits bounded
231//!   to `15..=1022`, `gain` 3 raw bits ⇒ `G = 3*(gain_index+1)/32`,
232//!   `tapset` `{2,1,1}/4`), the §4.3.1 `transient` (`{7,1}/8`), and
233//!   the §4.3.2.1 `intra` (`{7,1}/8`) flag. When `silence` is set,
234//!   the rest of the prefix is force-defaulted per the §4.3
235//!   shortcut. This is the only Table-56 segment that fits between
236//!   the SILK pipeline already wired up and the §4.3.2.1 coarse
237//!   energy (#936, blocked on the Laplace decoder + `e_prob_model`
238//!   table) / §4.3.3 bit allocation (#943, blocked on `cache_caps50`
239//!   + `LOG2_FRAC_TABLE`) sub-pieces.
240//!
241//! * Round 21 lands the §3.1 / §4.2 framing dispatch ([`OpusFrameRouting`]
242//!   / [`OperatingMode`] / [`SilkBandwidth`]) — the single
243//!   pure-function lookup that turns an [`OpusTocByte`] into the
244//!   per-Opus-frame routing decision a §4 decoder needs *before* it
245//!   touches the range coder: which layer(s) are present (SILK-only /
246//!   Hybrid / CELT-only), the SILK internal bandwidth (pinned to WB
247//!   for Hybrid per §4.2 even when the TOC bandwidth is SWB / FB), the
248//!   §4.2.2 SILK-frame count per channel (1 for 10/20 ms, 2 for 40 ms,
249//!   3 for 60 ms), the §4.2.4 per-frame LBRR-flag presence gate
250//!   (duration > 20 ms), and the channel-count multiplier for stereo.
251//!   Codifies the dispatch decision so downstream decoders consume one
252//!   `OpusFrameRouting` instead of open-coding the
253//!   `(mode, bandwidth, frame_size)` switch each time.
254//!
255//! * Round 23 lands the §4.2.7.4 SILK gain dequantization tail
256//!   ([`silk_log2lin`] / [`silk_gains_dequant`] /
257//!   [`SubframeGains::dequant_q16`](crate::silk_gains::SubframeGains::dequant_q16))
258//!   — the piecewise-linear approximation of `2^(inLog_Q7/128)` and the
259//!   composed `log_gain ∈ 0..=63 → gain_Q16 ∈ [81920, 1_686_110_208]`
260//!   mapping that the §4.2.7.9.1 LTP and §4.2.7.9.2 LPC synthesis
261//!   filters consume. The two §4.2.7.4 endpoints (`log_gain = 0`
262//!   ⇒ `81920` = 1.25× linear; `log_gain = 63` ⇒ `1_686_110_208` ≈
263//!   25 728× linear) are pinned to the RFC text. The §4.2.7.5 NLSF
264//!   stages had been deferred since round 5; this round closes that gap.
265//!
266//! * Round 24 lands the §4.3 CELT MDCT-band layout
267//!   ([`celt_band_layout`]: [`CeltFrameSize`] + Table 55
268//!   `bins_per_channel` lookups via [`celt_band_bins_per_channel`] +
269//!   [`celt_band_start_hz`] / [`celt_band_stop_hz`] band-edge
270//!   accessors + [`celt_band_at_hz`] reverse lookup + the §4.3
271//!   "first 17 bands not coded in Hybrid mode" rule baked into
272//!   [`celt_first_coded_band`] / [`HYBRID_FIRST_CODED_BAND`] + the
273//!   [`celt_total_bins_per_channel`] column-sum helper). The standard
274//!   non-Custom CELT layer's [`CELT_NUM_BANDS`] = 21 bands and the
275//!   per-band MDCT bin counts at the four CELT frame sizes (2.5 / 5
276//!   / 10 / 20 ms) are the lookup every §4.3.2 coarse-energy decoder,
277//!   §4.3.3 bit allocator, §4.3.4 PVQ shape decoder, §4.3.6
278//!   denormaliser, and §4.3.7 inverse-MDCT pass needs before any
279//!   band-loop iteration can start.
280//!
281//! * Round 25 lands the §4.3.4.5 CELT TF-resolution adjustment lookup
282//!   ([`celt_tf_adjust`]: Tables 60–63 [`TF_ADJ_NONTRANSIENT_SELECT0`]
283//!   / [`TF_ADJ_NONTRANSIENT_SELECT1`] / [`TF_ADJ_TRANSIENT_SELECT0`]
284//!   / [`TF_ADJ_TRANSIENT_SELECT1`] +
285//!   [`celt_tf_adjustment`](crate::celt_tf_adjust::celt_tf_adjustment)
286//!   `(frame_size, transient, tf_select, tf_change) -> i8` entry +
287//!   the §4.3.1
288//!   [`celt_tf_select_can_affect`](crate::celt_tf_adjust::celt_tf_select_can_affect)
289//!   "tf_select is only decoded if it can have an impact on the
290//!   result knowing the value of all per-band tf_change flags" gate +
291//!   [`TfDirection`] classification (`Unchanged` / `IncreaseTime(N)` /
292//!   `IncreaseFrequency(N)`) carrying the §4.3.4.5 Hadamard-transform
293//!   level count). The §4.3.4.5 band loop downstream — gated on
294//!   §4.3.2.1 coarse energy + §4.3.3 bit allocation, both still
295//!   deferred — turns each per-band `tf_change[b]` bit into one of
296//!   these adjustments before the §4.3.4.2 PVQ shape decoder runs.
297//!
298//! * Round 26 lands the §4.5.1 CELT redundancy / mode-transition side
299//!   information ([`decode_redundancy`] / [`RedundancyDecision`] /
300//!   [`RedundancyPosition`]) — the three-step procedure that decides
301//!   whether an Opus frame embeds an extra 5 ms redundant CELT frame
302//!   for a clean mode transition. §4.5.1.1 implicit signalling for
303//!   SILK-only Opus frames (the 17-bit remaining-budget gate),
304//!   §4.5.1.1 explicit signalling for Hybrid Opus frames (the 37-bit
305//!   gate + Table 64 `{4095, 1}/4096` flag), §4.5.1.2 redundancy
306//!   position (Table 65 `{1, 1}/2` uniform symbol: 0 = end-of-frame
307//!   / first-frame-in-transition, 1 = start-of-frame / second-frame-
308//!   in-transition), and §4.5.1.3 redundancy size (SILK-only =
309//!   remaining whole bytes; Hybrid = `2 + dec_uint(256)` with the
310//!   "claimed > remaining" branch routed to [`RedundancyDecision::Invalid`]
311//!   per the §4.5.1.3 "stop decoding and discard" recommendation).
312//!   CELT-only Opus frames bypass the §4.5.1 path entirely. This
313//!   round does NOT decode the redundant CELT frame itself — that
314//!   requires the §4.3.2.1 / §4.3.3 blockers (#936 / #943) — only
315//!   the boundary metadata that tells the caller WHERE the redundant
316//!   CELT bytes start and HOW MANY of them there are.
317//!
318//! * Round 28 lands the §4.5.1.4 redundant-CELT-frame decode
319//!   parameters and the §4.5.1.4 cross-lap placement
320//!   ([`redundant_frame_params`] / [`RedundantFrameParams`] /
321//!   [`CrossLapPlacement`] / [`apply_mb_to_wb_override`] /
322//!   [`REDUNDANT_FRAME_TENTHS_MS`] / [`REDUNDANT_CROSS_LAP_TENTHS_MS`])
323//!   — the pure-function lookup that turns an [`OpusFrameRouting`]
324//!   plus a [`RedundancyDecision`] into the four normative
325//!   §4.5.1.4 facts a §4.3 CELT decoder needs to actually decode
326//!   the redundant frame: "no TOC byte" (just feed the redundant
327//!   bytes into the CELT decoder), 5 ms fixed duration
328//!   ([`REDUNDANT_FRAME_TENTHS_MS`] = 50 tenths-ms), channel count
329//!   inherited from the carrier Opus frame, and audio bandwidth
330//!   inherited from the carrier with the §4.5.1.4 "MB SILK frames
331//!   → WB" exception ([`apply_mb_to_wb_override`]). Also lands the
332//!   §4.5.1.4 cross-lap placement decision
333//!   ([`CrossLapPlacement::FirstHalfAsIs`] for [`RedundancyPosition::Beginning`]
334//!   — CELT→SILK/Hybrid transitions, where the redundant CELT
335//!   frame's first 2.5 ms replace the SILK/Hybrid leading 2.5 ms
336//!   and the second 2.5 ms cross-lap; [`CrossLapPlacement::SecondHalfAsIs`]
337//!   for [`RedundancyPosition::End`] — SILK/Hybrid→CELT
338//!   transitions, where only the redundant frame's second 2.5 ms
339//!   is used and that half cross-laps with the SILK/Hybrid
340//!   trailing edge). The §4.3.7 power-complementary MDCT window
341//!   that actually performs the cross-lap mix is gated on the
342//!   undelivered §4.3.2 / §4.3.3 / §4.3.4 chain; this round owns
343//!   only the placement metadata (which 2.5 ms region cross-laps,
344//!   where in the carrier's sample buffer it sits).
345//!
346//! * Round 29 lands the §4.3.2.1 CELT coarse-energy Laplace-model
347//!   parameter surface ([`celt_e_prob_model`]: [`E_PROB_MODEL`] —
348//!   the 336-byte `[LM ∈ 0..4][mode ∈ {inter, intra}][band × 2]` Q8
349//!   `{prob, decay}` table feeding `ec_laplace_decode` +
350//!   [`EnergyPredictionMode::{Inter, Intra}`] selector driven by the
351//!   §4.3.2.1 CELT header `intra` flag + [`e_prob_pair`] / [`e_prob_row`]
352//!   accessors returning [`EProbPair`] / `&[u8; 42]` + the
353//!   [`INTRA_PRED_ALPHA_Q15`] / [`INTRA_PRED_BETA_Q15`] / [`Q15_ONE`]
354//!   intra-mode prediction-coefficient constants (`alpha = 0`,
355//!   `beta = 4915 / 32768` per RFC 6716 §4.3.2.1 p. 108)). This is the
356//!   parameter-surface fragment needed before the §4.3.2.1
357//!   Laplace decoder + 2-D `(time, frequency)` predictor can run;
358//!   the decoder itself and the per-LM inter-mode `(alpha, beta)`
359//!   pair were deferred (the latter landed in round 45 —
360//!   [`INTER_PRED_ALPHA_Q15`] / [`INTER_PRED_BETA_Q15`] /
361//!   [`energy_pred_coef`] returning [`EnergyPredCoef`], the Q15
362//!   numerators fixed by the RFC 6716 Appendix A normative
363//!   reference code).
364//!
365//! * Round 30 lands the §4.3.3 *intensity-stereo reservation*
366//!   parameter surface ([`celt_log2_frac_table`]:
367//!   [`LOG2_FRAC_TABLE`] — the 24-byte Q3 (1/8-bit) conservative
368//!   `log2` table feeding the §4.3.3 `intensity_rsv =
369//!   LOG2_FRAC_TABLE[end − start]` reservation + [`log2_frac`] typed
370//!   accessor + [`log2_frac_row`] full-row borrow + the
371//!   [`Q3_BITS_PER_WHOLE_BIT`] = 8 unit-denominator constant). This
372//!   is a parameter-surface piece of the §4.3.3 bit-allocation
373//!   procedure; the boost / trim / anti-collapse / skip / dual-stereo
374//!   reservations, the Table 57 static allocation search, the
375//!   `cache_caps50` per-band maximum, and the rest of the §4.3.3
376//!   allocation loop are all out of scope for this round.
377//!
378//! * Round 31 lands the §4.3.3 *per-band maximum-allocation* parameter
379//!   surface ([`celt_cache_caps50`]: [`CACHE_CAPS50`] — the 168-byte
380//!   `[LM ∈ 0..4][stereo ∈ {mono, stereo}][band ∈ 0..21]` Q0
381//!   bits/sample table feeding the §4.3.3 per-band bit cap +
382//!   [`CacheCapsStereo::{Mono, Stereo}`] selector + [`cache_caps_value`]
383//!   / [`cache_caps_row`] accessors + [`init_caps`] /
384//!   [`cap_for_band_bits`] convert-to-bits rule
385//!   `cap[band] = ((cache_caps50[i] + 64) * channels * N) / 4` per
386//!   RFC 6716 §4.3.3 p. 113 + [`INIT_CAPS_BIAS`] / [`INIT_CAPS_DIVISOR`]
387//!   / [`INIT_CAPS_MAX_CHANNELS`] convert-rule constants). Closes the
388//!   second of the two table dependencies round 24 noted for the
389//!   §4.3.3 allocator (round 30 landed [`LOG2_FRAC_TABLE`]; this round
390//!   lands [`CACHE_CAPS50`]). The §4.3.3 bit allocation orchestration
391//!   that consumes `cap[]` (boost / trim / anti-collapse / skip /
392//!   dual-stereo reservations, the Table 57 static allocation search)
393//!   is still out of scope.
394//!
395//! * Round 32 lands the §4.3.3 *allocation trim* parameter surface
396//!   ([`celt_alloc_trim`]: [`ALLOC_TRIM_PDF`] — the Table-58 PDF
397//!   `{2, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2}/128` and its derived
398//!   [`ALLOC_TRIM_ICDF`] for [`RangeDecoder::dec_icdf`] consumption +
399//!   [`ALLOC_TRIM_DEFAULT`] = 5 / [`ALLOC_TRIM_MIN`] = 0 /
400//!   [`ALLOC_TRIM_MAX`] = 10 trim-integer range + the §4.3.3
401//!   signalling gate `(ec_tell_frac + 48) ≤ (frame_bytes * 8 −
402//!   total_boost)` in [`alloc_trim_is_signalled`] + the
403//!   [`decode_alloc_trim`] wrapper that fuses the gate, the
404//!   gate-fail-returns-default rule, and the [`RangeDecoder::dec_icdf`]
405//!   read into one typed call). The §4.3.3 use of the trim — the
406//!   per-band `trim_offsets[]` derivation that shifts the Table 57
407//!   static allocation search — is still out of scope and runs at the
408//!   call site of [`decode_alloc_trim`].
409//!
410//! * Round 33 lands the §4.3.3 *band-boost* decoder
411//!   ([`celt_band_boost`]: [`decode_band_boosts`] driver +
412//!   [`band_boost_quanta`] §4.3.3 `min(8*N, max(48, N))` helper +
413//!   [`BandBoost`] / [`BandBoostOutcome`] per-band and full-driver
414//!   outcomes carrying the §4.3.3 `total_boost` accumulator consumed
415//!   by [`decode_alloc_trim`] downstream + [`DYNALLOC_LOGP_INIT`] = 6
416//!   / [`DYNALLOC_LOGP_MIN`] = 2 / [`DYNALLOC_LOOP_LOGP_AFTER_FIRST`]
417//!   = 1 cost constants + [`BAND_BOOST_QUANTA_FLOOR_EIGHTH_BITS`] = 48
418//!   / [`BAND_BOOST_QUANTA_CEIL_MULT`] = 8 quanta-rule constants +
419//!   [`BandBoostError`] caller-side bookkeeping bugs). Bridges round
420//!   31's [`crate::celt_cache_caps50::cap_for_band_bits`] per-band
421//!   upper bound and round 32's [`decode_alloc_trim`] gate's
422//!   `total_boost` input. The §4.3.3 *use* of the per-band boost
423//!   values — the §4.3.3 Table 57 static-allocation search +
424//!   anti-collapse / skip / dual-stereo reservations — is the
425//!   responsibility of the §4.3.3 allocator and runs at the call
426//!   site of [`decode_band_boosts`].
427//!
428//! * Round 34 lands the §4.3.3 *reservation block*
429//!   ([`celt_reservations`]: [`reserve_block`] /
430//!   [`ReservationOutcome`] / [`ReservationError`] +
431//!   [`ONE_BIT_EIGHTH_BITS`] = 8 /
432//!   [`CONSERVATIVE_DEDUCTION_EIGHTH_BITS`] = 1 /
433//!   [`ANTI_COLLAPSE_LM_MIN_EXCLUSIVE`] = 1 /
434//!   [`ANTI_COLLAPSE_HEADROOM_MULT_EIGHTH_BITS`] = 8 /
435//!   [`ANTI_COLLAPSE_HEADROOM_LM_OFFSET`] = 2 reservation-cost +
436//!   gating constants). The §4.3.3 procedure (RFC 6716 §4.3.3, p. 114)
437//!   skims four fixed-cost reservations off the top of the working
438//!   `total` budget before the Table 57 static-allocation search:
439//!   `anti_collapse_rsv` (8 1/8 bits iff transient && LM > 1 &&
440//!   total ≥ (LM + 2) * 8), `skip_rsv` (8 1/8 bits iff total > 8 after
441//!   anti-collapse), `intensity_rsv = LOG2_FRAC_TABLE[end − start]`
442//!   (stereo only; reset to 0 if > total), and `dual_stereo_rsv`
443//!   (8 1/8 bits iff total > 8 after intensity). The initial `total`
444//!   is `frame_size_bytes * 64 − ec_tell_frac − 1` (the §4.3.3
445//!   conservative `-1` deduction). Bridges round 33's `total_boost`
446//!   accumulator (validated as `≤ frame_eighth − ec_tell_frac`) and
447//!   round 30's [`crate::celt_log2_frac_table::log2_frac`] lookup with
448//!   the §4.3.3 Table 57 static-allocation search at the consumer
449//!   site. The §4.3.3 *use* of the reservations — the actual
450//!   `dec_bit_logp(1)` reads of the anti-collapse / skip /
451//!   dual-stereo flags and the `ec_dec_uint(end − start)` read of the
452//!   intensity-stereo band — runs at the §4.3.3 allocator's consumer
453//!   site once the Table 57 search produces the per-band shape
454//!   allocation.
455//!
456//! * Round 35 lands the §4.3.3 *per-band minimum-allocation vector*
457//!   ([`celt_band_thresh`]: [`band_min_thresh`] /
458//!   [`compute_band_min_thresh`] / [`band_min_thresh_vec`] /
459//!   [`standard_band_window`] / [`BandThreshError`] +
460//!   [`BAND_THRESH_BINS_MULTIPLIER`] = 24 /
461//!   [`BAND_THRESH_BINS_DIVISOR`] = 16 /
462//!   [`BAND_THRESH_PER_CHANNEL_EIGHTH_BITS`] = 8 /
463//!   [`BAND_THRESH_MONO_CHANNELS`] = 1 /
464//!   [`BAND_THRESH_STEREO_CHANNELS`] = 2 formula constants). The
465//!   §4.3.3 narrative (RFC 6716 §4.3.3, p. 115) computes a hard
466//!   per-band lower bound on the shape allocation: bands whose
467//!   allocation would drop below `thresh[band]` are dropped rather
468//!   than coded sparsely. For each coded band `b`, with
469//!   `N = celt_band_bins_per_channel(b, frame_size)` and
470//!   `channels ∈ {1, 2}`, the per-band minimum is
471//!   `thresh[b] = max((24 * N) / 16, 8 * channels)` in 1/8 bits — one
472//!   whole bit per channel or 48 128th-bits per MDCT bin, whichever is
473//!   greater. The §4.3.3 narrative is explicit that the band-size
474//!   dependent term `(24 * N) / 16` is *not* scaled by the channel
475//!   count (at the very low rates where this floor binds, the
476//!   §4.3.3 allocator concentrates the budget on the mid channel).
477//!   Bridges round 24's Table 55 band layout with the §4.3.3 Table 57
478//!   static-allocation search at the consumer site (where the
479//!   per-band minimum competes with the round-31 `cap[]` per-band
480//!   maximum, the round-33 boosts, and the upcoming
481//!   `trim_offsets[]`).
482//!
483//! * Round 36 lands the §4.3.3 *per-band allocation-trim offsets*
484//!   ([`celt_trim_offsets`]: [`band_trim_offset`] /
485//!   [`band_trim_offset_for_band`] / [`band_n_shortest`] /
486//!   [`shortest_frame_size`] / [`TrimOffsetError`] +
487//!   [`TRIM_OFFSETS_BIAS`] = 5 /
488//!   [`TRIM_OFFSETS_NUMERATOR_SCALE`] = 8 /
489//!   [`TRIM_OFFSETS_DIVISOR`] = 64 /
490//!   [`TRIM_OFFSETS_WIDTH_ONE_BINS_PER_CHANNEL`] = 1 /
491//!   [`TRIM_OFFSETS_WIDTH_ONE_PER_CHANNEL_EIGHTH_BITS`] = 8 /
492//!   [`TRIM_OFFSETS_MONO_CHANNELS`] = 1 /
493//!   [`TRIM_OFFSETS_STEREO_CHANNELS`] = 2 formula constants). The
494//!   §4.3.3 narrative (RFC 6716 §4.3.3, p. 115) derives a per-band
495//!   *trim-offset* vector from the round-32 `alloc_trim` index; the
496//!   §4.3.3 Table 57 static-allocation search will add these offsets
497//!   to the per-band budget when ranking quality columns. For each
498//!   coded band `b`, with `channels ∈ {1, 2}`, `LM ∈ {0, 1, 2, 3}`,
499//!   `n_shortest = celt_band_bins_per_channel(b, Ms2_5)`,
500//!   `n_per_channel = celt_band_bins_per_channel(b, frame_size)`,
501//!   and `remaining_bands` the band-position-dependent factor:
502//!   `base = (alloc_trim - 5 - LM) * channels * n_shortest *
503//!   remaining_bands * (1 << LM) * 8 / 64`, then
504//!   `trim_offsets[b] = base - (8 * channels)` when
505//!   `n_per_channel == 1` (width-1 bands receive greater benefit
506//!   from the coarse-energy coding; the §4.3.3 narrative backs the
507//!   trim off by one whole bit per channel). All arithmetic is
508//!   signed; the output is in 1/8 bits. Bridges round 32's
509//!   [`decode_alloc_trim`] gate, round 24's Table 55 layout, and
510//!   round 35's [`band_min_thresh`] floor with the upcoming §4.3.3
511//!   Table 57 static-allocation search.
512//!
513//! * Round 38 lands the §4.5.3 *Summary of Transitions* (Figure 18
514//!   plus Figure 19) ([`celt_transitions`]: [`NormativeTransition`]
515//!   with one variant per row of Figure 18 +
516//!   [`RecommendedNonNormativeTransition`] with one variant per row
517//!   of Figure 19 + [`BoundaryOp`] lifting the §4.5.3 figure-key
518//!   markers `;` / `|` / `!` / `&` / `+` / `c` / `P` / `>` to a
519//!   typed list +
520//!   [`classify_normative_transition`](crate::celt_transitions::classify_normative_transition)
521//!   `(prev_mode, prev_silk_bw, next_mode, next_silk_bw,
522//!   redundancy_present) -> Option<NormativeTransition>` for the
523//!   Figure-18 lookup +
524//!   [`recommended_non_normative`](crate::celt_transitions::recommended_non_normative)
525//!   `(prev_mode, prev_silk_bw, next_mode, next_silk_bw) ->
526//!   Option<RecommendedNonNormativeTransition>` for the Figure-19
527//!   lookup + the
528//!   [`NormativeTransition::seam_operations`](crate::celt_transitions::NormativeTransition::seam_operations)
529//!   and
530//!   [`RecommendedNonNormativeTransition::seam_operations`](crate::celt_transitions::RecommendedNonNormativeTransition::seam_operations)
531//!   accessors returning the ordered marker list at each
532//!   transition seam, transcribed from the §4.5.3 figures). Closes
533//!   the §4.5 chain after the round-26 §4.5.1 redundancy side
534//!   information, the round-28 §4.5.1.4 cross-lap placement, and
535//!   the round-27 §4.5.2 state-reset policy. The §4.5.3
536//!   classifier's SILK-bandwidth split between Figure-18 rows 2
537//!   (NB/MB SILK to Hybrid with R) and row 3 (WB SILK to Hybrid, no
538//!   R), the symmetric Hybrid to SILK split (rows 5 and 6), and the
539//!   §4.5 "audio-bandwidth change is the glitch source" reading
540//!   that rules out same-bandwidth SILK to SILK from row 1 are all
541//!   baked in.
542//!
543//! * Round 39 lands the §4.3.3 *static allocation table*
544//!   ([`celt_static_alloc`]:
545//!   [`STATIC_ALLOC`](crate::celt_static_alloc::STATIC_ALLOC) —
546//!   the 21×11 Q5 grid `alloc[band][q]` in 1/32-bit per MDCT bin
547//!   units transcribed from RFC 6716 §4.3.3 Table 57 (p. 112) +
548//!   [`STATIC_ALLOC_Q_COUNT`](crate::celt_static_alloc::STATIC_ALLOC_Q_COUNT)
549//!   = 11 / [`STATIC_ALLOC_Q_MIN`](crate::celt_static_alloc::STATIC_ALLOC_Q_MIN)
550//!   = 0 / [`STATIC_ALLOC_Q_MAX`](crate::celt_static_alloc::STATIC_ALLOC_Q_MAX)
551//!   = 10 / [`STATIC_ALLOC_TOTAL_CELLS`](crate::celt_static_alloc::STATIC_ALLOC_TOTAL_CELLS)
552//!   = 231 / [`STATIC_ALLOC_RIGHT_SHIFT`](crate::celt_static_alloc::STATIC_ALLOC_RIGHT_SHIFT)
553//!   = 2 / [`STATIC_ALLOC_INTERP_STEPS`](crate::celt_static_alloc::STATIC_ALLOC_INTERP_STEPS)
554//!   = 64 layout / conversion constants +
555//!   [`static_alloc_cell`](crate::celt_static_alloc::static_alloc_cell)
556//!   `(band, q) -> u8` raw-cell lookup +
557//!   [`static_alloc_row`](crate::celt_static_alloc::static_alloc_row)
558//!   `(band) -> &[u8; 11]` row borrow for the §4.3.3 search's
559//!   per-band quality inner loop +
560//!   [`static_alloc_eighth_bits`](crate::celt_static_alloc::static_alloc_eighth_bits)
561//!   `(band, q, channels, n_bins, lm) -> u32` applying the §4.3.3
562//!   `channels * N * alloc[band][q] << LM >> 2` unit conversion
563//!   from Q5 to Q3 (1/8-bit) per-band units +
564//!   [`StaticAllocError`](crate::celt_static_alloc::StaticAllocError)).
565//!   Pins the §4.3.3 invariants the allocator relies on: column 0
566//!   is uniformly zero (the no-allocation floor), each row is
567//!   monotone non-decreasing in `q`, and the saturation column
568//!   (col 10) is `200` for bands 0..=7 and declines to `104` at
569//!   band 20. Bridges the round-31 cap surface, the round-33
570//!   boosts, the round-34 reservations, the round-35 minimum
571//!   threshold, and the round-36 trim offsets with the §4.3.3
572//!   1/64-step interpolated search the next round will land.
573//!
574//! * Round 40 lands the §4.3.3 *1/64-step interpolated static-allocation
575//!   search* ([`celt_alloc_search`]:
576//!   [`Q_FP_MAX`](crate::celt_alloc_search::Q_FP_MAX) = 640
577//!   fixed-point-quality bound +
578//!   [`STATIC_ALLOC_INTERP_RIGHT_SHIFT`](crate::celt_alloc_search::STATIC_ALLOC_INTERP_RIGHT_SHIFT)
579//!   = 8 combined shift constant +
580//!   [`QFpComponents`](crate::celt_alloc_search::QFpComponents)
581//!   `(q_lo, frac)` decomposition +
582//!   [`q_fp_to_components`](crate::celt_alloc_search::q_fp_to_components)
583//!   `/ q_fp_from_components` invertible accessors +
584//!   [`per_band_eighth_bits_at_q_fp`](crate::celt_alloc_search::per_band_eighth_bits_at_q_fp)
585//!   `(band, q_fp, channels, n_bins, lm) -> u64` per-band Q3 lookup
586//!   under the §4.3.3 1/64-step linear interpolation
587//!   `cell_q11 = alloc[b][q_lo] * (64 - frac) + alloc[b][q_lo + 1] *
588//!   frac` followed by the `(channels * N * cell_q11) << LM >> 8`
589//!   unit conversion that folds the round-39 `>> 2` (Q5 → Q3) with
590//!   the 1/64-step `>> 6` (Q11 → Q5) in one step +
591//!   [`total_eighth_bits_at_q_fp`](crate::celt_alloc_search::total_eighth_bits_at_q_fp)
592//!   `(q_fp, channels, frame_size, is_hybrid) -> u64` summing across
593//!   coded bands respecting the §4.3 first-coded-band rule (`0` for
594//!   CELT-only / `17` for Hybrid) +
595//!   [`search_q_fp`](crate::celt_alloc_search::search_q_fp)
596//!   `(budget, channels, frame_size, is_hybrid) -> AllocSearchOutcome`
597//!   the §4.3.3 "highest allocation that does not exceed the number
598//!   of bits remaining" linear scan returning
599//!   [`AllocSearchOutcome`](crate::celt_alloc_search::AllocSearchOutcome)
600//!   `{ q_fp, total_eighth_bits }` +
601//!   [`AllocSearchError`](crate::celt_alloc_search::AllocSearchError)).
602//!   Closes the §4.3.3 1/64-step interpolation gap round 39 noted as
603//!   the next step. The orchestrated §4.3.3 allocator that consumes
604//!   the search output (folding in the round-33 boosts, the round-35
605//!   per-band minimum threshold, the round-31 per-band cap, and the
606//!   round-36 trim offsets, then running the skip / dual-stereo /
607//!   intensity-stereo flag reads) runs at the consumer site once the
608//!   round-34 reservation block + this round's search are composed.
609//!
610//! * Round 41 lands the §4.3.4.2 *PVQ codebook-size function*
611//!   ([`celt_pvq_v`]: [`pvq_codebook_size`]`(n, k) -> Result<u32,
612//!   PvqVError>` evaluating the RFC 6716 §4.3.4.2 bivariate
613//!   recurrence `V(N, K) = V(N - 1, K) + V(N, K - 1) + V(N - 1,
614//!   K - 1)` with base cases `V(N, 0) = 1` / `V(0, K) = 0 (K != 0)`
615//!   over two rolling rows + [`PVQ_V_N_MAX`] = 352 / [`PVQ_V_K_MAX`]
616//!   = 4096 caller-side bookkeeping bounds + [`PVQ_V_MAX`] =
617//!   `2**32 − 1` overflow guard inherited from RFC 6716 §4.1.5's
618//!   `ec_dec_uint(ft)` upper bound + [`PvqVError::{NOutOfRange,
619//!   KOutOfRange, OverflowsDecUintRange}`] error reporting). The
620//!   §4.3.4.2 PVQ index decode (`ec_dec_uint(V(N, K))` followed by
621//!   the §4.3.4.2 conversion of the index to a sign-magnitude
622//!   lattice point) and the §4.3.4.1 *Bits-to-Pulses* search both
623//!   consume this primitive; both run at the consumer site.
624//!
625//! The rest of the CELT layer is not yet wired up; the [`Decoder`]
626//! / [`Encoder`] entry points still return [`Error::NotImplemented`].
627
628#![warn(missing_debug_implementations)]
629
630use oxideav_core::RuntimeContext;
631
632/// Crate-local error type.
633#[derive(Debug, Clone, Copy, PartialEq, Eq)]
634pub enum Error {
635    /// The caller passed a zero-length packet. RFC 6716 §3.1 requires
636    /// every well-formed Opus packet to contain at least one byte (R1).
637    EmptyPacket,
638    /// The packet violates one of the §3.2 frame-packing
639    /// requirements (R2..R7). Examples: a code-1 packet with an odd
640    /// payload length; a code-2 packet whose declared first-frame
641    /// length runs off the end of the buffer; a code-3 packet with
642    /// `M = 0` or whose CBR per-frame size is not an integer divisor
643    /// of the remaining payload.
644    MalformedPacket,
645    /// The clean-room rebuild has not yet wired up a working
646    /// SILK / CELT pipeline; the higher-level decode / encode paths
647    /// return this until that work lands.
648    NotImplemented,
649}
650
651impl core::fmt::Display for Error {
652    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
653        match self {
654            Error::EmptyPacket => write!(
655                f,
656                "oxideav-opus: packet is empty; RFC 6716 §3.1 R1 requires at least one byte"
657            ),
658            Error::MalformedPacket => write!(
659                f,
660                "oxideav-opus: packet violates an RFC 6716 §3.2 frame-packing requirement"
661            ),
662            Error::NotImplemented => write!(
663                f,
664                "oxideav-opus: orphan-rebuild scaffold — SILK/CELT pipeline not wired up yet"
665            ),
666        }
667    }
668}
669
670impl std::error::Error for Error {}
671
672pub mod celt_alloc_search;
673pub mod celt_alloc_trim;
674pub mod celt_band_boost;
675pub mod celt_band_layout;
676pub mod celt_band_thresh;
677pub mod celt_cache_caps50;
678pub mod celt_deemphasis;
679pub mod celt_e_prob_model;
680pub mod celt_fine_energy;
681pub mod celt_header;
682pub mod celt_log2_frac_table;
683pub mod celt_mdct_window;
684pub mod celt_post_filter;
685pub mod celt_pvq_decode;
686pub mod celt_pvq_v;
687pub mod celt_redundancy;
688pub mod celt_reservations;
689pub mod celt_spreading;
690pub mod celt_static_alloc;
691pub mod celt_tf_adjust;
692pub mod celt_transitions;
693pub mod celt_trim_offsets;
694pub mod frames;
695pub mod framing;
696pub mod framing_self_delim;
697pub mod mode_transition_reset;
698pub mod range_decoder;
699pub mod redundancy_decode_params;
700pub mod silk_excitation;
701pub mod silk_frame;
702pub mod silk_gains;
703pub mod silk_header;
704pub mod silk_lcg_seed;
705pub mod silk_log2lin;
706pub mod silk_lpc_synth;
707pub mod silk_lsf_interp;
708pub mod silk_lsf_recon;
709pub mod silk_lsf_stabilize;
710pub mod silk_lsf_stage2;
711pub mod silk_lsf_to_lpc;
712pub mod silk_ltp;
713pub mod silk_ltp_synth;
714pub mod silk_resampler;
715pub mod silk_stereo;
716pub mod toc;
717
718pub use celt_alloc_search::{
719    per_band_eighth_bits_at_q_fp, q_fp_from_components, q_fp_to_components, search_q_fp,
720    total_eighth_bits_at_q_fp, AllocSearchError, AllocSearchOutcome, QFpComponents, Q_FP_MAX,
721    STATIC_ALLOC_INTERP_RIGHT_SHIFT,
722};
723pub use celt_alloc_trim::{
724    alloc_trim_icdf, alloc_trim_is_signalled, alloc_trim_pdf, decode_alloc_trim, frame_eighth_bits,
725    AllocTrimError, ALLOC_TRIM_DEFAULT, ALLOC_TRIM_FTB, ALLOC_TRIM_ICDF, ALLOC_TRIM_MAX,
726    ALLOC_TRIM_MIN, ALLOC_TRIM_PDF, ALLOC_TRIM_PDF_DENOMINATOR, ALLOC_TRIM_PDF_LEN,
727    ALLOC_TRIM_SIGNAL_COST_EIGHTH_BITS, EIGHTH_BITS_PER_BYTE,
728};
729pub use celt_band_boost::{
730    band_boost_quanta, decode_band_boosts, BandBoost, BandBoostError, BandBoostOutcome,
731    BAND_BOOST_QUANTA_CEIL_MULT, BAND_BOOST_QUANTA_FLOOR_EIGHTH_BITS, DYNALLOC_LOGP_INIT,
732    DYNALLOC_LOGP_MIN, DYNALLOC_LOOP_LOGP_AFTER_FIRST,
733};
734pub use celt_band_layout::{
735    celt_band_at_hz, celt_band_bins_per_channel, celt_band_start_hz, celt_band_stop_hz,
736    celt_end_coded_band, celt_first_coded_band, celt_total_bins_per_channel, CeltFrameSize,
737    CELT_MAX_BINS_PER_BAND, CELT_NUM_BANDS, HYBRID_FIRST_CODED_BAND,
738};
739pub use celt_band_thresh::{
740    band_min_thresh, band_min_thresh_vec, compute_band_min_thresh, standard_band_window,
741    BandThreshError, BAND_THRESH_BINS_DIVISOR, BAND_THRESH_BINS_MULTIPLIER,
742    BAND_THRESH_MONO_CHANNELS, BAND_THRESH_PER_CHANNEL_EIGHTH_BITS, BAND_THRESH_STEREO_CHANNELS,
743};
744pub use celt_cache_caps50::{
745    cache_caps_offset, cache_caps_row, cache_caps_value, cap_for_band_bits, init_caps,
746    CacheCaps50Error, CacheCapsStereo, CACHE_CAPS50, CACHE_CAPS50_LM_COUNT,
747    CACHE_CAPS50_STEREO_COUNT, CACHE_CAPS50_STEREO_MONO, CACHE_CAPS50_STEREO_STEREO,
748    CACHE_CAPS50_TOTAL_BYTES, INIT_CAPS_BIAS, INIT_CAPS_DIVISOR, INIT_CAPS_MAX_CHANNELS,
749};
750pub use celt_deemphasis::{DeemphasisError, DeemphasisFilter, DEEMPHASIS_ALPHA_P};
751pub use celt_e_prob_model::{
752    e_prob_pair, e_prob_row, energy_pred_coef, EProbModelError, EProbPair, EnergyPredCoef,
753    EnergyPredictionMode, E_PROB_MODEL, E_PROB_MODEL_BYTES_PER_BAND, E_PROB_MODEL_BYTES_PER_ROW,
754    E_PROB_MODEL_LM_COUNT, E_PROB_MODEL_MODE_COUNT, E_PROB_MODEL_MODE_INTER,
755    E_PROB_MODEL_MODE_INTRA, E_PROB_MODEL_TOTAL_BYTES, INTER_PRED_ALPHA_Q15, INTER_PRED_BETA_Q15,
756    INTRA_PRED_ALPHA_Q15, INTRA_PRED_BETA_Q15, Q15_ONE,
757};
758pub use celt_header::{CeltHeaderPrefix, CeltPostFilter};
759pub use celt_log2_frac_table::{
760    log2_frac, log2_frac_row, Log2FracError, LOG2_FRAC_TABLE, LOG2_FRAC_TABLE_LEN,
761    Q3_BITS_PER_WHOLE_BIT,
762};
763pub use celt_mdct_window::{
764    basic_window, celt_overlap_window, mdct_window, window_tap, MdctWindowError, BASIC_WINDOW_LEN,
765    CELT_OVERLAP_48K,
766};
767pub use celt_pvq_decode::{
768    decode_pvq_shape, decode_pvq_shape_into, decode_pvq_vector, decode_pvq_vector_into,
769    pvq_l1_norm, pvq_l2_norm_squared, pvq_unit_normalize, PvqDecodeError, PvqShapeError,
770    PVQ_DECODE_K_MAX, PVQ_DECODE_N_MAX,
771};
772pub use celt_pvq_v::{pvq_codebook_size, PvqVError, PVQ_V_K_MAX, PVQ_V_MAX, PVQ_V_N_MAX};
773pub use celt_redundancy::{
774    decode_redundancy, remaining_bits, whole_bytes_remaining, RedundancyDecision,
775    RedundancyPosition, HYBRID_REDUNDANCY_MIN_REMAINING_BITS,
776    HYBRID_REDUNDANCY_SIZE_BASELINE_BYTES, HYBRID_REDUNDANCY_SIZE_DEC_UINT_FT,
777    REDUNDANCY_FLAG_ICDF, REDUNDANCY_FLAG_ICDF_FTB, REDUNDANCY_MIN_SIZE_BYTES,
778    REDUNDANCY_POSITION_ICDF, REDUNDANCY_POSITION_ICDF_FTB,
779    SILK_ONLY_REDUNDANCY_MIN_REMAINING_BITS,
780};
781pub use celt_reservations::{
782    reserve_block, ReservationError, ReservationOutcome, ANTI_COLLAPSE_HEADROOM_LM_OFFSET,
783    ANTI_COLLAPSE_HEADROOM_MULT_EIGHTH_BITS, ANTI_COLLAPSE_LM_MIN_EXCLUSIVE,
784    CONSERVATIVE_DEDUCTION_EIGHTH_BITS, ONE_BIT_EIGHTH_BITS,
785};
786pub use celt_spreading::{
787    apply_spreading, decode_spread, rotate_in_place, rotate_strided, rotation_angle, rotation_gain,
788    spread_f_r, spread_theta, spreading_stride, SpreadingError, SPREAD_FTB, SPREAD_F_R,
789    SPREAD_ICDF, SPREAD_MAX, SPREAD_PDF, SPREAD_PDF_DENOMINATOR, SPREAD_PRE_ROTATION_MIN_BLOCK_LEN,
790    SPREAD_VALUE_COUNT,
791};
792pub use celt_static_alloc::{
793    static_alloc_cell, static_alloc_eighth_bits, static_alloc_row, StaticAllocError, STATIC_ALLOC,
794    STATIC_ALLOC_INTERP_STEPS, STATIC_ALLOC_Q_COUNT, STATIC_ALLOC_Q_MAX, STATIC_ALLOC_Q_MIN,
795    STATIC_ALLOC_RIGHT_SHIFT, STATIC_ALLOC_TOTAL_CELLS,
796};
797pub use celt_tf_adjust::{
798    celt_tf_adjustment, celt_tf_select_can_affect, TfAdjustment, TfDirection,
799    TF_ADJUSTMENT_ABS_MAX, TF_ADJUSTMENT_MAX, TF_ADJ_NONTRANSIENT_SELECT0,
800    TF_ADJ_NONTRANSIENT_SELECT1, TF_ADJ_TRANSIENT_SELECT0, TF_ADJ_TRANSIENT_SELECT1,
801};
802pub use celt_transitions::{
803    classify_normative_transition, recommended_non_normative, BoundaryOp, NormativeTransition,
804    RecommendedNonNormativeTransition,
805};
806pub use celt_trim_offsets::{
807    band_n_shortest, band_trim_offset, band_trim_offset_for_band, shortest_frame_size,
808    TrimOffsetError, TRIM_OFFSETS_BIAS, TRIM_OFFSETS_DIVISOR, TRIM_OFFSETS_MONO_CHANNELS,
809    TRIM_OFFSETS_NUMERATOR_SCALE, TRIM_OFFSETS_STEREO_CHANNELS,
810    TRIM_OFFSETS_WIDTH_ONE_BINS_PER_CHANNEL, TRIM_OFFSETS_WIDTH_ONE_PER_CHANNEL_EIGHTH_BITS,
811};
812pub use frames::{OpusPacket, MAX_FRAMES_PER_PACKET, MAX_FRAME_BYTES};
813pub use framing::{OperatingMode, OpusFrameRouting, SilkBandwidth};
814pub use framing_self_delim::{parse_self_delimited, SelfDelimitedParse};
815pub use mode_transition_reset::{decide_state_resets, CeltResetPlacement, StateReset};
816pub use range_decoder::RangeDecoder;
817pub use redundancy_decode_params::{
818    apply_mb_to_wb_override, redundant_frame_params, CrossLapPlacement, RedundantFrameParams,
819    REDUNDANT_CROSS_LAP_TENTHS_MS, REDUNDANT_FRAME_TENTHS_MS,
820};
821pub use silk_excitation::{
822    quantization_offset_q23, shell_block_count, Excitation, ExcitationConfig, SilkFrameSize,
823    MAX_EXCITATION_SAMPLES, MAX_SHELL_BLOCKS, SHELL_BLOCK_SAMPLES,
824};
825pub use silk_frame::{
826    FrameKind, QuantizationOffsetType, SignalType, SilkFrameHeader, SilkFrameHeaderConfig,
827    StereoPredictionWeights,
828};
829pub use silk_gains::{SubframeGain, SubframeGains, SubframeGainsConfig, SILK_MAX_SUBFRAMES};
830pub use silk_header::{
831    per_frame_lbrr_pdf, silk_frame_count, PerFrameLbrr, SilkChannelHeader, SilkHeaderBits,
832    SILK_MAX_FRAMES_PER_CHANNEL,
833};
834pub use silk_lcg_seed::decode_lcg_seed;
835pub use silk_log2lin::{
836    silk_gains_dequant, silk_log2lin, SILK_GAIN_Q16_MAX, SILK_GAIN_Q16_MIN, SILK_LOG_GAIN_BIAS,
837    SILK_LOG_GAIN_MULTIPLIER,
838};
839pub use silk_lpc_synth::{
840    lpc_synthesis_frame, lpc_synthesis_subframe, subframe_samples, LpcSynthState,
841    LPC_SYNTH_MAX_ORDER, LPC_SYNTH_MAX_SUBFRAME_SAMPLES,
842};
843pub use silk_lsf_interp::{LsfInterpContext, LsfInterpolated};
844pub use silk_lsf_recon::{cb1_q8, NlsfReconstructed};
845pub use silk_lsf_stabilize::NlsfStabilized;
846pub use silk_lsf_stage2::{
847    LsfStage2, D_LPC_MAX, D_LPC_NB_MB, D_LPC_WB, QSTEP_NB_MB_Q16, QSTEP_WB_Q16,
848};
849pub use silk_lsf_to_lpc::{nlsf_to_c_q17, ordering, LpcQ12, LpcQ17};
850pub use silk_ltp::{
851    LagCoding, LtpConfig, LtpParameters, LTP_FILTER_TAPS, LTP_MAX_SUBFRAMES,
852    LTP_SCALING_DEFAULT_Q14,
853};
854pub use silk_ltp_synth::{
855    ltp_synth_commit_subframe, ltp_synthesis_subframe, LtpSynthState, LtpSynthSubframe,
856    LTP_LPC_HISTORY_MAX, LTP_MAX_PITCH_LAG, LTP_OUT_HISTORY_MAX, LTP_SCALE_FRESH_Q14,
857};
858pub use silk_resampler::{
859    is_supported_output_rate, silk_frame_samples_at_output, silk_frame_samples_internal,
860    silk_internal_rate_hz, silk_resampler_delay_ms, silk_resampler_delay_samples_at,
861    REFERENCE_RATE_HZ, SILK_RESAMPLER_DELAY_MS_MB, SILK_RESAMPLER_DELAY_MS_NB,
862    SILK_RESAMPLER_DELAY_MS_WB, SUPPORTED_OUTPUT_RATES_HZ,
863};
864pub use silk_stereo::{
865    interp_phase_samples, stereo_ms_to_lr, StereoFrame, StereoUnmixState, StereoWeightsQ13,
866};
867pub use toc::{Bandwidth, ChannelMapping, FrameCountCode, Mode, OpusTocByte};
868
869/// No-op codec registration — the orphan-rebuild scaffold registers
870/// nothing into the runtime context until decode / encode paths are
871/// wired up.
872pub fn register(_ctx: &mut RuntimeContext) {}
873
874oxideav_core::register!("opus", register);