Jump to content

Simulating Cassette Recorder with a Raspberry Pi


Recommended Posts

I recently got a TI-99/4A, and it works great and I love the library of games for it. However, some games I couldn't play, because you need the cassettes and a cassette recorder, and not only that, but I couldn't even save and load my TI-BASIC programs!
I thought maybe my Pi could simulate a cassette recorder by just recording audio and playing it back. Not only would I not need to shell out even more money for the cassette recorder, but my programs would be much safer and I could even share them over the internet if they were on my computer!
But for some reason, the computer refused to recognize it. I tried adjusting every possible setting, I found this old thread, followed it to the letter, but nothing worked. Whenever I would save a program and try to load it, the TI-99/4A just refused to recognize it and said no data was found.
Luckily, through much searching, I found a very reliable and easy to implement solution, so I thought I'd share it here. It does not require the user to have a good audio recording setup for it to work and it always produces high-quality noise-less audio for playback. Since I couldn't find this information elsewhere, I thought I'd make an account and post it here.
The first part is how to set up the Pi specifically to do this, but this can be done on any computer, so skip that part if you are not using a Pi.
Here's how to do it...
Setting up the Pi:
1. First of all, you need a separate audio and microphone jack. The Pi does not even have a microphone jack. The easiest solution is to just buy a USB microphone/headphone adapter, I am using this one that is literally $7 on Amazon. They don't need to be high quality at all. Just get something like that and plug it into any USB port.
2. Install pyaudio. You cannot install pyaudio in the conventional way on the Pi, You have to build it yourself. Luckily, it's super easy, and this post here explains how to do it. Just use these commands:
sudo apt-get install git
git clone http://people.csail.mit.edu/hubert/git/pyaudio.git
sudo apt-get install libportaudio0 libportaudio2 libportaudiocpp0 portaudio19-dev python-dev
python pyaudio/setup.py install
3. Up the volume. Type "alsamixer" and then press F6 to bring up the "Select sound card" menu. You should see at least two sound cards, one being "0 bcm2835 ALSA" being the built-in one, and something called "# USB Audio Device". This is the one we are using. Remember the #, that's the ID number of your soundcard we will use later, it is most likely the ID number "1". When you select it, you will see two bars, one saying "Speaker" and one saying "Mic". Use the left/right arrow keys to go to both of those and hold the up arrow key to up them both to 100. When you are done, press Esc to exit.
4. Change your default sound card. Your default sound card is 0, which is either your HDMI or your built-in headphone depending on how your Pi is configured. We want the default sound card to be our USB sound card with the microphone port. We just got the ID number for it in the last step, so this should be easy thanks to this post. Essentially, create the file "asound.conf" by typing "sudo nano /etc/asound.conf" and paste in these contents, changing the "1" to whatever the sound card ID is assuming it's not just 1 (which it probably is):
pcm.!default {
        type hw
        card 1

ctl.!default {
        type hw
        card 1

After you do this, reboot the Pi.

5. Download dimhoff's TI-99/4A Python code. To download dimhoff's Python code, type this:
git clone https://github.com/dimhoff/ti99_4a_tape_decode
cd ti99_4a_tape_decode
6. Fix dimhoff's Python code. Now, this code is great, but it's broken. Well, sort of, it's moreso the Raspberry Pi is broken, and so you need to add in a line to his code to fix it.
Type "nano ti99_4a_tape_encode.py". Scroll down until you see the block of code that looks like this:
stream = p.open(format=pyaudio.paInt16,
This part sets up pyaudio for streaming audio. However, it is broken on the Pi. Luckily, this post solves our problem. We just need to add a single extra option here. So change the block of code above to the one below, adding the frames_per_buffer option:
stream = p.open(format=pyaudio.paInt16,
Any that's it! The Pi should now be ready for use.
Saving Programs:
1. Take the cassette recorder cables for the TI-99/4A plug one end into the back of the TI-99/4A and the other end into the Pi. The cable should have a red, white, and black wire. The black isn't used. Plug the red wire into the Pi's USB audio-in port (usually colored red) and the white wire into the Pi's USB audio-out port (usually colored green).
2. On the TI-99/4A, type "SAVE CS1" to save your program. Press enter so that the screen says "PRESS CASSETTE RECORD". On the Pi, our "cassette recorder", we need to "press record". To do this, type in this command:
arecord -r 44100 -f S16_LE out.wav
After you type that command, press enter, and the Pi will start recording. Immidiately press enter on the TI-99/4A as well. The TI-99/4A will say "RECORDING". Wait until it says "PRESS CASSETTE STOP", then, on the Raspberry Pi, type Ctrl+C to stop the recording.
3. Now we need the raw data for our program. To get this, use dimhoff's Python decoder script. Simply type this command:
python ti99_4a_tape_decode.py out.wav
This should take a little while, so don't worry if nothing seems to be happening. Once it is done, it will create a file called "tape_000.dat". This is our "tape". It essentially is the raw data of our program. You can throw away "out.wav" as it is not needed. If your program is a TI-BASIC script, you can view the contents of the script on the Pi by typing "python ti99_4a_list_basic.py tape_000.dat".
Loading Programs:
1. Plug up the TI-99/4A like I mentioned in step one of "Saving Programs". On the TI-99/4A, type "OLD CS1" and press enter until it says "PRESS CASSETTE PLAY THEN PRESS ENTER".
2. On the Raspberry Pi, type (but don't press enter):
python ti99_4a_tape_encode.py tape000.dat
3. When we press enter on the Pi, that's the same as pressing "CASSETTE PLAY". Despite what the TI-99/4A says, we are going to press enter on the TI-99/4A before we press enter on the Pi. This is because the Pi will not produce silence at the beginning of playback like the TI-99/4A expects. Simply press enter on the TI-99/4A then quickly press enter on the Pi afterwards, and wait a little while, then kaboom! Your program will load.




That's it!

I hope this was helpful!

This should work very reliably since the audio playback isn't dependent on your recording quality. It is purely computer generated specifically for the TI-99/4A.

Edited by amihart
  • Like 7
Link to comment
Share on other sites

Followup: I realize some people might want to convert old files that are in WAV format to this file type.

To do it, first convert the WAV file to 44100 Hz 16-bit signed little Endian, then run that WAV file through "ti99_4a_tape_decode.py".

ffmpeg -i input.wav -ar 44100 -format s16le output.wav
python ti99_4a_tape_decode.py output.wav
You can then play this back the same way I mentioned before, and the audio quality will probably even be better than your original recording.
Also note that sometimes when playing back files, ALSA spits out a ton of error messages. Those are usually meaningless.
Edited by amihart
  • Like 1
Link to comment
Share on other sites

This is awesome. A lot of people are in the same boat without a cassette recorder and this will definitely come in handy. I am using a very similar audio device to sample stuff of the pi to use in Amiga emulation (Amibian) - I never even thought I might be able to use it as a tape device for the TI. Thanks for yet another option and all the details necessary to get it working.

Link to comment
Share on other sites

This is awesome. A lot of people are in the same boat without a cassette recorder and this will definitely come in handy. I am using a very similar audio device to sample stuff of the pi to use in Amiga emulation (Amibian) - I never even thought I might be able to use it as a tape device for the TI. Thanks for yet another option and all the details necessary to get it working.

this is pretty cool stuff. i have a Program Recorder but I've found the media is not particularly reliable (for me, but ymmv).


Will check it out!


Great, I'm glad people found this useful! ^- ^

Tapes can degrade over time. This way your stuff is always perfect so it should all play back perfectly with no issue.

You can even record your own tapes and transfer them to this format to preserve them! Just do the same steps I showed for saving a program but use the tape recorder as an input and not the TI-99.




Also, just another update (I wish I could just edit the main post for these):


I found that on some Pis, Pyaudio is broken and will stutter like crazy when trying to play audio back. I've found like 30 threads on this issue going back two years and no solution, so apparently it's just broken. If you encounter this issue, the solution I found is simply to have ti99_a4_tape_encode.py save the output to a WAV file rather than play it back immediately. To do that, just put the name of a WAV file after the command, such as, "python ti99_a4_tape_encode.py tape000.dat mytape.wav". Then play the tape back using "aplay mytape.wav". This way also is arguably better because audio playback is instant rather than having a slight encoding delay. For some reason, the WAV file on my Pi refused to play until I upmixed it with "ffmpeg -i mytape.wav -ac 2 mytapeupmixed.wav". Not a big deal, just an extra command to type.


Here's a Bash file that does the whole recording process for you as well as encode a WAV file for easy playback:



if [ "$1" == "" ]; then
    echo "Usage: tirecord [file]"
    exit 1

echo "Recording... Press ^C to stop."
arecord -r 44100 -f S16_LE .tmp.wav > /dev/null 2>/dev/null
echo -e "\nRecording stopped."
echo "Generating cassette file..."
ti99_4a_tape_decode.py .tmp.wav 2>/dev/null
mv tape_000.dat $1.cs1
rm .tmp.wav
echo "Encoding wave file..."
ti99_4a_tape_encode.py $1.cs1 .$1.wav
ffmpeg -y -i .$1.wav -ac 2 $1.wav >/dev/null 2>/dev/null
rm .$1.wav
echo "Done."
Edited by amihart
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...