// moonaudio — pure MoonBit audio decoding and DSP toolkit.
// Copyright 2026 Sakuraqwq1
// Licensed under the Apache License, Version 2.0.
///|
/// Encoding of a single sample as stored in a container.
///
/// `moonaudio` always decodes samples to `Double` in the closed interval
/// `[-1.0, 1.0]`, so this type only describes the *source* (or requested
/// target) representation.
pub(all) enum SampleFormat {
/// Unsigned 8 bit, offset binary (0..255 maps to -1.0..1.0).
U8
/// Signed 16 bit, endianness depends on the container.
I16
/// Signed 24 bit, stored as three bytes.
I24
/// Signed 32 bit.
I32
/// IEEE 754 single precision.
F32
/// IEEE 754 double precision.
F64
}
///|
/// Number of bits occupied by one sample of this format.
pub fn SampleFormat::bits(self : SampleFormat) -> Int32 {
match self {
U8 => 8
I16 => 16
I24 => 24
I32 => 32
F32 => 32
F64 => 64
}
}
///|
/// Number of bytes occupied by one sample of this format.
pub fn SampleFormat::bytes(self : SampleFormat) -> Int32 {
self.bits() / 8
}
///|
/// `true` when the format stores IEEE floating point samples.
pub fn SampleFormat::is_float(self : SampleFormat) -> Bool {
match self {
F32 | F64 => true
_ => false
}
}
///|
/// `true` when the format stores signed integers.
pub fn SampleFormat::is_signed(self : SampleFormat) -> Bool {
match self {
I16 | I24 | I32 => true
_ => false
}
}
///|
/// Largest integer code of the format (1.0 for float formats).
pub fn SampleFormat::max_code(self : SampleFormat) -> Double {
match self {
U8 => 127.0
I16 => 32767.0
I24 => 8388607.0
I32 => 2147483647.0
F32 | F64 => 1.0
}
}
///|
/// Parse a format name such as `"s16"`, `"s24"`, `"f32"` or `"u8"`.
///
/// The accepted spellings follow `ffmpeg` style tooling, with a few aliases
/// (`pcm16`, `float32`, `int24`, ...) so the CLI is forgiving.
pub fn SampleFormat::parse(name : String) -> SampleFormat raise AudioError {
let lowered = name.to_lower()
match lowered {
"u8" | "u8le" | "uint8" | "pcm_u8" => U8
"s16" | "i16" | "s16le" | "i16le" | "int16" | "pcm16" | "pcm_s16le" => I16
"s24" | "i24" | "s24le" | "int24" | "pcm24" => I24
"s32" | "i32" | "s32le" | "int32" | "pcm32" => I32
"f32" | "float" | "float32" | "f32le" => F32
"f64" | "double" | "float64" | "f64le" => F64
_ => raise Invalid("unknown sample format \"" + name + "\"")
}
}
///|
/// Canonical short name of a sample format, the inverse of
/// [`SampleFormat::parse`].
pub fn SampleFormat::to_name(self : SampleFormat) -> String {
match self {
U8 => "u8"
I16 => "s16"
I24 => "s24"
I32 => "s32"
F32 => "f32"
F64 => "f64"
}
}
///|
/// `true` when two sample formats are the same variant.
pub fn SampleFormat::same(self : SampleFormat, other : SampleFormat) -> Bool {
self.to_name() == other.to_name()
}