News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: [Technical] Writing a cassette converting program  (Read 1327 times)


  • Hero Member
  • *****
  • Posts: 1107
    • View Profile
    • Psyklax Translations
[Technical] Writing a cassette converting program
« on: May 25, 2019, 03:13:11 pm »
Guys! I come with a request, which is unusual for me, but it's something that would more than likely take a lot of effort for me to achieve while being extremely simple for someone else to do. This could describe a lot of requests, I suppose, but whatever.

First, the tl;dr part, since this is going to take some explaining. Basically, I need a program - in whichever high-level language you like - that takes a file, and makes a new file based on the amount of bytes between important bytes. Based on that information, it makes a new binary file.

If this sounds a bit abstract, it is: I'm going to explain the whole thing below. But I just wrote that so that anyone who thinks they can do it can continue reading for details, while others can ignore the fluff. :D


So, now the long explanation. I'm quite big on game preservation, and recently my friend discovered in his collection a game for a computer I'd never even heard of. The computer was the Colour Genie, and the game was a computer version of Monopoly written in BASIC. I'm very much aware that yet another computer Monopoly on a system nobody has heard of - and in BASIC no less - is probably the least interesting thing you could imagine, but as far as I'm aware, it's not been dumped to a tape file to play in an emulator and thus is unpreserved. Yes, there is an emulator, and yes, the computer uses cassette tapes.

Anyway, my friend tried recording it as a WAV file and using a program designed for converting WAVs to tape files, but it just produced a load of gibberish. I knew the principle behind games on cassette was to use pulses to make binary information, ones and zeroes. So I opened the WAV in Wavosaur and zoomed in to see if I could figure it out. I noticed that sometimes the 'line' on the screen crossed the centre once, and sometimes twice, within the same length of time.

There are quite a few working tape files out there, so I was able to see what it's supposed to look like. It didn't take me long to figure out that one pulse is 0 while two pulses means 1. So by literally counting by hand on the screen - "zero, zero, one, one..." and typing that into a hex editor, I discovered, to my amazement, that I was, bit by bit (literally), recreating a BASIC program.

Of course I could do this incredibly tedious process until the end of the game, but I don't think my sanity would hold up. So, I decided to figure out a way I could get a computer to do it for me. I figured that a WAV is still just a simple binary file at heart, and I was right. My friend recorded it in 96khz 8-bit mono, which resulted in a very simple and predictable file: $80 is the centre of the wave (silence) and each sample goes above or below $80, and this constant up-and-down produces sound.

It occurred to me that all I need to know is whether a certain amount of bytes have passed before crossing that centre $80 line. If it came quickly, it must be a 1, and if it took longer, it must be a 0, but eventually it would cross that line. Now, I have no idea how to program in high-level languages, but I do know a thing or two about coding in assembly for 8-bit CPUs, so I know that this would be an incredibly simple procedure. I've decided to explain the logic that the computer will follow:

0 reset counter
1 increment counter
2 load byte
3 is it >= $80?
4 if yes, continue; if no, go to 1
5 load check byte
6 is it zero?
7 if yes, continue; if no, go to B
8 load counter
9 is it >= $48?
A if yes, write 0 bit and continue; if no, write 1 bit, set check byte, continue
B reset counter
C increment counter
D load byte
E is it <= $80?
F if yes, continue; if no, go to C
G load check byte
H is it zero?
I if yes, continue; if no, go to 0
J load counter
K is it >= $48?
L if yes, write 0 bit and go to 0; if no, write 1 bit, set check byte, go to 0

A few explainers: the counter is to count how many bytes have been checked; the check byte is a byte of RAM that is either 1 or 0 to signify that the next crossing of the line is to be ignored (because it's a 1). Everything else should be understandable to anyone who's written routines for the 6502 or similar.

So, put simply, I just want a program that can do this exact thing: go through that routine and make a new file from it. I'd love to do it myself, but I figure I'll need to do quite a bit of basic learning in a high-level language before I can even get there, whereas I could write this in 6502 assembly already - which doesn't really help me.


Sorry for the long explanation. I hope this all makes sense to someone, and I know that there are people active on the forum who could probably knock this kind of thing up in under an hour, although there are advancements that could be made, such as reading the WAV header to determine the frequency and adjust values accordingly, and telling where the program actually starts and ends. But for me, this will do for now. Perhaps someone could point me to a modern programming language I could learn to do it myself - a tutorial that assumes you know how assembly works, for example. :D Anyway, I've talked enough. Any help is appreciated! :)


  • Jr. Member
  • **
  • Posts: 33
    • View Profile
Re: [Technical] Writing a cassette converting program
« Reply #1 on: May 26, 2019, 03:46:31 pm »
Hey Psyklax, sounds like a cool project. Could you possibly post a series of output bytes that you'd expect (say 4 bytes), and also the initial .wav input bytes that produce it? I would understand the output and input data better. Your pseudo code helps, but each higher level programming language would have a different structure than the 6502 assembly, so the raw data might help us more.

This sounds fun, like the kind of thing for a programming challenge! See how many different languages we can make it in  :thumbsup:


  • Hero Member
  • *****
  • Posts: 1107
    • View Profile
    • Psyklax Translations
Re: [Technical] Writing a cassette converting program
« Reply #2 on: May 26, 2019, 06:26:03 pm »
Thanks for the interest. :) I'll give you a little example, though I won't bother with pictures of the waveform since it's not really necessary for this task.

I'll give you a simple example. I've already recorded several lines of BASIC by hand, so here's the start of the second one - any more and the amount of bytes in the WAV will get too much. The first line is "0 CLS", which makes sense I suppose. The second line is this:

1 forI=1to2:print@488,"PRESS 'STOP' ON RECORDER"

Yes, they didn't include spaces. I'll just go through the first three bytes of the data: that is, the line number (which takes up two bytes) and the FOR command. They look like this in the tape file:

01 00 81

meaning 01 00 is the line number (I suppose this BASIC supports 65,536 lines then), and 81 is the hex code for the FOR command. I would paste the bytes from the WAV, but even these three bytes are way too much to put in this thread, so instead I've uploaded the WAV with just the three bytes mentioned:

If you open it in a hex editor, you'll see the header, followed by the audio data. If you need to know more about the header, take a look here:

The sound data begins at $2C. The first four bytes are "82 80 80 7E". I just cut it at this point, just before it dips below 80. As you can see, it takes $5D bytes to go back to 80, which is more than $48 (the number I decided upon in my pseudo code). So we know it must be a 0. The next six also take more than $48 bytes to cross the 80 line, but on the eighth try, it makes it in just $2D bytes. This means we know it's a 1, but now we set my 'check byte' because we need to keep counting, but ignore the next time it crosses (because we know it's a 1 already).

So $36 bytes later, we reach 80 and the program should see that our 'check byte' is not zero and thus we reset the counter and go again. Of course we now have done it eight times, so I suppose it would make sense to write our first byte: 01. You could have a second counter for that.

I won't go any further, but suffice to say that this should be clear enough. Of course, this is with a file at 96khz for extra clarity, but with this method you could theoretically record as low as 8khz (or even lower) and still get the right result with a different number to $48 - though when you go really low then the number of bytes between samples gets very small, so there would be a chance of an error.

Hopefully this will get either you or someone else thinking about how to do it. Thanks again for your interest! :)


  • Sr. Member
  • ****
  • Posts: 318
    • View Profile
Re: [Technical] Writing a cassette converting program
« Reply #3 on: May 27, 2019, 12:14:22 am »
Have you checked to see whether there's source code available for utilities that do similar things for other platforms? I know that there's a command-line program for the Tandy Color Computer that will convert WAV files to binaries and vice versa, and I have to imagine such a thing exists for every major retrocomputing platform (and that the basic principles are essentially the same between platforms).

It looks like the program for Atari 8-bit computers has the same name, CAS2WAV and WAV2CAS; maybe it's the same program. There's a related Sourceforge project, A8CAS.

With a couple of relatively small changes to account for different cassette data encoding schemes, I'd imagine there must be an open-source program with the right bones for this task.


  • Sr. Member
  • ****
  • Posts: 471
    • View Profile
Re: [Technical] Writing a cassette converting program
« Reply #4 on: May 31, 2019, 07:01:29 pm »
I heard of the Colour Genie before, but didn't know there was a dedicated emulator until just now. If you haven't tried it yet, you could check out MAME/MESS for it. It's supposed to support WAV directly, there's apparently also a generic cassette conversion tool, possibly debugging and other useful functions etc.