Skip to main content

ZX Spectrum cassette forensics

My first "computer, while growing up, was a Russian clone of a ZX Spectrum. I got it as a "hand-me-down", along with a few tapes and a short booklet in cyrillic. Back then I had no clue of English and even less of other languages, so I just dumbly typed the programs in.

I guess that first computer was responsible for me learning to program, since the games would not load from any of the tapes I had. This happened again with my second gifted computer, a Sinclair QL, for which I had no games.

Anyway, more than 30 years later I thought of trying to see what was actually on those ZX tapes:


There are 35 games listed, though I managed to load probably less than 10 in that computer's lifetime.

Step 1 - buy a cassette deck and restore it


But we're not here about that project.

Instead, you should make sure that you have a decent and well-adjusted tape player. If it's a brand name and mains-powered, it should probably work. Portable players in my experience have a lower quality/stability.

It should have the belts in a good condition (or direct drive) so that wow and flutter are reduced to a minimum. It should have a good frequency response (head alignment) because high frequencies matter.

In short: if the music tapes sound almost as good as on a CD player, it will work. If they sound muffled, garbled or fluctuate, it will not work.

Step 2 - play the tapes and record them onto a computer.

This was actually pretty tricky, I have a bunch of laptops but neither of them as a stereo line input. Luckily I had a USB soundcard in my hoarding stash. To record them, I used Audacity and recorded each side of the tape into a separate file, at 16-bit 44Khz. They came up to around 350MB each, as WAV files.

If you are doing this, make sure you save them uncompressed. The volume level of the final recording should also sit at around 70%.


Make a backup of the unmodified original files, since they are a part of history now.

Step 3 - analog analysis

You can see 6 programs above, with the last one being quite short.

If you zoom in, each program generally has 3 sections: title, screen and data. Each section begins with an annoying tone, called a leader, I think.

If you zoom in on each section you can see the data bits, below is the leader:


You can already see that the left and right channels have different amplitudes. In some cases, some channel might provide better data recovery than the other, so don't convert the file to mono, yet.

The peaks should not be cut and the amplitude should be at around 70% of the full height. If it's lower, you can select Effect -> Amplify.

Zoom out so that more of the tone is seen, select a part of it and click Analyze -> Plot Spectrum.


The main peak should be at around 700 Hz, plus or minus 30Hz.

I had one side of one tape register at only 627Hz and this caused most of the data on it not to be recognized. I used Effect -> Change Speed and added 15%:


Those are the basics steps to ensure that the analog data is correct. In my case, I'm only interested in getting some data out of the tapes, I don't need a bit-perfect digitization. Usually, most of the ZX software is archived somewhere, so just by having the title, you should be able to find it somewhere (such as worldofspectrum.org).

I might make a follow-up post on recovering the full data, if it fails to get digitized. This is useful for preserving software that was not published or that got lost. I found three such programs on those 3 tapes, but not sure if it's worth spending the time to restore them.

Step 4 - digital recovery

If you are lucky, you can just use MakeTZX and it will decode the WAV file into a TZX file. In my case, however, it missed 50% of the programs, so an alternative was needed.

A more powerful alternative is tzxwav. Since it's open-source and written in Python, you can easily customize the processing, for example to better handle the wow or tape speed.

You generally want to run tzxwav in verbose mode and save the output for studying.

tzxwav.exe -v -p -D -p -S mix -o t10a.tzx c10a.wav

=== Program: TURTLES   ---------------------------------|
 Expected length: 288
 Leader: @295972, Sync: @554979, End: @559808
  0:06.711    295972 -    559808: Program: TURTLES    (288 bytes)
--- data
 Length: 288
 Leader: @613219, Sync: @715528, End: @794553
  0:13.905    613219 -    794553: 288 bytes of data
=== Program: TURTLES   ---------------------------------|
 Expected length: 427
 Leader: @905196, Sync: @1163917, End: @1168934
  0:20.525    905196 -   1168934: Program: TURTLES    (427 bytes)
--- data
.....

In the example above, I ran tzxwav on both stereo channels (-S option) and some debugging settings. The title has been recognized and can be used when searching online.

The major warning that I have to make here: make sure to double-check the options before pressing enter, the file name after -o will be overwritten!

Moving further down the log file, we can see the first sign of errors:

...
--- data
 Length: 20
 Leader: @19942303, Sync: @20044604, End: @20051327
  7:32.206  19942303 -  20051327: 20 bytes of data
=== Bytes: ©PLETER
 Start: 16384, Expected length: 6912
 Leader: @20162387, Sync: @20421575, End: @20426709
  7:37.196  20162387 -  20426709: Screen: ©PLETER
--- data###########-------------------------------------|  2:00
 Length: 6911
 CRC ERROR!
 Leader: @20481147, Sync: @20583492, End: @22437310
  7:44.425  20481147 -  22437310: 6911 bytes of data, CRC ERROR!
--- data#################-------------------------------|  1:46
 Length: 41375
 CRC ERROR!
 Leader: @22552094, Sync: @22654466, End: @33277092
  8:31.385  22552094 -  33277092: 41375 bytes of data, CRC ERROR!
=== Program: Black Lamp###------------------------------|  1:42

Now it's the time to start playing with the program arguments. I would start with "-T high". Since it takes some time to get until that portion, I would also add "-s 22000000" and remove the "-o", in order to quickly check if any of the tzxwav parameters make recovery easier. This will skip the first 7:40 minutes of the wav file and just start processing after that timestamp.

You can also inspect the wav file visually at that timestamp:




In this case, probably deleting the first artifact of the right portion would fix the issue. Or "painting" the waveform so the volume stays constant.

Eventually, you will either see the program names or have an error-free tzx file to inspect.


...
 13:13.594  34997535 -  35261478: Bytes: black      (start: 40000, 6912 bytes)
--- data###################-----------------------------|  1:36
...
 13:20.796  35315143 -  37424177: 6912 bytes of data
=== Bytes: lamp      #######----------------------------|  1:34
...
 14:13.856  37655089 -  37919259: Bytes: lamp       (start: 25000, 40535 bytes)
--- data########################------------------------|  1:21
...
 19:06.916  50579028 -  50843591: Program: vu3d       (6803 bytes)
--- data############################--------------------|  1:04
...
 19:14.146  50897862 -  52843404: 6803 bytes of data
=== Bytes: s
...
 20:00.837  52956929 -  53221081: Screen: s
--- data#############################-------------------|  1:01
...
 20:08.049  53274975 -  54990123: 6912 bytes of data
=== Bytes: c         #################------------------|  0:59
...
 20:56.749  55422670 -  63737278: 32183 bytes of data
=== Program: E L I T E ####################-------------|  0:47
...
 24:30.524  64850122 -  65114378: Program: E L I T E  (1140 bytes)
--- data####################################------------|  0:45
...
 25:53.130  68493039 -  71013540: 8625 bytes of data, CRC ERROR!
=== Program: BOMBER MAN##############################---|  0:09
...
 30:51.956  81671267 -  81937748: Program: BOMBER MAN (232 bytes)
--- data
...
 30:59.237  81992370 -  82158051: 232 bytes of data
=== Bytes: BOMBER
...
 31:05.595  82272774 -  82539351: Bytes: BOMBER     (start: 32768, 8000 bytes)
--- data##############################################--|  0:05
...
100% |##################################################|  0:00

Step 5 - reconnaissance

Well, part of this step was performed in the last paragraph, but, the nice thing about working with 8-bit data is that it's easy to scroll through files. The entire tape from above just uses about 100 screens of data. If you are used to studying hundreds of megabytes of logs, browsing through a 200k data file should be pocket change.

Binary analysis always leads to interesting findings, such as names that might have never be seen:



In this case, there is a corrupted program title that ends with "?PLETER", and we're trying to find out what it is. Using a similar technique, we can search in the file and see what's above or below:


Nothing promising above, just a LOADER string and a "*** SLUGS SUK COD ***" string, possibly a cracking group. The game is labeled as LOADER on the cassette face, but I never got it to actually load, so don't know what it contains. If we scroll down however:


We can see references to "pot", "draw", "deck", "deal" which likely means it's a game of poker. 

Changing the formatting of the file to wrap on newline instead of character count makes it easier to see code:


Hmm, seems like it's a game of strip poker. Looking at some more strings, the name Mindy is mentioned, so the most likely match is this game:


If you don't like messing with binary or just want to quickly browse the games, the other option is to load the tzx file into ZXBlockEditor



This allows you to double-check the loading screen against the screenshots shown or archival websites:



Comments

Post a Comment

Due to spammers, comments sometimes will go into a moderation queue. Apologies to real users.

Popular

FiberHome AN5506-02-F router hack

Ikea SKARSTA sit/standing desk hack

Floureon BYC17.GH3 thermostat teardown and impression

Non-genuine battery in Lenovo X230

Philips 3200 Coffee Machine - part 1

Zoom G1 guitar effects pedal repair

Racechip tuning box - part 2 - reverse engineering