Skip to content

Beeper Music

Tunes and chords from the 48K ZX Spectrum's one-bit speaker

The 48K Spectrum has no sound chip: the processor makes every note by flipping one bit of port $FE at the right moments. Its manual said that meant one note at a time. Within a few years programmers were playing continuous in-game tunes and three-voice chords through the same bit.

The ZX Spectrum manual was honest about the machine’s sound. “Because there is only one loudspeaker in the computer you can only play one note at a time,” Steven Vickers wrote, “so you are restricted to unharmonized tunes. If you want any more you must sing it yourself.”

Five years later Your Sinclair printed a type-in listing that played three-part music through that same loudspeaker. It was by the composer Tim Follin, and the magazine called it “this amazing three-channel sound routine”. A reader wrote in to say it “was a joy to hear”. Beeper music is the story of how Spectrum programmers got from the manual’s one note to that: continuous tunes under a moving game, then chords, all from a speaker that can only be switched on or off.

One bit and a processor

The 48K Spectrum has no sound chip. Chris Smith, who reconstructed the Spectrum’s ULA from its silicon, puts it plainly: the machine “does not incorporate a dedicated sound generation device, but instead makes use of a software oscillator that alters the logic state of a single bit output port at varying frequencies.” That bit is bit 4 of port 254 ($FE). The manual lists the port’s jobs in one line: it “drives the loudspeaker (D4) and the MIC socket (D3), and also sets the border colour (D2, D1 and D0).”

To make a note, a program switches bit 4 on and off at the note’s frequency. Each switch moves the speaker cone one way or the other, so the program is the oscillator: it has to count out the time between switches itself. Ian Logan and Frank O’Hara’s Complete Spectrum ROM Disassembly works through middle C, 261.63 Hz. The speaker must be switched every 1/523.26th of a second, so on a 3.5 MHz Z80 “the requisite OUT instruction be executed as close as possible to every 6,689 T states” (a T-state is one tick of the processor clock).

Because the same port also sets the border, every write to the speaker writes the border colour too. The ROM’s routine reads the current border colour from the system variables before it starts and puts it back in every byte it sends, so the border stays still while the speaker moves.

BEEP, and the ROM routine behind it

In Sinclair BASIC, BEEP duration, pitch plays one note: “the duration is given in seconds, and the pitch is given in semitones above middle C”. The manual’s worked example is the funeral march from Mahler’s First Symphony. It is also frank about the sound’s limits. The lowest notes “just sound like clicks; in fact the higher notes are also made of clicks in the same way, but faster, so that the ear cannot distinguish them”, and “only the middle range of notes are really any good for music”.

BEEP hands the work to the ROM’s BEEPER routine at address $03B5. It takes the number of cycles to play in DE and the length of its timing loop, divided by four, in HL. It spins in that loop, flips bit 4 with XOR $10, writes the port, and repeats until the cycles run out. Its first instruction is DI, to “disable the interrupt for the duration of a ‘beep’”. The Spectrum interrupts itself fifty times a second to scan the keyboard, and an interrupt arriving mid-note would add its own running time to one half-cycle and knock the note off pitch. So while a note plays, the processor does nothing else.

Music under a moving game

That is the problem every Spectrum game with music had to solve. A tune needs the processor to count out every half-cycle; a game needs the processor for everything else.

Matthew Smith’s Manic Miner (1983) played Grieg’s In the Hall of the Mountain King all the way through the game. Personal Computer News found “the graphics and sound are both superb”, and noted that “if the constant playing of Hall of the Mountain King starts to annoy you the writer has thoughtfully provided an on-off switch”.

Smith explained the method to Sinclair User in December 1984, talking about Jet Set Willy, whose music “plays continuously throughout the game” and “does not use an interrupt”. “The first instruction in the program is ‘disable all interrupts’,” he said. “It’s just move-a-tiny-little-bit, BEEP-a-tiny-little-bit. Have you noticed, the more lives you lose, the worse the music gets?” Game and tune take turns in one loop, a little of each. The magazine doubted anyone had noticed the effect, and it did not think much of the music either: “unutterably disgusting anyway, a maniac, stunted version of If I Were A Rich Man, even worse than the original.”

Chords from one bit

One bit cannot be on and off at once, so two notes at once looks impossible. The way round it is to stop thinking in square waves and send the speaker short pulses instead.

The Follin routine that Your Sinclair printed in August 1987 shows how. It is 1,340 bytes, loaded at address 40000, and its first byte is DI. Disassembled, its inner loop keeps a countdown for each of three voices in the registers H, L and D. Every pass through the loop subtracts one from each. When a voice’s count reaches zero, the routine sends one pulse to the speaker and reloads the count with that voice’s pitch from the tune. The block for the first voice is:

Z80 assembly
        dec  h              ; count down voice 1
        jr   nz,voice2      ; not zero yet: go on to voice 2
        xor  a
        out  ($fe),a        ; speaker bit low...
        ld   b,c
w1:     djnz w1             ; ...for C loops
        ld   a,$10
        out  ($fe),a        ; speaker bit high again...
        sub  c
        ld   b,a
w2:     djnz w2             ; ...for 16-C loops, so every pulse takes the same time
        ld   h,(ix+0)       ; reload voice 1's pitch
voice2: dec  l              ; the same again for voice 2, then voice 3

A voice with a small count pulses often and sounds high; one with a large count pulses rarely and sounds low. The three pulse trains share the speaker, and the ear hears three pitches. The pulse width C does the rest. A narrow pulse sounds quieter than a wide one, and the routine does not keep C fixed: as each note plays it widens the pulse step by step, then narrows it back to a resting value, so every note swells and fades. That is a volume envelope made from nothing but timing.

The listing’s own blurb was already promising more. Follin was “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!”

Two-voice music had been available to non-programmers for some time. CRASH’s September 1986 review of Mark Alexander’s The Music Box for Melbourne House described the 48K version of its predecessor, Wham! The Music Box: it “uses the Beep command split by a routine to create a duophonic effect and has some options for adding percussive noise”. By 1993 the question had reached Sinclair User’s help column. A reader asked how “games like Ocean have three channel music on them”, and Specman answered: “it only sounds like three channel music. The Speccy beeper is in fact still only one channel.”

Every T-state counts

A beeper routine’s pitch is its timing, so anything that changes the timing changes the music. Three things can:

  • Interrupts. The routines above switch them off, like the ROM does.
  • Uneven paths. In the Follin loop, the 16-C wait keeps each pulse the same length whatever its width. But a pass in which a voice fires still takes longer than one in which none does, so the voices nudge each other’s pitch slightly.
  • Contended memory. While the ULA is fetching the picture, it stops the Z80’s clock whenever the processor touches addresses 16384 to 32767, in Smith’s account. Code running there would run at a speed that changes as the screen is drawn, fifty times a second. The ROM’s BEEPER runs from ROM, and Follin’s routine loads at 40000, both outside that block. Smith also shows the ULA with a separate I/O contention handler, and port $FE is the ULA’s own port.

What players heard

Players noticed. CRASH’s January 1986 review of Mike Follin’s Vectron (Insight) rated the sound “fab — great when amplified”, a reminder that the internal speaker was quiet: the same Sinclair User issue that carried the Matthew Smith interview advertised add-ons that included a “beep amplifier”.

In February 1987 a reader from the Netherlands, Frank Bouts, wrote to CRASH asking why more games did not sound good: “if there are tunes like those from Ping Pong, and Vectron to name but two, why can’t every game have such good tunes?” He added: “I own a 128K and I can’t make tunes like Ping Pong even with my sound chip.” Lloyd Mangram replied that “considering the limitations posed by the BEEPer, there have been some excellent multi-channel simulations and sound definitely adds to a game.”

Follin’s reputation was made this way. Your Sinclair introduced him in 1987 as “the man behind the tunes on Mastertronic’s Agent X, and Firebird’s spectacular Sentinel”. When it reviewed Agent X II in January 1988 it found the game, like Software Creations’ Agent X and Chronos before it, “looks and sounds marvellous (a good tune by Tim Follin) but falls down on gameplay”. The music was worth mentioning even when the game was not.

The technique outlived the commercial market. In May 1993 Your Sinclair reviewed Bicie, by Simon Tillson, a “48K music synthesiser that allows you to write three-channel tunes using only the Speccy beeper”.

Beeper and AY

The Spectrum 128, and the +2 and +3 after it, added a General Instrument AY-3-8912 sound chip, which plays three channels by itself while the processor gets on with the game. Mangram greeted it in the same letters page: “At last Spectrum sound comes into its own with the advent of the Spectrum Plus Two.” Composers wrote for both. CRASH praised “Tim Follin’s 128K music” on Psycho Pig UXB in June 1988. But games were still sold for 48K machines, and on those the beeper and the processor’s timing loop were the only way to play a tune.

For a working melody player and a two-voice mixing loop, see the Beeper Music pattern.

Sources

  • Steven Vickers, Sinclair ZX Spectrum BASIC Programming (Sinclair Research, 1982): chapter 19, pp. 135–137, BEEP, the Mahler example, “one note at a time”, clicks and the useful range; chapter 23, p. 160, port 254.
  • Ian Logan and Frank O’Hara, The Complete Spectrum ROM Disassembly (Melbourne House, 1983), “The loudspeaker routines”: middle C and 6,689 T-states; the BEEPER routine at 03B5, its DI, the border colour taken from BORDCR, and XOR +10; the maskable interrupt every 20 ms.
  • Chris Smith, The ZX Spectrum ULA: How to Design a Microcomputer (ZX Design and Media, 2010): no dedicated sound device, the speaker output (ch. 19, p. 215); memory and I/O contention (ch. 18, pp. 190, 197).
  • Personal Computer News, 11–17 August 1983, p. 48: Mike Gerrard’s review of Manic Miner.
  • Sinclair User, issue 33, December 1984, pp. 89–90: “Hit Squad” profile of Matthew Smith and Software Projects; the same issue’s advertisements for add-ons with a beep amplifier.
  • CRASH, issue 24, January 1986: Vectron review.
  • CRASH, issue 32, September 1986: review of The Music Box (Melbourne House, author Mark Alexander).
  • CRASH, issue 37, February 1987, p. 42: “Sounding Off”, letter from Frank Bouts and reply by Lloyd Mangram.
  • Your Sinclair, issue 20, August 1987: Program Pitstop, Tim Follin’s three-channel routine with its hex dump.
  • Your Sinclair, issue 23, November 1987: reader’s letter on the Follin routine.
  • Your Sinclair, issue 25, January 1988: Agent X II review.
  • CRASH, issue 53, June 1988, p. 96: Psycho Pig UXB review.
  • Your Sinclair, issue 89, May 1993, p. 7: Bicie.
  • Sinclair User, issue 131, January 1993: Specman’s answer on three-channel beeper music.

See also

Checked. Verified against primary sources and signed off by a person.