# `synthesizer/schemas` _(no submodules)_ ## 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.