-module(rockbox@decoder). -compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([open/1, metadata/1, next_chunk/1, seek_ms/2, elapsed_ms/1, finished/1]). -export_type([decoder/0]). -moduledoc(~" Decode an audio file to interleaved-stereo S16LE PCM, one chunk at a time. Wraps the Rockbox codec engine. The codec state is process-wide, so only one `Decoder` may decode at a time — opening a second one blocks until the first is freed. It is a NIF resource, freed by the BEAM garbage collector — no explicit close."). -type decoder() :: any(). -file("src/rockbox/decoder.gleam", 18). -spec open(binary()) -> decoder(). -doc(~" Open a decoder for the local audio file at `path`."). open(Path) -> rockbox_ffi_nif:decoder_open(Path). -file("src/rockbox/decoder.gleam", 21). -spec metadata(decoder()) -> rockbox@metadata:metadata(). -doc(~" Tags and stream properties (same shape as `metadata.read`)."). metadata(Decoder) -> case gleam@dynamic@decode:run(json:decode(rockbox_ffi_nif:decoder_metadata_json(Decoder)), rockbox@metadata:decoder()) of {ok, Meta} -> Meta; _value -> erlang:error(#{ gleam_error => let_assert, message => ~"Pattern match failed, no pattern matched the value.", file => ~"src/rockbox/decoder.gleam", module => ~"rockbox/decoder", function => ~"metadata", line => 22, value => _value, start => 826, 'end' => 923, pattern_start => 837, pattern_end => 845 }) end. -file("src/rockbox/decoder.gleam", 55). -spec chunk_decoder() -> gleam@dynamic@decode:decoder({bitstring(), integer()}). chunk_decoder() -> gleam@dynamic@decode:field(0, {decoder, fun gleam@dynamic@decode:decode_bit_array/1}, fun(Samples) -> gleam@dynamic@decode:field(1, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Rate) -> gleam@dynamic@decode:success({Samples, Rate}) end) end). -file("src/rockbox/decoder.gleam", 30). -spec next_chunk(decoder()) -> gleam@option:option({bitstring(), integer()}). -doc(~" Next buffer of decoded PCM as `#(samples, sample_rate)`, where `samples` is a little-endian int16 buffer of interleaved stereo PCM. `None` at end of track (or after a codec error — see `finished`)."). next_chunk(Decoder) -> case gleam@dynamic@decode:run(rockbox_ffi_nif:decoder_next_chunk(Decoder), chunk_decoder()) of {ok, Chunk} -> {some, Chunk}; {error, _} -> none end. -file("src/rockbox/decoder.gleam", 39). -spec seek_ms(decoder(), integer()) -> nil. -doc(~" Request a seek to `ms` milliseconds."). seek_ms(Decoder, Ms) -> rockbox_ffi_nif:decoder_seek_ms(Decoder, Ms). -file("src/rockbox/decoder.gleam", 43). -spec elapsed_ms(decoder()) -> integer(). -doc(~" Playback position last reported by the codec, in milliseconds."). elapsed_ms(Decoder) -> rockbox_ffi_nif:decoder_elapsed_ms(Decoder). -file("src/rockbox/decoder.gleam", 49). -spec finished(decoder()) -> {boolean(), integer()}. -doc(~" `#(done, code)`: `done` is `True` once the track has ended; `code` is the exit status (`0` = clean end, negative = codec error), valid only when `done`."). finished(Decoder) -> rockbox_ffi_nif:decoder_finished(Decoder).