first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
# `encode/encode-to`
Universal encode entry point — encode an `AudioDocument` to bytes and
write them to any `Destination` (file path, WritableStream, or
callback).
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`encodeTo` is the top-level public-facing encode API. Callers do not
need to wire codec dispatch + destination plumbing manually — they
pass in a document, a format name, and a destination handle, and the
function takes care of routing through `CodecRegistry.encode` and
then writing the resulting bytes to the destination via the
appropriate platform call.
## Features
- Accepts three `Destination` variants:
- `string` file path → resolved via dynamic
`import('node:fs/promises')` for `writeFile`. Runtime-gated so
the import never appears statically.
- `WritableStream<Uint8Array>` → write via the stream's writer,
closes the stream after writing.
- `(chunk: Uint8Array) => void` callback → single invocation with
the full payload.
- Optional `opts.format: "pcm" | "float"` and `opts.bitDepth: 8 | 16
| 24 | 32` for codecs that support multiple sample formats (WAV).
- Optional `opts.sampleRate` override — used when the encode pipeline
needs to retarget a different rate than the document's natural
rate.
- Optional `opts.signal` (AbortSignal) — checked before encode
dispatch. Pre-aborted signals throw `AUDIO_CODECS.STREAM_ERROR`.
- Optional `opts.registry` to inject a pre-configured registry.
Defaults to a fresh `CodecRegistry()` — callers that need WAV/AIFF/
CAF or WASM codecs available should pass in the registry from
`decode-source.ts` or construct one with the codecs they need.
- Zod-validated options — invalid `sampleRate`/`bitDepth`/`format`
throws `AUDIO_CODECS.INVALID_SOURCE`.
- Encoder errors are wrapped — codec-specific failures surface as
`AUDIO_CODECS.ENCODE_FAILED` with the original error on `cause`.
- Invalid destination (not a path/stream/callback) throws
`AUDIO_CODECS.INVALID_SOURCE`.
## Usage: Basic Example
```ts
import { CodecRegistry, encodeTo, WavCodec } from "@suaveplan/audio-codecs";
const registry = new CodecRegistry({ codecs: [WavCodec] });
await encodeTo(doc, "/tmp/out.wav", "wav", {
registry,
bitDepth: 16,
format: "pcm",
});
```
## Usage: Advanced Example
Encode to a streaming destination (e.g. an HTTP response body) with
abort cancellation:
```ts
import { CodecRegistry, encodeTo, WavCodec } from "@suaveplan/audio-codecs";
const registry = new CodecRegistry({ codecs: [WavCodec] });
const ctrl = new AbortController();
const responseStream = new WritableStream<Uint8Array>({
write(chunk) {
sendOverWebSocket(chunk);
},
});
await encodeTo(doc, responseStream, "wav", {
registry,
bitDepth: 24,
format: "pcm",
signal: ctrl.signal,
});
// Or write via callback for fine-grained control:
let captured: Uint8Array | undefined;
await encodeTo(doc, (chunk) => { captured = chunk; }, "wav", { registry });
```
## API Reference
- `type Destination = string | WritableStream<Uint8Array> | ((chunk: Uint8Array) => void)`
- `interface EncodeToOpts { sampleRate?, bitDepth?, format?, signal?, registry? }`
- `const EncodeToOptsSchema` — Zod schema validating
`sampleRate`, `bitDepth`, and `format`.
- `async function encodeTo(doc: AudioDocument, destination: Destination,
format: string, opts?: EncodeToOpts): Promise<void>` — throws
`INVALID_SOURCE` for invalid options or unrecognised destination,
`STREAM_ERROR` for pre-aborted signals, `NOT_SUPPORTED` for unknown
formats, `ENCODE_FAILED` for codec errors.
## Implementation Notes
- The file-path destination uses dynamic `import('node:fs/promises')`
to keep the package universal. Browser callers must use the
`WritableStream` or callback destination — passing a string path
in a browser would fail with `INVALID_SOURCE` via the dynamic
import failure, which then surfaces as `INVALID_SOURCE` at the
outer boundary.
- The `WritableStream` path acquires a writer, writes one chunk, then
closes via `writer.close()`. Callers that need to keep the stream
open for additional writes should use a callback destination
instead — the closed-after-one-write semantics matches the
single-payload encode model.
- The callback destination receives the full encoded buffer in one
invocation. For per-chunk encode (where bytes arrive as encoding
progresses), use `CodecRegistry.encodeStream` directly instead of
`encodeTo`.
- Codec error wrapping preserves the original via `cause`; callers
can recover the underlying error via
`(err as AudioCodecsError).cause`.
- `opts.signal` is checked only before dispatch — codec internal
abort during encode requires the codec to honour the signal,
which most current codecs (WAV native, WASM wrappers) do not.
Mid-encode cancellation will not interrupt the codec call but
will surface as a thrown `STREAM_ERROR` from any subsequent
`encodeTo` call against the same controller.