Ogg Opus Files

Ogg Opus (RFC 7845) is the standard container for Opus audio. ruopus provides two convenience functions, encode_ogg_opus() and decode_ogg_opus(), that handle the full container round-trip in a single call, plus the OpusHead identification-header object returned by the decoder.

Encoding to Ogg Opus

encode_ogg_opus() takes raw 48 kHz float32 PCM and returns a complete Ogg Opus file as bytes:

import numpy as np
import ruopus

# Generate 3 seconds of stereo audio
sr = 48_000
t  = np.linspace(0, 3, sr * 3, dtype=np.float32)
pcm = np.column_stack([
    np.sin(2 * np.pi * 440 * t),   # left:  A4
    np.sin(2 * np.pi * 880 * t),   # right: A5
])   # shape (144000, 2)

ogg = ruopus.encode_ogg_opus(pcm, channels=2, bitrate=128_000)

with open("output.opus", "wb") as f:
    f.write(ogg)

print(f"Ogg Opus file: {len(ogg) / 1024:.1f} KB")

Input can also be a 1-D interleaved array (samples interleaved L, R, L, R, …):

flat_pcm = pcm.ravel()    # shape (288000,)
ogg = ruopus.encode_ogg_opus(flat_pcm, channels=2, bitrate=128_000)

Decoding from Ogg Opus

decode_ogg_opus() handles the complete demuxing pipeline:

  • Reads the OpusHead identification header

  • Applies the pre_skip (discards leading silence)

  • Trims trailing granule padding

  • Applies the output_gain_q8 to the decoded PCM

with open("input.opus", "rb") as f:
    data = f.read()

pcm, head = ruopus.decode_ogg_opus(data)

print(f"Channels:    {head.channel_count}")
print(f"Input rate:  {head.input_sample_rate} Hz")
print(f"Pre-skip:    {head.pre_skip} samples")
print(f"Output gain: {head.output_gain_q8} (Q7.8 dB)")
print(f"Decoded PCM: {pcm.shape}, dtype={pcm.dtype}")

The output is always float32 at 48 kHz, shaped (frames, channels).

Reading the OpusHead

The OpusHead object exposes every field of the RFC 7845 identification header:

pcm, head = ruopus.decode_ogg_opus(data)

print(repr(head))
# OpusHead(version=1, channel_count=2, pre_skip=312,
#          input_sample_rate=44100, mapping_family=0)

# Round-trip the header back to bytes (e.g. for remuxing):
header_bytes = head.to_bytes()

Channel-mapping family 0 (mono and stereo) is the only family currently supported by decode_ogg_opus(). For surround layouts, see Multistream Decoding.

Round-Trip Fidelity

A full encode → decode round-trip introduces the encoder lookahead (typically 120 samples) as latency and the codec’s lossy compression artifacts:

import numpy as np
import ruopus

original = np.random.randn(48_000).astype(np.float32)
ogg      = ruopus.encode_ogg_opus(original, channels=1, bitrate=256_000)
decoded, head = ruopus.decode_ogg_opus(ogg)

# The decoded length may differ slightly due to pre_skip and frame alignment
min_len = min(len(original), len(decoded))
rms_err = np.sqrt(np.mean((original[:min_len] - decoded[:min_len, 0]) ** 2))
print(f"RMS error vs original: {rms_err:.6f}")

Saving Decoded Audio

The decoded float32 PCM can be saved with audio_samples:

import numpy as np
import audio_samples as aus

pcm, head = ruopus.decode_ogg_opus(data)
samples = aus.AudioSamples.new_mono(pcm, 48_000)
aus.io.save("decoded.wav", samples, as_type=np.float32)