audio-codec-bsd 0.1.1

FLAC/PCM/WAV multi-format audio container decoder (symphonia + hound, pure Rust) emitting planar audio-core-bsd AudioFrames
Documentation
# audio-codec-bsd

[![License: BSD-2-Clause](https://img.shields.io/badge/license-BSD--2--Clause-blue.svg)](./LICENSE)
[![Rust](https://img.shields.io/badge/rust-1.85%2B-orange.svg)](https://www.rust-lang.org)

A multi-format audio container decoder that decodes **FLAC**, **PCM**, and
**WAV** files into planar `AudioFrame`s (from the `audio-core-bsd`
dependency). It is a pure-Rust, worker-thread codec: file I/O and heap
allocation happen here, never on a real-time audio thread.

> The doc comments on each public item are the primary reference. This README is
> an overview only.

## Overview

`audio-codec-bsd` reads compressed and uncompressed audio containers and emits
planar frames (one contiguous slice per channel) ready to feed an audio graph or
ring buffer. It is deliberately **not real-time safe**: decoding runs on a worker
thread, and decoded frames are handed off to the RT thread through a lock-free
channel.

### Supported formats

| Format | Container                    | Backend                             |
|--------|------------------------------|-------------------------------------|
| FLAC   | lossless compressed          | `symphonia` (MPL-2.0, pure Rust)    |
| WAV    | RIFF PCM / IEEE-float        | `hound` (Apache-2.0/MIT, pure Rust) |
| PCM    | raw headerless little-endian | planned                             |

Both `WavDecoder` (hound) and `SymphoniaDecoder` (symphonia) are implemented.
The [`open`] factory sniffs the leading magic bytes and returns the matching
decoder, so callers do not need to know the format ahead of time.

## Core types

| Type              | Description                                                                          |
|-------------------|--------------------------------------------------------------------------------------|
| `ContainerDecoder` | The public trait: `open()` a path, then iterate `next_frame()` → planar `AudioFrame`. |
| `StreamInfo`       | Stream metadata populated at open time (format / rate / channels / bit depth / length). |
| `FormatKind`       | Supported container: `Flac`, `Wav`, `Pcm`.                                           |
| `CodecError`       | Error enum (thiserror-backed): `Io`, `Format`, `Decode`, `Eof`, …                    |
| `Result<T>`        | Alias for `core::result::Result<T, CodecError>`.                                     |

## Dependencies

| Dependency       | Version | Purpose                                          | License           |
|------------------|---------|--------------------------------------------------|-------------------|
| `audio-core-bsd` | 0.1.0   | `AudioFrame` output type                         | BSD-2-Clause      |
| `thiserror`      | 2.0     | `CodecError` derive                              | MIT OR Apache-2.0 |
| `hound`          | 3.5     | WAV / RIFF PCM + IEEE-float decode (`WavDecoder`) | Apache-2.0/MIT    |
| `symphonia`      | 0.6     | FLAC + PCM container decode (`SymphoniaDecoder`)  | MPL-2.0           |
| `proptest` (dev) | 1.11.0  | property tests                                   | MIT OR Apache-2.0 |

> `symphonia` is **MPL-2.0**. MPL-2.0 permits static/dynamic linking from a
> BSD-2-Clause crate without copyleft contamination, provided that any *modified*
> symphonia source files are republished under MPL-2.0. Unmodified use (the
> default) imposes only a notice obligation.

## Status

**0.x — experimental.** The API is not yet frozen. WAV and FLAC decode are
implemented; raw headerless PCM is planned.

- edition: 2021
- MSRV: 1.85
- license: BSD-2-Clause

## Example

Open a container by magic-byte sniffing and drain it frame by frame into planar
`AudioFrame`s:

```rust,no_run
use audio_codec_bsd::open;
use std::path::Path;

let mut dec = open(Path::new("song.flac"))?;
let _info = dec.open(Path::new("song.flac"))?;
while let Some(_frame) = dec.next_frame()? {
    // push _frame into a lock-free ring for the RT thread.
}
# Ok::<(), audio_codec_bsd::CodecError>(())
```

## Worker-thread safety boundary

`ContainerDecoder` is **not** real-time safe. Implementations perform file I/O
and heap allocation — that is correct and intended. Decoded frames must be
handed to a lock-free ring buffer or similar channel so the RT audio thread
never blocks on or directly calls into this crate.

## License

BSD-2-Clause. See [`LICENSE`](./LICENSE).