# `TuningFork.Wav`
[🔗](https://github.com/jaman/tuning_fork/blob/v0.1.11/tuning_fork/lib/tuning_fork/wav.ex#L1)

16-bit little-endian PCM wrapped in a WAV header, and read back out of one.

    TuningFork.Wav.encode(pcm, rate: 44_100)

# `decode`

```elixir
@spec decode(binary()) ::
  {:ok, binary(), pos_integer(), pos_integer()} | {:error, term()}
```

Read a WAV, as `{:ok, pcm, rate, channels}`, with `pcm` as 16-bit signed samples whatever
the file holds: 8-bit unsigned, 16-, 24- and 32-bit integers and 32-bit floats are read,
plain or under an extensible header, and floats outside -1.0..1.0 are clipped.

Chunks other than `fmt ` and `data` are skipped. Fails with `{:error, :not_a_wav}`,
`{:error, :no_format_chunk}`, `{:error, :no_data_chunk}`, `{:error, :truncated}` or
`{:error, {:unsupported_bit_depth, bits}}`. A file cut short after both `fmt ` and `data`
have been read is not `:truncated`.

# `decode!`

```elixir
@spec decode!(binary()) :: {binary(), pos_integer(), pos_integer()}
```

Read a WAV, as `{pcm, rate, channels}`.

Raises `ArgumentError` where `decode/1` would report an error.

# `duration`

```elixir
@spec duration(binary(), pos_integer(), pos_integer()) :: float()
```

How long a 16-bit PCM buffer lasts, in seconds.

`rate` and `channels` must be the ones the buffer was rendered at.

# `encode`

```elixir
@spec encode(binary(), keyword()) :: binary()
```

Wrap PCM in a WAV header.

## Options

  * `:rate` — samples per second, default 44100
  * `:channels` — samples per frame, default 2

Both must be what the PCM was rendered at.

# `read!`

```elixir
@spec read!(Path.t()) :: {binary(), pos_integer(), pos_integer()}
```

Read a WAV file, as `{pcm, rate, channels}`. Raises as `decode!/1` does.

# `write!`

```elixir
@spec write!(Path.t(), binary(), keyword()) :: :ok
```

Write PCM to `path` as a WAV, creating the directory if it is not there.

`opts` are `encode/2`'s options.

---

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