dx7

dx7 · sources

Pure-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.

A 6-operator FM synthesizer modeled on the Yamaha DX7. Each of its six operators is a sine oscillator with its own frequency ratio (or a fixed frequency in Hz, where the coarse setting picks a decade — 1, 10, 100 or 1000 Hz — and the fine setting sweeps up to just under the next one, ignoring the played note entirely) and its own 4-rate/4-level DX7 envelope. That envelope is the DX7's own shape, not an ADSR: it idles at L4, climbs to L1 at rate R1, falls to L2 then to L3, and HOLDS at L3 for as long as the gate is high — so L3 is the sustain level and L4 is both where the envelope starts and where the release lands. Release times and decay times are linear in decibels, so a rate of 99 crosses the whole range in about 6 ms while a rate of 0 takes over five minutes, and an attack is roughly eight times faster than a decay set to the same number. Instead of filtering a rich waveform, operators modulate each other's phase — one of 32 fixed ALGORITHM wiring diagrams decides which operators are CARRIERS (summed to the output) and which are MODULATORS bending a carrier faster than you can hear, which is what sculpts FM's metallic, bell-like and electric-piano timbres. Every algorithm also carries exactly ONE feedback loop, whose depth is the FEEDBACK knob (loading a voice stamps that voice's stored depth onto it), and WHERE that loop sits is part of the algorithm: it is operator 6 feeding back into itself in most of them, but operator 2, 3, 4 or 5 in others, and in algorithms 4 and 6 it is a loop wrapping a whole stack (operator 4 back into 6, operator 5 back into 6) rather than a self-loop. That placement is often the only difference between two otherwise identically-wired algorithms — 1 and 2, or 26 and 27, route the same and sound different for exactly this reason. This is a PATCH-DRIVEN instrument: the ratios, levels, envelopes, feedback and stored transpose all come from the loaded voice — nine built-in patches written to evoke the classic factory sounds (E.PIANO 1, TUB BELLS, BRASS 1 …; they are original patches, not Yamaha's data), plus every voice of any .syx cartridge you import. The panel's live controls are therefore which voice is loaded, which algorithm wires it, how hard its feedback loop is driven, how it plays (polyphony, transpose, level) and a per-voice master ADSR layered over the patch's own operator envelopes. ALGORITHM and FEEDBACK are the two the engine applies incrementally — ride them under a held chord and nothing is retriggered or cut; loading a different VOICE is the destructive one. It plays up to 5 voices from the POLY bus — the first VOICES of that cable's 16 lanes — or monophonically from the PITCH CV + GATE pair. What a cartridge actually drives here: each operator's four envelope rates and levels, its frequency ratio (or fixed-frequency mode), its detune and its output level, plus the voice's algorithm, feedback depth and stored transpose. What it does NOT: the LFO and the pitch envelope are unpacked into the parsed voice but never sent to the engine, per-operator velocity sensitivity is sent and then ignored (nothing upstream carries velocity — the poly cable is pitch and gate only), and keyboard level scaling, rate scaling, amp-mod sensitivity and oscillator sync are not unpacked from the cartridge bytes at all.

the faceplate

dx7polypolyPitchGatepitch_cvcvgategateoutaudioaudiocvgatepitch
3 inputs · 1 outputs · 9 params

inputs

idcablewhat it does
polypolyPitchGateThe 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_cvcvMono 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)
gategateMono 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

idcablewhat it does
outaudioMono 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

idlabelrangedefaultcurve
algorithmAlgorithm1..325discrete
feedbackFeedback0..74discrete
voiceCountVoices1..55discrete
levelLevel0..20.7linear
transposeTranspose-24..24st0linear
attackAtk0.001..5s0.001log
decayDec0.001..5s0.1log
sustainSus0..11linear
releaseRel0.001..5s0.005log

controls

controlwhat it does
AlgorithmWhich 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.
AtkMaster 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.
DecMaster-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.
FeedbackHow 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.
LevelMaster 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.
RelMaster-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.
SusMaster-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.
TransposeGlobal 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.
VoicesHow 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.

Generated from packages/web/src/lib/{audio,video}/module-registry.ts · repo