2.9 KiB
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 optionalinitial*fields pluspolyphony(integer 1..32).SynthesizerPresetDataSchema—.strict()object carrying only the non-numericwaveform.- All numeric fields use
z.number().finite()soNaNandInfinitycannot sneak through.
Usage: Basic Example
import { SynthesizerPluginOptionsSchema } from "@suaveplan/audio-fx-plugin-synthesizer";
const parsed = SynthesizerPluginOptionsSchema.parse({
initialWaveform: "sawtooth",
});
Usage: Advanced Example
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.