-module(rockbox@player). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/rockbox/player.gleam"). -export([default_config/0, eq_preset_to_int/1, channel_mode_to_int/1, crossfeed_mode_to_int/1, repeat_mode_to_int/1, repeat_mode_from_int/1, new/0, with_config/1, set_queue/2, insert/3, queue/1, enqueue/2, play/1, pause/1, toggle/1, stop/1, next/1, previous/1, skip_to/2, seek_ms/2, set_volume/2, volume/1, sample_rate/1, set_crossfade/7, set_replaygain/4, status/1, set_shuffle/2, is_shuffle_enabled/1, set_repeat/2, repeat/1, set_eq_enabled/2, is_eq_enabled/1, set_eq_band/5, set_eq_precut/2, set_eq_preset/2, set_tone/5, set_bass/2, set_treble/2, set_surround/5, set_channel_mode/2, set_stereo_width/2, set_compressor/7, set_dither/2, set_pitch/2, set_bass_cutoff/2, set_treble_cutoff/2, set_crossfeed/6, set_bass_enhancement/3, set_fatigue_reduction/2, dsp_settings/1, resume/1, save_resume/1, clear_resume/1, load_resume/1, import_m3u/3, load_m3u/2, export_m3u/2, m3u_read/1, m3u_write/2, is_url/1]). -export_type([player/0, insert_position/0, config/0, resume_state/0, m3u_entry/0, eq_preset/0, channel_mode/0, crossfeed_mode/0, repeat_mode/0, status/0, eq_band/0, equalizer/0, tone/0, surround/0, compressor/0, crossfeed/0, bass_enhancement/0, dsp_settings/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( " Queue-based player with native ReplayGain and Rockbox crossfade.\n" "\n" " A `Player` owns a live audio output device and a background engine\n" " thread, so it only works where an output device exists. The handle is a\n" " NIF resource, freed by the BEAM garbage collector (which stops playback).\n" "\n" " ReplayGain `mode` here uses the player values: 0 off, 1 track, 2 album.\n" " Crossfade `mode`: 0 off, 1 auto-skip, 2 manual-skip, 3 shuffle,\n" " 4 shuffle-or-manual, 5 always. Mix mode: 0 crossfade, 1 mix.\n" "\n" " Mutating functions return the `Player`, so they can be piped:\n" "\n" " p\n" " |> player.set_queue(tracks)\n" " |> player.set_shuffle(True)\n" " |> player.set_repeat(player.All)\n" " |> player.play\n" ). -type player() :: any(). -type insert_position() :: prepend | insert | insert_next | insert_last | insert_shuffled | insert_last_shuffled | replace | {index, integer()}. -type config() :: {config, integer(), float(), float(), integer(), float(), boolean(), integer(), integer(), integer(), integer(), integer(), integer(), gleam@option:option(binary()), integer()}. -type resume_state() :: {resume_state, list(binary()), integer(), integer()}. -type m3u_entry() :: {m3u_entry, binary(), gleam@option:option(integer()), gleam@option:option(binary())}. -type eq_preset() :: flat | acoustic | bass_boost | bass_reducer | classical | dance | deep | electronic | hip_hop | jazz | latin | loudness | lounge | piano | pop | rn_b | rock | small_speakers | treble_boost | treble_reducer | vocal_boost. -type channel_mode() :: stereo | mono | custom | mono_left | mono_right | karaoke | swap. -type crossfeed_mode() :: crossfeed_off | meier | crossfeed_custom. -type repeat_mode() :: off | one | all. -type status() :: {status, binary(), gleam@option:option(integer()), integer(), integer(), integer(), boolean(), binary()}. -type eq_band() :: {eq_band, integer(), float(), float()}. -type equalizer() :: {equalizer, boolean(), float(), list(eq_band())}. -type tone() :: {tone, integer(), integer(), integer(), integer()}. -type surround() :: {surround, integer(), integer(), integer(), integer()}. -type compressor() :: {compressor, integer(), integer(), integer(), integer(), integer(), integer()}. -type crossfeed() :: {crossfeed, binary(), integer(), integer(), integer(), integer()}. -type bass_enhancement() :: {bass_enhancement, integer(), integer()}. -type dsp_settings() :: {dsp_settings, equalizer(), tone(), surround(), binary(), integer(), compressor(), boolean(), integer(), crossfeed(), bass_enhancement(), integer()}. -file("src/rockbox/player.gleam", 83). ?DOC( " Rockbox-default configuration (device sample rate, no crossfade,\n" " ReplayGain off, full volume, resume disabled).\n" ). -spec default_config() -> config(). default_config() -> {config, 0, 4.0, 1.0, 0, +0.0, true, 0, 0, 2000, 0, 2000, 0, none, 0}. -file("src/rockbox/player.gleam", 104). ?DOC( " Encode an `InsertPosition` as the ABI's integer tag plus the index arg\n" " (only meaningful for `Index`).\n" ). -spec insert_position_args(insert_position()) -> {integer(), integer()}. insert_position_args(Position) -> case Position of prepend -> {0, 0}; insert -> {1, 0}; insert_next -> {2, 0}; insert_last -> {3, 0}; insert_shuffled -> {4, 0}; insert_last_shuffled -> {5, 0}; replace -> {6, 0}; {index, I} -> {7, I} end. -file("src/rockbox/player.gleam", 144). ?DOC(" Encode an `EqPreset` as the ABI's integer id (0..20).\n"). -spec eq_preset_to_int(eq_preset()) -> integer(). eq_preset_to_int(Preset) -> case Preset of flat -> 0; acoustic -> 1; bass_boost -> 2; bass_reducer -> 3; classical -> 4; dance -> 5; deep -> 6; electronic -> 7; hip_hop -> 8; jazz -> 9; latin -> 10; loudness -> 11; lounge -> 12; piano -> 13; pop -> 14; rn_b -> 15; rock -> 16; small_speakers -> 17; treble_boost -> 18; treble_reducer -> 19; vocal_boost -> 20 end. -file("src/rockbox/player.gleam", 183). ?DOC(" Encode a `ChannelMode` as the ABI's integer id (0..6).\n"). -spec channel_mode_to_int(channel_mode()) -> integer(). channel_mode_to_int(Mode) -> case Mode of stereo -> 0; mono -> 1; custom -> 2; mono_left -> 3; mono_right -> 4; karaoke -> 5; swap -> 6 end. -file("src/rockbox/player.gleam", 204). ?DOC(" Encode a `CrossfeedMode` as the ABI's integer id (0/1/2).\n"). -spec crossfeed_mode_to_int(crossfeed_mode()) -> integer(). crossfeed_mode_to_int(Mode) -> case Mode of crossfeed_off -> 0; meier -> 1; crossfeed_custom -> 2 end. -file("src/rockbox/player.gleam", 221). ?DOC(" Encode a `RepeatMode` as the ABI's integer id (0/1/2).\n"). -spec repeat_mode_to_int(repeat_mode()) -> integer(). repeat_mode_to_int(Mode) -> case Mode of off -> 0; one -> 1; all -> 2 end. -file("src/rockbox/player.gleam", 230). ?DOC(" Decode the ABI's integer id (0/1/2) into a `RepeatMode` (unknown → `Off`).\n"). -spec repeat_mode_from_int(integer()) -> repeat_mode(). repeat_mode_from_int(Value) -> case Value of 1 -> one; 2 -> all; _ -> off end. -file("src/rockbox/player.gleam", 328). ?DOC(" Create a player on the default device with default settings.\n"). -spec new() -> player(). new() -> rockbox_ffi_nif:player_new(). -file("src/rockbox/player.gleam", 331). ?DOC(" Create a player with explicit configuration (including resume).\n"). -spec with_config(config()) -> player(). with_config(C) -> Resume_file = case erlang:element(14, C) of {some, Path} -> gleam_stdlib:identity(Path); none -> gleam@dynamic:nil() end, rockbox_ffi_nif:player_new_with_config_ex( erlang:element(2, C), erlang:element(3, C), erlang:element(4, C), erlang:element(5, C), erlang:element(6, C), erlang:element(7, C), erlang:element(8, C), erlang:element(9, C), erlang:element(10, C), erlang:element(11, C), erlang:element(12, C), erlang:element(13, C), Resume_file, erlang:element(15, C) ). -file("src/rockbox/player.gleam", 358). ?DOC( " Replace the queue. Each entry may be a local file path, an `http(s)://`\n" " URL to a finite remote file, or a live-radio / streaming URL.\n" ). -spec set_queue(player(), list(binary())) -> player(). set_queue(Player, Paths) -> rockbox_ffi_nif:player_set_queue_json( Player, erlang:iolist_to_binary(json:encode(Paths)) ), Player. -file("src/rockbox/player.gleam", 364). ?DOC(" Insert a list of paths / URLs into the queue at `position`.\n"). -spec insert(player(), list(binary()), insert_position()) -> player(). insert(Player, Paths, Position) -> {Pos, Index} = insert_position_args(Position), rockbox_ffi_nif:player_insert_json( Player, erlang:iolist_to_binary(json:encode(Paths)), Pos, Index ), Player. -file("src/rockbox/player.gleam", 375). ?DOC(" The current queue as a list of paths / URLs.\n"). -spec queue(player()) -> list(binary()). queue(Player) -> case gleam@dynamic@decode:run( json:decode(rockbox_ffi_nif:player_queue_json(Player)), gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_string/1} ) ) of {ok, Paths} -> Paths; {error, _} -> [] end. -file("src/rockbox/player.gleam", 384). ?DOC( " Append one track to the queue. `path` may be a local file path, an\n" " `http(s)://` URL to a finite remote file, or a live-radio / streaming URL.\n" ). -spec enqueue(player(), binary()) -> player(). enqueue(Player, Path) -> rockbox_ffi_nif:player_enqueue(Player, Path), Player. -file("src/rockbox/player.gleam", 393). ?DOC(" Start (or resume) playback.\n"). -spec play(player()) -> player(). play(Player) -> rockbox_ffi_nif:player_play(Player), Player. -file("src/rockbox/player.gleam", 402). ?DOC(" Pause playback.\n"). -spec pause(player()) -> player(). pause(Player) -> rockbox_ffi_nif:player_pause(Player), Player. -file("src/rockbox/player.gleam", 411). ?DOC(" Toggle between play and pause.\n"). -spec toggle(player()) -> player(). toggle(Player) -> rockbox_ffi_nif:player_toggle(Player), Player. -file("src/rockbox/player.gleam", 420). ?DOC(" Stop playback.\n"). -spec stop(player()) -> player(). stop(Player) -> rockbox_ffi_nif:player_stop(Player), Player. -file("src/rockbox/player.gleam", 429). ?DOC(" Skip to the next track.\n"). -spec next(player()) -> player(). next(Player) -> rockbox_ffi_nif:player_next(Player), Player. -file("src/rockbox/player.gleam", 438). ?DOC(" Skip to the previous track.\n"). -spec previous(player()) -> player(). previous(Player) -> rockbox_ffi_nif:player_previous(Player), Player. -file("src/rockbox/player.gleam", 447). ?DOC(" Skip to the track at `index` in the queue.\n"). -spec skip_to(player(), integer()) -> player(). skip_to(Player, Index) -> rockbox_ffi_nif:player_skip_to(Player, Index), Player. -file("src/rockbox/player.gleam", 456). ?DOC(" Seek to `ms` within the current track.\n"). -spec seek_ms(player(), integer()) -> player(). seek_ms(Player, Ms) -> rockbox_ffi_nif:player_seek_ms(Player, Ms), Player. -file("src/rockbox/player.gleam", 465). ?DOC(" Set the output volume (0.0..1.0).\n"). -spec set_volume(player(), float()) -> player(). set_volume(Player, Volume) -> rockbox_ffi_nif:player_set_volume(Player, Volume), Player. -file("src/rockbox/player.gleam", 474). -spec volume(player()) -> float(). volume(Player) -> rockbox_ffi_nif:player_volume(Player). -file("src/rockbox/player.gleam", 477). -spec sample_rate(player()) -> integer(). sample_rate(Player) -> rockbox_ffi_nif:player_sample_rate(Player). -file("src/rockbox/player.gleam", 480). ?DOC(" Configure crossfade behaviour.\n"). -spec set_crossfade( player(), integer(), integer(), integer(), integer(), integer(), integer() ) -> player(). set_crossfade( Player, Mode, Fade_out_delay_ms, Fade_out_duration_ms, Fade_in_delay_ms, Fade_in_duration_ms, Mix_mode ) -> rockbox_ffi_nif:player_set_crossfade( Player, Mode, Fade_out_delay_ms, Fade_out_duration_ms, Fade_in_delay_ms, Fade_in_duration_ms, Mix_mode ), Player. -file("src/rockbox/player.gleam", 513). ?DOC(" Configure ReplayGain (mode, pre-amp in dB, clipping prevention).\n"). -spec set_replaygain(player(), integer(), float(), boolean()) -> player(). set_replaygain(Player, Mode, Preamp_db, Prevent_clipping) -> rockbox_ffi_nif:player_set_replaygain( Player, Mode, Preamp_db, Prevent_clipping ), Player. -file("src/rockbox/player.gleam", 954). -spec status_decoder() -> gleam@dynamic@decode:decoder(status()). status_decoder() -> gleam@dynamic@decode:field( <<"state"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(State) -> gleam@dynamic@decode:field( <<"index"/utf8>>, gleam@dynamic@decode:one_of( gleam@dynamic@decode:map( {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Field@0) -> {some, Field@0} end ), [gleam@dynamic@decode:success(none)] ), fun(Index) -> gleam@dynamic@decode:field( <<"position_ms"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Position_ms) -> gleam@dynamic@decode:field( <<"duration_ms"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Duration_ms) -> gleam@dynamic@decode:field( <<"queue_len"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Queue_len) -> gleam@dynamic@decode:field( <<"shuffle"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_bool/1}, fun(Shuffle) -> gleam@dynamic@decode:field( <<"repeat"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Repeat) -> gleam@dynamic@decode:success( {status, State, Index, Position_ms, Duration_ms, Queue_len, Shuffle, Repeat} ) end ) end ) end ) end ) end ) end ) end ). -file("src/rockbox/player.gleam", 532). ?DOC(" A snapshot of the player's status.\n"). -spec status(player()) -> status(). status(Player) -> Status@1 = case gleam@dynamic@decode:run( json:decode(rockbox_ffi_nif:player_status_json(Player)), status_decoder() ) of {ok, Status} -> Status; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"rockbox/player"/utf8>>, function => <<"status"/utf8>>, line => 533, value => _assert_fail, start => 12833, 'end' => 12927, pattern_start => 12844, pattern_end => 12854}) end, Status@1. -file("src/rockbox/player.gleam", 541). ?DOC(" Enable or disable shuffle playback.\n"). -spec set_shuffle(player(), boolean()) -> player(). set_shuffle(Player, Enabled) -> rockbox_ffi_nif:player_set_shuffle(Player, Enabled), Player. -file("src/rockbox/player.gleam", 551). ?DOC(" Whether shuffle playback is currently enabled.\n"). -spec is_shuffle_enabled(player()) -> boolean(). is_shuffle_enabled(Player) -> rockbox_ffi_nif:player_is_shuffle_enabled(Player). -file("src/rockbox/player.gleam", 554). ?DOC(" Set the repeat mode (off / one / all).\n"). -spec set_repeat(player(), repeat_mode()) -> player(). set_repeat(Player, Mode) -> rockbox_ffi_nif:player_set_repeat(Player, repeat_mode_to_int(Mode)), Player. -file("src/rockbox/player.gleam", 560). ?DOC(" The current repeat mode (off / one / all).\n"). -spec repeat(player()) -> repeat_mode(). repeat(Player) -> repeat_mode_from_int(rockbox_ffi_nif:player_repeat(Player)). -file("src/rockbox/player.gleam", 567). ?DOC(" Enable or disable the graphic equalizer.\n"). -spec set_eq_enabled(player(), boolean()) -> player(). set_eq_enabled(Player, Enabled) -> rockbox_ffi_nif:player_set_eq_enabled(Player, Enabled), Player. -file("src/rockbox/player.gleam", 577). ?DOC(" Whether the graphic equalizer is currently enabled.\n"). -spec is_eq_enabled(player()) -> boolean(). is_eq_enabled(Player) -> rockbox_ffi_nif:player_is_eq_enabled(Player). -file("src/rockbox/player.gleam", 580). ?DOC(" Configure one EQ band: `cutoff_hz` in Hz, `q` factor, `gain_db` in dB.\n"). -spec set_eq_band(player(), integer(), integer(), float(), float()) -> player(). set_eq_band(Player, Band, Cutoff_hz, Q, Gain_db) -> rockbox_ffi_nif:player_set_eq_band(Player, Band, Cutoff_hz, Q, Gain_db), Player. -file("src/rockbox/player.gleam", 601). ?DOC(" Set the EQ pre-cut (headroom), in dB.\n"). -spec set_eq_precut(player(), float()) -> player(). set_eq_precut(Player, Db) -> rockbox_ffi_nif:player_set_eq_precut(Player, Db), Player. -file("src/rockbox/player.gleam", 610). ?DOC(" Apply a built-in EQ preset.\n"). -spec set_eq_preset(player(), eq_preset()) -> player(). set_eq_preset(Player, Preset) -> rockbox_ffi_nif:player_set_eq_preset(Player, eq_preset_to_int(Preset)), Player. -file("src/rockbox/player.gleam", 616). ?DOC(" Set the bass/treble tone controls (gains in dB, cutoffs in Hz).\n"). -spec set_tone(player(), integer(), integer(), integer(), integer()) -> player(). set_tone(Player, Bass_db, Treble_db, Bass_cutoff_hz, Treble_cutoff_hz) -> rockbox_ffi_nif:player_set_tone( Player, Bass_db, Treble_db, Bass_cutoff_hz, Treble_cutoff_hz ), Player. -file("src/rockbox/player.gleam", 637). ?DOC(" Set the bass tone gain, in dB.\n"). -spec set_bass(player(), integer()) -> player(). set_bass(Player, Bass_db) -> rockbox_ffi_nif:player_set_bass(Player, Bass_db), Player. -file("src/rockbox/player.gleam", 646). ?DOC(" Set the treble tone gain, in dB.\n"). -spec set_treble(player(), integer()) -> player(). set_treble(Player, Treble_db) -> rockbox_ffi_nif:player_set_treble(Player, Treble_db), Player. -file("src/rockbox/player.gleam", 655). ?DOC(" Configure the surround effect (delay in ms, balance, cutoffs in Hz).\n"). -spec set_surround(player(), integer(), integer(), integer(), integer()) -> player(). set_surround(Player, Delay_ms, Balance, Cutoff_low_hz, Cutoff_high_hz) -> rockbox_ffi_nif:player_set_surround( Player, Delay_ms, Balance, Cutoff_low_hz, Cutoff_high_hz ), Player. -file("src/rockbox/player.gleam", 676). ?DOC(" Set the channel-mixing mode.\n"). -spec set_channel_mode(player(), channel_mode()) -> player(). set_channel_mode(Player, Mode) -> rockbox_ffi_nif:player_set_channel_mode(Player, channel_mode_to_int(Mode)), Player. -file("src/rockbox/player.gleam", 682). ?DOC(" Set the stereo width, as a percentage.\n"). -spec set_stereo_width(player(), integer()) -> player(). set_stereo_width(Player, Percent) -> rockbox_ffi_nif:player_set_stereo_width(Player, Percent), Player. -file("src/rockbox/player.gleam", 691). ?DOC(" Configure the dynamic-range compressor.\n"). -spec set_compressor( player(), integer(), integer(), integer(), integer(), integer(), integer() ) -> player(). set_compressor( Player, Threshold_db, Makeup_gain, Ratio, Knee, Attack_ms, Release_ms ) -> rockbox_ffi_nif:player_set_compressor( Player, Threshold_db, Makeup_gain, Ratio, Knee, Attack_ms, Release_ms ), Player. -file("src/rockbox/player.gleam", 724). ?DOC(" Enable or disable output dithering.\n"). -spec set_dither(player(), boolean()) -> player(). set_dither(Player, Enabled) -> rockbox_ffi_nif:player_set_dither(Player, Enabled), Player. -file("src/rockbox/player.gleam", 733). ?DOC(" Set the pitch ratio (Rockbox's fixed-point pitch value).\n"). -spec set_pitch(player(), integer()) -> player(). set_pitch(Player, Ratio) -> rockbox_ffi_nif:player_set_pitch(Player, Ratio), Player. -file("src/rockbox/player.gleam", 742). ?DOC(" Set the bass tone cutoff frequency, in Hz.\n"). -spec set_bass_cutoff(player(), integer()) -> player(). set_bass_cutoff(Player, Hz) -> rockbox_ffi_nif:player_set_bass_cutoff(Player, Hz), Player. -file("src/rockbox/player.gleam", 751). ?DOC(" Set the treble tone cutoff frequency, in Hz.\n"). -spec set_treble_cutoff(player(), integer()) -> player(). set_treble_cutoff(Player, Hz) -> rockbox_ffi_nif:player_set_treble_cutoff(Player, Hz), Player. -file("src/rockbox/player.gleam", 762). ?DOC( " Configure the crossfeed (headphone) effect. `direct_gain`, `cross_gain`\n" " and `high_freq_gain` are gains; `high_freq_cutoff` is in Hz. The gain\n" " values only take effect in `CrossfeedCustom` mode.\n" ). -spec set_crossfeed( player(), crossfeed_mode(), integer(), integer(), integer(), integer() ) -> player(). set_crossfeed( Player, Mode, Direct_gain, Cross_gain, High_freq_gain, High_freq_cutoff ) -> rockbox_ffi_nif:player_set_crossfeed( Player, crossfeed_mode_to_int(Mode), Direct_gain, Cross_gain, High_freq_gain, High_freq_cutoff ), Player. -file("src/rockbox/player.gleam", 792). ?DOC(" Configure bass enhancement (`strength` and `precut`).\n"). -spec set_bass_enhancement(player(), integer(), integer()) -> player(). set_bass_enhancement(Player, Strength, Precut) -> rockbox_ffi_nif:player_set_bass_enhancement(Player, Strength, Precut), Player. -file("src/rockbox/player.gleam", 805). ?DOC(" Set the listening-fatigue reduction strength.\n"). -spec set_fatigue_reduction(player(), integer()) -> player(). set_fatigue_reduction(Player, Strength) -> rockbox_ffi_nif:player_set_fatigue_reduction(Player, Strength), Player. -file("src/rockbox/player.gleam", 1040). -spec bass_enhancement_decoder() -> gleam@dynamic@decode:decoder(bass_enhancement()). bass_enhancement_decoder() -> gleam@dynamic@decode:field( <<"strength"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Strength) -> gleam@dynamic@decode:field( <<"precut"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Precut) -> gleam@dynamic@decode:success( {bass_enhancement, Strength, Precut} ) end ) end ). -file("src/rockbox/player.gleam", 1025). -spec crossfeed_decoder() -> gleam@dynamic@decode:decoder(crossfeed()). crossfeed_decoder() -> gleam@dynamic@decode:field( <<"mode"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Mode) -> gleam@dynamic@decode:field( <<"direct_gain"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Direct_gain) -> gleam@dynamic@decode:field( <<"cross_gain"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Cross_gain) -> gleam@dynamic@decode:field( <<"high_freq_gain"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(High_freq_gain) -> gleam@dynamic@decode:field( <<"high_freq_cutoff"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(High_freq_cutoff) -> gleam@dynamic@decode:success( {crossfeed, Mode, Direct_gain, Cross_gain, High_freq_gain, High_freq_cutoff} ) end ) end ) end ) end ) end ). -file("src/rockbox/player.gleam", 1008). -spec compressor_decoder() -> gleam@dynamic@decode:decoder(compressor()). compressor_decoder() -> gleam@dynamic@decode:field( <<"threshold_db"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Threshold_db) -> gleam@dynamic@decode:field( <<"makeup_gain"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Makeup_gain) -> gleam@dynamic@decode:field( <<"ratio"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Ratio) -> gleam@dynamic@decode:field( <<"knee"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Knee) -> gleam@dynamic@decode:field( <<"attack_ms"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Attack_ms) -> gleam@dynamic@decode:field( <<"release_ms"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Release_ms) -> gleam@dynamic@decode:success( {compressor, Threshold_db, Makeup_gain, Ratio, Knee, Attack_ms, Release_ms} ) end ) end ) end ) end ) end ) end ). -file("src/rockbox/player.gleam", 1000). -spec surround_decoder() -> gleam@dynamic@decode:decoder(surround()). surround_decoder() -> gleam@dynamic@decode:field( <<"delay_ms"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Delay_ms) -> gleam@dynamic@decode:field( <<"balance"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Balance) -> gleam@dynamic@decode:field( <<"cutoff_low_hz"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Cutoff_low_hz) -> gleam@dynamic@decode:field( <<"cutoff_high_hz"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Cutoff_high_hz) -> gleam@dynamic@decode:success( {surround, Delay_ms, Balance, Cutoff_low_hz, Cutoff_high_hz} ) end ) end ) end ) end ). -file("src/rockbox/player.gleam", 992). -spec tone_decoder() -> gleam@dynamic@decode:decoder(tone()). tone_decoder() -> gleam@dynamic@decode:field( <<"bass_db"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Bass_db) -> gleam@dynamic@decode:field( <<"treble_db"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Treble_db) -> gleam@dynamic@decode:field( <<"bass_cutoff_hz"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Bass_cutoff_hz) -> gleam@dynamic@decode:field( <<"treble_cutoff_hz"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Treble_cutoff_hz) -> gleam@dynamic@decode:success( {tone, Bass_db, Treble_db, Bass_cutoff_hz, Treble_cutoff_hz} ) end ) end ) end ) end ). -file("src/rockbox/player.gleam", 978). -spec eq_band_decoder() -> gleam@dynamic@decode:decoder(eq_band()). eq_band_decoder() -> gleam@dynamic@decode:field( <<"cutoff_hz"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Cutoff_hz) -> gleam@dynamic@decode:field( <<"q"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_float/1}, fun(Q) -> gleam@dynamic@decode:field( <<"gain_db"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_float/1}, fun(Gain_db) -> gleam@dynamic@decode:success( {eq_band, Cutoff_hz, Q, Gain_db} ) end ) end ) end ). -file("src/rockbox/player.gleam", 985). -spec equalizer_decoder() -> gleam@dynamic@decode:decoder(equalizer()). equalizer_decoder() -> gleam@dynamic@decode:field( <<"enabled"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_bool/1}, fun(Enabled) -> gleam@dynamic@decode:field( <<"precut_db"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_float/1}, fun(Precut_db) -> gleam@dynamic@decode:field( <<"bands"/utf8>>, gleam@dynamic@decode:list(eq_band_decoder()), fun(Bands) -> gleam@dynamic@decode:success( {equalizer, Enabled, Precut_db, Bands} ) end ) end ) end ). -file("src/rockbox/player.gleam", 1046). -spec dsp_settings_decoder() -> gleam@dynamic@decode:decoder(dsp_settings()). dsp_settings_decoder() -> gleam@dynamic@decode:field( <<"equalizer"/utf8>>, equalizer_decoder(), fun(Equalizer) -> gleam@dynamic@decode:field( <<"tone"/utf8>>, tone_decoder(), fun(Tone) -> gleam@dynamic@decode:field( <<"surround"/utf8>>, surround_decoder(), fun(Surround) -> gleam@dynamic@decode:field( <<"channel_mode"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Channel_mode) -> gleam@dynamic@decode:field( <<"stereo_width"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Stereo_width) -> gleam@dynamic@decode:field( <<"compressor"/utf8>>, compressor_decoder(), fun(Compressor) -> gleam@dynamic@decode:field( <<"dither"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_bool/1}, fun(Dither) -> gleam@dynamic@decode:field( <<"pitch"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Pitch) -> gleam@dynamic@decode:field( <<"crossfeed"/utf8>>, crossfeed_decoder( ), fun( Crossfeed ) -> gleam@dynamic@decode:field( <<"bass_enhancement"/utf8>>, bass_enhancement_decoder( ), fun( Bass_enhancement ) -> gleam@dynamic@decode:field( <<"fatigue_reduction"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun( Fatigue_reduction ) -> gleam@dynamic@decode:success( {dsp_settings, Equalizer, Tone, Surround, Channel_mode, Stereo_width, Compressor, Dither, Pitch, Crossfeed, Bass_enhancement, Fatigue_reduction} ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/rockbox/player.gleam", 814). ?DOC(" Read back the whole DSP chain state.\n"). -spec dsp_settings(player()) -> dsp_settings(). dsp_settings(Player) -> Settings@1 = case gleam@dynamic@decode:run( json:decode(rockbox_ffi_nif:player_dsp_settings_json(Player)), dsp_settings_decoder() ) of {ok, Settings} -> Settings; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"rockbox/player"/utf8>>, function => <<"dsp_settings"/utf8>>, line => 815, value => _assert_fail, start => 20214, 'end' => 20322, pattern_start => 20225, pattern_end => 20237}) end, Settings@1. -file("src/rockbox/player.gleam", 930). -spec resume_decoder() -> gleam@dynamic@decode:decoder(resume_state()). resume_decoder() -> gleam@dynamic@decode:field( <<"tracks"/utf8>>, gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_string/1} ), fun(Tracks) -> gleam@dynamic@decode:field( <<"index"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Index) -> gleam@dynamic@decode:field( <<"elapsed_ms"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Elapsed_ms) -> gleam@dynamic@decode:success( {resume_state, Tracks, Index, Elapsed_ms} ) end ) end ) end ). -file("src/rockbox/player.gleam", 908). -spec decode_resume(gleam@dynamic:dynamic_()) -> gleam@option:option(resume_state()). decode_resume(Value) -> case gleam@dynamic@decode:run( Value, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, Json} -> case gleam@dynamic@decode:run(json:decode(Json), resume_decoder()) of {ok, State} -> {some, State}; {error, _} -> none end; {error, _} -> none end. -file("src/rockbox/player.gleam", 824). ?DOC( " Restore the queue and exact position from the configured resume file (does\n" " NOT auto-play). `None` if there is nothing to resume.\n" ). -spec resume(player()) -> gleam@option:option(resume_state()). resume(Player) -> decode_resume(rockbox_ffi_nif:player_resume(Player)). -file("src/rockbox/player.gleam", 829). ?DOC(" Persist the current queue + position to the resume file right now.\n"). -spec save_resume(player()) -> player(). save_resume(Player) -> rockbox_ffi_nif:player_save_resume(Player), Player. -file("src/rockbox/player.gleam", 838). ?DOC(" Delete the resume file (forget the saved state).\n"). -spec clear_resume(player()) -> player(). clear_resume(Player) -> rockbox_ffi_nif:player_clear_resume(Player), Player. -file("src/rockbox/player.gleam", 847). ?DOC(" Peek at a resume file without a player. `None` if it is missing/unreadable.\n"). -spec load_resume(binary()) -> gleam@option:option(resume_state()). load_resume(Path) -> case gleam@dynamic@decode:run( rockbox_ffi_nif:load_resume_json(Path), {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, Json} -> decode_resume(gleam_stdlib:identity(Json)); {error, _} -> none end. -file("src/rockbox/player.gleam", 919). -spec decode_string_list(gleam@dynamic:dynamic_()) -> list(binary()). decode_string_list(Value) -> case gleam@dynamic@decode:run( Value, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, Json} -> case gleam@dynamic@decode:run( json:decode(Json), gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_string/1} ) ) of {ok, Paths} -> Paths; {error, _} -> [] end; {error, _} -> [] end. -file("src/rockbox/player.gleam", 858). ?DOC( " Import a playlist file into the queue at `position`; returns the imported\n" " paths.\n" ). -spec import_m3u(player(), binary(), insert_position()) -> list(binary()). import_m3u(Player, Path, Position) -> {Pos, Index} = insert_position_args(Position), decode_string_list( rockbox_ffi_nif:player_import_m3u(Player, Path, Pos, Index) ). -file("src/rockbox/player.gleam", 868). ?DOC(" Replace the queue with a playlist file; returns the loaded paths.\n"). -spec load_m3u(player(), binary()) -> list(binary()). load_m3u(Player, Path) -> decode_string_list(rockbox_ffi_nif:player_load_m3u(Player, Path)). -file("src/rockbox/player.gleam", 873). ?DOC(" Export the current queue to an `.m3u8` (atomic). `Ok(Nil)` / `Error(Nil)`.\n"). -spec export_m3u(player(), binary()) -> {ok, nil} | {error, nil}. export_m3u(Player, Path) -> case rockbox_ffi_nif:player_export_m3u(Player, Path) of 0 -> {ok, nil}; _ -> {error, nil} end. -file("src/rockbox/player.gleam", 948). -spec optional_string() -> gleam@dynamic@decode:decoder(gleam@option:option(binary())). optional_string() -> gleam@dynamic@decode:one_of( gleam@dynamic@decode:map( {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Field@0) -> {some, Field@0} end ), [gleam@dynamic@decode:success(none)] ). -file("src/rockbox/player.gleam", 944). -spec optional_int() -> gleam@dynamic@decode:decoder(gleam@option:option(integer())). optional_int() -> gleam@dynamic@decode:one_of( gleam@dynamic@decode:map( {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Field@0) -> {some, Field@0} end ), [gleam@dynamic@decode:success(none)] ). -file("src/rockbox/player.gleam", 937). -spec m3u_entry_decoder() -> gleam@dynamic@decode:decoder(m3u_entry()). m3u_entry_decoder() -> gleam@dynamic@decode:field( <<"path"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Path) -> gleam@dynamic@decode:field( <<"duration_ms"/utf8>>, optional_int(), fun(Duration_ms) -> gleam@dynamic@decode:field( <<"title"/utf8>>, optional_string(), fun(Title) -> gleam@dynamic@decode:success( {m3u_entry, Path, Duration_ms, Title} ) end ) end ) end ). -file("src/rockbox/player.gleam", 881). ?DOC(" Parse a playlist file into its entries. `Error(Nil)` if it cannot be read.\n"). -spec m3u_read(binary()) -> {ok, list(m3u_entry())} | {error, nil}. m3u_read(Path) -> case gleam@dynamic@decode:run( rockbox_ffi_nif:m3u_read_json(Path), {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, Json} -> case gleam@dynamic@decode:run( json:decode(Json), gleam@dynamic@decode:list(m3u_entry_decoder()) ) of {ok, Entries} -> {ok, Entries}; {error, _} -> {error, nil} end; {error, _} -> {error, nil} end. -file("src/rockbox/player.gleam", 893). ?DOC(" Write a list of paths as an `.m3u8`. `Ok(Nil)` / `Error(Nil)`.\n"). -spec m3u_write(binary(), list(binary())) -> {ok, nil} | {error, nil}. m3u_write(Path, Paths) -> case rockbox_ffi_nif:m3u_write_json( Path, erlang:iolist_to_binary(json:encode(Paths)) ) of 0 -> {ok, nil}; _ -> {error, nil} end. -file("src/rockbox/player.gleam", 902). ?DOC(" Whether a string looks like an http(s):// URL.\n"). -spec is_url(binary()) -> boolean(). is_url(S) -> rockbox_ffi_nif:is_url(S).