Quickstart
==========
This guide covers the most common workflows: encode, decode, Ogg Opus files,
and a basic pipeline for streaming audio.
Basic Encode → Decode
---------------------
The simplest path: create an encoder and a decoder for the same channel count
and bounce a frame through both.
.. code-block:: python
import numpy as np
import ruopus
# Stereo encoder at 64 kbps (default: fullband, complexity 10, auto mode)
enc = ruopus.OpusEncoder(2, bitrate=64_000)
dec = ruopus.OpusDecoder(2)
# 20 ms stereo frame at 48 kHz → 960 samples per channel
frame = np.zeros((960, 2), dtype=np.float32)
packet = enc.encode_auto(frame) # bytes, encoded Opus packet
pcm = dec.decode_packet(packet) # (960, 2) float32 in [-1, 1]
print(f"Packet size: {len(packet)} bytes")
print(f"Decoded shape: {pcm.shape}, dtype: {pcm.dtype}")
Encoder input can be a 1-D interleaved array or a 2-D ``(frames, channels)``
array. Both are accepted without extra copies.
Choosing a Bitrate
------------------
Bitrate controls the quality/size tradeoff:
.. code-block:: python
# Phone-quality voice (8 kbps SILK narrowband)
enc_voice = ruopus.OpusEncoder(
1,
bitrate=8_000,
application=ruopus.Application.Voip,
signal=ruopus.Signal.Voice,
)
# High-quality music (128 kbps CELT fullband)
enc_music = ruopus.OpusEncoder(
2,
bitrate=128_000,
application=ruopus.Application.Audio,
signal=ruopus.Signal.Music,
)
# Low-latency game voice (32 kbps, restricted low delay = CELT only)
enc_ld = ruopus.OpusEncoder(
1,
bitrate=32_000,
application=ruopus.Application.RestrictedLowDelay,
)
See :doc:`codec_modes` for an explanation of what these settings select under
the hood.
Mono Audio
----------
For single-channel audio pass ``channels=1``. The PCM array is
``(frames, 1)`` after decoding.
.. code-block:: python
enc = ruopus.OpusEncoder(1, bitrate=32_000)
dec = ruopus.OpusDecoder(1)
frame = np.zeros((960, 1), dtype=np.float32) # or shape (960,)
packet = enc.encode_auto(frame)
pcm = dec.decode_packet(packet) # (960, 1) float32
Decoding to int16
-----------------
:meth:`~ruopus.OpusDecoder.decode_packet_i16` returns ``int16`` PCM scaled to
``[-32768, 32767]``, identical to the ``opus_demo`` reference output.
.. code-block:: python
dec = ruopus.OpusDecoder(2)
pcm_i16 = dec.decode_packet_i16(packet) # (frames, 2) int16
Streaming Pipeline
------------------
The encoder and decoder are both stateful: maintain them across frames so
inter-frame state (mode hysteresis, overlap buffers, concealment history) is
continuous:
.. code-block:: python
import numpy as np
import ruopus
ENC = ruopus.OpusEncoder(2, bitrate=64_000)
DEC = ruopus.OpusDecoder(2)
FRAME = 960 # 20 ms at 48 kHz
def process_stream(pcm_44k: np.ndarray) -> np.ndarray:
"""Resample, encode, and decode a stereo 44.1 kHz recording."""
# ruopus always works at 48 kHz; resample externally if needed
pcm = pcm_44k.astype(np.float32)
packets, decoded = [], []
for start in range(0, len(pcm) - FRAME, FRAME):
chunk = pcm[start : start + FRAME]
pkt = ENC.encode_auto(chunk)
out = DEC.decode_packet(pkt)
packets.append(pkt)
decoded.append(out)
return np.concatenate(decoded, axis=0)
Adjusting Encoder Settings at Runtime
--------------------------------------
All encoder properties are writable; changes take effect on the next frame:
.. code-block:: python
enc = ruopus.OpusEncoder(2, bitrate=64_000)
# Reduce bitrate mid-stream (e.g. bandwidth dropped)
enc.bitrate = 24_000
# Enable DTX to suppress silent frames
enc.dtx = True
# Bump complexity for a batch-encode job
enc.complexity = 10
Next Steps
----------
- Understand :doc:`codec_modes` and when to use each encode method
- Learn about valid :doc:`frame_sizes`
- Encode and decode complete files with :doc:`ogg`
- Handle packet loss with :doc:`fec_and_loss`
- Inspect packet structure with :doc:`packet_inspection`