Skip to main content

Overview

Symphonia provides a pure Rust implementation of the Vorbis audio decoder. Vorbis is a free, open-source lossy audio compression format that offers excellent quality-to-bitrate ratio and is commonly used in OGG containers.

Feature Flag

To enable Vorbis support, add the vorbis feature to your Cargo.toml:
[dependencies]
symphonia = { version = "0.5", features = ["vorbis"] }
Or use the standalone crate:
[dependencies]
symphonia-codec-vorbis = "0.5"

Status

Status: Excellent
  • Decoding: Fully supported
  • Gapless Playback: Yes
  • Container Support: OGG (requires ogg feature), WebM/Matroska (requires mkv feature)

Codec Type

use symphonia::core::codecs::CODEC_TYPE_VORBIS;

Decoder

The Vorbis decoder is implemented by the VorbisDecoder struct:
use symphonia_codec_vorbis::VorbisDecoder;
use symphonia::core::codecs::{Decoder, DecoderOptions};

// Create decoder from codec parameters
let mut decoder = VorbisDecoder::try_new(&codec_params, &DecoderOptions::default())?;

// Decode a packet
let decoded = decoder.decode(&packet)?;

Container Requirements

Vorbis requires a container format. It cannot be used as a standalone codec:
[dependencies]
# For OGG Vorbis
symphonia = { version = "0.5", features = ["vorbis", "ogg"] }

# For WebM/Matroska Vorbis
symphonia = { version = "0.5", features = ["vorbis", "mkv"] }

Supported Features

Vorbis Version

  • Vorbis I specification compliant

Bitrates

  • Variable Bitrate (VBR): 45-500 kbps (typical)
  • Quality-based encoding (q-1 to q10)
  • Managed bitrate encoding

Sample Rates

Supports all sample rates from 8 kHz to 192 kHz, including:
  • 8 kHz, 11.025 kHz, 12 kHz
  • 16 kHz, 22.05 kHz, 24 kHz
  • 32 kHz, 44.1 kHz, 48 kHz
  • 88.2 kHz, 96 kHz
  • 176.4 kHz, 192 kHz

Channels

Up to 255 channels (theoretically), with standard mappings for:
  • Mono (1.0)
  • Stereo (2.0)
  • 3.0 (L, C, R)
  • Quad (L, R, Ls, Rs)
  • 5.0 (L, C, R, Ls, Rs)
  • 5.1 (L, C, R, Ls, Rs, LFE)
  • 6.1 (L, C, R, Ls, Rs, Cs, LFE)
  • 7.1 (L, C, R, Ls, Rs, Lb, Rb, LFE)

Decoding Features

  • Variable block size windowing
  • MDCT (Modified Discrete Cosine Transform)
  • Residue vector quantization
  • Floor synthesis (Floor0 and Floor1)
  • Channel coupling
  • Huffman-style codebooks

Channel Mapping

Vorbis uses a specific channel ordering that Symphonia automatically handles:
// Symphonia automatically maps Vorbis channels to standard positions
// 1 channel: C
// 2 channels: L, R
// 3 channels: L, C, R
// 4 channels: L, R, Ls, Rs
// 5 channels: L, C, R, Ls, Rs
// 6 channels: L, C, R, Ls, Rs, LFE
// 7 channels: L, C, R, Ls, Rs, Cs, LFE
// 8 channels: L, C, R, Ls, Rs, Lb, Rb, LFE

Metadata Support

Vorbis uses Vorbis Comments for metadata:
use symphonia::core::meta::MetadataOptions;

let probed = symphonia::default::get_probe()
    .format(&hint, mss, &FormatOptions::default(), &MetadataOptions::default())?;

// Access Vorbis Comments
if let Some(metadata_rev) = probed.format.metadata().current() {
    for tag in metadata_rev.tags() {
        println!("{}: {}", tag.key, tag.value);
    }
}

// Common Vorbis Comment tags:
// TITLE, VERSION, ALBUM, TRACKNUMBER, ARTIST, PERFORMER,
// COPYRIGHT, LICENSE, ORGANIZATION, DESCRIPTION, GENRE,
// DATE, LOCATION, CONTACT, ISRC

Usage Example

use symphonia::core::codecs::{CODEC_TYPE_VORBIS, DecoderOptions};
use symphonia::core::formats::FormatOptions;
use symphonia::core::io::MediaSourceStream;
use symphonia::core::meta::MetadataOptions;
use symphonia::core::probe::Hint;
use std::fs::File;

fn decode_ogg_vorbis_file(path: &str) -> Result<(), Box<dyn std::error::Error>> {
    // Open the media source
    let file = Box::new(File::open(path)?);
    let mss = MediaSourceStream::new(file, Default::default());

    // Create a hint
    let mut hint = Hint::new();
    hint.with_extension("ogg");

    // Probe the media source
    let probed = symphonia::default::get_probe()
        .format(&hint, mss, &FormatOptions::default(), &MetadataOptions::default())?;

    let mut format = probed.format;

    // Find the Vorbis track
    let track = format.tracks()
        .iter()
        .find(|t| t.codec_params.codec == CODEC_TYPE_VORBIS)
        .ok_or("No Vorbis track found")?;

    // Create the decoder
    let mut decoder = symphonia::default::get_codecs()
        .make(&track.codec_params, &DecoderOptions::default())?;

    // Decode packets
    loop {
        let packet = match format.next_packet() {
            Ok(packet) => packet,
            Err(_) => break,
        };

        if packet.track_id() != track.id {
            continue;
        }

        let decoded = decoder.decode(&packet)?;
        // Process decoded audio...
    }

    Ok(())
}

Sample Format

Vorbis decodes to 32-bit floating-point samples (f32):
use symphonia::core::audio::AudioBufferRef;
use symphonia::core::conv::FromSample;

let decoded = decoder.decode(&packet)?;

match decoded {
    AudioBufferRef::F32(buf) => {
        // Access f32 samples directly
        for channel in 0..buf.spec().channels.count() {
            let samples = buf.chan(channel);
            // Process samples...
        }
    }
    _ => unreachable!("Vorbis always decodes to f32"),
}

Performance

  • Pure Rust implementation with no unsafe code
  • Efficient MDCT using optimized algorithms
  • Minimal memory allocations during decoding
  • Streaming-friendly design

Limitations

  • Must be used with a container format (OGG, WebM/Matroska)
  • Does not support encoding (decode-only)
  • Maximum of 255 channels (Vorbis specification limit)
  • Maximum of 32 channels practically supported by Symphonia

Specification Compliance

Fully compliant with:
  • Vorbis I specification
  • RFC 7845 (Ogg encapsulation of Vorbis)

Documentation

See Also

Build docs developers (and LLMs) love