Back in 1983 I had a clone of the ZX-81 computer. The hardware no longer works, but for some reason I kept some cassette tapes. I know these tapes contained some programs that were not available anywhere else. I wondered if it would be possible to retrieve those programs and convert them to digital format, so that I could try them on a modern emulator.
At first I was a little skeptical, after all, the tapes had been lying around for more than 30 years, unused. A quick test on a tape deck proved that at least the characteristic sound of recorded data was there, so it was worth a try. Some research revealed that the ZX-81 stored data using a simple scheme: each byte was stored MSB (Most Significant Bit) first. A “0” bit was encoded as 4 pulses and a “1” bit as 9 pulses. Each pulse lasted 300 us (microseconds). After each bit a “silence” gap of 1300 us was inserted. So the total duration of a “0” bit was 4*300 + 1300 = 2500 us. A “1” bit lasted 9 * 300 + 1300 = 4000 us. After converting the analog sound to a WAV file, I opened it in Audacity, trying to recognize some pattern. This is what I got:
In this small excerpt, there seems to be 9-10 pulses, a gap, a group of 4-5 pulses, another gap and another 4-5 pulses. If you allow some flexibility in the definitions of pulses and silence, this signal can be interpreted as the bit sequence “100”. Similar patterns repeat for the whole WAV file, showing that something is still there after all these years. The amplitude of the pulses vary a lot, sometimes an extra pulse shows up, the silence is not really silence, but the overall shape is not too bad. I tried to apply some filters in Audacity, hoping to get a cleaner signal. A single filter, called AUBandpass produced good results (I suspect this filter is available only on Macs, but there may be equivalent filters on other platforms).
The signal now is a lot nicer, and hopefully easier to decode:
The key factor in decoding the signal is identifying pulses and silence correctly. It doesn’t really matter the exact number of pulses, as long as you can differentiate “long” sequences (around 9 pulses), “short” sequences (around 4 pulses), and a “silence” sequences (no pulse). Of course there is no absolute silence, so you must use a threshold on the amplitude. Here, pulses are in red and silence in green:
In other words, long+silence means “1”, and short+silence means “0”. Eight consecutive bits form a byte.
Using these rules, I built a small program to perform the decoding. If the signal is not mangled beyond recognition, it is possible to get a coherent byte stream. The final test, of course, is to feed this stream into an emulator and see if it makes sense. To my surprise (I must admit I was expecting a high error rate), the first program ran perfectly:
Using the same process I was able to recover most of the programs.