dx7
dx7 · sourcesPure-TypeScript 6-operator DX7-style FM synthesizer. 32 algorithms, 5-voice polyphony via the polyPitchGate cable, bundled bank of factory-inspired patches (E.PIANO 1, BASS 1, HARMONICA, STRINGS 1, MARIMBA, etc.), and a .syx file picker for loading custom 32-voice cartridge dumps (in-memory only). On top of the six per-operator DX7 envelope generators, a per-voice master OUTPUT-VCA ADSR (Attack / Decay / Sustain / Release) gives a player-dialable amplitude swell / long-release without editing the SYX: one envelope per voice multiplies the summed-carrier output, gated by the same note-on/note-off as the operator EGs (soft/click-safe retrigger). Defaults are ~pass-through (fast attack, full sustain, fast release) so loaded patches sound identical until you touch the master ADSR; a long master release now outlives operator-EG silence (a voice frees only once both the operator EGs and the master amp envelope have faded). NOT a Plaits-backed implementation.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
poly | polyPitchGate | The polyphonic note source and the preferred way to play this synth: the 16-lane polyPitchGate cable (32 channels — a pitch and a gate per lane; patch POLYSEQZ, MIDI LANE, or another poly source here). DX7 has five voice slots, so only the first VOICES lanes are read and anything on lanes 6-16 is ignored. A rising gate on a lane triggers a fresh note-on at that lane's pitch, the falling gate releases it, and while a lane's gate stays high its pitch keeps being tracked so the note glides. A lane keeps its own voice for as long as its note lasts; when every voice slot is still busy a new note steals the oldest. Pitch and gate are sampled once per render block, so block-quantized sequencer writes land exactly. poly pitch+gate bus; 10-channel poly bus (5 pitch + 5 gate lanes) |
pitch_cv | cv | Mono V/oct pitch for single-voice playing — read only when nothing is patched into POLY, and only for the first lane, so this route is monophonic. 0 V is middle C (C4) and 1 V is an octave; TRANSPOSE and the loaded patch's own stored transpose add on top. control voltage (CV) |
gate | gate | Mono note-on/off gate for the single-voice (PITCH CV) route — level-sensitive, not edge-only: crossing above half a volt triggers a note-on, the note is held for as long as the level stays high (tracking PITCH CV, so it glides), and the falling edge releases it. Read only when nothing is patched into POLY; patch a keyboard or envelope gate here. gate / trigger; gate — acts while the level is high (reacts to both edges) |
outputs
| id | cable | what it does |
|---|---|---|
out | audio | Mono audio: every active voice's carrier operators summed, each voice scaled by its own master ADSR, then the whole bus scaled by LEVEL and by a fixed headroom trim of 0.4 so five voices sounding at once stay clear of clipping. Patch it into a VCA, filter, mixer, or straight to the output. audio signal |
params
| id | label | range | default | curve |
|---|---|---|---|---|
algorithm | Algorithm | 1..32 | 5 | discrete |
feedback | Feedback | 0..7 | 4 | discrete |
voiceCount | Voices | 1..5 | 5 | discrete |
level | Level | 0..2 | 0.7 | linear |
transpose | Transpose | -24..24st | 0 | linear |
attack | Atk | 0.001..5s | 0.001 | log |
decay | Dec | 0.001..5s | 0.1 | log |
sustain | Sus | 0..1 | 1 | linear |
release | Rel | 0.001..5s | 0.005 | log |
controls
| control | what it does |
|---|---|
| Algorithm | Which of the 32 DX7 algorithms wires the six operators together (1–32) — each one fixes both the carrier/modulator routing AND which operator carries the feedback loop, from the deep single-carrier stacks (16–18) through the classic 3-carrier electric-piano layouts (5) to the fully parallel additive organ (32, where all six operators are carriers). It is the biggest single shaper of a patch's character. Loading a preset stamps that voice's own stored algorithm onto this control; turning the knob afterwards overrides it, and the override is what the engine plays. Changing it is NON-DESTRUCTIVE — the engine re-binds its routing at the start of the next render block, so a note you are holding morphs into the new wiring instead of being cut off or re-attacked, and a tail that is ringing out keeps ringing. Sweep it while a chord is held; that is the point. |
| Atk | Master output-VCA attack, per voice, layered on top of the patch's own operator envelopes: a linear ramp to full level taking this long, 0.001 to 5 s. At the 0.001 s default the master VCA is open instantly, so you hear the patch's own attack; raise it for a swell. Retrigger is click-safe — a re-gated voice ramps up from wherever it was instead of resetting to zero. |
| Dec | Master-VCA decay: once the attack has reached full level, the master envelope slides exponentially toward SUSTAIN with this time constant (about 99 % of the way in five times the setting). With SUSTAIN at its default of 1 there is nothing to slide toward and this has no effect — lower SUSTAIN first to hear it. |
| Dx7 op detail {n} | Operator detail — everything about the one operator selected in the map, in three rows. PITCH sets COARSE (0-31), FINE (0-99) and DETUNE (-7…+7) and prints the RESOLVED frequency they produce, because on this synth the raw bytes mean nothing on their own — coarse 1 / fine 0 is ×1.00, and the same coarse in fixed mode is a decade in Hz instead. ENVELOPE is the operator's own 4-rate/4-level DX7 curve, dragged directly: vertical is LEVEL, horizontal is the RATE of the segment arriving at that point, so dragging a point RIGHT makes that segment SLOWER. The other five operators' envelopes are ghosted behind the one you are editing, which is the only place you can compare envelopes across operators while changing one. The eight R/L numbers read out underneath, and COPY EG stamps this operator's envelope onto another. OUTPUT LEVEL is the operator's contribution, shown as both the raw 0-99 byte and its level in dB. The header carries the patch-safety cluster: a dirty marker (✱) once you have changed anything, REVERT to throw the edits away and reload the stored voice, STORE to save the edit buffer under a new 10-character name (an edited voice exists ONLY in the edit buffer until you store it — loading another preset discards it), and INIT for a bare single-carrier sine, which with operator muting is the canonical way to learn what FM actually does. |
| Dx7 operator map {n} | Operator map — the algorithm's wiring diagram, live. Each of the six tiles is one operator, placed exactly where the current ALGORITHM puts it: modulators above, carriers along the bottom. A horizontal CARRIER RAIL runs under the bottom row and every carrier drops onto it, which is what makes the output sum literal — the operators touching that rail are the ones you actually hear; everything above is bending a phase. Tile colour repeats the same information (carriers warm, modulators cool, an operator that is both purple) but the rail is the primary cue, so the map still reads correctly with any colour vision. Each tile also shows its resolved frequency (`×3.06`, or `FIX 220 Hz` for a fixed-frequency operator), a miniature of its envelope scaled by its output level — so a quiet operator draws a short curve and six tiles can be compared at a glance — and an ON/OFF dot. Clicking a tile selects it for the detail panel; clicking the dot mutes that operator without changing the selection, which is the fastest way to hear what one operator is contributing. Muting is per-rack state and is shared with everyone in the rackspace; which operator you have SELECTED is yours alone, so a collaborator editing OP 5 never yanks your panel. |
| Dx7 preset select {n} | The voice selector, and the single control that defines the sound: pick one of the nine built-in patches (E.PIANO 1, BASS 1, HARMONICA, STRINGS 1, MARIMBA, TUB BELLS, BRASS 1, CALLIOPE, WIRE LEAD) or, once you have imported a cartridge, any voice from it. Choosing a voice STAMPS it — its six operators, their envelopes and its stored transpose become the working voice, and its stored algorithm and feedback depth are written onto the ALGORITHM and FEEDBACK knobs, which jump to the patch's own values. The whole stamp is one edit, so a single undo puts the previous voice back. Unlike those two knobs, a voice load is DESTRUCTIVE: it re-sends the whole patch and resets every note, so one you are holding re-attacks from the start of its envelope and one already ringing out its release is cut short. Treat it as a between-notes control. Picking the voice that is already loaded is the REVERT — it restamps the pristine patch over your operator edits without stopping anything that is sounding. |
| Dx7 syx input {n} | Load .syx bank — import a real Yamaha DX7 cartridge dump. It accepts the standard 4104-byte 32-voice SysEx bank, a bare 4096-byte payload, or a single 128-byte packed voice; a bank's 32 voices are APPENDED to the selector (never replacing what is already there, so several cartridges can be stacked) and the first voice of the new bank is selected for you. A status line reports how many voices loaded plus a count of any warnings — a bad header byte or a checksum mismatch is warned about, not rejected; only a file whose SIZE matches none of the three shapes is refused outright. Imported voices ride in the module's data, so they are saved with the rack and reach everyone in the rackspace. |
| Feedback | How hard the algorithm's single feedback loop is driven, 0 to 7 — the one continuous timbral control an FM player rides, which is why it is a knob here while the operators' 78 values live in the loaded voice. WHERE the loop sits is fixed by the ALGORITHM (operator 6 into itself in most of them, but 2, 3, 4 or 5 in others, and in algorithms 4 and 6 a loop wrapping a whole stack) — this only sets its depth. Feeding an operator its own output enriches it toward a sawtooth and then, at the top of the range, into noise: on a modulator it is the fastest route from a clean bell to a metallic crash or a breath/hiss layer, and on a carrier it is the classic DX7 brass edge. 0 disables the loop entirely. Loading a preset stamps that voice's own stored depth here; turning the knob afterwards overrides it. Like ALGORITHM it is applied incrementally, so riding it under a held chord neither retriggers nor cuts anything. |
| Level | Master output gain for the whole synth, 0 to 2 (0.7 default); it scales the summed voice bus feeding OUT. The fixed 0.4 headroom trim is applied on top of it either way, so LEVEL 1 is the knob's own unity rather than unity gain end to end. |
| Rel | Master-VCA release after the gate falls: an exponential fade with this time constant. It acts as a CEILING on the patch's own tail — at the 0.005 s default the master VCA closes in well under a tenth of a second, cutting the long releases stored in bell and pad voices, so raise it (a second or more) when you want those tails to ring. The voice slot is freed only once both this envelope and the operator envelopes have faded out. |
| Sus | Master-VCA sustain level (0 to 1) — the level a held note settles at after attack and decay, kept until the gate falls. At the default of 1 the master VCA simply stays open, so the patch's own operator envelopes are what you hear. |
| Transpose | Global pitch offset in semitones (-24 to +24) added to every voice on top of the loaded patch's own stored transpose (BASS 1, for instance, already sits an octave down). It is continuous rather than stepped, so fractional settings detune the whole instrument. It is re-applied while a gate is held — turning it retunes sounding notes live — but a note already released keeps the pitch it ended on. |
| Voices | How many of the POLY cable's lanes are read, 1 to 5 — the cable itself carries 16, but DX7 has five voice slots and never looks past lane 5. Lanes above the setting are ignored, so 1 gives a strictly monophonic instrument (the same first lane the mono PITCH CV + GATE pair drives) and 5 lets full chords through. Five voice slots exist either way; a note arriving while all of them are still busy steals the oldest. |
source
dx7.ts on GitHub.