# `Rockbox.Player`
[🔗](https://github.com/tsirysndr/rockboxd/blob/master/bindings/elixir/lib/rockbox/player.ex#L1)

Queue-based player with native ReplayGain and Rockbox crossfade.

A player owns a live audio output device and a background engine thread, so
it only works where an output device exists. The handle is a NIF resource,
freed by the BEAM garbage collector (which stops playback).

ReplayGain `mode` here uses the *player* values: `0` off, `1` track,
`2` album. Crossfade `mode`: `0` off, `1` auto-skip, `2` manual-skip,
`3` shuffle, `4` shuffle-or-manual, `5` always. Mix mode: `0` crossfade,
`1` mix.

## Piping

Every mutating/command function returns the player handle, so calls chain:

    p
    |> Player.set_queue(tracks)
    |> Player.set_shuffle(true)
    |> Player.set_repeat(:all)
    |> Player.play()

Getters/queries (`status/1`, `volume/1`, `queue/1`, `repeat/1`,
`dsp_settings/1`, `resume/1`, …) still return their values.

# `t`

```elixir
@opaque t()
```

Opaque player handle (a NIF resource).

# `balance`

```elixir
@spec balance(t()) :: integer()
```

Current stereo balance, `-100` (full left) to `+100` (full right).

# `clear_queue`

```elixir
@spec clear_queue(t()) :: t()
```

Empty the queue and stop playback (also clears any saved resume state).

# `clear_resume`

```elixir
@spec clear_resume(t()) :: t()
```

Delete the resume file (forget the saved state). Returns the player handle.

# `dsp_settings`

```elixir
@spec dsp_settings(t()) :: map()
```

The full DSP-chain state as an atom-keyed map.

# `enqueue`

```elixir
@spec enqueue(t(), Path.t()) :: t()
```

Append one track to the queue. `path` may be a local file path, an
`http(s)://` URL to a finite remote file, or a live-radio / streaming URL.

# `eq_enabled?`

```elixir
@spec eq_enabled?(t()) :: boolean()
```

Whether the equalizer is currently enabled.

# `export_m3u`

```elixir
@spec export_m3u(t(), Path.t()) :: :ok | {:error, :export_failed}
```

Export the current queue to an .m3u8 file (atomic write).

# `import_m3u`

```elixir
@spec import_m3u(t(), Path.t(), Rockbox.InsertPosition.t() | 0..7, non_neg_integer()) ::
  {:ok, [String.t()]} | {:error, term()}
```

Import an .m3u/.m3u8 playlist into the queue at `position`.

Returns `{:ok, [path, ...]}` with the imported entries, or `{:error, reason}`.
`index` is only used when `position` is `:index` (7).

# `insert`

```elixir
@spec insert(t(), [Path.t()], Rockbox.InsertPosition.t() | 0..7, non_neg_integer()) ::
  t()
```

Insert file paths / URLs into the queue at `position`.

`position` is a `Rockbox.InsertPosition` atom (or its integer code); `index`
is only used when `position` is `:index` (7).

# `load_m3u`

```elixir
@spec load_m3u(t(), Path.t()) :: {:ok, [String.t()]} | {:error, term()}
```

Replace the queue with an .m3u/.m3u8 playlist file.

Returns `{:ok, [path, ...]}` with the loaded entries, or `{:error, reason}`.

# `new`

```elixir
@spec new() :: t() | nil
```

Create a player on the default device with default settings.

# `new`

```elixir
@spec new(keyword() | map()) :: t() | nil
```

Create a player with configuration overrides (see `@default_config` keys).
`sample_rate: 0` means the device default.

Pass `resume_file: "/path/to/state.m3u8"` (optionally with
`resume_save_interval_ms:`) to enable automatic queue+position persistence;
restore it later with `resume/1`.

# `next`

```elixir
@spec next(t()) :: t()
```

# `pause`

```elixir
@spec pause(t()) :: t()
```

# `play`

```elixir
@spec play(t()) :: t()
```

# `previous`

```elixir
@spec previous(t()) :: t()
```

# `queue`

```elixir
@spec queue(t()) :: [String.t()]
```

The current queue as a list of path/URL strings.

# `remove`

```elixir
@spec remove(t(), non_neg_integer()) :: t()
```

Remove the track at zero-based `index` from the queue. An out-of-range index
is ignored. Removing a track before the current one keeps the current track
playing; removing the currently-playing track hard-cuts to the track that
slides into its place; removing the last remaining track stops playback.

# `repeat`

```elixir
@spec repeat(t()) :: Rockbox.RepeatMode.t()
```

The current repeat mode as a `Rockbox.RepeatMode` atom (`:off`/`:one`/`:all`).

# `resume`

```elixir
@spec resume(t()) :: {:ok, map()} | {:error, :absent}
```

Restore the queue + exact position from the player's resume file (does NOT
auto-play). Returns `{:ok, %{tracks: [...], index: i, elapsed_ms: ms}}` or
`{:error, :absent}` when there is nothing to resume.

# `sample_rate`

```elixir
@spec sample_rate(t()) :: non_neg_integer()
```

# `save_resume`

```elixir
@spec save_resume(t()) :: t()
```

Persist the queue + exact position to the resume file now. Returns the player handle.

# `seek_ms`

```elixir
@spec seek_ms(t(), non_neg_integer()) :: t()
```

# `set_balance`

```elixir
@spec set_balance(t(), integer()) :: t()
```

Set the stereo balance, `-100` (full left) to `+100` (full right); `0` is
centred.

# `set_bass`

```elixir
@spec set_bass(t(), integer()) :: t()
```

Set the bass tone axis in dB, leaving treble and cutoffs unchanged.

# `set_bass_cutoff`

```elixir
@spec set_bass_cutoff(t(), integer()) :: t()
```

Override the bass tone shelf cutoff in Hz (`0` = native default); gains unchanged.

# `set_bass_enhancement`

```elixir
@spec set_bass_enhancement(t(), integer(), integer()) :: t()
```

Perceptual bass enhancement. `strength` is a percentage (`0` = off); `precut`
is in tenths of a dB (`<= 0`).

# `set_channel_mode`

```elixir
@spec set_channel_mode(t(), Rockbox.ChannelMode.t() | 0..6) :: t()
```

Channel mixing mode. Accepts a `Rockbox.ChannelMode` atom (e.g. `:mono`) or
its integer code.

# `set_compressor`

```elixir
@spec set_compressor(
  t(),
  integer(),
  integer(),
  integer(),
  integer(),
  integer(),
  integer()
) :: t()
```

Dynamic-range compressor. `threshold_db` `0` disables it; the remaining
arguments are makeup gain, ratio, knee, attack (ms) and release (ms).

# `set_crossfade`

```elixir
@spec set_crossfade(t(), 0..5, integer(), integer(), integer(), integer(), 0..1) ::
  t()
```

# `set_crossfeed`

```elixir
@spec set_crossfeed(
  t(),
  Rockbox.CrossfeedMode.t() | 0..2,
  integer(),
  integer(),
  integer(),
  integer()
) :: t()
```

Headphone crossfeed. `mode` accepts a `Rockbox.CrossfeedMode` atom (`:off`,
`:meier`, `:custom`) or its integer code.

`direct_gain`, `cross_gain` and `hf_gain` are in tenths of a dB (`<= 0`);
`hf_cutoff_hz` is in Hz. The cross/high-frequency parameters only apply in
`:custom` mode.

# `set_dither`

```elixir
@spec set_dither(t(), boolean()) :: t()
```

Enable or disable output dithering + noise shaping.

# `set_eq_band`

```elixir
@spec set_eq_band(t(), 0..10, integer(), number(), number()) :: t()
```

Configure one EQ band (0..10). `cutoff_hz` in Hz, `q` a Q factor, `gain_db`
in dB.

# `set_eq_enabled`

```elixir
@spec set_eq_enabled(t(), boolean()) :: t()
```

Enable or disable the 10-band parametric equalizer.

# `set_eq_precut`

```elixir
@spec set_eq_precut(t(), number()) :: t()
```

Global EQ pre-cut in dB (attenuation applied before the bands).

# `set_eq_preset`

```elixir
@spec set_eq_preset(t(), Rockbox.EqPreset.t() | 0..20) :: t()
```

Apply a built-in EQ preset. Accepts a `Rockbox.EqPreset` atom (e.g. `:rock`)
or its integer code.

# `set_fatigue_reduction`

```elixir
@spec set_fatigue_reduction(t(), 0..3) :: t()
```

Auditory fatigue reduction: `0` off, `1` weak, `2` moderate, `3` strong.

# `set_pitch`

```elixir
@spec set_pitch(t(), integer()) :: t()
```

Pitch/speed ratio (`10000` = normal); pitch and tempo shift together.

# `set_queue`

```elixir
@spec set_queue(t(), [Path.t()]) :: t()
```

Replace the queue. Each entry may be a local file path, an `http(s)://`
URL to a finite remote file, or a live-radio / streaming URL.

# `set_repeat`

```elixir
@spec set_repeat(t(), Rockbox.RepeatMode.t() | 0..2) :: t()
```

Set the repeat mode. Accepts a `Rockbox.RepeatMode` atom (`:off`, `:one`,
`:all`) or its integer code (`0`, `1`, `2`).

# `set_replaygain`

```elixir
@spec set_replaygain(t(), 0..2, number(), boolean()) :: t()
```

# `set_shuffle`

```elixir
@spec set_shuffle(t(), boolean()) :: t()
```

Enable or disable shuffle playback.

# `set_stereo_width`

```elixir
@spec set_stereo_width(t(), integer()) :: t()
```

Custom stereo width in percent (audible with channel mode `:custom`).

# `set_surround`

```elixir
@spec set_surround(t(), integer(), integer(), integer(), integer()) :: t()
```

Haas surround effect: `delay_ms` (`0` = off), `balance` %, and the band-split
cutoffs in Hz.

# `set_tone`

```elixir
@spec set_tone(t(), integer(), integer(), integer(), integer()) :: t()
```

Bass/treble tone controls in dB, with band-split cutoffs in Hz (`0` = the
native defaults).

# `set_treble`

```elixir
@spec set_treble(t(), integer()) :: t()
```

Set the treble tone axis in dB, leaving bass and cutoffs unchanged.

# `set_treble_cutoff`

```elixir
@spec set_treble_cutoff(t(), integer()) :: t()
```

Override the treble tone shelf cutoff in Hz (`0` = native default); gains unchanged.

# `set_volume`

```elixir
@spec set_volume(t(), number()) :: t()
```

# `shuffle_enabled?`

```elixir
@spec shuffle_enabled?(t()) :: boolean()
```

Whether shuffle playback is currently enabled.

# `skip_to`

```elixir
@spec skip_to(t(), non_neg_integer()) :: t()
```

# `status`

```elixir
@spec status(t()) :: map()
```

A snapshot of the player's status as an atom-keyed map.

# `stop`

```elixir
@spec stop(t()) :: t()
```

# `toggle`

```elixir
@spec toggle(t()) :: t()
```

# `volume`

```elixir
@spec volume(t()) :: float()
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
