first commit
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# `synthesizer/schemas`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Zod schemas validating the construction-time options, waveform enum, and preset payload of `SynthesizerPlugin`. These run on the public boundary so any malformed object is rejected with `AUDIO_FX.INVALID_OPTIONS` / `AUDIO_FX.INVALID_PRESET` before it can corrupt runtime state.
|
||||
|
||||
Separating schemas from the plugin module lets `index.ts` re-export them so callers can introspect the option surface (for forms, RPC validation, or storybook controls) without importing the audio implementation.
|
||||
|
||||
## Features
|
||||
|
||||
- `SynthWaveformSchema` — `z.enum(["sine", "square", "sawtooth", "triangle"])` reused in both options and preset payloads.
|
||||
- `SynthesizerPluginOptionsSchema` — validates the eight optional `initial*` fields plus `polyphony` (integer 1..32).
|
||||
- `SynthesizerPresetDataSchema` — `.strict()` object carrying only the non-numeric `waveform`.
|
||||
- All numeric fields use `z.number().finite()` so `NaN` and `Infinity` cannot sneak through.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { SynthesizerPluginOptionsSchema } from "@suaveplan/audio-fx-plugin-synthesizer";
|
||||
|
||||
const parsed = SynthesizerPluginOptionsSchema.parse({
|
||||
initialWaveform: "sawtooth",
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
SynthWaveformSchema,
|
||||
SynthesizerPluginOptionsSchema,
|
||||
SynthesizerPresetDataSchema,
|
||||
} from "@suaveplan/audio-fx-plugin-synthesizer";
|
||||
|
||||
// Render a waveform dropdown from the schema.
|
||||
const waveforms = SynthWaveformSchema.options;
|
||||
for (const wf of waveforms) ui.addOption(wf);
|
||||
|
||||
// Validate a wire preset blob before applying.
|
||||
function isSynthPreset(blob: unknown): boolean {
|
||||
return SynthesizerPresetDataSchema.safeParse(blob).success;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `SynthWaveformSchema: z.ZodEnum<["sine", "square", "sawtooth", "triangle"]>`
|
||||
- `SynthesizerPluginOptionsSchema: z.ZodObject<{ initialWaveform?, initialAttackSec?, initialDecaySec?, initialSustain?, initialReleaseSec?, initialCutoffHz?, initialResonance?, initialPortamentoMs?, polyphony? }>`
|
||||
- `SynthesizerPresetDataSchema: z.ZodObject<{ waveform: SynthWaveform }, "strict">`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The `SynthWaveformSchema` is exported as a named schema (not inlined) so the same value is reused by `SynthesizerPluginOptionsSchema.initialWaveform` and `SynthesizerPresetDataSchema.waveform`. That guarantees both validation paths agree byte-for-byte on the legal waveform set — adding a fifth waveform (e.g., `"pulse"`) is a one-line change in `schemas.ts`.
|
||||
|
||||
`polyphony` is bounded at 32 because the voice pool's stealing scan is `O(polyphony)` per attack; 32 voices is comfortably within the per-event budget of a real-time renderer but going much higher would warrant a heap-based stealing structure. The lower bound of 1 makes the plugin a valid monosynth (every triggerAttack steals the previous voice), which is a useful configuration in its own right.
|
||||
Reference in New Issue
Block a user