# `glados` _(no submodules)_ ## Purpose `GLaDOSPlugin` is the universal voice-effect insert. It runs the input signal through a fixed six-stage chain — granular pitch shift → formant tilt → robotic-intensity tremolo → soft-clip distortion → low-pass filter → short feedback reverb — and exposes a typed setter for each stage plus six named presets. The plugin is an insert (`io.inputs[0].count === io.outputs[0].count === "preserve"`), so it accepts any input channel count and emits the same shape. The plugin extends `AbstractAudioFxPlugin`, runs identically across browser / server / worklet renderers, and validates every setter at the boundary: out-of-range values throw `AUDIO_FX.INVALID_OPTIONS` with the offending value attached. Six built-in presets cover the GLaDOS family (mainline, test chamber, cake deception) plus Wheatley, Cave Johnson, and a generic robotic voice. ## Features - Six chained stages, each with a typed setter: `setPitchShift`, `setFormantShift`, `setRoboticIntensity`, `setDistortionAmount`, `setLowPassCutoff`, `setReverbAmount`. - Six built-in presets (`glados-mainline`, `glados-test-chamber`, `glados-cake-deception`, `wheatley`, `cave-johnson`, `robotic-generic`) selected via the construction `preset` option or `applyGladosPreset(name)`. - `getGLaDOSPresets()` exposes the read-only preset table so editors can render preset dropdowns and preview the values. - Per-stage range validation: `pitchShift`/`formantShift` ∈ [-12, 12] semitones, `roboticIntensity`/`distortionAmount`/`reverbAmount` ∈ [0, 1], `lowPassCutoff` ∈ [20, 20 000] Hz. - `applyGladosPreset` is named distinctly from `AbstractAudioFxPlugin.applyPreset(snapshot)` so the two methods do not collide. ## Usage: Basic Example ```ts import { GLaDOSPlugin } from "@suaveplan/audio-fx-plugin-glados"; const glados = new GLaDOSPlugin({ preset: "glados-mainline" }); chain.add(glados); ``` ## Usage: Advanced Example ```ts import { GLaDOSPlugin, getGLaDOSPresets } from "@suaveplan/audio-fx-plugin-glados"; const presetNames = Object.keys(getGLaDOSPresets()) as ReadonlyArray< keyof ReturnType >; const voice = new GLaDOSPlugin({ preset: "wheatley" }); await voice.setup( { sampleRate: 48_000, channels: 2, blockSize: 512 }, ctx ); // Customise the wheatley preset with extra reverb. voice.setReverbAmount(0.4); voice.setLowPassCutoff(5_500); // Preview every preset on the same line of dialogue. for (const name of presetNames) { voice.applyGladosPreset(name); await player.playDemo(); } ``` ## API Reference - `GLaDOSPlugin` (class extends `AbstractAudioFxPlugin`) - `new GLaDOSPlugin(options?: GLaDOSPluginOptions)` — throws `AUDIO_FX.INVALID_OPTIONS` on malformed options. - `applyGladosPreset(name: GLaDOSPreset): void`, `getCurrentPreset(): GLaDOSPreset`, `getGladosConfig(): GLaDOSConfig`. - `setPitchShift(-12..12)`, `setFormantShift(-12..12)`, `setRoboticIntensity(0..1)`, `setDistortionAmount(0..1)`, `setLowPassCutoff(20..20000)`, `setReverbAmount(0..1)` — each throws `AUDIO_FX.INVALID_OPTIONS` on out-of-range. - `getGLaDOSPresets()` — read-only view of the six built-in presets. - Types: `GLaDOSPreset` literal union, `GLaDOSConfig`, `GLaDOSPluginOptions`, `GLaDOSPresetData`. ## Implementation Notes The pitch-shift stage is a per-channel granular ring buffer with linear-interpolated fractional read — the same shape used by `PitchShifterPlugin` but with a smaller window because vocal content does not need the larger windows that drum or instrumental material benefits from. For pitch shifts within the GLaDOS-typical range (-5 to +5 semitones) this produces an audibly clean result. Going further out is supported but the perceptual artefacts increase. The formant-tilt stage is a simple gain shift (`10^(formantShift / 8)`) rather than a true formant analyzer. A real formant-shift implementation needs spectral analysis + cepstrum manipulation, which is much heavier and would not measurably improve the GLaDOS character. The simple gain matches what most game-audio implementations use for "robotic voice" effects. The robotic-intensity stage is a 30 Hz tremolo modulating amplitude — fast enough to read as "robotic clicking" rather than "vibrato". The depth is mapped linearly from the `roboticIntensity` knob so the user-facing range `[0, 1]` translates to `0` (no tremolo) through `1` (full chopping). The 30 Hz rate is faster than typical tremolo because that's what makes the voice sound mechanical rather than emotional. The distortion stage is a `tanh` soft-clip with parallel dry/wet routing — same shape as the `DistortionPlugin`'s waveshaper mode but with a fixed drive that scales with the user's `distortionAmount` knob. The low-pass is a one-pole filter (the same shape used by `MicrophoneSimulationPlugin`), and the reverb is a short feedback delay (`REVERB_DELAY_MS = 30 ms` per channel). Both are intentionally simpler than their dedicated sibling-plugin counterparts because the GLaDOS character does not need surgical control — the user wants "more or less" of each colour, not a fully parametric filter and convolution. Preset application replaces the *entire* config in one shot via `{ ...PRESETS[preset] }`. Individual setter overrides applied after `applyGladosPreset` will stick; the next preset application replaces them. The preset payload encodes both the preset name and the live config so `applyPreset(snap)` restores any per-stage overrides made after the preset was originally applied.