My first computer was a ZX81, even at the time it was rather outdated and only one other person at school had one, but it’s what we could afford and I loved it. Very much a hobby / enthusiast computer, there were lots of low run and home built peripherals, electronic projects and so on.
The ZX81 had no sound whatsoever, not even a beeper. While there are expansions available now with Yamaha chips, at the time the most common were sound generators and speech synthesis units. The latter of these were either phrase based (a set vocabulary) or allophone based (compose any word with phonems). I recently picked up a Sweet Talker by Cheetah (mostly famous for Joysticks) but there was no documentation or software out there….
It’s a fairly typical looking expansion, inside is the speech chip and a speaker, the speaker grille is just a bunch of hand drilled holes in an attempted uniform pattern – yes they really left the factory like this, these were all hand assembled. While this one is loose they came boxed with an instruction sheet and a tape with a program called ‘Chatbox’. I found images of the ZX Spectrum version but nothing for ZX81, so I went to https://www.sinclairzxworld.com/ to look for help, it seems to be the most active Sinclair enthusiast forum.
Fortunately someone actually had the tape and was able to give me the basics. The ZX Spectrum manual and the ZX81 tape (as .P and wav files) are below for reference.
The absolute minimum required to make the unit work is the below program. The REM statement is just a comment and it’s only there because the POKE statements will trample over the memory space for that line resulting in machine code, yes really.
10 REM CHEETAH SPEECH TEST
20 POKE 16514,62
30 POKE 16515,20
40 POKE 16516,211
50 POKE 16517,7
60 POKE 16518,201
70 RAND USR 16514
Memory address 16514 is the first byte after the first basic keyword (the REM), we don’t overwrite the very start because the REM will stop the basic interpreter trying to understand machine code. Line 30 is the actual allophone to play from the chart in the instructions linked above. What will happen when you run this lines 20-60 will write the code that sends code 20 to the speech unit, and line 70 causes it to execute the code starting at address 16514. The unit will just make a loud continuous annoying sound, because we haven’t turned it off afterwards – but that’s the very basic operation.
After some time struggling because my ZX Basic is covered with several decades of rust, I came up with the following program that lets you enter allophones to play back.
10 REM ALLOPHONE ENTRY TEST
20 POKE 16514,62
30 POKE 16516,211
40 POKE 16517,7
50 POKE 16518,201
100 POKE 16515,0
110 RAND USR 16514
120 SLOW
130 INPUT J$
140 FAST
150 LET N=1
160 LET K=VAL J$(N TO N+1)
170 POKE 16515,K
180 RAND USR 16514
190 LET N=N+3
200 IF LEN J$<N THEN GOTO 100
210 GOTO 160
The ZX81 only has 1K of RAM as standard, so you really have to strip programs down if not using an expansion pack. So what’s happening in the above is I’m populating all the machine code except for the allophone at address 16515. Lines 100 and 110 are sending it the code to turn off, this is my startup and loop reset. Line 120 puts the machine into SLOW mode – ZX81s can run in FAST or SLOW, in FAST the screen will flash annoyingly as it switches off screen updates and sync resulting in a flashing screen, it’s great for long calculations or running code, but really unpleasant for text input. Line 130 reads a string, you have to use double digit values separated by a space. After accepting input I put it into FAST mode for the playback. N is a counter for how far in the string we are, K is loaded with the value from that point in the string using the VAL command with an index. I had definitely forgotten all this and had to refer to my old books. Then the code gets loaded to address 16515 and the code executed to play the sound. N is increased by three (“XX “) and we loop, jumping back to the reset once N goes above the length of the input string. Modern programmers are probably looking on in horror at the GOTO statements, welcome to 1981!
This is what it sounds like sending the allophones required to say ‘ZX81’, both without a pause between the sounds and then with one added, I think I prefer the non pause flow, but the paused sounds more vintage. The string entered is “43 07 21 01 07 42 55 03 20 13 19 01 46 15 11”, if you’re really bored check the instructions linked above to see how I constructed the words.