gopus is a pure-Go, no-cgo implementation of the Opus audio codec (RFC 6716 /
RFC 8251) that targets byte- and quality-parity with libopus 1.6.1. The
pinned reference lives in tmp_check/opus-1.6.1/; when behavior is uncertain,
gopus matches libopus unless fixture evidence says otherwise.
State current behavior in the present tense — in code comments and in these docs. Do not write historical or changelog narrative ("previously…", "was a…", "now uses…", "removed…"); describe what the code does today.
- Match libopus 1.6.1 exactly — both observable behavior and, on the bit-exact lanes, the emitted bytes and the entropy coder's final range.
- Never weaken a gate to make work pass. Do not relax quality thresholds, edit fixture or baseline files, loosen oracle tolerances, or skip a failing case to go green. Fix the root cause. Fixture/baseline edits are review-visible evidence, not a shortcut.
- Parity is proven on two tiers (see README "Parity & testing"): bit-exact kernel
oracles plus differential fuzzing of every public decode entry point, and
opus_comparequality on real audio. SILK decode is bit-exact; CELT/Hybrid sit in the near-exact envelope.
- The
puregobuild tag is the scalar reference path: bit-exact on every architecture, and the lane the byte-parity gates compare against. - The default build selects assembly (arm64 NEON, amd64 SSE/AVX2) only where libopus does, and only behind a quality gate.
- One residual is documented: a few CELT float kernels drift by ≤1 ULP on darwin/arm64 — a per-arch float budget, exactly like libopus's own NEON-vs-scalar difference. Do not chase ≤1-ULP arm64 float drift as a bug.
Runtime codec-domain storage must use the same scalar width as libopus, including temporary scratch buffers.
- In the libopus float build,
opus_val16,opus_val32,opus_val64,opus_res,celt_sig,celt_norm,celt_ener,celt_glog,celt_coef, andsilk_floatare Cfloat; use Gofloat32or the matching local alias. - Scratch is in scope. Reusable scratch fields, local temporary slices, conversion buffers, MDCT/PVQ/energy/PLC/QEXT/DRED buffers, SILK pitch/NLSF/NSQ state, helper allocators, and test-only runtime probes must follow libopus width too.
- Do not add runtime
float64,complex128,KissFFT64State,ensureFloat64Slice, orensureComplexSliceunless the matching libopus source uses Cdoublefor that exact helper. Cite the C file/function in the code or the baseline reason. - Use fixed-width Go integer types for libopus state and arithmetic: C
int/opus_intruntime fields and scratch should beint32,opus_int16should beint16,opus_uint32should beuint32, and so on. - Go
intis allowed for indexes, lengths, loop counters, slice capacities, public Go ergonomics, and table indexing only. Do not keep reusable scratch or codec-domain arithmetic inintjust because it compiles. - When a remaining wide scalar or generic
intis deliberate, it must be an index/length/public-boundary use or have a source-cited reason tied to a matching libopus type.
Encode/decode and the container hot paths are allocation-free in steady state via
caller-owned, pre-allocated buffers. Keep them that way, and lock any new
zero-alloc path with a testing.AllocsPerRun(...) == 0 test (warm up first so the
measurement reflects steady state, not one-time lazy init).
- Write idiomatic Go that reads like the surrounding code. Match libopus logic and numeric behavior exactly, but do not transliterate C line-for-line.
- The public API is pre-v1 and unreleased: break internal or public interfaces when it yields a cleaner design, then fix the callers. Do not add conversion bridges, compatibility wrappers, or cast-heavy shims to preserve an old surface.
make testruns the full suite against a live libopus oracle (ensure-libopusbuilds the pinned reference).make test-fastis the quick lane;make test-raceis the race sweep.make test-type-parityruns the type-parity guard. Do not runmake update-type-parity-baselineto hide new debt; refresh the baseline only when cleanup removed findings or a remaining wide scalar is intentionally tied to a specific C helper.make lint(golangci-lint + vet across the build-tag matrix) andmake deadcode(the multi-config dead-code detector — a single-configdeadcoderun is false-positive dominated here because of build-tag/arch gating).- Optional features are behind build tags, mirrored tag-for-flag with libopus:
gopus_dred,gopus_osce,gopus_qext,gopus_custom_modes,gopus_fixed_point. The default build links zero of their code. - Run
go testfor the packages you touch (default and, where relevant,-tags purego) before finishing a codec or runtime change.
internal/{celt,silk,hybrid,encoder}— the codec core.internal/{dred,osce,lpcnetplc,dnnmath,dnnblob}— the tag-gated neural features (DRED, OSCE/deep-PLC).internal/{rangecoding,opusmath,plc,fixedpoint,util}— shared primitives;internal/libopustest— the C oracle helper harness.- Public packages: root
github.com/thesyncim/gopus,multistream,types,container/ogg,container/red. tmp_check/opus-1.6.1/— pinned libopus reference;testvectors/— RFC 8251 vectors;tools/— C oracle/reference sources;scripts/— dev tooling.