How the Super Nintendo made sound.
We start from the very beginning — what a digital sound even is — assuming you know nothing about audio. Once the vocabulary is solid, we open up Nintendo's little audio computer: the SPC700 CPU, its 64 KB of private RAM, and the S-DSP that decodes samples and mixes eight voices into 32 kHz stereo. Sixteen modules, each with a live synthesiser so you can hear every idea. No game audio ships with this page; every sound is generated in your browser.
Digital sound from zero
Waves, sampling, harmonics, compression, envelopes, pitch and echo — the universal vocabulary of digital audio, from scratch.
The SNES sound hardware
The S-SMP two-computer split, the S-DSP's 8 voices, BRR samples, ADSR/GAIN, Gaussian interpolation and the echo FIR.
Emulating the chip
Two crystals, the CPU↔APU sync problem, and the SPC file format you can play today.
Digital sound from zero
This first part is pure fundamentals — nothing about any specific chip yet. It's the toolkit that every piece of digital audio gear is built from, whether that's a phone, a CD player, or the little Sony chip we'll meet in Part II. We build the vocabulary one word at a time — wave, sample, harmonic, compression, envelope, pitch, echo — and you can play and see each idea with a synthesised tone. If a term is ever used before it's explained, that's a bug. Everything in Parts II and III is just these ideas wired into silicon.
Sound as waves
Let's start with what sound physically is. When something vibrates — a guitar string, your vocal cords, a speaker cone — it pushes and pulls on the surrounding air, making tiny, fast changes in air pressure. Those changes ripple outward as a wave and reach your eardrum, which vibrates in step. That's all sound is: a wobble in air pressure over time.
To put that wobble in a computer we do something wonderfully simple. Many thousands of times per second we measure the pressure and write the number down. Each measurement is called a sample. String the samples together in order and you have the whole sound as a plain list of numbers; feed that list back to a speaker at the same speed and the sound reappears.
A movie isn't really moving — it's a stack of still photos shown fast enough that your eye fills in the motion. Digital sound works the same way: each sample is a still “photo” of the wave's height at one instant. Play the photos back quickly and smooth sound returns. Take too few per second and, like a choppy movie, it comes out wrong — that's Module 02.
Three numbers describe any simple wave. Its frequency is how many times it repeats each second, measured in hertz (Hz) — 440 Hz means 440 cycles a second, and higher frequency means higher pitch. Its amplitude is how far the wave swings from rest — how loud it is. And its phase is where in the cycle it happens to start. Hold on to frequency and amplitude; they run through the whole course.
The basic shapes
A synthesiser like the one on this page builds everything from a few shapes. A sine is the purest tone — one frequency, no extra colour, like a tuning fork. Square and saw(tooth) are jagged and buzzy — those classic chiptune “bleeps” — because they're secretly a sine plus a pile of higher tones (Module 03). Triangle sits in between, mellow but a little richer than a sine. Noise is every frequency at once with no pitch — your “shh”: wind, static, a snare. Play with the scope: switch shapes, sweep the frequency, and watch the trace while you listen.
The trace is an oscilloscope: it draws amplitude (up/down) against time (left/right), so you're literally seeing the stream of sample values as a line.
- Sound is a pressure wave; a digital signal is that wave measured as regularly-spaced numbers (samples).
- Frequency = pitch (Hz); amplitude = loudness; phase = where the cycle starts.
- Sine, square, saw, triangle and noise are the building blocks a synth combines.
Sampling & quantisation
Storing sound as numbers raises two questions. How often do we measure, and how precisely do we write each measurement down? The answers are the sample rate and the bit depth, and together they define any audio format — including the SNES's.
The sample rate is measured in samples per second, again in hertz. There's a hard rule about it, the Nyquist limit: to capture a frequency you must sample more than twice as fast. You've seen this rule with your eyes: in old films a fast-spinning wagon wheel can appear to crawl or even roll backwards, because the camera's frames sample the motion too slowly — the flipbook from Module 01 with too few pages. Sample sound too slowly and high frequencies do the same trick: they don't just vanish — they fold back down and reappear as false, lower tones. That folding is called aliasing, and it sounds like a metallic, warbly grunge riding on top of the sound.
The S-DSP mixes all its voices internally and pushes out
16-bit stereo at 32 000 Hz. By Nyquist that
gives a ceiling of 16 kHz — a touch shy of the ~20 kHz limit
of young ears, which is part of why the SNES sounds warm and slightly
soft rather than crisp and clinical. Individual voices are usually
stored at rates well below 32 kHz to save precious RAM;
the chip then reads them out more slowly — a per-voice pitch register
set below its neutral value of $1000 — so they
still sound at their true pitch (Module 06). Raising that register
above $1000 is what shifts a sound up.
A bit is a single 0-or-1 switch. Line up n of them and you can spell 2n different patterns: 2 bits give 4, 8 bits give 256, 16 bits give 65 536. “16-bit audio” simply means each sample is written down as one of 65 536 possible values.
Bit depth is the other knob: how many distinct values a sample can take. 16-bit gives 65 536 possible levels; drop to 8-bit and you have only 256, so every sample must snap to the nearest available rung. That rounding is quantisation, and the error it introduces is heard as a gritty hiss — quantisation noise. The lab below lets you strangle both knobs on a bright tone. Drop the rate to hear aliasing; drop the bits to hear the crunch. The reference button plays it back at the SNES's own 32 kHz / 16-bit.
- Sample rate = how often; the Nyquist limit is half the sample rate — above it, sound aliases.
- Bit depth = how precisely; too few bits adds quantisation noise (a gritty hiss).
- The S-DSP outputs 16-bit stereo at 32 000 Hz — a 16 kHz ceiling, hence its warm tone.
Waves add up
In Module 01 we said a square or saw wave is “secretly a sine plus a stack of higher tones.” That wasn't a metaphor. It's one of the most important facts in audio, and we owe it to the mathematician Fourier: any sound, however complicated, is just a sum of simple sine waves at different frequencies and volumes. Add the right sines and you can build any waveform; pull a sound apart and you always find sines underneath.
The lowest sine is the fundamental — the pitch you actually hear. The sines stacked above it, at 2×, 3×, 4×… the fundamental's frequency, are the harmonics. Their pattern of loudnesses is what makes a flute sound different from a trumpet at the same pitch. A pure sine has no harmonics at all; a saw has every harmonic, each a bit quieter than the last; a square has only the odd ones.
The finished tone is a baked cake — you taste it all at once. The list of harmonics is the recipe: two parts fundamental, one part second harmonic, a pinch of the fifth. Change the amounts and you've baked a different instrument. The mixer below is that recipe card, live.
Slide the first eight harmonics up and down and listen to the timbre change, or hit a preset to snap to a sine, a saw, a square or a reedy organ. This is additive synthesis — building sound by piling sines up. (The SNES doesn't synthesise this way; it plays recorded samples. But understanding harmonics is what lets you read why one sample sounds bright and another dull.)
- Any tone = a sum of sine waves: a fundamental plus harmonics at whole-number multiples.
- The pattern of harmonic loudnesses is the timbre — why a flute ≠ a trumpet.
- Saw = all harmonics; square = odd harmonics only; sine = fundamental alone.
Squeezing samples: ADPCM & BRR
The SNES has only 64 KB of audio RAM (Part II), so every sample must be tiny. Raw 16-bit audio is far too fat, so the chip stores everything in a compressed form. The trick is ADPCM — Adaptive Differential PCM. Instead of storing each sample's full value, ADPCM predicts the next sample from the previous ones and stores only the small correction, in just a few bits. Sound changes smoothly, so the corrections stay small, and a handful of bits is plenty.
The SNES's specific flavour is called BRR — Bit Rate Reduction — and it's beautifully rigid. Samples are packed into 9-byte blocks, each holding exactly 16 samples. The first byte is the header; the remaining eight bytes hold sixteen 4-bit signed nibbles, one per sample — each a tiny signed value spanning just −8…+7.
From here on you'll see numbers like $C5. The
$ marks hexadecimal
— base 16, with digits 0–9 and then A–F standing for 10–15. Each hex
digit is exactly four bits (one nibble), which is why hardware people
love it: a byte is always two hex digits, $00–$FF
= 0–255. So $C5 = 12 × 16 + 5 = 197.
Decoding is where the “adaptive” and “predictive” parts live. Each 4-bit nibble is first scaled up by the header's shift (0–12). Then one of four filters reconstructs the real sample by adding a prediction from the previous one or two decoded outputs:
- Filter 0 — no prediction; the nibble stands alone. Used at the start of a sample so nothing leaks in from before.
- Filter 1 — adds about
0.94×the previous sample. A gentle slope-follower. - Filters 2 and 3 — use the previous two samples for a stronger prediction, ideal for smooth, tonal material.
Let's decode one sample by hand, with real numbers. Say the header set
shift = 8 and filter 1,
the previous decoded sample came out as 1000, and the next
nibble is −3. First the scaling,
(nibble << shift) >> 1:
shift −3 left by 8 places to get −768, then halve it → −384.
Next the prediction: filter 1 contributes about 15⁄16 of the previous
sample, ⌊1000 × 15⁄16⌋ = 937. Add them:
937 − 384 = 553. That's the reconstructed
16-bit sample — sixteen of those little sums and the block is done.
Two header flags finish the picture. END marks the last block of a sample; LOOP, when set on that final block, tells the hardware to jump back to a loop point instead of going silent (Module 10). One subtlety hides there: filters 1–3 lean on samples decoded before the block, so the block at the loop point should use filter 0 (or data crafted so the history matches), otherwise the first pass and every repeat through the loop decode slightly differently and the joint clicks — we'll see the loop machinery in Module 10. The whole scheme lands around a 3.5 : 1 squeeze — 32 bytes of PCM become 9 bytes of BRR.
The lab actually runs a BRR codec. It synthesises a short plucked waveform, encodes it to real 9-byte blocks (brute-forcing the best filter and shift per block, exactly as tools like BRRtools do), then decodes and plays it back. Compare the source with the decoded version — the loss is audible but small — and inspect the block headers.
- ADPCM stores a prediction plus a small correction, not the full sample — cheap and compact.
- BRR = 9-byte blocks of 16 samples: 1 header + 8 data bytes of 4-bit nibbles.
- The header holds a 4-bit shift, a 2-bit filter select, and LOOP + END flags; four filters reconstruct from the previous 1–2 samples.
Envelopes — shaping a note over time
A real note isn't a steady blast — its loudness changes from the moment it starts to the moment it dies away. That loudness-over-time curve is the envelope, and it matters as much as the waveform. The very same tone with a slow, swelling envelope becomes a string pad; with a sharp attack and quick decay it becomes a plucked harp. Envelope is character.
The classic way to describe an envelope has four stages, abbreviated ADSR:
- Attack — how quickly the note fades in to full volume when it starts.
- Decay — how quickly it then falls back to a held level.
- Sustain — the held level while the note is still on. (This is a loudness, not a time.)
- Release — how quickly it fades to silence once the note is let go.
Strike a piano key hard and the sound leaps up (attack), settles back a little (decay), and hums at a steady level as long as you hold the key (sustain). Lift your finger and it fades out (release). A pipe organ has an almost instant attack and a sustain that never droops; a plucked string has a fast attack and no sustain at all. Same four stages, different settings.
Draw an envelope with the sliders below and hear it applied to a live tone. Watch how the same sawtooth becomes a pluck, a pad, or a stab depending only on the four numbers. In Part II you'll set these exact stages on the S-DSP's hardware envelope registers (Module 11).
- An envelope is a note's loudness shaped over time; ADSR = Attack, Decay, Sustain, Release.
- Sustain is a level (how loud while held), not a duration.
- The same waveform with different envelopes becomes different-sounding instruments.
Playing at any pitch
A game can't store a separate recording for every note; there isn't the RAM. Instead it stores one sample and plays it back faster for a higher pitch or slower for a lower one. You already know this trick from tape decks: run the tape fast and a voice turns squeaky and chipmunk-like; run it slow and it drops to a growl. Changing a recording's playback speed changes its pitch. Reading a stored waveform at a new speed is called resampling, and it's the beating heart of a sample-based sound chip.
The catch: to play back faster you need sample values between the ones you stored — at fractional positions like “sample 4.63.” You have to make up those in-between values, and how you do it is called interpolation. The crudest method, nearest-neighbour, just grabs whichever stored sample is closest — cheap, but it produces a jagged, aliased buzz. Linear interpolation draws a straight line between the two neighbours — better, but corners in the signal still add grit.
The SNES uses something nicer: a 4-point Gaussian interpolation. For each fractional position it takes the four nearest stored samples and blends them with weights read from a fixed Gaussian-shaped table baked into the chip — a 512-entry table on the real silicon, which the lab below stands in for with a smooth Gaussian approximation (the same shortcut its code comments admit to). The result is smooth, and it gently rolls off the highest frequencies — which, along with the 32 kHz output, is the other half of why the SNES sounds so soft and round. Play the same bright sweep through nearest and Gaussian and the difference is immediate.
The resample speed is set by a per-voice 14-bit register,
VxPITCH. A value of $1000 means the DSP
consumes exactly one stored sample per output sample — the
data is read at the output rate of 32 000 samples per second.
Double it to $2000 and the DSP steps through two stored
samples per output sample: an octave up. VxPITCH's slot in
the register table arrives in Module 09; the interpolation hardware
behind it in Module 12.
- Resampling = playing one stored sample faster or slower to change its pitch.
- Faster playback needs invented in-between values — that's interpolation.
- Nearest is buzzy; the SNES's 4-point Gaussian is smooth and rolls off the highs (its warm sound).
Echo, reverb & filters
The last big idea before the hardware is space. A sound in a room reaches your ear directly, then again a moment later after bouncing off the walls, and again and again, each bounce quieter. Recreate that and a dry, flat sample suddenly sits in a cathedral. It's built from three simple parts.
The first is a delay line: a short memory that holds the sound and plays it back a set number of milliseconds later. One delay gives you a single echo. The second is feedback: route the delay's output back into its own input, scaled down, and the echo repeats — each pass quieter than the last — until it fades. Many overlapping, decaying echoes blur into reverb.
The third part is a filter. Real walls absorb high frequencies more than low ones, so each echo should come back a little duller than the last. A filter does exactly that. The most flexible kind is an FIR filter, which builds each output sample as a weighted sum of the last few input samples; the weights are called taps. Choose the taps and you choose the filter's colour. The SNES bakes exactly this into its echo hardware — an 8-tap FIR — which we'll design in Module 13.
“Weighted sum” sounds fancier than it is. Take a 3-tap FIR with
taps 0.5, 0.3, 0.2, and suppose the three most recent input
samples were 10, 20, 40 (newest first). The output sample is
0.5 × 10 + 0.3 × 20 + 0.2 × 40 =
5 + 6 + 8 = 19. That's the whole
algorithm: multiply each recent sample by its tap, add, slide forward one
sample, repeat — 32 000 times a second.
- An echo is a delay line; feedback makes it repeat and decay.
- Many overlapping decaying echoes blur into reverb — a sense of space.
- An FIR filter is a weighted sum of recent samples (taps); it colours each echo. The SNES uses an 8-tap FIR.
The SNES sound hardware
Now we meet the silicon. The Super Nintendo's audio is handled by a near-independent little computer, the Sony S-SMP, wired to the S-DSP mixer. Every idea from Part I is about to become a register: BRR blocks in RAM, eight hardware voices, ADSR and GAIN envelopes, a 14-bit pitch, the 4-point Gaussian, and an echo unit with an 8-tap FIR. We'll go block by block — and every lab drives the real register names and addresses.
The S-SMP & the SPC700
Here's the surprise that defines SNES audio: it isn't a peripheral, it's a whole second computer. Sony's S-SMP package — often just called the APU, the Audio Processing Unit — contains its own CPU, its own memory, its own boot ROM, and the sound mixer, all running on a separate crystal. The main SNES CPU can't reach into it directly at all.
Inside the S-SMP:
- The SPC700 — an 8-bit CPU running at roughly 1.024 MHz, with a small, quirky instruction set of its own.
- 64 KB of private audio RAM (ARAM) — the SPC700's entire world: driver code, the sample directory, all BRR samples, and the echo buffer share this one space.
- Three timers the driver reads to keep musical time — T0 and T1 tick at 8 kHz, T2 at a finer 64 kHz.
- A 64-byte IPL boot ROM that runs at power-on and knows how to receive an upload.
- The S-DSP (next module), which does the actual sample decoding and mixing.
$2140–$2143 on the CPU side, the same latches as $F4–$F7 on the SPC700 side.
Before the handshake, one thing is worth pinning down: what does
“writing to $2140” physically mean? Not
every address in a computer is RAM. Some addresses are wired straight to a
chip instead — store a byte there and it lands in a
register,
a byte-sized cell of the hardware itself. This is
memory-mapped I/O: the CPU talks to other chips with the
same store instructions it uses for memory, just at special addresses. The
four mailbox ports are
latches
— each simply holds the last byte one side wrote until the other side gets
around to reading it. And the driver we keep mentioning is
not hardware at all: it's a program, the piece of SPC700 code that reads
those mailbox bytes and turns them into music. It gets a module of its own
(Module 14).
All communication squeezes through those four mailbox ports. At power-on the main CPU can't just poke samples into ARAM; it has to hand them over through a handshake with the IPL boot ROM. The CPU uploads a sound driver plus all the BRR samples, tells the SPC700 where to start, and from then on the APU runs on its own — the game only sends short note events (“play sample 5 at this pitch”) whenever the music demands. Step through that boot handshake below.
- SNES audio is a near-independent computer: SPC700 CPU + 64 KB ARAM + timers + IPL ROM + the S-DSP.
- Main CPU and APU share only a 4-byte mailbox —
$2140–$2143(CPU) /$F4–$F7(SPC). - The CPU uploads a driver and samples via the IPL boot handshake, then the APU plays on its own.
The S-DSP & its 8 voices
The S-DSP is the part that actually makes sound. It runs eight independent voices, and every voice is a little assembly line: it reads a BRR sample from ARAM, resamples it to the wanted pitch (the Gaussian of Module 06), shapes it with an envelope (ADSR or GAIN), and scales it by a left and a right volume. All eight results are summed and pushed out as one 16-bit stereo pair, 32 000 times a second.
The S-DSP is controlled entirely through a 128-byte register
file, addressed $00–$7F. It's laid out
cleverly: the low nibble of the address picks a field, the high nibble picks
the voice, so each voice gets a tidy 16-byte row. Per voice you get:
| Register | Address (voice x) | What it does |
|---|---|---|
| VxVOL L / R | $x0 / $x1 | left and right volume for the voice (signed) |
| VxPITCH | $x2 / $x3 | 14-bit resample rate — the pitch |
| VxSRCN | $x4 | which sample to play (index into the directory) |
| VxADSR1/2 | $x5 / $x6 | the ADSR envelope settings |
| VxGAIN | $x7 | the alternative GAIN envelope mode |
| VxENVX / VxOUTX | $x8 / $x9 | read-back: current envelope level and output |
Those volumes being signed is not a technicality. A negative volume flips the waveform upside down — it inverts its phase (Module 01). Set a voice's left volume positive and its right volume negative and the two speakers push and pull in opposition, a trick games leaned on for wide, pseudo-surround effects.
The rest of the file is global: KON/KOFF
key voices on and off (one bit each), FLG holds mute/reset,
the noise clock and the echo-write-enable bit ECEN
(remember it — it matters in Module 13), MVOLL/R and
EVOLL/R are the master
and echo volumes, PMON/NON/EON enable
pitch-modulation, noise and echo per voice, DIR points at the
sample directory (Module 10), ESA/EDL place the echo
buffer and EFB ($0D) sets its feedback (Module 13),
C0–C7 are the echo FIR taps, and the read-only
ENDX ($7C) reports which voices have reached their
sample's END block.
Toggle the eight voices below and hear them sum.
- The S-DSP mixes 8 voices — each source → pitch → envelope → L/R volume — into 32 kHz stereo.
- A 128-byte register file (
$00–$7F) controls it: 16 bytes per voice plus global registers. KON/KOFFstart and stop voices;MVOLsets the master volume.
BRR samples & the sample directory
A voice's VxSRCN register just says “play sample
number 5.” How does the DSP turn that number into an address in
ARAM? Through a lookup table called the sample directory.
The global DIR register holds the high byte of where that
table lives, and each entry is four bytes: a start pointer
and a loop pointer, both 16-bit. VxSRCN is
simply the index into it.
VxSRCN = 5 indexes the directory at DIR×$100; entry 5 (at DIR×$100 + 5×4) holds two 16-bit pointers. Decoding starts at start and walks 9-byte BRR blocks until the END flag; with LOOP also set, playback bends back to the loop pointer — usually mid-sample, past the attack.
So keying a voice on does this: read VxSRCN, jump to
DIR's table, pull out the start and loop addresses for that
entry, and begin decoding BRR blocks from the start address. The hardware
walks block after block until it hits one with the END
flag set. What happens next depends on the LOOP flag in
that same header:
- END set, LOOP clear — the voice goes silent. This is a one-shot: a drum hit, a footstep.
- END set, LOOP set — the voice jumps to the loop pointer and keeps decoding. This is how a half-second recording of a violin sustains for as long as the note is held.
That loop pointer usually lands partway into the sample — a short attack plays once, then a small steady-state section repeats forever. It's the single most important trick for fitting real instruments into 64 KB. The lab decodes a real looping BRR sample and lets you play it once or hold the loop.
DIRpoints at a table of {start, loop} pointers;VxSRCNindexes it.- The DSP decodes BRR blocks from the start pointer until it sees the END flag.
- END + LOOP jumps to the loop pointer, so a tiny sample can sustain indefinitely.
ADSR & GAIN on hardware
Module 05 drew envelopes as smooth curves. On the S-DSP an envelope is a handful of bits, and there are two ways to make one. The first is hardware ADSR, packed into two registers per voice:
| Register | Bits | Field |
|---|---|---|
VxADSR1 ($x5) | bit 7 | 1 = use ADSR (0 = use GAIN instead) |
| bits 6–4 / 3–0 | decay rate (3 bits) · attack rate (4 bits) | |
VxADSR2 ($x6) | bits 7–5 | sustain level (3 bits, in eighths) |
| bits 4–0 | sustain rate (5 bits) — how fast the level sags from the sustain level while the key is held |
The rates aren't times in milliseconds — they're indices into a fixed rate table in the chip. A higher attack rate means a faster attack; the fastest is nearly instant, the slowest takes several seconds. A few real rows to calibrate your ear: attack rate 15 is effectively instantaneous and rate 14 takes about 6 ms, while attack rate 0 crawls up over ~4.1 s; the fastest decay (rate 7) falls in ~37 ms; sustain rate 31 fades in ~18 ms while sustain rate 1 takes a glacial ~38 s. Attack rises linearly; decay and the sustain phase fall exponentially, which is why SNES notes taper so naturally. Sustain rate 0 is special: it means “hold the sustain level forever,” used for organ-like tones.
One naming trap if you're mapping this back onto Module 05's ADSR: the
sustain rate is not the release. It governs how the
envelope keeps sagging from the sustain level while the key is still
held. So where did the “R” go? It happens at
key-off: when the driver clears the voice via
KOF, the chip ignores the sustain rate entirely and applies
one fixed release for every voice — a linear ramp down of 1⁄256 of
full scale per output sample, so even a full-volume note reaches silence in
about 8 ms. On this chip the release isn't programmable at all.
ADSR1 packs the enable bit, decay rate and attack rate; ADSR2 packs the sustain level and the sustain rate — which shapes the slow sag while the key is held. The release is not in either byte: key-off always triggers the same fixed linear ramp (right panel).
The alternative is GAIN mode (bit 7 of ADSR1 cleared).
GAIN gives the driver hands-on control: a direct mode sets the
level outright, and four ramp modes slide the level:
linear increase, bent-line increase
(rises linearly, then eases off for the final quarter),
linear decrease, and exponential
decrease.
Drivers use GAIN for effects ADSR can't express, like a slow fade-in or a
custom multi-stage envelope. Either way, the chip exposes the current
envelope level in the read-only VxENVX register (0–127) — the
ENVX readout the lab tracks live.
VxADSR1/2pack attack rate, decay rate, sustain level and sustain rate into bit-fields (rates are table indices, not times).- Sustain rate applies while the key is held; key-off (
KOF) always uses the same fixed linear release ramp of −1/256 per sample. - Clearing ADSR1 bit 7 switches to
VxGAIN: direct level, or four ramps — linear increase, bent-line increase, linear decrease, exponential decrease. VxENVXreads back the current envelope level (0–127) at any instant.
Pitch, Gaussian interpolation & modulation
Back in Module 06 we heard why interpolation matters. Here's how the
S-DSP actually does it. For each output sample the chip needs a value at a
fractional position between stored samples. It takes the
four nearest stored samples — two behind, two ahead — and
multiplies each by a weight read from a fixed 512-entry
Gaussian table, indexed by the fractional part of the
voice's accumulating pitch counter — the running position that
grows by VxPITCH every output sample. (VxPITCH
is the step size; the counter's fraction is where the read head currently
sits between two stored samples.) Sum the four weighted taps and that's
the output.
Drag the position below and watch the four active taps slide along the
stored samples, their weights (g0…g3) shifting as the read
head moves. Because the Gaussian is broad and smooth, it quietly attenuates
the highest frequencies — the mathematical root of the SNES's soft treble.
Two more features ride on the pitch machinery.
Pitch modulation (PMON) lets voice
N's output continuously bend the pitch of voice N+1 — a
cheap way to make growling, vibrato-rich, or metallic sounds without extra
samples. (Voice 0 is the exception: it has no lower-numbered neighbour to
listen to, so its PMON bit does nothing.) And the noise generator (NON)
replaces a voice's sample with pseudo-random noise, clocked at a rate set
in the FLG register — the source of wind, surf, cymbals and
explosions. Both are per-voice enable bits, so a game can mix tonal voices,
a modulated voice and a noise voice in the same eight.
PMON bit routes the previous voice's output (OUTX) into its pitch. Voice 0 has no previous voice, so its bit is dead — modulator pairs start at V0→V1.- The S-DSP resamples with a 4-point Gaussian: four taps weighted by a fixed table indexed by the pitch counter's fractional part.
- The Gaussian's smoothness rolls off highs — the technical reason for the SNES's warm tone.
PMONlets one voice modulate the next voice's pitch;NONswaps a voice for the noise generator.
The echo unit & the 8-tap FIR
The lush reverb in so much SNES music comes from one dedicated block: the
echo unit. It's the delay-feedback-filter machine of
Module 07, built into the chip. The delay lives in a circular
echo buffer inside ARAM: the ESA register
sets its start page and EDL sets its length in 16 ms
steps, from 0 to 15 — so the longest possible echo is
15 × 16 = 240 ms. (EDL = 0
is a special case: the buffer doesn't vanish but shrinks to a token
4 bytes.) The price is concrete: at 32 000
samples/s in 16-bit stereo, 240 ms of delay is
240 ms × 32 000 × 4 bytes ≈
30 KB — nearly half of the 64 KB of ARAM, gone
from the space the samples live in. Because the buffer sits in the same
64 KB as the samples, a long echo
eats memory the samples could have used — a constant trade-off for SNES
composers.
EFB) into the buffer again, and by echo volume (EVOL) into the final mix.
Each pass through the buffer is scaled by the feedback register
EFB before being written back — that's what makes the echo
repeat and decay. And crucially, on the way out the echo signal runs
through an 8-tap FIR filter whose coefficients are the
global registers C0–C7. Those eight signed taps
let the driver shape the echo's tone: a gentle low-pass for a warm hall, or
odd taps for a metallic ring. Design the filter below — set the eight taps,
the delay and the feedback — and hear the reverb while the tap stems and the
filter's frequency response plot update live.
- The echo buffer lives in ARAM:
ESAsets its start,EDLits length — it competes with sample data. EFBfeeds the echo back on itself (decay);EVOLmixes it into the output.- An 8-tap FIR (
C0–C7) colours the echo return — the SNES's signature tunable reverb.
Mixing it all & music drivers
Follow one sample through to the speaker. Each of the eight voices is
scaled by its VxVOL left and right, summed, and multiplied by
the master volume MVOLL/R. In parallel, the echo return is
scaled by EVOLL/R and added in. The result is clamped to 16
bits and clocked out as the stereo pair, 32 000 times a second. That's
the whole output stage — a handful of multiplies and adds, done in
hardware.
VxVOL → Σ → × MVOL. Echo path below: EON-selected voices are written into the ARAM echo buffer, come back through the 8-tap FIR, feed themselves back via EFB, and join the mix through EVOL. The sum is clamped to 16 bits and clocked out at 32 kHz.
But the S-DSP has no idea what a “song” is. It only knows
registers. Turning sheet music into register writes is the job of a
music driver — a program running on the SPC700 that the
game uploaded at boot. Every musical tick it reads a sequence of note
events and translates them: load VxSRCN and VxPITCH
for the instrument and note, set the volumes, choose an envelope, then write
a bit into KON to key the voice on. Timers keep the tempo.
Different studios wrote different drivers. Nintendo's own is often called
the N-SPC / Kankichi engine (heard across first-party
games); Rare, Konami, Square and others shipped their own, each with its
own effects and sequence format. They all boil down to the same loop:
read events → write DSP registers → wait for the timer. The lab is
a tiny four-voice tracker doing exactly that — toggle steps and each active
cell fires a KON write on the beat.
KON write on that step. Edit while it plays.
- Final mix = Σ(voice × VxVOL) × MVOL, plus echo × EVOL, clamped to 16-bit, at 32 kHz.
- A music driver on the SPC700 turns note events into register writes and keys voices with
KON. - Studios wrote their own drivers (Nintendo's N-SPC and many others) over the same DSP.
Emulating the chip
To hear SNES music on a modern machine, an emulator has to recreate two synchronised computers cycle by cycle — and then package the result so you can share a song as a tiny file. These last two modules cover the timing problem at the heart of accurate SNES audio emulation, and the SPC file format that lets a fixed 66,048-byte download — barely more than the 64 KB of ARAM it wraps — play a full track.
Emulating the SPC700 + DSP
An emulator that wants SNES music to sound right can't fake the audio chip — it has to run it. That means two problems at once. First, there are two crystals: the main system runs at 21.477 MHz while the S-SMP runs off its own ~24.576 MHz crystal (divided down to the SPC700's ~1.024 MHz). A quick word on the unit hiding in “MHz”: a CPU cycle is a single tick of a chip's clock, the smallest step in which it can do any work, and megahertz just counts millions of those ticks per second. The two clocks here aren't in any tidy ratio, so the emulator must interleave them carefully; let them drift and the mailbox handshake from Module 08 breaks, and games hang waiting for an APU that answered a beat too early or too late.
Second is the CPU↔APU sync problem. Because games poll the mailbox in tight timing loops, an accurate emulator has to switch between emulating the main CPU and the SPC700 the instant either touches a shared port — sometimes cycle by cycle. Get it slightly wrong and you get missing music, stuck notes, or a boot that never completes.
On top of timing sit the fiddly details of the DSP itself: the exact 512-entry Gaussian table, the precise integer maths of the four BRR filters, and edge cases like what a shift value above 12 does or how the very first block behaves. Getting these bit-exact took years of reverse engineering. Much of it crystallised in blargg's SPC_DSP core — a compact, bit-accurate C++ implementation. snes9x uses that core directly, and bsnes' own DSP is derived from the same core and the research behind it — which is why the two agree down to the sample. The lab steps an SPC700 driver snippet as it writes a voice's volumes and keys it on — the fetch/execute cycle an emulator runs millions of times a second.
Reading the listing: in MOV X, #$4C the # means “this literal number” — copy the value $4C itself into register X. Without #, as in MOV $F2, X, the operand is an address: X's value is stored to location $F2. Everything after ; is a comment for humans.
- SNES audio accuracy means running two crystals in lock-step (21.477 MHz vs the SMP's ~24.576 MHz → 1.024 MHz).
- The CPU↔APU mailbox is polled in tight loops, so the emulator must sync the two cores tightly.
- blargg's SPC_DSP core — used directly by snes9x, and the basis for bsnes' derived DSP — nails the Gaussian table and BRR-decode edge cases.
SPC files & try it
Here's the elegant payoff of the two-computer design. Because the whole song lives inside the APU — driver, samples and all — you can capture a track by freezing the APU's entire state. That snapshot is the SPC file format, and it's small and rigidly fixed in size: a 256-byte header carrying the SPC700's CPU registers and the ID666 metadata tags (song title, game, composer, length — the same idea as an MP3's ID3 tags), then a full 64 KB dump of ARAM, the 128 bytes of DSP registers, and a few spare bytes: 66 048 bytes, every time. No rendered audio is stored — the ARAM dump does contain the BRR-compressed samples, but the finished waveform the console would output is nowhere in the file. It's the machine itself, paused mid-song.
An SPC player is therefore not really a player of audio; it's a mini SNES
with only the sound half. It loads the 64 KB into an emulated ARAM,
restores the DSP registers and SPC700 state, and simply lets the
frozen driver keep running from exactly where it was captured. The
music resumes because the driver picks up its own sequence data and carries
on writing KONs — the same loop from Module 14, thawed. This is
why a 66,048-byte file can play minutes of music: you're shipping the
program and its instruments, not the performance.
Want to go further? Grab bsnes or
snes9x, load a game you own, and open the audio
debugger to watch the eight voices and DSP registers change in real
time. Or open an .spc in a player and mute voices one by
one — you'll hear the exact eight-voice split from Module 09. Everything
in this course is right there on screen.
One last thing: a quick exam. Six questions, each pointing back at the module that answers it.
- You can read the signal path from a pressure wave — Module 01 — all the way to 32 kHz stereo.
- You know the SNES stores sound as BRR, plays it on 8 Gaussian-interpolated voices, and shapes it with ADSR/GAIN and an 8-tap echo FIR.
- You understand why one little Sony computer, frozen into a 64 KB SPC file, can replay a whole song.