first commit
This commit is contained in:
74
docs/media/audio-ir/audio-ir-room-plugin-pool/README.md
Normal file
74
docs/media/audio-ir/audio-ir-room-plugin-pool/README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# @suaveplan/audio-ir-room-plugin-pool - Original audio-ir content package: ships the outdoor-swimming-pool room impulse response paired with a https CDN fallback. Universal.
|
||||
|
||||
Original audio-ir content package. Ships a single `room`-family
|
||||
impulse response — `pool-outdoor-swimming-pool` — sourced from the
|
||||
outdoor-swimming-pool capture in the Suaveplan internal media library,
|
||||
paired with a CDN fallback at `https://swch.b-cdn.net/_/audio/ir/room/roompool.wav`.
|
||||
|
||||
Universal; no browser, DOM, or Node-specific APIs in the public
|
||||
surface. The shipped bundle plugin uses `import.meta.url` to locate the
|
||||
in-tarball `files/` directory at runtime.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [manifest](./src/manifest/manifest.md) — Declares the lone `IrManifestEntry` shipped by `@suaveplan/audio-ir-room-plugin-pool`. The entry's `uri` is a `fallback…
|
||||
- [manifest](./src/manifest/manifest.md) — Declares the lone `IrManifestEntry` shipped by `@suaveplan/audio-ir-room-plugin-pool`. The entry's `uri` is a `fallback…
|
||||
- [register](./src/register/register.md) — Single entry point for plugging `@suaveplan/audio-ir-room-plugin-pool` into a consumer's `IrRegistry` + `StorageUriReso…
|
||||
- [register](./src/register/register.md) — Single entry point for plugging `@suaveplan/audio-ir-room-plugin-pool` into a consumer's `IrRegistry` + `StorageUriReso…
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Modules
|
||||
|
||||
- `./manifest` — `manifest: IrManifest`, plus the canonical constants
|
||||
(`BUNDLE_PACKAGE_SLUG`, `BUNDLE_URI`, `CDN_URI`, `ENTRY_ID`,
|
||||
`CHANNELS`, `SAMPLE_RATE`).
|
||||
- `./register` — `register(registry, target, options?)` and the
|
||||
re-exported `MutableUriPluginRegistrar` type (sourced from
|
||||
`@suaveplan/audio-ir-core`). Wires the bundle plugin onto a
|
||||
consumer-supplied registrar and calls `registerManifest`.
|
||||
|
||||
## Quick start
|
||||
|
||||
```ts
|
||||
import {
|
||||
createIrRegistry,
|
||||
createUriPluginCollector,
|
||||
} from "@suaveplan/audio-ir-core";
|
||||
import { createIrLoader } from "@suaveplan/audio-ir-loader";
|
||||
import { decodeWav } from "@suaveplan/audio-decode-wav";
|
||||
import { createStorageUriResolver } from "@suaveplan/storage-uri";
|
||||
import { fallbackUriPlugin } from "@suaveplan/storage-uri-plugin-fallback";
|
||||
import { register } from "@suaveplan/audio-ir-room-plugin-pool";
|
||||
|
||||
const registry = createIrRegistry();
|
||||
const collector = createUriPluginCollector();
|
||||
register(registry, collector);
|
||||
|
||||
// Append the consumer's https://-aware plugin via collector.use(...).
|
||||
const innerPlugins = [...collector.plugins];
|
||||
const innerResolver = createStorageUriResolver(innerPlugins);
|
||||
const fb = fallbackUriPlugin({
|
||||
resolver: innerResolver,
|
||||
policy: { errorClass: "any" },
|
||||
});
|
||||
const resolver = createStorageUriResolver([...innerPlugins, fb]);
|
||||
|
||||
const loader = createIrLoader({
|
||||
registry,
|
||||
resolver,
|
||||
decoders: { wav: decodeWav },
|
||||
});
|
||||
const ir = await loader.load("pool-outdoor-swimming-pool");
|
||||
```
|
||||
|
||||
## License & sources
|
||||
|
||||
The bundled WAV (`files/outdoor-swimming-pool.wav`) was copied from the
|
||||
Suaveplan internal media library at
|
||||
`/mnt/c/Users/Administrator/Mountain Duck/74a17879-9780-426d-8bd9-7ed805f53d41/media/_/audio/ir/room/outdoor-swimming-pool.wav`.
|
||||
The CDN copy lives at `https://swch.b-cdn.net/_/audio/ir/room/roompool.wav`.
|
||||
|
||||
License: **All Rights Reserved — Suaveplan internal media library**. Do
|
||||
not redistribute the bundled WAV outside Suaveplan distributions.
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
# `manifest` — single-entry `IrManifest` for the outdoor-swimming-pool IR
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Declares the lone `IrManifestEntry` shipped by `@suaveplan/audio-ir-room-plugin-pool`.
|
||||
The entry's `uri` is a `fallback://?u=<bundle>&u=<https>` URI built at module
|
||||
load by `buildFallbackUri` from `@suaveplan/storage-uri-plugin-fallback` —
|
||||
when the consuming resolver has both a `bundle://` plugin and an `https://`
|
||||
plugin wired, the shipped `fallback://` walk hits the in-package WAV first
|
||||
and only reaches for the CDN copy when the local file is absent.
|
||||
|
||||
The manifest also pins the **decoded** `channels` and `sampleRate` of the
|
||||
bundled WAV (`channels = 1`, `sampleRate = 48000`) so the loader's
|
||||
`validateAndFinalize` step can reject any subsequent re-encode that drifts
|
||||
from those values. Both numbers were obtained by feeding
|
||||
`files/outdoor-swimming-pool.wav` through `decodeWav` once at
|
||||
manifest-authoring time.
|
||||
|
||||
## Features
|
||||
|
||||
- Round-trips through `IrManifestSchema` at module load — any drift in the
|
||||
schema fails the build before `dist/` is emitted.
|
||||
- `BUNDLE_PACKAGE_SLUG`, `BUNDLE_URI`, `CDN_URI`, `ENTRY_ID`, `CHANNELS`,
|
||||
`SAMPLE_RATE` exported as named `const` literals so consumers can refer
|
||||
to them without re-deriving from `manifest.entries[0]`.
|
||||
- Frozen at runtime (`IrManifestSchema` applies `Object.freeze` to the
|
||||
parsed manifest + every entry).
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { manifest } from "@suaveplan/audio-ir-room-plugin-pool/manifest";
|
||||
|
||||
console.log(manifest.packageSlug); // "pool"
|
||||
console.log(manifest.entries[0].id); // "pool-outdoor-swimming-pool"
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
BUNDLE_URI,
|
||||
CDN_URI,
|
||||
ENTRY_ID,
|
||||
manifest,
|
||||
} from "@suaveplan/audio-ir-room-plugin-pool/manifest";
|
||||
import { parseFallbackUri } from "@suaveplan/storage-uri-plugin-fallback";
|
||||
|
||||
const entry = manifest.entries[0];
|
||||
const parsed = parseFallbackUri(entry.uri);
|
||||
console.log(parsed.candidates); // [BUNDLE_URI, CDN_URI]
|
||||
console.log(entry.id === ENTRY_ID); // true
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| --- | --- | --- |
|
||||
| `manifest` | `IrManifest` | Frozen single-entry manifest. |
|
||||
| `BUNDLE_PACKAGE_SLUG` | `"audio-ir-room-plugin-pool"` | Slug expected by the bundle plugin. |
|
||||
| `BUNDLE_URI` | string literal | Bundle-local URI for the WAV. |
|
||||
| `CDN_URI` | string literal | HTTPS CDN URI for the WAV. |
|
||||
| `ENTRY_ID` | `"pool-outdoor-swimming-pool"` | Entry id within the registry. |
|
||||
| `CHANNELS` | `1` | Decoded channel count of the WAV. |
|
||||
| `SAMPLE_RATE` | `48000` | Decoded sample rate of the WAV (Hz). |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The manifest constants are NOT optional — the spec for this package
|
||||
requires them to equal the values measured by decoding
|
||||
`files/outdoor-swimming-pool.wav` at authoring time. If the bundled WAV is
|
||||
ever re-mastered, both `CHANNELS` and `SAMPLE_RATE` MUST be updated to
|
||||
match the new decode result, and the file-presence integration test
|
||||
SHOULD re-run as part of that change to assert the new constants.
|
||||
|
||||
`buildFallbackUri([BUNDLE_URI, CDN_URI])` runs at module load. The
|
||||
ordering of candidates IS the failover policy — bundle wins when present,
|
||||
CDN wins when bundle reports `BUNDLE_URI.NOT_FOUND`. Reversing the array
|
||||
would silently flip that policy without a separate spec change, so the
|
||||
constants are kept verbose and explicit rather than inlined.
|
||||
|
||||
The `license` field intentionally says "All Rights Reserved — Suaveplan
|
||||
internal media library" because the source media library has no public
|
||||
license attached. Consumers SHOULD NOT redistribute the bundled WAV
|
||||
outside the Suaveplan distribution.
|
||||
@@ -0,0 +1,124 @@
|
||||
# `register` — install bundle plugin + register manifest
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Single entry point for plugging `@suaveplan/audio-ir-room-plugin-pool` into a
|
||||
consumer's `IrRegistry` + `StorageUriResolver` composition. Constructs the
|
||||
package-scoped `bundleUriPlugin` (rooted at the in-package `files/`
|
||||
directory via `import.meta.url`) and hands it to a `MutableUriPluginRegistrar`,
|
||||
then calls `registerManifest(registry, manifest)` so the lone
|
||||
`pool-outdoor-swimming-pool` entry is reachable via `registry.get(id)`.
|
||||
|
||||
The `MutableUriPluginRegistrar` shape is the canonical collector interface
|
||||
shipped by `@suaveplan/audio-ir-core` — see that package's
|
||||
`registrar/registrar.md` for the type definition and the
|
||||
`createUriPluginCollector()` factory every consumer should reach for
|
||||
first. This package only consumes the interface; it does NOT redeclare it.
|
||||
|
||||
The helper deliberately does NOT install the `fallback://` plugin or any
|
||||
`https://` plugin. Both are resolver-composition concerns the consumer
|
||||
owns once per resolver (the `fallback://` plugin is stateful across
|
||||
candidates; sharing a single instance keeps the per-candidate counter
|
||||
attribution consistent across every content package that uses it).
|
||||
|
||||
## Features
|
||||
|
||||
- One call wires both the bundle adapter and the manifest registration.
|
||||
- Uses `import.meta.url` to locate `files/` — works in both Node and any
|
||||
modern bundler that preserves package URLs.
|
||||
- No fallback plugin registration — single-responsibility wrt content.
|
||||
- `target` is typed against the foundation's `MutableUriPluginRegistrar`
|
||||
so a single shape works across every `audio-ir-{family}-plugin-<name>`
|
||||
content package.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
createIrRegistry,
|
||||
createUriPluginCollector,
|
||||
} from "@suaveplan/audio-ir-core";
|
||||
import { createStorageUriResolver } from "@suaveplan/storage-uri";
|
||||
import { register } from "@suaveplan/audio-ir-room-plugin-pool/register";
|
||||
|
||||
const registry = createIrRegistry();
|
||||
const collector = createUriPluginCollector();
|
||||
register(registry, collector);
|
||||
|
||||
const resolver = createStorageUriResolver(collector.plugins);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Compose multiple content packages into a single resolver, then wrap an
|
||||
HTTPS-aware plugin and the shared `fallbackUriPlugin` on top:
|
||||
|
||||
```ts
|
||||
import {
|
||||
createIrRegistry,
|
||||
createUriPluginCollector,
|
||||
} from "@suaveplan/audio-ir-core";
|
||||
import { createIrLoader } from "@suaveplan/audio-ir-loader";
|
||||
import { decodeWav } from "@suaveplan/audio-decode-wav";
|
||||
import { createStorageUriResolver } from "@suaveplan/storage-uri";
|
||||
import { fallbackUriPlugin } from "@suaveplan/storage-uri-plugin-fallback";
|
||||
import { register } from "@suaveplan/audio-ir-room-plugin-pool/register";
|
||||
|
||||
const registry = createIrRegistry();
|
||||
const collector = createUriPluginCollector();
|
||||
register(registry, collector);
|
||||
|
||||
// Append the consumer's https://-aware plugin.
|
||||
const innerPlugins = [...collector.plugins, myHttpsPlugin];
|
||||
const innerResolver = createStorageUriResolver(innerPlugins);
|
||||
const outerResolver = createStorageUriResolver([
|
||||
...innerPlugins,
|
||||
fallbackUriPlugin({ resolver: innerResolver, policy: { errorClass: "any" } }),
|
||||
]);
|
||||
|
||||
const loader = createIrLoader({
|
||||
registry,
|
||||
resolver: outerResolver,
|
||||
decoders: { wav: decodeWav },
|
||||
});
|
||||
const ir = await loader.load("pool-outdoor-swimming-pool");
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| --- | --- | --- |
|
||||
| `register(registry, target, options?)` | function | Wire the bundle plugin into `target` and register the manifest into `registry`. |
|
||||
| `RegisterOptions` | interface | Optional `{ fetch?: FetchLike }` override for the bundle adapter (use `nodeFileFetch` under Node). |
|
||||
| `MutableUriPluginRegistrar` | type | Re-exported from `@suaveplan/audio-ir-core`. Canonical `{ use(plugin: UriPlugin): void }` collector shape. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`new URL("../../files/", import.meta.url)` is intentional — the
|
||||
`manifest/manifest.ts` file lives at `src/manifest/manifest.ts` in the
|
||||
source tree, and at `dist/manifest/manifest.js` after build. In both
|
||||
cases the relative climb two levels up from the file's URL lands on the
|
||||
package root, where `files/` lives at the same level as `dist/` and
|
||||
`src/`. The trailing slash is required by `bundleUriPlugin` — it
|
||||
rejects `rootUrl` values whose pathname does not end with `/`.
|
||||
|
||||
The bundle plugin's `packageSlug` is `"audio-ir-room-plugin-pool"`,
|
||||
which matches the `bundle://audio-ir-room-plugin-pool/...` authority in
|
||||
the manifest's URI. Mismatch would surface as `BUNDLE_URI.INVALID_URI`
|
||||
at first dispatch, not at registration — so the manifest's bundle URI
|
||||
and `BUNDLE_PACKAGE_SLUG` are both exported from `manifest.ts` as
|
||||
single-source-of-truth constants.
|
||||
|
||||
The helper does NOT clear or re-init the registry. Repeated calls
|
||||
against the same registry will fail on `AUDIO_IR.DUPLICATE_ID` from
|
||||
`registerManifest`, which is the desired behaviour — content packages
|
||||
should install exactly once per process.
|
||||
|
||||
`MutableUriPluginRegistrar` is no longer declared locally; the type is
|
||||
imported from `@suaveplan/audio-ir-core` so every content package
|
||||
targets exactly one shape. The function body is unchanged across the
|
||||
type-only switch.
|
||||
Reference in New Issue
Block a user