macrooscillator
macrooscillator · sourcesPlaits-style macro oscillator (Mutable Instruments archetype). Clean-room pure-TypeScript implementation — not a port of Plaits' C++ source (see PR #27 for the closed emscripten attempt). First-slice scope ships two synthesis models behind the three canonical macros (HARMONICS / TIMBRE / MORPH): (0) virtual analog (VA) — morphing saw→square→triangle PolyBLEP wave + detuned partner (HARMONICS = detune amount) + wavefolder (TIMBRE = fold amount); (1) waveshape — sine through a morphable wavefolder/tanh-waveshaper (TIMBRE = drive, MORPH = wavefolder↔tanh, HARMONICS = sub-octave mix). PITCH input is V/oct; NOTE param is a ±60-semitone offset on top. TRIG resets phase on rising edge for percussive attack alignment. OUT is the level-scaled main output; AUX is a per-model raw tap (unfolded sub-octave triangle in VA, pre-distortion body in waveshape). More models (granular, FM, chord, speech, kick/snare/hat, modal, etc.) land in follow-up PRs.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
pitch | pitch | 1V/octave pitch CV — 0 V plays C4 (261.63 Hz) and each +1 raises the note one octave. It sums with the NOTE control before the engine, so PITCH does the musical tracking while NOTE trims a fixed offset; the resulting frequency is clamped to roughly 1 Hz..20 kHz. V/oct pitch CV |
trig | gate | Strike / restart trigger: each rising edge (crossing above 0.5) resets the selected engine — phase accumulators snap to zero on the pitched models, and the percussion (KICK/SNARE/HIHAT), STRING and other excited models retrigger their attack/burst. It is sampled per-edge, so it fires once per pulse; hold it high or leave it unpatched and the model simply free-runs (sustained tones keep ringing, drums decay once). gate / trigger; trigger — fires once per rising edge |
model_cv | cv | CV that displaces the MODEL selector on a discrete (stepped) scale, switching which of the 14 engines is active. Because model select is a switch and not a continuous control, a smoothly-changing source (an LFO) will step rapidly through engines and sound glitchy — drive it with stepped/held voltages (a sequencer, sample-and-hold) for clean model changes. control voltage (CV); modulates model (integer buckets — CV selects a discrete step) |
note_cv | cv | CV that displaces the NOTE control, adding a semitone offset (the param spans ±60 st) on top of the PITCH V/oct input — useful for sequenced transposition that rides above the main pitch tracking. control voltage (CV); modulates note (additive offset — ±1 CV sweeps the full range, centered on the knob) |
harm_cv | cv | CV that displaces the HARMONICS macro (0..1). Its sonic effect depends on the active model (detune, FM ratio, chord shape, inharmonicity, string stiffness, kick pitch-sweep range, etc.). control voltage (CV); modulates harmonics (additive offset — ±1 CV sweeps the full range, centered on the knob) |
timb_cv | cv | CV that displaces the TIMBRE macro (0..1) — the second model-dependent axis (wavefolder drive, FM mod index, voice waveform, spectral tilt, filter cutoff, click amount, and so on). control voltage (CV); modulates timbre (additive offset — ±1 CV sweeps the full range, centered on the knob) |
morph_cv | cv | CV that displaces the MORPH macro (0..1) — the third model-dependent axis (waveshape crossfade, FM feedback / decay, chord spread, even/odd balance, damping, body-decay length, grain envelope, etc.). control voltage (CV); modulates morph (additive offset — ±1 CV sweeps the full range, centered on the knob) |
level_cv | cv | CV that displaces the LEVEL control (0..1), scaling the main OUT amplitude. It only affects OUT — the AUX tap is deliberately left unscaled. control voltage (CV); modulates level (additive offset — ±1 CV sweeps the full range, centered on the knob) |
outputs
| id | cable | what it does |
|---|---|---|
out | audio | The main audio output of the selected model, after the LEVEL scalar is applied. This is the primary voice to patch into a filter / VCA / mixer. audio signal |
aux | audio | A model-dependent auxiliary tap carrying a clean / raw variant of the same voice — the sub-octave triangle on VA, the pre-distortion body on WAVESHAPE, the clean carrier on FM, the root voice on CHORD, the fundamental mode on MODAL, the glottal pulse on SPEECH, and so on. It is NOT scaled by LEVEL (Plaits convention), so it stays a steady reference for use as a sidechain trigger, a scope/sync reference, or a second timbre to mix in. audio signal |
params
| id | label | range | default | curve |
|---|---|---|---|---|
model | Model | 0..? | 0 | discrete |
note | Note | -60..60st | 0 | linear |
harmonics | Harmonics | 0..1 | 0.3 | linear |
timbre | Timbre | 0..1 | 0.3 | linear |
morph | Morph | 0..1 | 0.5 | linear |
level | Level | 0..1 | 0.8 | linear |
controls
| control | what it does |
|---|---|
| Harmonics | The first of the three universal macros (0..1). Its meaning is model-specific: e.g. detune (VA), sub mix (WAVESHAPE), carrier:modulator ratio (FM 2-OP), chord shape (CHORD), inharmonicity (ADDITIVE), string stiffness (STRING), preset (MODAL), pitch-sweep range (KICK), noise/tone balance (SNARE), bandpass centre (HIHAT), wavetable frame (WAVETABLE), grain density (GRANULAR), vowel (SPEECH). |
| Level | Output level (0..1) applied to the main OUT only; the AUX tap is left at full scale regardless of this control. ⚠ It cannot fix the module's real level problem: OUT RMS spans 76.6 dB BETWEEN engines at identical macro settings (FM 2-OP −5.0 dBFS against MODAL −81.6 dBFS), and LEVEL moves all fourteen by the same amount. The faceplate's `out` and `vs loudest` readouts print where the current engine sits in that spread. Note also that at LEVEL 0 the main output is genuinely silent while AUX is unchanged — on eight of the fourteen engines that means AUX is still at full scale. |
| Macro hero {n} | The engine picture in the faceplate's hero slot: a short window of the CURRENT engine at the CURRENT macro settings, computed from the live knobs through the module's own pure-math mirror rather than tapped off the audio, so it shows what the voice will do before anything has struck it. OUT is drawn solid and AUX as a ghost, both at the SAME scale — which is how the level relationship between the two outputs becomes visible instead of being something you discover with a meter. Two captions carry facts the picture would otherwise hide: the display gain (MODAL peaks at 0.0028, so an un-scaled trace would be a flat line indistinguishable from silence) and the lead-in that had to be skipped (MODAL's exciter is a fixed 4 Hz impulse train, so its first non-zero sample is a quarter of a second in). |
| Macro strike {n} | Audition: strike the engine once, exactly as a rising edge into TRIG would. It exists because five of the fourteen engines (FM 6-OP, STRING, KICK, SNARE, HIHAT) initialise their excitation or envelopes to zero and are therefore SILENT — not quiet, silent — with nothing patched into TRIG, so on a bare rack more than a third of the module cannot be heard at all. Pressing it writes nothing: no param moves, nothing is persisted, nothing is shared with the rackspace and nothing lands in the undo stack. A real cable into TRIG keeps working alongside it. |
| Model | Picks which of the 14 synthesis engines is active, as a discrete (stepped) fader from 0 to 13: 0 VA, 1 WAVESHAPE, 2 FM 2-OP, 3 FM 6-OP, 4 CHORD, 5 ADDITIVE, 6 STRING, 7 MODAL, 8 KICK, 9 SNARE, 10 HIHAT, 11 WAVETABLE, 12 GRANULAR, 13 SPEECH. The fader snaps to integer steps and the model readout above the panel names the current selection; switching is glitch-free because every engine runs continuously underneath. |
| Morph | The third universal macro (0..1), model-specific: saw→square→triangle morph (VA), folder↔tanh crossfade (WAVESHAPE), feedback (FM 2-OP) / envelope decay (FM 6-OP), chord spread (CHORD), even/odd balance (ADDITIVE), damping (STRING), mode-amp morph (MODAL), body decay (KICK/SNARE), decay length (HIHAT), phase-distortion (WAVETABLE), grain-envelope shape (GRANULAR), pitched→whispered source (SPEECH). |
| Note | Fixed pitch offset in semitones (−60..+60 st) added on top of the PITCH V/oct input — a manual transpose for tuning the oscillator without re-patching, separate from the per-note tracking that PITCH provides. |
| Timbre | The second universal macro (0..1), model-specific: wavefolder drive (VA), distortion drive (WAVESHAPE), FM modulation index (FM), voice waveform sine→saw (CHORD), spectral tilt (ADDITIVE), excitation brightness (STRING), resonance Q (MODAL), click amount (KICK), noise hi-pass (SNARE), metallic↔noise blend (HIHAT), LP filter (WAVETABLE), pitch jitter (GRANULAR), formant Q (SPEECH). |
source
macrooscillator.ts on GitHub.