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