My current project is one of steep learning curves, long memories, and hours of waiting and iterations.
Back in high school, I had a TI 99/4A personal computer. We were too poor for the disk drive modules, so I had to store my programs on cassette tapes. I spent a lot of my time working on programming that thing, from those little games that were published in the BASIC programming manual all the way to the big-idea experimental programs and games that I worked hard to complete (my biggest and most persistent project was a Pac-Man clone). Years of my youth were blown writing BASIC code on that machine, and now that all of my TI equipment is gone into the past, all I have left as a vestige is a short stack of audio cassette tapes and a few handwritten notes.
I decided some time ago that I needed to find a way to transcribe those disintegrating cassettes into sound files, and then transcribe those sound files back into the program code. Call it a sick drive to historically document and preserve the past, but I am intensely interested in seeing just how embarrassingly horrible my code was back then compared to now. BASIC was every programmer’s wet nurse, and she fed me well enough to grow up and see that not every design decision was right.
As a thought exercise, it’s obvious to me that something along these lines is doable. There are several TI 99/4A emulators out there, and many of them offer the ability to read tape dump audio files, so I know it’s doable. I’ve tried one of the dump converters (CS1er), and had no luck with my files. So then, this is a perfect opportunity to try my hand at rolling my own solution.
The first step is to play the cassettes. Easy enough, you’d think. But there are many, many problems that make this a non-trivial task. Do you know how hard it is to find a cassette player in this modern age? The Walkman I kept as my constant companion in college is so old, the rubber drive belt has stretched, dried out, and broken. The dual-deck recorder I bought at pawn two years ago when I first had a view of doing this project is likewise having belt problems, and is producing substandard audio. So this weekend I went to no less than four electronics stores before I found a dictation-style portable cassette recorder. Even the sales people got a chuckle when I asked them if they had cassette players. Yeah, I realize we’re a long way from the 80’s, but anything would help.
The next step is to connect that cassette player to a computer and record. I am advantaged to have in my possession some semi-professional recording gear. This was a no-brainer. The problem, however, is that the gear records with too much fidelity. See, when the TI outputs sound to be recorded onto tape, it uses a square wave; the cassette recorder tries to record that square wave onto magnetic tape by modulating a magnetic field in the recording head. This changes the shape of the waveform and adds its own “color” to it. Likewise, the magnetic tape also changes the shape by its own response to the head’s magnetic field. And on playback, the playback head also changes the shape by its response to the magnetic domains on the tape surface as they pass under the head.
By the time the audio comes back out of the system, the wave shape is so far removed that anything looking like a square wave that anything that records with high fidelity is going to misinterpret the signal. I had to go lo-fi and use the cheapest player and feed it into my cheapest audio interface with the crappiest settings. This method seems to give good approximations of the original square waves, since the overdriven inputs on the audio interface are clipping the wave tops. However, as I discovered tonight, the recorded files are unusable. Here’s the short story on why:
The TI (and most other data storage systems that use FSK) decode their signals by looking at the “zero crossings” of the waveform, the moment where the waveform goes from a positive voltage, crosses zero volts, and goes to a negative voltage (and vice-versa). The internal demodulation circuitry counts the amount of time between zero crossings — a phase — and uses that to determine the data bit value. With the TI, a bit of value 0 is one phase change of time T, and a bit of 1 is two phase changes each of T/2, meaning two changes within time T.
At the beginning of a data file, the TI encodes a few seconds of zeros so the internal demodulator circuitry can get a feel for how long a 0 is. This becomes time T. The timing header is then punctuated by a string of eight 1 bits to tell the circuitry that actual data is about to start, then there are a few bytes to tell how many data record blocks are in the file, and then the remainder of the file is those data records.
Some of the problems with the files I’ve transcribed so far is that of where the waveforms cross zero. Sometimes, the signal is too low that you’ll get zero crossings happening inside a zero bit, and sometimes you have the positive phases be longer in distance than the negative phases. This is an analog signal problem rooted in the AC gain and DC bias of the playback deck. The secret is to record the signal loud enough that the squiggly caps of the waveform get clipped and flattened, but also record it low enough that the phases themselves are even in length. Both of these are major problems I’m having on this front.
What I might do is record below the clipping point, and then use the audio editor to shift the waveform up or down so the phases cross equally. Not sure yet. But once I get the playback problems hammered out — and I suspect there’s no one-hammer-fits-all approach, since every file was recorded at different times on different tape types with different tape machines and settings — then I’ll have audio files with just enough fidelity to pull data with confidence. I’m crossing my fingers.
The next step in this process is one of programming the software to demodulate these files and output the binary program code. I’m using this as a perfect opportunity to relearn the C programming language which excels at this kind of low-level data operation. So far, I’ve learned how to use external libraries to read audio files, I’ve learned how to read those files and find all of the zero crossings, and I’ve thus far made rudimentary attempts at decoding the 1’s from the 0’s. It is at this stage that I’m having problems with the good tape dumps that I’ve made so far.
Apparently, most of the usable files have spurious data encoded in them. Remember when I said that 1 bits were two phase changes within time T? Well, if you see a phase change in T/2, you can assume that the next phase will also be in T/2 time. If so, then you have a 1 bit. Well, what if you have 3 consecutive phase changes that are T/2 each followed by one change in time T (a 0 bit)? What is that third T/2 phase change? I have no idea how that gets in there, and have no idea what to do with it. These are more problems to work through. Maybe they’re data markers. Maybe they’re tape playback variations. Maybe the TI I owned had some non-standard method for storing data. Who’s to know? I don’t, at least not at this point.
The final step in this process, assuming I work through all of the other milestones, is to take that decoded stream of ones and zeros and assemble them into data records, check them for consistency, and then decode those into bytes, and then letters, and then the actual source code that my skinny fingers hammered out on that full action keyboard by the light of my color TV oh so many years ago. This early in the game, this step seems like a stretch goal; I have so many milestones to pass in these most rudimentary levels to attain that sort of sophistication. I have to put myself into the mindset of how things were implemented with analog electronics to figure out how best to proceed with deciphering these signals from the past.
Maybe then I’ll be able to touch the face of that young, hopeful kid I once was.