COOLJAPAN
← All posts

OxiAudio 0.2.1 Released — The Pulse-Cache Row Clamp That Was Capping Opus at 32 kbps

OxiAudio 0.2.1 is a deep Opus conformance-hardening release: the CELT frame-size ceiling is raised from 80 bytes (~32 kbps) to the RFC's real 1275-byte limit (510 kbps mono) by fixing a celt_bits2pulses/celt_pulses2bits partition-scale clamp bug, CBR frames stop silently shrinking, hybrid packets are now entropy-exact, and encode_opus is RFC 6716-conformant by default. Pure Rust audio codec + DSP layer for the COOLJAPAN ecosystem.

release oxiaudio pure-rust cooljapan noffi audio codec dsp signal-processing

A single clamped index — a partition scale forced to 0 before it indexed a pulse-cache row it should have addressed as lm + 1 — was the entire reason OxiAudio’s conformant Opus encoder had been stuck at roughly 32 kbps.

Today we released OxiAudio 0.2.1 — a deep Opus codec conformance-hardening release for the COOLJAPAN Pure-Rust audio codec and DSP layer. The headline fix raises the CELT frame-size ceiling from 80 bytes to the RFC’s own 1275-byte limit (510 kbps mono), and it’s joined by a CBR sizing fix, entropy-exact hybrid packets, three allocation-DoS closures in the container decoders, and OGG page CRC validation.

No libFLAC. No libvorbis. No libopus. No dr_libs. No FFI. No -sys crates. Default features carry zero C/C++/Fortran dependencies — just clean, memory-safe Rust that compiles to a single binary and goes wherever Rust goes.

Why OxiAudio 0.2.1 is a game changer

Four defects had been quietly limiting OxiAudio’s own Opus encoder below its real potential, and none of them were things a “does it decode?” test could ever catch:

OxiAudio 0.2.1 closes all of it.

Technical Deep Dive: what actually changed under the hood

  1. opus_celt.rs / opus_celt_bands.rs / opus_celt_rate.rs — the pulse-cache row bug. A band that splits four times (band 20 at LM=3: 176 → 88 → 44 → 22 → 11 bins) reaches partition scale lm = -1, which libopus indexes as pulse-cache row 0. The clamp instead selected row 1, giving those leaves a different pulse count than the reference decoder derives — and four-deep splits only happen once a band’s budget clears the cache maximum, which is exactly why the old 80-byte cap hid the bug for as long as it did. final_range equality against the reference decoder is now swept from MIN_CELT_FRAME_BYTES to 1275 across ten fixtures (tones from 120 Hz to 19 kHz, speech, music, full-scale and near-silent noise, an impulse train, digital silence) × two frame positions each.
  2. opus_range.rs — two independent range-coder bugs. RangeEncoder::finish_to_size_checked wrote its partial raw-bit window at its own byte index rather than |=-merging it into the shared boundary byte the way ec_enc_done does, so a frame always needed one byte more than libopus expected. Separately, carry_out’s shift used EC_CODE_BITS - EC_SYM_BITS (24) where libopus’s ec_enc uses EC_CODE_BITS - EC_SYM_BITS - 1 (23, now a named EC_CODE_SHIFT constant) — an off-by-one that dropped bit 23 of every emitted byte.
  3. opus_encoder.rs / hybrid layer — entropy exactness. The encoder never wrote the hybrid redundancy flag (logp = 12) a decoder reads between the SILK and CELT layers, and encode_celt_hybrid_layer_into hardcoded TARGET_BITS_HYBRID = 512 while the packet itself was assembled at a variable length. The hybrid writer is now real CBR (encode_hybrid_frame_conformant_sized) and passes its actual emitted length into the layer; final_range equality now holds across [MIN_HYBRID_FRAME_BYTES, MAX_HYBRID_FRAME_BYTES] = [20, 1275].
  4. Decoder-side hardening. wavpack.rs, aiff.rs, and musepack.rs now validate size and frame-count header fields against the bytes actually available before sizing an allocation or a slice read; ogg_reader.rs now checksums each page (CRC field zeroed, compared against the stored value) before its packets ever reach the Opus/Vorbis decoders.

Getting Started

cargo add oxiaudio

The core pipeline is unchanged — decode, run DSP, re-encode:

use std::path::Path;

// Decode any supported format
let buf = oxiaudio::decode_file(Path::new("input.flac")).expect("decode failed");
println!("{} frames @ {} Hz", buf.frame_count(), buf.sample_rate);

// DSP: normalize, then add reverb
let mut out = buf.clone();
oxiaudio::dsp::normalize(&mut out, -1.0);
let with_reverb = oxiaudio::dsp::reverb(&out, 0.6, 0.4, 0.3);

// Re-encode as FLAC
oxiaudio::encode_flac(&with_reverb, Path::new("output.flac")).expect("encode failed");

What’s new is the headroom on the Opus side — encode_opus_file’s target_bitrate_kbps can now genuinely reach the frame sizes it asks for, up to the RFC’s own 510 kbps mono ceiling instead of stalling out around 32 kbps. Opus takes 48 kHz input only (the encoder does not resample):

use std::path::Path;

// Opus operates on 48 kHz input only -- the encoder does not resample.
let src = oxiaudio::decode_file(Path::new("input48k.wav")).expect("decode failed");

// 256 kbps mono Opus -- unreachable before 0.2.1, when the CELT frame-size
// ceiling silently topped out around 32 kbps (80 bytes/frame).
oxiaudio::encode_opus_file(&src, Path::new("output.opus"), 256)
    .expect("opus encode failed");

What’s New in 0.2.1

Tips

This is the foundation

OxiAudio is part of NoFFI — the COOLJAPAN initiative to replace every C/C++/Fortran/-sys FFI dependency in the Rust world with a clean, memory-safe, 100% Pure Rust implementation. Its spectral layer sits on OxiFFT, the ecosystem’s Pure-Rust FFT, and its codecs and DSP already power OxiSound (the COOLJAPAN audio playback layer, which pins oxiaudio and oxiaudio-core) and VoiRS (speech/voice synthesis, which pins oxiaudio-core and oxiaudio-encode directly for its FLAC output path).

As of this release: 1,136 tests passing / 5 skipped (default features), 1,242 / 6 skipped (--all-features), plus 63 doc tests, 0 clippy warnings, 0 rustdoc warnings, across 39,706 lines of production Rust in the 6 published crates.

Repository: https://github.com/cool-japan/oxiaudio

Star the repo if “a bit rate you asked for should be the bit rate you get” is a bar every audio encoder should clear.

The era of a codec silently capping itself below its own ceiling is over. Pure Rust audio — fast, safe, and sovereign — is here.

KitaSan at COOLJAPAN OÜ August 6, 2026

↑ Back to all posts