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,67 @@
# parameters
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Declares the parameter surface the `SpessaSynthPlugin` exposes to the host chain: 16 GM channels × 5 controls (`volume`, `pan`, `program`, `reverbSend`, `chorusSend`) plus a master gain, for a total of 81 parameters. Each is described as a `PluginParameter` from `@suaveplan/audio-fx-plugin-base` so the host chain's automation lanes, parameter-curve scheduler, and preset snapshot machinery treat them uniformly with every other plugin in the chain.
Parameter ids follow the deterministic `channel/<n>/<kind>` pattern (and the singleton `master/gain`) so external systems — control surfaces, OSC bridges, MIDI-learn UIs — can address any control by literal string without consulting a runtime registry.
## Features
- `buildParameterDeclarations()` — emits 81 `PluginParameter` records in deterministic order.
- `channelParameterId(channel, kind)` / `parseChannelParameterId(id)` — symmetric id encode / decode.
- `assertChannel(channel)` — throws `SPESSASYNTH.INVALID_CHANNEL` for non-integer or out-of-range channels.
- `CHANNEL_COUNT`, `CHANNEL_PARAM_KINDS`, `MASTER_GAIN_ID` — closed-enum constants.
- All ratios use `[0, 1]` for sends and volume, `[-1, 1]` for pan, `[0, 127]` for program selection, `[0, 4]` for master gain.
- Every parameter except `program` is marked `automatable: true` (program-change is a discrete enum jump and shouldn't be interpolated).
## Usage: Basic
```ts
import {
buildParameterDeclarations,
channelParameterId,
} from "@suaveplan/audio-fx-plugin-spessasynth/parameters";
const parameters = buildParameterDeclarations();
console.log(channelParameterId(0, "volume")); // "channel/0/volume"
```
## Usage: Advanced
```ts
import {
parseChannelParameterId,
MASTER_GAIN_ID,
assertChannel,
} from "@suaveplan/audio-fx-plugin-spessasynth/parameters";
function applyAutomation(id: string, value: number) {
if (id === MASTER_GAIN_ID) {
processor.setMasterGain(value);
return;
}
const decoded = parseChannelParameterId(id);
if (!decoded) return;
assertChannel(decoded.channel);
routeToChannel(decoded.channel, decoded.kind, value);
}
```
## API Reference
- `CHANNEL_COUNT: 16`, `MAX_CHANNEL_INDEX: 15`.
- `CHANNEL_PARAM_KINDS: ReadonlyArray<"volume" | "pan" | "program" | "reverbSend" | "chorusSend">`.
- `channelParameterId(channel: number, kind: ChannelParamKind): string`.
- `parseChannelParameterId(id: string): { channel, kind } | undefined`.
- `buildParameterDeclarations(): ReadonlyArray<PluginParameter>`.
- `assertChannel(channel: number): void`.
- `MASTER_GAIN_ID: "master/gain"`.
## Implementation Notes
`program` is declared `automatable: false` because the host chain's parameter-schedule evaluator interpolates linearly; an in-flight ramp between two program numbers would emit non-integer program values to the underlying synth, which has no defined semantics. Treating program-change as a discrete `setParameter` write keeps the contract clean. `volume` is `[0, 1]` to match MIDI CC #7 semantics — callers that need pre-master headroom should drive `master/gain` (which goes to 4×) rather than over-driving channel volume. The parameter order — channels in numeric order, kinds in declaration order, master last — is deterministic so snapshots and UI iteration produce stable byte-for-byte output.