Sound Effects on the ZX Spectrum: AYFXEdit and BeepFX
A comprehensive exploration of sound effect creation for the ZX Spectrum — from the primitive one-bit beeper to the AY-3-8912 sound chip — including assembly code examples, the history of audio tools, and the author's AYFXEdit and BeepFX editors.
I frequently discuss various sound synthesizers and musical procedures for vintage 8-bit computers and game consoles. Beyond music, games require sound effects — while music establishes atmosphere, effects provide crucial feedback that engages players with on-screen action.
During my work developing for older computers and consoles, I encountered a significant shortage of information and ready-made tools for game audio implementation, forcing me to create my own solutions. I invested considerable time in these developments and produced hundreds of sound effects.
Today I will explain how sound effects function within the primitive audio capabilities of 8-bit machines, specifically the ZX Spectrum, for which I created several editors and procedure sets for both the beeper and the AY-3-8910 sound chip.
The Spectrum's Sounds
The 1982 ZX Spectrum distinguished itself from contemporaries through its low cost but extremely primitive audio hardware. Still, this represented enormous progress — predecessor Sinclair models ZX80 and ZX81 lacked any sound capabilities whatsoever.
First came the beeper — a simple speaker present in all Spectrum versions, controlled directly by the microprocessor through a single output bit. All sound synthesis occurred entirely through software; the processor managed the necessary delays and switched the output bit between 0 and 1 at precise moments. Without hardware timers, accurate timing depended entirely on instruction execution duration. While synthesizing sound, the processor could not perform other tasks, freezing screen action completely.
The AY-3-8912 sound chip later expanded audio possibilities. It appeared almost immediately in 1983 within the Timex Sinclair 2068 (the USA version) and as various add-ons for the standard 48K model. However, incompatible implementations received weak game support. The chip finally became standardized in 1986 with the ZX Spectrum 128K, becoming its standard audio device. The beeper remained, and older games often used both simultaneously — the chip for music, the beeper for effects.
The AY-3-8912 elevated the computer's sound quality to match more advanced systems that also used this chip: the Amstrad CPC, MSX-compatible machines, and even the 16-bit Atari ST. Skilled programmers achieved impressive results with it.
The ZX Spectrum also featured other supplementary audio devices, including additional sound chips, various DACs, and even hardware speech synthesizers — but those are topics for a separate discussion.
Types of Effects
Although the platform offered only two standard audio devices, games contained four distinct categories of effects, each with characteristic qualities. Three involve the beeper — a consequence of architectural peculiarities of the original computer, which came in 16 KB and 48 KB variants.
The first category characterizes early games (1982-1984), mostly designed for the 16 KB version. Here, all RAM experienced "throttling" — periodic brief processor halts when the video controller accessed memory to form the screen image. This complex halt pattern prevented the precise timing necessary for stable-frequency sound synthesis. Consequently, tonal effects on the 16K sounded dirty, mixed with throttling noise.
Processing throttling did not affect ROM, which contained cassette procedures requiring precise delays, plus a basic sound routine used by the BASIC BEEP operator. Early games relied on this ROM procedure for clean tones, which is why sound design often consisted of simple clicks and beeps, and music was always monophonic. The game Cookie exemplified the rich sound achievable within such constraints.
The next two categories emerged when RAM became affordable and developers shifted focus to the 48 KB machines. Most RAM in these models lacked throttling, enabling software synthesis of any desired pitch — including melodies and polyphonic compositions — plus significantly more complex effects.
The second category, the most popular, comprises procedures that consume processor time until the sound finishes playing. These offered superior sound quality and diversity but completely halted screen action. Since lengthy action interruptions were unacceptable for many game types, such effects were typically kept brief and infrequent. Unfortunately, developers rarely demonstrated imagination in sound design; consequently, many Spectrum games sound impoverished and repetitive, with rare exceptions like Earth Shaker.
The third category, less common, involves background beeper effects. Sound generation occurs only during spare time after each frame's rendering, before next-frame synchronization. This approach stabilizes game speed regardless of the number of active game objects while allowing uninterrupted screen action. However, it achieves compromised audio quality: the sound becomes choppy and fragmented. By modern standards, few would accept such a compromise, but those were difficult times. Manic Miner exemplifies this approach.
Finally, the fourth category — AY effects — does not interrupt screen action and supports polyphony. The sound character remains consistent, determined by the chip's capabilities. Occasionally the AY chip hosted digitized audio, which did interrupt game action and music, so applications remained limited. The 128K version of Chase H.Q. featured voice samples using this technique.
Ready-Made Recipes
The fundamental problem with 8- and 16-bit era game sound effects was widespread ignorance about creation methods. Identifying when anyone actually possessed this knowledge is extremely difficult to pin down.
Contemporary platforms offer obvious processes: obtain sample libraries of digitally recorded audio fragments, process them with various programs, perhaps convert formats, and insert them into games.
In earlier times, when computers could not handle samples, everything was fundamentally different. Developers needed an understanding of sound synthesis principles or sound chip characteristics, methods for data preparation, and custom procedures and utilities. 1980s game developers — particularly "bedroom coders" creating games at home after school or work — rarely found time for this. Merely completing the game required substantial effort, so they typically limited themselves to typical procedures copied from one another.
Music implementation in amateur developments received partial solutions by the mid-1980s. Musical editors enabled composition and game insertion. The Music Box program was available for both beeper and AY-3-8912; later, in the early 1990s, Sound Tracker and Pro Tracker became standard solutions for AY-3-8912 music. You could simply compose in the editor, export the binary file including player code, and insert it into your program.
Sound effects fared significantly worse. The topic was not completely neglected — there were occasional press publications and some programs for creating and playing various sounds. But the solutions were primitive.
Sound effect programs fell into two categories. The first included collections of ready-made sound procedures playing predetermined effects — primarily the Supercode and New Supercode package series. The second category focused specifically on sound effect creation: not sophisticated editors, but procedure collections with interfaces for parameter selection and adjustment.
Spec-Sound (1983) allowed creating beeper effects by entering several values: initial tone height, height change speed, repetition count, and so forth. This occurred through a terribly inconvenient BASIC program. Sound Editor (1986), also for the beeper, contained four different effect types and allowed parameter adjustment in a more convenient, though still very slow, BASIC editor.
The celebrated SpeakEasy program (1982) allowed recording digital sound fragments through the cassette input, consuming the computer's entire memory, then playing back with terrible quality. Amusing, but practically useless.
A separate problem was combining music and sound effects. For the beeper, this mattered little since music and effects did not play simultaneously. But for AY-3-8912 music, this was a standard task required in every game — and nobody had solved it properly. Popular music playback procedures simply did not support sound effects, forcing developers to reinvent solutions from scratch.
Even well after the platform's popularity had declined — in the late 1990s and early 2000s — ready-made solutions for adding sound effects to amateur games remained unavailable, and finding any information on the subject was difficult.
Some Code
To better understand the underlying principles, here are code examples showing how basic sound effects work for AY and beeper. Notably, they differ fundamentally in implementation.
Beeper effects typically work as procedures — small subroutines. One effect equals one directly executed processor code fragment, running in the main thread with interrupts disabled. Different sounds require different synthesis algorithms, though often the code is quite similar.
Conversely, sound chip effects (including AY-3-8912) traditionally operate "in the background": the chip state — sound pitch and volume — updates on frame interrupts, fifty times per second, and between updates the chip generates the specified sound while the processor handles other tasks. A single chip state-update procedure serves all effects; only the data set passed to the chip's control registers differs.
The most common beeper effect is what I would call a "chirp" — a rapidly rising tone resembling bird chirping — which appears in thousands of Spectrum games:
ld b,100 ;effect duration
ld a,0 ;initial output bit value
loop1:
out (#fe),a ;output beeper port bit
xor 16 ;invert output bit
push bc ;save loop counter
loop2:
djnz loop2 ;delay loop, iterations equal outer counter
pop bc ;restore counter
djnz loop1 ;execute outer loopThe outer loop iteration count — effect duration — is set in register B. Within the loop, decreasing delay with each iteration raises the tone. Overall tone height is set by code execution speed, ranging from approximately 2,600 Hz initially to roughly 58,300 Hz at the end.
A simple noise impact sound — low, brief, resonant noise — looks like:
ld hl,0 ;initial ROM address
ld b,50 ;effect duration
loop1:
ld a,(hl) ;read ROM byte
inc hl ;increment pointer
and 16 ;isolate beeper bit
out (#fe),a ;output to beeper port
push bc ;save loop counter
ld b,250 ;set delay loop duration
loop2:
djnz loop2 ;execute delay loop
pop bc ;restore counter
djnz loop1 ;execute outer loopThis simply reads ROM contents, isolates the fourth bit, and outputs it. The outer loop determines effect duration; the nested loop determines noise "height."
For AY-3-8910 sound effect implementation, here is a simplified example — functional but lacking effect-music mixing support. It reads data streams for registers and outputs them to the corresponding chip registers each interrupt:
ld hl,sound_data ;effect data initial address
ld (sfx_ptr),hl ;store pointer in variable
;code in frame interrupt handler
ld hl,(sfx_ptr) ;read effect data pointer
loop:
ld a,(hl) ;read byte
cp #fe ;check if effect end
jp z,done ;exit if end marker
inc hl ;advance pointer
cp #ff ;check if frame end
jp z,done ;exit, pointer at next frame
ld bc,#fffd ;AY register selection port
out (c),a ;output register number
ld a,(hl) ;read next byte
inc hl ;advance pointer
ld bc,#bffd ;AY register data port
out (c),a ;output register value
jp loop ;continue reading
done:
ld (sfx_ptr),hl ;save pointer for next frameIt is worth noting why beeper and AY effect sounds differ so distinctly. First, there are timbre differences: the sound chip generates only square waves, while the beeper can produce various signal forms. Second, the speed of change is vastly different: chip effects update at most once per 1/50th of a second, while beeper pitches change with every sound-generation cycle. The simple beeper "chirp" described above could not be reproduced on the AY chip — its pitch glide speed far exceeds the 1/50-second update rate.
AYFX Editor
Though I focus more on beeper topics, I, like many dedicated Spectrum enthusiasts, invested considerable time with the AY-3-8910. My first universal sound effect solution targeted this chip specifically.
The full program name is AY Sound FX Editor, though the executable filename ayfxedit became the project's nickname. I created it in 2006 while developing Ball Quest for ATM Turbo and MSX standard computers.
The package comprises a Windows editor program and assembly language Z80 player source code. The player lacks effect-music mixing support, but I simultaneously created a Pro Tracker 3 (PT3) format music player variant with integrated effect playback.
The editor represents effects as up to 256 single-channel effects, each supporting up to 4,096 frames — approximately 80 seconds per effect. Multi-channel effects are not supported since single-channel typically sufficed; if absolutely necessary, running multiple effects simultaneously works fine.
Each effect frame contains volume, tone height, and noise values, plus tone and noise enable/disable settings, all represented as graphical sliders. Simple mouse movements let you easily create volume, height, or noise changes, building the desired effect while immediately hearing the modifications.
The editor supports importing and exporting from various formats, particularly PSG dumps saved by different emulators — enabling uninhibited sound effect borrowing from MSX and other computer games. VGM format import with data conversion for the SN76489 sound chip is also available.
The basic player implementation uses simple priority: any free channel gets selected; otherwise, the longest-playing effect is replaced. Effect-music mixing handles volume comparison: louder effects override music; otherwise, music sounds through.
Beyond Ball Quest, this engine in various modifications served many games and the Evo SDK project. Over time it gained popularity, with other developers continuing development — including a port to different compilers, a web version, and a NextBASIC library for the ZX Spectrum Next.
BeepFX Editor
The BeepFX beeper effect editor gained less comparable popularity, yet I take greater pride in it since it expanded possibilities and significantly enriched beeper sound, enabling previously unheard sounds on the platform.
I created BeepFX in 2011, after the Magic Tokens and Zombie Calavera games where I had hand-programmed all effects. That experience made clear which tools most benefited sound creation and what the typical solution set of procedure code reduced to.
The editor enables creating banks of 128 different effects, exportable as binary files or assembler listings for direct game insertion. The player code is quite compact, comprising three universal procedures for tone synthesis, noise synthesis, and 1-bit sample playback. Effects are described through parameter sets, significantly economizing memory.
Effects consist of sequential block lists. Four block types exist: tone effects, noise effects, 1-bit digitization playback (reusable across effects), and simple pauses. The editor allows you to hear individual blocks or complete effects through double-clicking in the interface.
Each block type has specific parameters — duration, tone or noise height, height changes over time. Tone blocks include duty cycle and duty-cycle glide; digitizations play at various speeds with different offsets. Often a single block suffices for an effect, yet the block-combining capability creates rich, complex sound sequences.
Certainly, the numerical parameter input lacks the intuitive graphical interface of AYFXEdit, yet effect creation remains learnable through parameter experimentation and studying the included demonstrations, which contain approximately 80 different sounds.
One limitation exists: effects completely halt screen action and cannot operate in interrupt mode like Manic Miner. However, practice showed that even lengthy action interruptions minimally harm gameplay when providing a rich, diverse audio palette — something relatively uncommon on the Spectrum.
I applied BeepFX practically much later, in 2021, when porting Attack of the PETSCII Robots to ZX Spectrum. I created thirty new sounds for that project. With the player code, they consumed just 1,078 bytes — approximately 36 bytes per effect.
Conclusion
One might think the days of reinventing the wheel for early-21st-century technology — particularly regarding 1980s computers — have passed. Yet opportunities emerge more frequently than expected.
This was not my only instance of reinventing musical and audio implementation solutions for vintage computers and consoles that subsequently achieved notable popularity. My FamiTone library for the Famicom (NES, Dendy) console represents another such case, which I will discuss next time.
FAQ
What is this article about in one sentence?
This article explains the core idea in practical terms and focuses on what you can apply in real work.
Who is this article for?
It is written for engineers, technical leaders, and curious readers who want a clear, implementation-focused explanation.
What should I read next?
Use the related articles below to continue with closely connected topics and concrete examples.