# oxideav-opus
Pure-Rust Opus audio codec (SILK + CELT) for the
[oxideav](https://github.com/OxideAV) framework.
## Status
**Clean-room rebuild in progress (orphan scaffold).** The prior
implementation was retired under the workspace clean-room policy; the
crate is being re-implemented from scratch against the published RFCs
using only material under `docs/` and black-box validator binaries.
A top-level `OpusDecoder::decode_packet` packet → PCM orchestration is
now in place: it parses the §3.1 TOC, splits the §3.2 frame packing
(all four frame-count codes), runs the §4.5 multi-frame loop, routes
each Opus frame by mode, and lays out the interleaved 48 kHz output
buffer (RFC 7845 §5.1) with correct per-frame sample counts. Both **mono
and stereo SILK-only** packets now decode **end-to-end to real PCM**: the
§4.2 bitstream decode (the §4.2.3 header bits, the §4.2.5 LBRR / §4.2.6
regular SILK frame loop, each frame decoded in Table-5 order through
gains / LSF chain / LTP / excitation with inter-frame state threaded),
then the §4.2.7.9 LTP / LPC synthesis filters (composed in the
`silk_synthesis` module with the §4.2.7.9 per-subframe LPC selection and
cross-frame histories), then a §4.2.9 non-normative resample to 48 kHz
and i16 conversion. For **stereo**, the §4.2.2 mid/side interleave (mid
frame then side frame per 20 ms interval, the §4.2.7.2 mid-only flag
skipping the side frame) is decoded into two independent per-channel
synthesis states and converted from mid/side to left/right by the §4.2.8
`silk_stereo` unmixer, run **per SILK interval** with that interval's
§4.2.7.1 weights and the cross-packet `StereoUnmixState` history. The
§4.5.2 SILK state reset (CELT→SILK transition) and the §4.2.7.1
mono→stereo weight reset are applied across packets. The CELT **synthesis
backend** is now composed end-to-end: `celt_synthesis::CeltSynthState`
turns already-decoded per-band shapes + `log2` energies into time-domain
PCM through §4.3.6 denormalise → §4.3.7 inverse MDCT → §4.3.7 weighted
overlap-add → §4.3.7.2 de-emphasis, threading the cross-frame overlap and
de-emphasis state (the CELT analogue of `silk_synthesis`), and emits
interleaved 48 kHz i16 via `synthesize_frame_interleaved_i16`. A
**CELT-only silence frame now decodes end-to-end to real PCM**: the
§4.3.7.1 range-coded frame prefix (silence flag + post-filter group +
transient + intra) is decoded from the real range coder by
`celt_frame_prefix`, and a set silence flag drives the synthesis backend
with all-zero bands, emitting zero PCM while advancing the overlap-add /
de-emphasis state (`FrameDecodeStatus::CeltSilence`). The §4.3.2.1
coarse-energy *front half* now decodes for non-silent CELT-only frames:
the Laplace symbol decoder (`celt_laplace::ec_laplace_decode`, the
15-bit path) feeds the new `celt_coarse_energy` *reconstruction
recurrence*, which runs the §4.3.2.1 2-D prediction filter
`A(z_l, z_b)` in reverse (the frequency accumulator `pred_freq[b+1] =
pred_freq[b] + (1-beta)*R[b]` and `E[b][l] = alpha*E[b][l-1] +
pred_freq[b] + R[b]`, derived algebraically from the RFC z-transform),
adds back the §4.3 `e_means` Q4 baseline, and threads the cross-frame
`E[b][l-1]` predictor state on `OpusDecoder` (reset on an intra frame /
SILK→CELT transition). A non-silent CELT-only frame thus consumes its
prefix + coarse energy from the real range coder and advances the
synthesis state, reporting `FrameDecodeStatus::CeltCoarseEnergyDecoded`.
On top of the coarse energy, a non-silent frame now also decodes the
full run of Table-56 symbols between coarse energy and the §4.3.4
residual, from the same range coder in exact Table-56 order: the §4.3.1
per-band `tf_change` flags and gated `tf_select` bit (`celt_tf_decode`),
the §4.3.4.3 `spread` symbol (`celt_spreading`), then the §4.3.3
allocation *header* — the signalled part of the bit allocation: the band
boosts
(`celt_band_boost`, walked over the `start..end` coding window with the
per-band `cap[]` from `celt_cache_caps50` and the per-channel MDCT-bin
counts), the allocation trim (`celt_alloc_trim`, gated on the running
`ec_tell_frac`), and the §4.3.3 anti-collapse / skip / intensity-stereo
/ dual-stereo reservations (`celt_reservations`). This advances the
entropy decoder through everything the bitstream explicitly carries
before the implicit interpolation, leaving the coder positioned exactly
where the §4.3.4 PVQ shape decode resumes, and the frame reports
`FrameDecodeStatus::CeltAllocationDecoded`. The remaining CELT band-data
stages — the §4.3.3 *implicit* allocation (`interp_bits2pulses`, the
per-band pulse / fine-energy split, which is reference-code-only and
absent from the RFC narrative body), §4.3.4 PVQ band shapes, and
§4.3.2.2 fine energy — are still pending, so the band shapes are
all-zero and these frames emit correct-length silence until those land.
The one residual coarse-energy seam is the RFC's "clamped internally"
bound, which is not in the normative body (only in reference code) and
is left as a documented identity in `celt_coarse_energy` — exact for
every in-range bitstream — pending a clean-room docs trace. The §4.4
packet-loss concealment is also outstanding (the RFC defines PLC as a
non-normative decoder feature with no bitstream algorithm; lost / DTX
frames currently emit the §4.6 silence floor).
The crate now also carries the start of the **encode side**: the
bit-exact §5.1 range *encoder* (`RangeEncoder` — the §5.1.1 symbol
update, §5.1.1.2 carry propagation, the §5.1.2 division-free variants
sharing the decoder's `icdf[]` tables, §5.1.3 raw bits, §5.1.4
uniform integers, §5.1.5 finalization, §5.1.6 `tell`/`tell_frac`
matching the decoder bit-for-bit), write-side mirrors of **every**
SILK §4.2.7 decode stage (header / gains with a deterministic
quantizer / LSF stage-1 + stage-2 / interpolation index / LTP / seed
/ excitation, each returning the value the decoder will
reconstruct), the whole-frame Table-5 composition
(`encode_silk_frame`), and SILK-only **packet encoders for both mono
and stereo** (`encode_silk_only_packet_mono` /
`encode_silk_only_packet_stereo`: TOC byte + §4.2.3/§4.2.4 header
bits + 1–3 SILK frames at 10/20/40/60 ms — the stereo entry writing
the §4.2.2 mid/side interleave with the §4.2.7.1 weight quintuple and
gated §4.2.7.2 mid-only flag on each mid frame, and two independent
per-channel carried states) whose packets decode end-to-end through a
fresh `OpusDecoder::decode_packet` to real SILK PCM, with every
per-frame parameter verified equal to the encoder's prediction. LBRR
(in-band FEC, §4.2.5) emission is included for both channel layouts
and closes the FEC loop: `decode_packet_fec` recovers real (mono or
two-channel) audio from the encoder's own redundancy. On top of the
packet writers sit the **stereo analysis front half** — the exact
§4.2.8 algebraic-inverse downmix `stereo_lr_to_ms` (L/R → mid/side
with the decoder's weight-interpolation ramp; roundtrips to the
input at the §4.2.8 one-sample delay), the least-squares §4.2.7.1
weight estimator `estimate_stereo_weights`, and the exhaustive
codebook quantizer `StereoWeightSymbols::quantize` — plus the **§3.2
/ Appendix-B framing writers** (`compose_packet`,
`compose_packet_code3`, `compose_self_delimited`; all four codes,
CBR/VBR, §3.2.5 padding chains, parser-validated R2/R3/R5/R6) and
the **RFC 7845 write side** (`OpusHead::compose`, byte-identical on
reparse, and `assemble_multistream_packet`, roundtripped against the
splitter and decoded sample-identically through
`MultistreamDecoder`). What the encoder does *not* yet have is the
§5.2.3 signal analysis that picks the SILK symbols themselves
(pitch/LTP analysis, LSF fitting, excitation quantization from
residual PCM beyond the gains quantizer) — packets are encoded from
symbol scripts, not yet from raw PCM.
Differential encoder/decoder testing and a restored cargo-fuzz suite
(4 coverage-guided targets, incl. an encoder↔decoder range-coder
roundtrip) have also hardened the decoder: five mis-transcribed rows
in the §4.2.7.8.3 split tables (now verified cell-by-cell against the
RFC across all 64 rows), a `dec_bits(32)` shift overflow, a
§4.2.7.5.8 recurrence i64 overflow on adversarial input, and the
§4.2.7.8 10 ms-MB 128-vs-120-sample special case (previously every
10 ms MB SILK packet failed to synthesize) are all fixed with
regression tests.
The crate ships a large, individually unit-tested set of SILK and
CELT building blocks plus a complete RFC 7845 multistream /
multichannel decode subsystem (1296 lib tests + SILK-fixture,
multistream, FEC, and CELT synthesis-backend integration suites).
Per-stage progress lives in `CHANGELOG.md`.
## What works
**Packet → PCM orchestration (RFC 6716 §3 / §4):**
- `OpusDecoder::decode_packet` — the top-level packet → interleaved
48 kHz PCM path: TOC parse, §3.2 frame split, §4.5 multi-frame loop,
per-mode routing, the §4.5.2 cross-packet SILK state reset, and the
RFC 7845 §5.1 output sample-count layout. Mono SILK-only packets decode
end-to-end to real PCM (bitstream → §4.2.7.9 synthesis → §4.2.9
resample); other modes emit correct-length silence flagged via
`FrameDecodeStatus`.
- `silk_decode::decode_silk_frame` — the §4.2.6 / §4.2.7 in-order SILK
frame decode that composes the per-stage decoders in exact Table-5
symbol order and runs the LSF → stable-Q12-LPC chain.
- `silk_synthesis::synthesize_silk_frame` — the §4.2.7.9 synthesis
composition: §4.2.7.9.1 LTP + §4.2.7.9.2 LPC filters with the §4.2.7.9
per-subframe LPC selection and cross-frame `SilkSynthState` histories,
producing internal-rate (8/12/16 kHz) time-domain samples.
- `OpusDecoder::decode_silk_only_stereo` — the §4.2.2 stereo SILK decode:
the §4.2.3 two-channel header bits, the §4.2.5 / §4.2.6 interleaved
mid/side SILK frames (the §4.2.7.1 weights + §4.2.7.2 mid-only flag on
the mid frame; an uncoded side frame clears its §4.2.7.9 LTP buffer per
§4.5.2), two independent per-channel synthesis states, and the §4.2.8
`silk_stereo::stereo_ms_to_lr` mid/side → left/right unmix run per SILK
interval into interleaved L/R PCM.
**Packet & framing (RFC 6716 §3 / §4.2):**
- `OpusTocByte` — the §3.1 TOC parser (config × stereo flag × frame-count
code).
- `OpusPacket` — the §3.2 frame-packing parser for all four frame-count
codes (single, two-equal, two-unequal, signalled with optional VBR
lengths + padding); returned frame slices borrow from the input.
- `parse_self_delimited` — RFC 6716 Appendix B self-delimiting framing
(for chaining inside a multistream demuxer).
- `OpusFrameRouting` — §3.1 / §4.2 mode dispatch (SILK-only / Hybrid /
CELT-only, SILK-frame count, per-frame LBRR-flag gating, channel
multiplier).
- A §3.4 R1–R7 malformed-input rejection audit
(`tests/malformed_input.rs`).
- An **end-to-end SILK fixture-decode suite** (`tests/silk_fixture_decode.rs`)
that decodes the in-project NB-mono / WB-stereo / MB-60 ms-mono Opus
streams packet-by-packet through `decode_packet` and validates §3.1 TOC
routing, whole-stream error-free SILK decode (mono + stereo, NB/MB/WB,
20/60 ms), §3 sample-count accounting, and 440 Hz dominance on the NB
sine fixture. Validation is signal- / structure-based, not bit-exact:
the §4.2.9 SILK→48 kHz resampler is non-normative, so the decoded
envelope differs from the polyphase-resampled reference decoder.
**Multistream / multichannel (RFC 7845 §3 / §5.1 / §5.1.1):**
- `OpusHead` — the §5.1 identification-header parser: version (with the
major-nibble compatibility bound), output channel count, pre-skip,
input sample rate, output gain, mapping family, and the §5.1.1
channel-mapping table (stream count N, coupled count M, per-output
mapping indices). Enforces every MUST in §5.1 / §5.1.1 (non-zero
channel/stream counts, per-family channel ranges, `M ≤ N`,
`M + N ≤ 255`, and the `< M+N` / 255 mapping-index bound). Family 0
synthesizes the table from the RFC-pinned defaults.
- `split_multistream_packet` — the §3 N-packet split: the first `N − 1`
streams via Appendix-B self-delimited framing, the final stream as the
undelimited remainder.
- `MultistreamDecoder` — the multichannel decode: one stateful
sub-decoder per coded stream, decoding each split packet and
assembling the `C` output channels by the §5.1.1 index rule
(coupled-stream L/R by parity, mono streams, index-255 silence, a
decoded channel routed to multiple outputs), with the §3 equal-duration
constraint enforced. Validated end-to-end against the real SILK
fixtures: an `N = 1` family-0 decode is byte-identical to a plain
`OpusDecoder`, a coupled-stream L/R split reproduces a plain stereo
decode exactly, and mono-pair / swapped / silence / duplicate maps all
route correctly.
- `apply_output_gain` / `PreSkip` — the §5.1 post-decode output-gain
application (Q7.8 dB, i16-saturating) and the cross-packet pre-skip
accumulator.
**Range coder (RFC 6716 §4.1 / §5.1):** `RangeDecoder` — the shared
entropy primitive consumed by both layers, including the §4.1.2
two-step `ec_decode` / `ec_dec_update` path and the Laplace / iCDF
helpers — and `RangeEncoder`, its bit-exact §5.1 write-side mirror
(validated by per-primitive roundtrips, `tell`/`tell_frac` lockstep,
a 5000-seed mixed-symbol fuzz roundtrip, and a coverage-guided
libfuzzer differential target).
**SILK encode side (RFC 6716 §5.2 bitstream back end):** write-side
mirrors of every §4.2.7 stage sharing the decode tables
(`SilkFrameHeader::encode_pre_gains` / `encode_lsf_stage1`,
`SubframeGains::encode`/`quantize`, `LsfStage2::encode`,
`LsfInterpolated::encode_index`, `encode_lcg_seed`,
`LtpParameters::encode`, `Excitation::encode`), the Table-5
whole-frame composition `encode_silk_frame`, the §4.2.3/§4.2.4
header-bit writer `SilkHeaderBits::encode` (mono + two-channel), the
§3.1 TOC composer `OpusTocByte::compose_byte`, and the packet-level
`encode_silk_only_packet_mono` / `encode_silk_only_packet_stereo`
(each with a `_with_lbrr` variant for §4.2.5 in-band-FEC emission;
the stereo entry writes the §4.2.2 mid/side interleave with the
§4.2.7.1 weights and gated §4.2.7.2 mid-only flag per interval and
threads two independent per-channel carried states, exactly
mirroring the decoder's stereo walk) — every layer
roundtrip-verified against the decoder, up to whole packets decoding
end-to-end through `OpusDecoder::decode_packet` (mono and stereo)
and FEC recovery through `decode_packet_fec`.
**Stereo encode analysis (§4.2.7.1 / §4.2.8 write half):**
`stereo_lr_to_ms` — the exact algebraic inverse of the §4.2.8
unmixer (frame-aligned L/R → mid/side with the decoder's
weight-interpolation ramp, one-sample lookahead for the final `p0`,
`StereoDownmixState` history; a multi-frame roundtrip through
`stereo_ms_to_lr` reproduces the input at the §4.2.8 one-sample
delay) — `estimate_stereo_weights` (least-squares fit of the raw
side onto the `p0` / mid predictor pair, f64 normal equations) and
`StereoWeightSymbols::quantize` (exhaustive deterministic argmin
over the 5625-quintuple §4.2.7.1 codebook; representable targets
roundtrip value-exactly).
**Packet-framing / RFC 7845 write side:** `compose_packet` /
`compose_packet_code3` / `compose_self_delimited` / `encode_length` —
the §3.2 + Appendix-B framing writers (all four codes, CBR/VBR,
§3.2.5 padding chains, every parser-enforced requirement validated
before writing; roundtripped against `OpusPacket::parse` /
`parse_self_delimited`, including chained self-delimited buffers and
multi-frame SILK packets decoding end-to-end) — plus
`OpusHead::compose` (byte-identical reparse, full §5.1/§5.1.1 MUST
validation) and `assemble_multistream_packet` (§3 stream packing via
the Appendix-B writer, equal-duration constraint enforced,
sample-identical decode through `MultistreamDecoder`).
**SILK (RFC 6716 §4.2):** frame-header decode (§4.2.7.1–§4.2.7.5.1),
subframe gains (§4.2.7.4), the full LSF chain (stage-2 residual → NLSF
reconstruction → stabilization → interpolation → NLSF→LPC →
bandwidth-expansion → prediction-gain limiting, §4.2.7.5.2–§4.2.7.5.8),
LTP parameters (§4.2.7.6), LCG seed (§4.2.7.7), excitation
(§4.2.7.8), LTP + LPC synthesis filters (§4.2.7.9), stereo unmixing
(§4.2.8), the §4.2.9 resampler delay budget, and **in-band FEC
recovery** (§2.1.7 / §4.2.5): `OpusDecoder::decode_packet_fec`
reconstructs a lost frame's audio from the Low Bit-Rate Redundancy
(LBRR) frames carried in the next received packet — decoding the §4.2.5
LBRR frame(s) (mono, or interleaved mid/side for stereo), running the
full §4.2.7.9 synthesis from a fresh state, unmixing a stereo recovery
via §4.2.8, and resampling to 48 kHz, reported through `FecDecodeStatus`.
**CELT (RFC 6716 §4.3 / §4.5):** the §4.3 band layout (Table 55), the
pre-band header symbols (silence / post-filter / transient / intra),
the §4.3.4.5 *time-frequency change decode* (`celt_tf_decode` — the
per-band `tf_change` flag loop, first band absolute and subsequent
bands difference-coded relative to the previous band's choice, plus the
§4.3.1-gated `tf_select` flag and the resulting per-band TF adjustment
vector) layered on the §4.3.4.5 TF-resolution adjustment tables, the
coarse-energy Laplace
parameter tables (§4.3.2.1), the allocation parameter surfaces
(log2-frac / alloc-trim / cache-caps / static-allocation), the
§4.3.4.1 *Bits-to-Pulses* pulse-cost cache (the run-packed
`cache_bits50` / `cache_index50` lookup plus the budget-to-pulse-count
inversion), the §4.3.6 band denormalisation (unit-norm PVQ shape ×
`sqrt(2**log2_energy)`, laid out across the coded bands into the
inverse-MDCT input buffer), the §4.3.7 inverse MDCT transform core (the
`N` frequency-domain bins → `2N` time-domain samples mapping, scaled by
`1/2`, with the §4.3.7 overlap-add window already landed at
`celt_mdct_window`), the §4.3.7 *weighted overlap-add* (`celt_overlap_add`
— the stateful per-channel adder that windows each `2N` inverse-MDCT
block with the low-overlap synthesis window and overlap-adds the leading
half with the previous block's windowed trailing half at hop `N`,
carrying the overlap history across frames and reconstructing the
aliasing-free time-domain signal), the §4.3.4.5 *time-frequency Hadamard
transform* (`celt_tf_hadamard` — the across-block / sequency-order
orthonormal Walsh–Hadamard reshaping that consumes the per-band
`TfDirection`, preserving the unit-norm shape energy), the §4.3.4
*per-band shape decode orchestrator* (`celt_band_shape` — composing
§4.3.4.2 PVQ decode → §4.3.4.3 spreading → §4.3.4.5 TF transform into
one `decode_band_shape` call given a band's `(N, K, spread, tf_adjust,
nb_blocks)`), and the §4.5 redundancy / mode-transition state-reset
machinery.
The one structural blocker on the CELT-only real-PCM path is the §4.3.3
**allocation orchestration** (the reference `interp_bits2pulses`:
reallocation of unused bits with concurrent skip decoding, the
fine-energy-vs-shape split, and the final reallocation) together with
the §4.3.4.4 **split-decoding gain precision** ("derived from the
current allocation"). RFC 6716 §4.3.3 *names* these steps (p. 111) but
provides no algorithm for them — they live only in the reference
`rate.c` / `bands.c`, which the clean-room wall bars. Without the
per-band pulse count `K` they produce, the §4.3.4 shape decode (now
fully composed) cannot be driven against a real bitstream, so non-silent
CELT-only frames still emit correct-length silence after consuming their
prefix + coarse energy. This is a precise docs gap: a clean-room trace
of `interp_bits2pulses` + the split-gain `qb` derivation would unblock
the end-to-end CELT path. The §4.3.5 anti-collapse remains separately
gapped (no PRNG / energy-injection algorithm in the RFC narrative).
## Clean-room sources
The rebuild consults only:
- RFC 6716 — Definition of the Opus Audio Codec.
- RFC 8251 — Updates to the Opus Audio Codec.
- RFC 7587 — RTP Payload Format for Opus.
- RFC 7845 — Ogg Encapsulation for Opus.
- Black-box invocations of the `opusdec` / `opusenc` binaries (not
their source) as opaque validators.
No external library source is permitted as a reference under the
workspace clean-room policy.
## License
MIT. See `LICENSE`.