// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
pub suberror DecoderError {
InvalidFormat(String)
Unsupported(String)
} derive(Debug, Eq)
///|
pub impl Show for DecoderError with fn output(self, logger) {
match self {
InvalidFormat(reason) =>
logger.write_string("DecoderError::InvalidFormat(\{reason})")
Unsupported(reason) =>
logger.write_string("DecoderError::Unsupported(\{reason})")
}
}
///|
pub struct DecodedSamples {
channels : Int
sample_rate : Int
samples : Array[Double]
cursor : Ref[Int]
}
///|
pub fn DecodedSamples::new(
channels : Int,
sample_rate : Int,
samples : Array[Double],
) -> DecodedSamples {
guard channels > 0 else { panic() }
guard sample_rate > 0 else { panic() }
{ channels, sample_rate, samples, cursor: @ref.new(0) }
}
///|
pub fn DecodedSamples::channels(self : DecodedSamples) -> Int {
self.channels
}
///|
pub fn DecodedSamples::sample_rate(self : DecodedSamples) -> Int {
self.sample_rate
}
///|
pub fn DecodedSamples::next(self : DecodedSamples) -> Double? {
if self.cursor.val >= self.samples.length() {
None
} else {
let value = self.samples[self.cursor.val]
self.cursor.val += 1
Some(value)
}
}
///|
pub fn DecodedSamples::len(self : DecodedSamples) -> Int {
self.samples.length()
}
///|
pub fn DecodedSamples::position(self : DecodedSamples) -> Int {
self.cursor.val
}
///|
pub fn DecodedSamples::seek_to(
self : DecodedSamples,
sample_index : Int,
) -> Unit {
if sample_index <= 0 {
self.cursor.val = 0
} else if sample_index >= self.samples.length() {
self.cursor.val = self.samples.length()
} else {
self.cursor.val = sample_index
}
}
///|
pub struct WavDecoder {
inner : DecodedSamples
}
///|
pub fn WavDecoder::new(bytes : Bytes) -> WavDecoder raise DecoderError {
{ inner: decode_wav_bytes(bytes) }
}
///|
pub fn WavDecoder::into_inner(self : WavDecoder) -> DecodedSamples {
self.inner
}
///|
pub fn WavDecoder::channels(self : WavDecoder) -> Int {
self.inner.channels()
}
///|
pub fn WavDecoder::sample_rate(self : WavDecoder) -> Int {
self.inner.sample_rate()
}
///|
pub fn WavDecoder::next(self : WavDecoder) -> Double? {
self.inner.next()
}
///|
pub fn WavDecoder::len(self : WavDecoder) -> Int {
self.inner.len()
}
///|
pub fn WavDecoder::position(self : WavDecoder) -> Int {
self.inner.position()
}
///|
pub fn WavDecoder::seek_to(self : WavDecoder, sample_index : Int) -> Unit {
self.inner.seek_to(sample_index)
}
///|
pub struct Mp3Decoder {
inner : DecodedSamples
}
///|
pub fn Mp3Decoder::new(bytes : Bytes) -> Mp3Decoder raise DecoderError {
{ inner: decode_mp3_bytes(bytes) }
}
///|
pub fn Mp3Decoder::into_inner(self : Mp3Decoder) -> DecodedSamples {
self.inner
}
///|
pub fn Mp3Decoder::channels(self : Mp3Decoder) -> Int {
self.inner.channels()
}
///|
pub fn Mp3Decoder::sample_rate(self : Mp3Decoder) -> Int {
self.inner.sample_rate()
}
///|
pub fn Mp3Decoder::next(self : Mp3Decoder) -> Double? {
self.inner.next()
}
///|
pub fn Mp3Decoder::len(self : Mp3Decoder) -> Int {
self.inner.len()
}
///|
pub fn Mp3Decoder::position(self : Mp3Decoder) -> Int {
self.inner.position()
}
///|
pub fn Mp3Decoder::seek_to(self : Mp3Decoder, sample_index : Int) -> Unit {
self.inner.seek_to(sample_index)
}
///|
pub struct FlacDecoder {
inner : DecodedSamples
}
///|
pub fn FlacDecoder::new(bytes : Bytes) -> FlacDecoder raise DecoderError {
{ inner: decode_flac_bytes(bytes) }
}
///|
pub fn FlacDecoder::into_inner(self : FlacDecoder) -> DecodedSamples {
self.inner
}
///|
pub fn FlacDecoder::channels(self : FlacDecoder) -> Int {
self.inner.channels()
}
///|
pub fn FlacDecoder::sample_rate(self : FlacDecoder) -> Int {
self.inner.sample_rate()
}
///|
pub fn FlacDecoder::next(self : FlacDecoder) -> Double? {
self.inner.next()
}
///|
pub fn FlacDecoder::len(self : FlacDecoder) -> Int {
self.inner.len()
}
///|
pub fn FlacDecoder::position(self : FlacDecoder) -> Int {
self.inner.position()
}
///|
pub fn FlacDecoder::seek_to(self : FlacDecoder, sample_index : Int) -> Unit {
self.inner.seek_to(sample_index)
}
///|
pub struct VorbisDecoder {
inner : DecodedSamples
}
///|
pub fn VorbisDecoder::new(bytes : Bytes) -> VorbisDecoder raise DecoderError {
{ inner: decode_vorbis_bytes(bytes) }
}
///|
pub fn VorbisDecoder::from_stream_reader(
bytes : Bytes,
) -> VorbisDecoder raise DecoderError {
VorbisDecoder::new(bytes)
}
///|
pub fn VorbisDecoder::into_inner(self : VorbisDecoder) -> DecodedSamples {
self.inner
}
///|
pub fn VorbisDecoder::channels(self : VorbisDecoder) -> Int {
self.inner.channels()
}
///|
pub fn VorbisDecoder::sample_rate(self : VorbisDecoder) -> Int {
self.inner.sample_rate()
}
///|
pub fn VorbisDecoder::next(self : VorbisDecoder) -> Double? {
self.inner.next()
}
///|
pub fn VorbisDecoder::len(self : VorbisDecoder) -> Int {
self.inner.len()
}
///|
pub fn VorbisDecoder::position(self : VorbisDecoder) -> Int {
self.inner.position()
}
///|
pub fn VorbisDecoder::seek_to(self : VorbisDecoder, sample_index : Int) -> Unit {
self.inner.seek_to(sample_index)
}
///|
pub struct ReadSeekSource {
inner : Bytes
byte_len : Int?
is_seekable : Bool
}
///|
pub fn ReadSeekSource::new(
bytes : Bytes,
byte_len? : Int? = None,
is_seekable? : Bool = true,
) -> ReadSeekSource {
ReadSeekSource::from_bytes(bytes, byte_len~, is_seekable~)
}
///|
pub fn ReadSeekSource::from_bytes(
bytes : Bytes,
byte_len? : Int? = None,
is_seekable? : Bool = true,
) -> ReadSeekSource {
let effective_len = match byte_len {
Some(v) => Some(v)
None => Some(bytes.length())
}
{ inner: bytes, byte_len: effective_len, is_seekable }
}
///|
pub fn ReadSeekSource::byte_len(self : ReadSeekSource) -> Int? {
self.byte_len
}
///|
pub fn ReadSeekSource::is_seekable(self : ReadSeekSource) -> Bool {
self.is_seekable
}
///|
pub fn ReadSeekSource::into_inner(self : ReadSeekSource) -> Bytes {
self.inner
}