How it works
Every number above is computed for one sample at a time. The audio engine runs exactly this calculation 48 000 times a second; the animation slows it down to between one sample every 10 seconds and one per second, so you can follow a single sample from the clock to the DAC. No recorded sound and no precomputed waveform is involved at any point. That is also how the Yamaha DX7 made sound.
One sample, step by step
- Sample clock. Counts samples n = 0, 1, 2, … and turns the count into a time, t = n / Fs. At 48 000 Hz two samples are 20.83 μs apart. The same t goes to both operators. The DX7 ran at a fixed 49 096 samples a second (Shirriff, part 1; msfa DX7 hardware notes).
- Modulator. Computes m(t) = Am × sin(2π × fm × t). It needs only t and its own two knobs, and produces one number. Nothing about earlier or later samples is stored.
- Modulation index. I scales how far m(t) pushes the carrier. At I = 0 the carrier is a pure sine; larger values add more sidebands, which is the core result of Chowning's 1973 paper.
- Carrier. Computes y(t) = Ac × sin(2π × fc × t + I × m(t)). The modulator's number is added to the carrier's phase, inside the sine, not to its output. Strictly this is phase modulation; it is what the DX7 does, and it is mathematically equivalent to FM (Wikipedia: FM synthesis). On the DX7 chip, "the first adder adds the modulation value to the current phase value" (Shirriff, part 1).
- DAC. y(t) is a single number. The digital-to-analog converter turns the stream of these numbers into a voltage. The DX7 used a 12-bit BA9221 DAC followed by a low-pass filter around 16 kHz that smooths the steps into a continuous waveform (Shirriff, part 5). Then n goes up by one and everything repeats.
While a sample is in flight, slots that are still waiting for their token keep the previous sample's value, dimmed. The knob values are local to each box and are always current.
Same principle as the DX7
The DX7's sound chip, the YM21280 "OPS", computes every operator's output fresh for every sample. It "operates sequentially, updating one oscillator and computing one operator at a time", cycles through 96 operator slots (16 voices × 6 operators), and starts the cycle over 49 096 times a second (Shirriff, part 1).
| Step | This visualizer | DX7 (YM21280 OPS chip) |
| Time base | t = n / Fs at 48 000 Hz. The audio engine keeps a phase accumulator per operator and advances it every sample. | A phase counter per oscillator, advanced every sample at 49 096 Hz (msfa). |
| Sine | Math.sin of the phase, in double precision. | A log-sine ROM indexed by phase (only a quarter cycle is stored), then an exponential ROM to undo the logarithm (log-sine ROM, exponential circuit). |
| Modulation | I × m(t) is added to the carrier's phase. | The modulation value is added to the phase before the sine lookup (part 1). |
| Operators | Two: modulator, then carrier, in that order every sample. | Six per voice in 32 algorithms, computed from operator 6 down to 1; "the signal from operator N+1 enters, and is used to compute the modulation for operator N" (Shirriff, part 4). |
| Output | One y per sample to the Web Audio output. | Time-multiplexed samples to a 12-bit DAC and a 16 kHz low-pass filter (part 5). |
| Stored audio | None. | None. The ROMs hold the sine and exponential functions, not recorded sound. |
What this is not
Sample-based synthesizers store recordings and play them back. Wavetable synthesizers store whole waveform cycles and read through them. Here, as in the DX7, the only table is the sine function itself, looked up by phase. The waveform on the scope exists only as the sequence of numbers computed one after another; the full-speed trace computes those same numbers for display.
Simplifications
- Math.sin in floating point instead of the DX7's fixed-point log-sine and exponential ROMs.
- Two operators and one fixed algorithm instead of six operators and 32 algorithms; no envelopes and no operator feedback.
- 48 000 Hz instead of 49 096 Hz.
- Changed knobs are smoothed over 128 samples in the audio engine to avoid clicks; the animation uses the new value directly.
Using the controls
- Drag a knob up or down; half the window height covers its full range. The mouse wheel and arrow keys make small steps. Frequency and speed knobs are logarithmic.
- Play runs the animation, Step advances exactly one sample, Reset returns to n = 0, Jump goes to any sample.
- Audio on plays the same formula in real time. The animation and the audio run on separate timelines.
Sources
- Ken Shirriff: Reverse-engineering the Yamaha DX7 synthesizer's sound chip from die photos — sequential per-sample operation, 96 oscillators, 49 096 Hz, modulation added to phase.
- Ken Shirriff: The Yamaha DX7 synthesizer's clever exponential circuit — the exponential ROM.
- Ken Shirriff: Part III, inside the log-sine ROM — how the sine is generated from the phase.
- Ken Shirriff: Part 4, how algorithms are implemented — operator order and how one operator modulates the next.
- Ken Shirriff: Part V, the output circuitry — the DAC and the 16 kHz filter.
- Raph Levien, music-synthesizer-for-android: DX7 hardware notes — 49 096 Hz, 96 subsamples, phase accumulator, log-sine and exponential tables.
- John Chowning (1973): The Synthesis of Complex Audio Spectra by Means of Frequency Modulation, Journal of the Audio Engineering Society 21(7), 1973.
- Wikipedia: Yamaha DX7 and Frequency modulation synthesis.