Beeper Music
Single-channel melody on the Sinclair ZX Spectrum's one-bit speaker
How the 48K Spectrum's single speaker bit produced continuous in-game tunes and three-voice harmony: Matthew Smith's interleaved game loop, Tim Follin's multi-channel routines, and what they cost the rest of the program.
The 48K Sinclair ZX Spectrum has no sound chip. It has one bit — bit 4 of port $FE (254) — wired to a small internal speaker, the beeper. The manual lists the port’s output duties in one line: it “drives the loudspeaker (D4) and the MIC socket (D3), and also sets the border colour”. The ROM disassembly describes the mechanism: the speaker “is activated by having D4 low during an OUT instruction that is using port ‘254’. When D4 is high in a similar situation the loudspeaker is deactivated. A ‘beep’ can therefore be produced by regularly changing the level of D4.” Toggle it fast enough and the cone vibrates at half the toggle rate.
That is the whole instrument. Everything the Spectrum’s music did in its first four years — continuous in-game tunes, two- and three-voice harmony, drum sounds — came from a program deciding, several thousand times a second, whether that bit should be high or low.
How a tone works
To produce a tone at frequency f Hz, the program toggles the bit 2f times a second. The ROM’s own worked example is middle C: at 261.63 Hz “the requisite OUT instruction be executed as close as possible to every 6,689 T states”. A tone routine spins a delay loop for that many T-states, flips the bit, and repeats.
Sinclair BASIC’s BEEP duration, pitch — “the duration is given in seconds, and the pitch is given in semitones above middle C” — calls the ROM’s BEEPER routine at $03B5. It takes the number of cycles to play in DE and a quarter of the timing-loop length in HL, and its first instruction is DI: the ROM disables interrupts “for the duration of a ‘beep’”, because an interrupt landing mid-loop would stretch a half-cycle and put the note out of tune. That is the constraint every beeper driver inherits. While a note is sounding, nothing else can be allowed to disturb the timing — including the game.
Music while the game runs
The ROM routine plays a note and returns; a game wants a tune and motion. Matthew Smith’s solution in Jet Set Willy is the simplest one, and he described it in Sinclair User in 1984: the music “does not use an interrupt. ‘The first instruction in the program is “disable all interrupts” … It’s just move-a-tiny-little-bit, BEEP-a-tiny-little-bit.’“ The game loop and the tone loop are interleaved by hand, so the game’s own work sits in the gaps between toggles — which is why, as Smith put it, “the more lives you lose, the worse the music gets”: when the game does more between beeps, the timing drifts. Manic Miner runs the same way, with its tune under the whole game.
A monophonic driver needs three things: a note table of half-periods, a song as a list of (note, duration) pairs, and a loop that plays each entry. Tick-based timing — durations counted in frames, the driver advanced from the interrupt — is the natural fit on a machine with a sound chip; on the beeper, where the interrupt has to be off during a note, the driver is usually the main loop.
note_data:
defb NOTE_C4, 4 ; note, duration in ticks
defb NOTE_E4, 4
defb NOTE_G4, 8
defb $FF, 0 ; terminator
Polyphony from one bit
The beeper has one bit, so two notes at once ought to be impossible. Sinclair User’s Specman fielded the question in 1993 — how do “games like Ocean have three channel music on them?” — and gave the honest answer first: “it only sounds like three channel music. The Speccy beeper is in fact still only one channel.”
The trick is interleaving. The driver keeps two or three virtual voices, each with its own phase counter, and advances all of them on every pass through the toggle loop. Whenever any voice’s counter wraps, the speaker bit flips. The combined toggle pattern is a single square wave whose edges come from all the voices at once, and the ear resolves it into chords. Precision is the cost: each pitch is approximate, and close intervals shimmer.
The name attached to this on the Spectrum is Tim Follin. Your Sinclair published one of his routines as a type-in in August 1987 — “This amazing three-channel sound routine is the product of the versatile musical talent of Tim Follin, the man behind the tunes on Mastertronic’s Agent X, and Firebird’s spectacular Sentinel” — and it “begins at 40000 and is a mere 1340 bytes long”. The same page reports him “currently working on a brilliant new routine for 6 channel sound with chorus bass, 128K snare drum, echo on/off/delay time, portamento, and full ADSR”. By then CRASH’s letters page could refer to “some excellent multi-channel simulations” as an established thing.
The cost shows in Ghouls ‘n’ Ghosts (1989), where Follin’s brother Mike wrote the push-scroll. The scroll kept “the processor … uninterruptably tied up for most of the 2-frame game cycle, so music could only be played at a 25Hz rate. Rather than have sub-standard music, it was decided to have 3-channel sound effects in the game and high quality 50Hz music for the front-end pages.” One bit, one CPU: the scroll and the music were competing for the same T-states, and the music lost the in-game slot.
By the platform’s late years the technique had become a tool for other people to use. Simon Tillson’s Bicie, reviewed in 1993, was a “48K music synthesiser that allows you to write three-channel tunes using only the Speccy beeper”.
Beeper and AY
The 128K Spectrum, the +2 and the +3 added an AY-3-8912: three tone channels, a noise generator and envelopes, driven from a register file rather than by the CPU’s timing. The same composers wrote for both — CRASH was praising “Tim Follin’s 128K music” on Psycho Pig UXB in 1988 — but the 48K machine stayed in the market throughout, so a 48K soundtrack remained a requirement, and the beeper driver kept running inside games that also had an AY score.