///|
/// Vorbis stream configuration parsed from headers.
struct VorbisInfo {
channels : Int
sample_rate : Int
blocksize_0 : Int
blocksize_1 : Int
codebooks : Array[VorbisCodebook]
floors : Array[VorbisFloorConfig]
residues : Array[VorbisResidueConfig]
mappings : Array[VorbisMapping]
modes : Array[VorbisMode]
} derive(Show)
///|
/// Vorbis floor type 1 configuration.
struct VorbisFloorConfig {
partitions : Int
partition_class : Array[Int]
class_dimensions : Array[Int]
class_subclasses : Array[Int]
class_masterbooks : Array[Int]
subclass_books : Array[Array[Int]]
multiplier : Int
x_list : Array[Int]
sorted_index : Array[Int]
} derive(Show)
///|
/// Vorbis residue configuration.
struct VorbisResidueConfig {
residue_type : Int
begin : Int
end_ : Int
partition_size : Int
classifications : Int
classbook : Int
cascade : Array[Int]
books : Array[Array[Int]]
} derive(Show)
///|
/// Vorbis channel mapping.
struct VorbisMapping {
submaps : Int
coupling_steps : Int
coupling_magnitude : Array[Int]
coupling_angle : Array[Int]
mux : Array[Int]
submap_floor : Array[Int]
submap_residue : Array[Int]
} derive(Show)
///|
/// Vorbis mode configuration.
struct VorbisMode {
block_flag : Bool
mapping : Int
} derive(Show)
///|
/// Parse the Vorbis identification header.
fn parse_identification_header(
data : Bytes,
) -> (Int, Int, Int, Int) raise AudioError {
if data.length() < 30 {
raise AudioError::DecodeFailed("Vorbis: identification header too short")
}
// Check packet type (1) and "vorbis" magic
if data[0].to_int() != 1 {
raise AudioError::DecodeFailed("Vorbis: not an identification header")
}
if data[1].to_int() != 0x76 ||
data[2].to_int() != 0x6F ||
data[3].to_int() != 0x72 ||
data[4].to_int() != 0x62 ||
data[5].to_int() != 0x69 ||
data[6].to_int() != 0x73 {
raise AudioError::DecodeFailed("Vorbis: invalid magic")
}
let _version = read_u32le(data, 7)
let channels = read_u8(data, 11)
let sample_rate = read_u32le(data, 12)
// Skip bitrate fields (12 bytes)
let blocksize_byte = read_u8(data, 28)
let blocksize_0 = 1 << (blocksize_byte & 0x0F)
let blocksize_1 = 1 << ((blocksize_byte >> 4) & 0x0F)
(channels, sample_rate, blocksize_0, blocksize_1)
}
///|
/// Parse the Vorbis setup header (codebooks, floors, residues, mappings, modes).
fn parse_setup_header(
data : Bytes,
channels : Int,
) -> (
Array[VorbisCodebook],
Array[VorbisFloorConfig],
Array[VorbisResidueConfig],
Array[VorbisMapping],
Array[VorbisMode],
) raise AudioError {
if data.length() < 7 {
raise AudioError::DecodeFailed("Vorbis: setup header too short")
}
if data[0].to_int() != 5 {
raise AudioError::DecodeFailed("Vorbis: not a setup header")
}
// Check "vorbis" magic
if data[1].to_int() != 0x76 ||
data[2].to_int() != 0x6F ||
data[3].to_int() != 0x72 ||
data[4].to_int() != 0x62 ||
data[5].to_int() != 0x69 ||
data[6].to_int() != 0x73 {
raise AudioError::DecodeFailed("Vorbis: invalid setup magic")
}
let br = new_bit_reader(data)
// Skip packet type + "vorbis" = 7 bytes
br.bit_pos = 7 * 8
// Codebooks
let codebook_count = read_bits(br, 8) + 1
let codebooks : Array[VorbisCodebook] = []
for _ in 0.. ignore
}
// Floors
let floor_count = read_bits(br, 6) + 1
let floors : Array[VorbisFloorConfig] = []
for _ in 0.. VorbisFloorConfig raise AudioError {
let floor_type = read_bits(br, 16)
if floor_type != 1 {
raise AudioError::DecodeFailed(
"Vorbis: only floor type 1 is supported (got \{floor_type})",
)
}
let partitions = read_bits(br, 5)
let partition_class : Array[Int] = []
let mut max_class = -1
for _ in 0.. max_class {
max_class = cls
}
}
let class_dimensions : Array[Int] = []
let class_subclasses : Array[Int] = []
let class_masterbooks : Array[Int] = []
let subclass_books : Array[Array[Int]] = []
for _ in 0..<=max_class {
let dim = read_bits(br, 3) + 1
class_dimensions.push(dim)
let sub = read_bits(br, 2)
class_subclasses.push(sub)
let master = if sub > 0 { read_bits(br, 8) } else { 0 }
class_masterbooks.push(master)
let books : Array[Int] = []
let num_sub = 1 << sub
for _ in 0.. VorbisResidueConfig raise AudioError {
let residue_type = read_bits(br, 16)
if residue_type > 2 {
raise AudioError::DecodeFailed(
"Vorbis: unsupported residue type \{residue_type}",
)
}
let begin = read_bits(br, 24)
let end_ = read_bits(br, 24)
let partition_size = read_bits(br, 24) + 1
let classifications = read_bits(br, 6) + 1
let classbook = read_bits(br, 8)
let cascade : Array[Int] = []
for _ in 0.. VorbisMapping raise AudioError {
let mapping_type = read_bits(br, 16)
if mapping_type != 0 {
raise AudioError::DecodeFailed("Vorbis: unsupported mapping type")
}
let submaps = if read_bit(br) { read_bits(br, 4) + 1 } else { 1 }
let mut coupling_steps = 0
let coupling_magnitude : Array[Int] = []
let coupling_angle : Array[Int] = []
if read_bit(br) {
coupling_steps = read_bits(br, 8) + 1
let ch_bits = ilog(channels - 1)
for _ in 0.. 1 {
for _ in 0.. ignore // unused time config
submap_floor.push(read_bits(br, 8))
submap_residue.push(read_bits(br, 8))
}
VorbisMapping::{
submaps,
coupling_steps,
coupling_magnitude,
coupling_angle,
mux,
submap_floor,
submap_residue,
}
}
///|
/// Parse all three Vorbis headers from an OGG demuxer and return VorbisInfo.
fn parse_vorbis_headers(demuxer : OggDemuxer) -> VorbisInfo raise AudioError {
// Packet 1: Identification header
let id_packet = match next_packet(demuxer) {
Some(p) => p
None =>
raise AudioError::DecodeFailed("Vorbis: missing identification header")
}
let (channels, sample_rate, blocksize_0, blocksize_1) = parse_identification_header(
id_packet,
)
// Packet 2: Comment header (skip)
match next_packet(demuxer) {
Some(_) => ()
None => raise AudioError::DecodeFailed("Vorbis: missing comment header")
}
// Packet 3: Setup header
let setup_packet = match next_packet(demuxer) {
Some(p) => p
None => raise AudioError::DecodeFailed("Vorbis: missing setup header")
}
let (codebooks, floors, residues, mappings, modes) = parse_setup_header(
setup_packet, channels,
)
VorbisInfo::{
channels,
sample_rate,
blocksize_0,
blocksize_1,
codebooks,
floors,
residues,
mappings,
modes,
}
}
///|
/// Top-level OGG/Vorbis decode function.
/// Decodes an OGG/Vorbis file from raw bytes into an AudioBuffer.
pub fn decode_ogg(raw : Bytes) -> AudioBuffer raise AudioError {
let demuxer = new_ogg_demuxer(raw)
let info = parse_vorbis_headers(demuxer)
// Decode audio packets
let samples : Array[Float] = []
let mut prev_left : Array[Float] = []
let mut prev_right : Array[Float] = []
while true {
let packet = match next_packet(demuxer) {
Some(p) => p
None => break
}
let (left, right) = decode_audio_packet(info, packet)
// Overlap-add with previous window
if prev_left.length() > 0 {
let overlap = if prev_left.length() < left.length() {
prev_left.length()
} else {
left.length()
}
let half_overlap = overlap / 2
// Add overlapping region
for i in 0..= 2 {
samples.push(
prev_left[prev_left.length() - half_overlap + i] + left[i],
)
samples.push(
prev_right[prev_right.length() - half_overlap + i] + right[i],
)
} else {
samples.push(
prev_left[prev_left.length() - half_overlap + i] + left[i],
)
}
}
// Add non-overlapping part of current window
for i in half_overlap..= 2 {
samples.push(left[i])
samples.push(right[i])
} else {
samples.push(left[i])
}
}
}
prev_left = left
prev_right = right
}
let data = FixedArray::make(samples.length(), (0.0 : Float))
for i in 0..