Show HN: I recovered one of my earliest ZX-Spectrum games from an audio cassette

49 points by codeguppy 6 days ago

Recently, I managed to recover some of my earliest work from the ZX Spectrum era from an old audio cassette.

It is a mini-game, that I created as a teen, called "Atomix," written in BASIC with a mix of Z80 assembly — some of which I coded myself, while other parts were disassembled from existing games. I put the game in an modern emulator and recorded a screencast. See the video in my linkedin post:

https://www.linkedin.com/feed/update/urn:li:activity:7288665...

TheRealSteel 5 days ago

That's so cool!! I'm kind of sad I mostly missed that era of computing. Always thought the ZX Spectrum was a cool system. It's neat that writing your own software was accessible and practical all the way back then. I'll probably buy one when I have the money and room to collect that sort of thing.

There's something that seems very satisfying about loading software from tape, too.

That's what I love about coding. All you need is a computer and an idea and nobody can stop you creating it.

  • jerkstate 5 days ago

    You haven’t missed it! It’s still there! My kids are learning Scratch - but they are also learning C on the Vic-20 (6502 cpu), which is simple enough that the disassembly is easy to understand. The compiler and IDE are cc65 and VSCode - the commodore keyboard is very bad and it’s a lot easier to run the debugger/monitor on an emulator.

  • pkphilip 5 days ago

    Ah! the memories! They are not as rosy as they seem now though.. the tapes were very finicky and you could get data errors very easily - sometimes almost at the very end of the loading of the programs.

    But yes, I did enjoy those days.

  • pjmlp 5 days ago
    • tromp 5 days ago

      Unfortunately, it's not sold in the Netherlands :-(

      • pjmlp 5 days ago

        I thought it was everywhere in Europe, I can guarantee that at least in Portugal, Spain and Germany I have seen them at plenty of electronic stores during Christmas.

  • rvdginste 5 days ago

    > There's something that seems very satisfying about loading software from tape, too.

    Uhhh.. as someone who used to load software from tape on a CPC 464 ages ago, I can tell you that it was painfully slow. Nothing satisfying about it for me...

    • ralferoo 5 days ago

      You might like my Amstrad CPC demo from 10 years ago called Breaking Baud.

      It was a custom turbo loader for the CPC that had a co-operative multi-tasking thing going on, so it had a loader, music player, realtime data decompressor and some spare time left to do some other things.

      I had plans to make the demo even better, but actually what got produced was quite pure because everything, literally EVERYTHING, is loaded directly into RAM and then decompressed in place (that's what the random white flashes are you might see at times - it's usually where a RLE marker was placed in RAM and shown by the display hardware before the background task to expand/copy the RLE section was executed).

      As such, every step of the animations loaded could actually a full screen independent of the last, it's just most of the time it compresses super easily as the delta from what's already in the memory at that point is very small.

      The live capture of the demo as it was presented live for the first time is here: https://www.youtube.com/watch?v=D62jpqZ6TG4 Someone else running it on real hardware (but sadly turned down the tape volume after a minute or so): https://www.youtube.com/watch?v=G7HEK1B2oIc

      This is a very early prototype that actually shows the speed of loading completely unrelated images, just relying on compression - some of the screens load 16KB in around 10 seconds: https://www.youtube.com/watch?v=qfGcvWOaFFw (BUT BE WARNED IF YOU ARE SENSITIVE TO FLICKER)

      • ralferoo 5 days ago

        I linked below in another comment a version of the last video captured on an emulator, so no flicker. Also, I set the correct palette for each picture, so it's a bit nicer to look at anyway: https://www.youtube.com/watch?v=NxX4fu6dAzo

codeguppy 5 days ago

I still believe those early 8 bit computers were great to introduce young people to coding. These days we have many options but also lots of distractions. At one point I tried to replicate that coding experience in a browser by implementing codeguppy.com -- I think I had partial success... What do you think?

  • fragmede 5 days ago

    Simply judging by the fact that you have competitors that are paying to show up in search results for "codeguppy" implies you're quite successful

ggm 5 days ago

Well done. Speaks volumes (sorry) to the robustness of the encoding model.

This was Kansas City Standard? 300bps. The zx format is I believe much the same.

My audio tapes from this period are badly affected by heat, and stretching (I made a geared tape rewinder out of meccano which worked but was not kind to tape)

  • pechay 5 days ago

    The ZX Spectrum ROM loader is 1500bps and some games loaded at over 3000. There wasn't any encoding, just straight-up 1s and 0s straight into RAM.

    • ralferoo 5 days ago

      There was an encoding, in fact a very specific coding, designed to overcome the limitations of tape as a media, the biasing circuitry in tape heads and wiring polarity problems.

      Granted, it was quite a simple encoding, but it wasn't just "straight-up 1s and 0s straight into RAM".

      The bits of data to be output are encoded into high/low symbols representing the voltage on the pin, a 0 bit is output as HL and a 1 bit is output as HHLL, recorded at a nominal symbol rate of 855 T-states or approx. 4092 symbols per second.

      In other words, both 0 and 1 bits are output as a pair of pulses with the 1 bit being twice as long as the 0 bit. If you had a continuous stream of 0 bits, it'd be a steady 2046Hz square wave, with a steady stream of 1 bits, it'd be a steady 1024Hz square wave.

      There are many reasons why this scheme is adopted rather than the much simpler "high voltage=1, low voltage=0" which would be your "straight-up 1s and 0s straight into RAM".

      The first main reason is that while the signal ends up as a perfect square wave, recording this to tape and reading it back doesn't give a perfect square wave, but instead a noisy wave that's more like a sine wave but with flattened peaks and valleys. This is very much in the analog domain.

      Firstly, there's the conversion of the 0V/5V to analogue wave form, where's actually zero-biased to produced a +ve / -ve waveform. Ignoring all the weirdness on the tape, this is read back as a +ve / -ve waveform, amplified and rebiased to a non-zero voltage (so e.g. now the signal might be 1V-4V or it might be -1V to 6V). So now, converting that back to digital is hard - you need to choose an arbitrary cut-off voltage where lower is 0 and higher is 1, but you then find that then the volume changes the relative size of 0 and 1 bits when read back from tape.

      The next problem is called "head biasing", but essentially the magnetic head needs to keep changing polarity to record a useful signal, but if the polarity of the head stays +ve or -ve too long it becomes saturated and resists change in the opposite direction, and so takes longer to change state. So for instance if you recorded a pattern like LHHHHLLH it might read back as LHHHHHLH. A video of mine that shows this effect is: https://www.youtube.com/watch?v=-GdPSnFswgk

      The next problem is that tape motor speeds, tape can stretch, even oscillators in different machines can vary slightly and it's very unlikely that the signal you read back will be exactly the speed it was recorded at. You can "re-clock" on edge transitions, but if you have long stretches without a transition, it's hard to be certain how many bits were there.

      Replacing a bit with a pair of pulses solves all of the above problems. There are several competing tape formats that use pairs of pulses - using output symbols HL and LH, which gives a constant bit rate, and the one used in the Spectrum of HL or HHLL, which is effectively frequency modulation and gives an average bit rate of 1500 baud (it'd be 1000 baud for all 1 bits, 2000 baud for all 0 bits). The latter was adopted almost universally, as it's simpler to decode on read - it's just timing the period of a pair of pulses (i.e. an entire wave). The former one requires slightly slower baud rates, but a related encoding is the basis of most early floppy disk encodings which use MFM.

      There are alternative encoding schemes possible, just very infrequently used. I made a demo for the Amstrad CPC back in 2014 that tries to implement a turbo loader by clever use of output symbols, and it actually translates an entire byte at a time into a sequence of "overall balanced" pulses over a roughly uniform time period, and achieves a baud rate of 2687-3072. I was attempting to implement something like MFM coding used on floppies, but it wasn't quite possible with tape. This demo also had realtime decompression of data. There's more information on that here: https://github.com/ralferoo/breaking-baud/blob/master/docs/t... and you can see an example of it in action here: https://www.youtube.com/watch?v=NxX4fu6dAzo - when watching this be mindful that each screen is 16KB and would take 52seconds with the standard loader (same speed as the Spectrum standard loader).

      • pechay 5 days ago

        Thank you for your incredibly detailed correction :)

K0balt 5 days ago

Very cool!

I recently stumbled across a cassette of the first “commercial” software I ever wrote, a simple database with an inventory tracking module for a local food co-op.

I was 14 at the time, and the software was written for the zx80/81. Around that time I also sold a simple universal list database with no rows or keys, searchable with a super simple regex type syntax. That was for use with a battery-backed RAM expansion pack, and offloaded to cassette as backup.

fjfaase 5 days ago

Well done. Not an easy feat I know from experience. I did the same for some basis/assembly programs for the Acorn Atom. Recovered those from tape.