
Jamminate your 8-bit!
A little over a year ago I got deeply involved with the FujiNet project. I started by adding write capability for Disk II to the Apple II version, and helped out with adding other features, debugging. I also worked on bringing up FujiNet with MS-DOS over RS232.
In August there was some discussion on what might be an interesting use of FujiNet that could be used as a simple cross-platform programming demo and raise awareness of FujiNet. I thought about it a lot, but had a hard time thinking of something that wasn’t some text based “fetch the latest page from a site” or yet another multi-player game. Then I started thinking about doing something with music? Would it be possible to use the FujiNet as a bridge between an 8 bit computer and some sort of network-based “MIDI”? Could I do something that would be easy for others to replicate and didn’t require any exotic hardware beyond an old computer and a FujiNet? Some kind of program that would open a network socket and receive note messages and then play them. But what protocol? Was there such a thing as MIDI over a network? Well, yes and no. There was some effort done to make MIDI work over a network, and Apple did some work with that. But Apple defined their own protocol and it seemed like there wasn’t a lot of documentation on it. Plus the apps I could find weren’t really what I was looking for. More research though and I found something called Open Sound Control or OSC. Not only is the protocol open and documented, it’s also extremely simple and there are a lot of apps that can communicate via OSC.
With September coming up I thought it might also be fun to use a TRS-80 computer to tie in with #SepTandy. I’ve had a TRS-80 Color Computer 2 for about a decade that I’ve done very little with, it can do better than 1 bit sound, and so I decided that the CoCo 2 would be the machine I would initially target for my FujiNet application.
The first thing to do was research what kind of music software there already was on the CoCo. I dug around through Rainbow Magazine scans and found a “mega-music” issue from December of 1983. Almost every article in the issue had something to do with music! The one article that stood out to me was one on four-part harmony. Somehow the CoCo had been made to be able to play chords, which seemed like it would be even better than my original plan of just playing a single note. At first I thought I was going to have to type in the program listing, but NF6X on mastodon pointed out there were tape and disk images released by Rainbow Magazine. The image I found for the December ’83 issue was missing the program I wanted, but a bit more searching and I found a different disk image that had the software.
Testing out the program it seemed to work as advertised! I wanted to test it with a song I would recognize though, and I sure wasn’t going to spend the time tediously entering a song through the clunky BASIC program’s interface. Instead I put together a quick & dirty Python script that would tear down a MIDI file and spit it out in the binary format that the BASIC program used. Loading in my song and playing it back sounded pretty good!
I put the fancy four-part harmony program aside and started working on the networking and OSC side. I found an app called TouchOSC which could act as a keyboard, and another app called Surge XT which would be the synthesizer. It was easy to connect them together via a TCP socket and push the keys of the on-screen keyboard in TouchOSC and have sounds play in Surge XT.
Making the CoCo open a socket through the FujiNet and wait for a connection from TouchOSC was the next challenge. This part was extremely easy. There’s a library for FujiNet that can be easily called from C which takes care of opening a socket, accepting a connection, and reading the data. I chose a port number for my application to listen on for an OSC connection, configured TouchOSC to use that for sending OSC messages, and had the CoCo print out everything it received. As soon as I pushed a piano key on the touch screen of my iPad I saw a message. When I let go of the key, another message. And the data in the message was very simple and I was able to decode the notes easily. I thought I was going to have to spend time reading over OSC protocol documents, but not at all. The note value was encoded as simple ASCII with null padding, and to determine if it was on or off I just needed to look at the binary encoded velocity to see if it was zero or non-zero, with zero meaning off.
But just printing messages isn’t good enough. There was already a fancy PLAY command in the CoCo BASIC that could take a string of note values and play them. I figured calling that would probably be easier than trying to adapt some complex assembly routines for playing sound. With my experience on the Apple II, I was sure that documentation on how to call BASIC’s PLAY command from assembly would have been documented numerous times by many authors. Well, if it had, that documentation was not anywhere I could find. I had to spend some time staring at ROM disassemblies and figuring out what address the PLAY routine lived at and how I could call it from C. I eventually figured it out and made it so when the note message arrived I could play a note of a fixed length.
Good, but I really wanted the note to stay on until I released a key. I was sure I could do better, but that meant now I was going to have to delve into how to play sound from assembly.
Oh, did I mention the insanity of how the hardware in the CoCo works? No? Well…
Much of the hardware goes through two chips. The joystick, the keyboard, the cassette, the RS232 port, and the sound. The joystick and keyboard are handled by one chip, the rest by the other chip. No problem, I just need to configure things so that I can play sound while reading and writing to the RS232 port, right? Nope. The RS232 port is extremely bare bones. There’s no UART, no ACIA, no nothing. RS232 transmission is done by the CPU itself directly setting the TX line to mark or space, idling for just the right amount of clock cycles, and then toggling the line again. Receiving is done by watching the RX line and seeing when it changes state and recording the bit, then idling and doing it again. There’s no buffer to load a byte into and transmit while doing something else, and worse, no buffer to receive a byte into that the CPU can then process it when it’s ready. The CPU has to be completely tied up to use the RS232 port.
Then there’s the sound. While the CoCo can definitely produce better sound than an Apple II or IBM PC without a sound card, the CoCo has no dedicated sound chip. The CPU still has to handle all the sound generation itself by writing 6 bit values to an appropriate memory location.
Oh but it gets better. Not only do sound and RS232 use the same chip, they share the same registers. That means that in order to use one feature, the other feature has to be disabled. Which is every bit as inconvenient as you’d imagine.
I started contemplating how I was ever going to make this whole thing work the way I wanted. I was feeling overwhelmed with the complexity that was evolving because of discovering that the CoCo was more primitive than I realized. Was I going to need to write an intricate cycle counted assembly routine for doing I/O to call in place of the Drivewire routine in ROM? Was I going to need to lower the baud rate so I would have time to update the sound while transferring data? I wasn’t sure, but before getting myself bogged down with that, I figured the first thing to do was get waveform playing working and see how terrible it was when interrupted to handle the RS232 port.
Of course, before I could get waveform playback working, I needed the assembly source used by the four-part harmony program.
The article in the magazine only provided the source to the BASIC part, the assembly part was binary values in DATA lines and POKEd in by BASIC. The article made reference to where the assembly code had come from though. I hunted down the correct publication and issue, but it was a terrible scan and it was going to be horrible to have to type it in. Then I had the idea of trying to search for some of the comments in the listing. I managed to find an Italian blog which discussed the program, and gave me a few more pointers to search for. A bit more digging and I stumbled upon a version by Simon Jonassen which had been modified to use interrupts so the music could play continuously while the program did other things!
I grabbed the source from github and was able to build it, put the required files on a disk, and watch as the BASIC program ran and drew a picture, then animated a little car at the end, all while music played the entire time. Yes, playing the music slowed down the running program, but that didn’t matter to me because the program I was writing only had two jobs: play the requested sound and check if it had been told to play another sound. With sound playing through interrupts that would mean I shouldn’t need to write some intricate routine with precise timing to keep sound playing while also checking for new data on the RS232 port.
Adapting the interrupt driven sound routine so I could use it from my program was pretty easy. I just removed the song sequencing stuff and exported the init, stop, and frequency lookup routines to my C program. I slapped together a short test program in C which would start playing a single note, loop briefly to let the note play, and then stop it and exit the program. It worked perfectly! I then replaced the call to BASIC PLAY with calls to use the new waveform playback and gave it a try. Immediately ran into problems with RS232. Figuring out how I could share the registers between sound and RS232 was extremely challenging. If things weren’t in the right state then either sound or RS232 just wouldn’t work at all. Sometimes I had weird issues where sound worked, but the notes that played were from keys I had already released. Other times the playback would lag way behind and start a second or two late.
Eventually I managed to get through all that, and with the four voice support, that meant I could push up to four keys on my keyboard and play four notes at the same time! On an 8-bit TRS-80 Color Computer!
The only remaining issue was when I had to disable the sound and enable the RS232 port. I was fine with living with the sound dropping out briefly, the issue was the loud popping that happened when I did it. It took a lot of trial and error trying to figure out what caused it. It turned out that the sound needed to be turned off through the registers in just the right order, then after I was finished with RS232, turned back on and restore the DAC value that was there when I shut it off. Once I figured that all out the popping went away and there’s only a very brief interruption when pressing keys on the piano keyboard. It’s a small thing and I can live with it.
I’ve placed the source to Jamminate up on github. If you want to build it yourself, I recommend using defoogi which wraps up all the obscure 8-bit tools needed into a Docker container. Or even easier, just fork the repo and let github do the building for you! I’ve put a workflow into my repo which will automatically build when pushing commits up.
And look out for future versions! I have some ideas on making this cross-platform so it can be used on other old computers, and possibly making it able to send OSC messages and not just receive! Control Surge XT from your Apple II? Turn your Coleco Adam into a sequencer to use a Commodore 64 and Atari as a distributed orchestra?


Recent Toots