Now that the shooting gallery is done and dusted, it’s time to turn to a piece of our initial tour of the ZX Spectrum that has been left untouched: sound. There isn’t a whole lot new here compared to what has come before on other platforms, but that in turn means that the core principles of our solutions to it arrive pre-baked; we’ll just have to add the Spectrum-specific frosting.
The mainline Spectrum systems offer two sound options:
A 1-bit beeper under software control. This is present on all systems, and the underlying hardware is not unlike what we saw on the Apple II or the PC speaker.
A General Instrument AY-3-8910 synthesizer chip, present in all models from the 128K Spectrum on and available as a peripheral for the 16K and 48K variants. These are basically the same as the one in the Atari ST but it’s clocked differently and we don’t have a built-in BIOS call to communicate with it.
This is part of our general survey, rather like our text mode and bitmap mode surveys, so our goals will be modest; we’ll end this article with three programs that play us a C-major scale.
Using the Beeper Through the BIOS
The 1-bit beeper is very similar to the Apple II’s; the $10 bit on the I/O port may be set or cleared to set the speaker’s status. Specific tones are produced by carefully timing the intervals between toggling that bit. We’ll get to code that does that later, but we can put that off because we don’t have to do it ourselves— the BEEP command in BASIC already manages this and it does so by forwarding to a generic routine that we may, ourselves, make use of. The BEEPER routine lies at memory location $03B5 and it’s honestly more clever than the versions I’ve written for 6502 systems. The HL register specifies the delay time in units of 4 cycles (the length of a no-op) and it acquires that precision using a technique not unlike the one we used for programmable cycle-exact 6502 delays. The DE register specifies the duration of the note, which is a touch inconvenient because it actually specifies the number of wavelengths the note should have. Notes of equal length but different pitches will need different duration codes.
The BEEP command itself, though, relies on being told notes in half-steps off middle C and durations measured in seconds. We can look at its own implementation, at $03F8 , to see how to get the values we need. This is done via the system’s floating-point engine, so we actually get neat formulae for both right out of the commentary:
The frequency code HL for a frequency of f Hz is provided by the formula 437500/f – 30.125.
for a frequency of f Hz is provided by the formula 437500/f – 30.125. The duration code DE for a note with frequency f Hz and duration t seconds is simply f×t.
... continue reading