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,76 @@
# `glados`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<typeof getGLaDOSPresets>
>;
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.